feat(tvix/eval): add Evaluation::strict to toggle top-level deepseq
This makes it possible for callers to control whether they can receive partially evaluated values from an evaluation or not. We're actually flipping the default behaviour to non-strict top-level evaluation, which means that callers have to set `strict = true` on the Evaluation to get the previous behaviour. Change-Id: Ic048e9ba09c88866d4c3177d5fa07db11c4eb20e Reviewed-on: https://cl.tvl.fyi/c/depot/+/8325 Autosubmit: tazjin <tazjin@tvl.su> Tested-by: BuildkiteCI Reviewed-by: sterni <sternenseemann@systemli.org>
This commit is contained in:
parent
a5f28eea94
commit
ba138712e4
5 changed files with 26 additions and 5 deletions
|
@ -104,6 +104,11 @@ pub struct Evaluation<'code, 'co, 'ro> {
|
|||
/// able to read the files specified as arguments to `import`.
|
||||
pub enable_import: bool,
|
||||
|
||||
/// Determines whether the returned value should be strictly
|
||||
/// evaluated, that is whether its list and attribute set elements
|
||||
/// should be forced recursively.
|
||||
pub strict: bool,
|
||||
|
||||
/// (optional) Nix search path, e.g. the value of `NIX_PATH` used
|
||||
/// for resolving items on the search path (such as `<nixpkgs>`).
|
||||
pub nix_path: Option<String>,
|
||||
|
@ -161,6 +166,7 @@ impl<'code, 'co, 'ro> Evaluation<'code, 'co, 'ro> {
|
|||
src_builtins: vec![],
|
||||
io_handle: Box::new(DummyIO {}),
|
||||
enable_import: false,
|
||||
strict: false,
|
||||
nix_path: None,
|
||||
compiler_observer: None,
|
||||
runtime_observer: None,
|
||||
|
@ -256,7 +262,15 @@ impl<'code, 'co, 'ro> Evaluation<'code, 'co, 'ro> {
|
|||
.unwrap_or_default();
|
||||
|
||||
let runtime_observer = self.runtime_observer.take().unwrap_or(&mut noop_observer);
|
||||
let vm_result = run_lambda(nix_path, self.io_handle, runtime_observer, globals, lambda);
|
||||
|
||||
let vm_result = run_lambda(
|
||||
nix_path,
|
||||
self.io_handle,
|
||||
runtime_observer,
|
||||
globals,
|
||||
lambda,
|
||||
self.strict,
|
||||
);
|
||||
|
||||
match vm_result {
|
||||
Ok(mut runtime_result) => {
|
||||
|
|
|
@ -52,6 +52,7 @@ fn eval_test(code_path: &str, expect_success: bool) {
|
|||
}
|
||||
|
||||
let mut eval = crate::Evaluation::new_impure(&code, Some(code_path.into()));
|
||||
eval.strict = true;
|
||||
eval.builtins.extend(mock_builtins::builtins());
|
||||
|
||||
let result = eval.evaluate();
|
||||
|
@ -100,6 +101,7 @@ fn identity(code_path: &str) {
|
|||
let code = std::fs::read_to_string(code_path).expect("should be able to read test code");
|
||||
|
||||
let mut eval = crate::Evaluation::new(&code, None);
|
||||
eval.strict = true;
|
||||
eval.io_handle = Box::new(crate::StdIO);
|
||||
|
||||
let result = eval.evaluate();
|
||||
|
|
|
@ -1190,6 +1190,7 @@ pub fn run_lambda(
|
|||
observer: &mut dyn RuntimeObserver,
|
||||
globals: Rc<GlobalsMap>,
|
||||
lambda: Rc<Lambda>,
|
||||
strict: bool,
|
||||
) -> EvalResult<RuntimeResult> {
|
||||
// Retain the top-level span of the expression in this lambda, as
|
||||
// synthetic "calls" in deep_force will otherwise not have a span
|
||||
|
@ -1207,9 +1208,11 @@ pub fn run_lambda(
|
|||
root_span.into(),
|
||||
);
|
||||
|
||||
// Synthesise a frame that will instruct the VM to deep-force the final
|
||||
// value before returning it.
|
||||
// When evaluating strictly, synthesise a frame that will instruct
|
||||
// the VM to deep-force the final value before returning it.
|
||||
if strict {
|
||||
vm.enqueue_generator("final_deep_force", root_span.into(), final_deep_force);
|
||||
}
|
||||
|
||||
vm.frames.push(Frame::CallFrame {
|
||||
span: root_span.into(),
|
||||
|
|
|
@ -41,6 +41,7 @@ fn nix_eval(expr: &str) -> String {
|
|||
fn compare_eval(expr: &str) {
|
||||
let nix_result = nix_eval(expr);
|
||||
let mut eval = tvix_eval::Evaluation::new(expr, None);
|
||||
eval.strict = true;
|
||||
eval.io_handle = Box::new(tvix_eval::StdIO);
|
||||
|
||||
let tvix_result = eval
|
||||
|
|
|
@ -33,7 +33,8 @@ where
|
|||
T: serde::Deserialize<'code>,
|
||||
{
|
||||
// First step is to evaluate the Nix code ...
|
||||
let eval = tvix_eval::Evaluation::new(src, None);
|
||||
let mut eval = tvix_eval::Evaluation::new(src, None);
|
||||
eval.strict = true;
|
||||
let source = eval.source_map();
|
||||
let result = eval.evaluate();
|
||||
|
||||
|
|
Loading…
Reference in a new issue