mirror of
https://github.com/golang/go
synced 2024-11-24 07:10:18 -07:00
go/types: fix indexing of generic types
This is a clean port of CL 360603 to go/types. Change-Id: Iadb312f07e509ff83339d5525765b7b7987bf233 Reviewed-on: https://go-review.googlesource.com/c/go/+/360936 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
d6f7203a3c
commit
2b81b863a2
@ -101,77 +101,80 @@ func (check *Checker) indexExpr(x *operand, e *typeparams.IndexExpr) (isFuncInst
|
||||
|
||||
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
|
||||
case *Pointer:
|
||||
a, _ := under(t.base).(*Array)
|
||||
if a == nil {
|
||||
return false
|
||||
l = t.len
|
||||
e = t.elem
|
||||
if x.mode != variable {
|
||||
mode = value
|
||||
}
|
||||
case *Pointer:
|
||||
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
|
||||
}
|
||||
}
|
||||
|
||||
|
8
src/go/types/testdata/check/typeparams.go2
vendored
8
src/go/types/testdata/check/typeparams.go2
vendored
@ -114,6 +114,14 @@ func _[T interface{ [10]int }](x T, i int) { _ = x[i]; _ = x[9]; _ = x[10 /* ERR
|
||||
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] }
|
||||
|
Loading…
Reference in New Issue
Block a user