about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler/bindings.rs43
1 files changed, 29 insertions, 14 deletions
diff --git a/tvix/eval/src/compiler/bindings.rs b/tvix/eval/src/compiler/bindings.rs
index d7a5513934a1..94dae5fb951a 100644
--- a/tvix/eval/src/compiler/bindings.rs
+++ b/tvix/eval/src/compiler/bindings.rs
@@ -20,13 +20,20 @@ enum Binding {
     },
 }
 
-struct KeySlot {
-    slot: LocalIdx,
-    name: SmolStr,
+enum KeySlot {
+    /// There is no key slot (`let`-expressions do not emit their key).
+    None,
+
+    /// The key is statically known and has a slot.
+    Static { slot: LocalIdx, name: SmolStr },
+
+    /// The key is dynamic, i.e. only known at runtime, and must be compiled
+    /// into its slot.
+    Dynamic { slot: LocalIdx, expr: ast::Expr },
 }
 
 struct TrackedBinding {
-    key_slot: Option<KeySlot>,
+    key_slot: KeySlot,
     value_slot: LocalIdx,
     binding: Binding,
 }
@@ -168,12 +175,12 @@ impl Compiler<'_> {
                 // In an attribute set, the keys themselves are placed on the
                 // stack but their stack slot is inaccessible (it is only
                 // consumed by `OpAttrs`).
-                Some(KeySlot {
+                KeySlot::Static {
                     slot: self.scope_mut().declare_phantom(span, false),
                     name: name.clone(),
-                })
+                }
             } else {
-                None
+                KeySlot::None
             };
 
             let value_slot = match kind {
@@ -239,12 +246,12 @@ impl Compiler<'_> {
 
             let key_span = self.span_for(&path[0]);
             let key_slot = if kind.is_attrs() {
-                Some(KeySlot {
+                KeySlot::Static {
                     name: name.clone(),
                     slot: self.scope_mut().declare_phantom(key_span, false),
-                })
+                }
             } else {
-                None
+                KeySlot::None
             };
 
             let value_slot = match kind {
@@ -431,10 +438,18 @@ impl Compiler<'_> {
         for binding in bindings.into_iter() {
             value_indices.push(binding.value_slot);
 
-            if let Some(key_slot) = binding.key_slot {
-                let span = self.scope()[key_slot.slot].span;
-                self.emit_constant(Value::String(key_slot.name.into()), &span);
-                self.scope_mut().mark_initialised(key_slot.slot);
+            match binding.key_slot {
+                KeySlot::None => {} // nothing to do here
+
+                KeySlot::Static { slot, name } => {
+                    let span = self.scope()[slot].span;
+                    self.emit_constant(Value::String(name.into()), &span);
+                    self.scope_mut().mark_initialised(slot);
+                }
+
+                KeySlot::Dynamic { .. } => {
+                    todo!("dynamic keys not ye timplemented")
+                }
             }
 
             match binding.binding {