]> Cypherpunks repositories - gostls13.git/commitdiff
[dev.typeparams] go/types: implement <-ch where ch is of type parameter type
authorRob Findley <rfindley@google.com>
Sat, 17 Jul 2021 00:16:27 +0000 (20:16 -0400)
committerRobert Findley <rfindley@google.com>
Mon, 19 Jul 2021 17:08:29 +0000 (17:08 +0000)
This is a port of CL 333709 to go/types, adjusted for the different
error API.

Fixes #43671

Change-Id: Ifd340149bfbcabe401cec74398cb83f2ae812e51
Reviewed-on: https://go-review.googlesource.com/c/go/+/335075
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/expr.go
src/go/types/testdata/fixedbugs/issue43671.go2 [new file with mode: 0644]

index 46f6e3346311833b325b246dfd41243a7abed78f..751a3608900ea6e952b87a1216d439a3ce39d80d 100644 (file)
@@ -144,6 +144,14 @@ var op2str2 = [...]string{
        token.SHL: "shift",
 }
 
+func underIs(typ Type, f func(Type) bool) bool {
+       u := under(typ)
+       if tpar, _ := u.(*TypeParam); tpar != nil {
+               return tpar.underIs(f)
+       }
+       return f(u)
+}
+
 // The unary expression e may be nil. It's passed in for better error messages only.
 func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
        check.expr(x, e.X)
@@ -164,19 +172,29 @@ func (check *Checker) unary(x *operand, e *ast.UnaryExpr) {
                return
 
        case token.ARROW:
-               typ := asChan(x.typ)
-               if typ == nil {
-                       check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
-                       x.mode = invalid
-                       return
-               }
-               if typ.dir == SendOnly {
-                       check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x)
+               var elem Type
+               if !underIs(x.typ, func(u Type) bool {
+                       ch, _ := u.(*Chan)
+                       if ch == nil {
+                               check.invalidOp(x, _InvalidReceive, "cannot receive from non-channel %s", x)
+                               return false
+                       }
+                       if ch.dir == SendOnly {
+                               check.invalidOp(x, _InvalidReceive, "cannot receive from send-only channel %s", x)
+                               return false
+                       }
+                       if elem != nil && !Identical(ch.elem, elem) {
+                               check.invalidOp(x, _Todo, "channels of %s must have the same element type", x)
+                               return false
+                       }
+                       elem = ch.elem
+                       return true
+               }) {
                        x.mode = invalid
                        return
                }
                x.mode = commaok
-               x.typ = typ.elem
+               x.typ = elem
                check.hasCallOrRecv = true
                return
        }
diff --git a/src/go/types/testdata/fixedbugs/issue43671.go2 b/src/go/types/testdata/fixedbugs/issue43671.go2
new file mode 100644 (file)
index 0000000..6cc3801
--- /dev/null
@@ -0,0 +1,58 @@
+// 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
+
+type C0 interface{ int }
+type C1 interface{ chan int }
+type C2 interface{ chan int | <-chan int }
+type C3 interface{ chan int | chan float32 }
+type C4 interface{ chan int | chan<- int }
+type C5[T any] interface{ ~chan T | <-chan T }
+
+func _[T any](ch T) {
+       <-ch // ERROR cannot receive from non-channel
+}
+
+func _[T C0](ch T) {
+       <-ch // ERROR cannot receive from non-channel
+}
+
+func _[T C1](ch T) {
+       <-ch
+}
+
+func _[T C2](ch T) {
+       <-ch
+}
+
+func _[T C3](ch T) {
+       <-ch // ERROR channels of ch .* must have the same element type
+}
+
+func _[T C4](ch T) {
+       <-ch // ERROR cannot receive from send-only channel
+}
+
+func _[T C5[X], X any](ch T, x X) {
+       x = <-ch
+}
+
+// test case from issue, slightly modified
+type RecvChan[T any] interface {
+       ~chan T | ~<-chan T
+}
+
+func _[T any, C RecvChan[T]](ch C) T {
+       return <-ch
+}
+
+func f[T any, C interface{ chan T }](ch C) T {
+       return <-ch
+}
+
+func _(ch chan int) {
+       var x int = f(ch) // test constraint type inference for this case
+       _ = x
+}