From: Robert Findley Date: Wed, 27 Oct 2021 16:17:21 +0000 (-0400) Subject: go/types: factor out slice elem computation for copy built-in X-Git-Tag: go1.18beta1~702 X-Git-Url: http://www.git.cypherpunks.su/?a=commitdiff_plain;h=6f0185bf38a679f468b6a4209f15188a11662eb5;p=gostls13.git go/types: factor out slice elem computation for copy built-in 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 Run-TryBot: Robert Findley TryBot-Result: Go Bot Reviewed-by: Robert Griesemer --- diff --git a/src/go/types/builtins.go b/src/go/types/builtins.go index 3e2c994b09..29a8339f3e 100644 --- a/src/go/types/builtins.go +++ b/src/go/types/builtins.go @@ -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) { diff --git a/src/go/types/testdata/check/builtins.go2 b/src/go/types/testdata/check/builtins.go2 index fb912a1918..f9b6ec7926 100644 --- a/src/go/types/testdata/check/builtins.go2 +++ b/src/go/types/testdata/check/builtins.go2 @@ -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