mirror of
https://github.com/golang/go.git
synced 2024-09-21 10:28:27 +00:00
go/types: fix range over exprs of type parameter type
This is a port of CL 339897 to go/types. In addition, an error message that was adjusted in CL 274974 is ported to go/types (CL 274974 was only considered necessary for compiler compatibility). Change-Id: Idfe44d759c925f9fed353a2d1898d3d4d8d85452 Reviewed-on: https://go-review.googlesource.com/c/go/+/342433 Trust: Robert Findley <rfindley@google.com> Run-TryBot: Robert Findley <rfindley@google.com> TryBot-Result: Go Bot <gobot@golang.org> Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
parent
02f932e173
commit
7b7d7d7818
@ -145,7 +145,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
mode := invalid
|
||||
var typ Type
|
||||
var val constant.Value
|
||||
switch typ = implicitArrayDeref(under(x.typ)); t := typ.(type) {
|
||||
switch typ = arrayPtrDeref(under(x.typ)); t := typ.(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
if x.mode == constant_ {
|
||||
@ -181,7 +181,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||
|
||||
case *TypeParam:
|
||||
if t.underIs(func(t Type) bool {
|
||||
switch t := implicitArrayDeref(t).(type) {
|
||||
switch t := arrayPtrDeref(t).(type) {
|
||||
case *Basic:
|
||||
if isString(t) && id == _Len {
|
||||
return true
|
||||
@ -866,10 +866,10 @@ func makeSig(res Type, args ...Type) *Signature {
|
||||
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.
|
||||
//
|
||||
func implicitArrayDeref(typ Type) Type {
|
||||
func arrayPtrDeref(typ Type) Type {
|
||||
if p, ok := typ.(*Pointer); ok {
|
||||
if a := asArray(p.base); a != nil {
|
||||
return a
|
||||
|
@ -783,9 +783,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||
// 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 && s.Value != nil {
|
||||
// TODO(gri) this also needs to happen for channels in generic variables
|
||||
check.softErrorf(atPos(s.Value.Pos()), _InvalidIterVar, "range over %s permits only one iteration variable", &x)
|
||||
// ok to continue
|
||||
}
|
||||
@ -899,7 +899,7 @@ func isVarName(x ast.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
|
||||
@ -908,45 +908,17 @@ 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:
|
||||
var msg string
|
||||
if typ.dir == SendOnly {
|
||||
// TODO(rfindley): this error message differs from types2. Reconcile this.
|
||||
msg = "send-only channel"
|
||||
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, ""
|
||||
}
|
||||
|
137
src/go/types/testdata/check/typeparams.go2
vendored
137
src/go/types/testdata/check/typeparams.go2
vendored
@ -149,40 +149,109 @@ func _[T interface{}](x T) {
|
||||
for range x /* ERROR cannot range */ {}
|
||||
}
|
||||
|
||||
// Disabled for now until we have clarified semantics of range.
|
||||
// TODO(gri) fix this
|
||||
//
|
||||
// func _[T interface{ ~string | ~[]string }](x T) {
|
||||
// for range x {}
|
||||
// for i := range x { _ = i }
|
||||
// for i, _ := range x { _ = i }
|
||||
// for i, e := range x /* ERROR must have the same element type */ { _ = i }
|
||||
// for _, e := range x /* ERROR must have the same element type */ {}
|
||||
// var e rune
|
||||
// _ = e
|
||||
// for _, (e) = range x /* ERROR must have the same element type */ {}
|
||||
// }
|
||||
//
|
||||
//
|
||||
// func _[T interface{ ~string | ~[]rune | ~map[int]rune }](x T) {
|
||||
// for _, e := range x { _ = e }
|
||||
// for i, e := range x { _ = i; _ = e }
|
||||
// }
|
||||
//
|
||||
// func _[T interface{ ~string | ~[]rune | ~map[string]rune }](x T) {
|
||||
// for _, e := range x { _ = e }
|
||||
// for i, e := range x /* ERROR must have the same key type */ { _ = e }
|
||||
// }
|
||||
//
|
||||
// func _[T interface{ ~string | ~chan int }](x T) {
|
||||
// for range x {}
|
||||
// for i := range x { _ = i }
|
||||
// for i, _ := range x { _ = i } // TODO(gri) should get an error here: channels only return one value
|
||||
// }
|
||||
//
|
||||
// func _[T interface{ ~string | ~chan<-int }](x T) {
|
||||
// for i := range x /* ERROR send-only channel */ { _ = i }
|
||||
// }
|
||||
type myString string
|
||||
|
||||
func _[
|
||||
B1 interface{ string },
|
||||
B2 interface{ string | myString },
|
||||
|
||||
C1 interface{ chan int },
|
||||
C2 interface{ chan int | <-chan int },
|
||||
C3 interface{ chan<- int },
|
||||
|
||||
S1 interface{ []int },
|
||||
S2 interface{ []int | [10]int },
|
||||
|
||||
A1 interface{ [10]int },
|
||||
A2 interface{ [10]int | []int },
|
||||
|
||||
P1 interface{ *[10]int },
|
||||
P2 interface{ *[10]int | *[]int },
|
||||
|
||||
M1 interface{ map[string]int },
|
||||
M2 interface{ map[string]int | map[string]string },
|
||||
]() {
|
||||
var b0 string
|
||||
for range b0 {}
|
||||
for _ = range b0 {}
|
||||
for _, _ = range b0 {}
|
||||
|
||||
var b1 B1
|
||||
for range b1 {}
|
||||
for _ = range b1 {}
|
||||
for _, _ = range b1 {}
|
||||
|
||||
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
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user