mirror of
https://github.com/golang/go
synced 2024-11-12 04:40:22 -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:
parent
ea403bc237
commit
42e6b5bce2
@ -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
|
||||
}
|
||||
|
27
src/go/types/testdata/fixedbugs/issue49242.go2
vendored
Normal file
27
src/go/types/testdata/fixedbugs/issue49242.go2
vendored
Normal 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))
|
||||
}
|
46
src/go/types/testdata/spec/assignability.go2
vendored
46
src/go/types/testdata/spec/assignability.go2
vendored
@ -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.
|
||||
|
Loading…
Reference in New Issue
Block a user