]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: fix indexing of generic types
authorRobert Griesemer <gri@golang.org>
Mon, 1 Nov 2021 23:05:14 +0000 (16:05 -0700)
committerRobert Griesemer <gri@golang.org>
Tue, 2 Nov 2021 16:12:28 +0000 (16:12 +0000)
Correctly track if the index expression is addressable.
Rewrote code slightly.

Fixes #49275.

Change-Id: Ic54edd0213a091173ff5403ab0e3e1f1fca0e361
Reviewed-on: https://go-review.googlesource.com/c/go/+/360603
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
src/cmd/compile/internal/types2/index.go
src/cmd/compile/internal/types2/testdata/check/typeparams.go2

index 23e433ac6a772847ff61ba3555832d66af4383cd..bb7033e95784fee80264de19d1090a949fccc4a4 100644 (file)
@@ -101,77 +101,80 @@ func (check *Checker) indexExpr(x *operand, e *syntax.IndexExpr) (isFuncInst boo
 
        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(&kkey, "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
                }
        }
 
index 11adb21d95f029ec1b6d8a385d83479ceb705264..a1bf6c262f4ce105d36cd0172f96ec46558be14c 100644 (file)
@@ -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] }