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 existential 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:
-
Syntactic 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>andS<λ. T2>, ifT1andT2are subset types, we know they match structurally (at least shallowly). In particularly, the syntactic restriction rules out complex types likeS<λv. (i32[v], i32[v])>simplifying some operations. -
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
Twithλv. { i32[v] | v > 0}, after substitution and applying the lambda (the indexing syntaxT[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: BaseTyThe 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: ExprThe 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: ExprThe predicate p in the subset type {b[e] | p}.
Implementations§
Trait Implementations§
Source§impl PrettyNested for SubsetTy
impl PrettyNested for SubsetTy
fn fmt_nested(&self, cx: &PrettyCx<'_, '_>) -> Result<NestedString, Error>
fn nested_string(&self, cx: &PrettyCx<'_, '_>) -> String
Source§impl TypeFoldable for SubsetTy
impl TypeFoldable for SubsetTy
fn try_fold_with<F: FallibleTypeFolder>( &self, folder: &mut F, ) -> Result<Self, F::Error>
fn fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self
Source§fn normalize(&self, genv: GlobalEnv<'_, '_>) -> Self
fn normalize(&self, genv: GlobalEnv<'_, '_>) -> Self
Source§fn replace_holes(
&self,
f: impl FnMut(&[BoundVariableKinds], HoleKind) -> Expr,
) -> Self
fn replace_holes( &self, f: impl FnMut(&[BoundVariableKinds], HoleKind) -> Expr, ) -> Self
Source§fn with_holes(&self) -> Self
fn with_holes(&self) -> Self
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] | *}.fn replace_evars( &self, f: &mut impl FnMut(EVid) -> Option<Expr>, ) -> Result<Self, EVid>
Source§fn shift_horizontally(&self, amount: usize) -> Self
fn shift_horizontally(&self, amount: usize) -> Self
fn shift_in_escaping(&self, amount: u32) -> Self
fn shift_out_escaping(&self, amount: u32) -> Self
fn erase_regions(&self) -> Self
Source§impl TypeSuperFoldable for SubsetTy
impl TypeSuperFoldable for SubsetTy
fn try_super_fold_with<F: FallibleTypeFolder>( &self, folder: &mut F, ) -> Result<Self, F::Error>
fn super_fold_with<F: TypeFolder>(&self, folder: &mut F) -> Self
Source§impl TypeVisitable for SubsetTy
impl TypeVisitable for SubsetTy
fn visit_with<V: TypeVisitor>(&self, visitor: &mut V) -> ControlFlow<V::BreakTy>
fn has_escaping_bvars(&self) -> bool
Source§fn has_escaping_bvars_at_or_above(&self, binder: DebruijnIndex) -> bool
fn has_escaping_bvars_at_or_above(&self, binder: DebruijnIndex) -> bool
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>
fn fvars(&self) -> FxHashSet<Name>
Vec<i32[n]>{v : v > m} returns {n, m}.fn early_params(&self) -> FxHashSet<EarlyReftParam>
Source§fn redundant_bvars(&self) -> FxHashSet<BoundVar>
fn redundant_bvars(&self) -> FxHashSet<BoundVar>
impl Eq for SubsetTy
impl StructuralPartialEq for SubsetTy
Auto Trait Implementations§
impl Freeze for SubsetTy
impl RefUnwindSafe for SubsetTy
impl Send for SubsetTy
impl Sync for SubsetTy
impl Unpin for SubsetTy
impl UnwindSafe for SubsetTy
Blanket Implementations§
Source§impl<T> BorrowMut<T> for Twhere
T: ?Sized,
impl<T> BorrowMut<T> for Twhere
T: ?Sized,
Source§fn borrow_mut(&mut self) -> &mut T
fn borrow_mut(&mut self) -> &mut T
Source§impl<T> CloneToUninit for Twhere
T: Clone,
impl<T> CloneToUninit for Twhere
T: Clone,
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
§impl<Q, K> Equivalent<K> for Q
impl<Q, K> Equivalent<K> for Q
§fn equivalent(&self, key: &K) -> bool
fn equivalent(&self, key: &K) -> bool
key and return true if they are equal.§impl<T> Instrument for T
impl<T> Instrument for T
§fn instrument(self, span: Span) -> Instrumented<Self>
fn instrument(self, span: Span) -> Instrumented<Self>
§fn in_current_span(self) -> Instrumented<Self>
fn in_current_span(self) -> Instrumented<Self>
Source§impl<T> IntoEither for T
impl<T> IntoEither for T
Source§fn into_either(self, into_left: bool) -> Either<Self, Self>
fn into_either(self, into_left: bool) -> Either<Self, Self>
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 moreSource§fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
fn into_either_with<F>(self, into_left: F) -> Either<Self, Self>
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