fix(tvix/eval): thread Display & PartialEq through to thunk values
If a thunk is already evaluated, there are cases where due to the memoisation implementation something might observe a value wrapped in a thunk. In these cases, the implementation of `Display` and `PartialEq` must delegate to the underlying value. Note that there are a handful of other cases like these which we need to cover. It is a little tricky to write integration tests for these directly, especially as some of the open-upvalue optimisations coming down the pipe will reduce the number of observable thunks. One test that covers a part of this behaviour is currently disabled (needs some more machinery), but it's being brought back in the next commits. Change-Id: Iaa8cd338c12236af844bbc99d8cec2205f0d0095 Reviewed-on: https://cl.tvl.fyi/c/depot/+/6370 Reviewed-by: sterni <sternenseemann@systemli.org> Tested-by: BuildkiteCI
This commit is contained in:
parent
38d3db5fb8
commit
fea7f90a7f
2 changed files with 21 additions and 1 deletions
|
@ -172,8 +172,11 @@ impl Display for Value {
|
|||
write!(f, "{}", format!("{:.5}", num).trim_end_matches(['.', '0']))
|
||||
}
|
||||
|
||||
// Delegate thunk display to the type, as it must handle
|
||||
// the case of already evaluated thunks.
|
||||
Value::Thunk(t) => t.fmt(f),
|
||||
|
||||
// internal types
|
||||
Value::Thunk(_) => f.write_str("internal[thunk]"),
|
||||
Value::AttrPath(path) => write!(f, "internal[attrpath({})]", path.len()),
|
||||
Value::AttrNotFound => f.write_str("internal[not found]"),
|
||||
Value::Blueprint(_) => f.write_str("internal[blueprint]"),
|
||||
|
@ -203,6 +206,13 @@ impl PartialEq for Value {
|
|||
// Optimised attribute set comparison
|
||||
(Value::Attrs(a1), Value::Attrs(a2)) => Rc::ptr_eq(a1, a2) || { a1 == a2 },
|
||||
|
||||
// If either value is a thunk, the inner value must be
|
||||
// compared instead. The compiler should ensure that
|
||||
// thunks under comparison have been forced, otherwise it
|
||||
// is a bug.
|
||||
(Value::Thunk(lhs), rhs) => &*lhs.value() == rhs,
|
||||
(lhs, Value::Thunk(rhs)) => lhs == &*rhs.value(),
|
||||
|
||||
// Everything else is either incomparable (e.g. internal
|
||||
// types) or false.
|
||||
// TODO(tazjin): mirror Lambda equality behaviour
|
||||
|
|
|
@ -20,6 +20,7 @@
|
|||
|
||||
use std::{
|
||||
cell::{Ref, RefCell, RefMut},
|
||||
fmt::Display,
|
||||
rc::Rc,
|
||||
};
|
||||
|
||||
|
@ -131,3 +132,12 @@ impl UpvalueCarrier for Thunk {
|
|||
})
|
||||
}
|
||||
}
|
||||
|
||||
impl Display for Thunk {
|
||||
fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
|
||||
match &*self.0.borrow() {
|
||||
ThunkRepr::Evaluated(v) => v.fmt(f),
|
||||
_ => f.write_str("internal[thunk]"),
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue