Commit 1659aef3 authored by Robert Griesemer's avatar Robert Griesemer

go/ast: track position of <- for channel types

This is a backward-compatible API change.

Without the correct <- position information,
certain channel types have incorrect position
information.

R=iant, iant
CC=golang-dev
https://golang.org/cl/6585063
parent 5f7f9062
...@@ -407,6 +407,7 @@ type ( ...@@ -407,6 +407,7 @@ type (
// A ChanType node represents a channel type. // A ChanType node represents a channel type.
ChanType struct { ChanType struct {
Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first) Begin token.Pos // position of "chan" keyword or "<-" (whichever comes first)
Arrow token.Pos // position of "<-" (noPos if there is no "<-")
Dir ChanDir // channel direction Dir ChanDir // channel direction
Value Expr // value type Value Expr // value type
} }
......
...@@ -924,20 +924,22 @@ func (p *parser) parseChanType() *ast.ChanType { ...@@ -924,20 +924,22 @@ func (p *parser) parseChanType() *ast.ChanType {
pos := p.pos pos := p.pos
dir := ast.SEND | ast.RECV dir := ast.SEND | ast.RECV
var arrow token.Pos
if p.tok == token.CHAN { if p.tok == token.CHAN {
p.next() p.next()
if p.tok == token.ARROW { if p.tok == token.ARROW {
arrow = p.pos
p.next() p.next()
dir = ast.SEND dir = ast.SEND
} }
} else { } else {
p.expect(token.ARROW) arrow = p.expect(token.ARROW)
p.expect(token.CHAN) p.expect(token.CHAN)
dir = ast.RECV dir = ast.RECV
} }
value := p.parseType() value := p.parseType()
return &ast.ChanType{Begin: pos, Dir: dir, Value: value} return &ast.ChanType{Begin: pos, Arrow: arrow, Dir: dir, Value: value}
} }
// If the result is an identifier, it is not resolved. // If the result is an identifier, it is not resolved.
...@@ -1397,7 +1399,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { ...@@ -1397,7 +1399,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
case token.ARROW: case token.ARROW:
// channel type or receive expression // channel type or receive expression
pos := p.pos arrow := p.pos
p.next() p.next()
// If the next token is token.CHAN we still don't know if it // If the next token is token.CHAN we still don't know if it
...@@ -1421,29 +1423,25 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { ...@@ -1421,29 +1423,25 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr {
// (<-type) // (<-type)
// re-associate position info and <- // re-associate position info and <-
arrow := true dir := ast.SEND
for ok && arrow { for ok && dir == ast.SEND {
begin := typ.Begin
if typ.Dir == ast.RECV { if typ.Dir == ast.RECV {
// error: (<-type) is (<-(<-chan T)) // error: (<-type) is (<-(<-chan T))
p.errorExpected(begin, "'chan'") p.errorExpected(typ.Arrow, "'chan'")
} }
arrow = typ.Dir == ast.SEND arrow, typ.Begin, typ.Arrow = typ.Arrow, arrow, arrow
typ.Begin = pos dir, typ.Dir = typ.Dir, ast.RECV
typ.Dir = ast.RECV
typ, ok = typ.Value.(*ast.ChanType) typ, ok = typ.Value.(*ast.ChanType)
// TODO(gri) ast.ChanType should store exact <- position
pos = begin // estimate (we don't have the exact position of <- for send channels)
} }
if arrow { if dir == ast.SEND {
p.errorExpected(pos, "'chan'") p.errorExpected(arrow, "channel type")
} }
return x return x
} }
// <-(expr) // <-(expr)
return &ast.UnaryExpr{OpPos: pos, Op: token.ARROW, X: p.checkExpr(x)} return &ast.UnaryExpr{OpPos: arrow, Op: token.ARROW, X: p.checkExpr(x)}
case token.MUL: case token.MUL:
// pointer type or unary "*" expression // pointer type or unary "*" expression
......
...@@ -69,7 +69,7 @@ var invalids = []string{ ...@@ -69,7 +69,7 @@ var invalids = []string{
`package p; var a = <- /* ERROR "expected expression" */ chan int;`, `package p; var a = <- /* ERROR "expected expression" */ chan int;`,
`package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`, `package p; func f() { select { case _ <- chan /* ERROR "expected expression" */ int: } };`,
`package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`, `package p; func f() { _ = (<-<- /* ERROR "expected 'chan'" */ chan int)(nil) };`,
`package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan /* ERROR "expected 'chan'" */ <-int)(nil) };`, `package p; func f() { _ = (<-chan<-chan<-chan<-chan<-chan<- /* ERROR "expected channel type" */ int)(nil) };`,
} }
func TestInvalid(t *testing.T) { func TestInvalid(t *testing.T) {
......
...@@ -853,9 +853,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { ...@@ -853,9 +853,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) {
case ast.SEND | ast.RECV: case ast.SEND | ast.RECV:
p.print(token.CHAN) p.print(token.CHAN)
case ast.RECV: case ast.RECV:
p.print(token.ARROW, token.CHAN) p.print(token.ARROW, token.CHAN) // x.Arrow and x.Pos() are the same
case ast.SEND: case ast.SEND:
p.print(token.CHAN, token.ARROW) p.print(token.CHAN, x.Arrow, token.ARROW)
} }
p.print(blank) p.print(blank)
p.expr(x.Value) p.expr(x.Value)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment