1use super::check::{Decl, DefnDecl, Header};
20use super::env::{Const, CtorInfo, Hint, InductiveInfo, Kind, QuotKind, Safety};
21use super::error::{KResult, KernelFailure};
22use super::expr::{ExprId, Node};
23use super::level::LevelId;
24use super::logos::{explicit_levels, lower};
25use super::name::NameId;
26use super::tc::Kernel;
27use crate::context::{Context, Registration};
28use crate::quotient::PreludeKind;
29use crate::term::{Literal, Term};
30use std::collections::{BTreeMap, BTreeSet};
31use std::rc::Rc;
32
33#[derive(Clone, Debug)]
35pub struct Replayed {
36 pub name: String,
37 pub kind: &'static str,
38 pub verdict: Result<(), String>,
39}
40
41#[derive(Clone, Debug)]
44pub enum Declaration {
45 Inductive {
48 name: String,
49 params: Vec<String>,
50 arity: Term,
51 num_params: usize,
52 ctors: Vec<(String, Term)>,
53 },
54 Definition {
55 name: String,
56 params: Vec<String>,
57 ty: Term,
58 body: Term,
59 },
60 Axiom {
61 name: String,
62 params: Vec<String>,
63 ty: Term,
64 },
65 Quotient {
69 primitives: Vec<(QuotKind, String, Vec<String>, Term)>,
70 equality: String,
71 },
72 Observational {
76 constants: Vec<(String, Vec<String>, Term)>,
77 after: Vec<String>,
78 },
79}
80
81impl Declaration {
82 fn name(&self) -> &str {
83 match self {
84 Declaration::Inductive { name, .. }
85 | Declaration::Definition { name, .. }
86 | Declaration::Axiom { name, .. } => name,
87 Declaration::Quotient { primitives, .. } => &primitives[0].1,
88 Declaration::Observational { constants, .. } => &constants[0].0,
89 }
90 }
91
92 pub(crate) fn names(&self) -> Vec<&str> {
94 match self {
95 Declaration::Inductive { name, ctors, .. } => std::iter::once(name.as_str())
96 .chain(ctors.iter().map(|(c, _)| c.as_str()))
97 .collect(),
98 Declaration::Quotient { primitives, .. } => {
99 primitives.iter().map(|p| p.1.as_str()).collect()
100 }
101 Declaration::Observational { constants, .. } => {
102 constants.iter().map(|c| c.0.as_str()).collect()
103 }
104 _ => vec![self.name()],
105 }
106 }
107
108 fn kind(&self) -> &'static str {
109 match self {
110 Declaration::Inductive { .. } => "inductive",
111 Declaration::Definition { .. } => "definition",
112 Declaration::Axiom { .. } => "axiom",
113 Declaration::Quotient { .. } => "quotient",
114 Declaration::Observational { .. } => "observational",
115 }
116 }
117
118 pub(crate) fn terms(&self) -> Vec<&Term> {
119 match self {
120 Declaration::Inductive { arity, ctors, .. } => std::iter::once(arity)
121 .chain(ctors.iter().map(|(_, t)| t))
122 .collect(),
123 Declaration::Definition { ty, body, .. } => vec![ty, body],
124 Declaration::Axiom { ty, .. } => vec![ty],
125 Declaration::Quotient { primitives, .. } => primitives.iter().map(|p| &p.3).collect(),
126 Declaration::Observational { constants, .. } => {
127 constants.iter().map(|c| &c.2).collect()
128 }
129 }
130 }
131}
132
133pub fn replay(ctx: &Context) -> (Kernel, Vec<Replayed>) {
135 let (k, _, verdicts) = replay_items(ctx);
136 (k, verdicts)
137}
138
139pub(crate) fn replay_items(ctx: &Context) -> (Kernel, Vec<Declaration>, Vec<Replayed>) {
141 let items = collect(ctx);
142 let mut k = Kernel::logos(ctx);
143 let verdicts = admit_items(&mut k, ctx, &items);
144 (k, items, verdicts)
145}
146
147pub(crate) fn admit_items(k: &mut Kernel, ctx: &Context, items: &[Declaration]) -> Vec<Replayed> {
150 let mut out = Vec::new();
151 for component in order(ctx, items) {
152 let members: Vec<&Declaration> = component.iter().map(|i| &items[*i]).collect();
153 let verdict = admit_block(k, ctx, &members).map_err(|e| e.to_string());
154 for m in &members {
155 let names = match m {
156 Declaration::Quotient { .. } | Declaration::Observational { .. } => m.names(),
157 _ => vec![m.name()],
158 };
159 for name in names {
160 out.push(Replayed {
161 name: name.to_string(),
162 kind: m.kind(),
163 verdict: verdict.clone(),
164 });
165 }
166 }
167 }
168 out
169}
170
171pub fn admit(k: &mut Kernel, ctx: &Context, block: &[Declaration]) -> Result<(), String> {
174 let members: Vec<&Declaration> = block.iter().collect();
175 admit_block(k, ctx, &members).map_err(|e| e.to_string())
176}
177
178fn admit_block(k: &mut Kernel, ctx: &Context, members: &[&Declaration]) -> KResult<()> {
179 if members.is_empty() {
180 return Ok(());
181 }
182 if members.len() > 1
183 && !members
184 .iter()
185 .all(|m| matches!(m, Declaration::Inductive { .. }))
186 {
187 return Err(KernelFailure::reject(
188 "part of a dependency cycle that is not a mutual inductive block",
189 ));
190 }
191 match members[0] {
192 Declaration::Inductive { .. } => admit_inductives(k, ctx, members),
193 Declaration::Definition {
194 name,
195 params,
196 ty,
197 body,
198 } => admit_definition(k, ctx, name, params, ty, body),
199 Declaration::Axiom { name, params, ty } => admit_axiom(k, ctx, name, params, ty),
200 Declaration::Quotient {
201 primitives,
202 equality,
203 } => admit_quotient(k, ctx, primitives, equality),
204 Declaration::Observational { constants, .. } => constants
205 .iter()
206 .try_for_each(|(name, params, ty)| admit_axiom(k, ctx, name, params, ty)),
207 }
208}
209
210fn level_params(ctx: &Context, name: &str, ty: &Term) -> Vec<String> {
214 match super::logos::level_telescope(ctx, name) {
215 Some((ps, _)) => ps,
216 None => crate::term::free_level_vars(ty),
217 }
218}
219
220fn collect(ctx: &Context) -> Vec<Declaration> {
221 let names: BTreeSet<&str> = ctx
222 .iter_inductives()
223 .map(|(n, _)| n)
224 .chain(ctx.iter_definitions().map(|(n, _, _)| n))
225 .chain(ctx.iter_universe_polys().map(|(n, ..)| n))
226 .chain(ctx.iter_declarations().map(|(n, _)| n))
227 .collect();
228 let mut items: BTreeMap<String, Declaration> = names
229 .into_iter()
230 .filter_map(|n| Some((n.to_string(), item(ctx, n)?)))
231 .collect();
232 group_quotient(ctx, &mut items);
233 group_observational(ctx, &mut items);
234 items.into_values().collect()
235}
236
237pub(crate) fn item(ctx: &Context, name: &str) -> Option<Declaration> {
239 Some(match ctx.registration(name)? {
240 Registration::Inductive(arity) => Declaration::Inductive {
241 name: name.to_string(),
242 params: level_params(ctx, name, arity),
243 arity: arity.clone(),
244 num_params: ctx.inductive_num_params(name),
245 ctors: ctx
246 .get_constructors(name)
247 .into_iter()
248 .map(|(c, t)| (c.to_string(), t.clone()))
249 .collect(),
250 },
251 Registration::Definition(ty, body) => Declaration::Definition {
252 name: name.to_string(),
253 params: level_params(ctx, name, ty),
254 ty: ty.clone(),
255 body: body.clone(),
256 },
257 Registration::UniversePoly(params, ty, body) => Declaration::Definition {
258 name: name.to_string(),
259 params: params.to_vec(),
260 ty: ty.clone(),
261 body: body.clone(),
262 },
263 Registration::Axiom(ty) => Declaration::Axiom {
264 name: name.to_string(),
265 params: level_params(ctx, name, ty),
266 ty: ty.clone(),
267 },
268 })
269}
270
271const QUOTIENT: [(&str, PreludeKind, QuotKind); 4] = [
273 ("Quot", PreludeKind::Type, QuotKind::Type),
274 ("Quot_mk", PreludeKind::Constructor, QuotKind::Ctor),
275 ("Quot_lift", PreludeKind::Lift, QuotKind::Lift),
276 ("Quot_ind", PreludeKind::Induction, QuotKind::Ind),
277];
278
279const INSTALLED_QUOTIENT: [(crate::quotient::Kind, QuotKind); 4] = [
282 (crate::quotient::Kind::Type, QuotKind::Type),
283 (crate::quotient::Kind::Constructor, QuotKind::Ctor),
284 (crate::quotient::Kind::Lift, QuotKind::Lift),
285 (crate::quotient::Kind::Induction, QuotKind::Ind),
286];
287
288fn group_quotient(ctx: &Context, items: &mut BTreeMap<String, Declaration>) {
291 let prelude: Vec<(&str, QuotKind)> = QUOTIENT
292 .iter()
293 .filter(|(name, kind, _)| crate::quotient::prelude_kind(ctx, name) == Some(*kind))
294 .map(|(name, _, kind)| (*name, *kind))
295 .collect();
296 let installed_equality = ctx
297 .quotient_primitives
298 .get(crate::quotient::Kind::Lift.name())
299 .and_then(|c| c.equality.clone());
300 let installed: Vec<(&str, QuotKind)> = INSTALLED_QUOTIENT
301 .iter()
302 .filter(|(kind, _)| {
303 ctx.quotient_primitives
304 .get(kind.name())
305 .is_some_and(|c| c.kind == *kind)
306 })
307 .map(|(kind, quot)| (kind.name(), *quot))
308 .collect();
309 for (set, equality) in [
310 (prelude, Some("Eq".to_string())),
311 (installed, installed_equality),
312 ] {
313 let whole = set.len() == 4
314 && set
315 .iter()
316 .all(|(name, _)| matches!(items.get(*name), Some(Declaration::Axiom { .. })));
317 let Some(equality) = equality.filter(|_| whole) else {
318 continue;
319 };
320 let primitives = set
321 .iter()
322 .map(|(name, kind)| match items.remove(*name) {
323 Some(Declaration::Axiom { name, params, ty }) => (*kind, name, params, ty),
324 _ => unreachable!("certified above"),
325 })
326 .collect();
327 items.insert(
328 set[0].0.to_string(),
329 Declaration::Quotient {
330 primitives,
331 equality,
332 },
333 );
334 }
335}
336
337fn group_observational(ctx: &Context, items: &mut BTreeMap<String, Declaration>) {
340 let Some(certificate) = ctx.observational.as_ref() else {
341 return;
342 };
343 if !certificate
344 .names()
345 .all(|n| matches!(items.get(n), Some(Declaration::Axiom { .. })))
346 {
347 return;
348 }
349 let constants: Vec<(String, Vec<String>, Term)> = certificate
350 .names()
351 .map(|n| match items.remove(n) {
352 Some(Declaration::Axiom { name, params, ty }) => (name, params, ty),
353 _ => unreachable!("an axiom above"),
354 })
355 .collect();
356 let after = certificate
357 .dependencies
358 .iter()
359 .filter(|d| !constants.iter().any(|c| &c.0 == *d))
360 .cloned()
361 .collect();
362 items.insert(
363 constants[0].0.clone(),
364 Declaration::Observational { constants, after },
365 );
366}
367
368pub(crate) fn items_named(ctx: &Context, names: &BTreeSet<String>) -> Vec<Declaration> {
371 let mut items: BTreeMap<String, Declaration> = names
372 .iter()
373 .filter_map(|n| Some((n.clone(), item(ctx, n)?)))
374 .collect();
375 group_quotient(ctx, &mut items);
376 group_observational(ctx, &mut items);
377 items.into_values().collect()
378}
379
380fn globals(t: &Term, out: &mut BTreeSet<String>) {
381 match t {
382 Term::Global(n) | Term::Const { name: n, .. } => {
383 out.insert(n.clone());
384 }
385 Term::Pi {
386 param_type,
387 body_type: body,
388 ..
389 }
390 | Term::Lambda {
391 param_type, body, ..
392 } => {
393 globals(param_type, out);
394 globals(body, out);
395 }
396 Term::App(f, a) => {
397 globals(f, out);
398 globals(a, out);
399 }
400 Term::Match {
401 discriminant,
402 motive,
403 cases,
404 } => {
405 globals(discriminant, out);
406 globals(motive, out);
407 cases.iter().for_each(|c| globals(c, out));
408 }
409 Term::Fix { body, .. } => globals(body, out),
410 Term::MutualFix { defs, .. } => defs.iter().for_each(|(_, b)| globals(b, out)),
411 Term::Let {
412 ty, value, body, ..
413 } => {
414 globals(ty, out);
415 globals(value, out);
416 globals(body, out);
417 }
418 Term::Annotated { term, .. } => globals(term, out),
419 Term::Lit(lit) => {
420 out.insert(carrier(lit).to_string());
421 }
422 Term::Sort(_) | Term::Var(_) | Term::Hole => {}
423 }
424}
425
426fn carrier(lit: &Literal) -> &'static str {
429 match lit {
430 Literal::Int(_) | Literal::BigInt(_) => "Int",
431 Literal::Nat(_) => "Nat",
432 Literal::Float(_) => "Float",
433 Literal::Text(_) => "Text",
434 Literal::Duration(_) => "Duration",
435 Literal::Date(_) => "Date",
436 Literal::Moment(_) => "Moment",
437 }
438}
439
440pub(crate) fn item_globals(item: &Declaration) -> BTreeSet<String> {
443 let mut names = BTreeSet::new();
444 item.terms()
445 .into_iter()
446 .for_each(|t| globals(t, &mut names));
447 if let Declaration::Observational { after, .. } = item {
448 names.extend(after.iter().cloned());
449 }
450 names
451}
452
453fn order(ctx: &Context, items: &[Declaration]) -> Vec<Vec<usize>> {
455 let mut owner: BTreeMap<&str, usize> = BTreeMap::new();
456 for (i, item) in items.iter().enumerate() {
457 for name in item.names() {
458 owner.insert(name, i);
459 }
460 }
461 let globals: Vec<BTreeSet<String>> = items.iter().map(item_globals).collect();
462 let mut edges: Vec<Vec<usize>> = globals
463 .iter()
464 .enumerate()
465 .map(|(i, names)| {
466 names
467 .iter()
468 .filter_map(|n| owner.get(n.as_str()).copied())
469 .filter(|j| *j != i)
470 .collect()
471 })
472 .collect();
473 for (i, names) in globals.iter().enumerate() {
478 let mut projections: Vec<usize> = names
479 .iter()
480 .filter_map(|n| ctx.struct_of_constructor(n))
481 .flat_map(|(_, info)| info.projections.iter())
482 .filter_map(|p| owner.get(p.as_str()).copied())
483 .filter(|j| *j != i)
484 .collect();
485 projections.sort_unstable();
486 projections.dedup();
487 for j in projections {
488 if !edges[i].contains(&j) && !reaches(&edges, j, i) {
489 edges[i].push(j);
490 }
491 }
492 }
493 tarjan(&edges)
494}
495
496fn reaches(edges: &[Vec<usize>], from: usize, to: usize) -> bool {
498 let mut seen = vec![false; edges.len()];
499 let mut work = vec![from];
500 while let Some(i) = work.pop() {
501 if i == to {
502 return true;
503 }
504 if !std::mem::replace(&mut seen[i], true) {
505 work.extend(edges[i].iter().copied());
506 }
507 }
508 false
509}
510
511fn tarjan(edges: &[Vec<usize>]) -> Vec<Vec<usize>> {
514 let n = edges.len();
515 let (mut index, mut low, mut on) = (vec![usize::MAX; n], vec![0; n], vec![false; n]);
516 let (mut stack, mut out, mut next) = (Vec::new(), Vec::new(), 0);
517 for root in 0..n {
518 if index[root] != usize::MAX {
519 continue;
520 }
521 let mut work: Vec<(usize, usize)> = vec![(root, 0)];
522 while let Some(&mut (v, ref mut e)) = work.last_mut() {
523 if *e == 0 && index[v] == usize::MAX {
524 index[v] = next;
525 low[v] = next;
526 next += 1;
527 stack.push(v);
528 on[v] = true;
529 }
530 if *e < edges[v].len() {
531 let w = edges[v][*e];
532 *e += 1;
533 if index[w] == usize::MAX {
534 work.push((w, 0));
535 } else if on[w] {
536 low[v] = low[v].min(index[w]);
537 }
538 continue;
539 }
540 work.pop();
541 if let Some(&(parent, _)) = work.last() {
542 low[parent] = low[parent].min(low[v]);
543 }
544 if low[v] == index[v] {
545 let mut component = Vec::new();
546 while let Some(w) = stack.pop() {
547 on[w] = false;
548 component.push(w);
549 if w == v {
550 break;
551 }
552 }
553 component.sort_unstable();
554 out.push(component);
555 }
556 }
557 }
558 out
559}
560
561#[cfg(feature = "shadow")]
565pub(crate) fn judge(k: &mut Kernel, ctx: &Context, block: &[Declaration]) -> Result<(), String> {
566 let verdict = match block {
567 [Declaration::Definition {
568 name,
569 params,
570 ty,
571 body,
572 }] => judge_definition(k, ctx, name, params, ty, body),
573 [Declaration::Axiom { name, params, ty }] => judge_axiom(k, ctx, name, params, ty),
574 _ => admit_block(&mut k.clone(), ctx, &block.iter().collect::<Vec<_>>()),
575 };
576 verdict.map_err(|e| e.to_string())
577}
578
579#[cfg(feature = "shadow")]
580fn judge_definition(
581 k: &mut Kernel,
582 ctx: &Context,
583 name: &str,
584 params: &[String],
585 ty: &Term,
586 body: &Term,
587) -> KResult<()> {
588 let header = Header {
589 name: name_id(k, name),
590 lparams: lparams(k, params),
591 ty: lowered(k, ctx, ty)?,
592 };
593 let value = lowered(k, ctx, body)?;
594 let height = definition_height(k, value);
595 k.check_without_admitting(&Decl::Defn(DefnDecl {
596 header,
597 value,
598 hint: Hint::Regular(height),
599 safety: Safety::Safe,
600 }))
601}
602
603#[cfg(feature = "shadow")]
604fn judge_axiom(
605 k: &mut Kernel,
606 ctx: &Context,
607 name: &str,
608 params: &[String],
609 ty: &Term,
610) -> KResult<()> {
611 let header = Header {
612 name: name_id(k, name),
613 lparams: lparams(k, params),
614 ty: lowered(k, ctx, ty)?,
615 };
616 k.check_without_admitting(&Decl::Axiom {
617 header,
618 is_unsafe: false,
619 })
620}
621
622pub fn candidate_definition(
626 ctx: &Context,
627 name: &str,
628 levels: Option<&[String]>,
629 ty: &Term,
630 body: &Term,
631) -> Declaration {
632 let (ty, body) = (ctx.stored_term(ty.clone()), ctx.stored_term(body.clone()));
633 let params = match levels {
634 Some(levels) => levels.to_vec(),
635 None => crate::term::definition_telescope(&ty, &body)
636 .unwrap_or_else(|| crate::term::free_level_vars(&ty)),
637 };
638 Declaration::Definition {
639 name: name.to_string(),
640 params,
641 ty,
642 body,
643 }
644}
645
646pub fn candidate_axiom(
649 ctx: &Context,
650 name: &str,
651 levels: Option<&[String]>,
652 ty: &Term,
653) -> Declaration {
654 let ty = ctx.stored_term(ty.clone());
655 Declaration::Axiom {
656 name: name.to_string(),
657 params: levels.map_or_else(|| crate::term::free_level_vars(&ty), <[String]>::to_vec),
658 ty,
659 }
660}
661
662pub fn candidate_block(
667 ctx: &Context,
668 levels: Option<&[String]>,
669 block: &[crate::context::MutualInductive],
670) -> Vec<Declaration> {
671 let arities: Vec<Term> = block
672 .iter()
673 .map(|m| ctx.stored_term(m.sort.clone()))
674 .collect();
675 let telescopes: Vec<Vec<String>> = arities
676 .iter()
677 .map(|arity| levels.map_or_else(|| crate::term::free_level_vars(arity), <[String]>::to_vec))
678 .collect();
679 let own_levels = |name: &str| match block.iter().position(|m| m.name == name) {
680 Some(i) => (!telescopes[i].is_empty()).then(|| telescopes[i].clone()),
681 None => ctx.own_levels(name),
682 };
683 block
684 .iter()
685 .zip(arities)
686 .zip(&telescopes)
687 .map(|((m, arity), params)| Declaration::Inductive {
688 name: m.name.clone(),
689 params: params.clone(),
690 arity,
691 num_params: m.num_params,
692 ctors: m
693 .constructors
694 .iter()
695 .map(|(c, t)| {
696 let mut t = crate::annotation::stored(t.clone());
697 crate::term::bare_references_at_own_levels(&mut t, &own_levels);
698 (c.clone(), t)
699 })
700 .collect(),
701 })
702 .collect()
703}
704
705fn lowered(k: &mut Kernel, ctx: &Context, t: &Term) -> KResult<ExprId> {
706 lower(&mut k.s, &explicit_levels(ctx, t))
707 .map_err(|e| KernelFailure::reject(format!("no core term: {e:?}")))
708}
709
710fn lparams(k: &mut Kernel, params: &[String]) -> Rc<[NameId]> {
711 params
712 .iter()
713 .map(|p| k.s.names.str(NameId::ANON, p))
714 .collect::<Vec<_>>()
715 .into()
716}
717
718fn name_id(k: &mut Kernel, name: &str) -> NameId {
719 k.s.names.str(NameId::ANON, name)
720}
721
722fn admit_axiom(
723 k: &mut Kernel,
724 ctx: &Context,
725 name: &str,
726 params: &[String],
727 ty: &Term,
728) -> KResult<()> {
729 let header = Header {
730 name: name_id(k, name),
731 lparams: lparams(k, params),
732 ty: lowered(k, ctx, ty)?,
733 };
734 k.add_decl(Decl::Axiom {
735 header,
736 is_unsafe: false,
737 })
738}
739
740fn admit_quotient(
743 k: &mut Kernel,
744 ctx: &Context,
745 primitives: &[(QuotKind, String, Vec<String>, Term)],
746 equality: &str,
747) -> KResult<()> {
748 let eq = name_id(k, equality);
749 for (kind, name, params, ty) in primitives {
750 let header = Header {
751 name: name_id(k, name),
752 lparams: lparams(k, params),
753 ty: lowered(k, ctx, ty)?,
754 };
755 k.add_quotient(header, *kind, eq)?;
756 }
757 Ok(())
758}
759
760fn admit_definition(
761 k: &mut Kernel,
762 ctx: &Context,
763 name: &str,
764 params: &[String],
765 ty: &Term,
766 body: &Term,
767) -> KResult<()> {
768 let header = Header {
769 name: name_id(k, name),
770 lparams: lparams(k, params),
771 ty: lowered(k, ctx, ty)?,
772 };
773 let value = lowered(k, ctx, body)?;
774 let height = definition_height(k, value);
775 k.add_decl(Decl::Defn(DefnDecl {
776 header,
777 value,
778 hint: Hint::Regular(height),
779 safety: Safety::Safe,
780 }))
781}
782
783fn definition_height(k: &Kernel, value: ExprId) -> u32 {
785 let mut h = 0;
786 k.s.any_node(value, &mut |s, x| {
787 if let Node::Const(n, _) = s.node(x) {
788 if let Some(c) = k.env.get(n) {
789 if let Hint::Regular(d) = c.hint() {
790 h = h.max(d);
791 }
792 }
793 }
794 false
795 });
796 h + 1
797}
798
799fn telescope(k: &mut Kernel, mut ty: ExprId) -> KResult<(Vec<ExprId>, ExprId)> {
801 let mut locals = Vec::new();
802 loop {
803 let w = k.whnf(ty)?;
804 match k.s.node(w) {
805 Node::Pi(a, b) => {
806 let x = k.push_local(a, None);
807 locals.push(x);
808 ty = k.s.instantiate1(b, x);
809 }
810 _ => return Ok((locals, w)),
811 }
812 }
813}
814
815fn admit_inductives(k: &mut Kernel, ctx: &Context, block: &[&Declaration]) -> KResult<()> {
816 let names: Vec<&str> = block.iter().map(|i| i.name()).collect();
817 let mut types = Vec::new();
818 for item in block {
819 let Declaration::Inductive {
820 name,
821 params,
822 arity,
823 num_params,
824 ctors,
825 } = item
826 else {
827 unreachable!()
828 };
829 let n = name_id(k, name);
830 let lps = lparams(k, params);
831 k.check_name(n, true)?;
832 let ty = lowered(k, ctx, arity)?;
833 let level = k.with_decl(lps.clone(), Safety::Safe, |k| {
834 let s = k.check(ty)?;
835 k.ensure_sort(s)?;
836 let (locals, end) = telescope(k, ty)?;
837 match k.s.node(end) {
838 Node::Sort(l) => Ok((l, locals.len() as u32)),
839 _ => Err(KernelFailure::reject(format!(
840 "the arity of '{name}' does not end in a sort"
841 ))),
842 }
843 })?;
844 types.push((
845 n,
846 lps,
847 ty,
848 level,
849 *num_params as u32,
850 ctors.clone(),
851 params.clone(),
852 ));
853 }
854 for (n, lps, ty, (_, arity_len), num_params, ..) in &types {
855 let info = InductiveInfo {
856 num_params: *num_params,
857 num_indices: arity_len - num_params,
858 all: types.iter().map(|t| t.0).collect::<Vec<_>>().into(),
859 ctors: Vec::new().into(),
860 num_nested: 0,
861 is_rec: false,
862 is_reflexive: false,
863 is_unsafe: false,
864 rec: k.rec_name(*n),
865 };
866 k.env.add_provisional(Const {
867 name: *n,
868 lparams: lps.clone(),
869 ty: *ty,
870 kind: Kind::Induct(info),
871 });
872 }
873 let members: BTreeSet<NameId> = types.iter().map(|t| t.0).collect();
874 let mut finals = Vec::new();
875 let result = (|| -> KResult<()> {
876 for (n, lps, ind_ty, (level, arity_len), num_params, ctors, family_levels) in &types {
877 let mut ctor_ids = Vec::new();
878 let (mut is_rec, mut is_reflexive) = (false, false);
879 for (cidx, (cname, cty)) in ctors.iter().enumerate() {
880 let c = name_id(k, cname);
881 k.check_name(c, true)?;
882 let own_levels = super::logos::level_telescope(ctx, cname)
885 .map_or_else(|| family_levels.clone(), |(ps, _)| ps);
886 if own_levels != *family_levels {
887 return Err(KernelFailure::reject(format!(
888 "constructor '{cname}' takes the universe parameters {own_levels:?}, its family {family_levels:?}"
889 )));
890 }
891 crate::positivity::check_positivity_mutual_resolved(ctx, &names, cname, cty)
892 .map_err(|e| KernelFailure::reject(e.to_string()))?;
893 let ty = lowered(k, ctx, cty)?;
894 let shape = k.with_decl(lps.clone(), Safety::Safe, |k| {
895 check_constructor(
896 k,
897 cname,
898 *n,
899 lps,
900 *ind_ty,
901 *level,
902 *num_params,
903 *arity_len,
904 ty,
905 &members,
906 )
907 })?;
908 is_rec |= shape.recursive;
909 is_reflexive |= shape.reflexive;
910 ctor_ids.push(c);
911 finals.push(Const {
912 name: c,
913 lparams: lps.clone(),
914 ty,
915 kind: Kind::Ctor(CtorInfo {
916 induct: *n,
917 cidx: cidx as u32,
918 num_params: *num_params,
919 num_fields: shape.fields,
920 is_unsafe: false,
921 }),
922 });
923 }
924 let provisional = k.env.get(*n).expect("provisional").clone();
925 let Kind::Induct(mut info) = provisional.kind.clone() else {
926 unreachable!()
927 };
928 info.ctors = ctor_ids.into();
929 info.is_rec = is_rec;
930 info.is_reflexive = is_reflexive;
931 finals.push(Const {
932 name: *n,
933 lparams: lps.clone(),
934 ty: provisional.ty,
935 kind: Kind::Induct(info),
936 });
937 }
938 Ok(())
939 })();
940 for (n, ..) in &types {
941 k.env.remove(*n);
942 }
943 result?;
944 let irrelevant = irrelevant_levels(k, &finals);
945 for c in finals {
946 if let Some(mask) = irrelevant.get(&c.name) {
947 k.record_irrelevant_levels(c.name, *mask);
948 }
949 k.env.add(c);
950 }
951 Ok(())
952}
953
954struct CtorShape {
957 fields: u32,
958 recursive: bool,
959 reflexive: bool,
960}
961
962#[allow(clippy::too_many_arguments)]
966fn check_constructor(
967 k: &mut Kernel,
968 cname: &str,
969 family: NameId,
970 lps: &Rc<[NameId]>,
971 family_ty: ExprId,
972 level: LevelId,
973 num_params: u32,
974 arity_len: u32,
975 ty: ExprId,
976 members: &BTreeSet<NameId>,
977) -> KResult<CtorShape> {
978 let reject = |what: String| KernelFailure::reject(format!("constructor '{cname}' {what}"));
979 let s = k.check(ty)?;
980 k.ensure_sort(s)?;
981 let mut arity = family_ty;
982 let mut params = Vec::with_capacity(num_params as usize);
983 let mut cur = ty;
984 for i in 0..num_params {
985 let aw = k.whnf(arity)?;
986 let Node::Pi(param_ty, arity_body) = k.s.node(aw) else {
987 return Err(reject("outruns its family's parameters".into()));
988 };
989 let cw = k.whnf(cur)?;
990 let Node::Pi(dom, body) = k.s.node(cw) else {
991 return Err(reject(format!(
992 "has fewer than its family's {num_params} parameters"
993 )));
994 };
995 if !k.is_def_eq(dom, param_ty)? {
996 return Err(reject(format!(
997 "takes its parameter {i} at a type other than its family's"
998 )));
999 }
1000 let p = k.push_local(param_ty, None);
1001 params.push(p);
1002 arity = k.s.instantiate1(arity_body, p);
1003 cur = k.s.instantiate1(body, p);
1004 }
1005 let mentions_block = |k: &Kernel, e: ExprId| {
1006 k.s.any_node(
1007 e,
1008 &mut |s, x| matches!(s.node(x), Node::Const(m, _) if members.contains(&m)),
1009 )
1010 };
1011 let mut shape = CtorShape {
1012 fields: 0,
1013 recursive: false,
1014 reflexive: false,
1015 };
1016 loop {
1017 let cw = k.whnf(cur)?;
1018 let Node::Pi(dom, body) = k.s.node(cw) else {
1019 cur = cw;
1020 break;
1021 };
1022 shape.fields += 1;
1023 if mentions_block(k, dom) {
1024 shape.recursive = true;
1025 let dw = k.whnf(dom)?;
1026 shape.reflexive |= matches!(k.s.node(dw), Node::Pi(..));
1027 }
1028 if level != LevelId::ZERO && !k.s.levels.is_sprop(level) {
1029 let fs = k.infer(dom, true)?;
1030 let fs = k.ensure_sort(fs)?;
1031 let fl = k.sort_level(fs);
1032 if !k.s.levels.leq(fl, level) {
1033 return Err(KernelFailure::reject(format!(
1034 "universe inconsistency: constructor '{cname}' stores an argument in a sort above its inductive's"
1035 )));
1036 }
1037 }
1038 let x = k.push_local(dom, None);
1039 cur = k.s.instantiate1(body, x);
1040 }
1041 let (head, args) = k.s.app_args(cur);
1042 let identity = k.const_levels_of(lps);
1043 let returns_family =
1044 matches!(k.s.node(head), Node::Const(m, ls) if m == family && ls == identity);
1045 if !returns_family || args.len() != arity_len as usize || args[..params.len()] != params[..] {
1046 return Err(reject(format!(
1047 "must return its family applied to its parameters and then {} indices, not {}",
1048 arity_len - num_params,
1049 k.show(cur)
1050 )));
1051 }
1052 for index in &args[params.len()..] {
1053 if mentions_block(k, *index) {
1054 return Err(reject(
1055 "mentions its family in an index of its result".into(),
1056 ));
1057 }
1058 }
1059 Ok(shape)
1060}
1061
1062fn irrelevant_levels(k: &mut Kernel, block: &[Const]) -> BTreeMap<NameId, u64> {
1069 let members: BTreeSet<NameId> = block
1070 .iter()
1071 .filter(|c| matches!(c.kind, Kind::Induct(_)))
1072 .map(|c| c.name)
1073 .collect();
1074 let mut declared = BTreeMap::new();
1075 for c in block.iter().filter(|c| members.contains(&c.name)) {
1076 let ls = k.const_levels_of(&c.lparams);
1077 declared.insert(c.name, ls);
1078 }
1079 let mut mentioned: BTreeSet<NameId> = BTreeSet::new();
1080 for c in block {
1081 let num_params = match &c.kind {
1082 Kind::Induct(info) => info.num_params,
1083 Kind::Ctor(ci) => ci.num_params,
1084 _ => continue,
1085 };
1086 let mut rest = c.ty;
1087 for _ in 0..num_params {
1088 match k.s.node(rest) {
1089 Node::Pi(_, b) => rest = b,
1090 _ => break,
1091 }
1092 }
1093 for p in c.lparams.iter() {
1094 let s = &k.s;
1095 if s.any_node(rest, &mut |s, x| match s.node(x) {
1096 Node::Sort(l) => s.levels.mentions_param(l, *p),
1097 Node::Const(n, ls) if declared.get(&n) != Some(&ls) => s
1098 .levels
1099 .get_list(ls)
1100 .iter()
1101 .any(|l| s.levels.mentions_param(*l, *p)),
1102 _ => false,
1103 }) {
1104 mentioned.insert(*p);
1105 }
1106 }
1107 }
1108 block
1109 .iter()
1110 .map(|c| {
1111 let mask = c
1112 .lparams
1113 .iter()
1114 .enumerate()
1115 .filter(|(i, p)| *i < 64 && !mentioned.contains(p))
1116 .fold(0u64, |m, (i, _)| m | 1 << i);
1117 (c.name, mask)
1118 })
1119 .collect()
1120}