flux_middle::rty

Struct SubsetTy

Source
pub struct SubsetTy {
    pub bty: BaseTy,
    pub idx: Expr,
    pub pred: Expr,
}
Expand description

A subset type is a simplified version of a type that has the form {b[e] | p} where b is a BaseTy, e a refinement index, and p a predicate.

These are mainly found under a Binder with a single variable of the base type’s sort. This can be interpreted as a type constructor or an existial type. For example, under a binder with a variable v of sort int, we can interpret {i32[v] | v > 0} as:

  • A lambda λv:int. {i32[v] | v > 0} that “constructs” types when applied to ints, or
  • An existential type ∃v:int. {i32[v] | v > 0}.

This second interpretation is the reason we call this a subset type, i.e., the type ∃v. {b[v] | p} corresponds to the subset of values of type b whose index satisfies p. These are the types written as B{v: p} in the surface syntax and correspond to the types supported in other refinement type systems like Liquid Haskell (with the difference that we are explicit about separating refinements from program values via an index).

The main purpose for subset types is to be used as generic arguments of kind base when interpreted as type constructors. They have two key properties that makes them suitable for this:

  1. Syntacitc Restriction: Subset types are syntactically restricted, making it easier to relate them structurally (e.g., for subtyping). For instance, given two types S<λv. T1> and S<λ. T2>, if T1 and T2 are subset types, we know they match structurally (at least shallowly). In particularly, the syntactic restriction rules out complex types like S<λv. (i32[v], i32[v])> simplifying some operations.

  2. Eager Canonicalization: Subset types can be eagerly canonicalized via strengthening during substitution. For example, suppose we have a function:

    fn foo<T>(x: T[@a], y: { T[@b] | b == a }) { }

    If we instantiate T with λv. { i32[v] | v > 0}, after substitution and applying the lambda (the indexing syntax T[a] corresponds to an application of the lambda), we get:

    fn foo(x: {i32[@a] | a > 0}, y: { { i32[@b] | b > 0 } | b == a }) { }

    Via strengthening we can canonicalize this to

    fn foo(x: {i32[@a] | a > 0}, y: { i32[@b] | b == a && b > 0 }) { }

    As a result, we can guarantee the syntactic restriction through substitution.

Fields§

§bty: BaseTy

The base type b in the subset type {b[e] | p}.

NOTE: This is mostly going to be under a Binder. It is not yet clear to me whether this BaseTy should be able to mention variables in the binder. In general, in a type ∃v. {b[e] | p}, it’s fine to mention v inside b, but since SubsetTy is meant to facilitate syntactic manipulation we may want to restrict this.

§idx: Expr

The refinement index e in the subset type {b[e] | p}. This can be an arbitrary expression, which makes manipulation easier. However, since this is mostly found under a binder, we expect it to be Expr::nu().

§pred: Expr

The predicate p in the subset type {b[e] | p}.

Implementations§

Source§

impl SubsetTy

Source

pub fn new(bty: BaseTy, idx: impl Into<Expr>, pred: impl Into<Expr>) -> Self

Source

pub fn trivial(bty: BaseTy, idx: impl Into<Expr>) -> Self

Source

pub fn strengthen(&self, pred: impl Into<Expr>) -> Self

Source

pub fn to_ty(&self) -> Ty

Trait Implementations§

Source§

impl Clone for SubsetTy

Source§

fn clone(&self) -> SubsetTy

Returns a copy 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 SubsetTy

Source§

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

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

impl<__D: TyDecoder> Decodable<__D> for SubsetTy

Source§

fn decode(__decoder: &mut __D) -> Self

Source§

impl<__E: TyEncoder> Encodable<__E> for SubsetTy

Source§

fn encode(&self, __encoder: &mut __E)

Source§

impl Hash for SubsetTy

Source§

fn hash<__H: Hasher>(&self, state: &mut __H)

Feeds this value into the given Hasher. Read more
1.3.0 · Source§

fn hash_slice<H>(data: &[Self], state: &mut H)
where H: Hasher, Self: Sized,

