case _Copy:
// copy(x, y []T) int
- var dst Type
- if t := asSlice(x.typ); t != nil {
- dst = t.elem
- }
+ dst, _ := singleUnder(x.typ).(*Slice)
var y operand
arg(&y, 1)
if y.mode == invalid {
return
}
- var src Type
- switch t := optype(y.typ).(type) {
- case *Basic:
- if isString(y.typ) {
- src = universeByte
- }
- case *Slice:
- src = t.elem
- }
+ src, _ := singleUnderString(y.typ).(*Slice)
if dst == nil || src == nil {
check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
return
}
- if !Identical(dst, src) {
- check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
+ if !Identical(dst.elem, src.elem) {
+ check.errorf(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)
return
}
return true
}
+// If typ is a type parameter, single under returns the single underlying
+// type of all types in the corresponding type constraint if it exists, or
+// nil if it doesn't exist. If typ is not a type parameter, singleUnder
+// just returns the underlying type.
+func singleUnder(typ Type) Type {
+ var su Type
+ if underIs(typ, func(u Type) bool {
+ if su != nil && !Identical(su, u) {
+ return false
+ }
+ // su == nil || Identical(su, u)
+ su = u
+ return true
+ }) {
+ return su
+ }
+ return nil
+}
+
+// singleUnderString is like singleUnder but also considers []byte and
+// string as "identical". In this case, if successful, the result is always
+// []byte.
+func singleUnderString(typ Type) Type {
+ var su Type
+ if underIs(typ, func(u Type) bool {
+ if isString(u) {
+ u = NewSlice(universeByte)
+ }
+ if su != nil && !Identical(su, u) {
+ return false
+ }
+ // su == nil || Identical(su, u)
+ su = u
+ return true
+ }) {
+ return su
+ }
+ return nil
+}
+
// hasVarSize reports if the size of type t is variable due to type parameters.
func hasVarSize(t Type) bool {
switch t := under(t).(type) {
copy(x /* ERROR copy expects slice arguments */ , y)
}
-func _[T interface{~[]byte}](x, y T) {
+func _[T ~[]byte](x, y T) {
copy(x, y)
copy(x, "foo")
copy("foo" /* ERROR expects slice arguments */ , y)
copy(y /* ERROR different element types */ , x3)
}
-func _[T interface{~[]E}, E any](x T, y []E) {
+func _[T ~[]E, E any](x T, y []E) {
copy(x, y)
copy(x /* ERROR different element types */ , "foo")
}
-func _[T interface{~string}](x []byte, y T) {
+func _[T ~string](x []byte, y T) {
copy(x, y)
copy(y /* ERROR expects slice arguments */ , x)
}
-func _[T interface{~[]byte|~string}](x T, y []byte) {
+func _[T ~[]byte|~string](x T, y []byte) {
copy(x /* ERROR expects slice arguments */ , y)
- // TODO(gri) should this be valid?
- copy(y /* ERROR expects slice arguments */ , x)
+ copy(y, x)
+}
+
+type L0 []int
+type L1 []int
+
+func _[T L0 | L1](x, y T) {
+ copy(x, y)
}
// delete