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:
Robert Findley 2021-08-15 21:11:18 -04:00
parent 02f932e173
commit 7b7d7d7818
3 changed files with 113 additions and 72 deletions

View File

@ -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

View File

@ -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, ""
}

View File

@ -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