return
case syntax.Recv:
- u := coreType(x.typ)
- if u == nil {
- check.errorf(x, InvalidReceive, invalidOp+"cannot receive from %s (no core type)", x)
- x.mode = invalid
+ if elem := check.chanElem(x, x, true); elem != nil {
+ x.mode = commaok
+ x.typ = elem
+ check.hasCallOrRecv = true
return
}
- ch, _ := u.(*Chan)
- if ch == nil {
- check.errorf(x, InvalidReceive, invalidOp+"cannot receive from non-channel %s", x)
- x.mode = invalid
- return
- }
- if ch.dir == SendOnly {
- check.errorf(x, InvalidReceive, invalidOp+"cannot receive from send-only channel %s", x)
- x.mode = invalid
- return
- }
- x.mode = commaok
- x.typ = ch.elem
- check.hasCallOrRecv = true
+ x.mode = invalid
return
case syntax.Tilde:
// x.typ remains unchanged
}
+// chanElem returns the channel element type of x for a receive from x (recv == true)
+// or send to x (recv == false) operation. If the operation is not valid, chanElem
+// reports an error and returns nil.
+func (check *Checker) chanElem(pos poser, x *operand, recv bool) Type {
+ var elem Type
+ var cause string
+ typeset(x.typ, func(t, u Type) bool {
+ if u == nil {
+ // Type set contains no explicit terms.
+ // It is either empty or contains all types (any)
+ cause = "no specific channel type"
+ return false
+ }
+ ch, _ := u.(*Chan)
+ if ch == nil {
+ cause = check.sprintf("non-channel %s", t)
+ return false
+ }
+ if recv && ch.dir == SendOnly {
+ cause = check.sprintf("send-only channel %s", t)
+ return false
+ }
+ if !recv && ch.dir == RecvOnly {
+ cause = check.sprintf("receive-only channel %s", t)
+ return false
+ }
+ if elem != nil && !Identical(elem, ch.elem) {
+ cause = check.sprintf("channels with different element types %s and %s", elem, ch.elem)
+ return false
+ }
+ elem = ch.elem
+ return true
+ })
+
+ if cause == "" {
+ return elem
+ }
+
+ if recv {
+ if isTypeParam(x.typ) {
+ check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s: type set contains %s", x, cause)
+ } else {
+ // In this case, only the non-channel and send-only channel error are possible.
+ check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s %s", cause, x)
+ }
+ } else {
+ if isTypeParam(x.typ) {
+ check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s: type set contains %s", x, cause)
+ } else {
+ // In this case, only the non-channel and receive-only channel error are possible.
+ check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s %s", cause, x)
+ }
+ }
+ return nil
+}
+
func isShift(op syntax.Operator) bool {
return op == syntax.Shl || op == syntax.Shr
}
if ch.mode == invalid || val.mode == invalid {
return
}
- u := coreType(ch.typ)
- if u == nil {
- check.errorf(s, InvalidSend, invalidOp+"cannot send to %s: no core type", &ch)
- return
- }
- uch, _ := u.(*Chan)
- if uch == nil {
- check.errorf(s, InvalidSend, invalidOp+"cannot send to non-channel %s", &ch)
- return
- }
- if uch.dir == RecvOnly {
- check.errorf(s, InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch)
- return
+ if elem := check.chanElem(s, &ch, false); elem != nil {
+ check.assignment(&val, elem, "send")
}
- check.assignment(&val, uch.elem, "send")
case *syntax.AssignStmt:
if s.Rhs == nil {
return
case token.ARROW:
- u := coreType(x.typ)
- if u == nil {
- check.errorf(x, InvalidReceive, invalidOp+"cannot receive from %s (no core type)", x)
- x.mode = invalid
+ if elem := check.chanElem(x, x, true); elem != nil {
+ x.mode = commaok
+ x.typ = elem
+ check.hasCallOrRecv = true
return
}
- ch, _ := u.(*Chan)
- if ch == nil {
- check.errorf(x, InvalidReceive, invalidOp+"cannot receive from non-channel %s", x)
- x.mode = invalid
- return
- }
- if ch.dir == SendOnly {
- check.errorf(x, InvalidReceive, invalidOp+"cannot receive from send-only channel %s", x)
- x.mode = invalid
- return
- }
-
- x.mode = commaok
- x.typ = ch.elem
- check.hasCallOrRecv = true
+ x.mode = invalid
return
case token.TILDE:
// x.typ remains unchanged
}
+// chanElem returns the channel element type of x for a receive from x (recv == true)
+// or send to x (recv == false) operation. If the operation is not valid, chanElem
+// reports an error and returns nil.
+func (check *Checker) chanElem(pos positioner, x *operand, recv bool) Type {
+ var elem Type
+ var cause string
+ typeset(x.typ, func(t, u Type) bool {
+ if u == nil {
+ // Type set contains no explicit terms.
+ // It is either empty or contains all types (any)
+ cause = "no specific channel type"
+ return false
+ }
+ ch, _ := u.(*Chan)
+ if ch == nil {
+ cause = check.sprintf("non-channel %s", t)
+ return false
+ }
+ if recv && ch.dir == SendOnly {
+ cause = check.sprintf("send-only channel %s", t)
+ return false
+ }
+ if !recv && ch.dir == RecvOnly {
+ cause = check.sprintf("receive-only channel %s", t)
+ return false
+ }
+ if elem != nil && !Identical(elem, ch.elem) {
+ cause = check.sprintf("channels with different element types %s and %s", elem, ch.elem)
+ return false
+ }
+ elem = ch.elem
+ return true
+ })
+
+ if cause == "" {
+ return elem
+ }
+
+ if recv {
+ if isTypeParam(x.typ) {
+ check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s: type set contains %s", x, cause)
+ } else {
+ // In this case, only the non-channel and send-only channel error are possible.
+ check.errorf(pos, InvalidReceive, invalidOp+"cannot receive from %s %s", cause, x)
+ }
+ } else {
+ if isTypeParam(x.typ) {
+ check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s: type set contains %s", x, cause)
+ } else {
+ // In this case, only the non-channel and receive-only channel error are possible.
+ check.errorf(pos, InvalidSend, invalidOp+"cannot send to %s %s", cause, x)
+ }
+ }
+ return nil
+}
+
func isShift(op token.Token) bool {
return op == token.SHL || op == token.SHR
}
if ch.mode == invalid || val.mode == invalid {
return
}
- u := coreType(ch.typ)
- if u == nil {
- check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to %s: no core type", &ch)
- return
- }
- uch, _ := u.(*Chan)
- if uch == nil {
- check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to non-channel %s", &ch)
- return
- }
- if uch.dir == RecvOnly {
- check.errorf(inNode(s, s.Arrow), InvalidSend, invalidOp+"cannot send to receive-only channel %s", &ch)
- return
+ if elem := check.chanElem(inNode(s, s.Arrow), &ch, false); elem != nil {
+ check.assignment(&val, elem, "send")
}
- check.assignment(&val, uch.elem, "send")
case *ast.IncDecStmt:
var op token.Token
type C5[T any] interface{ ~chan T | <-chan T }
func _[T any](ch T) {
- <-ch // ERRORx `cannot receive from ch .* \(no core type\)`
+ <-ch // ERRORx `cannot receive from ch .*: type set contains no specific channel type`
}
func _[T C0](ch T) {
- <-ch // ERROR "cannot receive from non-channel ch"
+ <-ch // ERRORx `cannot receive from ch .*: type set contains non-channel int`
}
func _[T C1](ch T) {
}
func _[T C3](ch T) {
- <-ch // ERRORx `cannot receive from ch .* \(no core type\)`
+ <-ch // ERRORx `cannot receive from ch .*: type set contains channels with different element types int and float32`
}
func _[T C4](ch T) {
- <-ch // ERROR "cannot receive from send-only channel"
+ <-ch // ERRORx `cannot receive from ch .*: type set contains send-only channel chan<- int`
}
func _[T C5[X], X any](ch T, x X) {
type C5[T any] interface{ ~chan T | chan<- T }
func _[T any](ch T) {
- ch <- /* ERRORx `cannot send to ch .* no core type` */ 0
+ ch <- /* ERRORx `cannot send to ch .*: type set contains no specific channel type` */ 0
}
func _[T C0](ch T) {
- ch <- /* ERROR "cannot send to non-channel" */ 0
+ ch <- /* ERRORx `cannot send to ch .*: type set contains non-channel int` */ 0
}
func _[T C1](ch T) {
}
func _[T C2](ch T) {
- ch <-/* ERROR "cannot send to receive-only channel" */ 0
+ ch <- /* ERRORx `cannot send to ch .*: type set contains receive-only channel <-chan int` */ 0
}
func _[T C3](ch T) {
- ch <- /* ERRORx `cannot send to ch .* no core type` */ 0
+ ch <- /* ERRORx `cannot send to ch .*: type set contains channels with different element types` */ 0
}
func _[T C4](ch T) {