feat(tvix/eval): Implement builtins.deepSeq

This is done via a new `deepForce` function on Value. Since values can
be cyclical (for example, see the test-case), we need to do some extra
work to avoid RefCell borrow errors if we ever hit a graph cycle:

While deep-forcing values, we keep a set of thunks that we have
already seen and avoid doing any work on the same thunk twice. The set
is encapsulated in a separate type to stop potentially invalid
pointers from leaking out.

Finally, since deep_force is conceptually similar to
`VM::force_for_output` (but more suited to usage in eval since it
doesn't clone the values) this removes the latter, replacing it with
the former.

Co-Authored-By: Vincent Ambo <tazjin@tvl.su>
Change-Id: Iefddefcf09fae3b6a4d161a5873febcff54b9157
Reviewed-on: https://cl.tvl.fyi/c/depot/+/7000
Tested-by: BuildkiteCI
Reviewed-by: grfn <grfn@gws.fyi>
Reviewed-by: tazjin <tazjin@tvl.su>
This commit is contained in:
Griffin Smith 2022-10-12 22:47:23 -04:00 committed by grfn
parent 8724d2fff8
commit d4fa3152e9
10 changed files with 100 additions and 62 deletions

View file

@ -191,6 +191,16 @@ fn pure_builtins() -> Vec<Builtin> {
Ok(res.into())
},
),
Builtin::new(
"deepSeq",
&[true, true],
|mut args: Vec<Value>, vm: &mut VM| {
let arg2 = args.pop().unwrap();
let arg1 = args.pop().unwrap();
arg1.deep_force(vm, &mut Default::default())?;
Ok(arg2)
},
),
Builtin::new(
"div",
&[false, false],