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-28T20·50+0300
committertazjin <tazjin@tvl.su>2022-09-06T14·58+0000
commit1f37275cfb42994ed23742b80055a7ab0485247d (patch)
treea4d29f0729323fd18dc83d0ad1b57286a4633e90 /tvix/eval/src/value/thunk.rs
parent49296cebe3c1b5644e24f6c3017a75db7c85683d (diff)
feat(tvix/eval): introduce Value::Thunk variant r/4673
Introduces the representation of runtime thunks, that is lazily
evaluated values. Their representation is very similar to closures.

Change-Id: I24d1ab7947c070ae72ca6260a7bbe6198bc8c7c5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6343
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.rs55
1 files changed, 55 insertions, 0 deletions
diff --git a/tvix/eval/src/value/thunk.rs b/tvix/eval/src/value/thunk.rs
new file mode 100644
index 000000000000..15179388dc86
--- /dev/null
+++ b/tvix/eval/src/value/thunk.rs
@@ -0,0 +1,55 @@
+//! This module implements the runtime representation of Thunks.
+//!
+//! Thunks are a special kind of Nix value, similar to a 0-argument
+//! closure that yields some value. Thunks are used to implement the
+//! lazy evaluation behaviour of Nix:
+//!
+//! Whenever the compiler determines that an expression should be
+//! evaluated lazily, it creates a thunk instead of compiling the
+//! expression value directly. At any point in the runtime where the
+//! actual value of a thunk is required, it is "forced", meaning that
+//! the encompassing computation takes place and the thunk takes on
+//! its new value.
+//!
+//! Thunks have interior mutability to be able to memoise their
+//! computation. Once a thunk is evaluated, its internal
+//! representation becomes the result of the expression. It is legal
+//! for the runtime to replace a thunk object directly with its value
+//! object, but when forcing a thunk, the runtime *must* mutate the
+//! memoisable slot.
+
+use std::{cell::RefCell, rc::Rc};
+
+use crate::Value;
+
+use super::Lambda;
+
+/// Internal representation of the different states of a thunk.
+#[derive(Debug)]
+enum ThunkRepr {
+    /// Thunk is suspended and awaiting execution.
+    Suspended { lambda: Lambda },
+
+    /// Thunk is closed over some values, suspended and awaiting
+    /// execution.
+    ClosedSuspended {
+        lambda: Lambda,
+        upvalues: Vec<Value>,
+    },
+
+    /// Thunk currently under-evaluation; encountering a blackhole
+    /// value means that infinite recursion has occured.
+    Blackhole,
+
+    /// Fully evaluated thunk.
+    Evaluated(Value),
+}
+
+#[derive(Clone, Debug)]
+pub struct Thunk(Rc<RefCell<ThunkRepr>>);
+
+impl Thunk {
+    pub fn new(lambda: Lambda) -> Self {
+        Thunk(Rc::new(RefCell::new(ThunkRepr::Suspended { lambda })))
+    }
+}