mirror of https://github.com/golang/go.git
cmd/compile/internal/types2: differently named types are not assignable
When checking assignability, a value of a named type (incl. a type parameter) can never be assigned to a variable of a differently named type. Specifically, if the types are two differently named type parameters, then values of one are never assignable to variables of the other. This CL clarifies the assignabiliy rules and simplifies the implementation. Fixes #49242. Change-Id: Id72a2c9bed5cdb726855e7a707137db1009e7953 Reviewed-on: https://go-review.googlesource.com/c/go/+/360274 Trust: Robert Griesemer <gri@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
parent
82f902ae8e
commit
d2b512160e
|
|
@ -317,19 +317,11 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
|||
}
|
||||
}
|
||||
|
||||
// common case: if we don't have type parameters, we're done
|
||||
// optimization: if we don't have type parameters, we're done
|
||||
if Vp == nil && Tp == nil {
|
||||
return false, _IncompatibleAssign
|
||||
}
|
||||
|
||||
// determine type parameter operands with specific type terms
|
||||
if Vp != nil && !Vp.hasTerms() {
|
||||
Vp = nil
|
||||
}
|
||||
if Tp != nil && !Tp.hasTerms() {
|
||||
Tp = nil
|
||||
}
|
||||
|
||||
errorf := func(format string, args ...interface{}) {
|
||||
if check != nil && reason != nil {
|
||||
msg := check.sprintf(format, args...)
|
||||
|
|
@ -340,25 +332,36 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
|||
}
|
||||
}
|
||||
|
||||
ok := false
|
||||
code := _IncompatibleAssign
|
||||
switch {
|
||||
case Vp != nil && Tp != nil:
|
||||
x := *x // don't clobber outer x
|
||||
ok = Vp.is(func(V *term) bool {
|
||||
x.typ = V.typ
|
||||
return Tp.is(func(T *term) bool {
|
||||
ok, code = x.assignableTo(check, T.typ, reason)
|
||||
if !ok {
|
||||
errorf("cannot assign %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
// x's type V is not a named type and T is a type parameter, and
|
||||
// x is assignable to each specific type in T's type set.
|
||||
if !hasName(V) && Tp != nil {
|
||||
ok := false
|
||||
code := _IncompatibleAssign
|
||||
Tp.is(func(T *term) bool {
|
||||
if T == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
ok, code = x.assignableTo(check, T.typ, reason)
|
||||
if !ok {
|
||||
errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
case Vp != nil:
|
||||
return ok, code
|
||||
}
|
||||
|
||||
// x's type V is a type parameter and T is not a named type,
|
||||
// and values x' of each specific type in V's type set are
|
||||
// assignable to T.
|
||||
if Vp != nil && !hasName(T) {
|
||||
x := *x // don't clobber outer x
|
||||
ok = Vp.is(func(V *term) bool {
|
||||
ok := false
|
||||
code := _IncompatibleAssign
|
||||
Vp.is(func(V *term) bool {
|
||||
if V == nil {
|
||||
return false // no specific types
|
||||
}
|
||||
x.typ = V.typ
|
||||
ok, code = x.assignableTo(check, T, reason)
|
||||
if !ok {
|
||||
|
|
@ -367,19 +370,10 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
|
|||
}
|
||||
return true
|
||||
})
|
||||
case Tp != nil:
|
||||
x := *x // don't clobber outer x
|
||||
ok = Tp.is(func(T *term) bool {
|
||||
ok, code = x.assignableTo(check, T.typ, reason)
|
||||
if !ok {
|
||||
errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
|
||||
return false
|
||||
}
|
||||
return true
|
||||
})
|
||||
return ok, code
|
||||
}
|
||||
|
||||
return ok, code
|
||||
return false, _IncompatibleAssign
|
||||
}
|
||||
|
||||
// kind2tok translates syntax.LitKinds into token.Tokens.
|
||||
|
|
|
|||
|
|
@ -0,0 +1,27 @@
|
|||
// 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 _[P int](x P) int {
|
||||
return x // ERROR cannot use x .* as int value in return statement
|
||||
}
|
||||
|
||||
func _[P int]() int {
|
||||
return P /* ERROR cannot use P\(1\) .* as int value in return statement */ (1)
|
||||
}
|
||||
|
||||
func _[P int](x int) P {
|
||||
return x // ERROR cannot use x .* as P value in return statement
|
||||
}
|
||||
|
||||
func _[P, Q any](x P) Q {
|
||||
return x // ERROR cannot use x .* as Q value in return statement
|
||||
}
|
||||
|
||||
// test case from issue
|
||||
func F[G interface{ uint }]() int {
|
||||
f := func(uint) int { return 0 }
|
||||
return f(G /* ERROR cannot use G\(1\) .* as uint value in argument to f */ (1))
|
||||
}
|
||||
|
|
@ -109,20 +109,48 @@ func _[
|
|||
)
|
||||
|
||||
var (
|
||||
_ _CC = C
|
||||
_ _SC = C
|
||||
_ _RC = C
|
||||
_ _CC = C // ERROR cannot use C .* as _CC value
|
||||
_ _SC = C // ERROR cannot use C .* as _SC value
|
||||
_ _RC = C // ERROR cannot use C .* as _RC value
|
||||
|
||||
_ CC = _CC(nil)
|
||||
_ SC = _CC(nil)
|
||||
_ RC = _CC(nil)
|
||||
_ CC = _CC /* ERROR cannot use _CC\(nil\) .* as CC value */ (nil)
|
||||
_ SC = _CC /* ERROR cannot use _CC\(nil\) .* as SC value */ (nil)
|
||||
_ RC = _CC /* ERROR cannot use _CC\(nil\) .* as RC value */ (nil)
|
||||
|
||||
_ CC = C
|
||||
_ SC = C // ERROR cannot use C .* as SC value .* cannot assign Chan to SendChan
|
||||
_ RC = C // ERROR cannot use C .* as RC value .* cannot assign Chan to RecvChan
|
||||
_ CC = C // ERROR cannot use C .* as CC value
|
||||
_ SC = C // ERROR cannot use C .* as SC value
|
||||
_ RC = C // ERROR cannot use C .* as RC value
|
||||
)
|
||||
}
|
||||
|
||||
// "x's type V is not a named type and T is a type parameter, and x is assignable to each specific type in T's type set."
|
||||
func _[
|
||||
TP0 any,
|
||||
TP1 ~_Chan,
|
||||
TP2 ~chan int | ~chan byte,
|
||||
]() {
|
||||
var (
|
||||
_ TP0 = c // ERROR cannot use c .* as TP0 value
|
||||
_ TP0 = C // ERROR cannot use C .* as TP0 value
|
||||
_ TP1 = c
|
||||
_ TP1 = C // ERROR cannot use C .* as TP1 value
|
||||
_ TP2 = c // ERROR .* cannot assign chan int to chan byte
|
||||
)
|
||||
}
|
||||
|
||||
// "x's type V is a type parameter and T is not a named type, and values x' of each specific type in V's type set are assignable to T."
|
||||
func _[
|
||||
TP0 Interface,
|
||||
TP1 ~_Chan,
|
||||
TP2 ~chan int | ~chan byte,
|
||||
](X0 TP0, X1 TP1, X2 TP2) {
|
||||
i = X0
|
||||
I = X0
|
||||
c = X1
|
||||
C = X1 // ERROR cannot use X1 .* as Chan value
|
||||
c = X2 // ERROR .* cannot assign chan byte \(in TP2\) to chan int
|
||||
}
|
||||
|
||||
// "x is the predeclared identifier nil and T is a pointer, function, slice, map, channel, or interface type"
|
||||
func _[TP Interface](X TP) {
|
||||
b = nil // ERROR cannot use untyped nil
|
||||
|
|
|
|||
Loading…
Reference in New Issue