@@ -1332,8 +1332,12 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
13321332
13331333 eType := val .Type ().Elem ()
13341334
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.
13351339 var vDecoder ValueDecoder
1336- if ! ( eType . Kind () == reflect . Interface && val . Len () > 0 ) {
1340+ if ! isInterfaceSlice {
13371341 vDecoder , err = dc .LookupDecoder (eType )
13381342 if err != nil {
13391343 return nil , err
@@ -1351,14 +1355,22 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
13511355 }
13521356
13531357 var elem reflect.Value
1354- if vDecoder == nil {
1358+ if isInterfaceSlice && idx < val .Len () {
1359+ // Decode into an existing interface{} slot.
1360+
13551361 elem = val .Index (idx ).Elem ()
13561362 switch {
13571363 case elem .Kind () != reflect .Ptr || elem .IsNil ():
13581364 valueDecoder , err := dc .LookupDecoder (elem .Type ())
13591365 if err != nil {
13601366 return nil , err
13611367 }
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+
13621374 err = valueDecoder .DecodeValue (dc , vr , elem )
13631375 if err != nil {
13641376 return nil , newDecodeError (strconv .Itoa (idx ), err )
@@ -1380,6 +1392,15 @@ func decodeDefault(dc DecodeContext, vr ValueReader, val reflect.Value) ([]refle
13801392 }
13811393 }
13821394 } 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+ }
13831404 elem , err = decodeTypeOrValueWithInfo (vDecoder , dc , vr , eType )
13841405 if err != nil {
13851406 return nil , newDecodeError (strconv .Itoa (idx ), err )
0 commit comments