From 21400491728520e648d8f1634605ea2b704a8fc2 Mon Sep 17 00:00:00 2001 From: Robert Griesemer Date: Tue, 17 Nov 2020 16:12:29 -0800 Subject: [PATCH] [dev.typeparams] cmd/compile/internal/types2: port of https://golang.org/cl/270957 This ports the latest updates to the dev.go2go version of types2 to the dev.typeparams version. Change-Id: Ic1b09a8aaeefc701a5c194a587be26e0878e64da Reviewed-on: https://go-review.googlesource.com/c/go/+/270958 Trust: Robert Griesemer Run-TryBot: Robert Griesemer TryBot-Result: Go Bot Reviewed-by: Robert Findley --- src/cmd/compile/internal/types2/expr.go | 65 +++++++++++++++---- .../internal/types2/testdata/expr3.src | 1 + .../internal/types2/testdata/typeparams.go2 | 10 ++- 3 files changed, 61 insertions(+), 15 deletions(-) diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index f83aa86f6e..7c07950b01 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -1467,18 +1467,18 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin var key operand check.expr(&key, e.Index) check.assignment(&key, typ.key, "map index") - if x.mode == invalid { - goto Error - } + // ok to continue even if indexing failed - map element type is known x.mode = mapindex x.typ = typ.elem x.expr = e return expression case *Sum: - // A sum type can be indexed if all the sum's types - // support indexing and have the same element type. - var elem Type + // A sum type can be indexed if all of the sum's types + // support indexing and have the same index and element + // type. Special rules apply for maps in the sum type. + var tkey, telem Type // key is for map types only + nmaps := 0 // number of map types in sum type if typ.is(func(t Type) bool { var e Type switch t := t.Under().(type) { @@ -1495,21 +1495,58 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin case *Slice: e = t.elem case *Map: + // If there are multiple maps in the sum type, + // they must have identical key types. + // TODO(gri) We may be able to relax this rule + // but it becomes complicated very quickly. + if tkey != nil && !Identical(t.key, tkey) { + return false + } + tkey = t.key e = t.elem + nmaps++ case *TypeParam: check.errorf(x, "type of %s contains a type parameter - cannot index (implementation restriction)", x) case *instance: - unimplemented() + panic("unimplemented") } - if e != nil && (e == elem || elem == nil) { - elem = e - return true + if e == nil || telem != nil && !Identical(e, telem) { + return false } - return false + telem = e + return true }) { - valid = true - x.mode = variable - x.typ = elem + // If there are maps, the index expression must be assignable + // to the map key type (as for simple map index expressions). + if nmaps > 0 { + var key operand + check.expr(&key, e.Index) + check.assignment(&key, tkey, "map index") + // ok to continue even if indexing failed - map element type is known + + // If there are only maps, we are done. + if nmaps == len(typ.types) { + x.mode = mapindex + x.typ = telem + x.expr = e + return expression + } + + // Otherwise we have mix of maps and other types. For + // now we require that the map key be an integer type. + // TODO(gri) This is probably not good enough. + valid = isInteger(tkey) + // avoid 2nd indexing error if indexing failed above + if !valid && key.mode == invalid { + goto Error + } + x.mode = value // map index expressions are not addressable + } else { + // no maps + valid = true + x.mode = variable + } + x.typ = telem } } diff --git a/src/cmd/compile/internal/types2/testdata/expr3.src b/src/cmd/compile/internal/types2/testdata/expr3.src index 3c6e36f148..071c9bb367 100644 --- a/src/cmd/compile/internal/types2/testdata/expr3.src +++ b/src/cmd/compile/internal/types2/testdata/expr3.src @@ -103,6 +103,7 @@ func indexes() { var ok mybool _, ok = m["bar"] _ = ok + _ = m[0 /* ERROR "cannot convert 0" */ ] + "foo" // ERROR "cannot convert" var t string _ = t[- /* ERROR "negative" */ 1] diff --git a/src/cmd/compile/internal/types2/testdata/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/typeparams.go2 index 54cb34ec3b..04f563029f 100644 --- a/src/cmd/compile/internal/types2/testdata/typeparams.go2 +++ b/src/cmd/compile/internal/types2/testdata/typeparams.go2 @@ -94,11 +94,19 @@ func _[T any] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ type int }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ type string }] (x T, i int) { _ = x[i] } func _[T interface{ type []int }] (x T, i int) { _ = x[i] } -func _[T interface{ type [10]int, *[20]int, map[string]int }] (x T, i int) { _ = x[i] } +func _[T interface{ type [10]int, *[20]int, map[int]int }] (x T, i int) { _ = x[i] } func _[T interface{ type string, []byte }] (x T, i int) { _ = x[i] } func _[T interface{ type []int, [1]rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } func _[T interface{ type string, []rune }] (x T, i int) { _ = x /* ERROR "cannot index" */ [i] } +// indexing with various combinations of map types in type lists (see issue #42616) +func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = x[i] } +func _[T interface{ type []E }, E any](x T, i int) { _ = &x[i] } +func _[T interface{ type map[int]E }, E any](x T, i int) { _, _ = x[i] } // comma-ok permitted +func _[T interface{ type []E, map[int]E }, E any](x T, i int) { _ = &x /* ERROR cannot take address */ [i] } +func _[T interface{ type []E, map[int]E, map[uint]E }, E any](x T, i int) { _ = x /* ERROR cannot index */ [i] } // different map element types +func _[T interface{ type []E, map[string]E }, E any](x T, i int) { _ = x[i /* ERROR cannot use i */ ] } + // slicing // TODO(gri) implement this -- 2.50.0