mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +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
3 changed files with 113 additions and 72 deletions
|
|
@ -145,7 +145,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
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_ {
|
||||||
|
|
@ -181,7 +181,7 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
|
||||||
|
|
||||||
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
|
||||||
|
|
@ -866,10 +866,10 @@ 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 implicitArrayDeref(typ Type) Type {
|
func arrayPtrDeref(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
|
||||||
|
|
|
||||||
|
|
@ -783,9 +783,9 @@ func (check *Checker) stmt(ctxt stmtContext, s ast.Stmt) {
|
||||||
// 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 && s.Value != nil {
|
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)
|
check.softErrorf(atPos(s.Value.Pos()), _InvalidIterVar, "range over %s permits only one iteration variable", &x)
|
||||||
// ok to continue
|
// 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
|
// 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
|
||||||
|
|
@ -908,45 +908,17 @@ 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:
|
||||||
var msg string
|
var msg string
|
||||||
if typ.dir == SendOnly {
|
if typ.dir == SendOnly {
|
||||||
// TODO(rfindley): this error message differs from types2. Reconcile this.
|
msg = "receive from send-only channel"
|
||||||
msg = "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, ""
|
||||||
}
|
}
|
||||||
|
|
|
||||||
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 */ {}
|
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…
Add table
Add a link
Reference in a new issue