]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: delay "does not satisfy comparable" error until needed
authorRobert Griesemer <gri@golang.org>
Thu, 16 Dec 2021 00:13:05 +0000 (16:13 -0800)
committerRobert Findley <rfindley@google.com>
Mon, 20 Dec 2021 15:13:38 +0000 (15:13 +0000)
Fixes #49112.

Change-Id: I8effbca7bcbb257b18fd4d3d1914fd10d4afaaae
Reviewed-on: https://go-review.googlesource.com/c/go/+/372594
Trust: Robert Griesemer <gri@golang.org>
Run-TryBot: Robert Griesemer <gri@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/instantiate.go
src/cmd/compile/internal/types2/testdata/check/issues.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2
src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2 [new file with mode: 0644]
src/go/types/instantiate.go
src/go/types/testdata/check/issues.go2
src/go/types/testdata/fixedbugs/issue47411.go2
src/go/types/testdata/fixedbugs/issue49112.go2 [new file with mode: 0644]

index cda6c7baf4e5c543f674903a05f01ca8a24d9a81..b2e1087c41dae8d5c5c7a94110f6feb7112b34d1 100644 (file)
@@ -192,17 +192,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                return errorf("cannot implement %s (empty type set)", T)
        }
 
-       // If T is comparable, V must be comparable.
-       // TODO(gri) the error messages could be better, here
-       if Ti.IsComparable() && !Comparable(V) {
-               if Vi != nil && Vi.Empty() {
-                       return errorf("empty interface %s does not implement %s", V, T)
-               }
-               return errorf("%s does not implement comparable", V)
-       }
-
-       // V must implement T (methods)
-       // - check only if we have methods
+       // V must implement T's methods, if any.
        if Ti.NumMethods() > 0 {
                if m, wrong := check.missingMethod(V, Ti, true); m != nil {
                        // TODO(gri) needs to print updated name to avoid major confusion in error message!
@@ -220,10 +210,17 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                }
        }
 
+       // If T is comparable, V must be comparable.
+       // Remember as a pending error and report only if we don't have a more specific error.
+       var pending error
+       if Ti.IsComparable() && !Comparable(V) {
+               pending = errorf("%s does not implement comparable", V)
+       }
+
        // V must also be in the set of types of T, if any.
        // Constraints with empty type sets were already excluded above.
        if !Ti.typeSet().hasTerms() {
-               return nil // nothing to do
+               return pending // nothing to do
        }
 
        // If V is itself an interface, each of its possible types must be in the set
@@ -234,7 +231,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                        // TODO(gri) report which type is missing
                        return errorf("%s does not implement %s", V, T)
                }
-               return nil
+               return pending
        }
 
        // Otherwise, V's type must be included in the iface type set.
@@ -262,5 +259,5 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                }
        }
 
-       return nil
+       return pending
 }