Feeds a slice of this type into the given Hasher. Read more
Source§

impl PartialEq for SubsetTy

Source§

fn eq(&self, other: &SubsetTy) -> bool

Tests for self and other values to be equal, and is used by ==.
1.0.0 · Source§

fn ne(&self, other: &Rhs) -> bool

Tests for !=. The default implementation is almost always sufficient, and should not be overridden without very good reason.
Source§

impl Pretty for SubsetTy

Source§

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

Source§

fn default_cx(tcx: TyCtxt<'_>) -> PrettyCx<'_>

Source§

impl<'tcx> ToRustc<'tcx> for SubsetTy

Source§

type T = Ty<'tcx>

Source§

fn to_rustc(&self, tcx: TyCtxt<'tcx>) -> Ty<'tcx>

Source§

impl TypeFoldable for SubsetTy

Source§

fn try_fold_with<F: FallibleTypeFolder>( &self, folder: &mut F, ) -> Result<Self, F::Error>

Source§

fn fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self

Source§

fn normalize_projections<'tcx>( &self, genv: GlobalEnv<'_, 'tcx>, infcx: &InferCtxt<'tcx>, callsite_def_id: DefId, ) -> QueryResult<Self>

Source§

fn normalize(&self, defns: &SpecFuncDefns) -> Self

Normalize expressions by applying beta reductions for tuples and lambda abstractions.
Source§

fn replace_holes( &self, f: impl FnMut(&[BoundVariableKinds], HoleKind) -> Expr, ) -> Self

Replaces all holes with the result of calling a closure. The closure takes a list with all the layers of bound variables at the point the hole was found. Each layer corresponds to the list of bound variables at that level. The list is ordered from outermost to innermost binder, i.e., the last element is the binder closest to the hole.
Source§

fn with_holes(&self) -> Self

Remove all refinements and turn each underlying BaseTy into a TyKind::Exists with a TyKind::Constr and a hole. For example, Vec<{v. i32[v] | v > 0}>[n] becomes {n. Vec<{v. i32[v] | *}>[n] | *}.
Source§

fn replace_evars(&self, evars: &EVarSol) -> Self

Source§

fn shift_in_escaping(&self, amount: u32) -> Self

Source§

fn shift_out_escaping(&self, amount: u32) -> Self

Source§

fn erase_regions(&self) -> Self

Source§

impl TypeSuperFoldable for SubsetTy

Source§

fn try_super_fold_with<F: FallibleTypeFolder>( &self, folder: &mut F, ) -> Result<Self, F::Error>

Source§

fn super_fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self

Source§

impl TypeVisitable for SubsetTy

Source§

fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>

Source§

fn has_escaping_bvars(&self) -> bool

Source§

fn has_escaping_bvars_at_or_above(&self, binder: DebruijnIndex) -> bool

Returns true if self has any late-bound vars that are either bound by binder or bound by some binder outside of binder. If binder is ty::INNERMOST, this indicates whether there are any late-bound vars that appear free.
Source§

fn fvars(&self) -> FxHashSet<Name>

Returns the set of all free variables. For example, Vec<i32[n]>{v : v > m} returns {n, m}.
Source§

impl Eq for SubsetTy

Source§

impl StructuralPartialEq for SubsetTy

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, dst: *mut T)

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

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Checks if this value is equivalent to the given key. Read more
§

impl<Q, K> Equivalent<K> for Q
where Q: Eq + ?Sized, K: Borrow<Q> + ?Sized,

§

fn equivalent(&self, key: &K) -> bool

Compare self to key and return true if they are equal.
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> IntoEither for T

Source§

fn into_either(self, into_left: bool) -> Either<Self, Self>

Converts self into a Left variant of Either<Self, Self> if into_left is true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
where F: FnOnce(&Self) -> bool,

Converts self into a Left variant of Either<Self, Self> if into_left(&self) returns true. Converts self into a Right variant of Either<Self, Self> otherwise. Read more
Source§

impl<P> IntoQueryParam<P> for P

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.