1
0
mirror of https://github.com/golang/go synced 2024-10-01 01:18:32 -06:00

go/types: expose types.IsIdentical, the Type equivalence relation.

This function is absolutely critical for clients such as
exp/ssa, and too complex for clients to duplicate.

As with CL 7200046, gri expressed in the doc below [gophers
only] before going on leave that he intended to expose such a
predicate, though his wording suggests as an interface method
of Type rather than a standalone function.  (My preference is
for binary methods to be standalone; see "On Binary Methods",
Kim Bruce, 1995).  In any case if he wishes to move it that's
easily accommodated by clients.

https://docs.google.com/a/google.com/document/d/1-DQ4fxlMDs9cYtnkKhAAehX6MArjOQyJsRXp-6kiJLA/edit#heading=h.k3bwja7xony9

R=iant, gri, iant
CC=golang-dev
https://golang.org/cl/7203051
This commit is contained in:
Alan Donovan 2013-01-24 14:22:17 -05:00
parent f8fb95f288
commit 0cbf289b36
5 changed files with 20 additions and 20 deletions

View File

@ -142,7 +142,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
goto Error goto Error
} }
if !isIdentical(x.typ, y.typ) { if !IsIdentical(x.typ, y.typ) {
check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ) check.invalidArg(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
goto Error goto Error
} }
@ -191,7 +191,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
goto Error goto Error
} }
if !isIdentical(dst, src) { if !IsIdentical(dst, src) {
check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src) check.invalidArg(x.pos(), "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
goto Error goto Error
} }

View File

