@@ -83,48 +83,19 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
83
83
switch id {
84
84
case _Append :
85
85
// append(s S, x ...E) S, where E is the element type of S
86
- // spec: "The variadic function append appends zero or more values x to a slice s
87
- // of type S and returns the resulting slice, also of type S.
88
- // The values x are passed to a parameter of type ...E where E is the element type
89
- // of S and the respective parameter passing rules apply."
90
- S := x .typ
91
-
92
- // determine E
93
- var E Type
94
- typeset (S , func (_ , u Type ) bool {
95
- s , _ := u .(* Slice )
96
- if s == nil {
97
- var cause string
98
- if x .isNil () {
99
- // Printing x in this case would just print "nil".
100
- // Special case this so we can emphasize "untyped".
101
- cause = "untyped nil"
102
- } else {
103
- cause = check .sprintf ("%s" , x )
104
- }
105
- check .errorf (x , InvalidAppend , "invalid append: first argument must be a slice; have %s" , cause )
106
- E = nil
107
- return false
108
- }
109
- if E == nil {
110
- E = s .elem
111
- } else if ! Identical (E , s .elem ) {
112
- check .errorf (x , InvalidAppend , "invalid append: mismatched slice element types %s and %s in %s" , E , s .elem , x )
113
- E = nil
114
- return false
115
- }
116
- return true
117
- })
118
- if E == nil {
119
- return
120
- }
121
-
122
- // spec: "As a special case, append also accepts a first argument assignable
86
+ // spec: "The variadic function append appends zero or more values x to
87
+ // a slice s of type S and returns the resulting slice, also of type S.
88
+ // The values x are passed to a parameter of type ...E where E is the
89
+ // element type of S and the respective parameter passing rules apply.
90
+ // As a special case, append also accepts a first argument assignable
123
91
// to type []byte with a second argument of string type followed by ... .
124
92
// This form appends the bytes of the string."
93
+
94
+ // get special case out of the way
95
+ var sig * Signature
125
96
if nargs == 2 && hasDots (call ) {
126
97
if ok , _ := x .assignableTo (check , NewSlice (universeByte ), nil ); ok {
127
- y := args [1 ] // valid if != nil
98
+ y := args [1 ]
128
99
typeset (y .typ , func (_ , u Type ) bool {
129
100
if s , _ := u .(* Slice ); s != nil && Identical (s .elem , universeByte ) {
130
101
return true
@@ -135,31 +106,35 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
135
106
y = nil
136
107
return false
137
108
})
138
-
139
109
if y != nil {
140
- if check .recordTypes () {
141
- sig := makeSig (S , S , y .typ )
142
- sig .variadic = true
143
- check .recordBuiltinType (call .Fun , sig )
144
- }
145
- x .mode = value
146
- x .typ = S
147
- break
110
+ // setting the signature also signals that we're done
111
+ sig = makeSig (x .typ , x .typ , y .typ )
112
+ sig .variadic = true
148
113
}
149
114
}
150
115
}
151
116
152
- // check general case by creating custom signature
153
- sig := makeSig (S , S , NewSlice (E )) // []E required for variadic signature
154
- sig .variadic = true
155
- check .arguments (call , sig , nil , nil , args , nil ) // discard result (we know the result type)
156
- // ok to continue even if check.arguments reported errors
117
+ // general case
118
+ if sig == nil {
119
+ // spec: "If S is a type parameter, all types in its type set
120
+ // must have the same underlying slice type []E."
121
+ E , err := sliceElem (x )
122
+ if err != nil {
123
+ check .errorf (x , InvalidAppend , "invalid append: %s" , err .format (check ))
124
+ return
125
+ }
126
+ // check arguments by creating custom signature
127
+ sig = makeSig (x .typ , x .typ , NewSlice (E )) // []E required for variadic signature
128
+ sig .variadic = true
129
+ check .arguments (call , sig , nil , nil , args , nil ) // discard result (we know the result type)
130
+ // ok to continue even if check.arguments reported errors
131
+ }
157
132
158
- x .mode = value
159
- x .typ = S
160
133
if check .recordTypes () {
161
134
check .recordBuiltinType (call .Fun , sig )
162
135
}
136
+ x .mode = value
137
+ // x.typ is unchanged
163
138
164
139
case _Cap , _Len :
165
140
// cap(x)
@@ -376,25 +351,54 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
376
351
x .typ = resTyp
377
352
378
353
case _Copy :
379
- // copy(x, y []T) int
380
- u , _ := commonUnder (x .typ , nil )
381
- dst , _ := u .(* Slice )
382
-
354
+ // copy(x, y []E) int
355
+ // spec: "The function copy copies slice elements from a source src to a destination
356
+ // dst and returns the number of elements copied. Both arguments must have identical
357
+ // element type E and must be assignable to a slice of type []E.
358
+ // The number of elements copied is the minimum of len(src) and len(dst).
359
+ // As a special case, copy also accepts a destination argument assignable to type
360
+ // []byte with a source argument of a string type.
361
+ // This form copies the bytes from the string into the byte slice."
362
+
363
+ // get special case out of the way
383
364
y := args [1 ]
384
- src0 := coreString (y .typ )
385
- if src0 != nil && isString (src0 ) {
386
- src0 = NewSlice (universeByte )
387
- }
388
- src , _ := src0 .(* Slice )
389
-
390
- if dst == nil || src == nil {
391
- check .errorf (x , InvalidCopy , invalidArg + "copy expects slice arguments; found %s and %s" , x , y )
392
- return
365
+ var special bool
366
+ if ok , _ := x .assignableTo (check , NewSlice (universeByte ), nil ); ok {
367
+ special = true
368
+ typeset (y .typ , func (_ , u Type ) bool {
369
+ if s , _ := u .(* Slice ); s != nil && Identical (s .elem , universeByte ) {
370
+ return true
371
+ }
372
+ if isString (u ) {
373
+ return true
374
+ }
375
+ special = false
376
+ return false
377
+ })
393
378
}
394
379
395
- if ! Identical (dst .elem , src .elem ) {
396
- check .errorf (x , InvalidCopy , invalidArg + "arguments to copy %s and %s have different element types %s and %s" , x , y , dst .elem , src .elem )
397
- return
380
+ // general case
381
+ if ! special {
382
+ // spec: "If the type of one or both arguments is a type parameter, all types
383
+ // in their respective type sets must have the same underlying slice type []E."
384
+ dstE , err := sliceElem (x )
385
+ if err != nil {
386
+ check .errorf (x , InvalidCopy , "invalid copy: %s" , err .format (check ))
387
+ return
388
+ }
389
+ srcE , err := sliceElem (y )
390
+ if err != nil {
391
+ // If we have a string, for a better error message proceed with byte element type.
392
+ if ! allString (y .typ ) {
393
+ check .errorf (y , InvalidCopy , "invalid copy: %s" , err .format (check ))
394
+ return
395
+ }
396
+ srcE = universeByte
397
+ }
398
+ if ! Identical (dstE , srcE ) {
399
+ check .errorf (x , InvalidCopy , "invalid copy: arguments %s and %s have different element types %s and %s" , x , y , dstE , srcE )
400
+ return
401
+ }
398
402
}
399
403
400
404
if check .recordTypes () {
@@ -938,6 +942,37 @@ func (check *Checker) builtin(x *operand, call *syntax.CallExpr, id builtinId) (
938
942
return true
939
943
}
940
944
945
+ // sliceElem returns the slice element type for a slice operand x
946
+ // or a type error if x is not a slice (or a type set of slices).
947
+ func sliceElem (x * operand ) (Type , * typeError ) {
948
+ var E Type
949
+ var err * typeError
950
+ typeset (x .typ , func (_ , u Type ) bool {
951
+ s , _ := u .(* Slice )
952
+ if s == nil {
953
+ if x .isNil () {
954
+ // Printing x in this case would just print "nil".
955
+ // Special case this so we can emphasize "untyped".
956
+ err = typeErrorf ("argument must be a slice; have untyped nil" )
957
+ } else {
958
+ err = typeErrorf ("argument must be a slice; have %s" , x )
959
+ }
960
+ return false
961
+ }
962
+ if E == nil {
963
+ E = s .elem
964
+ } else if ! Identical (E , s .elem ) {
965
+ err = typeErrorf ("mismatched slice element types %s and %s in %s" , E , s .elem , x )
966
+ return false
967
+ }
968
+ return true
969
+ })
970
+ if err != nil {
971
+ return nil , err
972
+ }
973
+ return E , nil
974
+ }
975
+
941
976
// hasVarSize reports if the size of type t is variable due to type parameters
942
977
// or if the type is infinitely-sized due to a cycle for which the type has not
943
978
// yet been checked.
0 commit comments