}
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) {
// 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
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
// 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
}
if !check.identical(f.typ, m.typ) {
- return m, true
+ return m, f
}
}
// 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."
import (
"bytes"
+ "fmt"
"go/ast"
"go/constant"
"go/token"
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()
}
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 */
// 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 */ }