go/types, types2: fix incorrect logic in assignability check

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>
This commit is contained in:
Robert Griesemer 2023-05-25 16:35:17 -07:00 committed by Gopher Robot
parent 96d16803c2
commit 05293d6b49
3 changed files with 36 additions and 8 deletions

View 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.

View 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.

View File

@ -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
}