Skip to main content

ClosureBody

Enum ClosureBody 

Source
pub enum ClosureBody {
    Tree {
        params: Vec<Param>,
        block: Arc<Block>,
        decl: Option<Arc<FnDecl>>,
    },
    Linear(LinearClosure),
}
Expand description

Where a closure’s body is, which is the one thing about a closure the two backends do not agree on.

Everything else a closure is — what it captured, how many parameters it declares, which module it resolves names in, whether it is async — is the same fact whichever backend made it, and a host that receives one reads those the same way either way. The body is not: the interpreter walks a tree and the linear-memory backend runs a lowered function, and neither can run the other’s.

The declaration is part of the body, not part of the closure. The parameters an interpreted call binds against and the return type it coerces to are syntax, and syntax is one backend’s form of a body: a lowered function has neither, because cove_ir::lower spent both when it chose the slots and emitted the conversions. Keeping them beside the Arc<Block> they came from is what lets every field of a Closure outside this enum be a fact both backends state the same way, so that reaching syntax means reaching past the one variant that has any — which is the direction issue #109 asks for.

So this is an enum rather than a second Value variant. Issue #109 asks that the internal representation become less exposed to an embedder, not more, and a Value::LoweredClosure beside Value::Closure would make every host that already handles a callback handle two — while the difference between them is one field that no host reads. A host calls a closure back through crate::host::Reentry, which hands it to the backend that made it, and that backend is the only party that has to know which of these it is.

Variants§

§

Tree

The syntax crate::interp::Interpreter walks, and the declaration it walks it under.

Fields

§params: Vec<Param>

The parameters as source wrote them.

Interpreter::bind_params reads every field of one: the name to match a labelled argument against, variadic to know which arguments to gather, default to evaluate in the callee’s environment when an argument was left out, and is_var to bind the caller’s place rather than a copy — which is also what Interpreter::call_shared_method reads off the first parameter of a lock closure. The lowering answers that last question when it chooses the slots, and has no use for the other three.

§block: Arc<Block>

The block to evaluate.

§decl: Option<Arc<FnDecl>>

The declaration this closure came from, and None for a lambda, which has none of its own.

Read for the written return type: a dyn Trait in it is what tells the interpreter to wrap what the body produced. The lowered form needs no equivalent, because cove_ir::lower boxes what a function declared as erased returns, so the answer that leaves a lowered body is already wrapped.

§

Linear(LinearClosure)

The lowered function cove_runtime::vm runs, addressed in the cove_ir::Program that run was given, together with the environment object it closes over.

A closure built by one run cannot be called by another, which is true of the tree form as well: both name something a particular run owns. Which of the two a Closure holds is the question which backend made this, and crate::host::Reentry is the only thing that asks it.

The environment is here and the captures are not. A cove-ir closure’s captures are inline in a heap object, at the widths its layout says, and copying them out into Closure::captures would be materialising a value nothing asked for and losing the identity of the storage they came from. So the object crosses instead, as a LinearClosure, and Closure::captures is empty.

Trait Implementations§

Source§

impl Clone for ClosureBody

Source§

fn clone(&self) -> ClosureBody

Returns a duplicate of the value. Read more
1.0.0 (const: unstable) · Source§

fn clone_from(&mut self, source: &Self)

Performs copy-assignment from source. Read more
Source§

impl Debug for ClosureBody

Source§

fn fmt(&self, f: &mut Formatter<'_>) -> Result

Formats the value using the given formatter. Read more

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> 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> CloneToUninit for T
where T: Clone,

Source§

unsafe fn clone_to_uninit(&self, dest: *mut u8)

🔬This is a nightly-only experimental API. (clone_to_uninit)
Performs copy-assignment from self to dest. Read more
Source§

impl<T> From<T> for T

Source§

fn from(t: T) -> T

Returns the argument unchanged.

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> ToOwned for T
where T: Clone,

Source§

type Owned = T

The resulting type after obtaining ownership.
Source§

fn to_owned(&self) -> T

Creates owned data from borrowed data, usually by cloning. Read more
Source§

fn clone_into(&self, target: &mut T)

Uses borrowed data to replace owned data, usually by cloning. Read more
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.