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::Deref;
7
8use super::{prelude::*, stx::*, theory::*};
9use crate::zero::{LabelSegment, QualifiedName};
10
11/// A way of resolving [BwdIdx] found in [BaseTmS_::Var] to values.
12pub type Env = Bwd<BaseTmV>;
13
14/// The fiber environment: resolves [BwdIdx] found in
15/// [`super::stx::FiberTmS_::Var`] to fiber-term values. Separate from
16/// [Env], the base environment.
17pub type FiberEnv = Bwd<FiberTmV>;
18
19/// The content of a record type value.
20#[derive(Clone)]
21pub struct RecordV {
22    /// The closed-over environment.
23    pub env: Env,
24    /// The types for the fields.
25    pub fields: Rc<Row<BaseTyS>>,
26    /// Specializations of the fields.
27    ///
28    /// When we get to actually computing the type of fields, we will look here
29    /// to see if they have been specialized.
30    pub specializations: Dtry<BaseTyV>,
31}
32
33impl RecordV {
34    /// Construct a record type value.
35    pub fn new(env: Env, fields: Row<BaseTyS>, specializations: Dtry<BaseTyV>) -> Self {
36        Self {
37            env,
38            fields: Rc::new(fields),
39            specializations,
40        }
41    }
42
43    /// Add a specialization a path `path` to type `ty`.
44    ///
45    /// Precondition: assumes that this produces a subtype.
46    pub fn add_specialization(&self, path: &[(FieldName, LabelSegment)], ty: BaseTyV) -> Self {
47        Self {
48            specializations: merge_specializations(
49                &self.specializations,
50                &Dtry::singleton(path, ty),
51            ),
52            ..self.clone()
53        }
54    }
55
56    /// Merge in the specializations in `specializations`.
57    ///
58    /// Precondition: assumes that this produces a subtype.
59    pub fn specialize(&self, specializations: &Dtry<BaseTyV>) -> Self {
60        Self {
61            specializations: merge_specializations(&self.specializations, specializations),
62            ..self.clone()
63        }
64    }
65}
66
67/// Merge new specializations with old specializations.
68pub fn merge_specializations(old: &Dtry<BaseTyV>, new: &Dtry<BaseTyV>) -> Dtry<BaseTyV> {
69    let mut result: IndexMap<_, _> = old.entries().map(|(name, e)| (*name, e.clone())).collect();
70    for (field, entry) in new.entries() {
71        let new_entry = match (old.entry(field), &entry.1) {
72            (Option::None, e) => e.clone(),
73            (Some(_), DtryEntry::File(subty)) => DtryEntry::File(subty.clone()),
74            (Some(DtryEntry::File(ty)), DtryEntry::SubDir(d)) => DtryEntry::File(ty.specialize(d)),
75            (Some(DtryEntry::SubDir(d1)), DtryEntry::SubDir(d2)) => {
76                DtryEntry::SubDir(merge_specializations(d1, d2))
77            }
78        };
79        result.insert(*field, (entry.0, new_entry));
80    }
81    result.into()
82}
83
84/// Inner enum for [BaseTyV].
85pub enum BaseTyV_ {
86    /// Type constructor for object types, also see [BaseTyS_::Object].
87    Object(ObType),
88    /// Type constructor for morphism types, also see [BaseTyS_::Morphism].
89    Morphism(MorType, BaseTmV, BaseTmV),
90    /// Type constructor for specialized record types.
91    ///
92    /// This is the target of both [BaseTyS_::Specialize] and [BaseTyS_::Record].
93    /// Specifically, [BaseTyS_::Record] evaluates to `BaseTyV_::Record(r)` with
94    /// `r.specializations = Dtry::empty()`, and then `BaseTyS_::Specialize(ty, d)` will
95    /// add the specializations in `d` to the evaluation of `ty` (which must
96    /// evaluate to a value of form `BaseTyV_::Record(_)`).
97    Record(RecordV),
98    /// Type constructor for singleton types, also see [BaseTyS_::Sing].
99    Sing(BaseTyV, BaseTmV),
100    /// Type constructor for identity types, also see [BaseTyS_::Id].
101    Id(BaseTyV, BaseTmV, BaseTmV),
102    /// A metavariable, also see [BaseTyS_::Meta].
103    Meta(MetaVar),
104}
105
106/// Value for total types, dereferences to [BaseTyV_].
107#[derive(Clone, Deref)]
108#[deref(forward)]
109pub struct BaseTyV(Rc<BaseTyV_>);
110
111impl BaseTyV {
112    /// Smart constructor for [BaseTyV], [BaseTyV_::Object] case.
113    pub fn object(object_type: ObType) -> Self {
114        Self(Rc::new(BaseTyV_::Object(object_type)))
115    }
116
117    /// Smart constructor for [BaseTyV], [BaseTyV_::Morphism] case.
118    pub fn morphism(morphism_type: MorType, dom: BaseTmV, cod: BaseTmV) -> Self {
119        Self(Rc::new(BaseTyV_::Morphism(morphism_type, dom, cod)))
120    }
121
122    /// Smart constructor for [BaseTyV], [BaseTyV_::Record] case.
123    pub fn record(record_v: RecordV) -> Self {
124        Self(Rc::new(BaseTyV_::Record(record_v)))
125    }
126
127    /// Smart constructor for [BaseTyV], [BaseTyV_::Sing] case.
128    pub fn sing(ty_v: BaseTyV, tm_v: BaseTmV) -> Self {
129        Self(Rc::new(BaseTyV_::Sing(ty_v, tm_v)))
130    }
131
132    /// Smart constructor for [BaseTyV], [BaseTyV_::Id] case.
133    pub fn id(ty_v: BaseTyV, tm_v1: BaseTmV, tm_v2: BaseTmV) -> Self {
134        Self(Rc::new(BaseTyV_::Id(ty_v, tm_v1, tm_v2)))
135    }
136
137    /// Compute the specialization of `self` by `specializations`.
138    ///
139    /// Specialization is the process of assigning subtypes to the fields
140    /// of a (possibly nested) record.
141    ///
142    /// There are some subtle points around how multiple specializations
143    /// compose that we have to think about.
144    ///
145    /// Consider the following:
146    ///
147    /// ```text
148    /// type r1 = [ A : Type, B : Type, a : A ]
149    /// type r2 = [ x : r1, y : x.B ]
150    /// type r3 = r2 & [ .x : r1 & [ .A : (= Int) ] ] & [ .x.B : (= Bool) ]
151    /// type r3' = r2 & [ .x : r1 & [ .A : (= Int), .B : (= Bool) ] ]
152    /// type r3'' = r2 & [ .x.A : (= Int), .x.B : (= Bool) ]
153    /// ```
154    ///
155    /// r3 and r3' should be represented in the same way, and r3, r3' and r3''
156    /// should all be equivalent.
157    pub fn specialize(&self, specializations: &Dtry<BaseTyV>) -> Self {
158        match &**self {
159            BaseTyV_::Record(r) => BaseTyV::record(r.specialize(specializations)),
160            _ => panic!("can only specialize a record type"),
161        }
162    }
163
164    /// Specializes the field at `path` to `ty`.
165    ///
166    /// Precondition: assumes that this produces a subtype.
167    pub fn add_specialization(&self, path: &[(FieldName, LabelSegment)], ty: BaseTyV) -> Self {
168        match &**self {
169            BaseTyV_::Record(r) => BaseTyV::record(r.add_specialization(path, ty)),
170            _ => panic!("can only specialize a record type"),
171        }
172    }
173
174    /// The empty record type — the unit type / empty model.
175    /// Also used as a throwaway type for
176    /// untyped placeholder binders (whose type is discarded).
177    pub fn empty_record() -> Self {
178        Self(Rc::new(BaseTyV_::Record(RecordV::new(Env::nil(), Row::empty(), Dtry::empty()))))
179    }
180
181    /// Smart constructor for [BaseTyV], [BaseTyV_::Meta] case.
182    pub fn meta(mv: MetaVar) -> Self {
183        Self(Rc::new(BaseTyV_::Meta(mv)))
184    }
185}
186
187/// Inner enum for [TmN].
188#[derive(PartialEq, Eq)]
189pub enum TmN_ {
190    /// Variable.
191    Var(FwdIdx, VarName, LabelSegment),
192    /// Projection.
193    Proj(TmN, FieldName, LabelSegment),
194}
195
196/// Neutrals for [terms](BaseTmV), dereferences to [TmN_].
197#[derive(Clone, Deref, PartialEq, Eq)]
198#[deref(forward)]
199pub struct TmN(Rc<TmN_>);
200
201impl TmN {
202    /// Smart constructor for [TmN], [TmN_::Var] case.
203    pub fn var(fwd_idx: FwdIdx, var_name: VarName, label: LabelSegment) -> Self {
204        TmN(Rc::new(TmN_::Var(fwd_idx, var_name, label)))
205    }
206
207    /// Smart constructor for [TmN], [TmN_::Proj] case.
208    pub fn proj(tm_n: TmN, field_name: FieldName, label: LabelSegment) -> Self {
209        TmN(Rc::new(TmN_::Proj(tm_n, field_name, label)))
210    }
211
212    /// Extracts a qualifed name from a series of projections.
213    pub fn to_qualified_name(&self) -> QualifiedName {
214        let mut segments = Vec::new();
215        let mut n = self;
216        while let TmN_::Proj(n1, f, _) = &**n {
217            n = n1;
218            segments.push(*f);
219        }
220        segments.reverse();
221        segments.into()
222    }
223}
224
225/// Inner enum for [BaseTmV].
226pub enum BaseTmV_ {
227    /// Neutrals.
228    ///
229    /// We store the type because we need it for eta-expansion.
230    Neu(TmN, BaseTyV),
231    /// Application of an object operation in the theory.
232    App(VarName, BaseTmV),
233    /// Lists of objects.
234    List(Vec<BaseTmV>),
235    /// Records.
236    Cons(Row<BaseTmV>),
237    /// The identity morphism of an object.
238    Id(BaseTmV),
239    /// The tabulation of a morphism.
240    Tab(BaseTmV),
241    /// Composition of morphisms.
242    Compose(BaseTmV, BaseTmV),
243    /// A metavariable.
244    Meta(MetaVar),
245}
246
247/// Values for terms, dereferences to [BaseTmV_].
248#[derive(Clone, Deref)]
249#[deref(forward)]
250pub struct BaseTmV(Rc<BaseTmV_>);
251
252impl BaseTmV {
253    /// Smart constructor for [BaseTmV], [BaseTmV_::Neu] case.
254    pub fn neu(n: TmN, ty: BaseTyV) -> Self {
255        BaseTmV(Rc::new(BaseTmV_::Neu(n, ty)))
256    }
257
258    /// Smart constructor for [BaseTmV], [BaseTmV_::App] case.
259    pub fn app(name: VarName, x: BaseTmV) -> Self {
260        BaseTmV(Rc::new(BaseTmV_::App(name, x)))
261    }
262
263    /// Smart constructor for [BaseTmV], [BaseTmV_::List] case.
264    pub fn list(elems: Vec<BaseTmV>) -> Self {
265        BaseTmV(Rc::new(BaseTmV_::List(elems)))
266    }
267
268    /// Smart constructor for [BaseTmV], [BaseTmV_::Cons] case.
269    pub fn cons(fields: Row<BaseTmV>) -> Self {
270        BaseTmV(Rc::new(BaseTmV_::Cons(fields)))
271    }
272
273    /// The empty record value `[]` — the unique element of the empty
274    /// record type. Also serves as the (proof-irrelevant) canonical
275    /// inhabitant of `Id` types under eta.
276    pub fn empty_cons() -> Self {
277        BaseTmV(Rc::new(BaseTmV_::Cons(Row::empty())))
278    }
279
280    /// Smart constructor for [BaseTmV], [BaseTmV_::Id] case.
281    pub fn id(x: BaseTmV) -> Self {
282        BaseTmV(Rc::new(BaseTmV_::Id(x)))
283    }
284
285    /// Smart constructor for [BaseTmV], [BaseTmV_::Tab] case.
286    pub fn tab(mor: BaseTmV) -> Self {
287        BaseTmV(Rc::new(BaseTmV_::Tab(mor)))
288    }
289
290    /// Smart constructor for [BaseTmV], [BaseTmV_::Compose] case.
291    pub fn compose(f: BaseTmV, g: BaseTmV) -> Self {
292        BaseTmV(Rc::new(BaseTmV_::Compose(f, g)))
293    }
294
295    /// Smart constructor for [BaseTmV], [BaseTmV_::Meta] case.
296    pub fn meta(mv: MetaVar) -> Self {
297        BaseTmV(Rc::new(BaseTmV_::Meta(mv)))
298    }
299
300    /// Unwraps a neutral term, or panics.
301    pub fn unwrap_neu(&self) -> TmN {
302        match &**self {
303            BaseTmV_::Neu(n, _) => n.clone(),
304            _ => panic!("expected term to be a neutral"),
305        }
306    }
307}
308
309/// Inner enum for [FiberTyV]; value counterpart of [`super::stx::FiberTyS_`].
310///
311/// A fiber record stores its evaluated field types directly (no captured
312/// environment, unlike [`RecordV`]): the only fields ever projected are
313/// the closed [`Over`](Self::Over) generators, and the dependent
314/// [`Id`](Self::Id) equation fields are read off by name downstream
315/// (conversion and model generation) rather than re-evaluated.
316pub enum FiberTyV_ {
317    /// The type of a fiber element over the codomain object `obj` (a base
318    /// object value, possibly modal). See [`super::stx::FiberTyS_::Over`].
319    Over(BaseTmV),
320    /// An instance presented as a record of fiber types. See
321    /// [`super::stx::FiberTyS_::Record`].
322    Record(Row<FiberTyV>),
323    /// A propositional equation between fiber elements. See
324    /// [`super::stx::FiberTyS_::Id`].
325    Id(FiberTyV, FiberTmV, FiberTmV),
326}
327
328/// Values for fiber types, dereferences to [FiberTyV_].
329#[derive(Clone, Deref)]
330#[deref(forward)]
331pub struct FiberTyV(Rc<FiberTyV_>);
332
333impl FiberTyV {
334    /// Smart constructor for [FiberTyV], [FiberTyV_::Over] case.
335    pub fn over(obj: BaseTmV) -> Self {
336        Self(Rc::new(FiberTyV_::Over(obj)))
337    }
338
339    /// Smart constructor for [FiberTyV], [FiberTyV_::Record] case.
340    pub fn record(fields: Row<FiberTyV>) -> Self {
341        Self(Rc::new(FiberTyV_::Record(fields)))
342    }
343
344    /// Smart constructor for [FiberTyV], [FiberTyV_::Id] case.
345    pub fn id(ty: FiberTyV, tm1: FiberTmV, tm2: FiberTmV) -> Self {
346        Self(Rc::new(FiberTyV_::Id(ty, tm1, tm2)))
347    }
348}
349
350/// Inner enum for [FiberTmV]; value counterpart of [`super::stx::FiberTmS_`].
351///
352/// Every fiber term is neutral, so — unlike [`BaseTmV_`] — there is no
353/// closure/neutral split and no stored type for eta. Variables carry a
354/// forward index into the fiber environment.
355pub enum FiberTmV_ {
356    /// A fiber-context variable (generator or sub-instance import).
357    Var(FwdIdx, VarName, LabelSegment),
358    /// Projection of a generator out of a sub-instance import (`we.e`).
359    Proj(FiberTmV, FieldName, LabelSegment),
360    /// A fiber list literal. See [`super::stx::FiberTmS_::List`].
361    List(Vec<FiberTmV>),
362    /// A theory object-operation applied to a fiber element. See
363    /// [`super::stx::FiberTmS_::ObApp`].
364    ObApp(VarName, FiberTmV),
365    /// Application of a codomain morphism (identified by its path) to a
366    /// fiber element; the second field is the codomain object it lands at.
367    /// See [`super::stx::FiberTmS_::OverApp`].
368    OverApp(Vec<(FieldName, LabelSegment)>, BaseTmV, FiberTmV),
369    /// A metavariable.
370    Meta(MetaVar),
371}
372
373/// Values for fiber terms, dereferences to [FiberTmV_].
374#[derive(Clone, Deref)]
375#[deref(forward)]
376pub struct FiberTmV(Rc<FiberTmV_>);
377
378impl FiberTmV {
379    /// Smart constructor for [FiberTmV], [FiberTmV_::Var] case.
380    pub fn var(fwd_idx: FwdIdx, var_name: VarName, label: LabelSegment) -> Self {
381        Self(Rc::new(FiberTmV_::Var(fwd_idx, var_name, label)))
382    }
383
384    /// Smart constructor for [FiberTmV], [FiberTmV_::Proj] case.
385    pub fn proj(tm: FiberTmV, field_name: FieldName, label: LabelSegment) -> Self {
386        Self(Rc::new(FiberTmV_::Proj(tm, field_name, label)))
387    }
388
389    /// Smart constructor for [FiberTmV], [FiberTmV_::List] case.
390    pub fn list(elems: Vec<FiberTmV>) -> Self {
391        Self(Rc::new(FiberTmV_::List(elems)))
392    }
393
394    /// Smart constructor for [FiberTmV], [FiberTmV_::ObApp] case.
395    pub fn ob_app(name: VarName, arg: FiberTmV) -> Self {
396        Self(Rc::new(FiberTmV_::ObApp(name, arg)))
397    }
398
399    /// Smart constructor for [FiberTmV], [FiberTmV_::OverApp] case.
400    pub fn over_app(mor: Vec<(FieldName, LabelSegment)>, cod: BaseTmV, inner: FiberTmV) -> Self {
401        Self(Rc::new(FiberTmV_::OverApp(mor, cod, inner)))
402    }
403
404    /// Smart constructor for [FiberTmV], [FiberTmV_::Meta] case.
405    pub fn meta(mv: MetaVar) -> Self {
406        Self(Rc::new(FiberTmV_::Meta(mv)))
407    }
408}