fix: emulate struct by interface{} only for recursive struct types

This commit is contained in:
Marc Vertes
2019-12-16 19:00:07 +01:00
committed by Traefiker Bot
parent 7a0c09f5eb
commit 4f93be7f19
5 changed files with 43 additions and 2 deletions

19
_test/struct29.go Normal file
View File

@@ -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

19
_test/struct30.go Normal file
View File

@@ -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

View File

@@ -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
}

View File

@@ -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

View File

@@ -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 {