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}