]> Cypherpunks.ru repositories - gostls13.git/commitdiff
go/types, types2: simplify missingMethodReason
authorRobert Griesemer <gri@golang.org>
Thu, 3 Feb 2022 05:36:50 +0000 (21:36 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 4 Feb 2022 23:42:47 +0000 (23:42 +0000)
Added a funcString helper so we don't need to rewrite strings
with strings.Replace.

Use compiler format for error message about wrong method type;
this removes another unnecessary variation.

Simplify conditions for pointer-to-interface related error:
if one of the involved types is an interface pointer, it can't
have any methods.

Rewrite logic so we don't need all the else-if branches.

Adjusted a test case for types2 accordingly. The go/types version
of this test case has a different error because the implementation
of Checker.typeAssertion is different in the two type checkers
(the types2 version gives errors closer to the 1.17 compiler).

Change-Id: I19e604d7063c3e31e8290bd78384a9f38bb0d740
Reviewed-on: https://go-review.googlesource.com/c/go/+/382694
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/lookup.go
src/cmd/compile/internal/types2/testdata/check/issues.src
src/go/types/lookup.go

index fc6b34941ab11c8e71e15222df2471d92b2b5b2d..1aeb2beaa02a3f9dd445f79eafb90c1a194b4615 100644 (file)
@@ -7,6 +7,7 @@
 package types2
 
 import (
+       "bytes"
        "strings"
 )
 
@@ -364,48 +365,40 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
 
 // missingMethodReason returns a string giving the detailed reason for a missing method m,
 // where m is missing from V, but required by T. It puts the reason in parentheses,
-// and may include more have/want info after that. If non-nil, wrongType is a relevant
+// 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.
-func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string {
-       var r string
+func (check *Checker) missingMethodReason(V, T Type, m, alt *Func) string {
        var mname string
        if check.conf.CompilerErrorMessages {
                mname = m.Name() + " method"
        } else {
                mname = "method " + m.Name()
        }
-       if wrongType != nil {
-               if m.Name() != wrongType.Name() {
-                       r = check.sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
-                               mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
-               } else if Identical(m.typ, wrongType.typ) {
-                       r = check.sprintf("(%s has pointer receiver)", mname)
-               } else {
-                       if check.conf.CompilerErrorMessages {
-                               r = check.sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
-                                       mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
-                       } else {
-                               r = check.sprintf("(wrong type for %s)\n\thave %s\n\twant %s",
-                                       mname, wrongType.typ, m.typ)
-                       }
+
+       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), check.funcString(m))
                }
-               // This is a hack to print the function type without the leading
-               // 'func' keyword in the have/want printouts. We could change to have
-               // an extra formatting option for types2.Type that doesn't print out
-               // 'func'.
-               r = strings.Replace(r, "^^func", "", -1)
-       } else if IsInterface(T) {
-               if isInterfacePtr(V) {
-                       r = "(" + check.interfacePtrError(V) + ")"
+
+               if Identical(m.typ, alt.typ) {
+                       return check.sprintf("(%s has pointer receiver)", mname)
                }
-       } else if isInterfacePtr(T) {
-               r = "(" + check.interfacePtrError(T) + ")"
+
+               return check.sprintf("(wrong type for %s)\n\t\thave %s\n\t\twant %s",
+                       mname, check.funcString(alt), check.funcString(m))
        }
-       if r == "" {
-               r = check.sprintf("(missing %s)", mname)
+
+       if isInterfacePtr(V) {
+               return "(" + check.interfacePtrError(V) + ")"
        }
-       return r
+
+       if isInterfacePtr(T) {
+               return "(" + check.interfacePtrError(T) + ")"
+       }
+
+       return check.sprintf("(missing %s)", mname)
 }
 
 func isInterfacePtr(T Type) bool {
@@ -421,6 +414,13 @@ func (check *Checker) interfacePtrError(T Type) string {
        return check.sprintf("type %s is pointer to interface, not interface", T)
 }
 
+// funcString returns a string of the form name + signature for f.
+func (check *Checker) funcString(f *Func) string {
+       buf := bytes.NewBufferString(f.name)
+       WriteSignature(buf, f.typ.(*Signature), check.qualifier)
+       return buf.String()
+}
+
 // assertableTo reports whether a value of type V can be asserted to have type T.
 // It returns (nil, false) as affirmative answer. Otherwise it returns a missing
 // method required by V and whether it is missing or just has the wrong type.
index a19f99b31a31455abfdd0b4697801400f41e75f0..4c49147922623ce040800c689a10b416f1c7f9df 100644 (file)
@@ -137,7 +137,7 @@ func issue10260() {
        T1{}.foo /* ERROR cannot call pointer method foo on T1 */ ()
        x.Foo /* ERROR "x.Foo undefined \(type I1 has no field or method Foo, but does have foo\)" */ ()
 
-       _ = i2. /* ERROR impossible type assertion: i2.\(\*T1\)\n\t\*T1 does not implement I2 \(wrong type for method foo\)\n\thave func\(\)\n\twant func\(x int\) */ (*T1)
+       _ = i2. /* ERROR impossible type assertion: i2\.\(\*T1\)\n\t\*T1 does not implement I2 \(wrong type for method foo\)\n\t\thave foo\(\)\n\t\twant foo\(x int\) */ (*T1)
 
        i1 = i0 /* ERROR cannot use .* missing method foo */
        i1 = t0 /* ERROR cannot use .* missing method foo */
index 77e8fe9df50713a1d4eded63f11d8d11094acaa7..1b4f953803100df4ff298f009d7a0b32637081a8 100644 (file)
@@ -7,6 +7,7 @@
 package types
 
 import (
+       "bytes"
        "strings"
 )
 
@@ -366,50 +367,40 @@ func (check *Checker) missingMethod(V Type, T *Interface, static bool) (method,
 
 // missingMethodReason returns a string giving the detailed reason for a missing method m,
 // where m is missing from V, but required by T. It puts the reason in parentheses,
-// and may include more have/want info after that. If non-nil, wrongType is a relevant
+// 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.
-func (check *Checker) missingMethodReason(V, T Type, m, wrongType *Func) string {
-       var r string
+// it may have a pointer receiver, or it may have the correct name except wrong case.
+func (check *Checker) missingMethodReason(V, T Type, m, alt *Func) string {
        var mname string
        if compilerErrorMessages {
                mname = m.Name() + " method"
        } else {
                mname = "method " + m.Name()
        }
-       if wrongType != nil {
-               if m.Name() != wrongType.Name() {
-                       // Note: this case can't happen because we don't look for alternative
-                       // method spellings, unlike types2. Keep for symmetry with types2.
-                       r = check.sprintf("(missing %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
-                               mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
-               } else if Identical(m.typ, wrongType.typ) {
-                       r = check.sprintf("(%s has pointer receiver)", mname)
-               } else {
-                       if compilerErrorMessages {
-                               r = check.sprintf("(wrong type for %s)\n\t\thave %s^^%s\n\t\twant %s^^%s",
-                                       mname, wrongType.Name(), wrongType.typ, m.Name(), m.typ)
-                       } else {
-                               r = check.sprintf("(wrong type for %s)\n\thave %s\n\twant %s",
-                                       mname, wrongType.typ, m.typ)
-                       }
+
+       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), check.funcString(m))
                }
-               // This is a hack to print the function type without the leading
-               // 'func' keyword in the have/want printouts. We could change to have
-               // an extra formatting option for types2.Type that doesn't print out
-               // 'func'.
-               r = strings.Replace(r, "^^func", "", -1)
-       } else if IsInterface(T) {
-               if isInterfacePtr(V) {
-                       r = "(" + check.interfacePtrError(V) + ")"
+
+               if Identical(m.typ, alt.typ) {
+                       return check.sprintf("(%s has pointer receiver)", mname)
                }
-       } else if isInterfacePtr(T) {
-               r = "(" + check.interfacePtrError(T) + ")"
+
+               return check.sprintf("(wrong type for %s)\n\t\thave %s\n\t\twant %s",
+                       mname, check.funcString(alt), check.funcString(m))
        }
-       if r == "" {
-               r = check.sprintf("(missing %s)", mname)
+
+       if isInterfacePtr(V) {
+               return "(" + check.interfacePtrError(V) + ")"
        }
-       return r
+
+       if isInterfacePtr(T) {
+               return "(" + check.interfacePtrError(T) + ")"
+       }
+
+       return check.sprintf("(missing %s)", mname)
 }
 
 func isInterfacePtr(T Type) bool {
@@ -425,6 +416,13 @@ func (check *Checker) interfacePtrError(T Type) string {
        return check.sprintf("type %s is pointer to interface, not interface", T)
 }
 
+// funcString returns a string of the form name + signature for f.
+func (check *Checker) funcString(f *Func) string {
+       buf := bytes.NewBufferString(f.name)
+       WriteSignature(buf, f.typ.(*Signature), check.qualifier)
+       return buf.String()
+}
+
 // assertableTo reports whether a value of type V can be asserted to have type T.
 // It returns (nil, false) as affirmative answer. Otherwise it returns a missing
 // method required by V and whether it is missing or just has the wrong type.