about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--tvix/eval/src/tests/tvix_tests/disabled-identity-nested-attrs.nix3
-rw-r--r--tvix/eval/src/tests/tvix_tests/identity-nested-attrs.nix1
-rw-r--r--tvix/eval/src/vm.rs36
3 files changed, 36 insertions, 4 deletions
diff --git a/tvix/eval/src/tests/tvix_tests/disabled-identity-nested-attrs.nix b/tvix/eval/src/tests/tvix_tests/disabled-identity-nested-attrs.nix
deleted file mode 100644
index f8dacf3e084a..000000000000
--- a/tvix/eval/src/tests/tvix_tests/disabled-identity-nested-attrs.nix
+++ /dev/null
@@ -1,3 +0,0 @@
-# TODO: temporarily disabled because need "strict output" (b is
-# thunked)
-{ a = { b = null; }; }
diff --git a/tvix/eval/src/tests/tvix_tests/identity-nested-attrs.nix b/tvix/eval/src/tests/tvix_tests/identity-nested-attrs.nix
new file mode 100644
index 000000000000..6a139452ef28
--- /dev/null
+++ b/tvix/eval/src/tests/tvix_tests/identity-nested-attrs.nix
@@ -0,0 +1 @@
+{ a = { b = null; }; }
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index d85f31a3cb02..091a4ebb38ab 100644
--- a/tvix/eval/src/vm.rs
+++ b/tvix/eval/src/vm.rs
@@ -602,6 +602,38 @@ impl VM {
 
         Ok(())
     }
+
+    /// Strictly evaluate the supplied value for outputting it. This
+    /// will ensure that lists and attribute sets do not contain
+    /// chunks which, for users, are displayed in a strange and often
+    /// unexpected way.
+    fn force_for_output(&mut self, value: &Value) -> EvalResult<()> {
+        match value {
+            Value::Attrs(attrs) => {
+                for (_, value) in attrs.iter() {
+                    self.force_for_output(value)?;
+                }
+                Ok(())
+            }
+
+            Value::List(list) => list.iter().try_for_each(|elem| self.force_for_output(elem)),
+
+            Value::Thunk(thunk) => {
+                thunk.force(self)?;
+                self.force_for_output(&thunk.value())
+            }
+
+            // If any of these internal values are encountered here a
+            // critical error has happened (likely a compiler bug).
+            Value::AttrPath(_)
+            | Value::AttrNotFound
+            | Value::DynamicUpvalueMissing(_)
+            | Value::Blueprint(_)
+            | Value::DeferredUpvalue(_) => panic!("tvix bug: internal value left on stack"),
+
+            _ => Ok(()),
+        }
+    }
 }
 
 // TODO: use Rc::unwrap_or_clone once it is stabilised.
@@ -618,5 +650,7 @@ pub fn run_lambda(lambda: Lambda) -> EvalResult<Value> {
     };
 
     vm.call(Rc::new(lambda), vec![], 0);
-    vm.run()
+    let value = vm.run()?;
+    vm.force_for_output(&value)?;
+    Ok(value)
 }