Answer architecture round 1: refuse a name read inside the field it binds, check every scope's cycles, build a column read in one pass, drop the implicit struct pick for names across tags, and state the fresh-draw rule once

This commit is contained in:
2026-10-05 09:39:18 +02:00
committed by Lillem4n
parent a45edf8fb5
commit 1a15a139c8
23 changed files with 257 additions and 230 deletions
+10 -2
View File
@@ -166,14 +166,22 @@ func repeatCheck(path string, n node, mem renderCounts) error {
// graph (renderEdges). Every node is a root: a field its parent's format never
// renders is still reachable by dot path, so a cycle in one would otherwise reach
// render and be fatal there.
func checkNoCycles(sites []categorySite) error {
func checkNoCycles(s nodeScope) error {
const (
grey = 1
black = 2
)
inScope := map[node]bool{}
_ = s(func(_ string, n node) error {
inScope[n] = true
return nil
})
color := map[node]int{}
var visit func(n node, path string) error
visit = func(n node, path string) error {
if !inScope[n] {
return nil // loaded before this scope and proven then, so it never reaches back into it
}
switch color[n] {
case grey:
return fmt.Errorf("reference cycle: %s", path)
@@ -189,5 +197,5 @@ func checkNoCycles(sites []categorySite) error {
color[n] = black
return nil
}
return sitesScope(sites)(func(path string, n node) error { return visit(n, path) })
return s(func(path string, n node) error { return visit(n, path) })
}