catlog/tt/
val.rs

1//! Values for types and terms.
2//!
3//! See [crate::tt] for what this means.
4
5use bwd::Bwd;
6use derive_more::Constructor;
7use std::ops::Deref;
8
9use crate::{
10    tt::{prelude::*, stx::*},
11    zero::LabelSegment,
12};
13
14/// A way of resolving [BwdIdx] found in [TmS_::Var] to values
15pub type Env = Bwd<TmV>;
16
17/// The content of a record type value
18#[derive(Clone, Constructor)]
19pub struct RecordV {
20    /// The base type.
21    pub fields0: Row<Ty0>,
22    /// The closed-over environment.
23    pub env: Env,
24    /// The total types for the fields.
25    ///
26    /// These are ready to be evaluated in `env.snoc(x)` where `x` is a value of
27    /// type `Ty0::Record(fields0)`.
28    pub fields1: Row<TyS>,
29    /// Specializations of the fields.
30    ///
31    /// When we get to actually computing the type of fields, we will look here
32    /// to see if they have been specialized.
33    pub specializations: Dtry<TyV>,
34}
35
36impl RecordV {
37    /// Add a specialization a path `path` to type `ty`
38    ///
39    /// Precondition: assumes that this produces a subtype.
40    pub fn add_specialization(&self, path: &[(FieldName, LabelSegment)], ty: TyV) -> Self {
41        Self {
42            specializations: merge_specializations(
43                &self.specializations,
44                &Dtry::singleton(path, ty),
45            ),
46            ..self.clone()
47        }
48    }
49
50    /// Merge in the specializations in `specializations`
51    ///
52    /// Precondition: assumes that this produces a subtype.
53    pub fn specialize(&self, specializations: &Dtry<TyV>) -> Self {
54        Self {
55            specializations: merge_specializations(&self.specializations, specializations),
56            ..self.clone()
57        }
58    }
59}
60
61/// Merge new specializations with old specializations
62pub fn merge_specializations(old: &Dtry<TyV>, new: &Dtry<TyV>) -> Dtry<TyV> {
63    let mut result: IndexMap<FieldName, (LabelSegment, DtryEntry<TyV>)> =
64        old.entries().map(|(name, e)| (*name, e.clone())).collect();
65    for (field, entry) in new.entries() {
66        let new_entry = match (old.entry(field), &entry.1) {
67            (Option::None, e) => e.clone(),
68            (Some(_), DtryEntry::File(subty)) => DtryEntry::File(subty.clone()),
69            (Some(DtryEntry::File(ty)), DtryEntry::SubDir(d)) => DtryEntry::File(ty.specialize(d)),
70            (Some(DtryEntry::SubDir(d1)), DtryEntry::SubDir(d2)) => {
71                DtryEntry::SubDir(merge_specializations(d1, d2))
72            }
73        };
74        result.insert(*field, (entry.0, new_entry));
75    }
76    result.into()
77}
78
79/// Inner enum for [TyV]
80pub enum TyV_ {
81    /// Type constructor for object types, also see [TyS_::Object].
82    Object(ObjectType),
83    /// Type constructor for morphism types, also see [TyS_::Morphism].
84    Morphism(MorphismType, TmV, TmV),
85    /// Type constructor for specialized record types.
86    ///
87    /// This is the target of both [TyS_::Specialize] and [TyS_::Record].
88    /// Specifically, [TyS_::Record] evaluates to `TyV_::Record(r)` with
89    /// `r.specializations = Dtry::empty()`, and then `TyS_::Specialize(ty, d)` will
90    /// add the specializations in `d` to the evaluation of `ty` (which must
91    /// evaluate to a value of form `TyV_::Record(_)`).
92    Record(RecordV),
93    /// Type constructor for singleton types, also see [TyS_::Sing].
94    Sing(TyV, TmV),
95    /// Type constructor for unit types, also see [TyS_::Unit].
96    Unit,
97}
98
99/// Value for total types, dereferences to [TyV_].
100#[derive(Clone)]
101pub struct TyV(Rc<TyV_>);
102
103impl Deref for TyV {
104    type Target = TyV_;
105
106    fn deref(&self) -> &Self::Target {
107        &self.0
108    }
109}
110
111impl TyV {
112    /// Smart constructor for [TyV], [TyV_::Object] case.
113    pub fn object(object_type: ObjectType) -> Self {
114        Self(Rc::new(TyV_::Object(object_type)))
115    }
116
117    /// Smart constructor for [TyV], [TyV_::Morphism] case.
118    pub fn morphism(morphism_type: MorphismType, dom: TmV, cod: TmV) -> Self {
119        Self(Rc::new(TyV_::Morphism(morphism_type, dom, cod)))
120    }
121
122    /// Smart constructor for [TyV], [TyV_::Record] case.
123    pub fn record(record_v: RecordV) -> Self {
124        Self(Rc::new(TyV_::Record(record_v)))
125    }
126
127    /// Smart constructor for [TyV], [TyV_::Sing] case.
128    pub fn sing(ty_v: TyV, tm_v: TmV) -> Self {
129        Self(Rc::new(TyV_::Sing(ty_v, tm_v)))
130    }
131
132    /// Compute the specialization of `self` by `specializations`.
133    ///
134    /// Specialization is the process of assigning subtypes to the fields
135    /// of a (possibly nested) record.
136    ///
137    /// There are some subtle points around how multiple specializations
138    /// compose that we have to think about.
139    ///
140    /// Consider the following:
141    ///
142    /// ```text
143    /// type r1 = [ A : Type, B : Type, a : A ]
144    /// type r2 = [ x : r1, y : x.B ]
145    /// type r3 = r2 & [ .x : r1 & [ .A : (= Int) ] ] & [ .x.B : (= Bool) ]
146    /// type r3' = r2 & [ .x : r1 & [ .A : (= Int), .B : (= Bool) ] ]
147    /// type r3'' = r2 & [ .x.A : (= Int), .x.B : (= Bool) ]
148    /// ```
149    ///
150    /// r3 and r3' should be represented in the same way, and r3, r3' and r3''
151    /// should all be equivalent.
152    pub fn specialize(&self, specializations: &Dtry<TyV>) -> Self {
153        match &**self {
154            TyV_::Record(r) => TyV::record(r.specialize(specializations)),
155            _ => panic!("can only specialize a record type"),
156        }
157    }
158
159    /// Specializes the field at `path` to `ty`
160    ///
161    /// Precondition: assumes that this produces a subtype.
162    pub fn add_specialization(&self, path: &[(FieldName, LabelSegment)], ty: TyV) -> Self {
163        match &**self {
164            TyV_::Record(r) => TyV::record(r.add_specialization(path, ty)),
165            _ => panic!("can only specialize a record type"),
166        }
167    }
168
169    /// Smart constructor for [TyV], [TyV_::Unit] case.
170    pub fn unit() -> Self {
171        Self(Rc::new(TyV_::Unit))
172    }
173
174    /// The base type
175    pub fn ty0(&self) -> Ty0 {
176        match &**self {
177            TyV_::Object(qname) => Ty0::Object(qname.clone()),
178            TyV_::Morphism(_, _, _) => Ty0::Unit,
179            TyV_::Record(record_v) => Ty0::Record(record_v.fields0.clone()),
180            TyV_::Sing(ty_v, _) => ty_v.ty0(),
181            TyV_::Unit => Ty0::Unit,
182        }
183    }
184}
185
186/// Inner enum for [TmN].
187#[derive(PartialEq, Eq)]
188pub enum TmN_ {
189    /// Variable.
190    Var(FwdIdx, VarName, LabelSegment),
191    /// Projection.
192    Proj(TmN, FieldName, LabelSegment),
193}
194
195/// Neutrals for base terms, dereferences to [TmN_].
196#[derive(Clone, PartialEq, Eq)]
197pub struct TmN(Rc<TmN_>);
198
199impl Deref for TmN {
200    type Target = TmN_;
201
202    fn deref(&self) -> &Self::Target {
203        &self.0
204    }
205}
206
207impl TmN {
208    /// Smart constructor for [TmN], [TmN_::Var] case.
209    pub fn var(fwd_idx: FwdIdx, var_name: VarName, label: LabelSegment) -> Self {
210        TmN(Rc::new(TmN_::Var(fwd_idx, var_name, label)))
211    }
212
213    /// Smart constructor for [TmN], [TmN_::Proj] case.
214    pub fn proj(tm_n: TmN, field_name: FieldName, label: LabelSegment) -> Self {
215        TmN(Rc::new(TmN_::Proj(tm_n, field_name, label)))
216    }
217}
218
219/// Values for base terms.
220///
221/// Note that this is *not* the value for total terms. So evaluating a `TmS` to
222/// produce a `TmV` and then quoting back will lose information about anything
223/// morphism-related. See [crate::tt] for more information.
224///
225/// It turns out that each of the cases for [TmV] has a single cheaply cloneable
226/// field, so we don't need to bother making a `TmV_`.
227#[derive(Clone)]
228pub enum TmV {
229    /// Neutrals.
230    ///
231    /// We store the type because we need it for eta-expansion.
232    Neu(TmN, TyV),
233    /// Records.
234    Cons(Row<TmV>),
235    /// The unique element of `Ty0::Unit`.
236    Tt,
237    /// An element of a type that is opaque to conversion checking
238    Opaque,
239}
240
241impl TmV {
242    /// Coerces self to a neutral
243    pub fn as_neu(&self) -> TmN {
244        match self {
245            TmV::Neu(n, _) => n.clone(),
246            _ => panic!("expected neutral"),
247        }
248    }
249}