mirror of
https://github.com/golang/go
synced 2024-11-15 02:20:32 -07:00
go/types, types2: don't lose alias information during unification
While at it, rename asTypeParam to asBoundTypeParam for clarity. For #67547. Fixes #67628. Change-Id: I2f447c4cd4d72f5315fe9323d82fcb9bf33657c6 Reviewed-on: https://go-review.googlesource.com/c/go/+/588797 Reviewed-by: Robert Griesemer <gri@google.com> Auto-Submit: Robert Griesemer <gri@google.com> LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com> Commit-Queue: Robert Griesemer <gri@google.com> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
c26be72d68
commit
ee29dbe43e
@ -205,10 +205,10 @@ func (u *unifier) join(x, y *TypeParam) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// asTypeParam returns x.(*TypeParam) if x is a type parameter recorded with u.
|
||||
// asBoundTypeParam returns x.(*TypeParam) if x is a type parameter recorded with u.
|
||||
// Otherwise, the result is nil.
|
||||
func (u *unifier) asTypeParam(x Type) *TypeParam {
|
||||
if x, _ := x.(*TypeParam); x != nil {
|
||||
func (u *unifier) asBoundTypeParam(x Type) *TypeParam {
|
||||
if x, _ := Unalias(x).(*TypeParam); x != nil {
|
||||
if _, found := u.handles[x]; found {
|
||||
return x
|
||||
}
|
||||
@ -269,7 +269,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
|
||||
// asInterface returns the underlying type of x as an interface if
|
||||
// it is a non-type parameter interface. Otherwise it returns nil.
|
||||
func asInterface(x Type) (i *Interface) {
|
||||
if _, ok := x.(*TypeParam); !ok {
|
||||
if _, ok := Unalias(x).(*TypeParam); !ok {
|
||||
i, _ = under(x).(*Interface)
|
||||
}
|
||||
return i
|
||||
@ -291,11 +291,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
u.depth--
|
||||
}()
|
||||
|
||||
x = Unalias(x)
|
||||
y = Unalias(y)
|
||||
|
||||
// nothing to do if x == y
|
||||
if x == y {
|
||||
if x == y || Unalias(x) == Unalias(y) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -314,7 +311,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// Ensure that if we have at least one
|
||||
// - defined type, make sure one is in y
|
||||
// - type parameter recorded with u, make sure one is in x
|
||||
if asNamed(x) != nil || u.asTypeParam(y) != nil {
|
||||
if asNamed(x) != nil || u.asBoundTypeParam(y) != nil {
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s\t// swap", y, x)
|
||||
}
|
||||
@ -358,7 +355,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// isTypeLit(x) is false and y was not changed above. In other
|
||||
// words, if y was a defined type, it is still a defined type
|
||||
// (relevant for the logic below).
|
||||
switch px, py := u.asTypeParam(x), u.asTypeParam(y); {
|
||||
switch px, py := u.asBoundTypeParam(x), u.asBoundTypeParam(y); {
|
||||
case px != nil && py != nil:
|
||||
// both x and y are type parameters
|
||||
if u.join(px, py) {
|
||||
@ -449,7 +446,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
}
|
||||
|
||||
// x != y if we get here
|
||||
assert(x != y)
|
||||
assert(x != y && Unalias(x) != Unalias(y))
|
||||
|
||||
// If u.EnableInterfaceInference is set and we don't require exact unification,
|
||||
// if both types are interfaces, one interface must have a subset of the
|
||||
@ -573,6 +570,10 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
emode |= exact
|
||||
}
|
||||
|
||||
// Continue with unaliased types but don't lose original alias names, if any (go.dev/issue/67628).
|
||||
xorig, x := x, Unalias(x)
|
||||
yorig, y := y, Unalias(y)
|
||||
|
||||
switch x := x.(type) {
|
||||
case *Basic:
|
||||
// Basic types are singletons except for the rune and byte
|
||||
@ -751,7 +752,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
case *TypeParam:
|
||||
// x must be an unbound type parameter (see comment above).
|
||||
if debug {
|
||||
assert(u.asTypeParam(x) == nil)
|
||||
assert(u.asBoundTypeParam(x) == nil)
|
||||
}
|
||||
// By definition, a valid type argument must be in the type set of
|
||||
// the respective type constraint. Therefore, the type argument's
|
||||
@ -774,13 +775,13 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// need to take care of that case separately.
|
||||
if cx := coreType(x); cx != nil {
|
||||
if traceInference {
|
||||
u.tracef("core %s ≡ %s", x, y)
|
||||
u.tracef("core %s ≡ %s", xorig, yorig)
|
||||
}
|
||||
// If y is a defined type, it may not match against cx which
|
||||
// is an underlying type (incl. int, string, etc.). Use assign
|
||||
// mode here so that the unifier automatically takes under(y)
|
||||
// if necessary.
|
||||
return u.nify(cx, y, assign, p)
|
||||
return u.nify(cx, yorig, assign, p)
|
||||
}
|
||||
}
|
||||
// x != y and there's nothing to do
|
||||
@ -789,7 +790,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// avoid a crash in case of nil type
|
||||
|
||||
default:
|
||||
panic(sprintf(nil, true, "u.nify(%s, %s, %d)", x, y, mode))
|
||||
panic(sprintf(nil, true, "u.nify(%s, %s, %d)", xorig, yorig, mode))
|
||||
}
|
||||
|
||||
return false
|
||||
|
@ -208,10 +208,10 @@ func (u *unifier) join(x, y *TypeParam) bool {
|
||||
return true
|
||||
}
|
||||
|
||||
// asTypeParam returns x.(*TypeParam) if x is a type parameter recorded with u.
|
||||
// asBoundTypeParam returns x.(*TypeParam) if x is a type parameter recorded with u.
|
||||
// Otherwise, the result is nil.
|
||||
func (u *unifier) asTypeParam(x Type) *TypeParam {
|
||||
if x, _ := x.(*TypeParam); x != nil {
|
||||
func (u *unifier) asBoundTypeParam(x Type) *TypeParam {
|
||||
if x, _ := Unalias(x).(*TypeParam); x != nil {
|
||||
if _, found := u.handles[x]; found {
|
||||
return x
|
||||
}
|
||||
@ -272,7 +272,7 @@ func (u *unifier) inferred(tparams []*TypeParam) []Type {
|
||||
// asInterface returns the underlying type of x as an interface if
|
||||
// it is a non-type parameter interface. Otherwise it returns nil.
|
||||
func asInterface(x Type) (i *Interface) {
|
||||
if _, ok := x.(*TypeParam); !ok {
|
||||
if _, ok := Unalias(x).(*TypeParam); !ok {
|
||||
i, _ = under(x).(*Interface)
|
||||
}
|
||||
return i
|
||||
@ -294,11 +294,8 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
u.depth--
|
||||
}()
|
||||
|
||||
x = Unalias(x)
|
||||
y = Unalias(y)
|
||||
|
||||
// nothing to do if x == y
|
||||
if x == y {
|
||||
if x == y || Unalias(x) == Unalias(y) {
|
||||
return true
|
||||
}
|
||||
|
||||
@ -317,7 +314,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// Ensure that if we have at least one
|
||||
// - defined type, make sure one is in y
|
||||
// - type parameter recorded with u, make sure one is in x
|
||||
if asNamed(x) != nil || u.asTypeParam(y) != nil {
|
||||
if asNamed(x) != nil || u.asBoundTypeParam(y) != nil {
|
||||
if traceInference {
|
||||
u.tracef("%s ≡ %s\t// swap", y, x)
|
||||
}
|
||||
@ -361,7 +358,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// isTypeLit(x) is false and y was not changed above. In other
|
||||
// words, if y was a defined type, it is still a defined type
|
||||
// (relevant for the logic below).
|
||||
switch px, py := u.asTypeParam(x), u.asTypeParam(y); {
|
||||
switch px, py := u.asBoundTypeParam(x), u.asBoundTypeParam(y); {
|
||||
case px != nil && py != nil:
|
||||
// both x and y are type parameters
|
||||
if u.join(px, py) {
|
||||
@ -452,7 +449,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
}
|
||||
|
||||
// x != y if we get here
|
||||
assert(x != y)
|
||||
assert(x != y && Unalias(x) != Unalias(y))
|
||||
|
||||
// If u.EnableInterfaceInference is set and we don't require exact unification,
|
||||
// if both types are interfaces, one interface must have a subset of the
|
||||
@ -576,6 +573,10 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
emode |= exact
|
||||
}
|
||||
|
||||
// Continue with unaliased types but don't lose original alias names, if any (go.dev/issue/67628).
|
||||
xorig, x := x, Unalias(x)
|
||||
yorig, y := y, Unalias(y)
|
||||
|
||||
switch x := x.(type) {
|
||||
case *Basic:
|
||||
// Basic types are singletons except for the rune and byte
|
||||
@ -754,7 +755,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
case *TypeParam:
|
||||
// x must be an unbound type parameter (see comment above).
|
||||
if debug {
|
||||
assert(u.asTypeParam(x) == nil)
|
||||
assert(u.asBoundTypeParam(x) == nil)
|
||||
}
|
||||
// By definition, a valid type argument must be in the type set of
|
||||
// the respective type constraint. Therefore, the type argument's
|
||||
@ -777,13 +778,13 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// need to take care of that case separately.
|
||||
if cx := coreType(x); cx != nil {
|
||||
if traceInference {
|
||||
u.tracef("core %s ≡ %s", x, y)
|
||||
u.tracef("core %s ≡ %s", xorig, yorig)
|
||||
}
|
||||
// If y is a defined type, it may not match against cx which
|
||||
// is an underlying type (incl. int, string, etc.). Use assign
|
||||
// mode here so that the unifier automatically takes under(y)
|
||||
// if necessary.
|
||||
return u.nify(cx, y, assign, p)
|
||||
return u.nify(cx, yorig, assign, p)
|
||||
}
|
||||
}
|
||||
// x != y and there's nothing to do
|
||||
@ -792,7 +793,7 @@ func (u *unifier) nify(x, y Type, mode unifyMode, p *ifacePair) (result bool) {
|
||||
// avoid a crash in case of nil type
|
||||
|
||||
default:
|
||||
panic(sprintf(nil, nil, true, "u.nify(%s, %s, %d)", x, y, mode))
|
||||
panic(sprintf(nil, nil, true, "u.nify(%s, %s, %d)", xorig, yorig, mode))
|
||||
}
|
||||
|
||||
return false
|
||||
|
17
src/internal/types/testdata/fixedbugs/issue67628.go
vendored
Normal file
17
src/internal/types/testdata/fixedbugs/issue67628.go
vendored
Normal file
@ -0,0 +1,17 @@
|
||||
// -gotypesalias=1
|
||||
|
||||
// Copyright 2024 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 any](x P) P { return x }
|
||||
|
||||
func _() {
|
||||
type A = int
|
||||
var a A
|
||||
b := f(a) // type of b is A
|
||||
// error should report type of b as A, not int
|
||||
_ = b /* ERROR "mismatched types A and untyped string" */ + "foo"
|
||||
}
|
Loading…
Reference in New Issue
Block a user