about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/compiler.rs27
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.exp1
-rw-r--r--tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.nix15
3 files changed, 40 insertions, 3 deletions
diff --git a/tvix/eval/src/compiler.rs b/tvix/eval/src/compiler.rs
index a2ab6273c102..6eca088ec254 100644
--- a/tvix/eval/src/compiler.rs
+++ b/tvix/eval/src/compiler.rs
@@ -667,13 +667,34 @@ impl Compiler {
         for inherit in node.inherits() {
             match inherit.from() {
                 // Within a `let` binding, inheriting from the outer
-                // scope is practically a no-op.
-                None => {
+                // scope is a no-op *if* the identifier can be
+                // statically resolved.
+                None if self.scope().with_stack.is_empty() => {
                     self.emit_warning(inherit.syntax().clone(), WarningKind::UselessInherit);
-
                     continue;
                 }
 
+                None => {
+                    for ident in inherit.idents() {
+                        // If the identifier resolves statically, it
+                        // has precedence over dynamic bindings, and
+                        // the inherit is useless.
+                        if self
+                            .resolve_local(ident.ident_token().unwrap().text())
+                            .is_some()
+                        {
+                            self.emit_warning(ident.syntax().clone(), WarningKind::UselessInherit);
+                            continue;
+                        }
+
+                        self.compile_ident(ident.clone());
+                        self.declare_local(
+                            ident.syntax().clone(),
+                            ident.ident_token().unwrap().text(),
+                        );
+                    }
+                }
+
                 Some(from) => {
                     for ident in inherit.idents() {
                         self.compile(from.expr().unwrap());
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.exp b/tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.exp
new file mode 100644
index 000000000000..d00491fd7e5b
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.exp
@@ -0,0 +1 @@
+1
diff --git a/tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.nix b/tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.nix
new file mode 100644
index 000000000000..d335e5363000
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/eval-okay-useless-inherit-with.nix
@@ -0,0 +1,15 @@
+# Normally using an `inherit` without a source attribute set within a
+# `let` is a no-op, *unless* there is a with in-scope that might
+# provide the value.
+
+# Provide a dynamic `x` identifier in the scope.
+with ({ x = 1;});
+
+# inherit this `x` as a static identifier
+let inherit x;
+
+# Provide another dynamic `x` identifier
+in with ({ x = 3; });
+
+# Inherited static identifier should have precedence
+x