@@ -442,21 +442,26 @@ func (d *Decoder) Decode(input interface{}) error {
442442 return err
443443}
444444
445+ // isNil returns true if the input is nil or a typed nil pointer.
446+ func isNil (input interface {}) bool {
447+ if input == nil {
448+ return true
449+ }
450+ val := reflect .ValueOf (input )
451+ return val .Kind () == reflect .Ptr && val .IsNil ()
452+ }
453+
445454// Decodes an unknown data type into a specific reflection value.
446455func (d * Decoder ) decode (name string , input interface {}, outVal reflect.Value ) error {
447- var inputVal reflect.Value
448- if input != nil {
449- inputVal = reflect .ValueOf (input )
450-
451- // We need to check here if input is a typed nil. Typed nils won't
452- // match the "input == nil" below so we check that here.
453- if inputVal .Kind () == reflect .Ptr && inputVal .IsNil () {
454- input = nil
455- }
456+ var (
457+ inputVal = reflect .ValueOf (input )
458+ outputKind = getKind (outVal )
459+ decodeNil = d .config .DecodeNil && d .cachedDecodeHook != nil
460+ )
461+ if isNil (input ) {
462+ // Typed nils won't match the "input == nil" below, so reset input.
463+ input = nil
456464 }
457-
458- decodeNil := d .config .DecodeNil && d .config .DecodeHook != nil
459-
460465 if input == nil {
461466 // If the data is nil, then we don't set anything, unless ZeroFields is set
462467 // to true.
@@ -467,12 +472,10 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
467472 d .config .Metadata .Keys = append (d .config .Metadata .Keys , name )
468473 }
469474 }
470-
471475 if ! decodeNil {
472476 return nil
473477 }
474478 }
475-
476479 if ! inputVal .IsValid () {
477480 if ! decodeNil {
478481 // If the input value is invalid, then we just set the value
@@ -483,11 +486,17 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
483486 }
484487 return nil
485488 }
486-
487- // If we get here, we have an untyped nil so the type of the input is assumed.
488- // We do this because all subsequent code requires a valid value for inputVal.
489- var mapVal map [string ]interface {}
490- inputVal = reflect .MakeMap (reflect .TypeOf (mapVal ))
489+ // Hooks need a valid inputVal, so reset it to zero value of outVal type.
490+ switch outputKind {
491+ case reflect .Struct , reflect .Map :
492+ var mapVal map [string ]interface {}
493+ inputVal = reflect .ValueOf (mapVal ) // create nil map pointer
494+ case reflect .Slice , reflect .Array :
495+ var sliceVal []interface {}
496+ inputVal = reflect .ValueOf (sliceVal ) // create nil slice pointer
497+ default :
498+ inputVal = reflect .Zero (outVal .Type ())
499+ }
491500 }
492501
493502 if d .cachedDecodeHook != nil {
@@ -498,9 +507,11 @@ func (d *Decoder) decode(name string, input interface{}, outVal reflect.Value) e
498507 return fmt .Errorf ("error decoding '%s': %w" , name , err )
499508 }
500509 }
510+ if isNil (input ) {
511+ return nil
512+ }
501513
502514 var err error
503- outputKind := getKind (outVal )
504515 addMetaKey := true
505516 switch outputKind {
506517 case reflect .Bool :
@@ -781,8 +792,8 @@ func (d *Decoder) decodeBool(name string, data interface{}, val reflect.Value) e
781792 }
782793 default :
783794 return fmt .Errorf (
784- "'%s' expected type '%s', got unconvertible type '%s ', value: '%v'" ,
785- name , val . Type () , dataVal . Type () , data )
795+ "'%s' expected type '%s', got unconvertible type '%#v ', value: '%# v'" ,
796+ name , val , dataVal , data )
786797 }
787798
788799 return nil
0 commit comments