index 76f9cc5010af6d1879faeb843641edd01c674c17..5b6eebd4fd2eff93d87454c12a045886f72ea853 100644 (file)
@@ -58,7 +58,7 @@ func _() {
 type T1[P interface{~uint}] struct{}
 
 func _[P any]() {
-    _ = T1[P /* ERROR empty interface P does not implement interface{~uint} */ ]{}
+    _ = T1[P /* ERROR P does not implement interface{~uint} */ ]{}
 }
 
 // This is the original (simplified) program causing the same issue.
@@ -74,8 +74,8 @@ func (u T2[U]) Add1() U {
     return u.s + 1
 }
 
-func NewT2[U any]() T2[U /* ERROR empty interface U does not implement Unsigned */ ] {
-    return T2[U /* ERROR empty interface U does not implement Unsigned */ ]{}
+func NewT2[U any]() T2[U /* ERROR U does not implement Unsigned */ ] {
+    return T2[U /* ERROR U does not implement Unsigned */ ]{}
 }
 
 func _() {
index ce5db0a615ff0622d783efc8d95b28aa8f4110ef..3f405baed7741808a958687f4e82559b7a5d39a7 100644 (file)
@@ -16,11 +16,11 @@ func _[P comparable,
         _ = f[P]
         _ = f[Q]
         _ = f[func( /* ERROR does not implement comparable */ )]
-        _ = f[R /* ERROR empty interface R does not implement comparable */ ]
+        _ = f[R /* ERROR R does not implement comparable */ ]
 
         _ = g[int]
         _ = g[P /* ERROR P does not implement interface{interface{comparable; ~int\|~string} */ ]
         _ = g[Q]
-        _ = g[func( /* ERROR does not implement comparable */ )]
-        _ = g[R /* ERROR empty interface R does not implement interface{interface{comparable; ~int\|~string} */ ]
+        _ = g[func( /* ERROR func\(\) does not implement interface{interface{comparable; ~int\|~string}} */ )]
+        _ = g[R /* ERROR R does not implement interface{interface{comparable; ~int\|~string} */ ]
 }
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2
new file mode 100644 (file)
index 0000000..0efc906
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f[P int](P) {}
+
+func _() {
+        _ = f[int]
+        _ = f[[ /* ERROR \[\]int does not implement int */ ]int]
+
+        f(0)
+        f( /* ERROR \[\]int does not implement int */ []int{})
+}
index e8748975c9150398521e29f4680ccc7fc6473748..e6a5cbf8ae30c8210dfd079cf57b6c4d8f463be2 100644 (file)
@@ -192,17 +192,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                return errorf("cannot implement %s (empty type set)", T)
        }
 
-       // If T is comparable, V must be comparable.
-       // TODO(gri) the error messages could be better, here
-       if Ti.IsComparable() && !Comparable(V) {
-               if Vi != nil && Vi.Empty() {
-                       return errorf("empty interface %s does not implement %s", V, T)
-               }
-               return errorf("%s does not implement comparable", V)
-       }
-
-       // V must implement T (methods)
-       // - check only if we have methods
+       // V must implement T's methods, if any.
        if Ti.NumMethods() > 0 {
                if m, wrong := check.missingMethod(V, Ti, true); m != nil {
                        // TODO(gri) needs to print updated name to avoid major confusion in error message!
@@ -221,10 +211,17 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                }
        }
 
+       // If T is comparable, V must be comparable.
+       // Remember as a pending error and report only if we don't have a more specific error.
+       var pending error
+       if Ti.IsComparable() && !Comparable(V) {
+               pending = errorf("%s does not implement comparable", V)
+       }
+
        // V must also be in the set of types of T, if any.
        // Constraints with empty type sets were already excluded above.
        if !Ti.typeSet().hasTerms() {
-               return nil // nothing to do
+               return pending // nothing to do
        }
 
        // If V is itself an interface, each of its possible types must be in the set
@@ -235,7 +232,7 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                        // TODO(gri) report which type is missing
                        return errorf("%s does not implement %s", V, T)
                }
-               return nil
+               return pending
        }
 
        // Otherwise, V's type must be included in the iface type set.
@@ -263,5 +260,5 @@ func (check *Checker) implements(V, T Type, qf Qualifier) error {
                }
        }
 
-       return nil
+       return pending
 }
index 371856eea34333b2fa3c414b88a3543c977a21e2..cec1ccb0cc8effa9ec30d13de9021bdcc920e41f 100644 (file)
@@ -58,7 +58,7 @@ func _() {
 type T1[P interface{~uint}] struct{}
 
 func _[P any]() {
-    _ = T1[P /* ERROR empty interface P does not implement interface{~uint} */ ]{}
+    _ = T1[P /* ERROR P does not implement interface{~uint} */ ]{}
 }
 
 // This is the original (simplified) program causing the same issue.
@@ -74,8 +74,8 @@ func (u T2[U]) Add1() U {
     return u.s + 1
 }
 
-func NewT2[U any]() T2[U /* ERROR empty interface U does not implement Unsigned */ ] {
-    return T2[U /* ERROR empty interface U does not implement Unsigned */ ]{}
+func NewT2[U any]() T2[U /* ERROR U does not implement Unsigned */ ] {
+    return T2[U /* ERROR U does not implement Unsigned */ ]{}
 }
 
 func _() {
index d6c34be8dba4874c56ad7566ede166bc504e7a8c..db5fb32483c3b40617d1f946ae7b9f10fd5fdbe0 100644 (file)
@@ -16,11 +16,11 @@ func _[P comparable,
         _ = f[P]
         _ = f[Q]
         _ = f[func /* ERROR does not implement comparable */ ()]
-        _ = f[R /* ERROR empty interface R does not implement comparable */ ]
+        _ = f[R /* ERROR R does not implement comparable */ ]
 
         _ = g[int]
         _ = g[P /* ERROR P does not implement interface{interface{comparable; ~int\|~string} */ ]
         _ = g[Q]
-        _ = g[func /* ERROR does not implement comparable */ ()]
-        _ = g[R /* ERROR empty interface R does not implement interface{interface{comparable; ~int\|~string} */ ]
+        _ = g[func /* ERROR func\(\) does not implement interface{interface{comparable; ~int\|~string}} */ ()]
+        _ = g[R /* ERROR R does not implement interface{interface{comparable; ~int\|~string} */ ]
 }
diff --git a/src/go/types/testdata/fixedbugs/issue49112.go2 b/src/go/types/testdata/fixedbugs/issue49112.go2
new file mode 100644 (file)
index 0000000..61b757c
--- /dev/null
@@ -0,0 +1,15 @@
+// Copyright 2021 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+func f[P int](P) {}
+
+func _() {
+        _ = f[int]
+        _ = f[[ /* ERROR \[\]int does not implement int */ ]int]
+
+        f(0)
+        f/* ERROR \[\]int does not implement int */ ([]int{})
+}