From f173161f4c0fc754df2b6daeca302d3e65bbf77d Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Sun, 14 Aug 2022 22:28:30 +0300 Subject: 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 Reviewed-by: grfn Tested-by: BuildkiteCI --- tvix/eval/src/compiler.rs | 54 ++++++++++++++++------ .../src/tests/tvix_tests/eval-okay-let-inherit.exp | 1 + .../src/tests/tvix_tests/eval-okay-let-inherit.nix | 8 ++++ 3 files changed, 49 insertions(+), 14 deletions(-) create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.exp create mode 100644 tvix/eval/src/tests/tvix_tests/eval-okay-let-inherit.nix (limited to 'tvix') 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 -- cgit 1.4.1