feat(tvix/eval): construct attribute sets lazily

This thunks the construction of attribute sets. Because Tvix does not
currently have a "strict output" mode, a test had to be disabled that
now displays a thunk representation.

The test will be re-enabled once that is available.

Change-Id: I360332be64cd5c154f9caea21828f6f1b37a265c
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6363
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
Vincent Ambo 2022-08-30 19:55:04 +03:00 committed by tazjin
parent 727845645d
commit 23a5caabec
3 changed files with 13 additions and 3 deletions

View file

@ -115,7 +115,7 @@ impl Compiler {
ast::Expr::BinOp(op) => self.compile_binop(slot, op), ast::Expr::BinOp(op) => self.compile_binop(slot, op),
ast::Expr::HasAttr(has_attr) => self.compile_has_attr(slot, has_attr), ast::Expr::HasAttr(has_attr) => self.compile_has_attr(slot, has_attr),
ast::Expr::List(list) => self.compile_list(slot, list), ast::Expr::List(list) => self.compile_list(slot, list),
ast::Expr::AttrSet(attrs) => self.compile_attr_set(slot, attrs), ast::Expr::AttrSet(attrs) => self.thunk(slot, move |c, s| c.compile_attr_set(s, attrs)),
ast::Expr::Select(select) => self.compile_select(slot, select), ast::Expr::Select(select) => self.compile_select(slot, select),
ast::Expr::Assert(assert) => self.compile_assert(slot, assert), ast::Expr::Assert(assert) => self.compile_assert(slot, assert),
ast::Expr::IfElse(if_else) => self.compile_if_else(slot, if_else), ast::Expr::IfElse(if_else) => self.compile_if_else(slot, if_else),
@ -422,7 +422,8 @@ impl Compiler {
for ident in inherit.idents() { for ident in inherit.idents() {
count += 1; count += 1;
// First emit the identifier itself // First emit the identifier itself (this
// becomes the new key).
self.emit_literal_ident(&ident); self.emit_literal_ident(&ident);
// Then emit the node that we're inheriting // Then emit the node that we're inheriting
@ -434,6 +435,7 @@ impl Compiler {
// than pushing/popping the same attrs // than pushing/popping the same attrs
// potentially a lot of times. // potentially a lot of times.
self.compile(slot, from.expr().unwrap()); self.compile(slot, from.expr().unwrap());
self.emit_force();
self.emit_literal_ident(&ident); self.emit_literal_ident(&ident);
self.chunk().push_op(OpCode::OpAttrsSelect); self.chunk().push_op(OpCode::OpAttrsSelect);
} }
@ -494,6 +496,7 @@ impl Compiler {
// Push the set onto the stack // Push the set onto the stack
self.compile(slot, set); self.compile(slot, set);
self.emit_force();
// Compile each key fragment and emit access instructions. // Compile each key fragment and emit access instructions.
// //
@ -542,6 +545,7 @@ impl Compiler {
default: ast::Expr, default: ast::Expr,
) { ) {
self.compile(slot, set); self.compile(slot, set);
self.emit_force();
let mut jumps = vec![]; let mut jumps = vec![];
for fragment in path.attrs() { for fragment in path.attrs() {
@ -645,6 +649,8 @@ impl Compiler {
Some(from) => { Some(from) => {
for ident in inherit.idents() { for ident in inherit.idents() {
self.compile(slot, from.expr().unwrap()); self.compile(slot, from.expr().unwrap());
self.emit_force();
self.emit_literal_ident(&ident); self.emit_literal_ident(&ident);
self.chunk().push_op(OpCode::OpAttrsSelect); self.chunk().push_op(OpCode::OpAttrsSelect);
let idx = self.declare_local( let idx = self.declare_local(
@ -788,6 +794,8 @@ impl Compiler {
// resolve that directly (thus avoiding duplication on the // resolve that directly (thus avoiding duplication on the
// stack). // stack).
self.compile(slot, node.namespace().unwrap()); self.compile(slot, node.namespace().unwrap());
self.emit_force();
let local_idx = self.scope_mut().declare_phantom(); let local_idx = self.scope_mut().declare_phantom();
let with_idx = self.scope().stack_index(local_idx); let with_idx = self.scope().stack_index(local_idx);

View file

@ -0,0 +1,3 @@
# TODO: temporarily disabled because need "strict output" (b is
# thunked)
{ a = { b = null; }; }

View file

@ -1 +0,0 @@
{ a = { b = null; }; }