mirror of https://github.com/golang/go.git
go/types: improve error message for pointer receiver errors
The compiler produces high quality error messages when an interface is implemented by *T, rather than T. This change improves the analogous error messages in go/types, from "missing method X" to "missing method X (X has pointer receiver)". I am open to improving this message further - I didn't copy the compiler error message exactly because, at one of the call sites of (*check).missingMethod, we no longer have access to the name of the interface. Fixes golang/go#36336 Change-Id: Ic4fc38b13fff9e5d9a69cc750c21e0b0c34d85a8 Reviewed-on: https://go-review.googlesource.com/c/go/+/229801 Run-TryBot: Rebecca Stambler <rstambler@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
da33f9c78a
commit
512277dc19
|
|
@ -1566,10 +1566,13 @@ func (check *Checker) typeAssertion(pos token.Pos, x *operand, xtyp *Interface,
|
|||
if method == nil {
|
||||
return
|
||||
}
|
||||
|
||||
var msg string
|
||||
if wrongType != nil {
|
||||
msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
|
||||
if check.identical(method.typ, wrongType.typ) {
|
||||
msg = fmt.Sprintf("missing method %s (%s has pointer receiver)", method.name, method.name)
|
||||
} else {
|
||||
msg = fmt.Sprintf("wrong type for method %s (have %s, want %s)", method.name, wrongType.typ, method.typ)
|
||||
}
|
||||
} else {
|
||||
msg = "missing method " + method.name
|
||||
}
|
||||
|
|
|
|||
|
|
@ -271,8 +271,10 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
|
|||
// 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.
|
||||
// If the type has the correctly names method, but with the wrong
|
||||
// If the type has the correctly named method, but with the wrong
|
||||
// signature, the existing method is returned as well.
|
||||
// To improve error messages, also report the wrong signature
|
||||
// when the method exists on *V instead of V.
|
||||
func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method, wrongType *Func) {
|
||||
check.completeInterface(T)
|
||||
|
||||
|
|
@ -302,6 +304,15 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
|
|||
for _, m := range T.allMethods {
|
||||
obj, _, _ := check.rawLookupFieldOrMethod(V, false, m.pkg, m.name)
|
||||
|
||||
// Check if *V implements this method of T.
|
||||
if obj == nil {
|
||||
ptr := NewPointer(V)
|
||||
obj, _, _ = check.rawLookupFieldOrMethod(ptr, false, m.pkg, m.name)
|
||||
if obj != nil {
|
||||
return m, obj.(*Func)
|
||||
}
|
||||
}
|
||||
|
||||
// we must have a method (not a field of matching function type)
|
||||
f, _ := obj.(*Func)
|
||||
if f == nil {
|
||||
|
|
|
|||
|
|
@ -266,7 +266,12 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) bool {
|
|||
if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
|
||||
if reason != nil {
|
||||
if wrongType != nil {
|
||||
*reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
|
||||
if check.identical(m.typ, wrongType.typ) {
|
||||
*reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
|
||||
} else {
|
||||
*reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
|
||||
}
|
||||
|
||||
} else {
|
||||
*reason = "missing method " + m.Name()
|
||||
}
|
||||
|
|
|
|||
|
|
@ -130,6 +130,9 @@ func issue10260() {
|
|||
t2 *T2
|
||||
)
|
||||
|
||||
var x I1 = T1 /* ERROR cannot use .*: missing method foo \(foo has pointer receiver\) */ {}
|
||||
_ = x /* ERROR .* cannot have dynamic type T1 \(missing method foo \(foo has pointer receiver\)\) */ .(T1)
|
||||
|
||||
_ = 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 */
|
||||
|
|
@ -355,4 +358,4 @@ func issue35895() {
|
|||
// Because both t1 and t2 have the same global package name (template),
|
||||
// qualify packages with full path name in this case.
|
||||
var _ t1.Template = t2 /* ERROR cannot use .* \(value of type "html/template".Template\) as "text/template".Template */ .Template{}
|
||||
}
|
||||
}
|
||||
|
|
|
|||
Loading…
Reference in New Issue