0
1
mirror of https://github.com/golang/go synced 2025-05-27 15:10:40 +00:00

cmd/compile/internal/types2: better error message for invalid range clause

Fixes .

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>
This commit is contained in:
Robert Griesemer
2022-01-04 15:13:33 -08:00
parent da7891f6f3
commit f009910625
3 changed files with 76 additions and 10 deletions
src/cmd/compile/internal/types2
stmt.go
testdata
fixedbugs
test/fixedbugs

@ -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 != "" {

@ -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 {}
}

@ -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"
}