Also correct scope position for such variables.
Adjusted some comments.
Fixes #51437.
Change-Id: Ic49a1459469c8b2c7bc24fe546795f7d56c67cb4
Reviewed-on: https://go-review.googlesource.com/c/go/+/389594
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Cuong Manh Le <cuong.manhle.vn@gmail.com>
Reviewed-by: Robert Findley <rfindley@google.com>
(cherry picked from commit
d3fe4e193e387f250ba53a80f669eac465b1641d)
Reviewed-on: https://go-review.googlesource.com/c/go/+/390018
Trust: Dmitri Shuralyov <dmitshur@golang.org>
Run-TryBot: Dmitri Shuralyov <dmitshur@golang.org>
TryBot-Result: Gopher Robot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
var a []int
- for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
+ for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
var i interface{}
switch y := i.(type) { /*y=undef*/
case *syntax.ForStmt:
inner |= breakOk | continueOk
- check.openScope(s, "for")
- defer check.closeScope()
if rclause, _ := s.Init.(*syntax.RangeClause); rclause != nil {
check.rangeStmt(inner, s, rclause)
break
}
+ check.openScope(s, "for")
+ defer check.closeScope()
+
check.simpleStmt(s.Init)
if s.Cond != nil {
var x operand
}
func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) {
- // scope already opened
-
// determine lhs, if any
sKey := rclause.Lhs // possibly nil
var sValue, sExtra syntax.Expr
}
}
+ // Open the for-statement block scope now, after the range clause.
+ // Iteration variables declared with := need to go in this scope (was issue #51437).
+ check.openScope(s, "range")
+ defer check.closeScope()
+
// check assignment to/declaration of iteration variables
// (irregular assignment, cannot easily map to existing assignment checks)
rhs := [2]Type{key, val} // key, val may be nil
if rclause.Def {
- // 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)
+ // short variable declaration
var vars []*Var
for i, lhs := range lhs {
if lhs == nil {
// declare variables
if len(vars) > 0 {
- scopePos := syntax.EndPos(rclause.X) // TODO(gri) should this just be s.Body.Pos (spec clarification)?
+ scopePos := s.Body.Pos()
for _, obj := range vars {
- // spec: "The scope of a constant or variable identifier declared inside
- // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
- // for short variable declarations) and ends at the end of the innermost
- // containing block."
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
}
} else {
--- /dev/null
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct{}
+
+func (T) m() []int { return nil }
+
+func f(x T) {
+ for _, x := range func() []int {
+ return x.m() // x declared in parameter list of f
+ }() {
+ _ = x // x declared by range clause
+ }
+}
var F = /*F=func:12*/ F /*F=var:17*/ ; _ = F
var a []int
- for i, x := range /*i=undef*/ /*x=var:16*/ a /*i=var:20*/ /*x=var:20*/ { _ = i; _ = x }
+ for i, x := range a /*i=undef*/ /*x=var:16*/ { _ = i; _ = x }
var i interface{}
switch y := i.(type) { /*y=undef*/
case *ast.RangeStmt:
inner |= breakOk | continueOk
- check.openScope(s, "for")
- defer check.closeScope()
// check expression to iterate over
var x operand
}
}
+ // Open the for-statement block scope now, after the range clause.
+ // Iteration variables declared with := need to go in this scope (was issue #51437).
+ check.openScope(s, "range")
+ defer check.closeScope()
+
// check assignment to/declaration of iteration variables
// (irregular assignment, cannot easily map to existing assignment checks)
rhs := [2]Type{key, val} // key, val may be nil
if s.Tok == token.DEFINE {
- // 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)
+ // short variable declaration
var vars []*Var
for i, lhs := range lhs {
if lhs == nil {
// declare variables
if len(vars) > 0 {
- scopePos := s.X.End()
+ scopePos := s.Body.Pos()
for _, obj := range vars {
- // spec: "The scope of a constant or variable identifier declared inside
- // a function begins at the end of the ConstSpec or VarSpec (ShortVarDecl
- // for short variable declarations) and ends at the end of the innermost
- // containing block."
check.declare(check.scope, nil /* recordDef already called */, obj, scopePos)
}
} else {
--- /dev/null
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct{}
+
+func (T) m() []int { return nil }
+
+func f(x T) {
+ for _, x := range func() []int {
+ return x.m() // x declared in parameter list of f
+ }() {
+ _ = x // x declared by range clause
+ }
+}
--- /dev/null
+// compile
+
+// Copyright 2022 The Go Authors. All rights reserved.
+// Use of this source code is governed by a BSD-style
+// license that can be found in the LICENSE file.
+
+package p
+
+type T struct{}
+
+func (T) m() []T { return nil }
+
+func f(x T) {
+ for _, x := range func() []T {
+ return x.m()
+ }() {
+ _ = x
+ }
+}