From 14147e9b5f1f16b2a713e2aee58ea201db0e0308 Mon Sep 17 00:00:00 2001 From: Vincent Ambo Date: Fri, 23 Sep 2022 19:04:41 +0300 Subject: refactor(tvix/eval): introduce type to track kind of bindings 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 Tested-by: BuildkiteCI --- tvix/eval/src/compiler/bindings.rs | 41 ++++++++++++++++++++++++++++---------- 1 file changed, 30 insertions(+), 11 deletions(-) diff --git a/tvix/eval/src/compiler/bindings.rs b/tvix/eval/src/compiler/bindings.rs index b09989bc00..7ee8ef8a84 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( @@ -39,7 +58,7 @@ impl Compiler<'_> { slot: LocalIdx, count: &mut usize, bindings: &mut Vec, - 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(&mut self, slot: LocalIdx, rec_attrs: bool, node: &N) -> usize + fn compile_recursive_scope(&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 = 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); -- cgit 1.4.1