diff --git a/src/go/types/expr.go b/src/go/types/expr.go index 165778c2f7..f88b2389c6 100644 --- a/src/go/types/expr.go +++ b/src/go/types/expr.go @@ -1568,12 +1568,12 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface, } var msg string - if wrongType { - msg = "wrong type for method" + if wrongType != nil { + msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ) } else { - msg = "missing method" + msg = "missing method " + method.name } - check.errorf(pos, "%s cannot have dynamic type %s (%s %s)", x, T, msg, method.name) + check.errorf(pos, "%s cannot have dynamic type %s (%s)", x, T, msg) } func (check *Checker) singleValue(x *operand) { diff --git a/src/go/types/lookup.go b/src/go/types/lookup.go index 342c8baab2..d774dd5d5c 100644 --- a/src/go/types/lookup.go +++ b/src/go/types/lookup.go @@ -263,14 +263,17 @@ func (check *Checker) lookupType(m map[Type]int, typ Type) (int, bool) { // x is of interface type V). // func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) { - return (*Checker)(nil).missingMethod(V, T, static) + m, typ := (*Checker)(nil).missingMethod(V, T, static) + return m, typ != nil } // missingMethod is like MissingMethod but accepts a receiver. // The receiver may be nil if missingMethod is invoked through // an exported API call (such as MissingMethod), i.e., when all // methods have been type-checked. -func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) { +// If the type has the correctly names method, but with the wrong +// signature, the existing method is returned as well. +func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) { check.completeInterface(T) // fast path for common case @@ -286,10 +289,10 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method * switch { case obj == nil: if static { - return m, false + return m, nil } case !check.identical(obj.Type(), m.typ): - return m, true + return m, obj } } return @@ -302,7 +305,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method * // we must have a method (not a field of matching function type) f, _ := obj.(*Func) if f == nil { - return m, false + return m, nil } // methods may not have a fully set up signature yet @@ -311,7 +314,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method * } if !check.identical(f.typ, m.typ) { - return m, true + return m, f } } @@ -323,7 +326,7 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method * // method required by V and whether it is missing or just has the wrong type. // The receiver may be nil if assertableTo is invoked through an exported API call // (such as AssertableTo), i.e., when all methods have been type-checked. -func (check *Checker) assertableTo(V *Interface, T Type) (method *Func, wrongType bool) { +func (check *Checker) assertableTo(V *Interface, T Type) (method, wrongType *Func) { // no static check is required if T is an interface // spec: "If T is an interface type, x.(T) asserts that the // dynamic type of x implements the interface T." diff --git a/src/go/types/operand.go b/src/go/types/operand.go index d0e7531d4f..a762ad9bc8 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -8,6 +8,7 @@ package types import ( "bytes" + "fmt" "go/ast" "go/constant" "go/token" @@ -254,8 +255,8 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool { if Ti, ok := Tu.(*Interface); ok { if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ { if reason != nil { - if wrongType { - *reason = "wrong type for method " + m.Name() + if wrongType != nil { + *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ) } else { *reason = "missing method " + m.Name() } diff --git a/src/go/types/testdata/issues.src b/src/go/types/testdata/issues.src index fe2407999c..f8d037b99e 100644 --- a/src/go/types/testdata/issues.src +++ b/src/go/types/testdata/issues.src @@ -129,6 +129,9 @@ func issue10260() { t1 *T1 t2 *T2 ) + + _ = i2 /* ERROR i2 .* cannot have dynamic type \*T1 \(wrong type for method foo \(have func\(\), want func\(x int\)\)\) */ .(*T1) + i1 = i0 /* ERROR cannot use .* missing method foo */ i1 = t0 /* ERROR cannot use .* missing method foo */ i1 = i2 /* ERROR cannot use .* wrong type for method foo */ @@ -146,7 +149,7 @@ func issue10260() { // a few more - less exhaustive now f := func(I1, I2){} - f(i0 /* ERROR cannot use .* missing method foo */ , i1 /* ERROR cannot use .* wrong type for method foo */) + f(i0 /* ERROR cannot use .* missing method foo */ , i1 /* ERROR cannot use .* wrong type for method foo \(have func\(\), want func\(x int\)\) */ ) _ = [...]I1{i0 /* ERROR cannot use .* missing method foo */ } _ = [...]I1{i2 /* ERROR cannot use .* wrong type for method foo */ }