fix(tvix/eval): manually count entries in recursive scopes

The previous version had a bug where we assumed that the number of
entries in an attribute set AST node would be equivalent to the number
of entries in the runtime attribute set, but due to inherit nodes
containing a variable number of entries, this did not work out.

Fixes b/199

Change-Id: I6f7f7729f3512b297cf29a2e046302ca28477854
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6749
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
Vincent Ambo 2022-09-23 00:51:19 +03:00 committed by tazjin
parent bd9cda2af7
commit 1015f2f8e7
4 changed files with 14 additions and 4 deletions

View file

@ -241,8 +241,8 @@ impl Compiler<'_> {
self.scope_mut().begin_scope(); self.scope_mut().begin_scope();
if node.rec_token().is_some() { if node.rec_token().is_some() {
self.compile_recursive_scope(slot, true, &node); let count = self.compile_recursive_scope(slot, true, &node);
self.push_op(OpCode::OpAttrs(Count(node.entries().count())), &node); self.push_op(OpCode::OpAttrs(Count(count)), &node);
} else { } else {
let mut count = self.compile_inherit_attrs(slot, node.inherits()); let mut count = self.compile_inherit_attrs(slot, node.inherits());

View file

@ -552,10 +552,11 @@ impl Compiler<'_> {
self.patch_jump(else_idx); // patch jump *over* else body self.patch_jump(else_idx); // patch jump *over* else body
} }
fn compile_recursive_scope<N>(&mut self, slot: LocalIdx, rec_attrs: bool, node: &N) fn compile_recursive_scope<N>(&mut self, slot: LocalIdx, rec_attrs: bool, node: &N) -> usize
where where
N: ToSpan + ast::HasEntry, N: ToSpan + ast::HasEntry,
{ {
let mut count = 0;
self.scope_mut().begin_scope(); self.scope_mut().begin_scope();
// First pass to find all plain inherits (if they are not useless). // First pass to find all plain inherits (if they are not useless).
@ -588,6 +589,8 @@ impl Compiler<'_> {
} }
}; };
count += 1;
// If the identifier resolves statically in a // If the identifier resolves statically in a
// `let`, it has precedence over dynamic // `let`, it has precedence over dynamic
// bindings, and the inherit is useless. // bindings, and the inherit is useless.
@ -625,6 +628,7 @@ impl Compiler<'_> {
} }
}; };
count += 1;
inherit_froms.push((from.expr().unwrap(), name, self.span_for(&attr))); inherit_froms.push((from.expr().unwrap(), name, self.span_for(&attr)));
} }
} }
@ -632,7 +636,7 @@ impl Compiler<'_> {
} }
// Data structures to track the bindings observed in the // Data structures to track the bindings observed in the
// second path, and forward the information needed to compile // second pass, and forward the information needed to compile
// their value. // their value.
enum BindingKind { enum BindingKind {
InheritFrom { InheritFrom {
@ -689,6 +693,8 @@ impl Compiler<'_> {
// Declare all regular bindings // Declare all regular bindings
for entry in node.attrpath_values() { for entry in node.attrpath_values() {
count += 1;
let mut path = match self.normalise_ident_path(entry.attrpath().unwrap().attrs()) { let mut path = match self.normalise_ident_path(entry.attrpath().unwrap().attrs()) {
Ok(p) => p, Ok(p) => p,
Err(err) => { Err(err) => {
@ -773,6 +779,8 @@ impl Compiler<'_> {
self.push_op(OpCode::OpFinalise(stack_idx), node); self.push_op(OpCode::OpFinalise(stack_idx), node);
} }
} }
count
} }
/// Compile a standard `let ...; in ...` expression. /// Compile a standard `let ...; in ...` expression.

View file

@ -0,0 +1 @@
{ }

View file

@ -0,0 +1 @@
rec { inherit; }