From 2bda5ef91f35b1bfdbd3744cd011c3d129903a9a Mon Sep 17 00:00:00 2001 From: Masaaki Goshima Date: Mon, 22 Mar 2021 21:29:16 +0900 Subject: [PATCH] Fix encoding of MarshalJSON of function type --- cover_marshal_json_test.go | 67 ++++++++++++++++++------ internal/encoder/compiler.go | 9 ++-- internal/encoder/encoder.go | 2 +- internal/encoder/opcode.go | 2 + internal/encoder/vm/vm.go | 25 +++++---- internal/encoder/vm_escaped/vm.go | 25 +++++---- internal/encoder/vm_escaped_indent/vm.go | 25 +++++---- internal/encoder/vm_indent/vm.go | 25 +++++---- 8 files changed, 108 insertions(+), 72 deletions(-) diff --git a/cover_marshal_json_test.go b/cover_marshal_json_test.go index 6061e23..6931bf3 100644 --- a/cover_marshal_json_test.go +++ b/cover_marshal_json_test.go @@ -39,6 +39,16 @@ func (c *coverPtrMarshalJSONString) MarshalJSON() ([]byte, error) { return []byte(c.C), nil } +type coverFuncMarshalJSON func() + +func (f coverFuncMarshalJSON) MarshalJSON() ([]byte, error) { + if f == nil { + return []byte(`null`), nil + } + f() + return []byte(`"func"`), nil +} + func TestCoverMarshalJSON(t *testing.T) { type structMarshalJSON struct { A coverMarshalJSON `json:"a"` @@ -82,6 +92,31 @@ func TestCoverMarshalJSON(t *testing.T) { name string data interface{} }{ + { + name: "FuncMarshalJSON", + data: coverFuncMarshalJSON(func() {}), + }, + { + name: "StructFuncMarshalJSON", + data: struct { + A coverFuncMarshalJSON + }{A: func() {}}, + }, + { + name: "StructFuncMarshalJSONMultiFields", + data: struct { + A coverFuncMarshalJSON + B coverFuncMarshalJSON + }{A: func() {}, B: func() {}}, + }, + { + name: "PtrStructFuncMarshalJSONMultiFields", + data: &struct { + A coverFuncMarshalJSON + B coverFuncMarshalJSON + C coverFuncMarshalJSON + }{A: func() {}, B: nil, C: func() {}}, + }, { name: "MarshalJSON", data: coverMarshalJSON{A: 1}, @@ -3652,22 +3687,24 @@ func TestCoverMarshalJSON(t *testing.T) { }, } for _, test := range tests { - for _, indent := range []bool{true, false} { - for _, htmlEscape := range []bool{true, false} { - var buf bytes.Buffer - enc := json.NewEncoder(&buf) - enc.SetEscapeHTML(htmlEscape) - if indent { - enc.SetIndent("", " ") - } - if err := enc.Encode(test.data); err != nil { - t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err) - } - stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape) - if buf.String() != stdresult { - t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String()) + t.Run(test.name, func(t *testing.T) { + for _, indent := range []bool{true, false} { + for _, htmlEscape := range []bool{true, false} { + var buf bytes.Buffer + enc := json.NewEncoder(&buf) + enc.SetEscapeHTML(htmlEscape) + if indent { + enc.SetIndent("", " ") + } + if err := enc.Encode(test.data); err != nil { + t.Fatalf("%s(htmlEscape:%v,indent:%v): %+v: %s", test.name, htmlEscape, indent, test.data, err) + } + stdresult := encodeByEncodingJSON(test.data, indent, htmlEscape) + if buf.String() != stdresult { + t.Errorf("%s(htmlEscape:%v,indent:%v): doesn't compatible with encoding/json. expected %q but got %q", test.name, htmlEscape, indent, stdresult, buf.String()) + } } } - } + }) } } diff --git a/internal/encoder/compiler.go b/internal/encoder/compiler.go index 9d2d452..aada822 100644 --- a/internal/encoder/compiler.go +++ b/internal/encoder/compiler.go @@ -506,6 +506,7 @@ func compileMarshalJSON(ctx *compileContext) (*Opcode, error) { if !typ.Implements(marshalJSONType) && runtime.PtrTo(typ).Implements(marshalJSONType) { code.AddrForMarshaler = true } + code.IsNilableType = isNilableType(typ) ctx.incIndex() return code, nil } @@ -516,6 +517,7 @@ func compileMarshalText(ctx *compileContext) (*Opcode, error) { if !typ.Implements(marshalTextType) && runtime.PtrTo(typ).Implements(marshalTextType) { code.AddrForMarshaler = true } + code.IsNilableType = isNilableType(typ) ctx.incIndex() return code, nil } @@ -1274,12 +1276,10 @@ func isNilableType(typ *runtime.Type) bool { switch typ.Kind() { case reflect.Ptr: return true - case reflect.Interface: - return true - case reflect.Slice: - return true case reflect.Map: return true + case reflect.Func: + return true default: return false } @@ -1418,6 +1418,7 @@ func compileStruct(ctx *compileContext, isPtr bool) (*Opcode, error) { Nilcheck: nilcheck, AddrForMarshaler: addrForMarshaler, IsNextOpPtrType: strings.Contains(valueCode.Op.String(), "Ptr"), + IsNilableType: isNilableType, } if fieldIdx == 0 { fieldCode.HeadIdx = fieldCode.Idx diff --git a/internal/encoder/encoder.go b/internal/encoder/encoder.go index 3c6db04..0e348cf 100644 --- a/internal/encoder/encoder.go +++ b/internal/encoder/encoder.go @@ -559,7 +559,7 @@ func AppendIndent(ctx *RuntimeContext, b []byte, indent int) []byte { func IsNilForMarshaler(v interface{}) bool { rv := reflect.ValueOf(v) switch rv.Kind() { - case reflect.Interface, reflect.Map, reflect.Ptr: + case reflect.Interface, reflect.Map, reflect.Ptr, reflect.Func: return rv.IsNil() case reflect.Slice: return rv.IsNil() || rv.Len() == 0 diff --git a/internal/encoder/opcode.go b/internal/encoder/opcode.go index 943f8b3..74f322d 100644 --- a/internal/encoder/opcode.go +++ b/internal/encoder/opcode.go @@ -26,6 +26,7 @@ type Opcode struct { Nilcheck bool // whether needs to nilcheck or not AddrForMarshaler bool // whether needs to addr for marshaler or not IsNextOpPtrType bool // whether next operation is ptr type or not + IsNilableType bool // whether type is nilable or not RshiftNum uint8 // use to take bit for judging whether negative integer or not Mask uint64 // mask for number Indent int // indent number @@ -242,6 +243,7 @@ func (c *Opcode) copy(codeMap map[uintptr]*Opcode) *Opcode { Nilcheck: c.Nilcheck, AddrForMarshaler: c.AddrForMarshaler, IsNextOpPtrType: c.IsNextOpPtrType, + IsNilableType: c.IsNilableType, Indent: c.Indent, Idx: c.Idx, HeadIdx: c.HeadIdx, diff --git a/internal/encoder/vm/vm.go b/internal/encoder/vm/vm.go index 70a3a65..1a06747 100644 --- a/internal/encoder/vm/vm.go +++ b/internal/encoder/vm/vm.go @@ -3,7 +3,6 @@ package vm import ( "fmt" "math" - "reflect" "sort" "unsafe" @@ -271,7 +270,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), false) @@ -298,7 +297,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) @@ -2711,7 +2710,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.Key...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2755,7 +2754,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.Key...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2798,7 +2797,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2924,7 +2923,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.Key...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { p = ptrToPtr(p + code.Offset) } @@ -2968,7 +2967,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.Key...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3011,7 +3010,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3623,7 +3622,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) b = append(b, code.Key...) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3640,7 +3639,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalJSON: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3685,7 +3684,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) b = append(b, code.Key...) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3702,7 +3701,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalText: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { diff --git a/internal/encoder/vm_escaped/vm.go b/internal/encoder/vm_escaped/vm.go index 3e8c775..eba9529 100644 --- a/internal/encoder/vm_escaped/vm.go +++ b/internal/encoder/vm_escaped/vm.go @@ -3,7 +3,6 @@ package vm_escaped import ( "fmt" "math" - "reflect" "sort" "unsafe" @@ -271,7 +270,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalJSON(code, b, ptrToInterface(code, p), true) @@ -298,7 +297,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) @@ -2711,7 +2710,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.EscapedKey...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2755,7 +2754,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.EscapedKey...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2798,7 +2797,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2924,7 +2923,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.EscapedKey...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { p = ptrToPtr(p + code.Offset) } @@ -2968,7 +2967,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, '{') } b = append(b, code.EscapedKey...) - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3011,7 +3010,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3623,7 +3622,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) b = append(b, code.EscapedKey...) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3640,7 +3639,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalJSON: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3685,7 +3684,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt p := load(ctxptr, code.HeadIdx) b = append(b, code.EscapedKey...) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3702,7 +3701,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalText: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { diff --git a/internal/encoder/vm_escaped_indent/vm.go b/internal/encoder/vm_escaped_indent/vm.go index 2b2b14c..e512e93 100644 --- a/internal/encoder/vm_escaped_indent/vm.go +++ b/internal/encoder/vm_escaped_indent/vm.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "math" - "reflect" "sort" "unsafe" @@ -269,7 +268,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, true) @@ -296,7 +295,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalText(code, b, ptrToInterface(code, p), true) @@ -2844,7 +2843,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.EscapedKey...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2890,7 +2889,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.EscapedKey...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2933,7 +2932,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{', '\n') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -3067,7 +3066,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.EscapedKey...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3113,7 +3112,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.EscapedKey...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3156,7 +3155,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{', '\n') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3870,7 +3869,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, ' ') p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3887,7 +3886,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalJSON: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3940,7 +3939,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, code.EscapedKey...) b = append(b, ' ') p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3957,7 +3956,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalText: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { diff --git a/internal/encoder/vm_indent/vm.go b/internal/encoder/vm_indent/vm.go index 62974af..57d9dab 100644 --- a/internal/encoder/vm_indent/vm.go +++ b/internal/encoder/vm_indent/vm.go @@ -4,7 +4,6 @@ import ( "bytes" "fmt" "math" - "reflect" "sort" "unsafe" @@ -275,7 +274,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalJSON(ctx, code, b, ptrToInterface(code, p), code.Indent, false) @@ -302,7 +301,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt code = code.Next break } - if code.Type.Kind() == reflect.Ptr && code.Indirect { + if code.IsNilableType && code.Indirect { p = ptrToPtr(p) } bb, err := appendMarshalText(code, b, ptrToInterface(code, p), false) @@ -2850,7 +2849,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.Key...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2896,7 +2895,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.Key...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -2939,7 +2938,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{', '\n') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalJSON { p = ptrToPtr(p + code.Offset) } @@ -3073,7 +3072,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.Key...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3119,7 +3118,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = appendIndent(ctx, b, code.Indent+1) b = append(b, code.Key...) b = append(b, ' ') - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadStringTagMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3162,7 +3161,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt if !code.AnonymousHead { b = append(b, '{', '\n') } - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { if code.Indirect || code.Op == encoder.OpStructPtrHeadOmitEmptyMarshalText { p = ptrToPtr(p + code.Offset) } @@ -3876,7 +3875,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, ' ') p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3893,7 +3892,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalJSON: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3946,7 +3945,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt b = append(b, code.Key...) b = append(b, ' ') p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck { @@ -3963,7 +3962,7 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet, opt case encoder.OpStructFieldOmitEmptyMarshalText: p := load(ctxptr, code.HeadIdx) p += code.Offset - if code.Type.Kind() == reflect.Ptr { + if code.IsNilableType { p = ptrToPtr(p) } if p == 0 && code.Nilcheck {