Skip to content

Commit 4e77872

Browse files
committed
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 <[email protected]> LUCI-TryBot-Result: Go LUCI <[email protected]>
1 parent 8bc32ab commit 4e77872

File tree

4 files changed

+68
-8
lines changed

4 files changed

+68
-8
lines changed

src/cmd/compile/internal/types2/issues_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -1092,3 +1092,32 @@ func _() {
10921092
conf := Config{GoVersion: "go1.17"}
10931093
mustTypecheck(src, &conf, nil)
10941094
}
1095+
1096+
func TestIssue68334(t *testing.T) {
1097+
const src = `
1098+
package p
1099+
1100+
func f(x int) {
1101+
for i, j := range x {
1102+
_, _ = i, j
1103+
}
1104+
var a, b int
1105+
for a, b = range x {
1106+
_, _ = a, b
1107+
}
1108+
}
1109+
`
1110+
1111+
got := ""
1112+
conf := Config{
1113+
GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
1114+
Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
1115+
}
1116+
typecheck(src, &conf, nil) // do not crash
1117+
1118+
want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
1119+
"p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
1120+
if got != want {
1121+
t.Errorf("got: %s want: %s", got, want)
1122+
}
1123+
}

src/cmd/compile/internal/types2/stmt.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -920,14 +920,15 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
920920

921921
// initialize lhs iteration variable, if any
922922
typ := rhs[i]
923-
if typ == nil {
923+
if typ == nil || typ == Typ[Invalid] {
924+
// typ == Typ[Invalid] can happen if allowVersion fails.
924925
obj.typ = Typ[Invalid]
925926
obj.used = true // don't complain about unused variable
926927
continue
927928
}
928929

929930
if rangeOverInt {
930-
assert(i == 0) // at most one iteration variable (rhs[1] == nil for rangeOverInt)
931+
assert(i == 0) // at most one iteration variable (rhs[1] == nil or Typ[Invalid] for rangeOverInt)
931932
check.initVar(obj, &x, "range clause")
932933
} else {
933934
var y operand
@@ -957,12 +958,12 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
957958

958959
// assign to lhs iteration variable, if any
959960
typ := rhs[i]
960-
if typ == nil {
961+
if typ == nil || typ == Typ[Invalid] {
961962
continue
962963
}
963964

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

src/go/types/issues_test.go

+29
Original file line numberDiff line numberDiff line change
@@ -1102,3 +1102,32 @@ func _() {
11021102
conf := Config{GoVersion: "go1.17"}
11031103
mustTypecheck(src, &conf, nil)
11041104
}
1105+
1106+
func TestIssue68334(t *testing.T) {
1107+
const src = `
1108+
package p
1109+
1110+
func f(x int) {
1111+
for i, j := range x {
1112+
_, _ = i, j
1113+
}
1114+
var a, b int
1115+
for a, b = range x {
1116+
_, _ = a, b
1117+
}
1118+
}
1119+
`
1120+
1121+
got := ""
1122+
conf := Config{
1123+
GoVersion: "go1.21", // #68334 requires GoVersion <= 1.21
1124+
Error: func(err error) { got += err.Error() + "\n" }, // #68334 requires Error != nil
1125+
}
1126+
typecheck(src, &conf, nil) // do not crash
1127+
1128+
want := "p:5:20: cannot range over x (variable of type int): requires go1.22 or later\n" +
1129+
"p:9:19: cannot range over x (variable of type int): requires go1.22 or later\n"
1130+
if got != want {
1131+
t.Errorf("got: %s want: %s", got, want)
1132+
}
1133+
}

src/go/types/stmt.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -922,14 +922,15 @@ func (check *Checker) rangeStmt(inner stmtContext, s *ast.RangeStmt) {
922922

923923
// initialize lhs iteration variable, if any
924924
typ := rhs[i]
925-
if typ == nil {
925+
if typ == nil || typ == Typ[Invalid] {
926+
// typ == Typ[Invalid] can happen if allowVersion fails.
926927
obj.typ = Typ[Invalid]
927928
obj.used = true // don't complain about unused variable
928929
continue
929930
}
930931

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

960961
// assign to lhs iteration variable, if any
961962
typ := rhs[i]
962-
if typ == nil {
963+
if typ == nil || typ == Typ[Invalid] {
963964
continue
964965
}
965966

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

0 commit comments

Comments
 (0)