case *TypeParam:
// TODO(gri) report detailed failure cause for better error messages
- var tkey, telem Type // tkey != nil if we have maps
+ var key, elem Type // key != nil: we must have all maps
+ mode := variable // non-maps result mode
+ // TODO(gri) factor out closure and use it for non-typeparam cases as well
if typ.underIs(func(u Type) bool {
- var key, elem Type
- alen := int64(-1) // valid if >= 0
+ l := int64(-1) // valid if >= 0
+ var k, e Type // k is only set for maps
switch t := u.(type) {
case *Basic:
- if !isString(t) {
- return false
+ if isString(t) {
+ e = universeByte
+ mode = value
}
- elem = universeByte
case *Array:
- elem = t.elem
- alen = t.len
+ l = t.len
+ e = t.elem
+ if x.mode != variable {
+ mode = value
+ }
case *Pointer:
- a, _ := under(t.base).(*Array)
- if a == nil {
- return false
+ if t := asArray(t.base); t != nil {
+ l = t.len
+ e = t.elem
}
- elem = a.elem
- alen = a.len
case *Slice:
- elem = t.elem
+ e = t.elem
case *Map:
- key = t.key
- elem = t.elem
- default:
+ k = t.key
+ e = t.elem
+ }
+ if e == nil {
return false
}
- assert(elem != nil)
- if telem == nil {
+ if elem == nil {
// first type
- tkey, telem = key, elem
- length = alen
- } else {
- // all map keys must be identical (incl. all nil)
- if !Identical(key, tkey) {
- return false
- }
- // all element types must be identical
- if !Identical(elem, telem) {
- return false
- }
- tkey, telem = key, elem
- // track the minimal length for arrays
- if alen >= 0 && alen < length {
- length = alen
- }
+ length = l
+ key, elem = k, e
+ return true
+ }
+ // all map keys must be identical (incl. all nil)
+ // (that is, we cannot mix maps with other types)
+ if !Identical(key, k) {
+ return false
+ }
+ // all element types must be identical
+ if !Identical(elem, e) {
+ return false
+ }
+ // track the minimal length for arrays, if any
+ if l >= 0 && l < length {
+ length = l
}
return true
}) {
// For maps, the index expression must be assignable to the map key type.
- if tkey != nil {
+ if key != nil {
index := check.singleIndex(e)
if index == nil {
x.mode = invalid
return false
}
- var key operand
- check.expr(&key, index)
- check.assignment(&key, tkey, "map index")
+ var k operand
+ check.expr(&k, index)
+ check.assignment(&k, key, "map index")
// ok to continue even if indexing failed - map element type is known
x.mode = mapindex
- x.typ = telem
+ x.typ = elem
x.expr = e
return false
}
// no maps
valid = true
- x.mode = variable
- x.typ = telem
+ x.mode = mode
+ x.typ = elem
}
}
func _[T interface{ [10]byte | string }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
func _[T interface{ [10]int | *[20]int | []int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERROR out of bounds */ ] }
+// indexing with strings and non-variable arrays (assignment not permitted)
+func _[T string](x T) { _ = x[0]; x /* ERROR cannot assign */ [0] = 0 }
+func _[T []byte | string](x T) { x /* ERROR cannot assign */ [0] = 0 }
+func _[T [10]byte]() { f := func() (x T) { return }; f /* ERROR cannot assign */ ()[0] = 0 }
+func _[T [10]byte]() { f := func() (x *T) { return }; f /* ERROR cannot index */ ()[0] = 0 }
+func _[T [10]byte]() { f := func() (x *T) { return }; (*f())[0] = 0 }
+func _[T *[10]byte]() { f := func() (x T) { return }; f()[0] = 0 }
+
// slicing
func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j] }