1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
//! This create provides an interface for type checking some arbitrary structure.
//! It is based on an abstract type lattice that uses a union-find implementation (https://crates.io/crates/ena)
//! internally to successively constrain types.
//!
//! The main component is the `TypeChecker` struct, which is parametrized by a `Key` that implements the `ena::UnifyKey`
//! trait.  This trait in-turn requires an implementation of `EnaValue` and `type_checker::AbstractValue.
//! The `TypeChecker` manages a set of abstract types in a lattice-like structure and perform a union-find procedure to
//! derive the least concrete abstract type that satisfies a defined set of constraints.
//! Each abstract type is referred to with a key assigned by the `TypeChecker` (refer to
//! `TypeChecker::new_key(&mut self)`).
//!
//! # Usage
//! The `TypeChecker` requires two types: `Key` and `AbstractType`.
//! `Key` needs to implement `EnaKey`, which has an associated type `EnaKey::Value` that is the `AbstractType`.
//! Most of the time, the key is simply a `u32` in disguise.
//! The abstract type needs to implement `EnaValue` providing an abstract "meet" or "unification" function, and
//! `type_check::AbstractType`.
//! ```
//! use rusttyc::{ TypeCheckKey, TypeChecker, EnaValue, EnaKey };
//! use ena::unify::UnifyValue;
//! #[derive(Debug, PartialEq, Eq, Clone, Copy)]
//! struct Key(u32);
//! #[derive(Debug, PartialEq, Eq, Clone)]
//! enum AbstractType {
//!     Variant1,
//!     Unconstrained,
//!     /* ... */
//! }
//! impl rusttyc::AbstractType for AbstractType {
//!     fn unconstrained() -> Self {
//!         Self::Unconstrained
//!     }
//! }
//! impl EnaValue for AbstractType {
//!     type Error = ();
//!
//!     fn unify_values(value1: &Self, value2: &Self) -> Result<Self, Self::Error> {
//!         /* Do something meaningful. */
//!         return Ok(value1.clone())
//!     }
//! }
//! impl EnaKey for Key {
//!     type Value = AbstractType;
//!
//!     fn index(&self) -> u32 { self.0 }
//!
//!     fn from_index(u: u32) -> Self { Key(u) }
//!
//!     fn tag() -> &'static str { "key" }
//! }
//!
//! let mut tc: TypeChecker<Key> = TypeChecker::new();
//!
//! let first = tc.new_key();
//! let second = tc.new_key();
//!
//! assert!(tc.impose(second.bound_by_abstract(AbstractType::Variant1)).is_ok());
//! assert!(tc.impose(first.more_concrete_than(second)).is_ok());
//!
//! assert_eq!(tc.get_type(first), tc.get_type(second));
//! ```
//!
//! For a full example, refer to the example directory.

mod constraints;
mod reification;
#[cfg(test)]
mod tests;
mod type_checker;

pub use constraints::TypeConstraint;
pub use ena::unify::{UnifyKey as EnaKey, UnifyValue as EnaValue};
pub use reification::{Generalizable, Reifiable, ReificationError, TryReifiable};
pub use type_checker::{AbstractType, TypeCheckKey, TypeChecker};