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