1
0
mirror of https://github.com/golang/go synced 2024-11-24 06:40:17 -07:00

go/types: differently named types are not assignable

This is a clean port of CL 360274 to go/types.

Change-Id: Idfa584fab95f7226e10b1a7c5b06d56a0bf9d757
Reviewed-on: https://go-review.googlesource.com/c/go/+/360759
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Robert Findley 2021-11-02 11:46:25 -04:00
parent ea403bc237
commit 42e6b5bce2
3 changed files with 95 additions and 46 deletions

View File

@ -302,19 +302,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...)
@ -325,25 +317,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 {
@ -352,17 +355,8 @@ 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
}

View File

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

View File

@ -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"
// TODO(rfindley) error messages about untyped nil diverge from types2 here.
// Consider aligning them.