mirror of https://github.com/goccy/go-json.git
Merge branch 'master' into feat-case-271
This commit is contained in:
commit
1e3fdb0e3d
29
CHANGELOG.md
29
CHANGELOG.md
|
@ -1,3 +1,32 @@
|
||||||
|
# v0.9.10 - 2022/07/15
|
||||||
|
|
||||||
|
### Fix bugs
|
||||||
|
|
||||||
|
* Fix boundary exception of type caching ( #382 )
|
||||||
|
|
||||||
|
# v0.9.9 - 2022/07/15
|
||||||
|
|
||||||
|
### Fix bugs
|
||||||
|
|
||||||
|
* Fix encoding of directed interface with typed nil ( #377 )
|
||||||
|
* Fix embedded primitive type encoding using alias ( #378 )
|
||||||
|
* Fix slice/array type encoding with types implementing MarshalJSON ( #379 )
|
||||||
|
* Fix unicode decoding when the expected buffer state is not met after reading ( #380 )
|
||||||
|
|
||||||
|
# v0.9.8 - 2022/06/30
|
||||||
|
|
||||||
|
### Fix bugs
|
||||||
|
|
||||||
|
* Fix decoding of surrogate-pair ( #365 )
|
||||||
|
* Fix handling of embedded primitive type ( #366 )
|
||||||
|
* Add validation of escape sequence for decoder ( #367 )
|
||||||
|
* Fix stream tokenizing respecting UseNumber ( #369 )
|
||||||
|
* Fix encoding when struct pointer type that implements Marshal JSON is embedded ( #375 )
|
||||||
|
|
||||||
|
### Improve performance
|
||||||
|
|
||||||
|
* Improve performance of linkRecursiveCode ( #368 )
|
||||||
|
|
||||||
# v0.9.7 - 2022/04/22
|
# v0.9.7 - 2022/04/22
|
||||||
|
|
||||||
### Fix bugs
|
### Fix bugs
|
||||||
|
|
|
@ -3968,3 +3968,20 @@ func TestIssue335(t *testing.T) {
|
||||||
t.Errorf("unexpected success")
|
t.Errorf("unexpected success")
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue372(t *testing.T) {
|
||||||
|
type A int
|
||||||
|
type T struct {
|
||||||
|
_ int
|
||||||
|
*A
|
||||||
|
}
|
||||||
|
var v T
|
||||||
|
err := json.Unmarshal([]byte(`{"A":7}`), &v)
|
||||||
|
assertErr(t, err)
|
||||||
|
|
||||||
|
got := *v.A
|
||||||
|
expected := A(7)
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("unexpected result: %v != %v", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
201
encode_test.go
201
encode_test.go
|
@ -7,11 +7,14 @@ import (
|
||||||
stdjson "encoding/json"
|
stdjson "encoding/json"
|
||||||
"errors"
|
"errors"
|
||||||
"fmt"
|
"fmt"
|
||||||
|
"io"
|
||||||
"log"
|
"log"
|
||||||
"math"
|
"math"
|
||||||
|
"math/big"
|
||||||
"reflect"
|
"reflect"
|
||||||
"regexp"
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
|
||||||
|
@ -2412,5 +2415,203 @@ func TestCamelCaseField(t *testing.T) {
|
||||||
|
|
||||||
if !bytes.Equal(expected, got) {
|
if !bytes.Equal(expected, got) {
|
||||||
t.Fatalf("failed to encode. expected %q but got %q", expected, got)
|
t.Fatalf("failed to encode. expected %q but got %q", expected, got)
|
||||||
|
|
||||||
|
func TestIssue339(t *testing.T) {
|
||||||
|
type T1 struct {
|
||||||
|
*big.Int
|
||||||
|
}
|
||||||
|
type T2 struct {
|
||||||
|
T1 T1 `json:"T1"`
|
||||||
|
}
|
||||||
|
v := T2{T1{Int: big.NewInt(10000)}}
|
||||||
|
b, err := json.Marshal(&v)
|
||||||
|
assertErr(t, err)
|
||||||
|
got := string(b)
|
||||||
|
expected := `{"T1":10000}`
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("unexpected result: %v != %v", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssue376(t *testing.T) {
|
||||||
|
type Container struct {
|
||||||
|
V interface{} `json:"value"`
|
||||||
|
}
|
||||||
|
type MapOnly struct {
|
||||||
|
Map map[string]int64 `json:"map"`
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(Container{MapOnly{}})
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := string(b)
|
||||||
|
expected := `{"value":{"map":null}}`
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("unexpected result: %v != %v", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
type Issue370 struct {
|
||||||
|
String string
|
||||||
|
Valid bool
|
||||||
|
}
|
||||||
|
|
||||||
|
func (i *Issue370) MarshalJSON() ([]byte, error) {
|
||||||
|
if !i.Valid {
|
||||||
|
return json.Marshal(nil)
|
||||||
|
}
|
||||||
|
return json.Marshal(i.String)
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssue370(t *testing.T) {
|
||||||
|
v := []struct {
|
||||||
|
V Issue370
|
||||||
|
}{
|
||||||
|
{V: Issue370{String: "test", Valid: true}},
|
||||||
|
}
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := string(b)
|
||||||
|
expected := `[{"V":"test"}]`
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("unexpected result: %v != %v", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssue374(t *testing.T) {
|
||||||
|
r := io.MultiReader(strings.NewReader(strings.Repeat(" ", 505)+`"\u`), strings.NewReader(`0000"`))
|
||||||
|
var v interface{}
|
||||||
|
if err := json.NewDecoder(r).Decode(&v); err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
got := v.(string)
|
||||||
|
expected := "\u0000"
|
||||||
|
if got != expected {
|
||||||
|
t.Errorf("unexpected result: %q != %q", got, expected)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
func TestIssue381(t *testing.T) {
|
||||||
|
var v struct {
|
||||||
|
Field0 bool
|
||||||
|
Field1 bool
|
||||||
|
Field2 bool
|
||||||
|
Field3 bool
|
||||||
|
Field4 bool
|
||||||
|
Field5 bool
|
||||||
|
Field6 bool
|
||||||
|
Field7 bool
|
||||||
|
Field8 bool
|
||||||
|
Field9 bool
|
||||||
|
Field10 bool
|
||||||
|
Field11 bool
|
||||||
|
Field12 bool
|
||||||
|
Field13 bool
|
||||||
|
Field14 bool
|
||||||
|
Field15 bool
|
||||||
|
Field16 bool
|
||||||
|
Field17 bool
|
||||||
|
Field18 bool
|
||||||
|
Field19 bool
|
||||||
|
Field20 bool
|
||||||
|
Field21 bool
|
||||||
|
Field22 bool
|
||||||
|
Field23 bool
|
||||||
|
Field24 bool
|
||||||
|
Field25 bool
|
||||||
|
Field26 bool
|
||||||
|
Field27 bool
|
||||||
|
Field28 bool
|
||||||
|
Field29 bool
|
||||||
|
Field30 bool
|
||||||
|
Field31 bool
|
||||||
|
Field32 bool
|
||||||
|
Field33 bool
|
||||||
|
Field34 bool
|
||||||
|
Field35 bool
|
||||||
|
Field36 bool
|
||||||
|
Field37 bool
|
||||||
|
Field38 bool
|
||||||
|
Field39 bool
|
||||||
|
Field40 bool
|
||||||
|
Field41 bool
|
||||||
|
Field42 bool
|
||||||
|
Field43 bool
|
||||||
|
Field44 bool
|
||||||
|
Field45 bool
|
||||||
|
Field46 bool
|
||||||
|
Field47 bool
|
||||||
|
Field48 bool
|
||||||
|
Field49 bool
|
||||||
|
Field50 bool
|
||||||
|
Field51 bool
|
||||||
|
Field52 bool
|
||||||
|
Field53 bool
|
||||||
|
Field54 bool
|
||||||
|
Field55 bool
|
||||||
|
Field56 bool
|
||||||
|
Field57 bool
|
||||||
|
Field58 bool
|
||||||
|
Field59 bool
|
||||||
|
Field60 bool
|
||||||
|
Field61 bool
|
||||||
|
Field62 bool
|
||||||
|
Field63 bool
|
||||||
|
Field64 bool
|
||||||
|
Field65 bool
|
||||||
|
Field66 bool
|
||||||
|
Field67 bool
|
||||||
|
Field68 bool
|
||||||
|
Field69 bool
|
||||||
|
Field70 bool
|
||||||
|
Field71 bool
|
||||||
|
Field72 bool
|
||||||
|
Field73 bool
|
||||||
|
Field74 bool
|
||||||
|
Field75 bool
|
||||||
|
Field76 bool
|
||||||
|
Field77 bool
|
||||||
|
Field78 bool
|
||||||
|
Field79 bool
|
||||||
|
Field80 bool
|
||||||
|
Field81 bool
|
||||||
|
Field82 bool
|
||||||
|
Field83 bool
|
||||||
|
Field84 bool
|
||||||
|
Field85 bool
|
||||||
|
Field86 bool
|
||||||
|
Field87 bool
|
||||||
|
Field88 bool
|
||||||
|
Field89 bool
|
||||||
|
Field90 bool
|
||||||
|
Field91 bool
|
||||||
|
Field92 bool
|
||||||
|
Field93 bool
|
||||||
|
Field94 bool
|
||||||
|
Field95 bool
|
||||||
|
Field96 bool
|
||||||
|
Field97 bool
|
||||||
|
Field98 bool
|
||||||
|
Field99 bool
|
||||||
|
}
|
||||||
|
|
||||||
|
// test encoder cache issue, not related to encoder
|
||||||
|
b, err := json.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to marshal %s", err.Error())
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
std, err := stdjson.Marshal(v)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("failed to marshal with encoding/json %s", err.Error())
|
||||||
|
t.FailNow()
|
||||||
|
}
|
||||||
|
|
||||||
|
if !bytes.Equal(std, b) {
|
||||||
|
t.Errorf("encoding result not equal to encoding/json")
|
||||||
|
t.FailNow()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -3,6 +3,7 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -194,9 +195,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
||||||
typ = iface.typ
|
typ = iface.typ
|
||||||
}
|
}
|
||||||
if ifacePtr == nil {
|
if ifacePtr == nil {
|
||||||
b = appendNullComma(ctx, b)
|
isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ)
|
||||||
code = code.Next
|
if !isDirectedNil {
|
||||||
break
|
b = appendNullComma(ctx, b)
|
||||||
|
code = code.Next
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
||||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
||||||
|
|
|
@ -24,7 +24,7 @@ func init() {
|
||||||
if typeAddr == nil {
|
if typeAddr == nil {
|
||||||
typeAddr = &runtime.TypeAddr{}
|
typeAddr = &runtime.TypeAddr{}
|
||||||
}
|
}
|
||||||
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift)
|
cachedDecoder = make([]Decoder, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadDecoderMap() map[uintptr]Decoder {
|
func loadDecoderMap() map[uintptr]Decoder {
|
||||||
|
@ -393,6 +393,15 @@ func compileStruct(typ *runtime.Type, structName, fieldName string, structTypeTo
|
||||||
}
|
}
|
||||||
allFields = append(allFields, fieldSet)
|
allFields = append(allFields, fieldSet)
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
fieldSet := &structFieldSet{
|
||||||
|
dec: pdec,
|
||||||
|
offset: field.Offset,
|
||||||
|
isTaggedKey: tag.IsTaggedKey,
|
||||||
|
key: field.Name,
|
||||||
|
keyLen: int64(len(field.Name)),
|
||||||
|
}
|
||||||
|
allFields = append(allFields, fieldSet)
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
fieldSet := &structFieldSet{
|
fieldSet := &structFieldSet{
|
||||||
|
|
|
@ -95,24 +95,30 @@ func unicodeToRune(code []byte) rune {
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func readAtLeast(s *Stream, n int64, p *unsafe.Pointer) bool {
|
||||||
|
for s.cursor+n >= s.length {
|
||||||
|
if !s.read() {
|
||||||
|
return false
|
||||||
|
}
|
||||||
|
*p = s.bufptr()
|
||||||
|
}
|
||||||
|
return true
|
||||||
|
}
|
||||||
|
|
||||||
func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) {
|
func decodeUnicodeRune(s *Stream, p unsafe.Pointer) (rune, int64, unsafe.Pointer, error) {
|
||||||
const defaultOffset = 5
|
const defaultOffset = 5
|
||||||
const surrogateOffset = 11
|
const surrogateOffset = 11
|
||||||
|
|
||||||
if s.cursor+defaultOffset >= s.length {
|
if !readAtLeast(s, defaultOffset, &p) {
|
||||||
if !s.read() {
|
return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
|
||||||
return rune(0), 0, nil, errors.ErrInvalidCharacter(s.char(), "escaped string", s.totalOffset())
|
|
||||||
}
|
|
||||||
p = s.bufptr()
|
|
||||||
}
|
}
|
||||||
|
|
||||||
r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset])
|
r := unicodeToRune(s.buf[s.cursor+1 : s.cursor+defaultOffset])
|
||||||
if utf16.IsSurrogate(r) {
|
if utf16.IsSurrogate(r) {
|
||||||
if s.cursor+surrogateOffset >= s.length {
|
if !readAtLeast(s, surrogateOffset, &p) {
|
||||||
s.read()
|
return unicode.ReplacementChar, defaultOffset, p, nil
|
||||||
p = s.bufptr()
|
|
||||||
}
|
}
|
||||||
if s.cursor+surrogateOffset >= s.length || s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
|
if s.buf[s.cursor+defaultOffset] != '\\' || s.buf[s.cursor+defaultOffset+1] != 'u' {
|
||||||
return unicode.ReplacementChar, defaultOffset, p, nil
|
return unicode.ReplacementChar, defaultOffset, p, nil
|
||||||
}
|
}
|
||||||
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
|
r2 := unicodeToRune(s.buf[s.cursor+defaultOffset+2 : s.cursor+surrogateOffset])
|
||||||
|
|
|
@ -31,7 +31,7 @@ func init() {
|
||||||
if typeAddr == nil {
|
if typeAddr == nil {
|
||||||
typeAddr = &runtime.TypeAddr{}
|
typeAddr = &runtime.TypeAddr{}
|
||||||
}
|
}
|
||||||
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift)
|
cachedOpcodeSets = make([]*OpcodeSet, typeAddr.AddrRange>>typeAddr.AddrShift+1)
|
||||||
}
|
}
|
||||||
|
|
||||||
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
func loadOpcodeMap() map[uintptr]*OpcodeSet {
|
||||||
|
@ -487,7 +487,10 @@ func (c *Compiler) listElemCode(typ *runtime.Type) (Code, error) {
|
||||||
case typ.Kind() == reflect.Map:
|
case typ.Kind() == reflect.Map:
|
||||||
return c.ptrCode(runtime.PtrTo(typ))
|
return c.ptrCode(runtime.PtrTo(typ))
|
||||||
default:
|
default:
|
||||||
code, err := c.typeToCodeWithPtr(typ, false)
|
// isPtr was originally used to indicate whether the type of top level is pointer.
|
||||||
|
// However, since the slice/array element is a specification that can get the pointer address, explicitly set isPtr to true.
|
||||||
|
// See here for related issues: https://github.com/goccy/go-json/issues/370
|
||||||
|
code, err := c.typeToCodeWithPtr(typ, true)
|
||||||
if err != nil {
|
if err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
}
|
}
|
||||||
|
@ -853,6 +856,9 @@ func (c *Compiler) implementsMarshalText(typ *runtime.Type) bool {
|
||||||
}
|
}
|
||||||
|
|
||||||
func (c *Compiler) isNilableType(typ *runtime.Type) bool {
|
func (c *Compiler) isNilableType(typ *runtime.Type) bool {
|
||||||
|
if !runtime.IfaceIndir(typ) {
|
||||||
|
return true
|
||||||
|
}
|
||||||
switch typ.Kind() {
|
switch typ.Kind() {
|
||||||
case reflect.Ptr:
|
case reflect.Ptr:
|
||||||
return true
|
return true
|
||||||
|
|
|
@ -3,6 +3,7 @@ package vm
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -194,9 +195,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
||||||
typ = iface.typ
|
typ = iface.typ
|
||||||
}
|
}
|
||||||
if ifacePtr == nil {
|
if ifacePtr == nil {
|
||||||
b = appendNullComma(ctx, b)
|
isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ)
|
||||||
code = code.Next
|
if !isDirectedNil {
|
||||||
break
|
b = appendNullComma(ctx, b)
|
||||||
|
code = code.Next
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
||||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
||||||
|
|
|
@ -3,6 +3,7 @@ package vm_color
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -194,9 +195,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
||||||
typ = iface.typ
|
typ = iface.typ
|
||||||
}
|
}
|
||||||
if ifacePtr == nil {
|
if ifacePtr == nil {
|
||||||
b = appendNullComma(ctx, b)
|
isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ)
|
||||||
code = code.Next
|
if !isDirectedNil {
|
||||||
break
|
b = appendNullComma(ctx, b)
|
||||||
|
code = code.Next
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
||||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
||||||
|
|
|
@ -3,6 +3,7 @@ package vm_color_indent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -194,9 +195,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
||||||
typ = iface.typ
|
typ = iface.typ
|
||||||
}
|
}
|
||||||
if ifacePtr == nil {
|
if ifacePtr == nil {
|
||||||
b = appendNullComma(ctx, b)
|
isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ)
|
||||||
code = code.Next
|
if !isDirectedNil {
|
||||||
break
|
b = appendNullComma(ctx, b)
|
||||||
|
code = code.Next
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
||||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
||||||
|
|
|
@ -3,6 +3,7 @@ package vm_indent
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"math"
|
"math"
|
||||||
|
"reflect"
|
||||||
"sort"
|
"sort"
|
||||||
"unsafe"
|
"unsafe"
|
||||||
|
|
||||||
|
@ -194,9 +195,12 @@ func Run(ctx *encoder.RuntimeContext, b []byte, codeSet *encoder.OpcodeSet) ([]b
|
||||||
typ = iface.typ
|
typ = iface.typ
|
||||||
}
|
}
|
||||||
if ifacePtr == nil {
|
if ifacePtr == nil {
|
||||||
b = appendNullComma(ctx, b)
|
isDirectedNil := typ != nil && typ.Kind() == reflect.Struct && !runtime.IfaceIndir(typ)
|
||||||
code = code.Next
|
if !isDirectedNil {
|
||||||
break
|
b = appendNullComma(ctx, b)
|
||||||
|
code = code.Next
|
||||||
|
break
|
||||||
|
}
|
||||||
}
|
}
|
||||||
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
ctx.KeepRefs = append(ctx.KeepRefs, up)
|
||||||
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
ifaceCodeSet, err := encoder.CompileToGetCodeSet(ctx, uintptr(unsafe.Pointer(typ)))
|
||||||
|
|
Loading…
Reference in New Issue