interp: handle recursive and incomplete seen types in nodeType

This comes from experiments looking into #1259 where incomplete twice seen types are marked as complete. To mitigate the problem instead of a map of seen types in `nodeType` a slice is used as a cheap way to keep track of our current path through the node tree.
This commit is contained in:
Nicholas Wiersma
2021-09-27 10:20:13 +02:00
committed by GitHub
parent 84424b52bc
commit 286d6c6359

View File

@@ -364,12 +364,25 @@ func structOf(t *itype, fields []structField, opts ...itypeOption) *itype {
return t return t
} }
// nodeType returns a type definition for the corresponding AST subtree. // seenNode determines if a node has been seen.
func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) { //
return nodeType2(interp, sc, n, map[*node]bool{}) // seenNode treats the slice of nodes as the path traveled down a node
// tree.
func seenNode(ns []*node, n *node) bool {
for _, nn := range ns {
if nn == n {
return true
}
}
return false
} }
func nodeType2(interp *Interpreter, sc *scope, n *node, seen map[*node]bool) (t *itype, err error) { // nodeType returns a type definition for the corresponding AST subtree.
func nodeType(interp *Interpreter, sc *scope, n *node) (*itype, error) {
return nodeType2(interp, sc, n, nil)
}
func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype, err error) {
if n.typ != nil && !n.typ.incomplete { if n.typ != nil && !n.typ.incomplete {
return n.typ, nil return n.typ, nil
} }
@@ -379,14 +392,15 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen map[*node]bool) (t
if sym.typ.isComplete() { if sym.typ.isComplete() {
return sym.typ, nil return sym.typ, nil
} }
if seen[n] { if seenNode(seen, n) {
// TODO (marc): find a better way to distinguish recursive vs incomplete types. // We have seen this node in our tree, so it must be recursive.
sym.typ.incomplete = false sym.typ.incomplete = false
return sym.typ, nil return sym.typ, nil
} }
} }
} }
seen[n] = true seen = append(seen, n)
defer func() { seen = seen[:len(seen)-1] }()
switch n.kind { switch n.kind {
case addressExpr, starExpr: case addressExpr, starExpr: