@@ -86,11 +86,13 @@ func getFilteredCodeSetIfNeeded(ctx *RuntimeContext, codeSet *OpcodeSet) (*Opcod
86
86
87
87
type Compiler struct {
88
88
structTypeToCode map [uintptr ]* StructCode
89
+ anonymousStructTypeToCode map [uintptr ]* StructCode
89
90
}
90
91
91
92
func newCompiler () * Compiler {
92
93
return & Compiler {
93
94
structTypeToCode : map [uintptr ]* StructCode {},
95
+ anonymousStructTypeToCode : map [uintptr ]* StructCode {},
94
96
}
95
97
}
96
98
@@ -169,11 +171,11 @@ func (c *Compiler) typeToCode(typ *runtime.Type) (Code, error) {
169
171
return c .sliceCode (typ )
170
172
case reflect .Map :
171
173
if isPtr {
172
- return c .ptrCode (runtime .PtrTo (typ ))
174
+ return c .ptrCode (runtime .PtrTo (typ ), false )
173
175
}
174
176
return c .mapCode (typ )
175
177
case reflect .Struct :
176
- return c .structCode (typ , isPtr )
178
+ return c .structCode (typ , isPtr , false )
177
179
case reflect .Int :
178
180
return c .intCode (typ , isPtr )
179
181
case reflect .Int8 :
@@ -208,11 +210,11 @@ func (c *Compiler) typeToCode(typ *runtime.Type) (Code, error) {
208
210
if isPtr && typ .Implements (marshalTextType ) {
209
211
typ = orgType
210
212
}
211
- return c .typeToCodeWithPtr (typ , isPtr )
213
+ return c .typeToCodeWithPtr (typ , isPtr , false )
212
214
}
213
215
}
214
216
215
- func (c * Compiler ) typeToCodeWithPtr (typ * runtime.Type , isPtr bool ) (Code , error ) {
217
+ func (c * Compiler ) typeToCodeWithPtr (typ * runtime.Type , isPtr , isAnonymous bool ) (Code , error ) {
216
218
switch {
217
219
case c .implementsMarshalJSON (typ ):
218
220
return c .marshalJSONCode (typ )
@@ -221,7 +223,7 @@ func (c *Compiler) typeToCodeWithPtr(typ *runtime.Type, isPtr bool) (Code, error
221
223
}
222
224
switch typ .Kind () {
223
225
case reflect .Ptr :
224
- return c .ptrCode (typ )
226
+ return c .ptrCode (typ , isAnonymous )
225
227
case reflect .Slice :
226
228
elem := typ .Elem ()
227
229
if elem .Kind () == reflect .Uint8 {
@@ -236,7 +238,7 @@ func (c *Compiler) typeToCodeWithPtr(typ *runtime.Type, isPtr bool) (Code, error
236
238
case reflect .Map :
237
239
return c .mapCode (typ )
238
240
case reflect .Struct :
239
- return c .structCode (typ , isPtr )
241
+ return c .structCode (typ , isPtr , isAnonymous )
240
242
case reflect .Interface :
241
243
return c .interfaceCode (typ , false )
242
244
case reflect .Int :
@@ -424,8 +426,8 @@ func (c *Compiler) marshalTextCode(typ *runtime.Type) (*MarshalTextCode, error)
424
426
}, nil
425
427
}
426
428
427
- func (c * Compiler ) ptrCode (typ * runtime.Type ) (* PtrCode , error ) {
428
- code , err := c .typeToCodeWithPtr (typ .Elem (), true )
429
+ func (c * Compiler ) ptrCode (typ * runtime.Type , isAnonymous bool ) (* PtrCode , error ) {
430
+ code , err := c .typeToCodeWithPtr (typ .Elem (), true , isAnonymous )
429
431
if err != nil {
430
432
return nil , err
431
433
}
@@ -485,12 +487,12 @@ func (c *Compiler) listElemCode(typ *runtime.Type) (Code, error) {
485
487
case ! typ .Implements (marshalTextType ) && runtime .PtrTo (typ ).Implements (marshalTextType ):
486
488
return c .marshalTextCode (typ )
487
489
case typ .Kind () == reflect .Map :
488
- return c .ptrCode (runtime .PtrTo (typ ))
490
+ return c .ptrCode (runtime .PtrTo (typ ), false )
489
491
default :
490
492
// isPtr was originally used to indicate whether the type of top level is pointer.
491
493
// However, since the slice/array element is a specification that can get the pointer address, explicitly set isPtr to true.
492
494
// See here for related issues: https://github.com/goccy/go-json/issues/370
493
- code , err := c .typeToCodeWithPtr (typ , true )
495
+ code , err := c .typeToCodeWithPtr (typ , true , false )
494
496
if err != nil {
495
497
return nil , err
496
498
}
@@ -511,7 +513,7 @@ func (c *Compiler) mapKeyCode(typ *runtime.Type) (Code, error) {
511
513
}
512
514
switch typ .Kind () {
513
515
case reflect .Ptr :
514
- return c .ptrCode (typ )
516
+ return c .ptrCode (typ , false )
515
517
case reflect .String :
516
518
return c .stringCode (typ , false )
517
519
case reflect .Int :
@@ -543,9 +545,9 @@ func (c *Compiler) mapKeyCode(typ *runtime.Type) (Code, error) {
543
545
func (c * Compiler ) mapValueCode (typ * runtime.Type ) (Code , error ) {
544
546
switch typ .Kind () {
545
547
case reflect .Map :
546
- return c .ptrCode (runtime .PtrTo (typ ))
548
+ return c .ptrCode (runtime .PtrTo (typ ), false )
547
549
default :
548
- code , err := c .typeToCodeWithPtr (typ , false )
550
+ code , err := c .typeToCodeWithPtr (typ , false , false )
549
551
if err != nil {
550
552
return nil , err
551
553
}
@@ -559,16 +561,20 @@ func (c *Compiler) mapValueCode(typ *runtime.Type) (Code, error) {
559
561
}
560
562
}
561
563
562
- func (c * Compiler ) structCode (typ * runtime.Type , isPtr bool ) (* StructCode , error ) {
564
+ func (c * Compiler ) structCode (typ * runtime.Type , isPtr , isAnonymous bool ) (* StructCode , error ) {
563
565
typeptr := uintptr (unsafe .Pointer (typ ))
564
- if code , exists := c .structTypeToCode [typeptr ]; exists {
566
+ structTypeToCode := c .structTypeToCode
567
+ if isAnonymous {
568
+ structTypeToCode = c .anonymousStructTypeToCode
569
+ }
570
+ if code , exists := structTypeToCode [typeptr ]; exists {
565
571
derefCode := * code
566
572
derefCode .isRecursive = true
567
573
return & derefCode , nil
568
574
}
569
575
indirect := runtime .IfaceIndir (typ )
570
576
code := & StructCode {typ : typ , isPtr : isPtr , isIndirect : indirect }
571
- c . structTypeToCode [typeptr ] = code
577
+ structTypeToCode [typeptr ] = code
572
578
573
579
fieldNum := typ .NumField ()
574
580
tags := c .typeToStructTags (typ )
@@ -613,7 +619,7 @@ func (c *Compiler) structCode(typ *runtime.Type, isPtr bool) (*StructCode, error
613
619
if ! code .disableIndirectConversion && ! indirect && isPtr {
614
620
code .enableIndirect ()
615
621
}
616
- delete (c . structTypeToCode , typeptr )
622
+ delete (structTypeToCode , typeptr )
617
623
return code , nil
618
624
}
619
625
@@ -680,7 +686,7 @@ func (c *Compiler) structFieldCode(structCode *StructCode, tag *runtime.StructTa
680
686
fieldCode .isAddrForMarshaler = true
681
687
fieldCode .isNilCheck = false
682
688
default :
683
- code , err := c .typeToCodeWithPtr (fieldType , isPtr )
689
+ code , err := c .typeToCodeWithPtr (fieldType , isPtr , fieldCode . isAnonymous )
684
690
if err != nil {
685
691
return nil , err
686
692
}
0 commit comments