1
0
mirror of https://github.com/golang/go synced 2024-11-17 19:04:47 -07:00

go/types, types2: combine missingMethodCause with missingMethod

For now this is simply a mechanical combination without any
relevant logic changes. This will make it easier to review
subsequent changes.

Change-Id: Ic2e2ae32b031d2dda0f69a08a5cc2349748bd25d
Reviewed-on: https://go-review.googlesource.com/c/go/+/472675
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Findley <rfindley@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Auto-Submit: Robert Griesemer <gri@google.com>
This commit is contained in:
Robert Griesemer 2023-03-01 13:53:48 -08:00 committed by Gopher Robot
parent ad461f3261
commit 2f9e38a1be
2 changed files with 82 additions and 84 deletions

View File

@ -323,14 +323,7 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
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 {
@ -342,16 +335,18 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
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
@ -372,7 +367,8 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
// 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
@ -381,60 +377,63 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
}
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 {

View File

@ -325,14 +325,7 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
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 {
@ -344,16 +337,18 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
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
@ -374,7 +369,8 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
// 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
@ -383,60 +379,63 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
}
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 {