1
0
mirror of https://github.com/golang/go synced 2024-11-24 08:20:03 -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 { if Vp == nil && Tp == nil {
return false, _IncompatibleAssign 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{}) { errorf := func(format string, args ...interface{}) {
if check != nil && reason != nil { if check != nil && reason != nil {
msg := check.sprintf(format, args...) msg := check.sprintf(format, args...)
@ -325,25 +317,36 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
} }
} }
ok := false // x's type V is not a named type and T is a type parameter, and
code := _IncompatibleAssign // x is assignable to each specific type in T's type set.
switch { if !hasName(V) && Tp != nil {
case Vp != nil && Tp != nil: ok := false
x := *x // don't clobber outer x code := _IncompatibleAssign
ok = Vp.is(func(V *term) bool { Tp.is(func(T *term) bool {
x.typ = V.typ if T == nil {
return Tp.is(func(T *term) bool { return false // no specific types
ok, code = x.assignableTo(check, T.typ, reason) }
if !ok { ok, code = x.assignableTo(check, T.typ, reason)
errorf("cannot assign %s (in %s) to %s (in %s)", V.typ, Vp, T.typ, Tp) if !ok {
return false errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp)
} return false
return true }
}) 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 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 x.typ = V.typ
ok, code = x.assignableTo(check, T, reason) ok, code = x.assignableTo(check, T, reason)
if !ok { if !ok {
@ -352,17 +355,8 @@ func (x *operand) assignableTo(check *Checker, T Type, reason *string) (bool, er
} }
return true return true
}) })
case Tp != nil: return ok, code
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 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 ( var (
_ _CC = C _ _CC = C // ERROR cannot use C .* as _CC value
_ _SC = C _ _SC = C // ERROR cannot use C .* as _SC value
_ _RC = C _ _RC = C // ERROR cannot use C .* as _RC value
_ CC = _CC(nil) _ CC = _CC /* ERROR cannot use _CC\(nil\) .* as CC value */ (nil)
_ SC = _CC(nil) _ SC = _CC /* ERROR cannot use _CC\(nil\) .* as SC value */ (nil)
_ RC = _CC(nil) _ RC = _CC /* ERROR cannot use _CC\(nil\) .* as RC value */ (nil)
_ CC = C _ CC = C // ERROR cannot use C .* as CC value
_ SC = C // ERROR cannot use C .* as SC value .* cannot assign Chan to SendChan _ SC = C // ERROR cannot use C .* as SC value
_ RC = C // ERROR cannot use C .* as RC value .* cannot assign Chan to RecvChan _ 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" // "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. // TODO(rfindley) error messages about untyped nil diverge from types2 here.
// Consider aligning them. // Consider aligning them.