aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2022-01-04 15:13:33 -0800
committerRobert Griesemer <gri@golang.org>2022-01-06 16:22:21 +0000
commitf0099106254e288db62de3e3b030915af7decc25 (patch)
tree2df3109c4170adfbd6c2af1638d52229b58be629 /src/cmd/compile
parentda7891f6f36c48f2931ed916ed305330c06f9bd7 (diff)
downloadgo-f0099106254e288db62de3e3b030915af7decc25.tar.gz
go-f0099106254e288db62de3e3b030915af7decc25.zip
cmd/compile/internal/types2: better error message for invalid range clause
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>
Diffstat (limited to 'src/cmd/compile')
-rw-r--r--src/cmd/compile/internal/types2/stmt.go30
-rw-r--r--src/cmd/compile/internal/types2/testdata/fixedbugs/issue50372.go27
2 files changed, 47 insertions, 10 deletions
diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go
index ab64882c02..ae9cc69c99 100644
--- a/src/cmd/compile/internal/types2/stmt.go
+++ b/src/cmd/compile/internal/types2/stmt.go
@@ -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
index 0000000000..0f15dc0b62
--- /dev/null
+++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50372.go
@@ -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 {}
+}