refactor(tvix/eval): Simplify forcing in builtins

Refactor the `force!` macro to a method on `Value` which returns a
smart-pointer-esque type, which simplifies the callsite and eliminates
rightward drift, especially for high-arity builtins.

Change-Id: I97a7837580accfb4bbd03b24f2acdbd38645efa5
Reviewed-on: https://cl.tvl.fyi/c/depot/+/6656
Autosubmit: grfn <grfn@gws.fyi>
Reviewed-by: tazjin <tazjin@tvl.su>
Tested-by: BuildkiteCI
This commit is contained in:
Griffin Smith 2022-09-18 16:53:08 -04:00 committed by grfn
parent bcbe1603c8
commit 69cbcc1eda
2 changed files with 90 additions and 97 deletions

View file

@ -1,5 +1,7 @@
//! This module implements the backing representation of runtime
//! values in the Nix language.
use std::cell::Ref;
use std::ops::Deref;
use std::rc::Rc;
use std::{fmt::Display, path::PathBuf};
@ -95,6 +97,26 @@ pub enum CoercionKind {
Strong,
}
/// A reference to a [`Value`] returned by a call to [`Value::force`], whether the value was
/// originally a thunk or not.
///
/// Implements [`Deref`] to [`Value`], so can generally be used as a [`Value`]
pub(crate) enum ForceResult<'a> {
ForcedThunk(Ref<'a, Value>),
Immediate(&'a Value),
}
impl<'a> Deref for ForceResult<'a> {
type Target = Value;
fn deref(&self) -> &Self::Target {
match self {
ForceResult::ForcedThunk(r) => r,
ForceResult::Immediate(v) => v,
}
}
}
impl Value {
/// Coerce a `Value` to a string. See `CoercionKind` for a rundown of what
/// input types are accepted under what circumstances.
@ -292,6 +314,17 @@ impl Value {
_ => Ok(false),
}
}
/// Ensure `self` is forced if it is a thunk, and return a reference to the resulting value.
pub(crate) fn force(&self, vm: &mut VM) -> Result<ForceResult, ErrorKind> {
match self {
Self::Thunk(thunk) => {
thunk.force(vm)?;
Ok(ForceResult::ForcedThunk(thunk.value()))
}
_ => Ok(ForceResult::Immediate(self)),
}
}
}
impl Display for Value {