Fix nested inheritance history and budget accounting
This commit is contained in:
@@ -8,7 +8,7 @@ import (
|
||||
)
|
||||
|
||||
type inheritanceWalker struct {
|
||||
root **document.Node
|
||||
nodes int // logical non-directive nodes in the entire working tree
|
||||
origins map[string]Origin
|
||||
limits projectionLimits
|
||||
retained *retainedNodeCounter
|
||||
@@ -38,8 +38,12 @@ func expandInheritanceWithBudgets(input *document.Node, inputOrigins map[string]
|
||||
if inputOrigins == nil {
|
||||
origins = directInheritanceOrigins(input, Path{}, nil)
|
||||
}
|
||||
nodes, within := inheritanceLowerBoundCount(root, limits.nodes)
|
||||
if !within {
|
||||
return nil, []Diagnostic{inheritanceBudgetDiagnostic(Path{}, root.Location)}
|
||||
}
|
||||
walker := inheritanceWalker{
|
||||
root: &root, limits: limits, origins: origins,
|
||||
nodes: nodes, limits: limits, origins: origins,
|
||||
retained: newRetainedNodeCounter(historyLimit),
|
||||
}
|
||||
if problem := walker.visit(&root, Path{}, true); problem != nil {
|
||||
@@ -79,7 +83,14 @@ func (w *inheritanceWalker) visit(node **document.Node, path Path, unscoped bool
|
||||
}
|
||||
}
|
||||
if scopeHasInheritanceDefinitions(*node) {
|
||||
resolved, diagnostics := expandSiblingDefinitionsWithOrigins(*node, path, w.limits, w.origins, w.retained)
|
||||
// Only this scope can change the logical total. Reserve the nodes
|
||||
// outside it so expansion checks the remaining budget before cloning.
|
||||
before, _ := inheritanceLowerBoundCount(*node, -1)
|
||||
limits := w.limits
|
||||
if limits.nodes >= 0 {
|
||||
limits.nodes -= w.nodes - before
|
||||
}
|
||||
resolved, diagnostics := expandSiblingDefinitionsWithOrigins(*node, path, limits, w.origins, w.retained)
|
||||
if len(diagnostics) != 0 {
|
||||
return &diagnostics[0]
|
||||
}
|
||||
@@ -92,11 +103,15 @@ func (w *inheritanceWalker) visit(node **document.Node, path Path, unscoped bool
|
||||
w.controls = append(w.controls, resolved.controls...)
|
||||
w.replacements = append(w.replacements, resolved.replacements...)
|
||||
w.operations = append(w.operations, resolved.operations...)
|
||||
if !inheritanceLowerBoundWithin(*w.root, w.limits.nodes) {
|
||||
problem := inheritanceBudgetDiagnostic(path, (*node).Location)
|
||||
return &problem
|
||||
}
|
||||
after, _ := inheritanceLowerBoundCount(*node, -1)
|
||||
w.nodes += after - before
|
||||
}
|
||||
// Operations retain immutable enclosing templates. Detach just this
|
||||
// container before replacing descendants during destination resolution;
|
||||
// untouched subtrees remain shared with the retained evidence.
|
||||
working := **node
|
||||
working.Mapping = slices.Clone(working.Mapping)
|
||||
*node = &working
|
||||
indices := make([]int, len((*node).Mapping))
|
||||
for index := range indices {
|
||||
indices[index] = index
|
||||
@@ -111,6 +126,9 @@ func (w *inheritanceWalker) visit(node **document.Node, path Path, unscoped bool
|
||||
}
|
||||
}
|
||||
case document.Sequence:
|
||||
working := **node
|
||||
working.Sequence = slices.Clone(working.Sequence)
|
||||
*node = &working
|
||||
for index := range (*node).Sequence {
|
||||
child := &(*node).Sequence[index]
|
||||
if problem := w.visit(child, path.Index(index), (*child).Kind == document.Mapping); problem != nil {
|
||||
|
||||
Reference in New Issue
Block a user