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:
Robert Griesemer 2013-06-21 14:30:47 -07:00
parent decfd079c5
commit 628104465d
4 changed files with 51 additions and 6 deletions

View File

@ -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 // x.(type) expressions are handled explicitly in type switches
if e.Type == nil { 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 goto Error
} }
typ := check.typ(e.Type, false) 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 var msg string
if wrongType { if wrongType {
msg = "%s cannot have dynamic type %s (wrong type for method %s)" 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)" msg = "%s cannot have dynamic type %s (missing method %s)"
} }
check.errorf(e.Type.Pos(), msg, x, typ, method.name) if msg != "" {
check.errorf(e.Type.Pos(), msg, x, typ, method.name)
}
// ok to continue // ok to continue
} }
x.mode = valueok x.mode = valueok

View File

@ -188,17 +188,21 @@ func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) {
return return
} }
// An interface type implements T if it has at least the methods of T.
if ityp, _ := typ.Underlying().(*Interface); ityp != nil { if ityp, _ := typ.Underlying().(*Interface); ityp != nil {
for _, m := range T.methods { for _, m := range T.methods {
_, obj := lookupMethod(ityp.methods, m.pkg, m.name) _, 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 m, true
} }
} }
return 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 { for _, m := range T.methods {
obj, _, indirect := LookupFieldOrMethod(typ, m.pkg, m.name) obj, _, indirect := LookupFieldOrMethod(typ, m.pkg, m.name)
if obj == nil { if obj == nil {
@ -222,6 +226,7 @@ func MissingMethod(typ Type, T *Interface) (method *Func, wrongType bool) {
return m, true return m, true
} }
} }
return return
} }

View File

@ -33,4 +33,36 @@ func string_conversions() {
// //
var ( var (
_ = int8(0) _ = 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
}

View File

@ -281,6 +281,9 @@ func type_asserts() {
_ = t.(T1 /* ERROR "missing method m" */ ) _ = t.(T1 /* ERROR "missing method m" */ )
_ = t.(T2 /* ERROR "wrong type for method m" */ ) _ = t.(T2 /* ERROR "wrong type for method m" */ )
_ = t.(I2 /* 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() {} func f0() {}