]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: use Checker.implements in operand.assignableTo
authorRobert Griesemer <gri@golang.org>
Thu, 27 Jan 2022 18:52:22 +0000 (10:52 -0800)
committerRobert Griesemer <gri@golang.org>
Fri, 28 Jan 2022 22:21:43 +0000 (22:21 +0000)
Now that we have the detailed error reporting in Checker.implements
we don't need it anymore in operand.assignableTo and can simply call
Checker.implements. This also more directly matches the spec.

For #50646.

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

index 02ab13ec5939e5eec120138c3b4fed3e71952f5e..e8f2d98d25f24ae25691c323803fd9c097ae1f08 100644 (file)
@@ -157,6 +157,8 @@ func (check *Checker) verify(pos syntax.Pos, tparams []*TypeParam, targs []Type)
 
 // implements checks if V implements T and reports an error if it doesn't.
 // If a qualifier is provided, it is used in error formatting.
+// The receiver may be nil if implements is called through an exported
+// API call such as AssignableTo.
 func (check *Checker) implements(V, T Type, qf Qualifier) error {
        Vu := under(V)
        Tu := under(T)
index 1eb24d136b37f9720c71a2f14497dddbf2f528f5..1bda0a51f5aeada520daf2603e57685b750dbb6a 100644 (file)
@@ -288,47 +288,30 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
                return true, 0
        }
 
