]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: change missingMethod to match MissingMethod signature
authorRobert Griesemer <gri@golang.org>
Wed, 1 Mar 2023 16:06:42 +0000 (08:06 -0800)
committerGopher Robot <gobot@golang.org>
Wed, 1 Mar 2023 21:23:56 +0000 (21:23 +0000)
This simplifies the use of missingMethod and also opens the door to
further missingMethod-internal simplifications.

Change-Id: I74d9694b6fca67c4103aea04d08916a69ad0e3c5
Reviewed-on: https://go-review.googlesource.com/c/go/+/472495
Reviewed-by: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>

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

index 0abb3fa3b5dc970b251809b73e9ab3de6569bc2b..2baa80c4faab3cb4c331c9e2feb9a6a06edb3aae 100644 (file)
@@ -1795,8 +1795,7 @@ func keyVal(x constant.Value) interface{} {
 // typeAssertion checks x.(T). The type of x must be an interface.
 func (check *Checker) typeAssertion(e syntax.Expr, x *operand, T Type, typeSwitch bool) {
        var cause string
-       method, _ := check.assertableTo(x.typ, T, &cause)
-       if method == nil {
+       if check.assertableTo(x.typ, T, &cause) {
                return // success
        }
 
index be0e6b44293bd0d9bd05a839241fe3373f647981..7c20a28136260235d5c62fdef65b7f52460a5016 100644 (file)
@@ -305,9 +305,7 @@ func (l *instanceLookup) add(inst *Named) {
 // present in V have matching types (e.g., for a type assertion x.(T) where
 // x is of interface type V).
 func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
-       m, alt := (*Checker)(nil).missingMethod(V, T, static, Identical, nil)
-       // Only report a wrong type if the alternative method has the same name as m.
-       return m, alt != nil && alt.name == m.name // alt != nil implies m != nil
+       return (*Checker)(nil).missingMethod(V, T, static, Identical, nil)
 }
 
 // missingMethod is like MissingMethod but accepts a *Checker as receiver,
@@ -318,17 +316,14 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
 // The underlying type of T must be an interface; T (rather than its under-
 // lying type) is used for better error messages (reported through *cause).
 // The comparator is used to compare signatures.
-// If a method is missing and cause is not nil, *cause is set to the error cause.
-//
-// If a method is missing on T but is found on *T, or if a method is found
-// on T when looked up with case-folding, this alternative method is returned
-// as the second result.
-func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y Type) bool, cause *string) (method, alt *Func) {
+// If a method is missing and cause is not nil, *cause describes the error.
+func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y Type) bool, cause *string) (method *Func, wrongType bool) {
        methods := under(T).(*Interface).typeSet().methods // T must be an interface
        if len(methods) == 0 {
                return
        }
 
+       var alt *Func
        if cause != nil {
                defer func() {
                        if method != nil {
@@ -347,11 +342,12 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
                                if !static {
                                        continue
                                }
-                               return m, nil
+                               return m, false
                        }
 
                        if !equivalent(f.typ, m.typ) {
-                               return m, f
+                               alt = f
+                               return m, true
                        }
                }
 
@@ -376,7 +372,7 @@ 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, nil
+                       return m, false
                }
 
                // methods may not have a fully set up signature yet
@@ -385,7 +381,8 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
                }
 
                if !found || !equivalent(f.typ, m.typ) {
-                       return m, f
+                       alt = f
+                       return m, f.name == m.name
                }
        }
 
@@ -470,22 +467,21 @@ func (check *Checker) funcString(f *Func, pkgInfo bool) 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.
 // The receiver may be nil if assertableTo is invoked through an exported API call
 // (such as AssertableTo), i.e., when all methods have been type-checked.
 // The underlying type of V must be an interface.
-// If the result is negative and cause is not nil, *cause is set to the error cause.
+// If the result is false and cause is not nil, *cause describes the error.
 // TODO(gri) replace calls to this function with calls to newAssertableTo.
