1
0
mirror of https://github.com/golang/go synced 2024-11-19 00:04:40 -07:00

go.tools/go/types: add missing checks for short variable declarations

Fixes golang/go#6766.

R=adonovan
CC=golang-dev
https://golang.org/cl/24330044
This commit is contained in:
Robert Griesemer 2013-11-15 14:26:29 -08:00
parent 01f122e48b
commit e785f050b6
3 changed files with 53 additions and 25 deletions

View File

@ -347,11 +347,12 @@ func (check *checker) assignVars(lhs, rhs []ast.Expr) {
check.errorf(rhs[0].Pos(), "assignment count mismatch (%d vs %d)", l, r)
}
func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
func (check *checker) shortVarDecl(pos token.Pos, lhs, rhs []ast.Expr) {
scope := check.topScope
// collect lhs variables
vars := make([]*Var, len(lhs))
var newVars []*Var
var lhsVars = make([]*Var, len(lhs))
for i, lhs := range lhs {
var obj *Var
if ident, _ := lhs.(*ast.Ident); ident != nil {
@ -368,6 +369,7 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
} else {
// declare new variable
obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil)
newVars = append(newVars, obj)
}
if obj != nil {
check.recordObject(ident, obj)
@ -378,18 +380,18 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
if obj == nil {
obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
}
vars[i] = obj
lhsVars[i] = obj
}
check.initVars(vars, rhs, token.NoPos)
check.initVars(lhsVars, rhs, token.NoPos)
// declare variables
n := scope.Len()
for _, obj := range vars {
scope.Insert(obj)
}
if n == scope.Len() {
check.errorf(lhs[0].Pos(), "no new variables on left side of :=")
// declare new variables
if len(newVars) > 0 {
for _, obj := range newVars {
check.declare(scope, nil, obj) // recordObject already called
}
} else {
check.errorf(pos, "no new variables on left side of :=")
}
}

View File

@ -235,7 +235,7 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
return
}
if s.Tok == token.DEFINE {
check.shortVarDecl(s.Lhs, s.Rhs)
check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
} else {
// regular assignment
check.assignVars(s.Lhs, s.Rhs)
@ -570,8 +570,9 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
rhs := [2]Type{key, val}
if decl {
// declaration; variable scope starts after the range clause
var idents []*ast.Ident
// short variable declaration; variable scope starts after the range clause
// (the for loop opens a new scope, so variables on the lhs never redeclare
// previously declared variables)
var vars []*Var
for i, lhs := range lhs {
if lhs == nil {
@ -579,17 +580,20 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
// determine lhs variable
name := "_" // dummy, in case lhs is not an identifier
ident, _ := lhs.(*ast.Ident)
if ident != nil {
name = ident.Name
var obj *Var
if ident, _ := lhs.(*ast.Ident); ident != nil {
// declare new variable
name := ident.Name
obj = NewVar(ident.Pos(), check.pkg, name, nil)
check.recordObject(ident, obj)
// _ variables don't count as new variables
if name != "_" {
vars = append(vars, obj)
}
} else {
check.errorf(lhs.Pos(), "cannot declare %s", lhs)
obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
}
idents = append(idents, ident)
obj := NewVar(lhs.Pos(), check.pkg, name, nil)
vars = append(vars, obj)
// initialize lhs variable
x.mode = value
@ -599,8 +603,12 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
}
// declare variables
for i, ident := range idents {
check.declare(check.topScope, ident, vars[i])
if len(vars) > 0 {
for _, obj := range vars {
check.declare(check.topScope, nil, obj) // recordObject already called
}
} else {
check.errorf(s.TokPos, "no new variables on left side of :=")
}
} else {
// ordinary assignment

View File

@ -137,7 +137,17 @@ func issue6487() {
_ = &m /* ERROR "cannot take address" */ ["foo"].x
}
func shortVarDecls() {
func issue6766a() {
a, a /* ERROR redeclared */ := 1, 2
_ = a
a, b, b /* ERROR redeclared */ := 1, 2, 3
_ = b
c, c /* ERROR redeclared */, b := 1, 2, 3
_ = c
a, b := /* ERROR no new variables */ 1, 2
}
func shortVarDecls1() {
const c = 0
type d int
a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */ := 1, "zwei", 3.0, 4
@ -684,6 +694,14 @@ func rangeloops2() {
for _, r /* ERROR cannot assign */ = range "foo" {}
}
func issue6766b() {
for _ := /* ERROR no new variables */ range "" {}
for a, a /* ERROR redeclared */ := range "" { _ = a }
var a int
_ = a
for a, a /* ERROR redeclared */ := range []int{1, 2, 3} { _ = a }
}
func labels0() {
goto L0
goto L1