diff --git a/src/cmd/compile/internal/types2/builtins.go b/src/cmd/compile/internal/types2/builtins.go index c022e79c97..e9df605fd1 100644 --- a/src/cmd/compile/internal/types2/builtins.go +++ b/src/cmd/compile/internal/types2/builtins.go @@ -144,7 +144,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( 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_ { @@ -180,7 +180,7 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) ( 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 @@ -862,10 +862,9 @@ 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 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, "" } diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 index 7392b88555..ba8e837346 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 @@ -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