Skip to main content

ThunkRepr

Enum ThunkRepr 

Source
pub enum ThunkRepr {
    Suspended {
        expr: Expr,
        env: Env,
    },
    InheritSelect {
        source_thunk: Thunk,
        name: SmolStr,
    },
    Native(Box<dyn FnOnce() -> Result<Value, EvalError>>),
    WithIdent {
        name: SmolStr,
        scope_cache: Rc<RefCell<Option<NixAttrs>>>,
        scope_value: Value,
        env: Env,
    },
    Blackhole,
    Promise(Rc<RefCell<Value>>),
    Failed(EvalError),
    Evaluated(Box<Value>),
    EvaluatedConcrete,
}
Expand description

Internal representation of a thunk’s state machine.

Transitions: SuspendedBlackholeEvaluated (on success), or SuspendedBlackholeSuspended (on failure, to allow retry).

Variants§

§

Suspended

Not yet evaluated. Holds the AST expression and captured environment.

Fields

§expr: Expr
§env: Env
§

InheritSelect

Pending inherit (source) name selection. When forced, forces the shared source_thunk and pulls out name.

The source_thunk is created once per inherit (source) a b c clause and shared (via Rc clone) across all inherited names. This means N names share one source evaluation instead of N independent evaluations — the source thunk’s own memoization ensures it is evaluated at most once.

This is its own variant (rather than synthesizing a Select AST node) because rnix doesn’t expose a public AST builder, and we want each inherited name to defer evaluation of the source expression so that inherit (lib.trivial) ... at the top of trivial.nix doesn’t blackhole on the still-being-constructed lib.trivial.

Fields

§source_thunk: Thunk
§name: SmolStr
§

Native(Box<dyn FnOnce() -> Result<Value, EvalError>>)

A lazy value backed by a Rust closure. Used for flake input evaluation: the closure calls evaluate_flake on first access instead of eagerly during flake setup, matching CppNix semantics where each input’s outputs function is wrapped in a thunk.

§

WithIdent

A deferred with-scope ident lookup. Stores a direct reference to the with-scope’s shared cache and the ident name. When forced, checks the cache for the resolved attrset and looks up the name — O(1) hash lookup, no Env traversal, no fixpoint re-forcing.

This is the construction-guarantee solution for the with-scope fixpoint problem: instead of creating 80K+ Env-capturing thunks (each doing a full lookup on force), we create 80K lightweight cache-referencing thunks that share the same resolved attrset.

Fields

§name: SmolStr

The ident name to look up

§scope_cache: Rc<RefCell<Option<NixAttrs>>>

Direct reference to the with-scope’s cached attrset. Shared via Rc — all idents from the same with scope reference the same cache. When ANY lookup forces the scope, the cache is populated and all subsequent WithIdent forces are O(1).

§scope_value: Value

The scope value (for initial force if cache is empty)

§env: Env

Fallback: the full env for lexical+outer-scope lookup if the with-scope doesn’t contain this name

§

Blackhole

Currently being evaluated – detects infinite recursion.

§

Promise(Rc<RefCell<Value>>)

Currently being evaluated, but the thunk is known to be self-recursive (its RHS references the bound name). Inner re-entrance returns the partial value from the cell instead of erroring with InfiniteRecursion — matches cppnix’s let x = f x; in x semantics where inner accesses to x see the not-yet-complete attrset under construction.

The cell starts as Value::Attrs(empty) (the cheapest sentinel that propagates through mapAttrs / attrNames / concatMap without further type errors). When the body completes, the cell is replaced with the final value and the repr transitions to Evaluated.

§

Failed(EvalError)

A Native (FnOnce) thunk whose closure already ran and FAILED. The closure is consumed and cannot be retried, so we memoize the error itself and re-raise it on every subsequent force. This is the correctness-preserving replacement for the old Evaluated(Null) poisoning: a thunk that threw on its first force MUST NOT silently become null on a second read (which turned a swallowed transient flake-input error into a bogus AttrNotFound/cannot select from set far downstream — the stylix darwinModules marquee root). A re-force re-throws the original error, exactly as cppnix re-throws a thunk that failed.

§

Evaluated(Box<Value>)

