@@ -330,33 +330,22 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
330
330
331
331
case _Copy :
332
332
// 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 )
337
334
338
335
var y operand
339
336
arg (& y , 1 )
340
337
if y .mode == invalid {
341
338
return
342
339
}
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 )
352
341
353
342
if dst == nil || src == nil {
354
343
check .invalidArg (x , _InvalidCopy , "copy expects slice arguments; found %s and %s" , x , & y )
355
344
return
356
345
}
357
346
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 )
360
349
return
361
350
}
362
351
@@ -783,6 +772,46 @@ func (check *Checker) builtin(x *operand, call *ast.CallExpr, id builtinId) (_ b
783
772
return true
784
773
}
785
774
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
+
786
815
// hasVarSize reports if the size of type t is variable due to type parameters.
787
816
func hasVarSize (t Type ) bool {
788
817
switch t := under (t ).(type ) {
0 commit comments