]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: differently named types are not assignable
authorRobert Findley <rfindley@google.com>
Tue, 2 Nov 2021 15:46:25 +0000 (11:46 -0400)
committerRobert Findley <rfindley@google.com>
Tue, 2 Nov 2021 21:19:29 +0000 (21:19 +0000)
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>
src/go/types/operand.go
src/go/types/testdata/fixedbugs/issue49242.go2 [new file with mode: 0644]
src/go/types/testdata/spec/assignability.go2

index a71449083f95d0930185fe9a1f0c98692624b4fe..8b76e939b6773c3b1bba6dc6a73158047dd88fa8 100644 (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,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 (file)
index 0000000..524a0cb
--- /dev/null
@@ -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))
+}
index 8ec878bf398ad8d9a1f940cc729110c3bfa48437..a6e71aac817e340784a8c7cf5f9aecc2837d8873 100644 (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.