]> Cypherpunks repositories - gostls13.git/commitdiff
go/types: factor out slice elem computation for copy built-in
authorRobert Findley <rfindley@google.com>
Wed, 27 Oct 2021 16:17:21 +0000 (12:17 -0400)
committerRobert Findley <rfindley@google.com>
Thu, 28 Oct 2021 16:08:36 +0000 (16:08 +0000)
This is a port of CL 357413 to go/types. Some test constraints are also
updated to remove 'interface', to coincide with the corresponding test
data file in types2.

Change-Id: I5248190501c2e4381eb7625f8d4fb269301d6e16
Reviewed-on: https://go-review.googlesource.com/c/go/+/359138
Trust: Robert Findley <rfindley@google.com>
Run-TryBot: Robert Findley <rfindley@google.com>
TryBot-Result: Go Bot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
src/go/types/builtins.go
src/go/types/testdata/check/builtins.go2

index 3e2c994b090afd6f73c47793ff5abc996c6800ad..29a8339f3ec6917993af9dfbe11d2c7c95c05f5b 100644 (file)
@@ -330,33 +330,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
 
        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
                }
 
@@ -783,6 +772,46 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
        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) {
index fb912a191822089b5ab675165d37448f7b58c7a5..f9b6ec792615a43a9d4ace78e3238d53492257d1 100644 (file)
@@ -51,7 +51,7 @@ func _[T any](x, y T) {
        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)
@@ -66,20 +66,26 @@ func _[T interface{~[]byte}](x, y T) {
        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