diff options
author | Vincent Ambo <mail@tazj.in> | 2023-01-29T20·40+0300 |
---|---|---|
committer | tazjin <tazjin@tvl.su> | 2023-02-03T18·47+0000 |
commit | 32698766ef05c1c5f65a2fdbb8d08c558d793dec (patch) | |
tree | a26db2d62544a323f86b1a9cfab40c008ccc761b /tvix/eval/src/compiler/bindings.rs | |
parent | f2afd38f2d9e4695f814d332cf2352572d8ab8d6 (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.rs | 41 |
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, - }, - } - } } |