Struct rusttyc::TcKey [−][src]
An inexpensive and simple indexing mechanism using during the type checking procedure.
It can that can be copied, checked for equality, and hashed, however, it is not ordered. A TcKey offers functions for relating them to other keys or types, symmetrically or asymmetrically, by creating constraints. These constraints only serve one purpose: They can be passed to the type checker's crate::TypeChecker::impose() function.
Example
There are several kinds of constraints that can be generated for a key. Assume the following data structures exist:
use rusttyc::{Variant, TcKey, TypeChecker, TcVar, TcErr, Partial, Arity}; #[derive(Debug, Clone, Copy, PartialEq, Eq)] enum MyVariant { Top, Numeric, UInt, U8, String, } impl Variant for MyVariant { type Err = String; fn meet(lhs: Partial<Self>, rhs: Partial<Self>) -> Result<Partial<Self>, Self::Err> { use MyVariant::*; let variant = match (lhs.variant, rhs.variant) { (Top, x) | (x, Top) => Ok(x), (String, String) => Ok(String), (String, _) | (_, String) => Err("string can only be met with string.".to_string()), (Numeric, x) | (x, Numeric) => Ok(x), // x can only be Numeric, UInt, or U8. (UInt, x) | (x, UInt) => Ok(x), // x can only be UInt or U8. (U8, U8) => Ok(U8), }?; Ok(Partial { variant, least_arity: 0 }) } fn top() -> Self { Self::Top } fn arity(&self) -> Arity { Arity::Fixed(0) } } #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] struct MyVar(u8); impl TcVar for MyVar {}
The type checking procedure can then proceed as follows.
#[derive(Debug, Clone, Copy, PartialEq, Eq)] enum MyVariant { Top, Numeric, UInt, U8, String, } impl Variant for MyVariant { type Err = String; fn meet(lhs: Partial<Self>, rhs: Partial<Self>) -> Result<Partial<Self>, Self::Err> { use MyVariant::*; let variant = match (lhs.variant, rhs.variant) { (Top, x) | (x, Top) => Ok(x), (String, String) => Ok(String), (String, _) | (_, String) => Err("string can only be met with string.".to_string()), (Numeric, x) | (x, Numeric) => Ok(x), // x can only be Numeric, UInt, or U8. (UInt, x) | (x, UInt) => Ok(x), // x can only be UInt or U8. (U8, U8) => Ok(U8), }?; Ok(Partial { variant, least_arity: 0 }) } fn top() -> Self { Self::Top } fn arity(&self) -> Arity { Arity::Fixed(0) } } #[derive(PartialEq, Eq, Hash, Clone, Copy, Debug)] struct MyVar(u8); impl TcVar for MyVar {} let mut tc: TypeChecker<MyVariant, MyVar> = TypeChecker::new(); let key1 = tc.new_term_key(); let key2 = tc.new_term_key(); let key3 = tc.new_term_key(); let key4 = tc.new_term_key(); tc.impose(key1.concretizes_explicit(MyVariant::Numeric))?; // key1 is numeric. // key2 is at least as concrete as k1, i.e. it will also be numeric. tc.impose(key2.concretizes(key1))?; tc.impose(key3.equate_with(key2))?; // key3 is the same type as key2, i.e., numeric let tt = tc.clone().type_check_preliminary()?; assert_eq!(tt[&key1].variant, MyVariant::Numeric); assert_eq!(tt[&key2].variant, MyVariant::Numeric); assert_eq!(tt[&key3].variant, MyVariant::Numeric); // we did not impose a constraint on it, yet, so its the top element. assert_eq!(tt[&key4].variant, MyVariant::Top); // Concretize key3 to be a UInt. Also affects key2 due to unification. // key1 is unaffected because of the asymmetric relation between key1 and key2, // which translates to an asymmetric relation between key1 and key3 as well. tc.impose(key3.concretizes_explicit(MyVariant::UInt))?; let tt = tc.clone().type_check_preliminary()?; assert_eq!(tt[&key1].variant, MyVariant::Numeric); assert_eq!(tt[&key2].variant, MyVariant::UInt); assert_eq!(tt[&key3].variant, MyVariant::UInt); assert_eq!(tt[&key4].variant, MyVariant::Top); // key4 is more concrete than both key2 (and transitively key3), and key1, so it becomes a UInt. tc.impose(key4.is_meet_of(key2, key1))?; // Make key2 and key3 U8. key4 depends on them, so it becomes U8 as well. key1 is unaffected. tc.impose(key2.concretizes_explicit(MyVariant::U8))?; let key5 = tc.new_term_key(); tc.impose(key5.concretizes_explicit(MyVariant::String))?; // key5 is a string. let tt = tc.clone().type_check_preliminary()?; assert_eq!(tt[&key1].variant, MyVariant::Numeric); assert_eq!(tt[&key2].variant, MyVariant::U8); assert_eq!(tt[&key3].variant, MyVariant::U8); assert_eq!(tt[&key4].variant, MyVariant::U8); assert_eq!(tt[&key5].variant, MyVariant::String); let key6 = tc.new_term_key(); // key6 is the meet of all other keys. tc.impose(key6.is_meet_of_all(&[key1, key2, key3, key4, key5]))?; let res = tc.type_check_preliminary(); // The meet of numeric types and strings will fail, so key6 cannot be resolved. assert!(res.is_err());
Implementations
impl TcKey
[src]
pub fn concretizes<V: ContextSensitiveVariant>(
self,
bound: Self
) -> Constraint<V>
[src]
self,
bound: Self
) -> Constraint<V>
Connects two keys asymmetrically. Refining bound
refines self
whereas refining self
leaves bound
unaffected.
pub fn equate_with<V: ContextSensitiveVariant>(
self,
other: Self
) -> Constraint<V>
[src]
self,
other: Self
) -> Constraint<V>
Equates two keys, i.e., they refer to the same type and are thus symmetrically connected. Refining one will refine the other as well.
pub fn concretizes_explicit<V: ContextSensitiveVariant>(
self,
bound: V
) -> Constraint<V>
[src]
self,
bound: V
) -> Constraint<V>
Declares that self
is at least as concrete as bound
.
pub fn is_meet_of<V: ContextSensitiveVariant>(
self,
left: Self,
right: Self
) -> Constraint<V>
[src]
self,
left: Self,
right: Self
) -> Constraint<V>
Declares that self
is the meet of left
and right
.
This binds self
to both left
and right
asymmetrically.
pub fn is_meet_of_all<V: ContextSensitiveVariant>(
self,
elems: &[Self]
) -> Constraint<V>
[src]
self,
elems: &[Self]
) -> Constraint<V>
Declares that self
is the meet of all elements contained in elems
.
This binds self
to all of these keys asymmetrically.
pub fn is_sym_meet_of<V: ContextSensitiveVariant>(
self,
left: Self,
right: Self
) -> Constraint<V>
[src]
self,
left: Self,
right: Self
) -> Constraint<V>
Declares that self
is the symmetric meet of left
and right
.
This binds self
to both left
and right
symmetrically.
pub fn is_sym_meet_of_all<V: ContextSensitiveVariant>(
self,
elems: &[Self]
) -> Constraint<V>
[src]
self,
elems: &[Self]
) -> Constraint<V>
Declares that self
is the symmetric meet of all elements contained in elems
.
This binds self
to all of these keys symmetrically.
Trait Implementations
impl Clone for TcKey
[src]
impl Copy for TcKey
[src]
impl Debug for TcKey
[src]
impl Eq for TcKey
[src]
impl Hash for TcKey
[src]
fn hash<__H: Hasher>(&self, state: &mut __H)
[src]
pub fn hash_slice<H>(data: &[Self], state: &mut H) where
H: Hasher,
1.3.0[src]
H: Hasher,
impl Ord for TcKey
[src]
fn cmp(&self, other: &TcKey) -> Ordering
[src]
#[must_use]pub fn max(self, other: Self) -> Self
1.21.0[src]
#[must_use]pub fn min(self, other: Self) -> Self
1.21.0[src]
#[must_use]pub fn clamp(self, min: Self, max: Self) -> Self
1.50.0[src]
impl PartialEq<TcKey> for TcKey
[src]
impl PartialOrd<TcKey> for TcKey
[src]
fn partial_cmp(&self, other: &TcKey) -> Option<Ordering>
[src]
fn lt(&self, other: &TcKey) -> bool
[src]
fn le(&self, other: &TcKey) -> bool
[src]
fn gt(&self, other: &TcKey) -> bool
[src]
fn ge(&self, other: &TcKey) -> bool
[src]
impl StructuralEq for TcKey
[src]
impl StructuralPartialEq for TcKey
[src]
Auto Trait Implementations
impl RefUnwindSafe for TcKey
[src]
impl Send for TcKey
[src]
impl Sync for TcKey
[src]
impl Unpin for TcKey
[src]
impl UnwindSafe for TcKey
[src]
Blanket Implementations
impl<T> Any for T where
T: 'static + ?Sized,
[src]
T: 'static + ?Sized,
impl<T> Borrow<T> for T where
T: ?Sized,
[src]
T: ?Sized,
impl<T> BorrowMut<T> for T where
T: ?Sized,
[src]
T: ?Sized,
pub fn borrow_mut(&mut self) -> &mut T
[src]
impl<T> From<T> for T
[src]
impl<T, U> Into<U> for T where
U: From<T>,
[src]
U: From<T>,
impl<T> ToOwned for T where
T: Clone,
[src]
T: Clone,
type Owned = T
The resulting type after obtaining ownership.
pub fn to_owned(&self) -> T
[src]
pub fn clone_into(&self, target: &mut T)
[src]
impl<T, U> TryFrom<U> for T where
U: Into<T>,
[src]
U: Into<T>,
type Error = Infallible
The type returned in the event of a conversion error.
pub fn try_from(value: U) -> Result<T, <T as TryFrom<U>>::Error>
[src]
impl<T, U> TryInto<U> for T where
U: TryFrom<T>,
[src]
U: TryFrom<T>,