about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler/bindings.rs41
1 files changed, 29 insertions, 12 deletions
diff --git a/tvix/eval/src/compiler/bindings.rs b/tvix/eval/src/compiler/bindings.rs
index 659dce299a1a..4f384484a973 100644
--- a/tvix/eval/src/compiler/bindings.rs
+++ b/tvix/eval/src/compiler/bindings.rs
@@ -53,19 +53,23 @@ impl BindingsKind {
 
 /// AST-traversing functions related to bindings.
 impl Compiler<'_> {
-    fn compile_inherits<N>(
+    /// Compile all inherits of a node with entries that do *not* have a
+    /// namespace to inherit from, and return the remaining ones that do.
+    fn compile_plain_inherits<N>(
         &mut self,
         slot: LocalIdx,
-        count: &mut usize,
-        bindings: &mut Vec<TrackedBinding>,
         kind: BindingsKind,
+        count: &mut usize,
         node: &N,
-    ) where
+    ) -> Vec<(ast::Expr, String, Span)>
+    where
         N: ToSpan + ast::HasEntry,
     {
-        // First pass over all inherits resolves only those without
-        // namespaces. Since they always resolve to a higher scope, we
-        // can just compile and declare them immediately.
+        // Pass over all inherits, resolving only those without namespaces.
+        // Since they always resolve in a higher scope, we can just compile and
+        // declare them immediately.
+        //
+        // Inherits with namespaces are returned to the caller.
         let mut inherit_froms: Vec<(ast::Expr, String, Span)> = vec![];
 
         for inherit in node.inherits() {
@@ -145,9 +149,21 @@ impl Compiler<'_> {
             }
         }
 
-        // Second pass over the inherits that have a namespace, to declare them
-        // in the tracked bindings. Compiling the values into their slots is the
-        // job of the caller.
+        inherit_froms
+    }
+
+    /// Declare all namespaced inherits, that is inherits which are inheriting
+    /// values from an attribute set.
+    ///
+    /// This only ensures that the locals stack is aware of the inherits, it
+    /// does not yet emit bytecode that places them on the stack. This is up to
+    /// the owner of the `bindings` vector, which this function will populate.
+    fn declare_namespaced_inherits(
+        &mut self,
+        kind: BindingsKind,
+        inherit_froms: Vec<(ast::Expr, String, Span)>,
+        bindings: &mut Vec<TrackedBinding>,
+    ) {
         for (from, name, span) in inherit_froms {
             let key_slot = if kind.is_attrs() {
                 // In an attribute set, the keys themselves are placed
@@ -425,10 +441,11 @@ impl Compiler<'_> {
         let mut count = 0;
         self.scope_mut().begin_scope();
 
-        // Vector to track these observed bindings.
+        // Vector to track all observed bindings.
         let mut bindings: Vec<TrackedBinding> = vec![];
 
-        self.compile_inherits(slot, &mut count, &mut bindings, kind, node);
+        let inherit_froms = self.compile_plain_inherits(slot, kind, &mut count, node);
+        self.declare_namespaced_inherits(kind, inherit_froms, &mut bindings);
 
         // Declare all regular bindings
         for entry in node.attrpath_values() {