From 4f93be7f19aec37fe776aeebfb88a8c50679136d Mon Sep 17 00:00:00 2001 From: Marc Vertes Date: Mon, 16 Dec 2019 19:00:07 +0100 Subject: [PATCH] fix: emulate struct by interface{} only for recursive struct types --- _test/struct29.go | 19 +++++++++++++++++++ _test/struct30.go | 19 +++++++++++++++++++ interp/gta.go | 1 + interp/run.go | 2 +- interp/type.go | 4 +++- 5 files changed, 43 insertions(+), 2 deletions(-) create mode 100644 _test/struct29.go create mode 100644 _test/struct30.go diff --git a/_test/struct29.go b/_test/struct29.go new file mode 100644 index 00000000..75159e07 --- /dev/null +++ b/_test/struct29.go @@ -0,0 +1,19 @@ +package main + +type T1 struct { + A []T2 + B []T2 +} + +type T2 struct { + name string +} + +var t = T1{} + +func main() { + println("ok") +} + +// Output: +// ok diff --git a/_test/struct30.go b/_test/struct30.go new file mode 100644 index 00000000..e872ba9d --- /dev/null +++ b/_test/struct30.go @@ -0,0 +1,19 @@ +package main + +type T1 struct { + A []T2 + M map[uint64]T2 +} + +type T2 struct { + name string +} + +var t = T1{} + +func main() { + println("ok") +} + +// Output: +// ok diff --git a/interp/gta.go b/interp/gta.go index 6658f03a..b85e3cfe 100644 --- a/interp/gta.go +++ b/interp/gta.go @@ -30,6 +30,7 @@ func (interp *Interpreter) gta(root *node, rpath string) ([]*node, error) { case defineStmt: var atyp *itype if n.nleft+n.nright < len(n.child) { + // Type is declared explicitly in the assign expression. if atyp, err = nodeType(interp, sc, n.child[n.nleft]); err != nil { return false } diff --git a/interp/run.go b/interp/run.go index 843d2c4b..48c4eb25 100644 --- a/interp/run.go +++ b/interp/run.go @@ -239,7 +239,7 @@ func isRecursiveStruct(t *itype, rtype reflect.Type) bool { if t.cat == structT && rtype.Kind() == reflect.Interface { return true } - if t.cat == ptrT { + if t.cat == ptrT && t.rtype != nil { return isRecursiveStruct(t.val, t.rtype.Elem()) } return false diff --git a/interp/type.go b/interp/type.go index db5b20ec..74ada6ed 100644 --- a/interp/type.go +++ b/interp/type.go @@ -885,7 +885,9 @@ func (t *itype) refType(defined map[string]bool) reflect.Type { panic(err) } } - if t.val != nil && defined[t.val.name] { + if t.val != nil && defined[t.val.name] && !t.val.incomplete && t.val.rtype == nil { + // Replace reference to self (direct or indirect) by an interface{} to handle + // recursive types with reflect. t.val.rtype = interf } switch t.cat {