1
0
mirror of https://github.com/golang/go synced 2024-11-24 13:00:15 -07:00

cmd/compile/internal/types2: range clause to accept type sets with single underlying types

This generalizes range clauses. Removed some dead code and cleaned
up the surrounding bits.

Change-Id: Icd8384205afa3f52b7e7df9abed5de2bb556861d
Reviewed-on: https://go-review.googlesource.com/c/go/+/357778
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
This commit is contained in:
Robert Griesemer 2021-10-21 15:56:08 -07:00
parent 2d205ebb96
commit c526cf8c1e
2 changed files with 36 additions and 48 deletions

View File

@ -834,19 +834,28 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
// 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.
typ := optype(x.typ)
if _, ok := typ.(*Chan); ok && sValue != nil {
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
// ok to continue
}
var msg string
key, val, msg = rangeKeyVal(typ, isVarName(sKey), isVarName(sValue))
if key == nil || msg != "" {
if msg != "" {
msg = ": " + msg
// Ranging over a type parameter is permitted if it has a single underlying type.
var cause string
u := singleUnder(x.typ)
switch t := u.(type) {
case nil:
cause = "type set has no single underlying type"
case *Chan:
if sValue != nil {
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
// ok to continue
}
if t.dir == SendOnly {
cause = "receive from send-only channel"
}
}
key, val = rangeKeyVal(u)
if key == nil || cause != "" {
if cause == "" {
check.softErrorf(&x, "cannot range over %s", &x)
} else {
check.softErrorf(&x, "cannot range over %s (%s)", &x, cause)
}
check.softErrorf(&x, "cannot range over %s%s", &x, msg)
// ok to continue
}
}
@ -927,44 +936,23 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
check.stmt(inner, s.Body)
}
// isVarName reports whether x is a non-nil, non-blank (_) expression.
func isVarName(x syntax.Expr) bool {
if x == nil {
return false
}
ident, _ := unparen(x).(*syntax.Name)
return ident == nil || ident.Value != "_"
}
// rangeKeyVal returns the key and value type produced by a range clause
// over an expression of type typ, and possibly an error message. If the
// range clause is not permitted the returned key is nil or msg is not
// empty (in that case we still may have a non-nil key type which can be
// used to reduce the chance for follow-on errors).
// The wantKey, wantVal, and hasVal flags indicate which of the iteration
// variables are used or present; this matters if we range over a generic
// type where not all keys or values are of the same type.
func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
// over an expression of type typ. If the range clause is not permitted
// the results are nil.
func rangeKeyVal(typ Type) (key, val Type) {
switch typ := arrayPtrDeref(typ).(type) {
case *Basic:
if isString(typ) {
return Typ[Int], universeRune, "" // use 'rune' name
return Typ[Int], universeRune // use 'rune' name
}
case *Array:
return Typ[Int], typ.elem, ""
return Typ[Int], typ.elem
case *Slice:
return Typ[Int], typ.elem, ""
return Typ[Int], typ.elem
case *Map:
return typ.key, typ.elem, ""
return typ.key, typ.elem
case *Chan:
var msg string
if typ.dir == SendOnly {
msg = "receive from send-only channel"
}
return typ.elem, Typ[Invalid], msg
case *top:
// we have a type parameter with no structural type
return nil, nil, "no structural type"
return typ.elem, Typ[Invalid]
}
return nil, nil, ""
return
}

View File

@ -184,7 +184,7 @@ func _[
for _, _ = range b1 {}
var b2 B2
for range b2 /* ERROR cannot range over b2 .* no structural type */ {}
for range b2 {}
var c0 chan int
for range c0 {}
@ -197,7 +197,7 @@ func _[
for _, _ /* ERROR permits only one iteration variable */ = range c1 {}
var c2 C2
for range c2 /* ERROR cannot range over c2 .* no structural type */ {}
for range c2 /* ERROR cannot range over c2.*no single underlying type */ {}
var c3 C3
for range c3 /* ERROR receive from send-only channel */ {}
@ -213,7 +213,7 @@ func _[
for _, _ = range s1 {}
var s2 S2
for range s2 /* ERROR cannot range over s2 .* no structural type */ {}
for range s2 /* ERROR cannot range over s2.*no single underlying type */ {}
var a0 []int
for range a0 {}
@ -226,7 +226,7 @@ func _[
for _, _ = range a1 {}
var a2 A2
for range a2 /* ERROR cannot range over a2 .* no structural type */ {}
for range a2 /* ERROR cannot range over a2.*no single underlying type */ {}
var p0 *[10]int
for range p0 {}
@ -239,7 +239,7 @@ func _[
for _, _ = range p1 {}
var p2 P2
for range p2 /* ERROR cannot range over p2 .* no structural type */ {}
for range p2 /* ERROR cannot range over p2.*no single underlying type */ {}
var m0 map[string]int
for range m0 {}
@ -252,7 +252,7 @@ func _[
for _, _ = range m1 {}
var m2 M2
for range m2 /* ERROR cannot range over m2 .* no structural type */ {}
for range m2 /* ERROR cannot range over m2.*no single underlying type */ {}
}
// type inference checks