Skip to content

Commit

Permalink
[release-branch.go1.22] go/types: fix assertion failure when range ov…
Browse files Browse the repository at this point in the history
…er int is not permitted

Fixes an assertion failure in Checker.rangeStmt that range over int
only has a key type and no value type. When allowVersion failed,
rangeKeyVal returns Typ[Invalid] for the value instead of nil. When
Config.Error != nil, rangeStmt proceeded. The check for rhs[1]==nil
was not enough to catch this case. It must also check rhs[1]==

Fixes #68334
Fixes #68370

Change-Id: Iffa1b2f7b6a94570ec50b8c6603e727a45ba3357
Reviewed-on: https://go-review.googlesource.com/c/go/+/597356
Reviewed-by: Robert Findley <rfindley@google.com>
LUCI-TryBot-Result: Go LUCI <golang-scoped@luci-project-accounts.iam.gserviceaccount.com>
(cherry picked from commit 4e77872)
Reviewed-on: https://go-review.googlesource.com/c/go/+/598055
  • Loading branch information
timothy-king authored and cherrymui committed Jul 16, 2024
1 parent 4e548f2 commit 4b27560
Show file tree
Hide file tree
Showing 4 changed files with 68 additions and 8 deletions.
29 changes: 29 additions & 0 deletions src/cmd/compile/internal/types2/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1093,3 +1093,32 @@ func _() {
conf := Config{GoVersion: "go1.17"}
mustTypecheck(src, &conf, nil)
}

func TestIssue68334(t *testing.T) {
const src = `
package p
func f(x int) {
for i, j := range x {
_, _ = i, j
}
var a, b int
for a, b = range x {
_, _ = a, b
}
}
`

got := ""
conf := Config{
GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
}
typecheck(src, &conf, nil) // do not crash

want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
"p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
if got != want {
t.Errorf("got: %s want: %s", got, want)
}
}
9 changes: 5 additions & 4 deletions src/cmd/compile/internal/types2/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -931,14 +931,15 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s

// initialize lhs iteration variable, if any
typ := rhs[i]
if typ == nil {
if typ == nil || typ == Typ[Invalid] {
// typ == Typ[Invalid] can happen if allowVersion fails.
obj.typ = Typ[Invalid]
obj.used = true // don't complain about unused variable
continue
}

if rangeOverInt {
assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.initVar(obj, &x, "range clause")
} else {
var y operand
Expand Down Expand Up @@ -968,12 +969,12 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s

// assign to lhs iteration variable, if any
typ := rhs[i]
if typ == nil {
if typ == nil || typ == Typ[Invalid] {
continue
}

if rangeOverInt {
assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.assignVar(lhs, nil, &x, "range clause")
// If the assignment succeeded, if x was untyped before, it now
// has a type inferred via the assignment. It must be an integer.
Expand Down
29 changes: 29 additions & 0 deletions src/go/types/issues_test.go
Original file line number Diff line number Diff line change
Expand Up @@ -1103,3 +1103,32 @@ func _() {
conf := Config{GoVersion: "go1.17"}
mustTypecheck(src, &conf, nil)
}

func TestIssue68334(t *testing.T) {
const src = `
package p
func f(x int) {
for i, j := range x {
_, _ = i, j
}
var a, b int
for a, b = range x {
_, _ = a, b
}
}
`

got := ""
conf := Config{
GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
}
typecheck(src, &conf, nil) // do not crash

want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
"p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
if got != want {
t.Errorf("got: %s want: %s", got, want)
}
}
9 changes: 5 additions & 4 deletions src/go/types/stmt.go
Original file line number Diff line number Diff line change
Expand Up @@ -922,14 +922,15 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {

// initialize lhs iteration variable, if any
typ := rhs[i]
if typ == nil {
if typ == nil || typ == Typ[Invalid] {
// typ == Typ[Invalid] can happen if allowVersion fails.
obj.typ = Typ[Invalid]
obj.used = true // don't complain about unused variable
continue
}

if rangeOverInt {
assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.initVar(obj, &x, "range clause")
} else {
var y operand
Expand Down Expand Up @@ -959,12 +960,12 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {

// assign to lhs iteration variable, if any
typ := rhs[i]
if typ == nil {
if typ == nil || typ == Typ[Invalid] {
continue
}

if rangeOverInt {
assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
check.assignVar(lhs, nil, &x, "range clause")
// If the assignment succeeded, if x was untyped before, it now
// has a type inferred via the assignment. It must be an integer.
Expand Down

0 comments on commit 4b27560

Please sign in to comment.