mirror of
https://github.com/golang/go
synced 2024-11-19 01:54:39 -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:
parent
01f122e48b
commit
e785f050b6
@ -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)
|
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
|
scope := check.topScope
|
||||||
|
|
||||||
// collect lhs variables
|
// collect lhs variables
|
||||||
vars := make([]*Var, len(lhs))
|
var newVars []*Var
|
||||||
|
var lhsVars = make([]*Var, len(lhs))
|
||||||
for i, lhs := range lhs {
|
for i, lhs := range lhs {
|
||||||
var obj *Var
|
var obj *Var
|
||||||
if ident, _ := lhs.(*ast.Ident); ident != nil {
|
if ident, _ := lhs.(*ast.Ident); ident != nil {
|
||||||
@ -368,6 +369,7 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
|
|||||||
} else {
|
} else {
|
||||||
// declare new variable
|
// declare new variable
|
||||||
obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil)
|
obj = NewVar(ident.Pos(), check.pkg, ident.Name, nil)
|
||||||
|
newVars = append(newVars, obj)
|
||||||
}
|
}
|
||||||
if obj != nil {
|
if obj != nil {
|
||||||
check.recordObject(ident, obj)
|
check.recordObject(ident, obj)
|
||||||
@ -378,18 +380,18 @@ func (check *checker) shortVarDecl(lhs, rhs []ast.Expr) {
|
|||||||
if obj == nil {
|
if obj == nil {
|
||||||
obj = NewVar(lhs.Pos(), check.pkg, "_", nil) // dummy variable
|
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
|
// declare new variables
|
||||||
n := scope.Len()
|
if len(newVars) > 0 {
|
||||||
for _, obj := range vars {
|
for _, obj := range newVars {
|
||||||
scope.Insert(obj)
|
check.declare(scope, nil, obj) // recordObject already called
|
||||||
}
|
}
|
||||||
if n == scope.Len() {
|
} else {
|
||||||
check.errorf(lhs[0].Pos(), "no new variables on left side of :=")
|
check.errorf(pos, "no new variables on left side of :=")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -235,7 +235,7 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
if s.Tok == token.DEFINE {
|
if s.Tok == token.DEFINE {
|
||||||
check.shortVarDecl(s.Lhs, s.Rhs)
|
check.shortVarDecl(s.TokPos, s.Lhs, s.Rhs)
|
||||||
} else {
|
} else {
|
||||||
// regular assignment
|
// regular assignment
|
||||||
check.assignVars(s.Lhs, s.Rhs)
|
check.assignVars(s.Lhs, s.Rhs)
|
||||||
@ -570,8 +570,9 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||||||
rhs := [2]Type{key, val}
|
rhs := [2]Type{key, val}
|
||||||
|
|
||||||
if decl {
|
if decl {
|
||||||
// declaration; variable scope starts after the range clause
|
// short variable declaration; variable scope starts after the range clause
|
||||||
var idents []*ast.Ident
|
// (the for loop opens a new scope, so variables on the lhs never redeclare
|
||||||
|
// previously declared variables)
|
||||||
var vars []*Var
|
var vars []*Var
|
||||||
for i, lhs := range lhs {
|
for i, lhs := range lhs {
|
||||||
if lhs == nil {
|
if lhs == nil {
|
||||||
@ -579,17 +580,20 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// determine lhs variable
|
// determine lhs variable
|
||||||
name := "_" // dummy, in case lhs is not an identifier
|
var obj *Var
|
||||||
ident, _ := lhs.(*ast.Ident)
|
if ident, _ := lhs.(*ast.Ident); ident != nil {
|
||||||
if ident != nil {
|
// declare new variable
|
||||||
name = ident.Name
|
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 {
|
} else {
|
||||||
check.errorf(lhs.Pos(), "cannot declare %s", lhs)
|
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
|
// initialize lhs variable
|
||||||
x.mode = value
|
x.mode = value
|
||||||
@ -599,8 +603,12 @@ func (check *checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// declare variables
|
// declare variables
|
||||||
for i, ident := range idents {
|
if len(vars) > 0 {
|
||||||
check.declare(check.topScope, ident, vars[i])
|
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 {
|
} else {
|
||||||
// ordinary assignment
|
// ordinary assignment
|
||||||
|
20
go/types/testdata/stmt0.src
vendored
20
go/types/testdata/stmt0.src
vendored
@ -137,7 +137,17 @@ func issue6487() {
|
|||||||
_ = &m /* ERROR "cannot take address" */ ["foo"].x
|
_ = &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
|
const c = 0
|
||||||
type d int
|
type d int
|
||||||
a, b, c /* ERROR "cannot assign" */ , d /* ERROR "cannot assign" */ := 1, "zwei", 3.0, 4
|
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" {}
|
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() {
|
func labels0() {
|
||||||
goto L0
|
goto L0
|
||||||
goto L1
|
goto L1
|
||||||
|
Loading…
Reference in New Issue
Block a user