Subst

Struct Subst 

Source
pub struct Subst { /* private fields */ }
Expand description

A unification variable’s binding, shared so that unifying in one place is visible everywhere.

Implementations§

Source§

impl Subst

Source

pub fn new() -> Subst

Source

pub fn fresh(&self) -> Ty

Source

pub fn fresh_row_var(&self) -> RowVarId

Source

pub fn fresh_row(&self) -> Row

Source

pub fn resolve(&self, t: &Ty) -> Ty

Fully apply the substitution — what diagnostics and the emitted Core see.

Source

pub fn resolve_row(&self, r: &Row) -> Row

Expand a row through its variable bindings, to a fixed point.

The seen set is not a safety net; it is the semantics. A definition’s row variable can be bound to a row that mentions itself — that is what mutual recursion between two effectful functions is — and because a row is a union, stopping at an already-expanded variable computes exactly the least fixed point rather than diverging.

Source

pub fn bind_row(&self, v: RowVarId, r: Row)

Source

pub fn instantiate(&self, s: &Scheme) -> Ty

Instantiate a scheme with fresh type and row variables.

Source

pub fn instantiate_named(&self, s: &Scheme) -> (Ty, BTreeMap<Arc<str>, Ty>)

Subst::instantiate, and the fresh variable each named parameter became.

A bounded definition needs the map: def sort[T: Ord](xs: list[T]) is lowered with a dictionary parameter per method of Ord, and the call site can only say which impl to pass once it knows what this call’s T turned out to be. docs/39 §39.4.

Source

pub fn unify_join(&self, a: &Ty, b: &Ty) -> Result<Ty, Mismatch>

Unify two types that are alternatives rather than actual-and-expected, and return the type of whichever one runs.

Subst::unify is asymmetric on purpose: its first argument is the actual type and its second the expected one, and Subst::subsume_row leans on that so a function which does less than its context allows is accepted. The two branches of an if are neither. Making one of them the “expected” type of the other says that a branch returning identity — inferred pure, so its row is closed — is the standard the other branch has to meet, and the other branch returning a call’s result carries a row variable. A variable is not a subset of the empty row, so the two are reported as a conflict, with nothing missing to name:

error[B0320]: the two branches may not perform {} here

which is docs/25-benchmarks-and-expressiveness.md §25.6 item 6, and what exercise 1.43 costs. The answer is the one every row-typed language reaches: the alternatives do not meet each other, they both flow into a fresh row, and the result performs whatever either of them might. Sound in the direction §3.2 requires — the join contains both branches’ atoms, so an effect can never be lost — and it leaves a free tail, exactly as a written function type does, so a later context may widen it again.

Source

pub fn unify(&self, a: &Ty, b: &Ty) -> Result<(), Mismatch>

Source

pub fn subsume_row(&self, actual: &Row, expected: &Row) -> Result<(), Mismatch>

Require actual ⊆ expected — the effect-row subsumption §3.1 permits and nothing else.

Rows are sets, so this is: whatever the actual row does, the expected row must already allow, or must have a variable free to absorb it. Concretely, three cases and no more:

  • everything the actual side does is already named on the expected side — nothing to do;
  • the expected side has a free row variable — bind it to the difference, leaving a fresh variable behind so a later call site can widen it again. This is what makes (a -> b ! e) accept a pure function at one call and an effectful one at the next;
  • the expected side is closed and lacks something — the rows genuinely differ, and that is the error.

The direction is the design. Equality would make a pure lambda fail to match (a -> b ! e) unless e were solved first, and would make the same higher-order function unusable at two call sites with different arguments. Subsumption over-approximates in one direction only: a definition’s inferred row may be a superset of what one call actually performs, which can cost a placement candidate but can never lose an effect.

Source

pub fn rows_equal(&self, a: &Row, b: &Row) -> bool

Two rows denote the same set of effects. Used where a signature is compared rather than checked — .becki agreement and --wire-compat.

Source

pub fn free_vars(&self, t: &Ty, out: &mut Vec<TyVarId>)

The free variables of a resolved type.

Source

pub fn free_row_vars(&self, t: &Ty, out: &mut Vec<RowVarId>)

The free row variables of a resolved type — what a definition generalises over.

Trait Implementations§

Source§

impl Clone for Subst

Source§

fn clone(&self) -> Subst

Returns a duplicate of the value. Read more
1.0.0 · Source§

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

Performs copy-assignment from source. Read more
Source§

impl Debug for Subst

Source§

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

Formats the value using the given formatter. Read more
Source§

impl Default for Subst

Source§

fn default() -> Subst

Returns the “default value” for a type. Read more

Auto Trait Implementations§

§

impl Freeze for Subst

§

impl !RefUnwindSafe for Subst

§

impl !Send for Subst

§

impl !Sync for Subst

§

impl Unpin for Subst

§

impl !UnwindSafe for Subst

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.