go.tools/go/types: fix isAssignable and IsIdentical

- Imported objects that are explicitly exported may have a nil package;
  don't use it for qualified name computation (it's not needed).
- isAssignable must check all possibilities before declaring failure.

Fixes golang/go#5675.

R=adonovan
CC=golang-dev
https://golang.org/cl/10141044
This commit is contained in:
Robert Griesemer 2013-06-11 10:00:00 -07:00
parent 63f3103b6f
commit 0d2f7d411b
2 changed files with 28 additions and 11 deletions

View File

@ -139,19 +139,20 @@ func (x *operand) isAssignable(ctxt *Context, T Type) bool {
Vu := V.Underlying()
Tu := T.Underlying()
// 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) {
return !isNamed(V) || !isNamed(T)
}
// T is an interface type and x implements T
// (Do this check first as it might succeed early.)
if Ti, ok := Tu.(*Interface); ok {
if m, _ := missingMethod(x.typ, Ti); m == nil {
return true
}
}
// 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) && (!isNamed(V) || !isNamed(T)) {
return true
}
// x is a bidirectional channel value, T is a channel
// type, x's type V and T have identical element types,
// and at least one of V or T is not a named type

View File

@ -6,6 +6,8 @@
package types
import "go/ast"
func isNamed(typ Type) bool {
if _, ok := typ.(*Basic); ok {
return ok
@ -211,6 +213,19 @@ func identicalTypes(a, b *Tuple) bool {
return true
}
// qname computes the "qualified name" of a function.
// TODO(gri) This is similar in functionality to Field.isMatch.
// Try to consolidate.
func qname(f *Func) string {
if ast.IsExported(f.name) {
return f.name
}
if f.pkg == nil {
panic("unexported function without package information")
}
return f.pkg.path + "." + f.name
}
// identicalMethods returns true if both object sets a and b have the
// same length and corresponding methods have identical types.
// TODO(gri) make this more efficient (e.g., sort them on completion)
@ -226,14 +241,15 @@ func identicalMethods(a, b *Scope) bool {
m := make(map[string]*Func)
for _, obj := range a.entries {
x := obj.(*Func)
qname := x.pkg.path + "." + x.name
assert(m[qname] == nil) // method list must not have duplicate entries
m[qname] = x
k := qname(x)
assert(m[k] == nil) // method list must not have duplicate entries
m[k] = x
}
for _, obj := range b.entries {
y := obj.(*Func)
qname := y.pkg.path + "." + y.name
if x := m[qname]; x == nil || !IsIdentical(x.typ, y.typ) {
k := qname(y)
if x := m[k]; x == nil || !IsIdentical(x.typ, y.typ) {
return false
}
}