-func (check *Checker) assertableTo(V, T Type, cause *string) (method, wrongType *Func) {
+func (check *Checker) assertableTo(V, T Type, cause *string) bool {
        // no static check is required if T is an interface
        // spec: "If T is an interface type, x.(T) asserts that the
        //        dynamic type of x implements the interface T."
        if IsInterface(T) {
-               return
+               return true
        }
        // TODO(gri) fix this for generalized interfaces
-       return check.missingMethod(T, V, false, Identical, cause)
+       m, _ := check.missingMethod(T, V, false, Identical, cause)
+       return m == nil
 }
 
 // newAssertableTo reports whether a value of type V can be asserted to have type T.
index c9ddef347326b5ad99f26a95e88b365129f06d31..7c87702bd8675f3bc00d0e2686bac15683fda730 100644 (file)
@@ -1742,8 +1742,7 @@ func keyVal(x constant.Value) interface{} {
 // typeAssertion checks x.(T). The type of x must be an interface.
 func (check *Checker) typeAssertion(e ast.Expr, x *operand, T Type, typeSwitch bool) {
        var cause string
-       method, _ := check.assertableTo(x.typ, T, &cause)
-       if method == nil {
+       if check.assertableTo(x.typ, T, &cause) {
                return // success
        }
 
index 893f3b8afc57108291fffef9fafb95d9395423b5..09597888992d20a1566fc716b1c649132edfdbdb 100644 (file)
@@ -307,9 +307,7 @@ func (l *instanceLookup) add(inst *Named) {
 // present in V have matching types (e.g., for a type assertion x.(T) where
 // x is of interface type V).
 func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType bool) {
-       m, alt := (*Checker)(nil).missingMethod(V, T, static, Identical, nil)
-       // Only report a wrong type if the alternative method has the same name as m.
-       return m, alt != nil && alt.name == m.name // alt != nil implies m != nil
+       return (*Checker)(nil).missingMethod(V, T, static, Identical, nil)
 }
 
 // missingMethod is like MissingMethod but accepts a *Checker as receiver,
@@ -320,17 +318,14 @@ func MissingMethod(V Type, T *Interface, static bool) (method *Func, wrongType b
 // The underlying type of T must be an interface; T (rather than its under-
 // lying type) is used for better error messages (reported through *cause).
 // The comparator is used to compare signatures.
-// If a method is missing and cause is not nil, *cause is set to the error cause.
-//
-// If a method is missing on T but is found on *T, or if a method is found
-// on T when looked up with case-folding, this alternative method is returned
-// as the second result.
-func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y Type) bool, cause *string) (method, alt *Func) {
+// If a method is missing and cause is not nil, *cause describes the error.
+func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y Type) bool, cause *string) (method *Func, wrongType bool) {
        methods := under(T).(*Interface).typeSet().methods // T must be an interface
        if len(methods) == 0 {
                return
        }
 
+       var alt *Func
        if cause != nil {
                defer func() {
                        if method != nil {
@@ -349,11 +344,12 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
                                if !static {
                                        continue
                                }
-                               return m, nil
+                               return m, false
                        }
 
                        if !equivalent(f.typ, m.typ) {
-                               return m, f
+                               alt = f
+                               return m, true
                        }
                }
 
@@ -378,7 +374,7 @@ 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, nil
+                       return m, false
                }
 
                // methods may not have a fully set up signature yet
@@ -387,7 +383,8 @@ func (check *Checker) missingMethod(V, T Type, static bool, equivalent func(x, y
                }
 
                if !found || !equivalent(f.typ, m.typ) {
-                       return m, f
+                       alt = f
+                       return m, f.name == m.name
                }
        }
 
@@ -472,22 +469,21 @@ func (check *Checker) funcString(f *Func, pkgInfo bool) 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.
 // The receiver may be nil if assertableTo is invoked through an exported API call
 // (such as AssertableTo), i.e., when all methods have been type-checked.
 // The underlying type of V must be an interface.
-// If the result is negative and cause is not nil, *cause is set to the error cause.
+// If the result is false and cause is not nil, *cause describes the error.
 // TODO(gri) replace calls to this function with calls to newAssertableTo.
-func (check *Checker) assertableTo(V, T Type, cause *string) (method, wrongType *Func) {
+func (check *Checker) assertableTo(V, T Type, cause *string) bool {
        // no static check is required if T is an interface
        // spec: "If T is an interface type, x.(T) asserts that the
        //        dynamic type of x implements the interface T."
        if IsInterface(T) {
-               return
+               return true
        }
        // TODO(gri) fix this for generalized interfaces
-       return check.missingMethod(T, V, false, Identical, cause)
+       m, _ := check.missingMethod(T, V, false, Identical, cause)
+       return m == nil
 }
 
 // newAssertableTo reports whether a value of type V can be asserted to have type T.