diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go index 0a51ab037fe..4bf6f1d286a 100644 --- a/src/cmd/compile/internal/gc/bimport.go +++ b/src/cmd/compile/internal/gc/bimport.go @@ -316,7 +316,7 @@ func (p *importer) typ() *Type { case chanTag: t = p.newtyp(TCHAN) - t.Chan = uint8(p.int()) + t.Chan = ChanDir(p.int()) t.Type = p.typ() default: diff --git a/src/cmd/compile/internal/gc/fmt.go b/src/cmd/compile/internal/gc/fmt.go index 94805594c7d..5eb99489bdf 100644 --- a/src/cmd/compile/internal/gc/fmt.go +++ b/src/cmd/compile/internal/gc/fmt.go @@ -1154,7 +1154,7 @@ func exprfmt(n *Node, prec int) string { return fmt.Sprintf("map[%v]%v", n.Left, n.Right) case OTCHAN: - switch n.Etype { + switch ChanDir(n.Etype) { case Crecv: return fmt.Sprintf("<-chan %v", n.Left) @@ -1162,7 +1162,7 @@ func exprfmt(n *Node, prec int) string { return fmt.Sprintf("chan<- %v", n.Left) default: - if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && n.Left.Etype == Crecv { + if n.Left != nil && n.Left.Op == OTCHAN && n.Left.Sym == nil && ChanDir(n.Left.Etype) == Crecv { return fmt.Sprintf("chan (%v)", n.Left) } else { return fmt.Sprintf("chan %v", n.Left) diff --git a/src/cmd/compile/internal/gc/go.go b/src/cmd/compile/internal/gc/go.go index 117836d2cd2..fdea1f2fbac 100644 --- a/src/cmd/compile/internal/gc/go.go +++ b/src/cmd/compile/internal/gc/go.go @@ -128,12 +128,18 @@ const ( CTNIL ) +// ChanDir is whether a channel can send, receive, or both. +type ChanDir uint8 + +func (c ChanDir) CanRecv() bool { return c&Crecv != 0 } +func (c ChanDir) CanSend() bool { return c&Csend != 0 } + const ( // types of channel // must match ../../../../reflect/type.go:/ChanDir - Crecv = 1 << 0 - Csend = 1 << 1 - Cboth = Crecv | Csend + Crecv ChanDir = 1 << 0 + Csend ChanDir = 1 << 1 + Cboth ChanDir = Crecv | Csend ) // The Class of a variable/function describes the "storage class" diff --git a/src/cmd/compile/internal/gc/parser.go b/src/cmd/compile/internal/gc/parser.go index b71cf8fef42..4649c4593b5 100644 --- a/src/cmd/compile/internal/gc/parser.go +++ b/src/cmd/compile/internal/gc/parser.go @@ -1187,17 +1187,17 @@ func (p *parser) uexpr() *Node { if x.Op == OTCHAN { // x is a channel type => re-associate <- - dir := EType(Csend) + dir := Csend t := x for ; t.Op == OTCHAN && dir == Csend; t = t.Left { - dir = t.Etype + dir = ChanDir(t.Etype) if dir == Crecv { // t is type <-chan E but <-<-chan E is not permitted // (report same error as for "type _ <-<-chan E") p.syntax_error("unexpected <-, expecting chan") // already progressed, no need to advance } - t.Etype = Crecv + t.Etype = EType(Crecv) } if dir == Csend { // channel dir is <- but channel element E is not a channel @@ -1697,7 +1697,7 @@ func (p *parser) try_ntype() *Node { p.next() p.want(LCHAN) t := Nod(OTCHAN, p.chan_elem(), nil) - t.Etype = Crecv + t.Etype = EType(Crecv) return t case LFUNC: @@ -1726,9 +1726,9 @@ func (p *parser) try_ntype() *Node { // LCHAN non_recvchantype // LCHAN LCOMM ntype p.next() - var dir EType = Cboth + var dir = EType(Cboth) if p.got(LCOMM) { - dir = Csend + dir = EType(Csend) } t := Nod(OTCHAN, p.chan_elem(), nil) t.Etype = dir diff --git a/src/cmd/compile/internal/gc/range.go b/src/cmd/compile/internal/gc/range.go index 6a28c3ceb5e..6adf8e0d6dc 100644 --- a/src/cmd/compile/internal/gc/range.go +++ b/src/cmd/compile/internal/gc/range.go @@ -58,7 +58,7 @@ func typecheckrange(n *Node) { t2 = t.Val() case TCHAN: - if t.ChanDir()&Crecv == 0 { + if !t.ChanDir().CanRecv() { Yyerror("invalid operation: range %v (receive from send-only type %v)", n.Right, n.Right.Type) goto out } diff --git a/src/cmd/compile/internal/gc/syntax.go b/src/cmd/compile/internal/gc/syntax.go index b23b4660886..2f3b98a8ef8 100644 --- a/src/cmd/compile/internal/gc/syntax.go +++ b/src/cmd/compile/internal/gc/syntax.go @@ -52,7 +52,7 @@ type Node struct { Op Op Ullman uint8 // sethi/ullman number Addable bool // addressable - Etype EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg + Etype EType // op for OASOP, etype for OTYPE, exclam for export, 6g saved reg, ChanDir for OTCHAN Bounded bool // bounds check unnecessary Class Class // PPARAM, PAUTO, PEXTERN, etc Embedded uint8 // ODCLFIELD embedded type diff --git a/src/cmd/compile/internal/gc/type.go b/src/cmd/compile/internal/gc/type.go index d207a046d74..b89c5dbf22f 100644 --- a/src/cmd/compile/internal/gc/type.go +++ b/src/cmd/compile/internal/gc/type.go @@ -110,7 +110,7 @@ var ( type Type struct { Etype EType Noalg bool - Chan uint8 + Chan ChanDir Trecur uint8 // to detect loops Printed bool Funarg bool // on TSTRUCT and TFIELD @@ -266,7 +266,7 @@ func typDDDArray(elem *Type) *Type { } // typChan returns a new chan Type with direction dir. -func typChan(elem *Type, dir uint8) *Type { +func typChan(elem *Type, dir ChanDir) *Type { t := typ(TCHAN) t.Type = elem t.Chan = dir @@ -957,7 +957,7 @@ func (t *Type) SetNumElem(n int64) { // ChanDir returns the direction of a channel type t. // The direction will be one of Crecv, Csend, or Cboth. -func (t *Type) ChanDir() uint8 { +func (t *Type) ChanDir() ChanDir { t.wantEtype(TCHAN) return t.Chan } diff --git a/src/cmd/compile/internal/gc/typecheck.go b/src/cmd/compile/internal/gc/typecheck.go index 6b566210d78..0b8eb8c75bd 100644 --- a/src/cmd/compile/internal/gc/typecheck.go +++ b/src/cmd/compile/internal/gc/typecheck.go @@ -414,7 +414,7 @@ OpSwitch: n.Type = nil return n } - t := typChan(l.Type, uint8(n.Etype)) // TODO(marvin): Fix Node.EType type union. + t := typChan(l.Type, ChanDir(n.Etype)) // TODO(marvin): Fix Node.EType type union. n.Op = OTYPE n.Type = t n.Left = nil @@ -1048,7 +1048,7 @@ OpSwitch: return n } - if t.ChanDir()&Crecv == 0 { + if !t.ChanDir().CanRecv() { Yyerror("invalid operation: %v (receive from send-only type %v)", n, t) n.Type = nil return n @@ -1075,7 +1075,7 @@ OpSwitch: return n } - if t.ChanDir()&Csend == 0 { + if !t.ChanDir().CanSend() { Yyerror("invalid operation: %v (send to receive-only type %v)", n, t) n.Type = nil return n @@ -1528,7 +1528,7 @@ OpSwitch: return n } - if t.ChanDir()&Csend == 0 { + if !t.ChanDir().CanSend() { Yyerror("invalid operation: %v (cannot close receive-only channel)", n) n.Type = nil return n