diff options
author | Vincent Ambo <mail@tazj.in> | 2022-08-14T19·28+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2022-08-31T22·10+0000 |
commit | f173161f4c0fc754df2b6daeca302d3e65bbf77d (patch) | |
tree | e3504fda83f4950def7ea39f06f3d2014d4020e2 | |
parent | 8c1c9aee3cab52befe55d6f41e1c9acaef1b1843 (diff) |
feat(tvix/eval): implement inherit in let expressions r/4549
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
-rw-r--r-- | tvix/eval/src/compiler.rs | 54 | ||||
-rw-r--r-- | tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.exp | 1 | ||||
-rw-r--r-- | tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.nix | 8 |
3 files changed, 49 insertions, 14 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs index 11bd649f71df..2f48a1cea8af 100644 --- a/tvix/eval/src/compiler.rs +++ b/tvix/eval/src/compiler.rs @@ -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)?; } diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.exp new file mode 100644 index 000000000000..d00491fd7e5b --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.exp @@ -0,0 +1 @@ +1 diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.nix new file mode 100644 index 000000000000..12eed10e13fc --- /dev/null +++ b/tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.nix @@ -0,0 +1,8 @@ +let + set = { + a = 1; + }; +in + let + inherit (set) a; + in a |