return
}
- var alt *Func
- if cause != nil {
- defer func() {
- if method != nil {
- *cause = check.missingMethodCause(V, T, method, alt)
- }
- }()
- }
+ var alt *Func // alternative method (pointer receiver or similar spelling)
// V is an interface
if u, _ := under(V).(*Interface); u != nil {
if !static {
continue
}
- return m, false
+ method = m
+ goto Error
}
if !equivalent(f.typ, m.typ) {
- alt = f
- return m, true
+ method, alt = m, f
+ wrongType = true
+ goto Error
}
}
- return
+ return nil, false
}
// V is not an interface
// we must have a method (not a struct field)
f, _ := obj.(*Func)
if f == nil {
- return m, false
+ method = m
+ goto Error
}
// methods may not have a fully set up signature yet
}
if !found || !equivalent(f.typ, m.typ) {
- alt = f
- return m, f.name == m.name
+ method, alt = m, f
+ wrongType = f.name == m.name
+ goto Error
}
}
- return
-}
+ return nil, false
-// missingMethodCause returns a string giving the detailed cause for a missing method m,
-// where m is missing from V, but required by T. It puts the cause in parentheses,
-// and may include more have/want info after that. If non-nil, alt is a relevant
-// method that matches in some way. It may have the correct name, but wrong type, or
-// it may have a pointer receiver, or it may have the correct name except wrong case.
-// check may be nil.
-// missingMethodCause should only be called by missingMethod.
-// TODO(gri) integrate this logic into missingMethod and get rid of this function.
-func (check *Checker) missingMethodCause(V, T Type, m, alt *Func) string {
- mname := "method " + m.Name()
+Error:
+ if cause == nil {
+ return
+ }
+
+ mname := "method " + method.Name()
if alt != nil {
- if m.Name() != alt.Name() {
- return check.sprintf("(missing %s)\n\t\thave %s\n\t\twant %s",
- mname, check.funcString(alt, false), check.funcString(m, false))
+ if method.Name() != alt.Name() {
+ *cause = check.sprintf("(missing %s)\n\t\thave %s\n\t\twant %s",
+ mname, check.funcString(alt, false), check.funcString(method, false))
+ return
}
- if Identical(m.typ, alt.typ) {
- return check.sprintf("(%s has pointer receiver)", mname)
+ if Identical(method.typ, alt.typ) {
+ *cause = check.sprintf("(%s has pointer receiver)", mname)
+ return
}
- altS, mS := check.funcString(alt, false), check.funcString(m, false)
- if altS == mS {
+ altS, methodS := check.funcString(alt, false), check.funcString(method, false)
+ if altS == methodS {
// Would tell the user that Foo isn't a Foo, add package information to disambiguate.
// See go.dev/issue/54258.
- altS, mS = check.funcString(alt, true), check.funcString(m, true)
+ altS, methodS = check.funcString(alt, true), check.funcString(method, true)
}
- return check.sprintf("(wrong type for %s)\n\t\thave %s\n\t\twant %s",
- mname, altS, mS)
+ *cause = check.sprintf("(wrong type for %s)\n\t\thave %s\n\t\twant %s",
+ mname, altS, methodS)
+ return
}
if isInterfacePtr(V) {
- return "(" + check.interfacePtrError(V) + ")"
+ *cause = "(" + check.interfacePtrError(V) + ")"
+ return
}
if isInterfacePtr(T) {
- return "(" + check.interfacePtrError(T) + ")"
+ *cause = "(" + check.interfacePtrError(T) + ")"
+ return
}
- obj, _, _ := lookupFieldOrMethod(V, true /* auto-deref */, m.pkg, m.name, false)
+ obj, _, _ := lookupFieldOrMethod(V, true /* auto-deref */, method.pkg, method.name, false)
if fld, _ := obj.(*Var); fld != nil {
- return check.sprintf("(%s.%s is a field, not a method)", V, fld.Name())
+ *cause = check.sprintf("(%s.%s is a field, not a method)", V, fld.Name())
+ return
}
- return check.sprintf("(missing %s)", mname)
+ *cause = check.sprintf("(missing %s)", mname)
+ return
}
func isInterfacePtr(T Type) bool {
return
}
- var alt *Func
- if cause != nil {
- defer func() {
- if method != nil {
- *cause = check.missingMethodCause(V, T, method, alt)
- }
- }()
- }
+ var alt *Func // alternative method (pointer receiver or similar spelling)
// V is an interface
if u, _ := under(V).(*Interface); u != nil {
if !static {
continue
}
- return m, false
+ method = m
+ goto Error
}
if !equivalent(f.typ, m.typ) {
- alt = f
- return m, true
+ method, alt = m, f
+ wrongType = true
+ goto Error
}
}
- return
+ return nil, false
}
// V is not an interface
// we must have a method (not a struct field)
f, _ := obj.(*Func)
if f == nil {
- return m, false
+ method = m
+ goto Error
}
// methods may not have a fully set up signature yet
}
if !found || !equivalent(f.typ, m.typ) {
- alt = f
- return m, f.name == m.name
+ method, alt = m, f
+ wrongType = f.name == m.name
+ goto Error
}
}
- return
-}
+ return nil, false
-// missingMethodCause returns a string giving the detailed cause for a missing method m,
-// where m is missing from V, but required by T. It puts the cause in parentheses,
-// and may include more have/want info after that. If non-nil, alt is a relevant
-// method that matches in some way. It may have the correct name, but wrong type, or
-// it may have a pointer receiver, or it may have the correct name except wrong case.
-// check may be nil.
-// missingMethodCause should only be called by missingMethod.
-// TODO(gri) integrate this logic into missingMethod and get rid of this function.
-func (check *Checker) missingMethodCause(V, T Type, m, alt *Func) string {
- mname := "method " + m.Name()
+Error:
+ if cause == nil {
+ return
+ }
+
+ mname := "method " + method.Name()
if alt != nil {
- if m.Name() != alt.Name() {
- return check.sprintf("(missing %s)\n\t\thave %s\n\t\twant %s",
- mname, check.funcString(alt, false), check.funcString(m, false))
+ if method.Name() != alt.Name() {
+ *cause = check.sprintf("(missing %s)\n\t\thave %s\n\t\twant %s",
+ mname, check.funcString(alt, false), check.funcString(method, false))
+ return
}
- if Identical(m.typ, alt.typ) {
- return check.sprintf("(%s has pointer receiver)", mname)
+ if Identical(method.typ, alt.typ) {
+ *cause = check.sprintf("(%s has pointer receiver)", mname)
+ return
}
- altS, mS := check.funcString(alt, false), check.funcString(m, false)
- if altS == mS {
+ altS, methodS := check.funcString(alt, false), check.funcString(method, false)
+ if altS == methodS {
// Would tell the user that Foo isn't a Foo, add package information to disambiguate.
// See go.dev/issue/54258.
- altS, mS = check.funcString(alt, true), check.funcString(m, true)
+ altS, methodS = check.funcString(alt, true), check.funcString(method, true)
}
- return check.sprintf("(wrong type for %s)\n\t\thave %s\n\t\twant %s",
- mname, altS, mS)
+ *cause = check.sprintf("(wrong type for %s)\n\t\thave %s\n\t\twant %s",
+ mname, altS, methodS)
+ return
}
if isInterfacePtr(V) {
- return "(" + check.interfacePtrError(V) + ")"
+ *cause = "(" + check.interfacePtrError(V) + ")"
+ return
}
if isInterfacePtr(T) {
- return "(" + check.interfacePtrError(T) + ")"
+ *cause = "(" + check.interfacePtrError(T) + ")"
+ return
}
- obj, _, _ := lookupFieldOrMethod(V, true /* auto-deref */, m.pkg, m.name, false)
+ obj, _, _ := lookupFieldOrMethod(V, true /* auto-deref */, method.pkg, method.name, false)
if fld, _ := obj.(*Var); fld != nil {
- return check.sprintf("(%s.%s is a field, not a method)", V, fld.Name())
+ *cause = check.sprintf("(%s.%s is a field, not a method)", V, fld.Name())
+ return
}
- return check.sprintf("(missing %s)", mname)
+ *cause = check.sprintf("(missing %s)", mname)
+ return
}
func isInterfacePtr(T Type) bool {