about summary refs log tree commit diff
path: root/tvix/eval/src/value/thunk.rs
diff options
context:
space:
mode:
authorVincent Ambo <mail@tazj.in>2022-08-29T15·33+0300
committertazjin <tazjin@tvl.su>2022-09-07T15·25+0000
commit9a783e50a490a873f157ec298165b3f38973e4b5 (patch)
treec3e5362a04d51ce422c00255354916beb32f1faf /tvix/eval/src/value/thunk.rs
parentdb9cb70d5d7807adff255e21a04d78c5700d1260 (diff)
feat(tvix/eval): implement OpForce in VM r/4688
This operation forces the evaluation of a thunk.

There is some potential here for making an implementation that avoids
some copies, but the thunk machinery is tricky to get right so the
first priority is to make sure it is correct by keeping the
implementation simple.

Change-Id: Ib381455b02f42ded717faff63f55afed4c8fb7e3
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6352
Tested-by: BuildkiteCI
Reviewed-by: sterni <sternenseemann@systemli.org>
Diffstat (limited to 'tvix/eval/src/value/thunk.rs')
-rw-r--r--tvix/eval/src/value/thunk.rs32
1 files changed, 31 insertions, 1 deletions
diff --git a/tvix/eval/src/value/thunk.rs b/tvix/eval/src/value/thunk.rs
index 9d52ded3c4..892868d0f6 100644
--- a/tvix/eval/src/value/thunk.rs
+++ b/tvix/eval/src/value/thunk.rs
@@ -23,7 +23,7 @@ use std::{
     rc::Rc,
 };
 
-use crate::{upvalues::UpvalueCarrier, Value};
+use crate::{errors::ErrorKind, upvalues::UpvalueCarrier, vm::VM, EvalResult, Value};
 
 use super::Lambda;
 
@@ -55,6 +55,36 @@ impl Thunk {
             lambda,
         })))
     }
+
+    pub fn force(&self, vm: &mut VM) -> EvalResult<Ref<'_, Value>> {
+        // Due to mutable borrowing rules, the following code can't
+        // easily use a match statement or something like that; it
+        // requires a bit of manual fiddling.
+        let mut thunk_mut = self.0.borrow_mut();
+
+        if let ThunkRepr::Blackhole = *thunk_mut {
+            return Err(ErrorKind::InfiniteRecursion.into());
+        }
+
+        if matches!(*thunk_mut, ThunkRepr::Suspended { .. }) {
+            if let ThunkRepr::Suspended { lambda, upvalues } =
+                std::mem::replace(&mut *thunk_mut, ThunkRepr::Blackhole)
+            {
+                vm.call(lambda, upvalues, 0);
+                *thunk_mut = ThunkRepr::Evaluated(vm.run()?);
+            }
+        }
+
+        drop(thunk_mut);
+
+        // Otherwise it's already ThunkRepr::Evaluated and we do not
+        // need another branch.
+
+        Ok(Ref::map(self.0.borrow(), |t| match t {
+            ThunkRepr::Evaluated(value) => value,
+            _ => unreachable!("already evaluated"),
+        }))
+    }
 }
 
 impl UpvalueCarrier for Thunk {