]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: combine missingMethodCause with missingMethod
authorRobert Griesemer <gri@golang.org>
Wed, 1 Mar 2023 21:53:48 +0000 (13:53 -0800)
committerGopher Robot <gobot@golang.org>
Thu, 2 Mar 2023 14:47:20 +0000 (14:47 +0000)
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>

src/cmd/compile/internal/types2/lookup.go
src/go/types/lookup.go

index 7c20a28136260235d5c62fdef65b7f52460a5016..216bed97343bfad9b3469a21cffd514ccf914622 100644 (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 {
index 09597888992d20a1566fc716b1c649132edfdbdb..66e28ee6cbb38465ba6b3f4d08f94319a1f44b77 100644 (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 {