1use fnotation::*;
4use scopeguard::{ScopeGuard, guard};
5
6use fnotation::{ParseConfig, parser::Prec};
7use tattle::declare_error;
8
9use super::fiber_elab::{CODOMAIN_BINDER, FiberElab, FiberError, path_str};
10use super::{
11 context::*, eval::*, modelgen::*, prelude::*, stx::*, theory::*, toplevel::*, val::*, wd::*,
12};
13use crate::{
14 dbl::model::DblModelPrinter,
15 zero::{QualifiedName, name},
16};
17
18pub const TT_PARSE_CONFIG: ParseConfig = ParseConfig::new(
20 &[
21 (":", Prec::nonassoc(20)),
22 (":=", Prec::nonassoc(10)),
23 ("&", Prec::lassoc(40)),
24 ("*", Prec::lassoc(60)),
25 ("==", Prec::nonassoc(30)),
26 ],
27 &[":", ":=", "&", "Unit", "Hom", "*", "=="],
28 &[
29 "model",
30 "def",
31 "instance",
32 "syn",
33 "chk",
34 "norm",
35 "generate",
36 "uwd",
37 "set_theory",
38 ],
39);
40
41pub enum TopElabResult {
43 Declaration(TopVarName, TopDecl),
45 Output(String),
47}
48
49pub struct TopElaborator {
53 current_theory: Option<Theory>,
54 reporter: Reporter,
55}
56
57impl TopElaborator {
58 pub fn new(reporter: Reporter) -> Self {
60 Self { current_theory: None, reporter }
61 }
62
63 fn bare_def<'c>(&self, n: &FNtn<'c>) -> Option<(TopVarName, &'c FNtn<'c>)> {
64 match n.ast0() {
65 App2(L(_, Keyword(":=")), L(_, Var(name)), tn) => {
66 Some((NameSegment::Text(ustr(name)), tn))
67 }
68 _ => None,
69 }
70 }
71
72 fn annotated_def<'c>(
73 &self,
74 n: &FNtn<'c>,
75 ) -> Option<(TopVarName, Option<&'c [&'c FNtn<'c>]>, &'c FNtn<'c>, &'c FNtn<'c>)> {
76 match n.ast0() {
77 App2(L(_, Keyword(":=")), L(_, App2(L(_, Keyword(":")), head_n, annotn)), valn) => {
78 match head_n.ast0() {
79 App1(L(_, Var(name)), L(_, Tuple(args))) => {
80 Some((name_seg(*name), Some(args.as_slice()), annotn, valn))
81 }
82 Var(name) => Some((name_seg(*name), None, annotn, valn)),
83 _ => None,
84 }
85 }
86 _ => None,
87 }
88 }
89
90 fn expr_with_context<'c>(&self, n: &'c FNtn<'c>) -> (&'c [&'c FNtn<'c>], &'c FNtn<'c>) {
91 match n.ast0() {
92 App1(L(_, Tuple(ctx_elems)), n) => (ctx_elems.as_slice(), n),
93 _ => (&[], n),
94 }
95 }
96
97 fn get_theory(&self, loc: Loc) -> Option<Theory> {
98 let Some(theory) = &self.current_theory else {
99 return self.error(
100 loc,
101 "have not yet set a theory, set a theory via `set_theory <THEORY_NAME>`",
102 );
103 };
104 Some(theory.clone())
105 }
106
107 fn elaborator<'a>(&self, theory: &Theory, toplevel: &'a Toplevel) -> Elaborator<'a> {
108 Elaborator::new(theory.clone(), self.reporter.clone(), toplevel)
109 }
110
111 fn error<T>(&self, loc: Loc, msg: impl Into<String>) -> Option<T> {
112 self.reporter.error(loc, ELAB_ERROR, msg.into());
113 None
114 }
115
116 pub fn elab(&mut self, toplevel: &Toplevel, tn: &FNtnTop) -> Option<TopElabResult> {
118 match tn.name {
119 "set_theory" => match tn.body.ast0() {
120 Var(theory_name) => match toplevel.theory_library.get(&name(*theory_name)) {
121 Some(theory) => {
122 self.current_theory = Some(theory.clone());
123 Some(TopElabResult::Output(format!("set theory to {}", theory_name)))
124 }
125 None => self.error(tn.loc, format!("{theory_name} not found")),
126 },
127 _ => self.error(tn.loc, "expected a theory name"),
128 },
129 "model" => {
130 let theory = self.get_theory(tn.loc)?;
131 let (name, ty_n) = self.bare_def(tn.body).or_else(|| {
132 self.error(
133 tn.loc,
134 "unknown syntax for model declaration, expected <name> := <model>",
135 )
136 })?;
137 let (ty_s, ty_v) = self.elaborator(&theory, toplevel).ty(ty_n);
138 Some(TopElabResult::Declaration(
139 name,
140 TopDecl::Type(Type::new(theory.clone(), ty_s, ty_v)),
141 ))
142 }
143 "def" => {
144 let theory = self.get_theory(tn.loc)?;
145 let (name, args_n, ty_n, tm_n) = self.annotated_def(tn.body).or_else(|| {
146 self.error(
147 tn.loc,
148 "unknown syntax for term declaration, expected <name> : <type> := <term>",
149 )
150 })?;
151 match args_n {
152 Some(args_n) => {
153 let mut elab = self.elaborator(&theory, toplevel);
154 let mut args_stx = IndexMap::new();
155 for arg_n in args_n {
156 let (name, label, ty_s, ty_v) = elab.binding(arg_n)?;
157 args_stx.insert(name, (label, ty_s));
158 elab.intro(name, label, Some(ty_v));
159 }
160 let (ret_ty_s, ret_ty_v) = elab.ty(ty_n);
161 let (body_s, _) = elab.chk(&ret_ty_v, tm_n);
162 Some(TopElabResult::Declaration(
163 name,
164 TopDecl::Def(Def::new(
165 theory.clone(),
166 args_stx.into(),
167 ret_ty_s,
168 body_s,
169 )),
170 ))
171 }
172 None => {
173 let mut elab = self.elaborator(&theory, toplevel);
174 let (ret_ty_s, ret_ty_v) = elab.ty(ty_n);
175 let (body_s, _) = elab.chk(&ret_ty_v, tm_n);
176 Some(TopElabResult::Declaration(
183 name,
184 TopDecl::Def(Def::new(theory.clone(), Row::empty(), ret_ty_s, body_s)),
185 ))
186 }
187 }
188 }
189 "instance" => {
190 let theory = self.get_theory(tn.loc)?;
191 let (name, args_n, ty_n, tm_n) = self.annotated_def(tn.body).or_else(|| {
192 self.error(
193 tn.loc,
194 "unknown syntax for instance declaration, expected <name> : <type> := [...]",
195 )
196 })?;
197 if args_n.is_some() {
198 return self.error(
199 tn.loc,
200 "an instance takes no arguments; for a parameterized map between \
201 models, use `def`",
202 );
203 }
204 let mut elab = self.elaborator(&theory, toplevel);
205 let (_, ret_ty_v) = elab.ty(ty_n);
206 let BaseTyV_::Record(r) = &*ret_ty_v else {
209 return self
210 .error(tn.loc, "an instance must be declared against a record type");
211 };
212 let (tm_s, tm_v) = elab.instance_body(r, tm_n);
213 Some(TopElabResult::Declaration(
214 name,
215 TopDecl::Instance(Instance::new(theory.clone(), tm_s, tm_v, ret_ty_v)),
216 ))
217 }
218 "syn" => {
219 let theory = self.get_theory(tn.loc)?;
220 let (ctx_ns, n) = self.expr_with_context(tn.body);
221 let mut elab = self.elaborator(&theory, toplevel);
222 for ctx_n in ctx_ns {
223 let (name, label, _, ty_v) = elab.binding(ctx_n)?;
224 elab.intro(name, label, Some(ty_v));
225 }
226 let (tm_s, _, ty_v) = elab.syn(n);
227 Some(TopElabResult::Output(format!(
228 "{tm_s} : {}",
229 elab.evaluator().quote_ty(&ty_v)
230 )))
231 }
232 "norm" => {
233 let (ctx_ns, n) = self.expr_with_context(tn.body);
234 if let [single] = ctx_ns
241 && let Var(inst_name) = single.ast0()
242 && let Some(TopDecl::Instance(inst)) =
243 toplevel.declarations.get(&name_seg(*inst_name))
244 {
245 let mut elab = self.elaborator(&inst.theory, toplevel);
246 elab.enter_instance(inst)?;
247 let (_, tm_v, ty_v) = elab.fiber_syn(n);
248 let FiberTyV_::Over(over) = &*ty_v else {
249 return elab
250 .error("norm expects an instance element (a term over an object)");
251 };
252 let over = over.clone();
253 return match normalize_instance_term(
254 toplevel,
255 &inst.theory.definition,
256 inst,
257 &tm_v,
258 &over,
259 ) {
260 Ok(nt) => Some(TopElabResult::Output(nt.render())),
261 Err(msg) => self.error(tn.loc, msg),
262 };
263 }
264 let theory = self.get_theory(tn.loc)?;
265 let mut elab = self.elaborator(&theory, toplevel);
266 for ctx_n in ctx_ns {
267 let (name, label, _, ty_v) = elab.binding(ctx_n)?;
268 elab.intro(name, label, Some(ty_v));
269 }
270 let (_, tm_v, ty_v) = elab.syn(n);
271 let eval = elab.evaluator();
272 let tm_s = eval.quote_tm(&eval.eta(&tm_v, Some(&ty_v)));
273 Some(TopElabResult::Output(format!("{tm_s}")))
274 }
275 "chk" => {
276 let theory = self.get_theory(tn.loc)?;
277 let (ctx_ns, n) = self.expr_with_context(tn.body);
278 let mut elab = self.elaborator(&theory, toplevel);
279 for ctx_n in ctx_ns {
280 let (name, label, _, ty_v) = elab.binding(ctx_n)?;
281 elab.intro(name, label, Some(ty_v));
282 }
283 let (tm_n, ty_n) = match n.ast0() {
284 App2(L(_, Keyword(":")), tm_n, ty_n) => (tm_n, ty_n),
285 _ => return elab.error("expected <expr> : <type>"),
286 };
287 let (_, ty_v) = elab.ty(ty_n);
288 let (tm_s, _) = elab.chk(&ty_v, tm_n);
289 Some(TopElabResult::Output(format!("{tm_s}")))
290 }
291 "uwd" => {
292 let theory = self.get_theory(tn.loc)?;
293 let mut elab = self.elaborator(&theory, toplevel);
294 let (_, ty_v) = elab.ty(tn.body);
295 let Some(uwd) = record_to_uwd(&ty_v) else {
296 return self.error(tn.loc, "expected a record type");
297 };
298 let out = uwd.to_doc().0.pretty(77).to_string().replace("\n", "\n#/ ");
299 Some(TopElabResult::Output(out))
300 }
301 "generate" => {
302 let theory = self.get_theory(tn.loc)?;
303 let mut elab = self.elaborator(&theory, toplevel);
304 let (_, ty_v) = elab.ty(tn.body);
305 let (model, ns) = Model::from_ty(toplevel, &theory.definition, &ty_v);
306 let printer = DblModelPrinter::new().include_summary(true);
307 let out = model.to_doc(&printer, &ns).0.pretty(77).to_string();
308 let out = out.trim().replace("\n", "\n#/ ");
309 Some(TopElabResult::Output(out))
310 }
311 _ => self.error(tn.loc, "unknown toplevel declaration"),
312 }
313 }
314}
315
316pub struct Elaborator<'a> {
318 theory: Theory,
319 reporter: Reporter,
320 toplevel: &'a Toplevel,
321 loc: Option<Loc>,
322 ctx: Context,
323 next_meta: usize,
324}
325
326struct ElaboratorCheckpoint {
327 loc: Option<Loc>,
328 ctx: ContextCheckpoint,
329}
330
331declare_error!(ELAB_ERROR, "elab", "an error during elaboration");
332
333impl<'a> Elaborator<'a> {
334 pub fn new(theory: Theory, reporter: Reporter, toplevel: &'a Toplevel) -> Self {
336 Self {
337 theory,
338 reporter,
339 toplevel,
340 loc: None,
341 ctx: Context::new(),
342 next_meta: 0,
343 }
344 }
345
346 fn instance_codomain(&self) -> Option<Rc<RecordV>> {
354 let (_, _, ty) = self.ctx.lookup(name_seg(CODOMAIN_BINDER))?;
355 match &*ty? {
356 BaseTyV_::Record(r) => Some(Rc::new(r.clone())),
357 _ => None,
358 }
359 }
360
361 fn theory(&self) -> &TheoryDef {
362 &self.theory.definition
363 }
364
365 fn checkpoint(&self) -> ElaboratorCheckpoint {
366 ElaboratorCheckpoint {
367 loc: self.loc,
368 ctx: self.ctx.checkpoint(),
369 }
370 }
371
372 fn reset_to(&mut self, c: ElaboratorCheckpoint) {
373 self.loc = c.loc;
374 self.ctx.reset_to(c.ctx);
375 }
376
377 fn enter<'c>(&'c mut self, loc: Loc) -> ScopeGuard<&'c mut Self, impl FnOnce(&'c mut Self)> {
378 let c = self.checkpoint();
379 self.loc = Some(loc);
380 guard(self, |e| {
381 e.reset_to(c);
382 })
383 }
384
385 fn fresh_meta(&mut self) -> MetaVar {
386 let i = self.next_meta;
387 self.next_meta += 1;
388 MetaVar::new(None, i)
389 }
390
391 fn error<T>(&self, msg: impl Into<String>) -> Option<T> {
392 self.reporter.error_option_loc(self.loc, ELAB_ERROR, msg.into());
393 None
394 }
395
396 fn ty_hole(&mut self) -> (BaseTyS, BaseTyV) {
397 let ty_m = self.fresh_meta();
398 (BaseTyS::meta(ty_m), BaseTyV::meta(ty_m))
399 }
400
401 fn ty_error(&mut self, msg: impl Into<String>) -> (BaseTyS, BaseTyV) {
402 self.reporter.error_option_loc(self.loc, ELAB_ERROR, msg.into());
403 self.ty_hole()
404 }
405
406 fn syn_hole(&mut self) -> (BaseTmS, BaseTmV, BaseTyV) {
407 let tm_m = self.fresh_meta();
408 let ty_m = self.fresh_meta();
409 (BaseTmS::meta(tm_m), BaseTmV::meta(tm_m), BaseTyV::meta(ty_m))
410 }
411
412 fn syn_error(&mut self, msg: impl Into<String>) -> (BaseTmS, BaseTmV, BaseTyV) {
413 self.reporter.error_option_loc(self.loc, ELAB_ERROR, msg.into());
414 self.syn_hole()
415 }
416
417 fn chk_hole(&mut self) -> (BaseTmS, BaseTmV) {
418 let tm_m = self.fresh_meta();
419 (BaseTmS::meta(tm_m), BaseTmV::meta(tm_m))
420 }
421
422 fn chk_error(&mut self, msg: impl Into<String>) -> (BaseTmS, BaseTmV) {
423 self.reporter.error_option_loc(self.loc, ELAB_ERROR, msg.into());
424 self.chk_hole()
425 }
426
427 fn evaluator(&self) -> Evaluator<'a> {
428 Evaluator::new(self.toplevel, self.ctx.env.clone(), self.ctx.scope.len())
429 }
430
431 fn intro(&mut self, name: VarName, label: LabelSegment, ty: Option<BaseTyV>) -> BaseTmV {
432 let v = BaseTmV::neu(
433 TmN::var(self.ctx.scope.len().into(), name, label),
434 ty.clone().unwrap_or(BaseTyV::empty_record()),
435 );
436 let v = if ty.is_some() {
437 self.evaluator().eta(&v, ty.as_ref())
438 } else {
439 v
440 };
441 self.ctx.env = self.ctx.env.snoc(v.clone());
442 self.ctx.push_scope(name, label, ty);
443 v
444 }
445
446 fn fiber_syn_error_msg(&mut self, msg: impl Into<String>) -> (FiberTmS, FiberTmV, FiberTyV) {
450 self.reporter.error_option_loc(self.loc, ELAB_ERROR, msg.into());
451 self.fiber_syn_hole()
452 }
453
454 fn fiber_syn(&mut self, n: &FNtn) -> (FiberTmS, FiberTmV, FiberTyV) {
458 let mut elab = self.enter(n.loc());
459 match n.ast0() {
460 Var(name) => match elab.lookup_fiber_tm(name_seg(*name)) {
461 Some(r) => r,
462 None => elab.fiber_syn_error(FiberError::UnknownElement(name.to_string())),
463 },
464 App1(recv_n, L(_, Field(f))) => {
466 let (recv_s, recv_v, recv_ty) = elab.fiber_syn(recv_n);
467 elab.fiber_proj(recv_s, recv_v, &recv_ty, name_seg(*f))
468 }
469 App1(L(_, Prim(op)), arg_n) => {
473 let op_name = name_seg(*op);
474 if !elab.check_ob_op(op_name) {
475 return elab.fiber_syn_hole();
476 }
477 let (arg_s, arg_v, arg_ty) = elab.fiber_syn(arg_n);
478 elab.fiber_ob_app(op_name, arg_s, arg_v, &arg_ty)
479 }
480 App1(head_n, arg_n) => {
484 let Some(path) = morphism_path(head_n) else {
485 return elab.fiber_syn_error_msg(
486 "expected a codomain morphism (a name or path like `Add.op`) applied \
487 to a fiber element",
488 );
489 };
490 let label = match arg_n.ast0() {
492 Var(x) => x.to_string(),
493 App1(_, L(_, Field(fld))) => fld.to_string(),
494 _ => "argument".to_string(),
495 };
496 let (arg_s, arg_v, arg_ty) = elab.fiber_syn(arg_n);
497 elab.apply_codomain_morphism(&path, arg_s, arg_v, arg_ty, &label)
498 }
499 Tuple(elems) => {
503 let mut ss = Vec::with_capacity(elems.len());
504 let mut vs = Vec::with_capacity(elems.len());
505 let mut objs = Vec::with_capacity(elems.len());
506 for e in elems.iter() {
507 let (s, v, ty) = elab.fiber_syn(e);
508 let FiberTyV_::Over(o) = &*ty else {
509 return elab.fiber_syn_error(FiberError::ListElementNotOver);
510 };
511 objs.push(o.clone());
512 ss.push(s);
513 vs.push(v);
514 }
515 (FiberTmS::list(ss), FiberTmV::list(vs), FiberTyV::over(BaseTmV::list(objs)))
516 }
517 _ => elab.fiber_syn_error_msg(
518 "expected a fiber element: a generator, a projection `we.e`, a fiber list \
519 `[..]`, an object operation `@op [..]`, or a morphism application `f[..]`",
520 ),
521 }
522 }
523
524 fn fiber_chk(&mut self, expected: &FiberTyV, n: &FNtn) -> (FiberTmS, FiberTmV) {
527 let syn = self.fiber_syn(n);
528 self.check_fiber(syn, expected)
529 }
530
531 fn fiber_ty(&mut self, n: &FNtn) -> Option<(FiberTyS, FiberTyV)> {
535 match n.ast0() {
536 Var(name) => {
537 let topvar = name_seg(*name);
538 let (imported_codomain, val) = match self.toplevel.declarations.get(&topvar) {
539 Some(TopDecl::Instance(i)) => (i.codomain.clone(), i.val.clone()),
540 _ => {
541 return self.error(format!(
542 "{name} must reference a top-level instance declaration"
543 ));
544 }
545 };
546 if let Some(cod) = self.instance_codomain() {
551 let enclosing = BaseTyV::record((*cod).clone());
552 if !self.codomains_match(&enclosing, &imported_codomain) {
553 self.report_fiber(FiberError::ImportCodomainMismatch(name.to_string()));
554 return None;
555 }
556 }
557 Some((FiberTyS::topvar(topvar), val))
562 }
563 App2(L(_, Keyword("==")), a_n, b_n) => {
564 let (a_s, a_v, a_ty) = self.fiber_syn(a_n);
565 let (b_s, b_v, b_ty) = self.fiber_syn(b_n);
566 if let Err(e) = self.evaluator().convertible_fiber_ty(&a_ty, &b_ty) {
567 self.report_fiber(FiberError::InconvertibleEquationSides(
568 e.pretty().to_string(),
569 ));
570 return None;
571 }
572 let FiberTyV_::Over(obj) = &*a_ty else {
573 self.report_fiber(FiberError::EquationNotOver);
574 return None;
575 };
576 Some(self.fiber_id_field(&a_ty, obj, a_s, a_v, b_s, b_v))
577 }
578 _ => self.error("expected an instance name or an equation `a == b`"),
579 }
580 }
581
582 fn empty_record_ty(&self) -> (BaseTyS, BaseTyV) {
586 (BaseTyS::record(Row::empty()), BaseTyV::empty_record())
587 }
588
589 fn codomain_self_value(&self) -> Option<BaseTmV> {
595 let (i, _, _) = self.ctx.lookup(name_seg(CODOMAIN_BINDER))?;
596 self.ctx.env.get(*i).cloned()
597 }
598
599 fn codomain_object(&self, field: FieldName, label: LabelSegment) -> Option<BaseTmV> {
602 Some(self.evaluator().proj(&self.codomain_self_value()?, field, label))
603 }
604
605 fn apply_codomain_morphism(
611 &mut self,
612 path: &[(FieldName, LabelSegment)],
613 arg_s: FiberTmS,
614 arg_v: FiberTmV,
615 arg_ty: FiberTyV,
616 arg_label_str: &str,
617 ) -> (FiberTmS, FiberTmV, FiberTyV) {
618 let Some(codomain) = self.instance_codomain() else {
619 return self.fiber_syn_error_msg(
620 "applied codomain morphism is only allowed inside an instance body",
621 );
622 };
623 let FiberTyV_::Over(arg_obj) = &*arg_ty else {
624 return self
625 .fiber_syn_error(FiberError::ArgNotElement(Some(arg_label_str.to_string())));
626 };
627 let arg_obj = arg_obj.clone();
628 let Some(self_val) = self.codomain_self_value() else {
629 return self.fiber_syn_error_msg(
630 "applied codomain morphism is only allowed inside an instance body",
631 );
632 };
633 let record_ty = BaseTyV::record((*codomain).clone());
636 let mor_ty = match self.evaluator().path_ty(&record_ty, &self_val, path) {
637 Ok(ty) => ty,
638 Err(e) => {
639 return self.fiber_syn_error_msg(format!(
640 "no such codomain morphism {}: {e}",
641 path_str(path)
642 ));
643 }
644 };
645 self.fiber_mor_app(path, &mor_ty, arg_s, arg_v, &arg_obj)
646 }
647
648 fn instance_body(&mut self, codomain: &RecordV, n: &FNtn) -> (FiberTyS, FiberTyV) {
662 let c = self.checkpoint();
663 let binder = name_seg(CODOMAIN_BINDER);
664 self.intro(binder, label_seg(CODOMAIN_BINDER), Some(BaseTyV::record(codomain.clone())));
665 let result = self.instance_body_inner(n);
666 self.reset_to(c);
667 result
668 }
669
670 fn enter_instance(&mut self, inst: &Instance) -> Option<()> {
676 self.intro(
677 name_seg(CODOMAIN_BINDER),
678 label_seg(CODOMAIN_BINDER),
679 Some(inst.codomain.clone()),
680 );
681 let FiberTyV_::Record(fields) = &*inst.val else {
682 return self.error("instance value is not a fiber record");
683 };
684 for (name, (label, field_ty)) in fields.iter() {
685 match &**field_ty {
686 FiberTyV_::Over(_) | FiberTyV_::Record(_) => {
691 self.intro_fiber(*name, *label, field_ty.clone());
692 }
693 FiberTyV_::Id(_, _, _) => {}
694 }
695 }
696 Some(())
697 }
698
699 fn instance_body_inner(&mut self, n: &FNtn) -> (FiberTyS, FiberTyV) {
724 let mut elab = self.enter(n.loc());
725 let empty = || (FiberTyS::record(Row::empty()), FiberTyV::record(Row::empty()));
726 let Tuple(field_ns) = n.ast0() else {
727 elab.error::<()>("expected a tuple instance body");
728 return empty();
729 };
730 let mut fields_s: Row<FiberTyS> = Row::empty();
736 let mut fields_v: Row<FiberTyV> = Row::empty();
737 let mut eq_count = 0usize;
738 let mut failed = false;
739
740 for field_n in field_ns.iter() {
741 elab.loc = Some(field_n.loc());
742 match field_n.ast0() {
743 App2(L(_, Keyword(":")), L(_, Var(name)), ty_n) => {
747 let n_seg = name_seg(*name);
748 let label = label_seg(*name);
749 let Some((ty_s, ty_v)) = elab.fiber_ty(ty_n) else {
750 failed = true;
751 continue;
752 };
753 match &*ty_v {
754 FiberTyV_::Record(_) => {
757 elab.intro_fiber(n_seg, label, ty_v.clone());
758 fields_s.insert(n_seg, label, ty_s);
759 fields_v.insert(n_seg, label, ty_v);
760 }
761 FiberTyV_::Id(_, _, _) => {
763 fields_s.insert(n_seg, label, ty_s);
764 fields_v.insert(n_seg, label, ty_v);
765 }
766 FiberTyV_::Over(_) => {
767 elab.error::<()>(format!(
768 "instance clause {name} cannot be annotated with a bare \
769 element type",
770 ));
771 failed = true;
772 }
773 }
774 }
775 App2(L(_, Keyword(":=")), L(_, Var(field_name)), L(_, Tuple(entries)))
778 if !entries.is_empty()
779 && entries
780 .iter()
781 .all(|e| matches!(e.ast0(), App2(L(_, Keyword(":=")), _, _))) =>
782 {
783 let Some(codomain) = elab.instance_codomain() else {
784 elab.error::<()>(
785 "mapping-literal assignment is only allowed inside an instance body",
786 );
787 failed = true;
788 continue;
789 };
790 let f_seg = name_seg(*field_name);
791 if !codomain.fields.has(f_seg) {
792 elab.error::<()>(format!("no such codomain field {field_name}"));
793 failed = true;
794 continue;
795 }
796 let mut entry_failed = false;
802 for entry_n in entries.iter() {
803 elab.loc = Some(entry_n.loc());
804 let App2(L(_, Keyword(":=")), key_n, target_n) = entry_n.ast0() else {
805 unreachable!("guard ensured all entries are `:=` clauses");
806 };
807 let (key_s, key_v, key_ty) = elab.fiber_syn(key_n);
808 let label = format!("{field_name} key");
809 let mor_path = vec![(name_seg(*field_name), label_seg(*field_name))];
810 let (lhs_s, lhs_v, lhs_ty) =
811 elab.apply_codomain_morphism(&mor_path, key_s, key_v, key_ty, &label);
812 let FiberTyV_::Over(cod_obj) = &*lhs_ty else {
813 entry_failed = true;
814 break;
815 };
816 let cod_obj = cod_obj.clone();
817 let (rhs_s, rhs_v) = elab.fiber_chk(&lhs_ty, target_n);
818 let (id_s, id_v) =
819 elab.fiber_id_field(&lhs_ty, &cod_obj, lhs_s, lhs_v, rhs_s, rhs_v);
820 let (eqn, eql) = next_eq_field(&mut eq_count);
821 fields_s.insert(eqn, eql, id_s);
822 fields_v.insert(eqn, eql, id_v);
823 }
824 if entry_failed {
825 failed = true;
826 continue;
827 }
828 }
829 App2(L(_, Keyword(":=")), L(_, Var(field_name)), L(_, Tuple(name_ns))) => {
832 let Some(codomain) = elab.instance_codomain() else {
833 elab.error::<()>(
834 "set-literal field assignment is only allowed inside an \
835 instance body",
836 );
837 failed = true;
838 continue;
839 };
840 let f_seg = name_seg(*field_name);
841 let f_label = label_seg(*field_name);
842 let Some(field_ty_s) = codomain.fields.get(f_seg) else {
843 elab.error::<()>(format!("no such codomain field {field_name}"));
844 failed = true;
845 continue;
846 };
847 if !matches!(&**field_ty_s, BaseTyS_::Object(_)) {
848 elab.error::<()>(format!(
849 "set-literal assignment requires field {field_name} to be \
850 object-typed",
851 ));
852 failed = true;
853 continue;
854 }
855 let Some(gen_obj_v) = elab.codomain_object(f_seg, f_label) else {
857 elab.error::<()>(
858 "set-literal field assignment is only allowed inside an \
859 instance body",
860 );
861 failed = true;
862 continue;
863 };
864 let gen_obj_s = elab.evaluator().quote_tm(&gen_obj_v);
865 for name_n in name_ns.iter() {
866 let Var(gen_name) = name_n.ast0() else {
867 elab.loc = Some(name_n.loc());
868 elab.error::<()>("set-literal entries must be bare names");
869 failed = true;
870 break;
871 };
872 let gen_seg = name_seg(*gen_name);
873 let gen_label = label_seg(*gen_name);
874 elab.intro_fiber(gen_seg, gen_label, FiberTyV::over(gen_obj_v.clone()));
875 fields_s.insert(gen_seg, gen_label, FiberTyS::over(gen_obj_s.clone()));
876 fields_v.insert(gen_seg, gen_label, FiberTyV::over(gen_obj_v.clone()));
877 }
878 }
879 App2(L(_, Keyword(":=")), lhs_n, rhs_n) => {
881 let (lhs_s, lhs_v, lhs_ty) = elab.fiber_syn(lhs_n);
882 let FiberTyV_::Over(obj) = &*lhs_ty else {
883 elab.loc = Some(lhs_n.loc());
884 elab.report_fiber(FiberError::MappingLhsNotOver);
885 failed = true;
886 continue;
887 };
888 let obj = obj.clone();
889 let (rhs_s, rhs_v) = elab.fiber_chk(&lhs_ty, rhs_n);
890 let (id_s, id_v) =
891 elab.fiber_id_field(&lhs_ty, &obj, lhs_s, lhs_v, rhs_s, rhs_v);
892 let (eqn, eql) = next_eq_field(&mut eq_count);
893 fields_s.insert(eqn, eql, id_s);
894 fields_v.insert(eqn, eql, id_v);
895 }
896 _ => {
897 elab.error::<()>(
898 "expected fields in the form `name : type`, \
899 `field := [names]`, or `mor(arg) := target`",
900 );
901 failed = true;
902 }
903 }
904 }
905
906 if failed {
909 return empty();
910 }
911 (FiberTyS::record(fields_s), FiberTyV::record(fields_v))
912 }
913
914 fn binding(&mut self, n: &FNtn) -> Option<(VarName, LabelSegment, BaseTyS, BaseTyV)> {
915 let mut elab = self.enter(n.loc());
916 match n.ast0() {
917 App2(L(_, Keyword(":")), L(_, Var(name)), ty_n) => {
918 let (ty_s, ty_v) = elab.ty(ty_n);
919 Some((name_seg(*name), label_seg(*name), ty_s, ty_v))
920 }
921 _ => elab.error("unexpected notation for binding"),
922 }
923 }
924
925 fn lookup_ty(&mut self, name: VarName) -> (BaseTyS, BaseTyV) {
926 let qname = QualifiedName::single(name);
927 if let Some(ob_type) = self.theory().basic_ob_type(qname) {
928 (BaseTyS::object(ob_type.clone()), BaseTyV::object(ob_type))
929 } else if let Some(d) = self.toplevel.declarations.get(&name) {
930 match d {
931 TopDecl::Type(t) => {
932 if t.theory == self.theory {
933 (BaseTyS::topvar(name), t.val.clone())
934 } else {
935 self.ty_error(format!(
936 "{name} refers to a type in theory {}, expected a type in theory {}",
937 t.theory, self.theory
938 ))
939 }
940 }
941 TopDecl::Instance(_) => self.ty_error(format!(
946 "{name} refers to an instance, which is not a base type; \
947 an instance can only be imported inside another instance body"
948 )),
949 TopDecl::Def(_) => self.ty_error(format!("{name} refers to a term not a type")),
950 }
951 } else {
952 self.ty_error(format!("no such type {name} defined"))
953 }
954 }
955 fn morphism_ty(&mut self, n: &FNtn) -> Option<(MorType, ObType, ObType)> {
956 let elab = self.enter(n.loc());
957 let theory = elab.theory();
958 match n.ast0() {
959 App1(L(_, Keyword("Hom")), L(_, Var(name))) => {
960 let qname = QualifiedName::single(name_seg(*name));
961 if let Some(ob_type) = theory.basic_ob_type(qname) {
962 if let Some(hom_type) = theory.hom_type(ob_type.clone()) {
963 Some((hom_type, ob_type.clone(), ob_type))
964 } else {
965 elab.error(format!("object type {name} does not have hom type"))
966 }
967 } else {
968 elab.error(format!("no such object type {name}"))
969 }
970 }
971 Var(name) => {
972 let qname = QualifiedName::single(name_seg(*name));
973 if let Some(mor_type) = theory.basic_mor_type(qname) {
974 let dom = theory.src_type(&mor_type);
975 let cod = theory.tgt_type(&mor_type);
976 Some((mor_type, dom, cod))
977 } else {
978 elab.error(format!("no such morphism type {name}"))
979 }
980 }
981 _ => elab.error("unexpected notation for morphism type"),
982 }
983 }
984
985 fn path(&mut self, n: &FNtn) -> Option<Vec<(NameSegment, LabelSegment)>> {
986 let mut elab = self.enter(n.loc());
987 match n.ast0() {
988 Field(f) => Some(vec![(name_seg(*f), label_seg(*f))]),
989 App1(p_n, L(_, Field(f))) => {
990 let mut p = elab.path(p_n)?;
991 p.push((name_seg(*f), label_seg(*f)));
992 Some(p)
993 }
994 _ => elab.error("unexpected notation for path"),
995 }
996 }
997
998 #[allow(clippy::type_complexity)]
999 fn specialization(
1000 &mut self,
1001 n: &FNtn,
1002 ) -> Option<(Vec<(NameSegment, LabelSegment)>, BaseTyS, BaseTyV)> {
1003 let mut elab = self.enter(n.loc());
1004 match n.ast0() {
1005 App2(L(_, Keyword(":")), p_n, ty_n) => {
1006 let p = elab.path(p_n)?;
1007 let (ty_s, ty_v) = elab.ty(ty_n);
1008 Some((p, ty_s, ty_v))
1009 }
1010 App2(L(_, Keyword(":=")), p_n, tm_n) => {
1011 let p = elab.path(p_n)?;
1012 let (tm_s, tm_v, ty_v) = elab.syn(tm_n);
1013 Some((
1014 p,
1015 BaseTyS::sing(elab.evaluator().quote_ty(&ty_v), tm_s),
1016 BaseTyV::sing(ty_v, tm_v),
1017 ))
1018 }
1019 _ => elab.error("unexpected notation for specialization"),
1020 }
1021 }
1022
1023 pub fn ty(&mut self, n: &FNtn) -> (BaseTyS, BaseTyV) {
1025 let mut elab = self.enter(n.loc());
1026 match n.ast0() {
1027 Var(name) => elab.lookup_ty(name_seg(*name)),
1028 Keyword("Unit") => elab.empty_record_ty(),
1029 App1(L(_, Prim("sing")), tm_n) => {
1030 let (tm_s, tm_v, ty_v) = elab.syn(tm_n);
1031 (BaseTyS::sing(elab.evaluator().quote_ty(&ty_v), tm_s), BaseTyV::sing(ty_v, tm_v))
1032 }
1033 App1(mt_n, L(_, Tuple(domcod_n))) => {
1034 let [dom_n, cod_n] = domcod_n.as_slice() else {
1035 return elab.ty_error("expected two arguments for morphism type");
1036 };
1037 let Some((mt, dom_ty, cod_ty)) = elab.morphism_ty(mt_n) else {
1038 return elab.ty_hole();
1039 };
1040 let (dom_s, dom_v) = elab.chk(&BaseTyV::object(dom_ty.clone()), dom_n);
1041 let (cod_s, cod_v) = elab.chk(&BaseTyV::object(cod_ty.clone()), cod_n);
1042 (
1043 BaseTyS::morphism(mt.clone(), dom_s, cod_s),
1044 BaseTyV::morphism(mt.clone(), dom_v, cod_v),
1045 )
1046 }
1047 Tuple(field_ns) => {
1048 let mut field_ty_vs = Vec::<(FieldName, (LabelSegment, BaseTyV))>::new();
1049 let mut failed = false;
1050 let self_var = elab.intro(name_seg("self"), label_seg("self"), None).unwrap_neu();
1051 let c = elab.checkpoint();
1052 for field_n in field_ns.iter() {
1053 elab.loc = Some(field_n.loc());
1054 let Some((name, label, ty_n)) = (match field_n.ast0() {
1055 App2(L(_, Keyword(":")), L(_, Var(name)), ty_n) => {
1056 let name_seg = name_seg(*name);
1057 Some((name_seg, label_seg(*name), ty_n))
1058 }
1059 _ => elab.error("expected fields in the form <name> : <type>"),
1060 }) else {
1061 failed = true;
1062 continue;
1063 };
1064 let (_, ty_v) = elab.ty(ty_n);
1065 field_ty_vs.push((name, (label, ty_v.clone())));
1066 elab.ctx.push_scope(name, label, Some(ty_v.clone()));
1067 elab.ctx.env = elab
1068 .ctx
1069 .env
1070 .snoc(BaseTmV::neu(TmN::proj(self_var.clone(), name, label), ty_v));
1071 }
1072 if failed {
1073 return elab.ty_hole();
1074 }
1075 elab.reset_to(c);
1076 let field_tys: Row<_> = field_ty_vs
1077 .iter()
1078 .map(|(name, (label, ty_v))| (*name, (*label, elab.evaluator().quote_ty(ty_v))))
1079 .collect();
1080 let r_v = RecordV::new(elab.ctx.env.clone(), field_tys.clone(), Dtry::empty());
1081 (BaseTyS::record(field_tys), BaseTyV::record(r_v))
1082 }
1083 App2(L(_, Keyword("&")), ty_n, L(_, Tuple(specialization_ns))) => {
1084 let (ty_s, mut ty_v) = elab.ty(ty_n);
1085 let mut specializations = Vec::new();
1086 for specialization_n in specialization_ns.iter() {
1093 elab.loc = Some(specialization_n.loc());
1094 let Some((path, sty_s, sty_v)) = elab.specialization(specialization_n) else {
1095 return elab.ty_hole();
1096 };
1097 match elab.evaluator().try_specialize(&ty_v, &path, sty_v) {
1098 Ok(specialized) => {
1099 ty_v = specialized;
1100 specializations.push((path, sty_s));
1101 }
1102 Err(s) => {
1103 return elab
1104 .ty_error(format!("Failed to specialize:\n... because {s}"));
1105 }
1106 }
1107 }
1108 (BaseTyS::specialize(ty_s, specializations), ty_v)
1109 }
1110 App2(L(_, Keyword("==")), tm1_n, tm2_n) => {
1111 let (tm1_s, tm1_v, tm1_ty) = elab.syn(tm1_n);
1112 let (tm2_s, tm2_v, tm2_ty) = elab.syn(tm2_n);
1113 if !matches!(&*tm1_ty, BaseTyV_::Morphism(_, _, _)) {
1114 elab.loc = Some(tm1_n.loc());
1115 return elab.ty_error(
1116 "Equality types are only supported for morphisms; equations \
1117 between instance elements live inside an instance body",
1118 );
1119 }
1120 if let Err(e) = elab.evaluator().convertible_ty(&tm1_ty, &tm2_ty) {
1121 let eval = elab.evaluator();
1122 return elab.ty_error(format!(
1123 "types {} and {} are not convertible:\n{}",
1124 eval.quote_ty(&tm1_ty),
1125 eval.quote_ty(&tm2_ty),
1126 e.pretty()
1127 ));
1128 }
1129 let eq_ty_s = BaseTyS::id(elab.evaluator().quote_ty(&tm1_ty), tm1_s, tm2_s);
1130 let eq_ty_v = BaseTyV::id(tm1_ty, tm1_v, tm2_v);
1131 (eq_ty_s, eq_ty_v)
1132 }
1133 _ => elab.ty_error("unexpected notation for type"),
1134 }
1135 }
1136
1137 fn lookup_tm(&mut self, name: Ustr) -> (BaseTmS, BaseTmV, BaseTyV) {
1138 let label = label_seg(name);
1139 let name = name_seg(name);
1140 if let Some((i, _, ty)) = self.ctx.lookup(name) {
1141 (
1142 BaseTmS::var(i, name, label),
1143 self.ctx.env.get(*i).unwrap().clone(),
1144 ty.clone().unwrap(),
1145 )
1146 } else if let Some(d) = self.toplevel.lookup(name) {
1147 match d {
1148 TopDecl::Type(_) => self.syn_error(format!("{name} refers type, not term")),
1149 TopDecl::Def(d) if d.args.is_empty() => {
1153 let def = d.clone();
1154 let eval = self.evaluator();
1155 (
1156 BaseTmS::topapp(name, vec![]),
1157 eval.eval_tm(&def.body),
1158 eval.eval_ty(&def.ret_ty),
1159 )
1160 }
1161 TopDecl::Def(_) => self.syn_error(format!("{name} must be applied to arguments")),
1162 TopDecl::Instance(_) => self.syn_error(format!(
1163 "{name} refers to an instance; use it in type position to import it, \
1164 not as a term"
1165 )),
1166 }
1167 } else {
1168 self.syn_error(format!("no such variable {name}"))
1169 }
1170 }
1171
1172 fn syn(&mut self, n: &FNtn) -> (BaseTmS, BaseTmV, BaseTyV) {
1174 let mut elab = self.enter(n.loc());
1175 match n.ast0() {
1176 Var(name) => elab.lookup_tm(ustr(name)),
1177 App1(tm_n, L(_, Field(f))) => {
1178 if let Var(inst) = tm_n.ast0()
1183 && matches!(
1184 elab.toplevel.declarations.get(&name_seg(*inst)),
1185 Some(TopDecl::Instance(_))
1186 )
1187 {
1188 return elab.syn_error(
1189 "cannot project a field out of an instance; an instance is \
1190 eliminated by mapping out of it, not by projection",
1191 );
1192 }
1193 let (tm_s, tm_v, ty_v) = elab.syn(tm_n);
1194 let BaseTyV_::Record(r) = &*ty_v else {
1195 return elab.syn_error("can only project from record type");
1196 };
1197 let label = label_seg(*f);
1198 let f = name_seg(*f);
1199 if !r.fields.has(f) {
1200 return elab.syn_error(format!("no such field {f}"));
1201 }
1202 (
1203 BaseTmS::proj(tm_s, f, label),
1204 elab.evaluator().proj(&tm_v, f, label),
1205 elab.evaluator().field_ty(&ty_v, &tm_v, f),
1206 )
1207 }
1208 App1(L(_, Prim("id")), ob_n) => {
1212 let (ob_s, ob_v, ob_t) = elab.syn(ob_n);
1213 let BaseTyV_::Object(ob_type) = &*ob_t else {
1214 return elab.syn_error("can only apply @id to objects");
1215 };
1216 let Some(mor_type) = elab.theory().hom_type(ob_type.clone()) else {
1217 return elab.syn_error("object type does not have a hom type");
1218 };
1219 (
1220 BaseTmS::id(ob_s),
1221 BaseTmV::id(ob_v.clone()),
1222 BaseTyV::morphism(mor_type, ob_v.clone(), ob_v),
1223 )
1224 }
1225 App1(L(_, Prim("tab")), mor_n) => {
1226 let (mor_s, mor_v, mor_t) = elab.syn(mor_n);
1227 let BaseTyV_::Morphism(mor_type, _, _) = &*mor_t else {
1228 return elab.syn_error("can only apply @tab to morphisms");
1229 };
1230 let Some(ob_type) = elab.theory().tabulator(mor_type.clone()) else {
1231 return elab.syn_error("theory does not have tabulators");
1232 };
1233 (BaseTmS::tab(mor_s), BaseTmV::tab(mor_v.clone()), BaseTyV::object(ob_type))
1234 }
1235 App1(L(_, Prim(name)), ob_n) => {
1236 let name = name_seg(*name);
1237 let Some(ob_op) = elab.theory().basic_ob_op([name].into()) else {
1238 let th_name = elab.theory.name.to_string();
1239 return elab.syn_error(format!("operation @{name} not in theory {th_name}"));
1240 };
1241 let dom = elab.theory().ob_op_dom(&ob_op);
1242 let (arg_s, arg_v) = elab.chk(&BaseTyV::object(dom), ob_n);
1243 let cod = elab.theory().ob_op_cod(&ob_op);
1244 (BaseTmS::ob_app(name, arg_s), BaseTmV::app(name, arg_v), BaseTyV::object(cod))
1245 }
1246 App2(L(_, Keyword("*")), f_n, g_n) => {
1247 let (f_s, f_v, f_ty) = elab.syn(f_n);
1248 let (g_s, g_v, g_ty) = elab.syn(g_n);
1249 let BaseTyV_::Morphism(f_mt, f_dom, f_cod) = &*f_ty else {
1250 elab.loc = Some(f_n.loc());
1251 return elab.syn_error("expected a morphism");
1252 };
1253 let BaseTyV_::Morphism(g_mt, g_dom, g_cod) = &*g_ty else {
1254 elab.loc = Some(g_n.loc());
1255 return elab.syn_error("expected a morphism");
1256 };
1257 let theory = elab.theory();
1258 if theory.tgt_type(f_mt) != theory.src_type(g_mt) {
1259 return elab.syn_error("incompatible morphism types");
1260 }
1261 if let Err(s) = elab.evaluator().equal_tm(f_cod, g_dom) {
1262 let f_cod_s = elab.evaluator().quote_tm(f_cod);
1263 let g_dom_s = elab.evaluator().quote_tm(g_dom);
1264 return elab.syn_error(format!(
1265 "codomain {} and domain {} not equal:\n...because {}",
1266 f_cod_s,
1267 g_dom_s,
1268 s.pretty(),
1269 ));
1270 }
1271 (
1272 BaseTmS::compose(f_s, g_s),
1273 BaseTmV::compose(f_v, g_v),
1274 BaseTyV::morphism(
1275 elab.theory().compose_types2(f_mt.clone(), g_mt.clone()).unwrap(),
1276 f_dom.clone(),
1277 g_cod.clone(),
1278 ),
1279 )
1280 }
1281 App1(L(_, Var(tv)), L(_, Tuple(args_n))) => {
1282 let tv = name_seg(*tv);
1283 let Some(TopDecl::Def(d)) = elab.toplevel.lookup(tv) else {
1284 return elab.syn_error(format!("no such toplevel def {tv}"));
1285 };
1286 let mut arg_stxs = Vec::new();
1287 let mut env = Env::nil();
1288 if args_n.len() != d.args.len() {
1289 return elab.syn_error(format!(
1290 "wrong number of args for {tv}, expected {}, got {}",
1291 d.args.len(),
1292 args_n.len()
1293 ));
1294 }
1295 for (arg_n, (_, (_, arg_ty_s))) in args_n.iter().zip(d.args.iter()) {
1296 let arg_ty_v = elab.evaluator().with_env(env.clone()).eval_ty(arg_ty_s);
1297 let (arg_s, arg_v) = elab.chk(&arg_ty_v, arg_n);
1298 arg_stxs.push(arg_s);
1299 env = env.snoc(arg_v);
1300 }
1301 let eval = elab.evaluator().with_env(env.clone());
1302 (BaseTmS::topapp(tv, arg_stxs), eval.eval_tm(&d.body), eval.eval_ty(&d.ret_ty))
1303 }
1304 Tag("tt") => {
1305 let (_, ty_v) = elab.empty_record_ty();
1307 (BaseTmS::cons(Row::empty()), BaseTmV::cons(Row::empty()), ty_v)
1308 }
1309 Tuple(_) => elab.syn_error("must check against a type in order to construct a record"),
1310 Prim("hole") => elab.syn_error("explicit hole"),
1311 _ => elab.syn_error("unexpected notation for term"),
1312 }
1313 }
1314
1315 fn chk(&mut self, ty: &BaseTyV, n: &FNtn) -> (BaseTmS, BaseTmV) {
1317 let mut elab = self.enter(n.loc());
1318 match (&**ty, n.ast0()) {
1319 (BaseTyV_::Record(r), Tuple(field_ns)) => {
1320 if r.fields.len() != field_ns.len() {
1326 return elab.chk_error(format!(
1327 "wrong number of fields provided, expected {}, got {}",
1328 r.fields.len(),
1329 field_ns.len(),
1330 ));
1331 }
1332 let mut field_stxs = IndexMap::new();
1333 let mut field_vals = IndexMap::new();
1334 for (field_n, (name, (label, field_ty_s))) in field_ns.iter().zip(r.fields.iter()) {
1335 elab.loc = Some(field_n.loc());
1336 let tm_n = match field_n.ast0() {
1337 App2(L(_, Keyword(":=")), L(_, Var(given_name)), field_val_n) => {
1338 if name_seg(*given_name) == *name {
1339 field_val_n
1340 } else {
1341 return elab.chk_error(format!("unexpected field {given_name}"));
1342 }
1343 }
1344 _ => {
1345 return elab.chk_error("unexpected notation for field");
1346 }
1347 };
1348 let v = BaseTmV::cons(field_vals.clone().into());
1349 let field_ty_v =
1350 elab.evaluator().with_env(r.env.snoc(v.clone())).eval_ty(field_ty_s);
1351 let (tm_s, tm_v) = elab.chk(&field_ty_v, tm_n);
1352 field_stxs.insert(*name, (*label, tm_s));
1353 field_vals.insert(*name, (*label, tm_v));
1354 }
1355 (BaseTmS::cons(field_stxs.into()), BaseTmV::cons(field_vals.into()))
1356 }
1357 (BaseTyV_::Object(ob_type), Tuple(ob_ns)) => {
1358 let Some(ob_type) = ob_type.clone().list_arg() else {
1359 return elab.chk_error("expected to object type to be a list");
1360 };
1361 let elem_ty_v = BaseTyV::object(ob_type);
1362 let mut elem_stxs = Vec::new();
1363 let mut elem_vals = Vec::new();
1364 for ob_n in ob_ns {
1365 elab.loc = Some(ob_n.loc());
1366 let (tm_s, tm_v) = elab.chk(&elem_ty_v, ob_n);
1367 elem_stxs.push(tm_s);
1368 elem_vals.push(tm_v);
1369 }
1370 (BaseTmS::list(elem_stxs), BaseTmV::list(elem_vals))
1371 }
1372 (_, Tuple(_)) => elab.chk_error("tuple expected to be record or object/morphism type"),
1373 (_, Prim("hole")) => elab.chk_error("explicit hole"),
1374 _ => {
1375 let (tm_s, tm_v, synthed) = elab.syn(n);
1376 let eval = elab.evaluator();
1377 if let Err(e) = eval.convertible_ty(&synthed, ty) {
1378 return elab.chk_error(format!(
1379 "synthesized type {} does not match expected type {}:\n{}",
1380 eval.quote_ty(&synthed),
1381 eval.quote_ty(ty),
1382 e.pretty()
1383 ));
1384 }
1385 if let Err(e) = eval.element_of(&tm_v, ty) {
1386 return elab.chk_error(format!(
1387 "evaluated term {} is not an element of specialized type {}:\n{}",
1388 eval.quote_tm(&tm_v),
1389 eval.quote_ty(ty),
1390 e.pretty()
1391 ));
1392 }
1393 (tm_s, tm_v)
1394 }
1395 }
1396 }
1397}
1398
1399impl<'a> FiberElab for Elaborator<'a> {
1403 fn ctx(&self) -> &Context {
1404 &self.ctx
1405 }
1406
1407 fn ctx_mut(&mut self) -> &mut Context {
1408 &mut self.ctx
1409 }
1410
1411 fn elab_theory(&self) -> &Theory {
1412 &self.theory
1413 }
1414
1415 fn evaluator(&self) -> Evaluator<'_> {
1416 Elaborator::evaluator(self)
1417 }
1418
1419 fn fresh_meta(&mut self) -> MetaVar {
1420 Elaborator::fresh_meta(self)
1421 }
1422
1423 fn report_fiber(&mut self, err: FiberError) {
1427 let msg = match err {
1428 FiberError::UnknownElement(name) => format!("no such fiber element {name}"),
1429 FiberError::ProjNonRecord => {
1430 "can only project a generator out of a sub-instance".to_string()
1431 }
1432 FiberError::UnknownProj(field) => {
1433 format!("no such generator {field} in sub-instance")
1434 }
1435 FiberError::UnknownObOp(op, th) => format!("operation @{op} not in theory {th}"),
1436 FiberError::ObOpOnNonElement(op) => format!("@{op} applied to a non-fiber-element"),
1437 FiberError::ListElementNotOver => {
1438 "fiber list elements must be elements over an object".to_string()
1439 }
1440 FiberError::MissingTerm => "missing term".to_string(),
1442 FiberError::ArgNotElement(label) => match label {
1443 Some(label) => format!("argument {label} is not an element over an object"),
1444 None => "argument is not an element over an object".to_string(),
1445 },
1446 FiberError::NotAMorphism(path) => {
1447 format!("codomain field {path} is not a morphism")
1448 }
1449 FiberError::ArgMismatch { path, got, expected, detail } => {
1450 format!("argument to {path} lies over {got}, but it expects {expected}:\n{detail}")
1451 }
1452 FiberError::WrongFiberType(detail) => {
1453 format!("fiber element has the wrong type:\n{detail}")
1454 }
1455 FiberError::MappingLhsNotOver => {
1456 "mapping-entry clause `mor(arg) := target` requires the LHS \
1457 to be an element over an object (a fiber element); morphism \
1458 equations constrain the model, not an instance"
1459 .to_string()
1460 }
1461 FiberError::EquationNotOver => {
1462 "instance equations must be between elements over an object \
1463 (fiber elements); morphism equations constrain the model, not \
1464 an instance"
1465 .to_string()
1466 }
1467 FiberError::InconvertibleEquationSides(detail) => {
1468 format!("equation sides have inconvertible fiber types:\n{detail}")
1469 }
1470 FiberError::ImportCodomainMismatch(name) => {
1471 format!(
1472 "cannot import {name}: it is an instance of a different model than \
1473 the enclosing instance"
1474 )
1475 }
1476 };
1477 self.reporter.error_option_loc(self.loc, ELAB_ERROR, msg);
1478 }
1479}
1480
1481fn morphism_path(n: &FNtn) -> Option<Vec<(FieldName, LabelSegment)>> {
1482 match n.ast0() {
1483 Var(f) => Some(vec![(name_seg(*f), label_seg(*f))]),
1484 App1(recv, L(_, Field(g))) => {
1485 let mut p = morphism_path(recv)?;
1486 p.push((name_seg(*g), label_seg(*g)));
1487 Some(p)
1488 }
1489 _ => None,
1490 }
1491}
1492
1493fn next_eq_field(eq_count: &mut usize) -> (FieldName, LabelSegment) {
1498 let key = format!("_eq{}", *eq_count);
1499 *eq_count += 1;
1500 (name_seg(key.as_str()), label_seg(key.as_str()))
1501}
1502
1503#[cfg(test)]
1505mod tests {
1506 use expect_test::expect;
1507 use std::rc::Rc;
1508
1509 use crate::stdlib;
1510 use crate::tt::modelgen::Model;
1511
1512 #[test]
1513 fn generate_model_from_text() {
1514 let th = Rc::new(stdlib::th_signed_category());
1515 let source = "[
1516 x : Object,
1517 loop : Negative[x, x]
1518 ]";
1519 let model = Model::from_text(&th.clone().into(), source).unwrap();
1520 let model = model.as_discrete().unwrap();
1521 assert_eq!(model, stdlib::models::negative_loop(th));
1522 }
1523
1524 #[test]
1526 fn generate_model_with_eqn() {
1527 let th = Rc::new(stdlib::th_schema()).into();
1528 let source = "[
1529 NW : Entity,
1530 NE : Entity,
1531 SW : Entity,
1532 SE : Entity,
1533 t : (Hom Entity)[NW,NE],
1534 l : (Hom Entity)[NW,SW],
1535 r : (Hom Entity)[NE,SE],
1536 b : (Hom Entity)[SW, SE],
1537 comm : (t * r == l * b)
1538 ]";
1539 let model = Model::from_text(&th, source).unwrap().as_discrete().unwrap();
1540 let eqns: Vec<_> = model.category.equations().collect();
1541 assert_eq!(eqns.len(), 1);
1542 }
1543
1544 #[test]
1545 fn text_error_reporting() {
1546 let th = Rc::new(stdlib::th_schema()).into();
1547
1548 let result = Model::from_text(&th, "[ : Entit]");
1549 let expected = expect![[r#"
1550 error[elab]: expected fields in the form <name> : <type>
1551 --> <none>:1:3
1552 1| [ : Entit]
1553 1| ^^^^^^^
1554 "#]];
1555 expected.assert_eq(&result.err().unwrap());
1556
1557 let result = Model::from_text(&th, "[x : Entity, f : Hom(Entit)[x,x]]");
1558 let expected = expect![[r#"
1559 error[elab]: no such object type Entit
1560 --> <none>:1:18
1561 1| [x : Entity, f : Hom(Entit)[x,x]]
1562 1| ^^^^^^^^^^
1563 "#]];
1564 expected.assert_eq(&result.err().unwrap());
1565
1566 let result = Model::from_text(&th, "[x : Entity, f : Hom(Entity)[x,y]]");
1567 let expected = expect![[r#"
1568 error[elab]: no such variable y
1569 --> <none>:1:32
1570 1| [x : Entity, f : Hom(Entity)[x,y]]
1571 1| ^
1572 error[elab]: synthesized type ?1 does not match expected type Entity:
1573 tried to convert between types of different type constructors
1574 --> <none>:1:32
1575 1| [x : Entity, f : Hom(Entity)[x,y]]
1576 1| ^
1577 "#]];
1578 expected.assert_eq(&result.err().unwrap());
1579 }
1580}