From 1659aef3990377081277c48304f7b63a3ce19092 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 2 Oct 2012 17:50:36 -0700 Subject: [PATCH] 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 --- src/pkg/go/ast/ast.go | 1 + src/pkg/go/parser/parser.go | 28 +++++++++++++--------------- src/pkg/go/parser/short_test.go | 2 +- src/pkg/go/printer/nodes.go | 4 ++-- 4 files changed, 17 insertions(+), 18 deletions(-) diff --git a/src/pkg/go/ast/ast.go b/src/pkg/go/ast/ast.go index d2e75dc1c0..e1582c3006 100644 --- a/src/pkg/go/ast/ast.go +++ b/src/pkg/go/ast/ast.go @@ -407,6 +407,7 @@ type ( // A ChanType node represents a channel type. ChanType struct { 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 Value Expr // value type } diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go index 9c1459f40c..139de9fb22 100644 --- a/src/pkg/go/parser/parser.go +++ b/src/pkg/go/parser/parser.go @@ -924,20 +924,22 @@ func (p *parser) parseChanType() *ast.ChanType { pos := p.pos dir := ast.SEND | ast.RECV + var arrow token.Pos if p.tok == token.CHAN { p.next() if p.tok == token.ARROW { + arrow = p.pos p.next() dir = ast.SEND } } else { - p.expect(token.ARROW) + arrow = p.expect(token.ARROW) p.expect(token.CHAN) dir = ast.RECV } 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. @@ -1397,7 +1399,7 @@ func (p *parser) parseUnaryExpr(lhs bool) ast.Expr { case token.ARROW: // channel type or receive expression - pos := p.pos + arrow := p.pos p.next() // 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 { // (<-type) // re-associate position info and <- - arrow := true - for ok && arrow { - begin := typ.Begin + dir := ast.SEND + for ok && dir == ast.SEND { if typ.Dir == ast.RECV { // error: (<-type) is (<-(<-chan T)) - p.errorExpected(begin, "'chan'") + p.errorExpected(typ.Arrow, "'chan'") } - arrow = typ.Dir == ast.SEND - typ.Begin = pos - typ.Dir = ast.RECV + arrow, typ.Begin, typ.Arrow = typ.Arrow, arrow, arrow + dir, typ.Dir = typ.Dir, ast.RECV 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 { - p.errorExpected(pos, "'chan'") + if dir == ast.SEND { + p.errorExpected(arrow, "channel type") } return x } // <-(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: // pointer type or unary "*" expression diff --git a/src/pkg/go/parser/short_test.go b/src/pkg/go/parser/short_test.go index d5856e4f95..daba853088 100644 --- a/src/pkg/go/parser/short_test.go +++ b/src/pkg/go/parser/short_test.go @@ -69,7 +69,7 @@ var invalids = []string{ `package p; var a = <- /* ERROR "expected expression" */ chan 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() { _ = (<-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) { diff --git a/src/pkg/go/printer/nodes.go b/src/pkg/go/printer/nodes.go index 04f2adbd87..01a7473b83 100644 --- a/src/pkg/go/printer/nodes.go +++ b/src/pkg/go/printer/nodes.go @@ -853,9 +853,9 @@ func (p *printer) expr1(expr ast.Expr, prec1, depth int) { case ast.SEND | ast.RECV: p.print(token.CHAN) 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: - p.print(token.CHAN, token.ARROW) + p.print(token.CHAN, x.Arrow, token.ARROW) } p.print(blank) p.expr(x.Value) -- 2.48.1