about summary refs log tree commit diff
path: root/tvix/eval/src/vm.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-31T01·47+0300
committertazjin <tazjin@tvl.su>2022-09-07T19·08+0000
commitafcfa7836401d90bbb131b170a3a69b3cf794b1c (patch)
tree50733b76e7595694c0b497ace3f65bab62873c51 /tvix/eval/src/vm.rs
parent6c6f9ae66123ea3e9e6cdc78bdb55ace712535a1 (diff)
feat(tvix/eval): semi-strictly evaluate output values of the VM r/4705
This essentially makes the VM behave like `nix-instantiate --eval
--strict`, i.e. data structures are traversed strictly and thunks are
forced. Thunks embedded in closures are not forced.

This allows us to re-enable tests that were disabled because they
needed to output nested thunk contents, but is overall a behaviour
that must be configurable later on, as it is not cmopatible with e.g.
an evaluation of nixpkgs.

Change-Id: I5303a5c8e4322feab1384fdb7712fecb950afca5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6372
Reviewed-by: sterni <sternenseemann@systemli.org>
Tested-by: BuildkiteCI
Diffstat (limited to 'tvix/eval/src/vm.rs')
-rw-r--r--tvix/eval/src/vm.rs36
1 files changed, 35 insertions, 1 deletions
diff --git a/tvix/eval/src/vm.rs b/tvix/eval/src/vm.rs
index d85f31a3cb..091a4ebb38 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)
 }