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}