From bb34665abdf82227abdf0fc726abe2df57f3193e Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Mon, 5 Sep 2022 15:46:21 +0300 Subject: [PATCH] refactor(tvix/eval): extract attribute set inherit into helper This will be re-used between the code paths for recursive/non-recursive sets, and it might even be possible to unify it with the logic for compiling `let inherit ...`. Change-Id: I960a061048ac583a6e932e11ff6e642d9fc3093e Reviewed-on: https://cl.tvl.fyi/c/depot/+/6464 Tested-by: BuildkiteCI Reviewed-by: sterni --- tvix/eval/src/compiler/mod.rs | 49 ++++++++++++++++++++++------------- 1 file changed, 31 insertions(+), 18 deletions(-) diff --git a/tvix/eval/src/compiler/mod.rs b/tvix/eval/src/compiler/mod.rs index 3fd43db53..6be2a1fb0 100644 --- a/tvix/eval/src/compiler/mod.rs +++ b/tvix/eval/src/compiler/mod.rs @@ -17,7 +17,7 @@ mod scope; use path_clean::PathClean; use rnix::ast::{self, AstToken, HasEntry}; -use rowan::ast::AstNode; +use rowan::ast::{AstChildren, AstNode}; use smol_str::SmolStr; use std::collections::HashMap; use std::path::{Path, PathBuf}; @@ -451,25 +451,20 @@ impl Compiler<'_, '_> { self.push_op(OpCode::OpList(Count(count)), &node); } - /// Compile attribute set literals into equivalent bytecode. - /// - /// This is complicated by a number of features specific to Nix - /// attribute sets, most importantly: - /// - /// 1. Keys can be dynamically constructed through interpolation. - /// 2. Keys can refer to nested attribute sets. - /// 3. Attribute sets can (optionally) be recursive. - fn compile_attr_set(&mut self, slot: LocalIdx, node: ast::AttrSet) { - if node.rec_token().is_some() { - todo!("recursive attribute sets are not yet implemented") - } - + /// Compiles inherited values in an attribute set. Inherited + /// values are *always* inherited from the outer scope, even if + /// there is a matching name within a recursive attribute set. + fn compile_inherit_attrs( + &mut self, + slot: LocalIdx, + inherits: AstChildren, + ) -> usize { + // Count the number of inherited values, so that the outer + // constructor can emit the correct number of pairs when + // constructing attribute sets. let mut count = 0; - // Inherits have to be evaluated before entering the scope of - // a potentially recursive attribute sets (i.e. we always - // inherit "from the outside"). - for inherit in node.inherits() { + for inherit in inherits { match inherit.from() { Some(from) => { for ident in inherit.idents() { @@ -508,6 +503,24 @@ impl Compiler<'_, '_> { } } + count + } + + /// Compile attribute set literals into equivalent bytecode. + /// + /// This is complicated by a number of features specific to Nix + /// attribute sets, most importantly: + /// + /// 1. Keys can be dynamically constructed through interpolation. + /// 2. Keys can refer to nested attribute sets. + /// 3. Attribute sets can (optionally) be recursive. + fn compile_attr_set(&mut self, slot: LocalIdx, node: ast::AttrSet) { + if node.rec_token().is_some() { + todo!("recursive attribute sets are not yet implemented") + } + + let mut count = self.compile_inherit_attrs(slot, node.inherits()); + for kv in node.attrpath_values() { count += 1;