]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/compile/internal/types2: allow slicing for operands with []byte|string type sets
authorRobert Griesemer <gri@golang.org>
Fri, 12 Nov 2021 23:08:00 +0000 (15:08 -0800)
committerRobert Griesemer <gri@golang.org>
Mon, 15 Nov 2021 21:22:12 +0000 (21:22 +0000)
Fixes #49566.

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

index 5b4ffd0dad8a3394532ab75b83902db8214add2e..53d834507ac30c641792b75a1e4ca44a218a72b7 100644 (file)
@@ -337,26 +337,11 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
                if y.mode == invalid {
                        return
                }
-               // src, _ := structuralType(y.typ).(*Slice); but also accepts strings
-               var src *Slice
-               var elem Type // == src.elem if valid
-               if underIs(y.typ, func(u Type) bool {
-                       switch u := u.(type) {
-                       case *Basic:
-                               if isString(u) && (elem == nil || Identical(elem, universeByte)) {
-                                       elem = universeByte
-                                       return true
-                               }
-                       case *Slice:
-                               if elem == nil || Identical(elem, u.elem) {
-                                       elem = u.elem
-                                       return true
-                               }
-                       }
-                       return false
-               }) {
-                       src = NewSlice(elem)
+               src0 := structuralString(y.typ)
+               if src0 != nil && isString(src0) {
+                       src0 = NewSlice(universeByte)
                }
+               src, _ := src0.(*Slice)
 
                if dst == nil || src == nil {
                        check.errorf(x, invalidArg+"copy expects slice arguments; found %s and %s", x, &y)
index 648c7abe6f24ad2004cbd32ae1680d2fc199370a..524d1957b575b62357097759e8177fd38dea77fa 100644 (file)
@@ -213,7 +213,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
 
        valid := false
        length := int64(-1) // valid if >= 0
-       switch u := structuralType(x.typ).(type) {
+       switch u := structuralString(x.typ).(type) {
        case nil:
                check.errorf(x, invalidOp+"cannot slice %s: %s has no structural type", x, x.typ)
                x.mode = invalid
@@ -232,7 +232,7 @@ func (check *Checker) sliceExpr(x *operand, e *syntax.SliceExpr) {
                        }
                        // spec: "For untyped string operands the result
                        // is a non-constant value of type string."
-                       if u.kind == UntypedString {
+                       if isUntyped(x.typ) {
                                x.typ = Typ[String]
                        }
                }
index 03c3f9a0b589ffffe0cc76a3ed2b60ad6af1b59e..f77d09391b6a7a6b43cc67b6e8c85f8a31216efe 100644 (file)
@@ -136,6 +136,10 @@ 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 structural type */ i:j:k] }
 
+func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x[i:j] }
+func _[T interface{ []byte | myByte1 | myByte2 | string }] (x T, i, j, k int) { var _ T = x /* ERROR 3-index slice of string */ [i:j:k] }
+func _[T interface{ []byte | myByte1 | []int | string }] (x T, i, j, k int) { var _ T = x[ /* ERROR no structural type */ i:j] }
+
 // len/cap built-ins
 
 func _[T any](x T) { _ = len(x /* ERROR invalid argument */ ) }
index 39737d47a7b5830d6c864b4dbad0eade8b2dd487..3ab738eb19685ab06079918079ca6797f24f62dd 100644 (file)
@@ -87,3 +87,40 @@ func structuralType(t Type) Type {
        }
        return nil
 }
+
+// structuralString is like structuralType but also considers []byte
+// and strings as identical. In this case, if successful and we saw
+// a string, the result is of type (possibly untyped) string.
+func structuralString(t Type) Type {
+       tpar, _ := t.(*TypeParam)
+       if tpar == nil {
+               return under(t) // string or untyped string
+       }
+
+       var su Type
+       hasString := false
+       if tpar.underIs(func(u Type) bool {
+               if u == nil {
+                       return false
+               }
+               if isString(u) {
+                       u = NewSlice(universeByte)
+                       hasString = true
+               }
+               if su != nil {
+                       u = match(su, u)
+                       if u == nil {
+                               return false
+                       }
+               }
+               // su == nil || match(su, u) != nil
+               su = u
+               return true
+       }) {
+               if hasString {
+                       return Typ[String]
+               }
+               return su
+       }
+       return nil
+}