feat(tvix/eval): implement inherit in let expressions

Note that at this point recursive bindings do not yet work in either
attrsets or let, so inheriting from the same scope is generally not
possible yet.

Change-Id: I6ca820d04b8ded5c22fb7ea18e2ec203bcaa8e9c
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6215
Reviewed-by: sterni <sternenseemann@systemli.org>
Reviewed-by: grfn <grfn@gws.fyi>
Tested-by: BuildkiteCI
This commit is contained in:
Vincent Ambo 2022-08-14 22:28:30 +03:00 committed by tazjin
parent 8c1c9aee3c
commit f173161f4c
3 changed files with 49 additions and 14 deletions

View file

@ -688,9 +688,36 @@ impl Compiler {
//
// Unless in a non-standard scope, the encountered values are
// simply pushed on the stack and their indices noted in the
// entries vector.
fn compile_let_in(&mut self, node: rnix::types::LetIn) -> Result<(), Error> {
self.begin_scope();
let mut entries = vec![];
let mut from_inherits = vec![];
for inherit in node.inherits() {
match inherit.from() {
// Within a `let` binding, inheriting from the outer
// scope is practically a no-op.
None => {
self.warnings.push(EvalWarning {
node: inherit.node().clone(),
kind: WarningKind::UselessInherit,
});
continue;
}
Some(_) => {
for ident in inherit.idents() {
self.locals.locals.push(Local {
name: ident.as_str().to_string(),
depth: self.locals.scope_depth,
});
}
from_inherits.push(inherit);
}
}
}
// Before compiling the values of a let expression, all keys
// need to already be added to the known locals. This is
@ -712,24 +739,23 @@ impl Compiler {
});
}
for inherit in node.inherits() {
match inherit.from() {
// Within a `let` binding, inheriting from the outer
// scope is practically a no-op.
None => {
self.warnings.push(EvalWarning {
node: inherit.node().clone(),
kind: WarningKind::UselessInherit,
});
// Now we can add instructions to look up each inherited value
// ...
for inherit in from_inherits {
let from = inherit
.from()
.expect("only inherits with `from` are pushed here");
continue;
}
Some(_) => todo!("let inherit from attrs"),
for ident in inherit.idents() {
// TODO: Optimised multi-select instruction?
self.compile(from.inner().unwrap())?;
self.emit_literal_ident(&ident);
self.chunk.push_op(OpCode::OpAttrsSelect);
}
}
// Now we can compile each expression, leaving the values on
// the stack in the right order.
// ... and finally each expression, leaving the values on the
// stack in the right order.
for value in entries {
self.compile(value)?;
}

View file

@ -0,0 +1 @@
1

View file

@ -0,0 +1,8 @@
let
set = {
a = 1;
};
in
let
inherit (set) a;
in a