cmd/compile: give ChanDir a type

Change-Id: I03621db79637b04982e1f0e7b4268c4ed2db6d22
Reviewed-on: https://go-review.googlesource.com/21484
Reviewed-by: Josh Bleecher Snyder <josharian@gmail.com>
Run-TryBot: Brad Fitzpatrick <bradfitz@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
diff --git a/src/cmd/compile/internal/gc/bimport.go b/src/cmd/compile/internal/gc/bimport.go
index 0a51ab0..4bf6f1d 100644
--- a/src/cmd/compile/internal/gc/bimport.go
+++ b/src/cmd/compile/internal/gc/bimport.go
@@ -316,7 +316,7 @@
 
 	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 9480559..5eb9948 100644
--- a/src/cmd/compile/internal/gc/fmt.go
+++ b/src/cmd/compile/internal/gc/fmt.go
@@ -1154,7 +1154,7 @@
 		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 @@
 			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 117836d..fdea1f2 100644
--- a/src/cmd/compile/internal/gc/go.go
+++ b/src/cmd/compile/internal/gc/go.go
@@ -128,12 +128,18 @@
 	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 b71cf8f..4649c45 100644
--- a/src/cmd/compile/internal/gc/parser.go
+++ b/src/cmd/compile/internal/gc/parser.go
@@ -1187,17 +1187,17 @@
 
 		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 @@
 		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 @@
 		// 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 6a28c3c..6adf8e0 100644
--- a/src/cmd/compile/internal/gc/range.go
+++ b/src/cmd/compile/internal/gc/range.go
@@ -58,7 +58,7 @@
 		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 b23b466..2f3b98a 100644
--- a/src/cmd/compile/internal/gc/syntax.go
+++ b/src/cmd/compile/internal/gc/syntax.go
@@ -52,7 +52,7 @@
 	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 d207a04..b89c5db 100644
--- a/src/cmd/compile/internal/gc/type.go
+++ b/src/cmd/compile/internal/gc/type.go
@@ -110,7 +110,7 @@
 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 @@
 }
 
 // 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 @@
 
 // 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 6b56621..0b8eb8c 100644
--- a/src/cmd/compile/internal/gc/typecheck.go
+++ b/src/cmd/compile/internal/gc/typecheck.go
@@ -414,7 +414,7 @@
 			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 @@
 			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 @@
 			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 @@
 			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