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.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
valid := false
length := int64(-1) // valid if >= 0
- switch u := structuralType(x.typ).(type) {
+ switch u := structuralString(x.typ).(type) {
case nil:
check.invalidOp(x, _NonSliceableOperand, "cannot slice %s: %s has no structural type", x, x.typ)
x.mode = invalid
}
// 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]
}
}
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 */ ) }
}
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
+}