1
0
mirror of https://github.com/golang/go synced 2024-11-25 00:07:56 -07:00

go/types: fix assertion failure when range over 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]==

Updates #68334

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>
This commit is contained in:
Tim King 2024-07-09 14:01:56 -07:00
parent 8bc32ab6b1
commit 4e77872d16
4 changed files with 68 additions and 8 deletions

View File

@ -1092,3 +1092,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)
}
}

View File

@ -920,14 +920,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
@ -957,12 +958,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.

View File

@ -1102,3 +1102,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)
}
}

View File

@ -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
@ -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.