]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: better error message for invalid range clause
authorRobert Griesemer <gri@golang.org>
Tue, 4 Jan 2022 23:13:33 +0000 (15:13 -0800)
committerRobert Griesemer <gri@golang.org>
Thu, 6 Jan 2022 16:22:21 +0000 (16:22 +0000)
Fixes #50372.

Change-Id: I8e4c0020dae42744cce016433e398e0b884bb044
Reviewed-on: https://go-review.googlesource.com/c/go/+/375475
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/stmt.go
src/cmd/compile/internal/types2/testdata/fixedbugs/issue50372.go [new file with mode: 0644]
test/fixedbugs/issue50372.go [new file with mode: 0644]

index ab64882c0273a2c197f4c38fa46ab1810f8d244e..ae9cc69c99691530c3302b2f48d769416079b2e4 100644 (file)
@@ -810,32 +810,34 @@ func (check *Checker) typeSwitchStmt(inner stmtContext, s *syntax.SwitchStmt, gu
 func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *syntax.RangeClause) {
        // scope already opened
 
-       // check expression to iterate over
-       var x operand
-       check.expr(&x, rclause.X)
-
        // determine lhs, if any
        sKey := rclause.Lhs // possibly nil
-       var sValue syntax.Expr
+       var sValue, sExtra syntax.Expr
        if p, _ := sKey.(*syntax.ListExpr); p != nil {
-               if len(p.ElemList) != 2 {
+               if len(p.ElemList) < 2 {
                        check.error(s, invalidAST+"invalid lhs in range clause")
                        return
                }
+               // len(p.ElemList) >= 2
                sKey = p.ElemList[0]
                sValue = p.ElemList[1]
+               if len(p.ElemList) > 2 {
+                       // delay error reporting until we know more
+                       sExtra = p.ElemList[2]
+               }
        }
 
+       // check expression to iterate over
+       var x operand
+       check.expr(&x, rclause.X)
+
        // determine key/value types
        var key, val Type
        if x.mode != invalid {
                // Ranging over a type parameter is permitted if it has a structural type.
                var cause string
                u := structuralType(x.typ)
-               switch t := u.(type) {
-               case nil:
-                       cause = check.sprintf("%s has no structural type", x.typ)
-               case *Chan:
+               if t, _ := u.(*Chan); t != nil {
                        if sValue != nil {
                                check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
                                // ok to continue
@@ -843,6 +845,14 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
                        if t.dir == SendOnly {
                                cause = "receive from send-only channel"
                        }
+               } else {
+                       if sExtra != nil {
+                               check.softErrorf(sExtra, "range clause permits at most two iteration variables")
+                               // ok to continue
+                       }
+                       if u == nil {
+                               cause = check.sprintf("%s has no structural type", x.typ)
+                       }
                }
                key, val = rangeKeyVal(u)
                if key == nil || cause != "" {
diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50372.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50372.go
new file mode 100644 (file)
index 0000000..0f15dc0
--- /dev/null
@@ -0,0 +1,27 @@
+// Copyright 2021 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
+
+func _(s []int) {
+        var i, j, k, l int
+        _, _, _, _ = i, j, k, l
+
+        for range s {}
+        for i = range s {}
+        for i, j = range s {}
+        for i, j, k /* ERROR range clause permits at most two iteration variables */ = range s {}
+        for i, j, k /* ERROR range clause permits at most two iteration variables */, l = range s {}
+}
+
+func _(s chan int) {
+        var i, j, k, l int
+        _, _, _, _ = i, j, k, l
+
+        for range s {}
+        for i = range s {}
+        for i, j /* ERROR range over .* permits only one iteration variable */ = range s {}
+        for i, j /* ERROR range over .* permits only one iteration variable */, k = range s {}
+        for i, j /* ERROR range over .* permits only one iteration variable */, k, l = range s {}
+}
diff --git a/test/fixedbugs/issue50372.go b/test/fixedbugs/issue50372.go
new file mode 100644 (file)
index 0000000..30a171d
--- /dev/null
@@ -0,0 +1,29 @@
+// errorcheck -G=3
+
+// 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
+
+func _(s []int) {
+        var i, j, k, l int
+        _, _, _, _ = i, j, k, l
+
+        for range s {}
+        for i = range s {}
+        for i, j = range s {}
+        for i, j, k = range s {} // ERROR "range clause permits at most two iteration variables"
+        for i, j, k, l = range s {} // ERROR "range clause permits at most two iteration variables"
+}
+
+func _(s chan int) {
+        var i, j, k, l int
+        _, _, _, _ = i, j, k, l
+
+        for range s {}
+        for i = range s {}
+        for i, j = range s {} // ERROR "range over .* permits only one iteration variable"
+        for i, j, k = range s {} // ERROR "range over .* permits only one iteration variable"
+        for i, j, k, l = range s {} // ERROR "range over .* permits only one iteration variable"
+}