Skip to content

Commit 6f0185b

Browse files
committed
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 <[email protected]> Run-TryBot: Robert Findley <[email protected]> TryBot-Result: Go Bot <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent 61536ec commit 6f0185b

File tree

2 files changed

+56
-21
lines changed

2 files changed

+56
-21
lines changed

src/go/types/builtins.go

Lines changed: 44 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -330,33 +330,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
330330

331331
case _Copy:
332332
// copy(x, y []T) int
333-
var dst Type
334-
if t := asSlice(x.typ); t != nil {
335-
dst = t.elem
336-
}
333+
dst, _ := singleUnder(x.typ).(*Slice)
337334

338335
var y operand
339336
arg(&y, 1)
340337
if y.mode == invalid {
341338
return
342339
}
343-
var src Type
344-
switch t := optype(y.typ).(type) {
345-
case *Basic:
346-
if isString(y.typ) {
347-
src = universeByte
348-
}
349-
case *Slice:
350-
src = t.elem
351-
}
340+
src, _ := singleUnderString(y.typ).(*Slice)
352341

353342
if dst == nil || src == nil {
354343
check.invalidArg(x, _InvalidCopy, "copy expects slice arguments; found %s and %s", x, &y)
355344
return
356345
}
357346

358-
if !Identical(dst, src) {
359-
check.invalidArg(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst, src)
347+
if !Identical(dst.elem, src.elem) {
348+
check.errorf(x, _InvalidCopy, "arguments to copy %s and %s have different element types %s and %s", x, &y, dst.elem, src.elem)
360349
return
361350
}
362351

@@ -783,6 +772,46 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
783772
return true
784773
}
785774

775+
// If typ is a type parameter, single under returns the single underlying
776+
// type of all types in the corresponding type constraint if it exists, or
777+
// nil if it doesn't exist. If typ is not a type parameter, singleUnder
778+
// just returns the underlying type.
779+
func singleUnder(typ Type) Type {
780+
var su Type
781+
if underIs(typ, func(u Type) bool {
782+
if su != nil && !Identical(su, u) {
783+
return false
784+
}
785+
// su == nil || Identical(su, u)
786+
su = u
787+
return true
788+
}) {
789+
return su
790+
}
791+
return nil
792+
}
793+
794+
// singleUnderString is like singleUnder but also considers []byte and
795+
// string as "identical". In this case, if successful, the result is always
796+
// []byte.
797+
func singleUnderString(typ Type) Type {
798+
var su Type
799+
if underIs(typ, func(u Type) bool {
800+
if isString(u) {
801+
u = NewSlice(universeByte)
802+
}
803+
if su != nil && !Identical(su, u) {
804+
return false
805+
}
806+
// su == nil || Identical(su, u)
807+
su = u
808+
return true
809+
}) {
810+
return su
811+
}
812+
return nil
813+
}
814+
786815
// hasVarSize reports if the size of type t is variable due to type parameters.
787816
func hasVarSize(t Type) bool {
788817
switch t := under(t).(type) {

src/go/types/testdata/check/builtins.go2

Lines changed: 12 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -51,7 +51,7 @@ func _[T any](x, y T) {
5151
copy(x /* ERROR copy expects slice arguments */ , y)
5252
}
5353

54-
func _[T interface{~[]byte}](x, y T) {
54+
func _[T ~[]byte](x, y T) {
5555
copy(x, y)
5656
copy(x, "foo")
5757
copy("foo" /* ERROR expects slice arguments */ , y)
@@ -66,20 +66,26 @@ func _[T interface{~[]byte}](x, y T) {
6666
copy(y /* ERROR different element types */ , x3)
6767
}
6868

69-
func _[T interface{~[]E}, E any](x T, y []E) {
69+
func _[T ~[]E, E any](x T, y []E) {
7070
copy(x, y)
7171
copy(x /* ERROR different element types */ , "foo")
7272
}
7373

74-
func _[T interface{~string}](x []byte, y T) {
74+
func _[T ~string](x []byte, y T) {
7575
copy(x, y)
7676
copy(y /* ERROR expects slice arguments */ , x)
7777
}
7878

79-
func _[T interface{~[]byte|~string}](x T, y []byte) {
79+
func _[T ~[]byte|~string](x T, y []byte) {
8080
copy(x /* ERROR expects slice arguments */ , y)
81-
// TODO(gri) should this be valid?
82-
copy(y /* ERROR expects slice arguments */ , x)
81+
copy(y, x)
82+
}
83+
84+
type L0 []int
85+
type L1 []int
86+
87+
func _[T L0 | L1](x, y T) {
88+
copy(x, y)
8389
}
8490

8591
// delete

0 commit comments

Comments
 (0)