aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/types2/stmt.go
diff options
context:
space:
mode:
authorRobert Griesemer <gri@golang.org>2021-08-04 16:52:25 -0700
committerRobert Griesemer <gri@golang.org>2021-08-06 20:34:45 +0000
commit93285c89d1146e2698d2b8e5bf45279961f5026e (patch)
tree27f5b9e4273adac607c5a615778a57d78f884e68 /src/cmd/compile/internal/types2/stmt.go
parent5aac85ad5ebfa9c2ecb01a3292bcf3513d876d7a (diff)
downloadgo-93285c89d1146e2698d2b8e5bf45279961f5026e.tar.gz
go-93285c89d1146e2698d2b8e5bf45279961f5026e.zip
[dev.typeparams] cmd/compile/internal/types2: fix range over exprs of type parameter type
For range expressions of type parameter type, the structural type of the type parameter's constraint determines the range operation. While at it, rename implicitArrayDeref to arrayPtrDeref. Change-Id: Ib631a8a14e717498e5264944f659309df1f68cc2 Reviewed-on: https://go-review.googlesource.com/c/go/+/339897 Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Robert Griesemer <gri@golang.org> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Findley <rfindley@google.com>
Diffstat (limited to 'src/cmd/compile/internal/types2/stmt.go')
-rw-r--r--src/cmd/compile/internal/types2/stmt.go37
1 files changed, 5 insertions, 32 deletions
diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go
index ad8efa91f8..7865c2d4f4 100644
--- a/src/cmd/compile/internal/types2/stmt.go
+++ b/src/cmd/compile/internal/types2/stmt.go
@@ -789,9 +789,9 @@ 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 {
- // TODO(gri) this also needs to happen for channels in generic variables
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
// ok to continue
}
@@ -900,7 +900,7 @@ func isVarName(x syntax.Expr) bool {
// 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) {
- switch typ := typ.(type) {
+ switch typ := arrayPtrDeref(typ).(type) {
case *Basic:
if isString(typ) {
return Typ[Int], universeRune, "" // use 'rune' name
@@ -909,10 +909,6 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
return Typ[Int], typ.elem, ""
case *Slice:
return Typ[Int], typ.elem, ""
- case *Pointer:
- if typ := asArray(typ.base); typ != nil {
- return Typ[Int], typ.elem, ""
- }
case *Map:
return typ.key, typ.elem, ""
case *Chan:
@@ -921,32 +917,9 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
msg = "receive from send-only channel"
}
return typ.elem, Typ[Invalid], msg
- case *TypeParam:
- first := true
- var key, val Type
- var msg string
- typ.underIs(func(t Type) bool {
- k, v, m := rangeKeyVal(t, wantKey, wantVal)
- if k == nil || m != "" {
- key, val, msg = k, v, m
- return false
- }
- if first {
- key, val, msg = k, v, m
- first = false
- return true
- }
- if wantKey && !Identical(key, k) {
- key, val, msg = nil, nil, "all possible values must have the same key type"
- return false
- }
- if wantVal && !Identical(val, v) {
- key, val, msg = nil, nil, "all possible values must have the same element type"
- return false
- }
- return true
- })
- return key, val, msg
+ case *top:
+ // we have a type parameter with no structural type
+ return nil, nil, "no structural type"
}
return nil, nil, ""
}