@@ -1332,8 +1332,12 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
1332
1332
1333
1333
eType := val .Type ().Elem ()
1334
1334
1335
+ isInterfaceSlice := eType .Kind () == reflect .Interface && val .Len () > 0
1336
+
1337
+ // If this is not an interface slice with pre-populated elements, we can look up
1338
+ // the decoder for eType once.
1335
1339
var vDecoder ValueDecoder
1336
- if ! ( eType . Kind () == reflect . Interface && val . Len () > 0 ) {
1340
+ if ! isInterfaceSlice {
1337
1341
vDecoder , err = dc .LookupDecoder (eType )
1338
1342
if err != nil {
1339
1343
return nil , err
@@ -1351,14 +1355,22 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
1351
1355
}
1352
1356
1353
1357
var elem reflect.Value
1354
- if vDecoder == nil {
1358
+ if isInterfaceSlice && idx < val .Len () {
1359
+ // Decode into an existing interface{} slot.
1360
+
1355
1361
elem = val .Index (idx ).Elem ()
1356
1362
switch {
1357
1363
case elem .Kind () != reflect .Ptr || elem .IsNil ():
1358
1364
valueDecoder , err := dc .LookupDecoder (elem .Type ())
1359
1365
if err != nil {
1360
1366
return nil , err
1361
1367
}
1368
+
1369
+ // If an element is allocated and unsettable, it must be overwritten.
1370
+ if ! elem .CanSet () {
1371
+ elem = reflect .New (elem .Type ()).Elem ()
1372
+ }
1373
+
1362
1374
err = valueDecoder .DecodeValue (dc , vr , elem )
1363
1375
if err != nil {
1364
1376
return nil , newDecodeError (strconv .Itoa (idx ), err )
@@ -1380,6 +1392,15 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
1380
1392
}
1381
1393
}
1382
1394
} else {
1395
+ // For non-interface slices, or if we've exhausted the pre-populated
1396
+ // slots, we create a fresh value.
1397
+
1398
+ if vDecoder == nil {
1399
+ vDecoder , err = dc .LookupDecoder (eType )
1400
+ if err != nil {
1401
+ return nil , err
1402
+ }
1403
+ }
1383
1404
elem , err = decodeTypeOrValueWithInfo (vDecoder , dc , vr , eType )
1384
1405
if err != nil {
1385
1406
return nil , newDecodeError (strconv .Itoa (idx ), err )
0 commit comments