about summary refs log tree commit diff
path: root/tvix/eval
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-09-23T16·04+0300
committertazjin <tazjin@tvl.su>2022-09-28T00·09+0000
commit14147e9b5f1f16b2a713e2aee58ea201db0e0308 (patch)
tree02eb36a638ee2407b6deb5a7ccac7c8ee9fa4e46 /tvix/eval
parent6d60c22b2a3d514ee6f3adfe36f94146d9a7bc1c (diff)
refactor(tvix/eval): introduce type to track kind of bindings r/4976
As part of the unification of binding logic between different carriers
of bindings, we need to track which kind of bindings we are dealing
with (attribute set? recursive scope? ...) to correctly emit keys and
declare identifiers in the locals stack.

Right now this changes no functionality as `BindingsKind::Attrs` is
not yet used (only RecAttrs and LetIn, which was previously
represented by the `rec_attrs` boolean).

Change-Id: Id2ac27894079ab584521cb568d75c124f7bf2403
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6771
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval')
-rw-r--r--tvix/eval/src/compiler/bindings.rs41
1 files changed, 30 insertions, 11 deletions
diff --git a/tvix/eval/src/compiler/bindings.rs b/tvix/eval/src/compiler/bindings.rs
index b09989bc00e2..7ee8ef8a84f0 100644
--- a/tvix/eval/src/compiler/bindings.rs
+++ b/tvix/eval/src/compiler/bindings.rs
@@ -32,6 +32,25 @@ struct TrackedBinding {
     binding: Binding,
 }
 
+/// What kind of bindings scope is being compiled?
+#[derive(Clone, Copy, PartialEq)]
+enum BindingsKind {
+    /// Standard `let ... in ...`-expression.
+    LetIn,
+
+    /// Non-recursive attribute set.
+    Attrs,
+
+    /// Recursive attribute set.
+    RecAttrs,
+}
+
+impl BindingsKind {
+    fn is_attrs(&self) -> bool {
+        matches!(self, BindingsKind::Attrs | BindingsKind::RecAttrs)
+    }
+}
+
 /// AST-traversing functions related to bindings.
 impl Compiler<'_> {
     fn compile_inherits<N>(
@@ -39,7 +58,7 @@ impl Compiler<'_> {
         slot: LocalIdx,
         count: &mut usize,
         bindings: &mut Vec<TrackedBinding>,
-        rec_attrs: bool,
+        kind: BindingsKind,
         node: &N,
     ) where
         N: ToSpan + ast::HasEntry,
@@ -57,7 +76,7 @@ impl Compiler<'_> {
                 // Within a `let` binding, inheriting from the outer
                 // scope is a no-op *if* the identifier can be
                 // statically resolved.
-                None if !rec_attrs && !self.scope().has_with() => {
+                None if !kind.is_attrs() && !self.scope().has_with() => {
                     self.emit_warning(&inherit, WarningKind::UselessInherit);
                     continue;
                 }
@@ -77,7 +96,7 @@ impl Compiler<'_> {
                         // If the identifier resolves statically in a
                         // `let`, it has precedence over dynamic
                         // bindings, and the inherit is useless.
-                        if !rec_attrs
+                        if kind == BindingsKind::LetIn
                             && matches!(
                                 self.scope_mut().resolve_local(&name),
                                 LocalPosition::Known(_)
@@ -87,7 +106,7 @@ impl Compiler<'_> {
                             continue;
                         }
 
-                        if rec_attrs {
+                        if kind == BindingsKind::RecAttrs {
                             self.emit_constant(Value::String(SmolStr::new(&name).into()), &attr);
                             let span = self.span_for(&attr);
                             self.scope_mut().declare_phantom(span, true);
@@ -118,7 +137,7 @@ impl Compiler<'_> {
 
         // Begin with the inherit (from)s since they all become a thunk anyway
         for (from, name, span) in inherit_froms {
-            let key_slot = if rec_attrs {
+            let key_slot = if kind.is_attrs() {
                 Some(KeySlot {
                     slot: self.scope_mut().declare_phantom(span, false),
                     name: SmolStr::new(&name),
@@ -358,7 +377,7 @@ impl Compiler<'_> {
         self.scope_mut().begin_scope();
 
         if node.rec_token().is_some() {
-            let count = self.compile_recursive_scope(slot, true, &node);
+            let count = self.compile_recursive_scope(slot, BindingsKind::RecAttrs, &node);
             self.push_op(OpCode::OpAttrs(Count(count)), &node);
         } else {
             let mut count = self.compile_inherit_attrs(slot, node.inherits());
@@ -376,7 +395,7 @@ impl Compiler<'_> {
         self.scope_mut().end_scope();
     }
 
-    fn compile_recursive_scope<N>(&mut self, slot: LocalIdx, rec_attrs: bool, node: &N) -> usize
+    fn compile_recursive_scope<N>(&mut self, slot: LocalIdx, kind: BindingsKind, node: &N) -> usize
     where
         N: ToSpan + ast::HasEntry,
     {
@@ -386,7 +405,7 @@ impl Compiler<'_> {
         // Vector to track these observed bindings.
         let mut bindings: Vec<TrackedBinding> = vec![];
 
-        self.compile_inherits(slot, &mut count, &mut bindings, rec_attrs, node);
+        self.compile_inherits(slot, &mut count, &mut bindings, kind, node);
 
         // Declare all regular bindings
         for entry in node.attrpath_values() {
@@ -408,7 +427,7 @@ impl Compiler<'_> {
                 continue;
             }
 
-            let key_slot = if rec_attrs {
+            let key_slot = if kind.is_attrs() {
                 let span = self.span_for(&entry.attrpath().unwrap());
                 Some(KeySlot {
                     slot: self.scope_mut().declare_phantom(span, false),
@@ -486,7 +505,7 @@ impl Compiler<'_> {
     /// simply pushed on the stack and their indices noted in the
     /// entries vector.
     pub(super) fn compile_let_in(&mut self, slot: LocalIdx, node: ast::LetIn) {
-        self.compile_recursive_scope(slot, false, &node);
+        self.compile_recursive_scope(slot, BindingsKind::LetIn, &node);
 
         // Deal with the body, then clean up the locals afterwards.
         self.compile(slot, node.body().unwrap());
@@ -496,7 +515,7 @@ impl Compiler<'_> {
     pub(super) fn compile_legacy_let(&mut self, slot: LocalIdx, node: ast::LegacyLet) {
         self.emit_warning(&node, WarningKind::DeprecatedLegacyLet);
         self.scope_mut().begin_scope();
-        self.compile_recursive_scope(slot, true, &node);
+        self.compile_recursive_scope(slot, BindingsKind::RecAttrs, &node);
         self.push_op(OpCode::OpAttrs(Count(node.entries().count())), &node);
         self.emit_constant(Value::String(SmolStr::new_inline("body").into()), &node);
         self.push_op(OpCode::OpAttrsSelect, &node);