-       // T is an interface type and x implements T and T is not a type parameter
-       if Ti, ok := Tu.(*Interface); ok && Tp == nil {
-               if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* !Implements(V, Ti) */ {
+       // T is an interface type and x implements T and T is not a type parameter.
+       // Also handle the case where T is a pointer to an interface.
+       if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
+               var qf Qualifier
+               if check != nil {
+                       qf = check.qualifier
+               }
+               if err := check.implements(V, T, qf); err != nil {
                        if reason != nil {
-                               if check != nil && check.conf.CompilerErrorMessages {
-                                       *reason = check.sprintf("%s does not implement %s %s", x.typ, T,
-                                               check.missingMethodReason(x.typ, T, m, wrongType))
-                               } else {
-                                       if wrongType != nil {
-                                               if Identical(m.typ, wrongType.typ) {
-                                                       *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
-                                               } else {
-                                                       *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
-                                               }
-                                       } else {
-                                               *reason = "missing method " + m.Name()
-                                       }
-                               }
+                               *reason = err.Error()
                        }
                        return false, _InvalidIfaceAssign
                }
                return true, 0
        }
 
-       // Provide extra detail in compiler error messages in some cases when T is
-       // not an interface.
-       if check != nil && check.conf.CompilerErrorMessages {
-               if isInterfacePtr(Tu) {
+       // If V is an interface, check if a missing type assertion is the problem.
+       if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
+               if check.implements(T, V, nil) == nil {
+                       // T implements V, so give hint about type assertion.
                        if reason != nil {
-                               *reason = check.sprintf("%s does not implement %s (type %s is pointer to interface, not interface)", x.typ, T, T)
-                       }
-                       return false, _InvalidIfaceAssign
-               }
-               if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
-                       if m, _ := check.missingMethod(T, Vi, true); m == nil {
-                               // T implements Vi, so give hint about type assertion.
-                               if reason != nil {
-                                       *reason = check.sprintf("need type assertion")
-                               }
-                               return false, _IncompatibleAssign
+                               *reason = "need type assertion"
                        }
+                       return false, _IncompatibleAssign
                }
        }
 
index 868df46bd9ea31cf5b3cefb3244b9b4bbf428404..fb7d89fb6829c47c258c87ccf969245566be0ef1 100644 (file)
@@ -165,8 +165,8 @@ func issue10260() {
        _ = map[int]I1{0: i0 /* ERROR cannot use .* missing method foo */ }
        _ = map[int]I1{0: i2 /* ERROR cannot use .* wrong type for method foo */ }
 
-       make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */
-       make(chan I1) <- i2 /* ERROR cannot use .* in send: wrong type for method foo */
+       make(chan I1) <- i0 /* ERROR I0 does not implement I1: missing method foo */
+       make(chan I1) <- i2 /* ERROR wrong type for method foo \(have func\(x int\), want func\(\)\) */
 }
 
 // Check that constants representable as integers are in integer form
index 7dea8a5e1d46c8bbd2f6ee734ec7a606f4b1e892..4a167eb91e09c6c888489a75891182adb78695b1 100644 (file)
@@ -157,6 +157,8 @@ func (check *Checker) verify(pos token.Pos, tparams []*TypeParam, targs []Type)
 
 // implements checks if V implements T and reports an error if it doesn't.
 // If a qualifier is provided, it is used in error formatting.
+// The receiver may be nil if implements is called through an exported
+// API call such as AssignableTo.
 func (check *Checker) implements(V, T Type, qf Qualifier) error {
        Vu := under(V)
        Tu := under(T)
index d119b5ee7be6c21da2086cbc6815fbda9ba59b0b..c04c5742a85b1e1fac254a562288fb410bfef9de 100644 (file)
@@ -8,7 +8,6 @@ package types
 
 import (
        "bytes"
-       "fmt"
        "go/ast"
        "go/constant"
        "go/token"
@@ -278,48 +277,30 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
                return true, 0
        }
 
-       // T is an interface type and x implements T and T is not a type parameter
-       if Ti, ok := Tu.(*Interface); ok && Tp == nil {
-               if m, wrongType := check.missingMethod(V, Ti, true); m != nil /* Implements(V, Ti) */ {
+       // T is an interface type and x implements T and T is not a type parameter.
+       // Also handle the case where T is a pointer to an interface.
+       if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
+               var qf Qualifier
+               if check != nil {
+                       qf = check.qualifier
+               }
+               if err := check.implements(V, T, qf); err != nil {
                        if reason != nil {
-                               if check != nil && compilerErrorMessages {
-                                       *reason = check.sprintf("%s does not implement %s %s", x.typ, T,
-                                               check.missingMethodReason(x.typ, T, m, wrongType))
-                               } else {
-                                       if wrongType != nil {
-                                               if Identical(m.typ, wrongType.typ) {
-                                                       *reason = fmt.Sprintf("missing method %s (%s has pointer receiver)", m.name, m.name)
-                                               } else {
-                                                       *reason = fmt.Sprintf("wrong type for method %s (have %s, want %s)", m.Name(), wrongType.typ, m.typ)
-                                               }
-
-                                       } else {
-                                               *reason = "missing method " + m.Name()
-                                       }
-                               }
+                               *reason = err.Error()
                        }
                        return false, _InvalidIfaceAssign
                }
                return true, 0
        }
 
-       // Provide extra detail in compiler error messages in some cases when T is
-       // not an interface.
-       if check != nil && compilerErrorMessages {
-               if isInterfacePtr(Tu) {
+       // If V is an interface, check if a missing type assertion is the problem.
+       if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
+               if check.implements(T, V, nil) == nil {
+                       // T implements V, so give hint about type assertion.
                        if reason != nil {
-                               *reason = check.sprintf("%s does not implement %s (type %s is pointer to interface, not interface)", x.typ, T, T)
-                       }
-                       return false, _InvalidIfaceAssign
-               }
-               if Vi, _ := Vu.(*Interface); Vi != nil && Vp == nil {
-                       if m, _ := check.missingMethod(T, Vi, true); m == nil {
-                               // T implements Vi, so give hint about type assertion.
-                               if reason != nil {
-                                       *reason = check.sprintf("need type assertion")
-                               }
-                               return false, _IncompatibleAssign
+                               *reason = "need type assertion"
                        }
+                       return false, _IncompatibleAssign
                }
        }
 
index 88ce452959845dd77e2ba9ccfac917dcfcf8df26..0b77b0e854012b7655081a98fa849e98b1409538 100644 (file)
@@ -165,8 +165,8 @@ func issue10260() {
        _ = map[int]I1{0: i0 /* ERROR cannot use .* missing method foo */ }
        _ = map[int]I1{0: i2 /* ERROR cannot use .* wrong type for method foo */ }
 
-       make(chan I1) <- i0 /* ERROR cannot use .* in send: missing method foo */
-       make(chan I1) <- i2 /* ERROR cannot use .* in send: wrong type for method foo */
+       make(chan I1) <- i0 /* ERROR I0 does not implement I1: missing method foo */
+       make(chan I1) <- i2 /* ERROR wrong type for method foo \(have func\(x int\), want func\(\)\) */
 }
 
 // Check that constants representable as integers are in integer form