]> Cypherpunks repositories - gostls13.git/commitdiff
go/types, types2: fix incorrect logic in assignability check
authorRobert Griesemer <gri@golang.org>
Thu, 25 May 2023 23:35:17 +0000 (16:35 -0700)
committerGopher Robot <gobot@golang.org>
Mon, 5 Jun 2023 14:01:09 +0000 (14:01 +0000)
Do not return prematurely in assignableTo.

Fixes #54424.

Change-Id: I769b3b4ad9d79b7bce60b92cc59c3564117e36db
Reviewed-on: https://go-review.googlesource.com/c/go/+/498400
Run-TryBot: Robert Griesemer <gri@google.com>
Reviewed-by: Robert Griesemer <gri@google.com>
Auto-Submit: Robert Griesemer <gri@google.com>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/operand.go
src/go/types/operand.go
src/internal/types/testdata/fixedbugs/issue54424.go [new file with mode: 0644]

index db9a6d84782b38a4eae7111b07b5ce809c6e8ee6..0469b000bb4b69e9684a040891a52440a3eeccee 100644 (file)
@@ -290,13 +290,21 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod
                return true, 0
        }
 
-       // 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.
+       // T is an interface type, but not a type parameter, and V implements T.
+       // Also handle the case where T is a pointer to an interface so that we get
+       // the Checker.implements error cause.
        if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
-               if !check.implements(x.Pos(), V, T, false, cause) {
+               if check.implements(x.Pos(), V, T, false, cause) {
+                       return true, 0
+               }
+               // V doesn't implement T but V may still be assignable to T if V
+               // is a type parameter; do not report an error in that case yet.
+               if Vp == nil {
                        return false, InvalidIfaceAssign
                }
-               return true, 0
+               if cause != nil {
+                       *cause = ""
+               }
        }
 
        // If V is an interface, check if a missing type assertion is the problem.
index 449b2ebb07c3df3a5a27cc545c2b7f13ebe1e613..d7719fdaaf7ac69361637f88d503be5236f256ac 100644 (file)
@@ -277,13 +277,21 @@ func (x *operand) assignableTo(check *Checker, T Type, cause *string) (bool, Cod
                return true, 0
        }
 
-       // 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.
+       // T is an interface type, but not a type parameter, and V implements T.
+       // Also handle the case where T is a pointer to an interface so that we get
+       // the Checker.implements error cause.
        if _, ok := Tu.(*Interface); ok && Tp == nil || isInterfacePtr(Tu) {
-               if !check.implements(x.Pos(), V, T, false, cause) {
+               if check.implements(x.Pos(), V, T, false, cause) {
+                       return true, 0
+               }
+               // V doesn't implement T but V may still be assignable to T if V
+               // is a type parameter; do not report an error in that case yet.
+               if Vp == nil {
                        return false, InvalidIfaceAssign
                }
-               return true, 0
+               if cause != nil {
+                       *cause = ""
+               }
        }
 
        // If V is an interface, check if a missing type assertion is the problem.
diff --git a/src/internal/types/testdata/fixedbugs/issue54424.go b/src/internal/types/testdata/fixedbugs/issue54424.go
new file mode 100644 (file)
index 0000000..ebfb83d
--- /dev/null
@@ -0,0 +1,12 @@
+// Copyright 2023 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 ~*T, T any]() {
+       var p P
+       var tp *T
+       tp = p // this assignment is valid
+       _ = tp
+}