From: Robert Findley Date: Tue, 2 Nov 2021 15:46:25 +0000 (-0400) Subject: go/types: differently named types are not assignable X-Git-Tag: go1.18beta1~591 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=42e6b5bce2d027d4fcc4a7358b97a468494855d8;p=gostls13.git 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 Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- diff --git a/src/go/types/operand.go b/src/go/types/operand.go index a71449083f..8b76e939b6 100644 --- a/src/go/types/operand.go +++ b/src/go/types/operand.go @@ -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,44 +317,46 @@ 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 - }) - }) - case Vp != nil: - x := *x // don't clobber outer x - ok = Vp.is(func(V *term) bool { - x.typ = V.typ - ok, code = x.assignableTo(check, T, reason) + // 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 (in %s) to %s", V.typ, Vp, T) + errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp) return false } return true }) - case Tp != 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 = Tp.is(func(T *term) bool { - ok, code = x.assignableTo(check, T.typ, reason) + 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 { - errorf("cannot assign %s to %s (in %s)", x.typ, T.typ, Tp) + errorf("cannot assign %s (in %s) to %s", V.typ, Vp, T) return false } return true }) + return ok, code } - return ok, code + return false, _IncompatibleAssign } diff --git a/src/go/types/testdata/fixedbugs/issue49242.go2 b/src/go/types/testdata/fixedbugs/issue49242.go2 new file mode 100644 index 0000000000..524a0cbae3 --- /dev/null +++ b/src/go/types/testdata/fixedbugs/issue49242.go2 @@ -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)) +} diff --git a/src/go/types/testdata/spec/assignability.go2 b/src/go/types/testdata/spec/assignability.go2 index 8ec878bf39..a6e71aac81 100644 --- a/src/go/types/testdata/spec/assignability.go2 +++ b/src/go/types/testdata/spec/assignability.go2 @@ -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.