mirror of
https://github.com/golang/go
synced 2024-11-18 17:14:45 -07: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:
parent
f8fb95f288
commit
0cbf289b36
@ -142,7 +142,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
|
||||
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)
|
||||
goto Error
|
||||
}
|
||||
@ -191,7 +191,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, bin *builtin, iota
|
||||
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)
|
||||
goto Error
|
||||
}
|
||||
|
@ -58,14 +58,14 @@ func (x *operand) isConvertible(T Type) bool {
|
||||
V := x.typ
|
||||
Vu := underlying(V)
|
||||
Tu := underlying(T)
|
||||
if isIdentical(Vu, Tu) {
|
||||
if IsIdentical(Vu, Tu) {
|
||||
return true
|
||||
}
|
||||
|
||||
// "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 T, ok := T.(*Pointer); ok {
|
||||
if isIdentical(underlying(V.Base), underlying(T.Base)) {
|
||||
if IsIdentical(underlying(V.Base), underlying(T.Base)) {
|
||||
return true
|
||||
}
|
||||
}
|
||||
|
@ -444,7 +444,7 @@ func (check *checker) binary(x, y *operand, op token.Token, hint Type) {
|
||||
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)
|
||||
x.mode = invalid
|
||||
return
|
||||
|
@ -137,7 +137,7 @@ func (x *operand) isAssignable(T Type) bool {
|
||||
V := x.typ
|
||||
|
||||
// x's type is identical to T
|
||||
if isIdentical(V, T) {
|
||||
if IsIdentical(V, T) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -146,7 +146,7 @@ func (x *operand) isAssignable(T Type) bool {
|
||||
|
||||
// x's type V and T have identical underlying types
|
||||
// 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)
|
||||
}
|
||||
|
||||
@ -161,7 +161,7 @@ func (x *operand) isAssignable(T Type) bool {
|
||||
// type, x's type V and T have identical element types,
|
||||
// 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 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)
|
||||
}
|
||||
}
|
||||
|
@ -92,8 +92,8 @@ func hasNil(typ Type) bool {
|
||||
return false
|
||||
}
|
||||
|
||||
// identical returns true if x and y are identical.
|
||||
func isIdentical(x, y Type) bool {
|
||||
// IsIdentical returns true if x and y are identical.
|
||||
func IsIdentical(x, y Type) bool {
|
||||
if x == y {
|
||||
return true
|
||||
}
|
||||
@ -111,13 +111,13 @@ func isIdentical(x, y Type) bool {
|
||||
// Two array types are identical if they have identical element types
|
||||
// and the same array length.
|
||||
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:
|
||||
// Two slice types are identical if they have identical element types.
|
||||
if y, ok := y.(*Slice); ok {
|
||||
return isIdentical(x.Elt, y.Elt)
|
||||
return IsIdentical(x.Elt, y.Elt)
|
||||
}
|
||||
|
||||
case *Struct:
|
||||
@ -130,7 +130,7 @@ func isIdentical(x, y Type) bool {
|
||||
for i, f := range x.Fields {
|
||||
g := y.Fields[i]
|
||||
if !f.QualifiedName.IsSame(g.QualifiedName) ||
|
||||
!isIdentical(f.Type, g.Type) ||
|
||||
!IsIdentical(f.Type, g.Type) ||
|
||||
f.Tag != g.Tag ||
|
||||
f.IsAnonymous != g.IsAnonymous {
|
||||
return false
|
||||
@ -143,7 +143,7 @@ func isIdentical(x, y Type) bool {
|
||||
case *Pointer:
|
||||
// Two pointer types are identical if they have identical base types.
|
||||
if y, ok := y.(*Pointer); ok {
|
||||
return isIdentical(x.Base, y.Base)
|
||||
return IsIdentical(x.Base, y.Base)
|
||||
}
|
||||
|
||||
case *Signature:
|
||||
@ -168,14 +168,14 @@ func isIdentical(x, y Type) bool {
|
||||
case *Map:
|
||||
// Two map types are identical if they have identical key and value types.
|
||||
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:
|
||||
// Two channel types are identical if they have identical value types
|
||||
// and the same direction.
|
||||
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:
|
||||
@ -197,7 +197,7 @@ func identicalTypes(a, b []*Var) bool {
|
||||
}
|
||||
for i, x := range a {
|
||||
y := b[i]
|
||||
if !isIdentical(x.Type, y.Type) {
|
||||
if !IsIdentical(x.Type, y.Type) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
@ -217,7 +217,7 @@ func identicalMethods(a, b []*Method) bool {
|
||||
m[x.QualifiedName] = x
|
||||
}
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -282,7 +282,7 @@ func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
|
||||
if ityp, _ := underlying(typ).(*Interface); ityp != nil {
|
||||
for _, m := range T.Methods {
|
||||
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
|
||||
}
|
||||
}
|
||||
@ -295,7 +295,7 @@ func missingMethod(typ Type, T *Interface) (method *Method, wrongType bool) {
|
||||
if mode == invalid {
|
||||
return m, false
|
||||
}
|
||||
if !isIdentical(sig, m.Type) {
|
||||
if !IsIdentical(sig, m.Type) {
|
||||
return m, true
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user