cmd/compile/internal/types2: slice exprs to accept type sets with single underlying types

Change-Id: Ib9bd08ab6153129aaf8b77b41fc6ea302d0c1589
Reviewed-on: https://go-review.googlesource.com/c/go/+/357779
Trust: Robert Griesemer <gri@golang.org>
Reviewed-by: Robert Findley <rfindley@google.com>
diff --git a/src/cmd/compile/internal/types2/index.go b/src/cmd/compile/internal/types2/index.go
index 47a5e50..62f49b9 100644
--- a/src/cmd/compile/internal/types2/index.go
+++ b/src/cmd/compile/internal/types2/index.go
@@ -207,9 +207,14 @@
 
 	valid := false
 	length := int64(-1) // valid if >= 0
-	switch typ := optype(x.typ).(type) {
+	switch u := singleUnder(x.typ).(type) {
+	case nil:
+		check.errorf(x, invalidOp+"cannot slice %s: type set has no single underlying type", x)
+		x.mode = invalid
+		return
+
 	case *Basic:
-		if isString(typ) {
+		if isString(u) {
 			if e.Full {
 				check.error(x, invalidOp+"3-index slice of string")
 				x.mode = invalid
@@ -221,26 +226,26 @@
 			}
 			// spec: "For untyped string operands the result
 			// is a non-constant value of type string."
-			if typ.kind == UntypedString {
+			if u.kind == UntypedString {
 				x.typ = Typ[String]
 			}
 		}
 
 	case *Array:
 		valid = true
-		length = typ.len
+		length = u.len
 		if x.mode != variable {
 			check.errorf(x, invalidOp+"%s (slice of unaddressable value)", x)
 			x.mode = invalid
 			return
 		}
-		x.typ = &Slice{elem: typ.elem}
+		x.typ = &Slice{elem: u.elem}
 
 	case *Pointer:
-		if typ := asArray(typ.base); typ != nil {
+		if u := asArray(u.base); u != nil {
 			valid = true
-			length = typ.len
-			x.typ = &Slice{elem: typ.elem}
+			length = u.len
+			x.typ = &Slice{elem: u.elem}
 		}
 
 	case *Slice:
diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2
index d1f07a2..1200a6e 100644
--- a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2
+++ b/src/cmd/compile/internal/types2/testdata/check/typeparams.go2
@@ -123,6 +123,11 @@
 func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x[i:j] }
 func _[T interface{ ~string }] (x T, i, j, k int) { var _ T = x /* ERROR 3-index slice of string */ [i:j:k] }
 
+type myByte1 []byte
+type myByte2 []byte
+func _[T interface{ []byte | myByte1 | myByte2 }] (x T, i, j, k int) { var _ T = x[i:j:k] }
+func _[T interface{ []byte | myByte1 | []int }] (x T, i, j, k int) { var _ T = x[ /* ERROR no single underlying type */ i:j:k] }
+
 // len/cap built-ins
 
 func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) }