aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRuss Cox <rsc@golang.org>2011-10-27 12:22:06 -0700
committerRuss Cox <rsc@golang.org>2011-10-27 12:22:06 -0700
commitfd31d9fd7beaac218899c5bdb74004152b076d82 (patch)
tree4f5743e7cd95aad0813b6d64c4ace7acf68b473a
parentd066e02adc0f343b178a0d8191e719e1218ffe80 (diff)
downloadgo-fd31d9fd7beaac218899c5bdb74004152b076d82.tar.gz
go-fd31d9fd7beaac218899c5bdb74004152b076d82.zip
go/parser: test and fix := scoping bug
R=iant CC=golang-dev, gri https://golang.org/cl/5327048
-rw-r--r--src/pkg/go/parser/parser.go10
-rw-r--r--src/pkg/go/parser/parser_test.go44
2 files changed, 53 insertions, 1 deletions
diff --git a/src/pkg/go/parser/parser.go b/src/pkg/go/parser/parser.go
index c78c6b56ec..e2c9441372 100644
--- a/src/pkg/go/parser/parser.go
+++ b/src/pkg/go/parser/parser.go
@@ -434,7 +434,9 @@ func (p *parser) parseLhsList() []ast.Expr {
switch p.tok {
case token.DEFINE:
// lhs of a short variable declaration
- p.shortVarDecl(p.makeIdentList(list))
+ // but doesn't enter scope until later:
+ // caller must call p.shortVarDecl(p.makeIdentList(list))
+ // at appropriate time.
case token.COLON:
// lhs of a label declaration or a communication clause of a select
// statement (parseLhsList is not called when parsing the case clause
@@ -1398,6 +1400,9 @@ func (p *parser) parseSimpleStmt(mode int) (ast.Stmt, bool) {
} else {
y = p.parseRhsList()
}
+ if tok == token.DEFINE {
+ p.shortVarDecl(p.makeIdentList(x))
+ }
return &ast.AssignStmt{x, pos, tok, y}, isRange
}
@@ -1722,6 +1727,9 @@ func (p *parser) parseCommClause() *ast.CommClause {
}
p.next()
rhs = p.parseRhs()
+ if tok == token.DEFINE && lhs != nil {
+ p.shortVarDecl(p.makeIdentList(lhs))
+ }
} else {
// rhs must be single receive operation
if len(lhs) > 1 {
diff --git a/src/pkg/go/parser/parser_test.go b/src/pkg/go/parser/parser_test.go
index 9705dcff25..dee90fbcf4 100644
--- a/src/pkg/go/parser/parser_test.go
+++ b/src/pkg/go/parser/parser_test.go
@@ -5,6 +5,7 @@
package parser
import (
+ "go/ast"
"go/token"
"os"
"testing"
@@ -134,3 +135,46 @@ func TestParse4(t *testing.T) {
}
}
}
+
+func TestColonEqualsScope(t *testing.T) {
+ f, err := ParseFile(fset, "", `package p; func f() { x, y, z := x, y, z }`, 0)
+ if err != nil {
+ t.Errorf("parse: %s", err)
+ }
+
+ // RHS refers to undefined globals; LHS does not.
+ as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.AssignStmt)
+ for _, v := range as.Rhs {
+ id := v.(*ast.Ident)
+ if id.Obj != nil {
+ t.Errorf("rhs %s has Obj, should not", id.Name)
+ }
+ }
+ for _, v := range as.Lhs {
+ id := v.(*ast.Ident)
+ if id.Obj == nil {
+ t.Errorf("lhs %s does not have Obj, should", id.Name)
+ }
+ }
+}
+
+func TestVarScope(t *testing.T) {
+ f, err := ParseFile(fset, "", `package p; func f() { var x, y, z = x, y, z }`, 0)
+ if err != nil {
+ t.Errorf("parse: %s", err)
+ }
+
+ // RHS refers to undefined globals; LHS does not.
+ as := f.Decls[0].(*ast.FuncDecl).Body.List[0].(*ast.DeclStmt).Decl.(*ast.GenDecl).Specs[0].(*ast.ValueSpec)
+ for _, v := range as.Values {
+ id := v.(*ast.Ident)
+ if id.Obj != nil {
+ t.Errorf("rhs %s has Obj, should not", id.Name)
+ }
+ }
+ for _, id := range as.Names {
+ if id.Obj == nil {
+ t.Errorf("lhs %s does not have Obj, should", id.Name)
+ }
+ }
+}