@ -58,14 +58,14 @@ func (x *operand) isConvertible(T Type) bool {
V := x.typ V := x.typ
Vu := underlying(V) Vu := underlying(V)
Tu := underlying(T) Tu := underlying(T)
if isIdentical(Vu, Tu) { if IsIdentical(Vu, Tu) {
return true return true
} }
// "x's type and T are unnamed pointer types and their pointer base types have identical underlying types" // "x's type and T are unnamed pointer types and their pointer base types have identical underlying types"
if V, ok := V.(*Pointer); ok { if V, ok := V.(*Pointer); ok {
if T, ok := T.(*Pointer); ok { if T, ok := T.(*Pointer); ok {
if isIdentical(underlying(V.Base), underlying(T.Base)) { if IsIdentical(underlying(V.Base), underlying(T.Base)) {
return true return true
} }
} }

View File

@ -444,7 +444,7 @@ func (check *checker) binary(x, y *operand, op token.Token, hint Type) {
return return
} }
if !isIdentical(x.typ, y.typ) { if !IsIdentical(x.typ, y.typ) {
check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ) check.invalidOp(x.pos(), "mismatched types %s and %s", x.typ, y.typ)
x.mode = invalid x.mode = invalid
return return

View File

@ -137,7 +137,7 @@ func (x *operand) isAssignable(T Type) bool {
V := x.typ V := x.typ
// x's type is identical to T // x's type is identical to T
if isIdentical(V, T) { if IsIdentical(V, T) {
return true return true
} }
@ -146,7 +146,7 @@ func (x *operand) isAssignable(T Type) bool {
// x's type V and T have identical underlying types // x's type V and T have identical underlying types
// and at least one of V or T is not a named type // and at least one of V or T is not a named type
if isIdentical(Vu, Tu) { if IsIdentical(Vu, Tu) {
return !isNamed(V) || !isNamed(T) return !isNamed(V) || !isNamed(T)
} }
@ -161,7 +161,7 @@ func (x *operand) isAssignable(T Type) bool {
// type, x's type V and T have identical element types, // type, x's type V and T have identical element types,
// and at least one of V or T is not a named type // and at least one of V or T is not a named type
if Vc, ok := Vu.(*Chan); ok && Vc.Dir == ast.SEND|ast.RECV { if Vc, ok := Vu.(*Chan); ok && Vc.Dir == ast.SEND|ast.RECV {
if Tc, ok := Tu.(*Chan); ok && isIdentical(Vc.Elt, Tc.Elt) { if Tc, ok := Tu.(*Chan); ok && IsIdentical(Vc.Elt, Tc.Elt) {
return !isNamed(V) || !isNamed(T) return !isNamed(V) || !isNamed(T)
} }
} }

View File

@ -92,8 +92,8 @@ func hasNil(typ Type) bool {
return false return false
} }
// identical returns true if x and y are identical. // IsIdentical returns true if x and y are identical.
func isIdentical(x, y Type) bool { func IsIdentical(x, y Type) bool {
if x == y { if x == y {
return true return true
} }
@ -111,13 +111,13 @@ func isIdentical(x, y Type) bool {
// Two array types are identical if they have identical element types // Two array types are identical if they have identical element types
// and the same array length. // and the same array length.
if y, ok := y.(*Array); ok { if y, ok := y.(*Array); ok {
return x.Len == y.Len && isIdentical(x.Elt, y.Elt) return x.Len == y.Len && IsIdentical(x.Elt, y.Elt)
} }
case *Slice: case *Slice:
// Two slice types are identical if they have identical element types. // Two slice types are identical if they have identical element types.
if y, ok := y.(*Slice); ok { if y, ok := y.(*Slice); ok {
return isIdentical(x.Elt, y.Elt) return IsIdentical(x.Elt, y.Elt)
} }
case *Struct: case *Struct:
@ -130,7 +130,7 @@ func isIdentical(x, y Type) bool {
for i, f := range x.Fields { for i, f := range x.Fields {
g := y.Fields[i] g := y.Fields[i]
if !f.QualifiedName.IsSame(g.QualifiedName) || if !f.QualifiedName.IsSame(g.QualifiedName) ||
!isIdentical(f.Type, g.Type) || !IsIdentical(f.Type, g.Type) ||
f.Tag != g.Tag || f.Tag != g.Tag ||
f.IsAnonymous != g.IsAnonymous { f.IsAnonymous != g.IsAnonymous {
return false return false
@ -143,7 +143,7 @@ func isIdentical(x, y Type) bool {
case *Pointer: case *Pointer:
// Two pointer types are identical if they have identical base types. // Two pointer types are identical if they have identical base types.
if y, ok := y.(*Pointer); ok { if y, ok := y.(*Pointer); ok {
return isIdentical(x.Base, y.Base) return IsIdentical(x.Base, y.Base)
} }
case *Signature: case *Signature:
@ -168,14 +168,14 @@ func isIdentical(x, y Type) bool {
case *Map: case *Map:
// Two map types are identical if they have identical key and value types. // Two map types are identical if they have identical key and value types.
if y, ok := y.(*Map); ok { if y, ok := y.(*Map); ok {
return isIdentical(x.Key, y.Key) && isIdentical(x.Elt, y.Elt) return IsIdentical(x.Key, y.Key) && IsIdentical(x.Elt, y.Elt)
} }
case *Chan: case *Chan:
// Two channel types are identical if they have identical value types // Two channel types are identical if they have identical value types
// and the same direction. // and the same direction.
if y, ok := y.(*Chan); ok { if y, ok := y.(*Chan); ok {
return x.Dir == y.Dir && isIdentical(x.Elt, y.Elt) return x.Dir == y.Dir && IsIdentical(x.Elt, y.Elt)
} }
case *NamedType: case *NamedType:
@ -197,7 +197,7 @@ func identicalTypes(a, b []*Var) bool {
} }
for i, x := range a { for i, x := range a {
y := b[i] y := b[i]
if !isIdentical(x.Type, y.Type) { if !IsIdentical(x.Type, y.Type) {
return false return false
} }
} }
@ -217,7 +217,7 @@ func identicalMethods(a, b []*Method) bool {
m[x.QualifiedName] = x m[x.QualifiedName] = x
} }
for _, y := range b { for _, y := range b {
if x := m[y.QualifiedName]; x == nil || !isIdentical(x.Type, y.Type) { if x := m[y.QualifiedName]; x == nil || !IsIdentical(x.Type, y.Type) {
return false return false
} }
} }
@ -282,7 +282,7 @@ func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
if ityp, _ := underlying(typ).(*Interface); ityp != nil { if ityp, _ := underlying(typ).(*Interface); ityp != nil {
for _, m := range T.Methods { for _, m := range T.Methods {
mode, sig := lookupField(ityp, m.QualifiedName) // TODO(gri) no need to go via lookupField mode, sig := lookupField(ityp, m.QualifiedName) // TODO(gri) no need to go via lookupField
if mode != invalid && !isIdentical(sig, m.Type) { if mode != invalid && !IsIdentical(sig, m.Type) {
return m, true return m, true
} }
} }
@ -295,7 +295,7 @@ func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
if mode == invalid { if mode == invalid {
return m, false return m, false
} }
if !isIdentical(sig, m.Type) { if !IsIdentical(sig, m.Type) {
return m, true return m, true
} }
} }