1use super::supplied::{derived_under_supplied_names, recursor_matches};
55use crate::declaration::{
56 ConstantInfo, ConstantVal, ConstructorVal, InductiveVal, RecursorRule, RecursorVal,
57};
58use crate::expr_util::{get_app_fn, get_app_fn_args, mk_app};
59use crate::infer::LocalDecl;
60use crate::level::{is_equivalent, is_geq, normalize as normalize_level};
61use crate::subst::instantiate;
62use crate::Node;
63use crate::{
64 BinderInfo, Environment, Expr, FVarId, KernelError, Level, LevelView, Name, TypeChecker,
65};
66use std::rc::Rc;
67
68#[derive(Clone, Debug)]
70pub struct InductiveSpec {
71 pub name: Name,
73 pub ty: Expr,
75 pub ctors: Vec<(Name, Expr)>,
78 pub rec_name: Option<Name>,
80}
81
82impl InductiveSpec {
83 pub fn new(name: Name, ty: Expr, ctors: Vec<(Name, Expr)>) -> Self {
85 Self {
86 name,
87 ty,
88 ctors,
89 rec_name: None,
90 }
91 }
92 pub fn with_rec_name(mut self, rec_name: Name) -> Self {
94 self.rec_name = Some(rec_name);
95 self
96 }
97 fn effective_rec_name(&self) -> Name {
98 self.rec_name
99 .clone()
100 .unwrap_or_else(|| Name::mk_str(self.name.clone(), "rec"))
101 }
102}
103
104#[derive(Clone, Debug)]
106pub struct DerivedFamily {
107 pub inductives: Vec<ConstantInfo>,
109 pub constructors: Vec<ConstantInfo>,
111 pub recursors: Vec<ConstantInfo>,
113}
114
115impl DerivedFamily {
116 pub fn into_constant_infos(self) -> Vec<ConstantInfo> {
118 let mut out = self.inductives;
119 out.extend(self.constructors);
120 out.extend(self.recursors);
121 out
122 }
123}
124
125const DERIVE_FVAR_BASE: u64 = 1 << 40;
132
133#[derive(Clone, Debug)]
134struct Binder {
135 fvar: FVarId,
136 bi: BinderInfo,
137 name: Name,
138 ty: Expr,
139}
140
141fn fv(b: &Binder) -> Expr {
142 Expr::FVar(b.fvar)
143}
144
145struct DeriveCtx<'e> {
150 tc: Option<TypeChecker<'e>>,
151 next: u64,
152}
153
154impl<'e> DeriveCtx<'e> {
155 fn checked(env: &'e Environment) -> Self {
156 Self {
157 tc: Some(TypeChecker::new(env)),
158 next: 0,
159 }
160 }
161 fn unchecked() -> Self {
162 Self { tc: None, next: 0 }
163 }
164 fn is_checked(&self) -> bool {
165 self.tc.is_some()
166 }
167 fn fresh(&mut self, bi: BinderInfo, name: Name, ty: Expr) -> Binder {
168 let id = FVarId(DERIVE_FVAR_BASE + self.next);
169 self.next += 1;
170 if let Some(tc) = self.tc.as_mut() {
171 tc.push_local(LocalDecl {
172 fvar: id,
173 name: name.clone(),
174 ty: ty.clone(),
175 val: None,
176 });
177 }
178 Binder {
179 fvar: id,
180 bi,
181 name,
182 ty,
183 }
184 }
185 fn whnf(&mut self, e: &Expr) -> Expr {
186 match self.tc.as_mut() {
187 Some(tc) => tc.whnf(e),
188 None => e.clone(),
189 }
190 }
191 fn is_def_eq(&mut self, a: &Expr, b: &Expr) -> bool {
192 match self.tc.as_mut() {
193 Some(tc) => tc.is_def_eq(a, b),
194 None => a == b,
195 }
196 }
197 #[allow(clippy::result_large_err)]
198 fn ensure_sort(&mut self, e: &Expr) -> Result<Option<Level>, KernelError> {
199 match self.tc.as_mut() {
200 Some(tc) => tc.ensure_sort(e).map(Some),
201 None => Ok(None),
202 }
203 }
204}
205
206fn abstract_fvar(expr: &Expr, fvar: FVarId, depth: u32) -> Expr {
215 match expr {
216 Expr::FVar(id) if *id == fvar => Expr::BVar(depth),
217 Expr::BVar(_) | Expr::Sort(_) | Expr::FVar(_) | Expr::Const(_, _) | Expr::Lit(_) => {
218 expr.clone()
219 }
220 Expr::App(f, a) => Expr::App(
221 Node::new(abstract_fvar(f, fvar, depth)),
222 Node::new(abstract_fvar(a, fvar, depth)),
223 ),
224 Expr::Lam(bi, n, ty, body) => Expr::Lam(
225 *bi,
226 n.clone(),
227 Node::new(abstract_fvar(ty, fvar, depth)),
228 Node::new(abstract_fvar(body, fvar, depth + 1)),
229 ),
230 Expr::Pi(bi, n, ty, body) => Expr::Pi(
231 *bi,
232 n.clone(),
233 Node::new(abstract_fvar(ty, fvar, depth)),
234 Node::new(abstract_fvar(body, fvar, depth + 1)),
235 ),
236 Expr::Let(n, ty, val, body) => Expr::Let(
237 n.clone(),
238 Node::new(abstract_fvar(ty, fvar, depth)),
239 Node::new(abstract_fvar(val, fvar, depth)),
240 Node::new(abstract_fvar(body, fvar, depth + 1)),
241 ),
242 Expr::Proj(n, i, e) => Expr::Proj(n.clone(), *i, Node::new(abstract_fvar(e, fvar, depth))),
243 }
244}
245
246fn close(binders: &[Binder], body: &Expr, lam: bool, bi_override: Option<BinderInfo>) -> Expr {
251 let mut r = body.clone();
252 for b in binders.iter().rev() {
253 let inner = abstract_fvar(&r, b.fvar, 0);
254 let bi = bi_override.unwrap_or(b.bi);
255 r = if lam {
256 Expr::Lam(
257 bi,
258 b.name.clone(),
259 Node::new(b.ty.clone()),
260 Node::new(inner),
261 )
262 } else {
263 Expr::Pi(
264 bi,
265 b.name.clone(),
266 Node::new(b.ty.clone()),
267 Node::new(inner),
268 )
269 };
270 }
271 r
272}
273
274pub(crate) fn has_const_occ(e: &Expr, names: &[Name]) -> bool {
279 match e {
280 Expr::Const(n, _) => names.contains(n),
281 Expr::BVar(_) | Expr::FVar(_) | Expr::Sort(_) | Expr::Lit(_) => false,
282 Expr::App(f, a) => has_const_occ(f, names) || has_const_occ(a, names),
283 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
284 has_const_occ(ty, names) || has_const_occ(body, names)
285 }
286 Expr::Let(_, ty, val, body) => {
287 has_const_occ(ty, names) || has_const_occ(val, names) || has_const_occ(body, names)
288 }
289 Expr::Proj(_, _, e) => has_const_occ(e, names),
290 }
291}
292
293fn collect_level_param_names(l: &Level, out: &mut Vec<Name>) {
294 match l.view() {
295 LevelView::Zero => {}
296 LevelView::Succ(a) => collect_level_param_names(a, out),
297 LevelView::Max(a, b) | LevelView::IMax(a, b) => {
298 collect_level_param_names(a, out);
299 collect_level_param_names(b, out);
300 }
301 LevelView::Param(n) => {
302 if !out.contains(n) {
303 out.push(n.clone());
304 }
305 }
306 LevelView::MVar(_) => {}
307 }
308}
309
310fn collect_expr_level_params(e: &Expr, out: &mut Vec<Name>) {
311 match e {
312 Expr::Sort(l) => collect_level_param_names(l, out),
313 Expr::Const(_, ls) => {
314 for l in ls {
315 collect_level_param_names(l, out);
316 }
317 }
318 Expr::BVar(_) | Expr::FVar(_) | Expr::Lit(_) => {}
319 Expr::App(f, a) => {
320 collect_expr_level_params(f, out);
321 collect_expr_level_params(a, out);
322 }
323 Expr::Lam(_, _, ty, body) | Expr::Pi(_, _, ty, body) => {
324 collect_expr_level_params(ty, out);
325 collect_expr_level_params(body, out);
326 }
327 Expr::Let(_, ty, val, body) => {
328 collect_expr_level_params(ty, out);
329 collect_expr_level_params(val, out);
330 collect_expr_level_params(body, out);
331 }
332 Expr::Proj(_, _, e) => collect_expr_level_params(e, out),
333 }
334}
335
336#[allow(clippy::result_large_err)]
337fn check_level_params_declared(
338 e: &Expr,
339 lparams: &[Name],
340 what: &str,
341 name: &Name,
342) -> Result<(), KernelError> {
343 let mut used = Vec::new();
344 collect_expr_level_params(e, &mut used);
345 for u in used {
346 if !lparams.contains(&u) {
347 return Err(KernelError::InvalidInductive(format!(
348 "{} '{}' uses undeclared universe parameter '{}'",
349 what, name, u
350 )));
351 }
352 }
353 Ok(())
354}
355
356fn peel_all(ctx: &mut DeriveCtx<'_>, ty: &Expr) -> (Vec<Binder>, Expr) {
363 let mut out = Vec::new();
364 let mut cur = ty.clone();
365 loop {
366 let curw = if matches!(cur, Expr::Pi(_, _, _, _)) {
367 cur
368 } else {
369 let w = ctx.whnf(&cur);
370 if !matches!(w, Expr::Pi(_, _, _, _)) {
371 return (out, w);
372 }
373 w
374 };
375 if let Expr::Pi(bi, name, dom, body) = curw {
376 let b = ctx.fresh(bi, name, (*dom).clone());
377 cur = instantiate(&body, &fv(&b));
378 out.push(b);
379 } else {
380 return (out, curw);
381 }
382 }
383}
384
385fn peel_binders_as_written(ctx: &mut DeriveCtx<'_>, ty: &Expr) -> (Vec<Binder>, Expr) {
391 let mut out = Vec::new();
392 let mut cur = ty.clone();
393 while let Expr::Pi(bi, name, dom, body) = cur {
394 let b = ctx.fresh(bi, name, (*dom).clone());
395 cur = instantiate(&body, &fv(&b));
396 out.push(b);
397 }
398 (out, cur)
399}
400
401#[allow(clippy::result_large_err)]
407fn peel_against_params(
408 ctx: &mut DeriveCtx<'_>,
409 ty: &Expr,
410 params: &[Binder],
411 what: &str,
412 name: &Name,
413) -> Result<Expr, KernelError> {
414 let mut cur = ty.clone();
415 for (i, p) in params.iter().enumerate() {
416 let curw = cur;
417 match curw {
418 Expr::Pi(_, _, dom, body) => {
419 if ctx.is_checked() && !ctx.is_def_eq(&dom, &p.ty) {
420 return Err(KernelError::InvalidInductive(format!(
421 "{} '{}': parameter #{} does not match the family parameter type",
422 what,
423 name,
424 i + 1
425 )));
426 }
427 cur = instantiate(&body, &fv(p));
428 }
429 _ => {
430 return Err(KernelError::InvalidInductive(format!(
431 "{} '{}' does not bind the {} family parameter(s)",
432 what,
433 name,
434 params.len()
435 )));
436 }
437 }
438 }
439 Ok(cur)
440}
441
442struct FamilyPre {
447 lparams: Vec<Name>,
448 ind_levels: Vec<Level>,
449 np: usize,
450 params: Vec<Binder>,
451 names: Vec<Name>,
452 indices: Vec<Vec<Binder>>,
455 ind_level: Level,
457}
458
459#[allow(clippy::result_large_err)]
460fn build_family_pre(
461 ctx: &mut DeriveCtx<'_>,
462 lparams: &[Name],
463 num_params: u32,
464 types: &[(Name, Expr)],
465) -> Result<FamilyPre, KernelError> {
466 if types.is_empty() {
467 return Err(KernelError::InvalidInductive(
468 "inductive family must contain at least one type".to_string(),
469 ));
470 }
471 for (i, lp) in lparams.iter().enumerate() {
472 if lparams[..i].contains(lp) {
473 return Err(KernelError::InvalidInductive(format!(
474 "duplicate universe parameter '{}'",
475 lp
476 )));
477 }
478 }
479 for (i, (n, _)) in types.iter().enumerate() {
480 if types[..i].iter().any(|(m, _)| m == n) {
481 return Err(KernelError::InvalidInductive(format!(
482 "duplicate inductive type name '{}'",
483 n
484 )));
485 }
486 }
487 let np = num_params as usize;
488 let ind_levels: Vec<Level> = lparams.iter().cloned().map(Level::param).collect();
489
490 for (n, ty) in types {
491 check_level_params_declared(ty, lparams, "inductive type", n)?;
492 if ctx.is_checked() {
493 ctx.ensure_sort(ty)?;
494 }
495 }
496
497 let mut params = Vec::new();
501 let mut cur = types[0].1.clone();
502 for i in 0..np {
503 let curw = cur;
504 match curw {
505 Expr::Pi(bi, name, dom, body) => {
506 let b = ctx.fresh(bi, name, (*dom).clone());
507 cur = instantiate(&body, &fv(&b));
508 params.push(b);
509 }
510 _ => {
511 return Err(KernelError::InvalidInductive(format!(
512 "inductive type '{}' has fewer than {} parameter binders (got {})",
513 types[0].0, np, i
514 )));
515 }
516 }
517 }
518
519 let mut names = Vec::new();
520 let mut indices = Vec::new();
521 let mut ind_level: Option<Level> = None;
522 for (j, (n, ty)) in types.iter().enumerate() {
523 let rest = if j == 0 {
524 cur.clone()
525 } else {
526 peel_against_params(ctx, ty, ¶ms, "inductive type", n)?
527 };
528 let (idx_binders, cod) = peel_all(ctx, &rest);
529 let codw = ctx.whnf(&cod);
530 let level = match codw {
531 Expr::Sort(l) => l,
532 other => {
533 return Err(KernelError::InvalidInductive(format!(
534 "inductive type '{}' must end in a sort, found '{}'",
535 n, other
536 )));
537 }
538 };
539 match &ind_level {
540 None => ind_level = Some(level),
541 Some(l0) => {
542 if !is_equivalent(l0, &level) {
543 return Err(KernelError::InvalidInductive(format!(
544 "mutually inductive type '{}' lives in a different universe than '{}'",
545 n, types[0].0
546 )));
547 }
548 }
549 }
550 names.push(n.clone());
551 indices.push(idx_binders);
552 }
553 let ind_level = normalize_level(&ind_level.unwrap_or_else(Level::zero));
555 Ok(FamilyPre {
556 lparams: lparams.to_vec(),
557 ind_levels,
558 np,
559 params,
560 names,
561 indices,
562 ind_level,
563 })
564}
565
566fn as_valid_ind_app(pre: &FamilyPre, e: &Expr, strict: bool) -> Option<(usize, Vec<Expr>)> {
579 let (head, args) = get_app_fn_args(e);
580 let (n, levels) = match head {
581 Expr::Const(n, levels) => (n, levels),
582 _ => return None,
583 };
584 let j = pre.names.iter().position(|x| x == n)?;
585 if strict {
586 if levels.len() != pre.ind_levels.len()
587 || !levels
588 .iter()
589 .zip(&pre.ind_levels)
590 .all(|(a, b)| is_equivalent(a, b))
591 {
592 return None;
593 }
594 if args.len() != pre.np + pre.indices[j].len() {
595 return None;
596 }
597 for (arg, p) in args.iter().zip(&pre.params) {
598 if **arg != Expr::FVar(p.fvar) {
599 return None;
600 }
601 }
602 if args
603 .iter()
604 .skip(pre.np)
605 .any(|index| has_const_occ(index, &pre.names))
606 {
607 return None;
608 }
609 }
610 let idx = args.iter().skip(pre.np).map(|e| (*e).clone()).collect();
611 Some((j, idx))
612}
613
614struct RecFieldSig {
619 ds: Vec<Binder>,
621 type_idx: usize,
623 index_args: Vec<Expr>,
625}
626
627struct FieldSig {
628 binder: Binder,
629 sort_level: Option<Level>,
631 rec: Option<RecFieldSig>,
632}
633
634struct CtorSig {
635 name: Name,
636 ty: Expr,
637 fields: Vec<FieldSig>,
638 ret_index_args: Vec<Expr>,
640}
641
642#[allow(clippy::result_large_err)]
647fn check_positivity(
648 ctx: &mut DeriveCtx<'_>,
649 pre: &FamilyPre,
650 ty: &Expr,
651 ctor_name: &Name,
652 decl_name: &Name,
653) -> Result<(), KernelError> {
654 let t = ctx.whnf(ty);
655 if !has_const_occ(&t, &pre.names) {
656 return Ok(());
657 }
658 match t {
659 Expr::Pi(bi, name, dom, body) => {
660 if has_const_occ(&dom, &pre.names) {
661 return Err(KernelError::InvalidInductive(format!(
662 "non-strictly-positive occurrence of '{}' in constructor '{}'",
663 decl_name, ctor_name
664 )));
665 }
666 let b = ctx.fresh(bi, name, (*dom).clone());
667 check_positivity(ctx, pre, &instantiate(&body, &fv(&b)), ctor_name, decl_name)
668 }
669 _ => {
670 if as_valid_ind_app(pre, &t, true).is_some() {
671 return Ok(());
672 }
673 match get_app_fn(&t) {
674 Expr::Const(c, _) if !pre.names.contains(c) => {
675 Err(KernelError::UnsupportedNestedInductive(decl_name.clone()))
676 }
677 _ => Err(KernelError::InvalidInductive(format!(
678 "invalid occurrence of '{}' in constructor '{}' (recursive occurrences \
679 must be applied to exactly the family parameters, with indices that do \
680 not mention the family)",
681 decl_name, ctor_name
682 ))),
683 }
684 }
685 }
686}
687
688fn classify_rec_field(
691 ctx: &mut DeriveCtx<'_>,
692 pre: &FamilyPre,
693 field_ty: &Expr,
694) -> Option<RecFieldSig> {
695 if !has_const_occ(field_ty, &pre.names) {
696 return None;
697 }
698 let (ds, cod) = peel_all(ctx, field_ty);
699 let codw = ctx.whnf(&cod);
700 let strict = ctx.is_checked();
701 let (type_idx, index_args) = as_valid_ind_app(pre, &codw, strict)?;
702 Some(RecFieldSig {
703 ds,
704 type_idx,
705 index_args,
706 })
707}
708
709#[allow(clippy::result_large_err)]
710fn check_ctor(
711 ctx: &mut DeriveCtx<'_>,
712 pre: &FamilyPre,
713 type_idx: usize,
714 cname: &Name,
715 cty: &Expr,
716) -> Result<CtorSig, KernelError> {
717 check_level_params_declared(cty, &pre.lparams, "constructor", cname)?;
718 if ctx.is_checked() {
719 ctx.ensure_sort(cty)?;
721 }
722 let decl_name = &pre.names[type_idx];
723 let rest = peel_against_params(ctx, cty, &pre.params, "constructor", cname)?;
724 let (field_binders, cod) = peel_binders_as_written(ctx, &rest);
727
728 let mut fields = Vec::with_capacity(field_binders.len());
729 for b in field_binders {
730 let sort_level = ctx.ensure_sort(&b.ty)?.map(|l| normalize_level(&l));
733 if let Some(sl) = &sort_level {
734 if !pre.ind_level.is_zero() && !is_geq(&pre.ind_level, sl) {
737 return Err(KernelError::InvalidInductive(format!(
738 "universe level of field '{}' in constructor '{}' is too big \
739 for inductive type '{}'",
740 b.name, cname, decl_name
741 )));
742 }
743 }
744 if ctx.is_checked() {
745 check_positivity(ctx, pre, &b.ty, cname, decl_name)?;
746 }
747 let rec = classify_rec_field(ctx, pre, &b.ty);
748 fields.push(FieldSig {
749 binder: b,
750 sort_level,
751 rec,
752 });
753 }
754
755 let ret_index_args = if ctx.is_checked() {
756 match as_valid_ind_app(pre, &cod, true) {
757 Some((j, idx)) if j == type_idx => idx,
758 _ => {
759 return Err(KernelError::InvalidInductive(format!(
760 "constructor '{}' must return '{}' applied to exactly the family \
761 parameters followed by index terms that do not mention the family",
762 cname, decl_name
763 )));
764 }
765 }
766 } else {
767 match as_valid_ind_app(pre, &cod, false) {
768 Some((j, idx)) if j == type_idx => idx,
769 _ => {
770 return Err(KernelError::InvalidInductive(format!(
771 "constructor '{}' does not return inductive type '{}'",
772 cname, decl_name
773 )));
774 }
775 }
776 };
777
778 Ok(CtorSig {
779 name: cname.clone(),
780 ty: cty.clone(),
781 fields,
782 ret_index_args,
783 })
784}
785
786fn family_rec_flags(family: &[Name], specs: &[InductiveSpec]) -> (bool, bool) {
814 let mut is_rec = false;
815 let mut is_reflexive = false;
816 for (_, ctor_ty) in specs.iter().flat_map(|spec| spec.ctors.iter()) {
817 let mut cur = ctor_ty;
818 while let Expr::Pi(_, _, dom, body) = cur {
819 if has_const_occ(dom, family) {
820 is_rec = true;
821 if matches!(&**dom, Expr::Pi(_, _, _, _)) {
822 is_reflexive = true;
823 }
824 }
825 cur = &**body;
826 }
827 }
828 (is_rec, is_reflexive)
829}
830
831fn is_large_eliminating(pre: &FamilyPre, ctors: &[Vec<CtorSig>]) -> bool {
839 if pre.ind_level.is_not_zero() {
840 return true;
842 }
843 if pre.names.len() > 1 {
844 return false;
845 }
846 let cs = &ctors[0];
847 match cs.len() {
848 0 => true, 1 => {
850 let c = &cs[0];
853 c.fields.iter().all(|f| {
854 let field_is_prop = matches!(&f.sort_level, Some(l) if l.is_zero());
855 field_is_prop || c.ret_index_args.contains(&Expr::FVar(f.binder.fvar))
856 })
857 }
858 _ => false,
859 }
860}
861
862fn compute_k_target(pre: &FamilyPre, ctors: &[Vec<CtorSig>]) -> bool {
866 pre.names.len() == 1
867 && pre.ind_level.is_zero()
868 && ctors[0].len() == 1
869 && ctors[0][0].fields.is_empty()
870}
871
872fn mk_elim_level_name(lparams: &[Name]) -> Name {
874 let mut cand = Name::str("u");
875 let mut i = 1u32;
876 while lparams.contains(&cand) {
877 cand = Name::str(format!("u_{}", i));
878 i += 1;
879 }
880 cand
881}
882
883fn last_component_name(n: &Name, fallback: &str) -> Name {
888 Name::str(n.last_str().unwrap_or(fallback).to_string())
889}
890
891#[allow(clippy::result_large_err)]
892fn derive_family_core(
893 ctx: &mut DeriveCtx<'_>,
894 pre: &FamilyPre,
895 specs: &[InductiveSpec],
896 ctors: Vec<Vec<CtorSig>>,
897) -> Result<DerivedFamily, KernelError> {
898 let k = pre.names.len();
899 let total_ctors: usize = ctors.iter().map(|c| c.len()).sum();
900 let rec_names: Vec<Name> = specs.iter().map(|s| s.effective_rec_name()).collect();
901
902 let large_elim = is_large_eliminating(pre, &ctors);
903 let k_target = compute_k_target(pre, &ctors);
904 let (rec_lparams, elim_level) = if large_elim {
905 let fresh = mk_elim_level_name(&pre.lparams);
906 let mut lp = Vec::with_capacity(pre.lparams.len() + 1);
907 lp.push(fresh.clone());
908 lp.extend(pre.lparams.iter().cloned());
909 (lp, Level::param(fresh))
910 } else {
911 (pre.lparams.clone(), Level::zero())
912 };
913 let rec_levels: Vec<Level> = rec_lparams.iter().cloned().map(Level::param).collect();
914 let param_exprs: Vec<Expr> = pre.params.iter().map(fv).collect();
915
916 let mut motives: Vec<Binder> = Vec::with_capacity(k);
918 for j in 0..k {
919 let mut t_args = param_exprs.clone();
920 t_args.extend(pre.indices[j].iter().map(fv));
921 let t_ty = mk_app(
922 Expr::Const(pre.names[j].clone(), pre.ind_levels.clone()),
923 &t_args,
924 );
925 let x = ctx.fresh(BinderInfo::Default, Name::str("t"), t_ty);
926 let mut dom = pre.indices[j].clone();
927 dom.push(x);
928 let motive_ty = close(
929 &dom,
930 &Expr::Sort(elim_level.clone()),
931 false,
932 Some(BinderInfo::Default),
933 );
934 let mname = if k == 1 {
935 Name::str("motive")
936 } else {
937 Name::str(format!("motive_{}", j + 1))
938 };
939 motives.push(ctx.fresh(BinderInfo::Implicit, mname, motive_ty));
940 }
941 let motive_exprs: Vec<Expr> = motives.iter().map(fv).collect();
942
943 struct MinorPlan {
947 type_idx: usize,
948 ctor_idx: usize,
949 minor: Binder,
950 }
951 let mut minors: Vec<MinorPlan> = Vec::with_capacity(total_ctors);
952 for (j, cs) in ctors.iter().enumerate() {
953 for (ci, c) in cs.iter().enumerate() {
954 let mut ih_binders: Vec<Binder> = Vec::new();
955 for f in &c.fields {
956 if let Some(rf) = &f.rec {
957 let ds_exprs: Vec<Expr> = rf.ds.iter().map(fv).collect();
958 let applied_field = mk_app(fv(&f.binder), &ds_exprs);
959 let mut m_args = rf.index_args.clone();
960 m_args.push(applied_field);
961 let ih_body = mk_app(fv(&motives[rf.type_idx]), &m_args);
962 let ih_ty = close(&rf.ds, &ih_body, false, None);
963 let ih_name =
964 Name::str(format!("{}_ih", f.binder.name.last_str().unwrap_or("a")));
965 ih_binders.push(ctx.fresh(BinderInfo::Default, ih_name, ih_ty));
966 }
967 }
968 let mut ctor_args = param_exprs.clone();
969 ctor_args.extend(c.fields.iter().map(|f| fv(&f.binder)));
970 let ctor_app = mk_app(
971 Expr::Const(c.name.clone(), pre.ind_levels.clone()),
972 &ctor_args,
973 );
974 let mut concl_args = c.ret_index_args.clone();
975 concl_args.push(ctor_app);
976 let concl = mk_app(fv(&motives[j]), &concl_args);
977 let mut tele: Vec<Binder> = c.fields.iter().map(|f| f.binder.clone()).collect();
978 tele.extend(ih_binders);
979 let minor_ty = close(&tele, &concl, false, None);
980 let minor = ctx.fresh(
981 BinderInfo::Default,
982 last_component_name(&c.name, "minor"),
983 minor_ty,
984 );
985 minors.push(MinorPlan {
986 type_idx: j,
987 ctor_idx: ci,
988 minor,
989 });
990 }
991 }
992 let minor_binders: Vec<Binder> = minors.iter().map(|m| m.minor.clone()).collect();
993 let minor_exprs: Vec<Expr> = minor_binders.iter().map(fv).collect();
994
995 let mut recursors = Vec::with_capacity(k);
997 for j in 0..k {
998 let mut t_args = param_exprs.clone();
1000 t_args.extend(pre.indices[j].iter().map(fv));
1001 let major_ty = mk_app(
1002 Expr::Const(pre.names[j].clone(), pre.ind_levels.clone()),
1003 &t_args,
1004 );
1005 let major = ctx.fresh(BinderInfo::Default, Name::str("t"), major_ty);
1006 let mut concl_args: Vec<Expr> = pre.indices[j].iter().map(fv).collect();
1007 concl_args.push(fv(&major));
1008 let concl = mk_app(fv(&motives[j]), &concl_args);
1009
1010 let mut rec_ty = close(std::slice::from_ref(&major), &concl, false, None);
1011 rec_ty = close(&pre.indices[j], &rec_ty, false, Some(BinderInfo::Implicit));
1012 rec_ty = close(&minor_binders, &rec_ty, false, Some(BinderInfo::Default));
1013 rec_ty = close(&motives, &rec_ty, false, Some(BinderInfo::Implicit));
1014 rec_ty = close(&pre.params, &rec_ty, false, Some(BinderInfo::Implicit));
1015
1016 let mut rules = Vec::with_capacity(ctors[j].len());
1019 for plan in minors.iter().filter(|m| m.type_idx == j) {
1020 let c = &ctors[j][plan.ctor_idx];
1021 let mut body_args: Vec<Expr> = c.fields.iter().map(|f| fv(&f.binder)).collect();
1022 for f in &c.fields {
1023 if let Some(rf) = &f.rec {
1024 let ds_exprs: Vec<Expr> = rf.ds.iter().map(fv).collect();
1025 let mut rec_args = param_exprs.clone();
1026 rec_args.extend(motive_exprs.iter().cloned());
1027 rec_args.extend(minor_exprs.iter().cloned());
1028 rec_args.extend(rf.index_args.iter().cloned());
1029 rec_args.push(mk_app(fv(&f.binder), &ds_exprs));
1030 let rec_call = mk_app(
1031 Expr::Const(rec_names[rf.type_idx].clone(), rec_levels.clone()),
1032 &rec_args,
1033 );
1034 body_args.push(close(&rf.ds, &rec_call, true, Some(BinderInfo::Default)));
1035 }
1036 }
1037 let body = mk_app(fv(&plan.minor), &body_args);
1038 let field_binders: Vec<Binder> = c.fields.iter().map(|f| f.binder.clone()).collect();
1039 let mut rhs = close(&field_binders, &body, true, Some(BinderInfo::Default));
1040 rhs = close(&minor_binders, &rhs, true, Some(BinderInfo::Default));
1041 rhs = close(&motives, &rhs, true, Some(BinderInfo::Default));
1042 rhs = close(&pre.params, &rhs, true, Some(BinderInfo::Default));
1043 rules.push(RecursorRule {
1044 ctor: c.name.clone(),
1045 nfields: c.fields.len() as u32,
1046 rhs,
1047 });
1048 }
1049
1050 recursors.push(ConstantInfo::Recursor(RecursorVal {
1051 common: ConstantVal {
1052 name: rec_names[j].clone(),
1053 level_params: rec_lparams.clone(),
1054 ty: rec_ty,
1055 },
1056 all: pre.names.clone(),
1057 num_params: pre.np as u32,
1058 num_indices: pre.indices[j].len() as u32,
1059 num_motives: k as u32,
1060 num_minors: total_ctors as u32,
1061 rules,
1062 k: k_target,
1063 is_unsafe: false,
1064 }));
1065 }
1066
1067 let (is_rec_family, is_reflexive) = family_rec_flags(&pre.names, specs);
1069 let is_prop = pre.ind_level.is_zero();
1070
1071 let mut inductives = Vec::with_capacity(k);
1072 let mut constructors = Vec::with_capacity(total_ctors);
1073 for (j, spec) in specs.iter().enumerate() {
1074 inductives.push(ConstantInfo::Inductive(InductiveVal {
1075 common: ConstantVal {
1076 name: pre.names[j].clone(),
1077 level_params: pre.lparams.clone(),
1078 ty: spec.ty.clone(),
1079 },
1080 num_params: pre.np as u32,
1081 num_indices: pre.indices[j].len() as u32,
1082 all: pre.names.clone(),
1083 ctors: ctors[j].iter().map(|c| c.name.clone()).collect(),
1084 num_nested: 0,
1085 is_rec: is_rec_family,
1086 is_unsafe: false,
1087 is_reflexive,
1088 is_prop,
1089 }));
1090 for (ci, c) in ctors[j].iter().enumerate() {
1091 constructors.push(ConstantInfo::Constructor(ConstructorVal {
1092 common: ConstantVal {
1093 name: c.name.clone(),
1094 level_params: pre.lparams.clone(),
1095 ty: c.ty.clone(),
1096 },
1097 induct: pre.names[j].clone(),
1098 cidx: ci as u32,
1099 num_params: pre.np as u32,
1100 num_fields: c.fields.len() as u32,
1101 is_unsafe: false,
1102 }));
1103 }
1104 }
1105
1106 Ok(DerivedFamily {
1107 inductives,
1108 constructors,
1109 recursors,
1110 })
1111}
1112
1113#[allow(clippy::result_large_err)]
1123pub(crate) fn check_specs_closed(specs: &[InductiveSpec]) -> Result<(), KernelError> {
1124 for spec in specs {
1125 crate::check::check_term_depth(&spec.name, &spec.ty)?;
1126 crate::check::check_closed_term(&spec.name, &spec.ty)?;
1127 for (ctor_name, ctor_ty) in &spec.ctors {
1128 crate::check::check_term_depth(ctor_name, ctor_ty)?;
1129 crate::check::check_closed_term(ctor_name, ctor_ty)?;
1130 }
1131 }
1132 Ok(())
1133}
1134
1135#[allow(clippy::result_large_err)]
1136fn check_distinct_ctor_names(specs: &[InductiveSpec]) -> Result<(), KernelError> {
1137 let mut seen: Vec<&Name> = Vec::new();
1138 for spec in specs {
1139 for (cname, _) in &spec.ctors {
1140 if seen.contains(&cname) {
1141 return Err(KernelError::InvalidInductive(format!(
1142 "duplicate constructor name '{}'",
1143 cname
1144 )));
1145 }
1146 seen.push(cname);
1147 }
1148 }
1149 Ok(())
1150}
1151
1152#[allow(clippy::result_large_err)]
1165fn check_types_do_not_mention_the_block(
1166 specs: &[InductiveSpec],
1167 family_names: &[Name],
1168) -> Result<(), KernelError> {
1169 for spec in specs {
1170 check_type_does_not_mention_the_block(&spec.name, &spec.ty, family_names)?;
1171 }
1172 Ok(())
1173}
1174
1175#[allow(clippy::result_large_err)]
1177fn check_type_does_not_mention_the_block(
1178 name: &Name,
1179 ty: &Expr,
1180 family_names: &[Name],
1181) -> Result<(), KernelError> {
1182 if has_const_occ(ty, family_names) {
1183 return Err(KernelError::InvalidInductive(format!(
1184 "the type of inductive type '{}' mentions a type of the block being declared: the \
1185 types of a block are checked before any of them is a constant",
1186 name
1187 )));
1188 }
1189 Ok(())
1190}
1191
1192#[allow(clippy::result_large_err)]
1202pub fn check_and_derive_family(
1203 env: &Environment,
1204 lparams: &[Name],
1205 num_params: u32,
1206 specs: &[InductiveSpec],
1207) -> Result<DerivedFamily, KernelError> {
1208 check_distinct_ctor_names(specs)?;
1209 check_specs_closed(specs)?;
1210 let family_names: Vec<Name> = specs.iter().map(|s| s.name.clone()).collect();
1211 check_types_do_not_mention_the_block(specs, &family_names)?;
1212
1213 let mut work = env.clone();
1215 for spec in specs {
1216 match work.find(&spec.name) {
1217 Some(ConstantInfo::Inductive(iv)) => {
1218 if iv.common.ty != spec.ty || iv.common.level_params != lparams {
1219 return Err(KernelError::InvalidInductive(format!(
1220 "inductive type '{}' is already declared with a different signature",
1221 spec.name
1222 )));
1223 }
1224 }
1225 Some(_) => {
1226 return Err(KernelError::InvalidInductive(format!(
1227 "'{}' is already declared and is not an inductive type",
1228 spec.name
1229 )));
1230 }
1231 None => {
1232 let stub = ConstantInfo::Inductive(InductiveVal {
1233 common: ConstantVal {
1234 name: spec.name.clone(),
1235 level_params: lparams.to_vec(),
1236 ty: spec.ty.clone(),
1237 },
1238 num_params,
1239 num_indices: 0,
1240 all: family_names.clone(),
1241 ctors: spec.ctors.iter().map(|(n, _)| n.clone()).collect(),
1242 num_nested: 0,
1243 is_rec: false,
1244 is_unsafe: false,
1245 is_reflexive: false,
1246 is_prop: false,
1247 });
1248 work.add_constant(stub)
1249 .map_err(|e| KernelError::Other(e.to_string()))?;
1250 }
1251 }
1252 }
1253
1254 let types: Vec<(Name, Expr)> = specs
1255 .iter()
1256 .map(|s| (s.name.clone(), s.ty.clone()))
1257 .collect();
1258 let mut ctx = DeriveCtx::checked(&work);
1259 let pre = build_family_pre(&mut ctx, lparams, num_params, &types)?;
1260 let mut ctor_sigs = Vec::with_capacity(specs.len());
1261 for (j, spec) in specs.iter().enumerate() {
1262 let mut cs = Vec::with_capacity(spec.ctors.len());
1263 for (cname, cty) in &spec.ctors {
1264 cs.push(check_ctor(&mut ctx, &pre, j, cname, cty)?);
1265 }
1266 ctor_sigs.push(cs);
1267 }
1268 derive_family_core(&mut ctx, &pre, specs, ctor_sigs)
1269}
1270
1271#[allow(clippy::result_large_err)]
1291pub fn add_inductive_family(
1292 env: &mut Environment,
1293 lparams: Vec<Name>,
1294 num_params: u32,
1295 specs: Vec<InductiveSpec>,
1296) -> Result<(), KernelError> {
1297 let fam = check_and_derive_family(env, &lparams, num_params, &specs)?;
1298 for ci in fam.into_constant_infos() {
1299 env.add_constant(ci)
1300 .map_err(|e| KernelError::Other(e.to_string()))?;
1301 }
1302 Ok(())
1303}
1304
1305#[allow(clippy::result_large_err)]
1314pub fn derive_family_unchecked(
1315 lparams: &[Name],
1316 num_params: u32,
1317 specs: &[InductiveSpec],
1318) -> Result<DerivedFamily, KernelError> {
1319 check_distinct_ctor_names(specs)?;
1320 let types: Vec<(Name, Expr)> = specs
1321 .iter()
1322 .map(|s| (s.name.clone(), s.ty.clone()))
1323 .collect();
1324 let mut ctx = DeriveCtx::unchecked();
1325 let pre = build_family_pre(&mut ctx, lparams, num_params, &types)?;
1326 let mut ctor_sigs = Vec::with_capacity(specs.len());
1327 for (j, spec) in specs.iter().enumerate() {
1328 let mut cs = Vec::with_capacity(spec.ctors.len());
1329 for (cname, cty) in &spec.ctors {
1330 cs.push(check_ctor(&mut ctx, &pre, j, cname, cty)?);
1331 }
1332 ctor_sigs.push(cs);
1333 }
1334 derive_family_core(&mut ctx, &pre, specs, ctor_sigs)
1335}
1336
1337#[allow(clippy::result_large_err)]
1347pub(crate) fn validate_inductive_val(
1348 env: &Environment,
1349 iv: &InductiveVal,
1350) -> Result<(), KernelError> {
1351 for (i, lp) in iv.common.level_params.iter().enumerate() {
1352 if iv.common.level_params[..i].contains(lp) {
1353 return Err(KernelError::InvalidInductive(format!(
1354 "duplicate universe parameter '{}' in inductive '{}'",
1355 lp, iv.common.name
1356 )));
1357 }
1358 }
1359 check_level_params_declared(
1360 &iv.common.ty,
1361 &iv.common.level_params,
1362 "inductive type",
1363 &iv.common.name,
1364 )?;
1365 check_type_does_not_mention_the_block(&iv.common.name, &iv.common.ty, &iv.all)?;
1368 let mut ctx = DeriveCtx::checked(env);
1369 ctx.ensure_sort(&iv.common.ty)?;
1370 let (binders, rest) = peel_all(&mut ctx, &iv.common.ty);
1371 let restw = ctx.whnf(&rest);
1372 let level = match restw {
1373 Expr::Sort(l) => l,
1374 other => {
1375 return Err(KernelError::InvalidInductive(format!(
1376 "inductive type '{}' must end in a sort, found '{}'",
1377 iv.common.name, other
1378 )));
1379 }
1380 };
1381 if binders.len() != (iv.num_params + iv.num_indices) as usize {
1382 return Err(KernelError::InvalidInductive(format!(
1383 "inductive '{}' declares {} params + {} indices but its type has {} binders",
1384 iv.common.name,
1385 iv.num_params,
1386 iv.num_indices,
1387 binders.len()
1388 )));
1389 }
1390 if iv.is_prop != level.is_zero() {
1391 return Err(KernelError::InvalidInductive(format!(
1392 "inductive '{}': is_prop flag ({}) is inconsistent with the declared sort",
1393 iv.common.name, iv.is_prop
1394 )));
1395 }
1396 if !iv.all.contains(&iv.common.name) {
1397 return Err(KernelError::InvalidInductive(format!(
1398 "inductive '{}' is missing from its own mutual group",
1399 iv.common.name
1400 )));
1401 }
1402 for (i, c) in iv.ctors.iter().enumerate() {
1403 if iv.ctors[..i].contains(c) {
1404 return Err(KernelError::InvalidInductive(format!(
1405 "duplicate constructor '{}' in inductive '{}'",
1406 c, iv.common.name
1407 )));
1408 }
1409 }
1410 Ok(())
1411}
1412
1413#[allow(clippy::result_large_err)]
1416fn family_pre_from_env<'e>(
1417 env: &'e Environment,
1418 all: &[Name],
1419 err_kind: fn(String) -> KernelError,
1420) -> Result<(DeriveCtx<'e>, FamilyPre), KernelError> {
1421 let mut lparams: Option<Vec<Name>> = None;
1422 let mut np: Option<u32> = None;
1423 let mut types = Vec::with_capacity(all.len());
1424 for tname in all {
1425 let siv = env.get_inductive_val(tname).ok_or_else(|| {
1426 err_kind(format!(
1427 "mutual inductive sibling '{}' is not declared in the environment",
1428 tname
1429 ))
1430 })?;
1431 if siv.all != all {
1432 return Err(err_kind(format!(
1433 "inductive '{}' declares a different mutual group",
1434 tname
1435 )));
1436 }
1437 match (&lparams, &np) {
1438 (None, None) => {
1439 lparams = Some(siv.common.level_params.clone());
1440 np = Some(siv.num_params);
1441 }
1442 (Some(lp), Some(n)) if *lp != siv.common.level_params || *n != siv.num_params => {
1443 return Err(err_kind(format!(
1444 "mutual inductive '{}' disagrees on level params or param count",
1445 tname
1446 )));
1447 }
1448 _ => {}
1449 }
1450 types.push((tname.clone(), siv.common.ty.clone()));
1451 }
1452 let lparams = lparams.unwrap_or_default();
1453 let np = np.unwrap_or(0);
1454 let mut ctx = DeriveCtx::checked(env);
1455 let pre = build_family_pre(&mut ctx, &lparams, np, &types)?;
1456 for (j, tname) in all.iter().enumerate() {
1458 if let Some(siv) = env.get_inductive_val(tname) {
1459 if siv.num_indices as usize != pre.indices[j].len() {
1460 return Err(err_kind(format!(
1461 "inductive '{}' declares {} indices but its type has {}",
1462 tname,
1463 siv.num_indices,
1464 pre.indices[j].len()
1465 )));
1466 }
1467 }
1468 }
1469 Ok((ctx, pre))
1470}
1471
1472#[allow(clippy::result_large_err)]
1477pub(crate) fn verify_constructor_val(
1478 env: &Environment,
1479 cv: &ConstructorVal,
1480) -> Result<(), KernelError> {
1481 let iv = env.get_inductive_val(&cv.induct).ok_or_else(|| {
1482 KernelError::InvalidInductive(format!(
1483 "constructor '{}' references unknown inductive '{}'",
1484 cv.common.name, cv.induct
1485 ))
1486 })?;
1487 if cv.common.level_params != iv.common.level_params {
1488 return Err(KernelError::InvalidInductive(format!(
1489 "constructor '{}' must use the level parameters of '{}'",
1490 cv.common.name, cv.induct
1491 )));
1492 }
1493 if cv.num_params != iv.num_params {
1494 return Err(KernelError::InvalidInductive(format!(
1495 "constructor '{}': num_params ({}) disagrees with inductive '{}' ({})",
1496 cv.common.name, cv.num_params, cv.induct, iv.num_params
1497 )));
1498 }
1499 match iv.ctors.iter().position(|c| c == &cv.common.name) {
1500 Some(pos) if pos as u32 == cv.cidx => {}
1501 Some(pos) => {
1502 return Err(KernelError::InvalidInductive(format!(
1503 "constructor '{}' has cidx {} but is at position {} in '{}'",
1504 cv.common.name, cv.cidx, pos, cv.induct
1505 )));
1506 }
1507 None => {
1508 return Err(KernelError::InvalidInductive(format!(
1509 "constructor '{}' is not listed by inductive '{}'",
1510 cv.common.name, cv.induct
1511 )));
1512 }
1513 }
1514 let all = iv.all.clone();
1515 let induct = cv.induct.clone();
1516 let (mut ctx, pre) = family_pre_from_env(env, &all, KernelError::InvalidInductive)?;
1517 let type_idx = pre.names.iter().position(|n| *n == induct).ok_or_else(|| {
1518 KernelError::InvalidInductive(format!(
1519 "inductive '{}' missing from its own mutual group",
1520 induct
1521 ))
1522 })?;
1523 let sig = check_ctor(&mut ctx, &pre, type_idx, &cv.common.name, &cv.common.ty)?;
1524 if sig.fields.len() != cv.num_fields as usize {
1525 return Err(KernelError::InvalidInductive(format!(
1526 "constructor '{}': num_fields ({}) disagrees with its type ({} fields)",
1527 cv.common.name,
1528 cv.num_fields,
1529 sig.fields.len()
1530 )));
1531 }
1532 Ok(())
1533}
1534
1535#[allow(clippy::result_large_err)]
1575pub(crate) fn verify_recursor_val(
1576 env: &Environment,
1577 rv: &RecursorVal,
1578) -> Result<RecursorVal, KernelError> {
1579 if rv.all.is_empty() {
1580 return Err(KernelError::InvalidRecursor(format!(
1581 "recursor '{}' has an empty mutual group",
1582 rv.common.name
1583 )));
1584 }
1585 let mut lparams: Option<Vec<Name>> = None;
1587 let mut np: Option<u32> = None;
1588 let mut specs = Vec::with_capacity(rv.all.len());
1589 let flat_style = super::installed::is_flat_style(&rv.common.name);
1598 for tname in &rv.all {
1599 let iv = env.get_inductive_val(tname).ok_or_else(|| {
1600 KernelError::InvalidRecursor(format!(
1601 "recursor '{}' references unknown inductive '{}'",
1602 rv.common.name, tname
1603 ))
1604 })?;
1605 if iv.all != rv.all {
1606 return Err(KernelError::InvalidRecursor(format!(
1607 "recursor '{}' and inductive '{}' disagree on the mutual group",
1608 rv.common.name, tname
1609 )));
1610 }
1611 match (&lparams, &np) {
1612 (None, None) => {
1613 lparams = Some(iv.common.level_params.clone());
1614 np = Some(iv.num_params);
1615 }
1616 (Some(lp), Some(n)) if *lp != iv.common.level_params || *n != iv.num_params => {
1617 return Err(KernelError::InvalidRecursor(format!(
1618 "mutual inductive '{}' disagrees on level params or param count",
1619 tname
1620 )));
1621 }
1622 _ => {}
1623 }
1624 let mut ctors = Vec::with_capacity(iv.ctors.len());
1625 for cname in &iv.ctors {
1626 let cval = env.get_constructor_val(cname).ok_or_else(|| {
1627 KernelError::InvalidRecursor(format!(
1628 "recursor '{}': constructor '{}' of '{}' is not declared yet",
1629 rv.common.name, cname, tname
1630 ))
1631 })?;
1632 ctors.push((cname.clone(), cval.common.ty.clone()));
1633 }
1634 let rec_name = super::installed::recursor_name(tname, flat_style);
1635 specs.push(InductiveSpec {
1636 name: tname.clone(),
1637 ty: iv.common.ty.clone(),
1638 ctors,
1639 rec_name: Some(rec_name),
1640 });
1641 }
1642 let lparams = lparams.unwrap_or_default();
1643 let np = np.unwrap_or(0);
1644 let fam = check_and_derive_family(env, &lparams, np, &specs)?;
1645
1646 let mut named_after: Option<&Name> = None;
1648 for (tname, d_ci) in rv.all.iter().zip(&fam.recursors) {
1649 if let ConstantInfo::Recursor(d) = d_ci {
1650 if d.common.name != rv.common.name {
1653 continue;
1654 }
1655 if let Some(installed) = derived_under_supplied_names(d, rv) {
1658 if recursor_matches(env, &[&fam.recursors], &installed, rv) {
1659 return Ok(installed);
1660 }
1661 }
1662 named_after = Some(tname);
1663 }
1664 }
1665 Err(KernelError::InvalidRecursor(match named_after {
1666 Some(tname) => format!(
1667 "recursor '{}' does not match the kernel-derived recursor for '{}'",
1668 rv.common.name, tname
1669 ),
1670 None => format!(
1671 "recursor '{}' is not named after a type of its family: the kernel derives '{}' \
1672 for '{}'",
1673 rv.common.name,
1674 specs[0].effective_rec_name(),
1675 rv.all[0]
1676 ),
1677 }))
1678}
1679
1680#[cfg(test)]
1681mod tests {
1682 use super::*;
1683
1684 fn nat_spec() -> InductiveSpec {
1685 let nat = Expr::Const(Name::str("Nat"), vec![]);
1686 InductiveSpec::new(
1687 Name::str("Nat"),
1688 Expr::Sort(Level::succ(Level::zero())),
1689 vec![
1690 (Name::str("Nat.zero"), nat.clone()),
1691 (
1692 Name::str("Nat.succ"),
1693 Expr::Pi(
1694 BinderInfo::Default,
1695 Name::str("n"),
1696 Node::new(nat.clone()),
1697 Node::new(nat),
1698 ),
1699 ),
1700 ],
1701 )
1702 .with_rec_name(Name::str("Nat.rec"))
1703 }
1704
1705 #[test]
1706 fn nat_derivation_shape() {
1707 let env = Environment::new();
1708 let fam = check_and_derive_family(&env, &[], 0, &[nat_spec()]).expect("derive Nat");
1709 assert_eq!(fam.inductives.len(), 1);
1710 assert_eq!(fam.constructors.len(), 2);
1711 assert_eq!(fam.recursors.len(), 1);
1712 let rv = match &fam.recursors[0] {
1713 ConstantInfo::Recursor(rv) => rv,
1714 other => panic!("expected recursor, got {:?}", other),
1715 };
1716 assert_eq!(rv.num_motives, 1);
1717 assert_eq!(rv.num_minors, 2);
1718 assert_eq!(rv.num_params, 0);
1719 assert_eq!(rv.num_indices, 0);
1720 assert!(!rv.k);
1721 assert_eq!(rv.common.level_params, vec![Name::str("u")]);
1723 let succ_rule = rv.get_rule(&Name::str("Nat.succ")).expect("succ rule");
1725 assert_eq!(succ_rule.nfields, 1);
1726 }
1727
1728 #[test]
1729 fn unchecked_matches_checked_for_nat() {
1730 let env = Environment::new();
1731 let a = check_and_derive_family(&env, &[], 0, &[nat_spec()]).expect("checked");
1732 let b = derive_family_unchecked(&[], 0, &[nat_spec()]).expect("unchecked");
1733 assert_eq!(a.recursors, b.recursors);
1734 assert_eq!(a.constructors, b.constructors);
1735 }
1736
1737 #[test]
1738 fn nested_inductive_rejected() {
1739 let mut env = Environment::new();
1741 crate::builtin::init_builtin_env(&mut env).expect("builtin env");
1742 let t = Expr::Const(Name::str("T"), vec![]);
1743 let list_t = Expr::App(
1744 Node::new(Expr::Const(Name::str("List"), vec![Level::zero()])),
1745 Node::new(t.clone()),
1746 );
1747 let spec = InductiveSpec::new(
1748 Name::str("T"),
1749 Expr::Sort(Level::succ(Level::zero())),
1750 vec![(
1751 Name::str("T.mk"),
1752 Expr::Pi(
1753 BinderInfo::Default,
1754 Name::str("l"),
1755 Node::new(list_t),
1756 Node::new(t),
1757 ),
1758 )],
1759 );
1760 let err = check_and_derive_family(&env, &[], 0, &[spec]).expect_err("must reject");
1761 assert!(matches!(err, KernelError::UnsupportedNestedInductive(_)));
1762 }
1763}