about summary refs log tree commit diff
path: root/tvix/eval/src/compiler/bindings.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2023-01-29T20·40+0300
committertazjin <tazjin@tvl.su>2023-02-03T18·47+0000
commit32698766ef05c1c5f65a2fdbb8d08c558d793dec (patch)
treea26db2d62544a323f86b1a9cfab40c008ccc761b /tvix/eval/src/compiler/bindings.rs
parentf2afd38f2d9e4695f814d332cf2352572d8ab8d6 (diff)
refactor(tvix/eval): statically resolve select from constant attrs r/5831
When resolving a select expression (`attrs.name` or `attrs.name or
default`), if the set compiles to a constant attribute set (as is most
notably the case with `builtins`) we can backtrack and replace that
attribute set directly with the compiled value.

For something like `builtins.length`, this will directly emit an
`OpConstant` that leaves the `length` builtin on the stack.

Change-Id: I639654e065a06e8cfcbcacb528c6da7ec9e513ee
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7957
Tested-by: BuildkiteCI
Reviewed-by: flokli <flokli@flokli.de>
Diffstat (limited to 'tvix/eval/src/compiler/bindings.rs')
-rw-r--r--tvix/eval/src/compiler/bindings.rs41
1 files changed, 4 insertions, 37 deletions
diff --git a/tvix/eval/src/compiler/bindings.rs b/tvix/eval/src/compiler/bindings.rs
index 59ca222b7219..9ce50d36db3e 100644
--- a/tvix/eval/src/compiler/bindings.rs
+++ b/tvix/eval/src/compiler/bindings.rs
@@ -226,7 +226,7 @@ impl TrackedBindings {
 
         // If the first element of the path is not statically known, the entry
         // can not be merged.
-        let name = match c.expr_static_attr_str(name) {
+        let name = match expr_static_attr_str(name) {
             Some(name) => name,
             None => return false,
         };
@@ -336,7 +336,7 @@ impl Compiler<'_> {
 
                 None => {
                     for attr in inherit.attrs() {
-                        let name = match self.expr_static_attr_str(&attr) {
+                        let name = match expr_static_attr_str(&attr) {
                             Some(name) => name,
                             None => {
                                 self.emit_error(&attr, ErrorKind::DynamicKeyInScope("inherit"));
@@ -387,7 +387,7 @@ impl Compiler<'_> {
 
                 Some(from) => {
                     for attr in inherit.attrs() {
-                        let name = match self.expr_static_attr_str(&attr) {
+                        let name = match expr_static_attr_str(&attr) {
                             Some(name) => name,
                             None => {
                                 self.emit_error(&attr, ErrorKind::DynamicKeyInScope("inherit"));
@@ -476,7 +476,7 @@ impl Compiler<'_> {
             *count += 1;
 
             let key_span = self.span_for(&key);
-            let key_slot = match self.expr_static_attr_str(&key) {
+            let key_slot = match expr_static_attr_str(&key) {
                 Some(name) if kind.is_attrs() => KeySlot::Static {
                     name,
                     slot: self.scope_mut().declare_phantom(key_span, false),
@@ -819,37 +819,4 @@ impl Compiler<'_> {
         self.contexts[ctx_idx].lambda.upvalue_count += 1;
         idx
     }
-
-    /// Convert a non-dynamic string expression to a string if possible.
-    fn expr_static_str(&self, node: &ast::Str) -> Option<SmolStr> {
-        let mut parts = node.normalized_parts();
-
-        if parts.len() != 1 {
-            return None;
-        }
-
-        if let Some(ast::InterpolPart::Literal(lit)) = parts.pop() {
-            return Some(SmolStr::new(lit));
-        }
-
-        None
-    }
-
-    /// Convert the provided `ast::Attr` into a statically known string if
-    /// possible.
-    fn expr_static_attr_str(&self, node: &ast::Attr) -> Option<SmolStr> {
-        match node {
-            ast::Attr::Ident(ident) => Some(ident.ident_token().unwrap().text().into()),
-            ast::Attr::Str(s) => self.expr_static_str(s),
-
-            // The dynamic node type is just a wrapper. C++ Nix does not care
-            // about the dynamic wrapper when determining whether the node
-            // itself is dynamic, it depends solely on the expression inside
-            // (i.e. `let ${"a"} = 1; in a` is valid).
-            ast::Attr::Dynamic(ref dynamic) => match dynamic.expr().unwrap() {
-                ast::Expr::Str(s) => self.expr_static_str(&s),
-                _ => None,
-            },
-        }
-    }
 }