mirror of
https://github.com/golang/go
synced 2024-11-24 11:50:15 -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:
|
case *TypeParam:
|
||||||
// TODO(gri) report detailed failure cause for better error messages
|
// 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 {
|
if typ.underIs(func(u Type) bool {
|
||||||
var key, elem Type
|
l := int64(-1) // valid if >= 0
|
||||||
alen := int64(-1) // valid if >= 0
|
var k, e Type // k is only set for maps
|
||||||
switch t := u.(type) {
|
switch t := u.(type) {
|
||||||
case *Basic:
|
case *Basic:
|
||||||
if !isString(t) {
|
if isString(t) {
|
||||||
return false
|
e = universeByte
|
||||||
|
mode = value
|
||||||
}
|
}
|
||||||
elem = universeByte
|
|
||||||
case *Array:
|
case *Array:
|
||||||
elem = t.elem
|
l = t.len
|
||||||
alen = t.len
|
e = t.elem
|
||||||
case *Pointer:
|
if x.mode != variable {
|
||||||
a, _ := under(t.base).(*Array)
|
mode = value
|
||||||
if a == nil {
|
}
|
||||||
return false
|
case *Pointer:
|
||||||
|
if t := asArray(t.base); t != nil {
|
||||||
|
l = t.len
|
||||||
|
e = t.elem
|
||||||
}
|
}
|
||||||
elem = a.elem
|
|
||||||
alen = a.len
|
|
||||||
case *Slice:
|
case *Slice:
|
||||||
elem = t.elem
|
e = t.elem
|
||||||
case *Map:
|
case *Map:
|
||||||
key = t.key
|
k = t.key
|
||||||
elem = t.elem
|
e = t.elem
|
||||||
default:
|
}
|
||||||
|
if e == nil {
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
assert(elem != nil)
|
if elem == nil {
|
||||||
if telem == nil {
|
|
||||||
// first type
|
// first type
|
||||||
tkey, telem = key, elem
|
length = l
|
||||||
length = alen
|
key, elem = k, e
|
||||||
} else {
|
return true
|
||||||
// all map keys must be identical (incl. all nil)
|
}
|
||||||
if !Identical(key, tkey) {
|
// all map keys must be identical (incl. all nil)
|
||||||
return false
|
// (that is, we cannot mix maps with other types)
|
||||||
}
|
if !Identical(key, k) {
|
||||||
// all element types must be identical
|
return false
|
||||||
if !Identical(elem, telem) {
|
}
|
||||||
return false
|
// all element types must be identical
|
||||||
}
|
if !Identical(elem, e) {
|
||||||
tkey, telem = key, elem
|
return false
|
||||||
// track the minimal length for arrays
|
}
|
||||||
if alen >= 0 && alen < length {
|
// track the minimal length for arrays, if any
|
||||||
length = alen
|
if l >= 0 && l < length {
|
||||||
}
|
length = l
|
||||||
}
|
}
|
||||||
return true
|
return true
|
||||||
}) {
|
}) {
|
||||||
// For maps, the index expression must be assignable to the map key type.
|
// For maps, the index expression must be assignable to the map key type.
|
||||||
if tkey != nil {
|
if key != nil {
|
||||||
index := check.singleIndex(e)
|
index := check.singleIndex(e)
|
||||||
if index == nil {
|
if index == nil {
|
||||||
x.mode = invalid
|
x.mode = invalid
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
var key operand
|
var k operand
|
||||||
check.expr(&key, index)
|
check.expr(&k, index)
|
||||||
check.assignment(&key, tkey, "map index")
|
check.assignment(&k, key, "map index")
|
||||||
// ok to continue even if indexing failed - map element type is known
|
// ok to continue even if indexing failed - map element type is known
|
||||||
x.mode = mapindex
|
x.mode = mapindex
|
||||||
x.typ = telem
|
x.typ = elem
|
||||||
x.expr = e
|
x.expr = e
|
||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// no maps
|
// no maps
|
||||||
valid = true
|
valid = true
|
||||||
x.mode = variable
|
x.mode = mode
|
||||||
x.typ = telem
|
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]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 */ ] }
|
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
|
// slicing
|
||||||
|
|
||||||
func _[T interface{ ~[10]E }, E any] (x T, i, j, k int) { var _ []E = x[i:j] }
|
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