Already evaluated and memoized as a THUNK value. The cache OnceCell is intentionally empty for this variant (caching a thunk would spin force_value), so the boxed Value is the sole store.

§

EvaluatedConcrete

Already evaluated and memoized as a CONCRETE (non-thunk) value. The value lives ONLY in the cache OnceCell (Box<Concrete>); this variant is a valueless terminal marker that collapses the former double-store (a redundant Evaluated(Box<Value>) alongside the cache). Any reader that finds this marker reconstructs the Value from cache via Concrete::into_value(), which is a byte-identical, lossless inverse of demand_unchecked (same enum shape, moves the inner Rc/Box — preserving string context and list/attrs Rc identity). In practice the cache fast path in force/force_inner returns before this arm is ever matched.

Auto Trait Implementations§

Blanket Implementations§

Source§

impl<T> Any for T
where T: 'static + ?Sized,

Source§

fn type_id(&self) -> TypeId

Gets the TypeId of self. Read more
Source§

impl<T> ArchivePointee for T

Source§

type ArchivedMetadata = ()

The archived version of the pointer metadata for this type.
Source§

fn pointer_metadata( _: &<T as ArchivePointee>::ArchivedMetadata, ) -> <T as Pointee>::Metadata

Converts some archived metadata to the pointer metadata for itself.
Source§

impl<T> Borrow<T> for T
where T: ?Sized,

Source§

fn borrow(&self) -> &T

Immutably borrows from an owned value. Read more
Source§

impl<T> BorrowMut<T> for T
where T: ?Sized,

Source§

fn borrow_mut(&mut self) -> &mut T

Mutably borrows from an owned value. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

Source§

impl<T> Instrument for T

Source§

fn instrument(self, span: Span) -> Instrumented<Self>

Instruments this type with the provided Span, returning an Instrumented wrapper. Read more
Source§

fn in_current_span(self) -> Instrumented<Self>

Instruments this type with the current Span, returning an Instrumented wrapper. Read more
Source§

impl<T, U> Into<U> for T
where U: From<T>,

Source§

fn into(self) -> U

Calls U::from(self).

That is, this conversion is whatever the implementation of From<T> for U chooses to do.

Source§

impl<T> LayoutRaw for T

Source§

fn layout_raw(_: <T as Pointee>::Metadata) -> Result<Layout, LayoutError>

Returns the layout of the type.
Source§

impl<T, N1, N2> Niching<NichedOption<T, N1>> for N2
where T: SharedNiching<N1, N2>, N1: Niching<T>, N2: Niching<T>,

Source§

unsafe fn is_niched(niched: *const NichedOption<T, N1>) -> bool

Returns whether the given value has been niched. Read more
Source§

fn resolve_niched(out: Place<NichedOption<T, N1>>)

Writes data to out indicating that a T is niched.
Source§

impl<T> Pointee for T

Source§

type Metadata = ()

The metadata type for pointers and references to this type.
Source§

impl<T> PolicyExt for T
where T: ?Sized,

Source§

fn and<P, B, E>(self, other: P) -> And<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow only if self and other return Action::Follow. Read more
Source§

fn or<P, B, E>(self, other: P) -> Or<T, P>
where T: Sized + Policy<B, E>, P: Policy<B, E>,

Create a new Policy that returns Action::Follow if either self or other returns Action::Follow. Read more
Source§

impl<T> Same for T

Source§

type Output = T

Should always be Self
Source§

impl<T, U> TryFrom<U> for T
where U: Into<T>,

Source§

type Error = Infallible

The type returned in the event of a conversion error.
Source§

fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>

Performs the conversion.
Source§

impl<T, U> TryInto<U> for T
where U: TryFrom<T>,

Source§

type Error = <U as TryFrom<T>>::Error

The type returned in the event of a conversion error.
Source§

fn try_into(self) -> Result<U, <U as TryFrom<T>>::Error>

Performs the conversion.
Source§

impl<T> WithSubscriber for T

Source§

fn with_subscriber<S>(self, subscriber: S) -> WithDispatch<Self>
where S: Into<Dispatch>,

Attaches the provided Subscriber to this type, returning a WithDispatch wrapper. Read more
Source§

fn with_current_subscriber(self) -> WithDispatch<Self>

Attaches the current default Subscriber to this type, returning a WithDispatch wrapper. Read more