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:
-
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>
andS<λ. T2>
, ifT1
andT2
are 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
T
withλ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: 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§
Trait Implementations§
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
fn normalize_projections<'tcx>( &self, genv: GlobalEnv<'_, 'tcx>, infcx: &InferCtxt<'tcx>, callsite_def_id: DefId, ) -> QueryResult<Self>
Source§fn normalize(&self, defns: &SpecFuncDefns) -> Self
fn normalize(&self, defns: &SpecFuncDefns) -> 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, evars: &EVarSol) -> 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.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,
Source§unsafe fn clone_to_uninit(&self, dst: *mut T)
unsafe fn clone_to_uninit(&self, dst: *mut T)
clone_to_uninit
)§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.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