Skip to main content

rill_lang/types/
ty.rs

1//! Type representation for the HM scalar layer.
2//!
3//! Scalar types classify the *element* type of a signal wire. Arities (wire
4//! counts) are synthesized separately (see `infer.rs`) because `<:`/`:>`
5//! divisibility is not expressible by unification.
6
7use std::collections::HashMap;
8
9/// A unification variable identifier.
10pub type TypeVarId = u32;
11
12/// The scalar (element) type of a wire.
13#[derive(Debug, Clone, PartialEq)]
14pub enum Scalar {
15    /// Integer.
16    Int,
17    /// Floating point (the runtime `T`).
18    Float,
19    /// Unresolved unification variable.
20    Var(TypeVarId),
21}
22
23/// A block/diagram type: the scalar type of each input and output wire.
24///
25/// The vector *lengths* are the arities. During inference we usually know the
26/// arities as concrete integers; unification only touches the `Scalar`s.
27#[derive(Debug, Clone, PartialEq)]
28pub struct Type {
29    /// Scalar type of each input wire (len = input arity).
30    pub ins: Vec<Scalar>,
31    /// Scalar type of each output wire (len = output arity).
32    pub outs: Vec<Scalar>,
33}
34
35impl Type {
36    /// A (n_in → n_out) type where every wire has the same scalar `s`.
37    pub fn uniform(n_in: usize, n_out: usize, s: Scalar) -> Type {
38        Type {
39            ins: vec![s.clone(); n_in],
40            outs: vec![s; n_out],
41        }
42    }
43    /// Input arity.
44    pub fn arity_in(&self) -> usize {
45        self.ins.len()
46    }
47    /// Output arity.
48    pub fn arity_out(&self) -> usize {
49        self.outs.len()
50    }
51}
52
53/// A polymorphic type scheme `∀ vars. ty` (for let-generalized definitions).
54#[derive(Debug, Clone, PartialEq)]
55pub struct Scheme {
56    /// Quantified type variables.
57    pub vars: Vec<TypeVarId>,
58    /// The generalized diagram type.
59    pub ty: Type,
60}
61
62/// A substitution mapping type variables to scalars.
63#[derive(Debug, Clone, Default)]
64pub struct Subst {
65    /// The mapping.
66    pub map: HashMap<TypeVarId, Scalar>,
67}
68
69impl Subst {
70    /// Follow the substitution chain for a single scalar to its representative.
71    pub fn resolve_scalar(&self, s: &Scalar) -> Scalar {
72        match s {
73            Scalar::Var(v) => match self.map.get(v) {
74                Some(inner) => self.resolve_scalar(inner),
75                None => s.clone(),
76            },
77            _ => s.clone(),
78        }
79    }
80    /// Apply the substitution across a whole type.
81    pub fn apply(&self, t: &Type) -> Type {
82        Type {
83            ins: t.ins.iter().map(|s| self.resolve_scalar(s)).collect(),
84            outs: t.outs.iter().map(|s| self.resolve_scalar(s)).collect(),
85        }
86    }
87}