mirror of
https://github.com/golang/go
synced 2024-09-05 07:54:46 +00:00
[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>
This commit is contained in:
parent
5aac85ad5e
commit
93285c89d1
|
@ -144,7 +144,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
mode := invalid
|
mode := invalid
|
||||||
var typ Type
|
var typ Type
|
||||||
var val constant.Value
|
var val constant.Value
|
||||||
switch typ = implicitArrayDeref(under(x.typ)); t := typ.(type) {
|
switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(t) && id == _Len {
|
if isString(t) && id == _Len {
|
||||||
if x.mode == constant_ {
|
if x.mode == constant_ {
|
||||||
|
@ -180,7 +180,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
|
||||||
|
|
||||||
case *TypeParam:
|
case *TypeParam:
|
||||||
if t.underIs(func(t Type) bool {
|
if t.underIs(func(t Type) bool {
|
||||||
switch t := implicitArrayDeref(t).(type) {
|
switch t := arrayPtrDeref(t).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(t) && id == _Len {
|
if isString(t) && id == _Len {
|
||||||
return true
|
return true
|
||||||
|
@ -862,10 +862,9 @@ func makeSig(res Type, args ...Type) *Signature {
|
||||||
return &Signature{params: params, results: result}
|
return &Signature{params: params, results: result}
|
||||||
}
|
}
|
||||||
|
|
||||||
// implicitArrayDeref returns A if typ is of the form *A and A is an array;
|
// arrayPtrDeref returns A if typ is of the form *A and A is an array;
|
||||||
// otherwise it returns typ.
|
// otherwise it returns typ.
|
||||||
//
|
func arrayPtrDeref(typ Type) Type {
|
||||||
func implicitArrayDeref(typ Type) Type {
|
|
||||||
if p, ok := typ.(*Pointer); ok {
|
if p, ok := typ.(*Pointer); ok {
|
||||||
if a := asArray(p.base); a != nil {
|
if a := asArray(p.base); a != nil {
|
||||||
return a
|
return a
|
||||||
|
|
|
@ -789,9 +789,9 @@ func (check *Checker) rangeStmt(inner stmtContext, s *syntax.ForStmt, rclause *s
|
||||||
// determine key/value types
|
// determine key/value types
|
||||||
var key, val Type
|
var key, val Type
|
||||||
if x.mode != invalid {
|
if x.mode != invalid {
|
||||||
|
// Ranging over a type parameter is permitted if it has a structural type.
|
||||||
typ := optype(x.typ)
|
typ := optype(x.typ)
|
||||||
if _, ok := typ.(*Chan); ok && sValue != nil {
|
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)
|
check.softErrorf(sValue, "range over %s permits only one iteration variable", &x)
|
||||||
// ok to continue
|
// 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
|
// 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.
|
// type where not all keys or values are of the same type.
|
||||||
func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
|
func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
|
||||||
switch typ := typ.(type) {
|
switch typ := arrayPtrDeref(typ).(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if isString(typ) {
|
if isString(typ) {
|
||||||
return Typ[Int], universeRune, "" // use 'rune' name
|
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, ""
|
return Typ[Int], typ.elem, ""
|
||||||
case *Slice:
|
case *Slice:
|
||||||
return Typ[Int], typ.elem, ""
|
return Typ[Int], typ.elem, ""
|
||||||
case *Pointer:
|
|
||||||
if typ := asArray(typ.base); typ != nil {
|
|
||||||
return Typ[Int], typ.elem, ""
|
|
||||||
}
|
|
||||||
case *Map:
|
case *Map:
|
||||||
return typ.key, typ.elem, ""
|
return typ.key, typ.elem, ""
|
||||||
case *Chan:
|
case *Chan:
|
||||||
|
@ -921,32 +917,9 @@ func rangeKeyVal(typ Type, wantKey, wantVal bool) (Type, Type, string) {
|
||||||
msg = "receive from send-only channel"
|
msg = "receive from send-only channel"
|
||||||
}
|
}
|
||||||
return typ.elem, Typ[Invalid], msg
|
return typ.elem, Typ[Invalid], msg
|
||||||
case *TypeParam:
|
case *top:
|
||||||
first := true
|
// we have a type parameter with no structural type
|
||||||
var key, val Type
|
return nil, nil, "no structural 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
|
|
||||||
}
|
}
|
||||||
return nil, nil, ""
|
return nil, nil, ""
|
||||||
}
|
}
|
||||||
|
|
|
@ -149,40 +149,109 @@ func _[T interface{}](x T) {
|
||||||
for range x /* ERROR cannot range */ {}
|
for range x /* ERROR cannot range */ {}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Disabled for now until we have clarified semantics of range.
|
type myString string
|
||||||
// TODO(gri) fix this
|
|
||||||
//
|
func _[
|
||||||
// func _[T interface{ ~string | ~[]string }](x T) {
|
B1 interface{ string },
|
||||||
// for range x {}
|
B2 interface{ string | myString },
|
||||||
// for i := range x { _ = i }
|
|
||||||
// for i, _ := range x { _ = i }
|
C1 interface{ chan int },
|
||||||
// for i, e := range x /* ERROR must have the same element type */ { _ = i }
|
C2 interface{ chan int | <-chan int },
|
||||||
// for _, e := range x /* ERROR must have the same element type */ {}
|
C3 interface{ chan<- int },
|
||||||
// var e rune
|
|
||||||
// _ = e
|
S1 interface{ []int },
|
||||||
// for _, (e) = range x /* ERROR must have the same element type */ {}
|
S2 interface{ []int | [10]int },
|
||||||
// }
|
|
||||||
//
|
A1 interface{ [10]int },
|
||||||
//
|
A2 interface{ [10]int | []int },
|
||||||
// func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) {
|
|
||||||
// for _, e := range x { _ = e }
|
P1 interface{ *[10]int },
|
||||||
// for i, e := range x { _ = i; _ = e }
|
P2 interface{ *[10]int | *[]int },
|
||||||
// }
|
|
||||||
//
|
M1 interface{ map[string]int },
|
||||||
// func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) {
|
M2 interface{ map[string]int | map[string]string },
|
||||||
// for _, e := range x { _ = e }
|
]() {
|
||||||
// for i, e := range x /* ERROR must have the same key type */ { _ = e }
|
var b0 string
|
||||||
// }
|
for range b0 {}
|
||||||
//
|
for _ = range b0 {}
|
||||||
// func _[T interface{ ~string | ~chan int }](x T) {
|
for _, _ = range b0 {}
|
||||||
// for range x {}
|
|
||||||
// for i := range x { _ = i }
|
var b1 B1
|
||||||
// for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
|
for range b1 {}
|
||||||
// }
|
for _ = range b1 {}
|
||||||
//
|
for _, _ = range b1 {}
|
||||||
// func _[T interface{ ~string | ~chan<-int }](x T) {
|
|
||||||
// for i := range x /* ERROR send-only channel */ { _ = i }
|
var b2 B2
|
||||||
// }
|
for range b2 /* ERROR cannot range over b2 .* no structural type */ {}
|
||||||
|
|
||||||
|
var c0 chan int
|
||||||
|
for range c0 {}
|
||||||
|
for _ = range c0 {}
|
||||||
|
for _, _ /* ERROR permits only one iteration variable */ = range c0 {}
|
||||||
|
|
||||||
|
var c1 C1
|
||||||
|
for range c1 {}
|
||||||
|
for _ = range c1 {}
|
||||||
|
for _, _ /* ERROR permits only one iteration variable */ = range c1 {}
|
||||||
|
|
||||||
|
var c2 C2
|
||||||
|
for range c2 /* ERROR cannot range over c2 .* no structural type */ {}
|
||||||
|
|
||||||
|
var c3 C3
|
||||||
|
for range c3 /* ERROR receive from send-only channel */ {}
|
||||||
|
|
||||||
|
var s0 []int
|
||||||
|
for range s0 {}
|
||||||
|
for _ = range s0 {}
|
||||||
|
for _, _ = range s0 {}
|
||||||
|
|
||||||
|
var s1 S1
|
||||||
|
for range s1 {}
|
||||||
|
for _ = range s1 {}
|
||||||
|
for _, _ = range s1 {}
|
||||||
|
|
||||||
|
var s2 S2
|
||||||
|
for range s2 /* ERROR cannot range over s2 .* no structural type */ {}
|
||||||
|
|
||||||
|
var a0 []int
|
||||||
|
for range a0 {}
|
||||||
|
for _ = range a0 {}
|
||||||
|
for _, _ = range a0 {}
|
||||||
|
|
||||||
|
var a1 A1
|
||||||
|
for range a1 {}
|
||||||
|
for _ = range a1 {}
|
||||||
|
for _, _ = range a1 {}
|
||||||
|
|
||||||
|
var a2 A2
|
||||||
|
for range a2 /* ERROR cannot range over a2 .* no structural type */ {}
|
||||||
|
|
||||||
|
var p0 *[10]int
|
||||||
|
for range p0 {}
|
||||||
|
for _ = range p0 {}
|
||||||
|
for _, _ = range p0 {}
|
||||||
|
|
||||||
|
var p1 P1
|
||||||
|
for range p1 {}
|
||||||
|
for _ = range p1 {}
|
||||||
|
for _, _ = range p1 {}
|
||||||
|
|
||||||
|
var p2 P2
|
||||||
|
for range p2 /* ERROR cannot range over p2 .* no structural type */ {}
|
||||||
|
|
||||||
|
var m0 map[string]int
|
||||||
|
for range m0 {}
|
||||||
|
for _ = range m0 {}
|
||||||
|
for _, _ = range m0 {}
|
||||||
|
|
||||||
|
var m1 M1
|
||||||
|
for range m1 {}
|
||||||
|
for _ = range m1 {}
|
||||||
|
for _, _ = range m1 {}
|
||||||
|
|
||||||
|
var m2 M2
|
||||||
|
for range m2 /* ERROR cannot range over m2 .* no structural type */ {}
|
||||||
|
}
|
||||||
|
|
||||||
// type inference checks
|
// type inference checks
|
||||||
|
|
||||||
|
|
Loading…
Reference in a new issue