go.tools/go/types: use types.ChanDir instead of ast.ChanDir
Clearer code and fewer dependencies on go/ast. R=adonovan CC=golang-dev https://golang.org/cl/43630043
This commit is contained in:
parent
1de4f6df60
commit
74d33a9c33
|
|
@ -10,7 +10,6 @@ import (
|
|||
"bufio"
|
||||
"errors"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/build"
|
||||
"go/token"
|
||||
"io"
|
||||
|
|
@ -601,17 +600,17 @@ func (p *parser) parseInterfaceType() types.Type {
|
|||
// ChanType = ( "chan" [ "<-" ] | "<-" "chan" ) Type .
|
||||
//
|
||||
func (p *parser) parseChanType() types.Type {
|
||||
dir := ast.SEND | ast.RECV
|
||||
dir := types.SendRecv
|
||||
if p.tok == scanner.Ident {
|
||||
p.expectKeyword("chan")
|
||||
if p.tok == '<' {
|
||||
p.expectSpecial("<-")
|
||||
dir = ast.SEND
|
||||
dir = types.SendOnly
|
||||
}
|
||||
} else {
|
||||
p.expectSpecial("<-")
|
||||
p.expectKeyword("chan")
|
||||
dir = ast.RECV
|
||||
dir = types.RecvOnly
|
||||
}
|
||||
elem := p.parseType()
|
||||
return types.NewChan(dir, elem)
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ package importer
|
|||
import (
|
||||
"encoding/binary"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
|
|
@ -251,7 +250,7 @@ func (p *importer) typ() types.Type {
|
|||
t := new(types.Chan)
|
||||
p.record(t)
|
||||
|
||||
*t = *types.NewChan(ast.ChanDir(p.int()), p.typ())
|
||||
*t = *types.NewChan(types.ChanDir(p.int()), p.typ())
|
||||
return t
|
||||
|
||||
case _Named:
|
||||
|
|
|
|||
|
|
@ -175,7 +175,7 @@ func (check *checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
|||
check.invalidArg(x.pos(), "%s is not a channel", x)
|
||||
return
|
||||
}
|
||||
if c.dir&ast.SEND == 0 {
|
||||
if c.dir == RecvOnly {
|
||||
check.invalidArg(x.pos(), "%s must not be a receive-only channel", x)
|
||||
return
|
||||
}
|
||||
|
|
|
|||
|
|
@ -102,7 +102,7 @@ func (check *checker) unary(x *operand, op token.Token) {
|
|||
x.mode = invalid
|
||||
return
|
||||
}
|
||||
if typ.dir&ast.RECV == 0 {
|
||||
if typ.dir == SendOnly {
|
||||
check.invalidOp(x.pos(), "cannot receive from send-only channel %s", x)
|
||||
x.mode = invalid
|
||||
return
|
||||
|
|
|
|||
|
|
@ -231,7 +231,7 @@ func (x *operand) isAssignableTo(conf *Config, T Type) bool {
|
|||
// x is a bidirectional channel value, T is a channel
|
||||
// type, x's type V and T have identical element types,
|
||||
// and at least one of V or T is not a named type
|
||||
if Vc, ok := Vu.(*Chan); ok && Vc.dir == ast.SEND|ast.RECV {
|
||||
if Vc, ok := Vu.(*Chan); ok && Vc.dir == SendRecv {
|
||||
if Tc, ok := Tu.(*Chan); ok && IsIdentical(Vc.elem, Tc.elem) {
|
||||
return !isNamed(V) || !isNamed(T)
|
||||
}
|
||||
|
|
|
|||
|
|
@ -202,7 +202,7 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
if ch.mode == invalid || x.mode == invalid {
|
||||
return
|
||||
}
|
||||
if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir&ast.SEND == 0 || !check.assignment(&x, tch.elem) {
|
||||
if tch, ok := ch.typ.Underlying().(*Chan); !ok || tch.dir == RecvOnly || !check.assignment(&x, tch.elem) {
|
||||
if x.mode != invalid {
|
||||
check.invalidOp(ch.pos(), "cannot send %s to channel %s", &x, &ch)
|
||||
}
|
||||
|
|
@ -571,7 +571,7 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||
case *Chan:
|
||||
key = typ.elem
|
||||
val = Typ[Invalid]
|
||||
if typ.dir&ast.RECV == 0 {
|
||||
if typ.dir == SendOnly {
|
||||
check.errorf(x.pos(), "cannot range over send-only channel %s", &x)
|
||||
// ok to continue
|
||||
}
|
||||
|
|
|
|||
|
|
@ -4,10 +4,7 @@
|
|||
|
||||
package types
|
||||
|
||||
import (
|
||||
"go/ast"
|
||||
"sort"
|
||||
)
|
||||
import "sort"
|
||||
|
||||
// TODO(gri) Revisit factory functions - make sure they have all relevant parameters.
|
||||
|
||||
|
|
@ -322,17 +319,27 @@ func (m *Map) Elem() Type { return m.elem }
|
|||
|
||||
// A Chan represents a channel type.
|
||||
type Chan struct {
|
||||
dir ast.ChanDir
|
||||
dir ChanDir
|
||||
elem Type
|
||||
}
|
||||
|
||||
// A ChanDir value indicates a channel direction.
|
||||
type ChanDir int
|
||||
|
||||
// The direction of a channel is indicated by one of the following constants.
|
||||
const (
|
||||
SendRecv ChanDir = iota
|
||||
SendOnly
|
||||
RecvOnly
|
||||
)
|
||||
|
||||
// NewChan returns a new channel type for the given direction and element type.
|
||||
func NewChan(dir ast.ChanDir, elem Type) *Chan {
|
||||
func NewChan(dir ChanDir, elem Type) *Chan {
|
||||
return &Chan{dir, elem}
|
||||
}
|
||||
|
||||
// Dir returns the direction of channel c.
|
||||
func (c *Chan) Dir() ast.ChanDir { return c.dir }
|
||||
func (c *Chan) Dir() ChanDir { return c.dir }
|
||||
|
||||
// Elem returns the element type of channel c.
|
||||
func (c *Chan) Elem() Type { return c.elem }
|
||||
|
|
|
|||
|
|
@ -9,7 +9,6 @@ package types
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"sort"
|
||||
)
|
||||
|
||||
|
|
@ -122,16 +121,18 @@ func WriteType(buf *bytes.Buffer, this *Package, typ Type) {
|
|||
var s string
|
||||
var parens bool
|
||||
switch t.dir {
|
||||
case ast.SEND:
|
||||
s = "chan<- "
|
||||
case ast.RECV:
|
||||
s = "<-chan "
|
||||
default:
|
||||
case SendRecv:
|
||||
s = "chan "
|
||||
// chan (<-chan T) requires parentheses
|
||||
if c, _ := t.elem.(*Chan); c != nil && c.dir == ast.RECV {
|
||||
if c, _ := t.elem.(*Chan); c != nil && c.dir == RecvOnly {
|
||||
parens = true
|
||||
}
|
||||
case SendOnly:
|
||||
s = "chan<- "
|
||||
case RecvOnly:
|
||||
s = "<-chan "
|
||||
default:
|
||||
panic("unreachable")
|
||||
}
|
||||
buf.WriteString(s)
|
||||
if parens {
|
||||
|
|
|
|||
|
|
@ -337,7 +337,19 @@ func (check *checker) typInternal(e ast.Expr, def *Named, cycleOk bool) Type {
|
|||
def.underlying = typ
|
||||
}
|
||||
|
||||
typ.dir = e.Dir
|
||||
dir := SendRecv
|
||||
switch e.Dir {
|
||||
case ast.SEND | ast.RECV:
|
||||
// nothing to do
|
||||
case ast.SEND:
|
||||
dir = SendOnly
|
||||
case ast.RECV:
|
||||
dir = RecvOnly
|
||||
default:
|
||||
check.invalidAST(e.Pos(), "unknown channel direction %d", e.Dir)
|
||||
// ok to continue
|
||||
}
|
||||
typ.dir = dir
|
||||
typ.elem = check.typ(e.Value, nil, true)
|
||||
return typ
|
||||
|
||||
|
|
|
|||
|
|
@ -89,7 +89,7 @@ func peers(o *Oracle, qpos *QueryPos) (queryResult, error) {
|
|||
for _, op := range ops {
|
||||
for _, ptr := range ptares.Queries[op.ch] {
|
||||
if ptr.PointsTo().Intersects(queryChanPts) {
|
||||
if op.dir == ast.SEND {
|
||||
if op.dir == types.SendOnly {
|
||||
sends = append(sends, op.pos)
|
||||
} else {
|
||||
receives = append(receives, op.pos)
|
||||
|
|
@ -129,7 +129,7 @@ func findArrow(qpos *QueryPos) token.Pos {
|
|||
// chanOp abstracts an ssa.Send, ssa.Unop(ARROW), or a SelectState.
|
||||
type chanOp struct {
|
||||
ch ssa.Value
|
||||
dir ast.ChanDir
|
||||
dir types.ChanDir // SendOnly or RecvOnly
|
||||
pos token.Pos
|
||||
}
|
||||
|
||||
|
|
@ -140,10 +140,10 @@ func chanOps(instr ssa.Instruction) []chanOp {
|
|||
switch instr := instr.(type) {
|
||||
case *ssa.UnOp:
|
||||
if instr.Op == token.ARROW {
|
||||
ops = append(ops, chanOp{instr.X, ast.RECV, instr.Pos()})
|
||||
ops = append(ops, chanOp{instr.X, types.RecvOnly, instr.Pos()})
|
||||
}
|
||||
case *ssa.Send:
|
||||
ops = append(ops, chanOp{instr.Chan, ast.SEND, instr.Pos()})
|
||||
ops = append(ops, chanOp{instr.Chan, types.SendOnly, instr.Pos()})
|
||||
case *ssa.Select:
|
||||
for _, st := range instr.States {
|
||||
ops = append(ops, chanOp{st.Chan, st.Dir, st.Pos})
|
||||
|
|
|
|||
|
|
@ -12,7 +12,6 @@ package pointer
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"go/token"
|
||||
|
||||
"code.google.com/p/go.tools/go/types"
|
||||
|
|
@ -994,11 +993,11 @@ func (a *analysis) genInstr(cgn *cgnode, instr ssa.Instruction) {
|
|||
for _, st := range instr.States {
|
||||
elemSize := a.sizeof(st.Chan.Type().Underlying().(*types.Chan).Elem())
|
||||
switch st.Dir {
|
||||
case ast.RECV:
|
||||
case types.RecvOnly:
|
||||
a.genLoad(cgn, recv, st.Chan, 0, elemSize)
|
||||
recv += nodeid(elemSize)
|
||||
|
||||
case ast.SEND:
|
||||
case types.SendOnly:
|
||||
a.genStore(cgn, st.Chan, a.valueNode(st.Send), 0, elemSize)
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -25,7 +25,6 @@ package pointer
|
|||
|
||||
import (
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"reflect"
|
||||
|
||||
"code.google.com/p/go.tools/go/exact"
|
||||
|
|
@ -781,7 +780,7 @@ type reflectChanOfConstraint struct {
|
|||
cgn *cgnode
|
||||
t nodeid // (ptr)
|
||||
result nodeid
|
||||
dirs []ast.ChanDir
|
||||
dirs []types.ChanDir
|
||||
}
|
||||
|
||||
func (c *reflectChanOfConstraint) String() string {
|
||||
|
|
@ -809,11 +808,11 @@ func (c *reflectChanOfConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
|||
}
|
||||
|
||||
// dirMap maps reflect.ChanDir to the set of channel types generated by ChanOf.
|
||||
var dirMap = [...][]ast.ChanDir{
|
||||
0: {ast.RECV, ast.SEND, ast.RECV | ast.SEND}, // unknown
|
||||
reflect.RecvDir: {ast.RECV},
|
||||
reflect.SendDir: {ast.SEND},
|
||||
reflect.BothDir: {ast.RECV | ast.SEND},
|
||||
var dirMap = [...][]types.ChanDir{
|
||||
0: {types.SendOnly, types.RecvOnly, types.SendRecv}, // unknown
|
||||
reflect.RecvDir: {types.RecvOnly},
|
||||
reflect.SendDir: {types.SendOnly},
|
||||
reflect.BothDir: {types.SendRecv},
|
||||
}
|
||||
|
||||
func ext۰reflect۰ChanOf(a *analysis, cgn *cgnode) {
|
||||
|
|
@ -909,7 +908,7 @@ func (c *reflectMakeChanConstraint) solve(a *analysis, _ *node, delta nodeset) {
|
|||
for typObj := range delta {
|
||||
T := a.rtypeTaggedValue(typObj)
|
||||
tChan, ok := T.Underlying().(*types.Chan)
|
||||
if !ok || tChan.Dir() != ast.SEND|ast.RECV {
|
||||
if !ok || tChan.Dir() != types.SendRecv {
|
||||
continue // not a bidirectional channel type
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -1385,7 +1385,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
|
|||
case *ast.SendStmt: // ch<- i
|
||||
ch := b.expr(fn, comm.Chan)
|
||||
st = &SelectState{
|
||||
Dir: ast.SEND,
|
||||
Dir: types.SendOnly,
|
||||
Chan: ch,
|
||||
Send: emitConv(fn, b.expr(fn, comm.Value),
|
||||
ch.Type().Underlying().(*types.Chan).Elem()),
|
||||
|
|
@ -1398,7 +1398,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
|
|||
case *ast.AssignStmt: // x := <-ch
|
||||
recv := unparen(comm.Rhs[0]).(*ast.UnaryExpr)
|
||||
st = &SelectState{
|
||||
Dir: ast.RECV,
|
||||
Dir: types.RecvOnly,
|
||||
Chan: b.expr(fn, recv.X),
|
||||
Pos: recv.OpPos,
|
||||
}
|
||||
|
|
@ -1409,7 +1409,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
|
|||
case *ast.ExprStmt: // <-ch
|
||||
recv := unparen(comm.X).(*ast.UnaryExpr)
|
||||
st = &SelectState{
|
||||
Dir: ast.RECV,
|
||||
Dir: types.RecvOnly,
|
||||
Chan: b.expr(fn, recv.X),
|
||||
Pos: recv.OpPos,
|
||||
}
|
||||
|
|
@ -1440,7 +1440,7 @@ func (b *builder) selectStmt(fn *Function, s *ast.SelectStmt, label *lblock) {
|
|||
var vars []*types.Var
|
||||
vars = append(vars, varIndex, varOk)
|
||||
for _, st := range states {
|
||||
if st.Dir == ast.RECV {
|
||||
if st.Dir == types.RecvOnly {
|
||||
tElem := st.Chan.Type().Underlying().(*types.Chan).Elem()
|
||||
vars = append(vars, types.NewVar(token.NoPos, nil, "", tElem))
|
||||
}
|
||||
|
|
|
|||
|
|
@ -10,7 +10,6 @@ package ssa
|
|||
import (
|
||||
"bytes"
|
||||
"fmt"
|
||||
"go/ast"
|
||||
"io"
|
||||
"reflect"
|
||||
"sort"
|
||||
|
|
@ -322,7 +321,7 @@ func (s *Select) String() string {
|
|||
if i > 0 {
|
||||
b.WriteString(", ")
|
||||
}
|
||||
if st.Dir == ast.RECV {
|
||||
if st.Dir == types.RecvOnly {
|
||||
b.WriteString("<-")
|
||||
b.WriteString(relName(st.Chan, s))
|
||||
} else {
|
||||
|
|
|
|||
10
ssa/ssa.go
10
ssa/ssa.go
|
|
@ -835,11 +835,11 @@ type Lookup struct {
|
|||
// It represents one goal state and its corresponding communication.
|
||||
//
|
||||
type SelectState struct {
|
||||
Dir ast.ChanDir // direction of case
|
||||
Chan Value // channel to use (for send or receive)
|
||||
Send Value // value to send (for send)
|
||||
Pos token.Pos // position of token.ARROW
|
||||
DebugNode ast.Node // ast.SendStmt or ast.UnaryExpr(<-) [debug mode]
|
||||
Dir types.ChanDir // direction of case (SendOnly or RecvOnly)
|
||||
Chan Value // channel to use (for send or receive)
|
||||
Send Value // value to send (for send)
|
||||
Pos token.Pos // position of token.ARROW
|
||||
DebugNode ast.Node // ast.SendStmt or ast.UnaryExpr(<-) [debug mode]
|
||||
}
|
||||
|
||||
// The Select instruction tests whether (or blocks until) one or more
|
||||
|
|
|
|||
Loading…
Reference in New Issue