]> Cypherpunks repositories - gostls13.git/commitdiff
[release-branch.go1.22] go/types: fix assertion failure when range over int is not...
authorTim King <taking@google.com>
Tue, 9 Jul 2024 21:01:56 +0000 (14:01 -0700)
committerCherry Mui <cherryyz@google.com>
Tue, 16 Jul 2024 18:53:36 +0000 (18:53 +0000)
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 4e77872d16340595d76b905fe24369b76cfd1b5f)
Reviewed-on: https://go-review.googlesource.com/c/go/+/598055

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

index 0117571f7b043c3f027626d663079743be92f82f..6b7eecac073e60d9636b1bec3bbf8a1374bb8818 100644 (file)
@@ -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)
+       }
+}
index d519657b6b153ebe9111478fd6323a5b90e7f9a5..0978c9d2291b4a883bd16c074dae56bf1b1ca796 100644 (file)
@@ -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
@@ -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.
index 6f9d5978e7ff22ee5d47ed87abbef7b0d6f6e53f..38820998a35b3ec4195bd0d43d89b6155902e1df 100644 (file)
@@ -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)
+       }
+}
index bb203f130c192a43ac8e4184d0e444a7cbed0b9d..f6e75a041a352d794eae3317c0cdbda8c85179a0 100644 (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.