go.tools/go/types: fix logic error in MissingMethod and type assert code
R=adonovan CC=golang-dev https://golang.org/cl/10448046
This commit is contained in:
parent
decfd079c5
commit
628104465d
|
@ -1564,7 +1564,7 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||
}
|
||||
// x.(type) expressions are handled explicitly in type switches
|
||||
if e.Type == nil {
|
||||
check.errorf(e.Pos(), "use of .(type) outside type switch")
|
||||
check.invalidAST(e.Pos(), "use of .(type) outside type switch")
|
||||
goto Error
|
||||
}
|
||||
typ := check.typ(e.Type, false)
|
||||
|
@ -1575,10 +1575,15 @@ func (check *checker) rawExpr(x *operand, e ast.Expr, hint Type, iota int, cycle
|
|||
var msg string
|
||||
if wrongType {
|
||||
msg = "%s cannot have dynamic type %s (wrong type for method %s)"
|
||||
} else {
|
||||
} else if _, ok := typ.Underlying().(*Interface); !ok {
|
||||
// Concrete types must have all methods of T. Interfaces
|
||||
// may not have all methods of T statically, but may have
|
||||
// them dynamically; don't report an error in that case.
|
||||
msg = "%s cannot have dynamic type %s (missing method %s)"
|
||||
}
|
||||
if msg != "" {
|
||||
check.errorf(e.Type.Pos(), msg, x, typ, method.name)
|
||||
}
|
||||
// ok to continue
|
||||
}
|
||||
x.mode = valueok
|
||||
|
|
|
@ -188,17 +188,21 @@ func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) {
|
|||
return
|
||||
}
|
||||
|
||||
// An interface type implements T if it has at least the methods of T.
|
||||
if ityp, _ := typ.Underlying().(*Interface); ityp != nil {
|
||||
for _, m := range T.methods {
|
||||
_, obj := lookupMethod(ityp.methods, m.pkg, m.name)
|
||||
if obj != nil && !IsIdentical(obj.Type(), m.typ) {
|
||||
if obj == nil {
|
||||
return m, false
|
||||
}
|
||||
if !IsIdentical(obj.Type(), m.typ) {
|
||||
return m, true
|
||||
}
|
||||
}
|
||||
return
|
||||
}
|
||||
|
||||
// a concrete type implements T if it implements all methods of T.
|
||||
// A concrete type implements T if it implements all methods of T.
|
||||
for _, m := range T.methods {
|
||||
obj, _, indirect := LookupFieldOrMethod(typ, m.pkg, m.name)
|
||||
if obj == nil {
|
||||
|
@ -222,6 +226,7 @@ func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) {
|
|||
return m, true
|
||||
}
|
||||
}
|
||||
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -34,3 +34,35 @@ func string_conversions() {
|
|||
var (
|
||||
_ = int8(0)
|
||||
)
|
||||
|
||||
func interface_conversions() {
|
||||
type E interface{}
|
||||
|
||||
type I1 interface{
|
||||
m1()
|
||||
}
|
||||
|
||||
type I2 interface{
|
||||
m1()
|
||||
m2()
|
||||
}
|
||||
|
||||
var e E
|
||||
var i1 I1
|
||||
var i2 I2
|
||||
_ = E(0)
|
||||
_ = E(nil)
|
||||
_ = E(e)
|
||||
_ = E(i1)
|
||||
_ = E(i2)
|
||||
|
||||
_ = I1 /* ERROR "cannot convert" */ (0)
|
||||
_ = I1(nil)
|
||||
_ = I1(i1)
|
||||
_ = I1 /* ERROR "cannot convert" */ (e)
|
||||
_ = I1(i2)
|
||||
|
||||
_ = I2 /* ERROR "cannot convert" */ (i1)
|
||||
|
||||
// TODO(gri) add more tests, improve error message
|
||||
}
|
|
@ -281,6 +281,9 @@ func type_asserts() {
|
|||
_ = t.(T1 /* ERROR "missing method m" */ )
|
||||
_ = t.(T2 /* ERROR "wrong type for method m" */ )
|
||||
_ = t.(I2 /* ERROR "wrong type for method m" */ )
|
||||
|
||||
// e doesn't statically have an m, but may have one dynamically.
|
||||
_ = e.(I2)
|
||||
}
|
||||
|
||||
func f0() {}
|
||||
|
|
Loading…
Reference in New Issue