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}