fix: avoid infinite recursion in genFunctionWrapper()
This commit is contained in:
16
_test/struct34.go
Normal file
16
_test/struct34.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
f func(*T)
|
||||||
|
}
|
||||||
|
|
||||||
|
func f1(t *T) { t.f = f2 }
|
||||||
|
|
||||||
|
func f2(t *T) { t.f = f1 }
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
println("ok")
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// ok
|
||||||
16
_test/struct35.go
Normal file
16
_test/struct35.go
Normal file
@@ -0,0 +1,16 @@
|
|||||||
|
package main
|
||||||
|
|
||||||
|
type T struct {
|
||||||
|
f func(*T)
|
||||||
|
}
|
||||||
|
|
||||||
|
func f1(t *T) { t.f = f1 }
|
||||||
|
|
||||||
|
func main() {
|
||||||
|
t := &T{}
|
||||||
|
f1(t)
|
||||||
|
println(t.f != nil)
|
||||||
|
}
|
||||||
|
|
||||||
|
// Output:
|
||||||
|
// true
|
||||||
@@ -482,7 +482,6 @@ func genFunctionWrapper(n *node) func(*frame) reflect.Value {
|
|||||||
if def, ok = n.val.(*node); !ok {
|
if def, ok = n.val.(*node); !ok {
|
||||||
return genValueAsFunctionWrapper(n)
|
return genValueAsFunctionWrapper(n)
|
||||||
}
|
}
|
||||||
setExec(def.child[3].start)
|
|
||||||
start := def.child[3].start
|
start := def.child[3].start
|
||||||
numRet := len(def.typ.ret)
|
numRet := len(def.typ.ret)
|
||||||
var rcvr func(*frame) reflect.Value
|
var rcvr func(*frame) reflect.Value
|
||||||
|
|||||||
@@ -111,6 +111,7 @@ type itype struct {
|
|||||||
size int // Size of array if ArrayT
|
size int // Size of array if ArrayT
|
||||||
rtype reflect.Type // Reflection type if ValueT, or nil
|
rtype reflect.Type // Reflection type if ValueT, or nil
|
||||||
incomplete bool // true if type must be parsed again (out of order declarations)
|
incomplete bool // true if type must be parsed again (out of order declarations)
|
||||||
|
recursive bool // true if the type has an element which refer to itself
|
||||||
untyped bool // true for a literal value (string or number)
|
untyped bool // true for a literal value (string or number)
|
||||||
sizedef bool // true if array size is computed from type definition
|
sizedef bool // true if array size is computed from type definition
|
||||||
isBinMethod bool // true if the type refers to a bin method function
|
isBinMethod bool // true if the type refers to a bin method function
|
||||||
@@ -902,7 +903,7 @@ func exportName(s string) string {
|
|||||||
|
|
||||||
var interf = reflect.TypeOf(new(interface{})).Elem()
|
var interf = reflect.TypeOf(new(interface{})).Elem()
|
||||||
|
|
||||||
func (t *itype) refType(defined map[string]bool) reflect.Type {
|
func (t *itype) refType(defined map[string]*itype, wrapRecursive bool) reflect.Type {
|
||||||
if t.rtype != nil {
|
if t.rtype != nil {
|
||||||
return t.rtype
|
return t.rtype
|
||||||
}
|
}
|
||||||
@@ -913,50 +914,56 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
|||||||
panic(err)
|
panic(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if t.val != nil && defined[t.val.name] && !t.val.incomplete && t.val.rtype == nil {
|
if t.val != nil && defined[t.val.name] != nil && !t.val.incomplete && t.val.rtype == nil {
|
||||||
// Replace reference to self (direct or indirect) by an interface{} to handle
|
// Replace reference to self (direct or indirect) by an interface{} to handle
|
||||||
// recursive types with reflect.
|
// recursive types with reflect.
|
||||||
t.val.rtype = interf
|
t.val.rtype = interf
|
||||||
|
defined[t.val.name].recursive = true
|
||||||
}
|
}
|
||||||
switch t.cat {
|
switch t.cat {
|
||||||
case aliasT:
|
case aliasT:
|
||||||
t.rtype = t.val.refType(defined)
|
t.rtype = t.val.refType(defined, wrapRecursive)
|
||||||
case arrayT, variadicT:
|
case arrayT, variadicT:
|
||||||
if t.sizedef {
|
if t.sizedef {
|
||||||
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined))
|
t.rtype = reflect.ArrayOf(t.size, t.val.refType(defined, wrapRecursive))
|
||||||
} else {
|
} else {
|
||||||
t.rtype = reflect.SliceOf(t.val.refType(defined))
|
t.rtype = reflect.SliceOf(t.val.refType(defined, wrapRecursive))
|
||||||
}
|
}
|
||||||
case chanT:
|
case chanT:
|
||||||
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.refType(defined))
|
t.rtype = reflect.ChanOf(reflect.BothDir, t.val.refType(defined, wrapRecursive))
|
||||||
case errorT:
|
case errorT:
|
||||||
t.rtype = reflect.TypeOf(new(error)).Elem()
|
t.rtype = reflect.TypeOf(new(error)).Elem()
|
||||||
case funcT:
|
case funcT:
|
||||||
in := make([]reflect.Type, len(t.arg))
|
in := make([]reflect.Type, len(t.arg))
|
||||||
out := make([]reflect.Type, len(t.ret))
|
out := make([]reflect.Type, len(t.ret))
|
||||||
|
//wrap := false
|
||||||
for i, v := range t.arg {
|
for i, v := range t.arg {
|
||||||
in[i] = v.refType(defined)
|
in[i] = v.refType(defined, true)
|
||||||
}
|
}
|
||||||
for i, v := range t.ret {
|
for i, v := range t.ret {
|
||||||
out[i] = v.refType(defined)
|
out[i] = v.refType(defined, true)
|
||||||
}
|
}
|
||||||
t.rtype = reflect.FuncOf(in, out, false)
|
t.rtype = reflect.FuncOf(in, out, false)
|
||||||
case interfaceT:
|
case interfaceT:
|
||||||
t.rtype = interf
|
t.rtype = interf
|
||||||
case mapT:
|
case mapT:
|
||||||
t.rtype = reflect.MapOf(t.key.refType(defined), t.val.refType(defined))
|
t.rtype = reflect.MapOf(t.key.refType(defined, wrapRecursive), t.val.refType(defined, wrapRecursive))
|
||||||
case ptrT:
|
case ptrT:
|
||||||
t.rtype = reflect.PtrTo(t.val.refType(defined))
|
t.rtype = reflect.PtrTo(t.val.refType(defined, wrapRecursive))
|
||||||
case structT:
|
case structT:
|
||||||
if t.name != "" {
|
if t.name != "" {
|
||||||
defined[t.name] = true
|
defined[t.name] = t
|
||||||
}
|
}
|
||||||
var fields []reflect.StructField
|
var fields []reflect.StructField
|
||||||
for _, f := range t.field {
|
for _, f := range t.field {
|
||||||
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.refType(defined), Tag: reflect.StructTag(f.tag)}
|
field := reflect.StructField{Name: exportName(f.name), Type: f.typ.refType(defined, wrapRecursive), Tag: reflect.StructTag(f.tag)}
|
||||||
fields = append(fields, field)
|
fields = append(fields, field)
|
||||||
}
|
}
|
||||||
t.rtype = reflect.StructOf(fields)
|
if t.recursive && wrapRecursive {
|
||||||
|
t.rtype = interf
|
||||||
|
} else {
|
||||||
|
t.rtype = reflect.StructOf(fields)
|
||||||
|
}
|
||||||
default:
|
default:
|
||||||
if z, _ := t.zero(); z.IsValid() {
|
if z, _ := t.zero(); z.IsValid() {
|
||||||
t.rtype = z.Type()
|
t.rtype = z.Type()
|
||||||
@@ -967,7 +974,7 @@ func (t *itype) refType(defined map[string]bool) reflect.Type {
|
|||||||
|
|
||||||
// TypeOf returns the reflection type of dynamic interpreter type t.
|
// TypeOf returns the reflection type of dynamic interpreter type t.
|
||||||
func (t *itype) TypeOf() reflect.Type {
|
func (t *itype) TypeOf() reflect.Type {
|
||||||
return t.refType(map[string]bool{})
|
return t.refType(map[string]*itype{}, false)
|
||||||
}
|
}
|
||||||
|
|
||||||
func (t *itype) frameType() (r reflect.Type) {
|
func (t *itype) frameType() (r reflect.Type) {
|
||||||
|
|||||||
Reference in New Issue
Block a user