diff options
author | Robert Griesemer <gri@golang.org> | 2022-01-04 15:13:33 -0800 |
---|---|---|
committer | Robert Griesemer <gri@golang.org> | 2022-01-06 16:22:21 +0000 |
commit | f0099106254e288db62de3e3b030915af7decc25 (patch) | |
tree | 2df3109c4170adfbd6c2af1638d52229b58be629 /src/cmd/compile | |
parent | da7891f6f36c48f2931ed916ed305330c06f9bd7 (diff) | |
download | go-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.go | 30 | ||||
-rw-r--r-- | src/cmd/compile/internal/types2/testdata/fixedbugs/issue50372.go | 27 |
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 {} +} |