Skip to main content

logicaffeine_kernel/dag/
inductive.rs

1//! Inductive families: Lean's `add_inductive`, including nested-inductive elimination and
2//! recursor generation.
3//!
4//! The kernel is handed the family's types and constructor types and derives everything else
5//! itself: parameter/index split, universe constraints, strict positivity, recursive and
6//! reflexive flags, large elimination, the K flag, and every recursor with its reduction rules.
7//! An export's claimed inductive, constructor and recursor declarations are admitted only if they
8//! are identical to what was derived, so a recursor with a forged rule, a missing induction
9//! hypothesis or an unjustified K flag cannot enter the environment.
10
11use super::env::{Const, CtorInfo, InductiveInfo, Kind, RecInfo, RecRule, Safety};
12use super::error::{KResult, KernelFailure};
13use super::expr::{ExprId, Node};
14use super::level::{LevelId, LevelNode, LevelsId};
15use super::name::NameId;
16use super::tc::Kernel;
17use rustc_hash::FxHashMap as FxMap;
18use std::rc::Rc;
19
20#[derive(Clone, Debug)]
21pub struct IndType {
22    pub name: NameId,
23    pub ty: ExprId,
24    pub ctors: Vec<(NameId, ExprId)>,
25}
26
27#[derive(Clone, Debug)]
28pub struct InductiveDecl {
29    pub lparams: Rc<[NameId]>,
30    pub nparams: u32,
31    pub types: Vec<IndType>,
32    pub is_unsafe: bool,
33}
34
35struct Stats {
36    levels: LevelsId,
37    result_level: LevelId,
38    nindices: Vec<u32>,
39    ind_consts: Vec<ExprId>,
40    ind_names: Vec<NameId>,
41    params: Vec<ExprId>,
42    is_not_zero: bool,
43}
44
45#[derive(Clone)]
46struct RecTmp {
47    motive: ExprId,
48    minors: Vec<ExprId>,
49    indices: Vec<ExprId>,
50    major: ExprId,
51}
52
53struct Nested {
54    params: Vec<ExprId>,
55    aux2nested: Vec<(NameId, ExprId)>,
56    types: Vec<IndType>,
57}
58
59struct NestState {
60    new_types: Vec<IndType>,
61    nested_aux: Vec<(ExprId, NameId)>,
62    next_idx: u64,
63    lvls: LevelsId,
64}
65
66fn reject(m: impl Into<String>) -> KernelFailure {
67    KernelFailure::reject(m)
68}
69
70impl Kernel {
71    /// Admits an inductive family whose declarations an export claims are `claimed`.
72    pub fn add_inductive(&mut self, decl: InductiveDecl, claimed: Vec<Const>) -> KResult<()> {
73        let first = decl.types.first().map(|t| t.name);
74        let safety = if decl.is_unsafe {
75            Safety::Unsafe
76        } else {
77            Safety::Safe
78        };
79        let r = self.with_decl(decl.lparams.clone(), safety, |k| {
80            let generated = k.generate_inductive(&decl)?;
81            k.compare_claimed(&generated, &claimed)
82        });
83        r.map_err(|e| {
84            e.in_declaration(first.map(|n| self.s.names.display(n)).unwrap_or_default())
85        })?;
86        for c in claimed {
87            self.env.add(c);
88        }
89        Ok(())
90    }
91
92    fn compare_claimed(&mut self, generated: &[Const], claimed: &[Const]) -> KResult<()> {
93        let mut by_name: FxMap<NameId, &Const> = FxMap::default();
94        for c in claimed {
95            if by_name.insert(c.name, c).is_some() {
96                return Err(reject(format!(
97                    "'{}' is declared twice in one inductive block",
98                    self.s.names.display(c.name)
99                )));
100            }
101        }
102        for g in generated {
103            let Some(c) = by_name.get(&g.name) else {
104                return Err(reject(format!(
105                    "the inductive block does not declare '{}', which the kernel derives",
106                    self.s.names.display(g.name)
107                )));
108            };
109            if *c != g {
110                return Err(reject(format!(
111                    "the exported '{}' differs from the declaration the kernel derives",
112                    self.s.names.display(g.name)
113                ))
114                .with_detail(self.explain_difference(g, c)));
115            }
116        }
117        if claimed.len() != generated.len() {
118            let extra: Vec<String> = claimed
119                .iter()
120                .filter(|c| !generated.iter().any(|g| g.name == c.name))
121                .map(|c| self.s.names.display(c.name))
122                .collect();
123            return Err(reject(format!(
124                "the inductive block declares constants the kernel does not derive: {}",
125                extra.join(", ")
126            )));
127        }
128        Ok(())
129    }
130
131    fn explain_difference(&self, g: &Const, c: &Const) -> String {
132        if g.lparams != c.lparams {
133            return "universe parameters differ".into();
134        }
135        if g.ty != c.ty {
136            return format!(
137                "derived type: {}\n  exported type: {}",
138                self.show(g.ty),
139                self.show(c.ty)
140            );
141        }
142        match (&g.kind, &c.kind) {
143            (Kind::Rec(a), Kind::Rec(b)) => {
144                if a.k != b.k {
145                    return format!("K flag: derived {}, exported {}", a.k, b.k);
146                }
147                if a.rules.len() != b.rules.len() {
148                    return format!(
149                        "derived {} rules, exported {}",
150                        a.rules.len(),
151                        b.rules.len()
152                    );
153                }
154                for (x, y) in a.rules.iter().zip(b.rules.iter()) {
155                    if x != y {
156                        return format!(
157                            "rule for '{}': derived {} with {} fields\n  exported {} with {} fields",
158                            self.s.names.display(x.ctor),
159                            self.show(x.rhs),
160                            x.nfields,
161                            self.show(y.rhs),
162                            y.nfields
163                        );
164                    }
165                }
166                format!("derived {a:?}\n  exported {b:?}")
167            }
168            (a, b) => format!("derived {a:?}\n  exported {b:?}"),
169        }
170    }
171
172    pub(crate) fn rec_name(&mut self, n: NameId) -> NameId {
173        self.s.names.str(n, "rec")
174    }
175
176    /// Lean's `Expr.consumeTypeAnnotations`.
177    fn consume_type_annotations(&self, mut e: ExprId) -> ExprId {
178        loop {
179            let w = &self.wk;
180            if self.is_app_of_arity(e, w.opt_param, 2) || self.is_app_of_arity(e, w.auto_param, 2) {
181                let Node::App(f, _) = self.s.node(e) else {
182                    unreachable!()
183                };
184                let Node::App(_, t) = self.s.node(f) else {
185                    unreachable!()
186                };
187                e = t;
188            } else if self.is_app_of_arity(e, w.out_param, 1)
189                || self.is_app_of_arity(e, w.semi_out_param, 1)
190            {
191                let Node::App(_, t) = self.s.node(e) else {
192                    unreachable!()
193                };
194                e = t;
195            } else {
196                return e;
197            }
198        }
199    }
200
201    fn local_type(&self, fv: ExprId) -> ExprId {
202        self.lctx[self.fvar_index(fv) as usize].ty
203    }
204
205    fn has_ind_occ(&self, names: &[NameId], e: ExprId) -> bool {
206        self.s.mentions_const(e, names)
207    }
208
209    fn generate_inductive(&mut self, decl: &InductiveDecl) -> KResult<Vec<Const>> {
210        if decl.types.is_empty() {
211            return Err(reject("empty inductive declaration"));
212        }
213        for t in &decl.types {
214            if self.s.has_fvar(t.ty) || self.s.has_loose_bvars(t.ty) {
215                return Err(reject("inductive type contains free variables"));
216            }
217            for (_, cty) in &t.ctors {
218                if self.s.has_fvar(*cty) || self.s.has_loose_bvars(*cty) {
219                    return Err(reject("constructor type contains free variables"));
220                }
221                self.check_no_nested_aux(*cty)?;
222            }
223        }
224        let allow_primitive = self.check_primitive_inductive(decl)?;
225        let nested = self.elim_nested(decl)?;
226        let num_nested = nested.aux2nested.len() as u32;
227        let mut provisional = Vec::new();
228        let r = self.add_inductive_core(
229            decl,
230            &nested.types,
231            num_nested,
232            allow_primitive,
233            &mut provisional,
234        );
235        let r = match r {
236            Ok(generated) if num_nested == 0 => Ok(generated),
237            Ok(generated) => self.restore_nested(decl, &nested, generated),
238            Err(e) => Err(e),
239        };
240        for n in provisional {
241            self.env.remove(n);
242        }
243        r
244    }
245
246    fn check_no_nested_aux(&self, e: ExprId) -> KResult<()> {
247        let p = self.wk.nested_prefix;
248        let bad = self.s.any_node(e, &mut |s, x| match s.node(x) {
249            Node::Const(c, _) | Node::Proj(c, _, _) => s.names.is_prefix_of(p, c),
250            _ => false,
251        });
252        if bad {
253            return Err(reject("declaration uses the reserved prefix '_nested'"));
254        }
255        Ok(())
256    }
257
258    /// Lean's `checkPrimitiveInductive`: may this family take the names `Nat`/`Bool`?
259    fn check_primitive_inductive(&mut self, decl: &InductiveDecl) -> KResult<bool> {
260        if decl.is_unsafe || !decl.lparams.is_empty() || decl.nparams != 0 || decl.types.len() != 1
261        {
262            return Ok(false);
263        }
264        let t = &decl.types[0];
265        let one = self.s.levels.of_nat(1);
266        if t.ty != self.s.sort(one) {
267            return Ok(false);
268        }
269        let fail = |k: &Kernel| {
270            reject(format!(
271                "invalid form for primitive inductive '{}'",
272                k.s.names.display(t.name)
273            ))
274        };
275        let w = (
276            self.wk.bool_,
277            self.wk.bool_false,
278            self.wk.bool_true,
279            self.wk.nat,
280            self.wk.nat_zero,
281            self.wk.nat_succ,
282        );
283        if t.name == w.0 {
284            let b = self.s.cnst(w.0, LevelsId::EMPTY);
285            if t.ctors != [(w.1, b), (w.2, b)] {
286                return Err(fail(self));
287            }
288        } else if t.name == w.3 {
289            let n = self.s.cnst(w.3, LevelsId::EMPTY);
290            let nn = self.s.pi(n, n);
291            if t.ctors != [(w.4, n), (w.5, nn)] {
292                return Err(fail(self));
293            }
294        } else {
295            return Ok(false);
296        }
297        Ok(true)
298    }
299
300    // ---- AddInductive ----
301
302    fn add_inductive_core(
303        &mut self,
304        decl: &InductiveDecl,
305        types: &[IndType],
306        num_nested: u32,
307        allow_primitive: bool,
308        provisional: &mut Vec<NameId>,
309    ) -> KResult<Vec<Const>> {
310        let nparams = decl.nparams as usize;
311        let is_unsafe = decl.is_unsafe;
312        self.check_duplicate_lparams(&decl.lparams)?;
313        let levels = self.const_levels_of(&decl.lparams);
314        let mut stats = Stats {
315            levels,
316            result_level: LevelId::ZERO,
317            nindices: Vec::new(),
318            ind_consts: Vec::new(),
319            ind_names: types.iter().map(|t| t.name).collect(),
320            params: Vec::new(),
321            is_not_zero: false,
322        };
323        // checkInductiveTypes
324        for (d, it) in types.iter().enumerate() {
325            self.check(it.ty)?;
326            let mut t = self.whnf(it.ty)?;
327            let mut i = 0usize;
328            let mut nindices = 0u32;
329            while let Node::Pi(dom, body) = self.s.node(t) {
330                if i < nparams {
331                    if d == 0 {
332                        let ty = self.consume_type_annotations(dom);
333                        let p = self.push_local(ty, None);
334                        stats.params.push(p);
335                        let b = self.s.instantiate1(body, p);
336                        t = self.whnf(b)?;
337                    } else {
338                        let p = stats.params[i];
339                        let pt = self.local_type(p);
340                        if !self.is_def_eq(dom, pt)? {
341                            return Err(reject("parameters of all inductive datatypes must match"));
342                        }
343                        let b = self.s.instantiate1(body, p);
344                        t = self.whnf(b)?;
345                    }
346                    i += 1;
347                } else {
348                    let ty = self.consume_type_annotations(dom);
349                    let a = self.push_local(ty, None);
350                    let b = self.s.instantiate1(body, a);
351                    t = self.whnf(b)?;
352                    nindices += 1;
353                }
354            }
355            if i != nparams {
356                return Err(reject(
357                    "number of parameters mismatch in inductive datatype declaration",
358                ));
359            }
360            let sort = self.ensure_sort(t)?;
361            let rl = self.sort_level(sort);
362            if d == 0 {
363                stats.result_level = rl;
364                stats.is_not_zero = self.s.levels.is_never_zero(rl);
365            } else if !self.s.levels.equiv(rl, stats.result_level) {
366                return Err(reject(
367                    "mutually inductive types must live in the same universe",
368                ));
369            }
370            stats.nindices.push(nindices);
371            let c = self.s.cnst(it.name, stats.levels);
372            stats.ind_consts.push(c);
373        }
374        let all: Rc<[NameId]> = types.iter().map(|t| t.name).collect::<Vec<_>>().into();
375        let is_rec = self.syntactic_occurrence(types, &stats.ind_names, false);
376        let is_reflexive = self.syntactic_occurrence(types, &stats.ind_names, true);
377        let mut out = Vec::new();
378        // declareInductiveTypes
379        for (d, it) in types.iter().enumerate() {
380            self.check_name(it.name, allow_primitive)?;
381            let c = Const {
382                name: it.name,
383                lparams: decl.lparams.clone(),
384                ty: it.ty,
385                kind: Kind::Induct(InductiveInfo {
386                    num_params: nparams as u32,
387                    num_indices: stats.nindices[d],
388                    all: all.clone(),
389                    ctors: it.ctors.iter().map(|c| c.0).collect::<Vec<_>>().into(),
390                    num_nested,
391                    is_rec,
392                    is_reflexive,
393                    is_unsafe,
394                    rec: self.rec_name(it.name),
395                }),
396            };
397            self.env.add_provisional(c.clone());
398            provisional.push(it.name);
399            out.push(c);
400        }
401        // checkConstructors
402        for (d, it) in types.iter().enumerate() {
403            let mut found: Vec<NameId> = Vec::new();
404            for (cn, cty) in &it.ctors {
405                if found.contains(cn) {
406                    return Err(reject(format!(
407                        "duplicate constructor name '{}'",
408                        self.s.names.display(*cn)
409                    )));
410                }
411                found.push(*cn);
412                self.check(*cty)?;
413                let mut t = *cty;
414                let mut i = 0usize;
415                loop {
416                    let Node::Pi(dom, body) = self.s.node(t) else {
417                        if !self.is_valid_ind_app_idx(&stats, t, d) {
418                            return Err(reject(format!(
419                                "invalid return type for '{}'",
420                                self.s.names.display(*cn)
421                            )));
422                        }
423                        break;
424                    };
425                    if i < nparams {
426                        let p = stats.params[i];
427                        let pt = self.local_type(p);
428                        if !self.is_def_eq(dom, pt)? {
429                            return Err(reject(format!(
430                                "arg #{} of '{}' does not match inductive datatype parameters",
431                                i + 1,
432                                self.s.names.display(*cn)
433                            )));
434                        }
435                        t = self.s.instantiate1(body, p);
436                    } else {
437                        let dt = self.infer(dom, true)?;
438                        let s = self.ensure_sort(dt)?;
439                        let sl = self.sort_level(s);
440                        let rl = stats.result_level;
441                        if !(self.s.levels.is_always_zero(rl) || self.s.levels.leq(sl, rl)) {
442                            return Err(reject(format!(
443                                "universe level of type_of(arg #{}) of '{}' is too big for the corresponding inductive datatype",
444                                i + 1,
445                                self.s.names.display(*cn)
446                            )));
447                        }
448                        if !is_unsafe {
449                            self.check_positivity(&stats, dom, *cn, i)?;
450                        }
451                        let ty = self.consume_type_annotations(dom);
452                        let a = self.push_local(ty, None);
453                        t = self.s.instantiate1(body, a);
454                    }
455                    i += 1;
456                }
457            }
458        }
459        // declareConstructors
460        for it in types {
461            for (cidx, (cn, cty)) in it.ctors.iter().enumerate() {
462                let mut arity = 0u32;
463                let mut t = *cty;
464                while let Node::Pi(_, b) = self.s.node(t) {
465                    arity += 1;
466                    t = b;
467                }
468                self.check_name(*cn, allow_primitive)?;
469                let c = Const {
470                    name: *cn,
471                    lparams: decl.lparams.clone(),
472                    ty: *cty,
473                    kind: Kind::Ctor(CtorInfo {
474                        induct: it.name,
475                        cidx: cidx as u32,
476                        num_params: nparams as u32,
477                        num_fields: arity - nparams as u32,
478                        is_unsafe,
479                    }),
480                };
481                if arity < nparams as u32 {
482                    return Err(reject(
483                        "constructor has fewer arguments than the inductive has parameters",
484                    ));
485                }
486                self.env.add_provisional(c.clone());
487                provisional.push(*cn);
488                out.push(c);
489            }
490        }
491        // recursors
492        let elim_level = self.get_elim_level(&stats, types, &decl.lparams)?;
493        let k = self.is_k_target(&stats, types);
494        let rec_infos = self.mk_rec_infos(&stats, types, elim_level)?;
495        let motives: Vec<ExprId> = rec_infos.iter().map(|r| r.motive).collect();
496        let minors: Vec<ExprId> = rec_infos
497            .iter()
498            .flat_map(|r| r.minors.iter().copied())
499            .collect();
500        let (rec_lparams, rec_levels) = match self.s.levels.node(elim_level) {
501            LevelNode::Param(u) => {
502                let mut ps = vec![u];
503                ps.extend(decl.lparams.iter().copied());
504                let mut ls = vec![elim_level];
505                ls.extend(self.s.levels.get_list(stats.levels).to_vec());
506                let lsid = self.s.levels.list(&ls);
507                (Rc::from(ps), lsid)
508            }
509            _ => (decl.lparams.clone(), stats.levels),
510        };
511        let rec_names: Vec<NameId> = types.iter().map(|t| self.rec_name(t.name)).collect();
512        let mut minor_idx = 0usize;
513        for (d, it) in types.iter().enumerate() {
514            let info = &rec_infos[d];
515            let mut binders = stats.params.clone();
516            binders.extend(&motives);
517            binders.extend(&minors);
518            binders.extend(&info.indices);
519            binders.push(info.major);
520            let mi = self.s.mk_app_n(info.motive, &info.indices);
521            let concl = self.s.app(mi, info.major);
522            let ty = self.mk_pi(&binders, concl);
523            let rules = self.mk_rec_rules(
524                &stats,
525                types,
526                &rec_names,
527                rec_levels,
528                d,
529                &motives,
530                &minors,
531                &mut minor_idx,
532            )?;
533            let name = rec_names[d];
534            self.check_name(name, allow_primitive)?;
535            let major_induct = it.name;
536            out.push(Const {
537                name,
538                lparams: rec_lparams.clone(),
539                ty,
540                kind: Kind::Rec(RecInfo {
541                    all: all.clone(),
542                    num_params: nparams as u32,
543                    num_indices: stats.nindices[d],
544                    num_motives: motives.len() as u32,
545                    num_minors: minors.len() as u32,
546                    rules: rules.into(),
547                    k,
548                    is_unsafe,
549                    major_induct,
550                }),
551            });
552        }
553        Ok(out)
554    }
555
556    /// `isRec` (`reflexive = false`) and `isReflexive` (`reflexive = true`), read off the
557    /// constructor types syntactically as Lean does.
558    fn syntactic_occurrence(&self, types: &[IndType], names: &[NameId], reflexive: bool) -> bool {
559        types.iter().any(|t| {
560            t.ctors.iter().any(|(_, cty)| {
561                let mut e = *cty;
562                while let Node::Pi(dom, body) = self.s.node(e) {
563                    let occ = self.has_ind_occ(names, dom);
564                    if occ && (!reflexive || matches!(self.s.node(dom), Node::Pi(..))) {
565                        return true;
566                    }
567                    e = body;
568                }
569                false
570            })
571        })
572    }
573
574    fn is_valid_ind_app_idx(&self, stats: &Stats, t: ExprId, i: usize) -> bool {
575        let (head, args) = self.s.app_args(t);
576        if head != stats.ind_consts[i]
577            || args.len() != stats.params.len() + stats.nindices[i] as usize
578        {
579            return false;
580        }
581        if args.iter().zip(&stats.params).any(|(a, p)| a != p) {
582            return false;
583        }
584        !args[stats.params.len()..]
585            .iter()
586            .any(|a| self.has_ind_occ(&stats.ind_names, *a))
587    }
588
589    fn is_valid_ind_app(&self, stats: &Stats, t: ExprId) -> Option<usize> {
590        (0..stats.ind_consts.len()).find(|i| self.is_valid_ind_app_idx(stats, t, *i))
591    }
592
593    fn is_rec_arg(&mut self, stats: &Stats, mut t: ExprId) -> KResult<Option<usize>> {
594        loop {
595            t = self.whnf(t)?;
596            let Node::Pi(dom, body) = self.s.node(t) else {
597                return Ok(self.is_valid_ind_app(stats, t));
598            };
599            let ty = self.consume_type_annotations(dom);
600            let a = self.push_local(ty, None);
601            t = self.s.instantiate1(body, a);
602        }
603    }
604
605    fn check_positivity(
606        &mut self,
607        stats: &Stats,
608        mut t: ExprId,
609        ctor: NameId,
610        idx: usize,
611    ) -> KResult<()> {
612        loop {
613            t = self.whnf(t)?;
614            if !self.has_ind_occ(&stats.ind_names, t) {
615                return Ok(());
616            }
617            if let Node::Pi(dom, body) = self.s.node(t) {
618                if self.has_ind_occ(&stats.ind_names, dom) {
619                    return Err(reject(format!(
620                        "arg #{} of '{}' has a non positive occurrence of the datatypes being declared",
621                        idx + 1,
622                        self.s.names.display(ctor)
623                    )));
624                }
625                let ty = self.consume_type_annotations(dom);
626                let a = self.push_local(ty, None);
627                t = self.s.instantiate1(body, a);
628            } else if self.is_valid_ind_app(stats, t).is_none() {
629                return Err(reject(format!(
630                    "arg #{} of '{}' has a non valid occurrence of the datatypes being declared",
631                    idx + 1,
632                    self.s.names.display(ctor)
633                )));
634            } else {
635                return Ok(());
636            }
637        }
638    }
639
640    fn is_large_eliminator(&mut self, stats: &Stats, types: &[IndType]) -> KResult<bool> {
641        if stats.is_not_zero {
642            return Ok(true);
643        }
644        if types.len() != 1 {
645            return Ok(false);
646        }
647        match types[0].ctors.len() {
648            0 => Ok(true),
649            1 => {
650                let mut t = types[0].ctors[0].1;
651                let mut i = 0;
652                let mut to_check = Vec::new();
653                while let Node::Pi(dom, body) = self.s.node(t) {
654                    let ty = self.consume_type_annotations(dom);
655                    let a = self.push_local(ty, None);
656                    if i >= stats.params.len() {
657                        let dt = self.infer(dom, true)?;
658                        let s = self.ensure_sort(dt)?;
659                        let sl = self.sort_level(s);
660                        if !self.s.levels.is_always_zero(sl) {
661                            to_check.push(a);
662                        }
663                    }
664                    t = self.s.instantiate1(body, a);
665                    i += 1;
666                }
667                let (_, args) = self.s.app_args(t);
668                Ok(to_check.iter().all(|a| args.contains(a)))
669            }
670            _ => Ok(false),
671        }
672    }
673
674    fn get_elim_level(
675        &mut self,
676        stats: &Stats,
677        types: &[IndType],
678        lparams: &[NameId],
679    ) -> KResult<LevelId> {
680        if !self.is_large_eliminator(stats, types)? {
681            return Ok(LevelId::ZERO);
682        }
683        let mut u = self.wk.u;
684        let mut i = 1;
685        while lparams.contains(&u) {
686            u = self.s.names.append_index_after(self.wk.u, i);
687            i += 1;
688        }
689        Ok(self.s.levels.param(u))
690    }
691
692    fn is_k_target(&mut self, stats: &Stats, types: &[IndType]) -> bool {
693        if types.len() != 1
694            || !self.s.levels.is_always_zero(stats.result_level)
695            || types[0].ctors.len() != 1
696        {
697            return false;
698        }
699        let mut t = types[0].ctors[0].1;
700        let mut i = 0;
701        while let Node::Pi(_, b) = self.s.node(t) {
702            if i >= stats.params.len() {
703                return false;
704            }
705            i += 1;
706            t = b;
707        }
708        true
709    }
710
711    fn mk_rec_infos(
712        &mut self,
713        stats: &Stats,
714        types: &[IndType],
715        elim_level: LevelId,
716    ) -> KResult<Vec<RecTmp>> {
717        let mut infos = Vec::new();
718        for (d, it) in types.iter().enumerate() {
719            let mut t = self.whnf(it.ty)?;
720            let mut i = 0;
721            let mut indices = Vec::new();
722            while let Node::Pi(dom, body) = self.s.node(t) {
723                if i < stats.params.len() {
724                    let b = self.s.instantiate1(body, stats.params[i]);
725                    t = self.whnf(b)?;
726                    i += 1;
727                } else {
728                    let ty = self.consume_type_annotations(dom);
729                    let a = self.push_local(ty, None);
730                    indices.push(a);
731                    let b = self.s.instantiate1(body, a);
732                    t = self.whnf(b)?;
733                }
734            }
735            let tp = self.s.mk_app_n(stats.ind_consts[d], &stats.params);
736            let t_ty = self.s.mk_app_n(tp, &indices);
737            let t_ty = self.consume_type_annotations(t_ty);
738            let major = self.push_local(t_ty, None);
739            let sort = self.s.sort(elim_level);
740            let mut bs = indices.clone();
741            bs.push(major);
742            let motive_ty = self.mk_pi(&bs, sort);
743            let motive_ty = self.consume_type_annotations(motive_ty);
744            let motive = self.push_local(motive_ty, None);
745            infos.push(RecTmp {
746                motive,
747                minors: Vec::new(),
748                indices,
749                major,
750            });
751        }
752        for (d, it) in types.iter().enumerate() {
753            for (cn, cty) in &it.ctors {
754                let (t, bu, u) = self.loop_ctor_args(stats, *cty)?;
755                let (it_idx, it_indices) = self.get_i_indices(stats, t)?;
756                let c = self.s.cnst(*cn, stats.levels);
757                let cp = self.s.mk_app_n(c, &stats.params);
758                let intro = self.s.mk_app_n(cp, &bu);
759                let mi = self.s.mk_app_n(infos[it_idx].motive, &it_indices);
760                let motive_app = self.s.app(mi, intro);
761                let mut v = Vec::new();
762                for ui in &u {
763                    let (ui_ty, xs) = self.loop_u_args(*ui)?;
764                    let (j, j_indices) = self.get_i_indices(stats, ui_ty)?;
765                    let mj = self.s.mk_app_n(infos[j].motive, &j_indices);
766                    let uxs = self.s.mk_app_n(*ui, &xs);
767                    let body = self.s.app(mj, uxs);
768                    let vi_ty = self.mk_pi(&xs, body);
769                    let vi_ty = self.consume_type_annotations(vi_ty);
770                    v.push(self.push_local(vi_ty, None));
771                }
772                let mut bs = bu.clone();
773                bs.extend(&v);
774                let minor_ty = self.mk_pi(&bs, motive_app);
775                let minor_ty = self.consume_type_annotations(minor_ty);
776                let minor = self.push_local(minor_ty, None);
777                infos[d].minors.push(minor);
778            }
779        }
780        Ok(infos)
781    }
782
783    /// The constructor's result type, its field locals, and the fields that are recursive.
784    fn loop_ctor_args(
785        &mut self,
786        stats: &Stats,
787        mut t: ExprId,
788    ) -> KResult<(ExprId, Vec<ExprId>, Vec<ExprId>)> {
789        let mut i = 0;
790        let mut bu = Vec::new();
791        let mut u = Vec::new();
792        while let Node::Pi(dom, body) = self.s.node(t) {
793            if i < stats.params.len() {
794                t = self.s.instantiate1(body, stats.params[i]);
795            } else {
796                let ty = self.consume_type_annotations(dom);
797                let a = self.push_local(ty, None);
798                bu.push(a);
799                if self.is_rec_arg(stats, dom)?.is_some() {
800                    u.push(a);
801                }
802                t = self.s.instantiate1(body, a);
803            }
804            i += 1;
805        }
806        Ok((t, bu, u))
807    }
808
809    fn loop_u_args(&mut self, ui: ExprId) -> KResult<(ExprId, Vec<ExprId>)> {
810        let ut = self.infer(ui, true)?;
811        let mut t = self.whnf(ut)?;
812        let mut xs = Vec::new();
813        while let Node::Pi(dom, body) = self.s.node(t) {
814            let ty = self.consume_type_annotations(dom);
815            let x = self.push_local(ty, None);
816            xs.push(x);
817            let b = self.s.instantiate1(body, x);
818            t = self.whnf(b)?;
819        }
820        Ok((t, xs))
821    }
822
823    fn get_i_indices(&self, stats: &Stats, t: ExprId) -> KResult<(usize, Vec<ExprId>)> {
824        let idx = self
825            .is_valid_ind_app(stats, t)
826            .ok_or_else(|| reject("ill-formed recursive occurrence"))?;
827        let (_, args) = self.s.app_args(t);
828        Ok((idx, args[stats.params.len()..].to_vec()))
829    }
830
831    #[allow(clippy::too_many_arguments)]
832    fn mk_rec_rules(
833        &mut self,
834        stats: &Stats,
835        types: &[IndType],
836        rec_names: &[NameId],
837        rec_levels: LevelsId,
838        d: usize,
839        motives: &[ExprId],
840        minors: &[ExprId],
841        minor_idx: &mut usize,
842    ) -> KResult<Vec<RecRule>> {
843        let mut rules = Vec::new();
844        for (cn, cty) in &types[d].ctors {
845            let (_, bu, u) = self.loop_ctor_args(stats, *cty)?;
846            let mut v = Vec::new();
847            for ui in &u {
848                let (ui_ty, xs) = self.loop_u_args(*ui)?;
849                let (j, j_indices) = self.get_i_indices(stats, ui_ty)?;
850                let rc = self.s.cnst(rec_names[j], rec_levels);
851                let mut val = self.s.mk_app_n(rc, &stats.params);
852                val = self.s.mk_app_n(val, motives);
853                val = self.s.mk_app_n(val, minors);
854                val = self.s.mk_app_n(val, &j_indices);
855                let uxs = self.s.mk_app_n(*ui, &xs);
856                let body = self.s.app(val, uxs);
857                v.push(self.mk_lambda(&xs, body));
858            }
859            let m = self.s.mk_app_n(minors[*minor_idx], &bu);
860            let m = self.s.mk_app_n(m, &v);
861            let mut bs = stats.params.clone();
862            bs.extend(motives);
863            bs.extend(minors);
864            bs.extend(&bu);
865            let rhs = self.mk_lambda(&bs, m);
866            rules.push(RecRule {
867                ctor: *cn,
868                nfields: bu.len() as u32,
869                rhs,
870            });
871            *minor_idx += 1;
872        }
873        Ok(rules)
874    }
875
876    // ---- ElimNestedInductive ----
877
878    fn with_params(&mut self, mut e: ExprId, n: usize) -> KResult<(Vec<ExprId>, ExprId)> {
879        let mut ps = Vec::new();
880        for _ in 0..n {
881            let Node::Pi(d, b) = self.s.node(e) else {
882                return Err(reject(
883                    "invalid inductive datatype declaration, incorrect number of parameters",
884                ));
885            };
886            let p = self.push_local(d, None);
887            ps.push(p);
888            e = self.s.instantiate1(b, p);
889        }
890        Ok((ps, e))
891    }
892
893    fn replace_params(&mut self, params: &[ExprId], e: ExprId, as_: &[ExprId]) -> ExprId {
894        let idx: Vec<u32> = as_.iter().map(|a| self.fvar_index(*a)).collect();
895        let abs = self.s.abstract_fvars(e, &idx);
896        self.s.instantiate_rev(abs, params)
897    }
898
899    fn instantiate_forall_params(
900        &mut self,
901        mut e: ExprId,
902        hi: usize,
903        args: &[ExprId],
904    ) -> KResult<ExprId> {
905        for _ in 0..hi {
906            let Node::Pi(_, b) = self.s.node(e) else {
907                return Err(reject(
908                    "invalid nested inductive datatype, ill-formed declaration",
909                ));
910            };
911            e = b;
912        }
913        Ok(self.s.instantiate_rev(e, &args[..hi]))
914    }
915
916    fn elim_nested(&mut self, decl: &InductiveDecl) -> KResult<Nested> {
917        let nparams = decl.nparams as usize;
918        let (params, _) = self.with_params(decl.types[0].ty, nparams)?;
919        let lvls = self.const_levels_of(&decl.lparams);
920        let mut st = NestState {
921            new_types: decl.types.clone(),
922            nested_aux: Vec::new(),
923            next_idx: 1,
924            lvls,
925        };
926        let mut i = 0;
927        while i < st.new_types.len() {
928            let ctors = st.new_types[i].ctors.clone();
929            let mut new_ctors = Vec::with_capacity(ctors.len());
930            for (cn, cty) in ctors {
931                let (as_, body) = self.with_params(cty, nparams)?;
932                let mut memo = FxMap::default();
933                let replaced = self.replace_all_nested(&params, &as_, body, &mut st, &mut memo)?;
934                new_ctors.push((cn, self.mk_pi(&as_, replaced)));
935            }
936            st.new_types[i].ctors = new_ctors;
937            i += 1;
938        }
939        let aux2nested = st.nested_aux.iter().map(|(e, n)| (*n, *e)).collect();
940        Ok(Nested {
941            params,
942            aux2nested,
943            types: st.new_types,
944        })
945    }
946
947    fn replace_all_nested(
948        &mut self,
949        params: &[ExprId],
950        as_: &[ExprId],
951        e: ExprId,
952        st: &mut NestState,
953        memo: &mut FxMap<ExprId, ExprId>,
954    ) -> KResult<ExprId> {
955        if let Some(r) = memo.get(&e) {
956            return Ok(*r);
957        }
958        let r = if let Some(r) = self.replace_if_nested(params, as_, e, st)? {
959            r
960        } else {
961            match self.s.node(e) {
962                Node::App(f, a) => {
963                    let f2 = self.replace_all_nested(params, as_, f, st, memo)?;
964                    let a2 = self.replace_all_nested(params, as_, a, st, memo)?;
965                    self.s.app(f2, a2)
966                }
967                Node::Lam(t, b) => {
968                    let t2 = self.replace_all_nested(params, as_, t, st, memo)?;
969                    let b2 = self.replace_all_nested(params, as_, b, st, memo)?;
970                    self.s.lam(t2, b2)
971                }
972                Node::Pi(t, b) => {
973                    let t2 = self.replace_all_nested(params, as_, t, st, memo)?;
974                    let b2 = self.replace_all_nested(params, as_, b, st, memo)?;
975                    self.s.pi(t2, b2)
976                }
977                Node::Let(t, v, b) => {
978                    let t2 = self.replace_all_nested(params, as_, t, st, memo)?;
979                    let v2 = self.replace_all_nested(params, as_, v, st, memo)?;
980                    let b2 = self.replace_all_nested(params, as_, b, st, memo)?;
981                    self.s.let_(t2, v2, b2)
982                }
983                Node::Proj(n, i, x) => {
984                    let x2 = self.replace_all_nested(params, as_, x, st, memo)?;
985                    self.s.proj(n, i, x2)
986                }
987                _ => e,
988            }
989        };
990        memo.insert(e, r);
991        Ok(r)
992    }
993
994    fn replace_if_nested(
995        &mut self,
996        params: &[ExprId],
997        as_: &[ExprId],
998        e: ExprId,
999        st: &mut NestState,
1000    ) -> KResult<Option<ExprId>> {
1001        if !matches!(self.s.node(e), Node::App(..)) {
1002            return Ok(None);
1003        }
1004        let (head, args) = self.s.app_args(e);
1005        let Node::Const(fname, i_lvls) = self.s.node(head) else {
1006            return Ok(None);
1007        };
1008        let Some(i_val) = self.env.inductive(fname).cloned() else {
1009            return Ok(None);
1010        };
1011        let i_np = i_val.num_params as usize;
1012        if i_np > args.len() {
1013            return Ok(None);
1014        }
1015        let new_names: Vec<NameId> = st.new_types.iter().map(|t| t.name).collect();
1016        let mut is_nested = false;
1017        let mut loose = false;
1018        for a in &args[..i_np] {
1019            if self.s.has_loose_bvars(*a) {
1020                loose = true;
1021            }
1022            if self.s.mentions_const(*a, &new_names) {
1023                is_nested = true;
1024            }
1025        }
1026        if !is_nested {
1027            return Ok(None);
1028        }
1029        if loose {
1030            return Err(reject(format!(
1031                "invalid nested inductive datatype '{}', nested inductive datatypes parameters cannot contain local variables",
1032                self.s.names.display(fname)
1033            )));
1034        }
1035        let i_as = self.s.mk_app_n(head, &args[..i_np]);
1036        let i_params = self.replace_params(params, i_as, as_);
1037        if let Some((_, aux)) = st.nested_aux.iter().find(|(x, _)| *x == i_params) {
1038            let c = self.s.cnst(*aux, st.lvls);
1039            let ca = self.s.mk_app_n(c, as_);
1040            return Ok(Some(self.s.mk_app_n(ca, &args[i_np..])));
1041        }
1042        let mut result = None;
1043        let i_lvl_list = self.s.levels.get_list(i_lvls).to_vec();
1044        for &j_name in i_val.all.iter() {
1045            let j_const = self.get_const(j_name)?;
1046            let Some(j_info) = self.env.inductive(j_name).cloned() else {
1047                return Err(reject(
1048                    "nested inductive refers to a non-inductive in its block",
1049                ));
1050            };
1051            let j = self.s.cnst(j_name, i_lvls);
1052            let j_as = self.s.mk_app_n(j, &args[..i_np]);
1053            let base = self.s.names.append(self.wk.nested_prefix, j_name);
1054            let aux_j = self.mk_unique_name(base, st);
1055            let aux_ty = self
1056                .s
1057                .instantiate_lparams(j_const.ty, &j_const.lparams, &i_lvl_list);
1058            let aux_ty = self.instantiate_forall_params(aux_ty, i_np, &args)?;
1059            let aux_ty = self.mk_pi(as_, aux_ty);
1060            let j_as2 = self.replace_params(params, j_as, as_);
1061            st.nested_aux.push((j_as2, aux_j));
1062            if j_name == fname {
1063                let c = self.s.cnst(aux_j, st.lvls);
1064                let ca = self.s.mk_app_n(c, as_);
1065                result = Some(self.s.mk_app_n(ca, &args[i_np..]));
1066            }
1067            let mut ctors = Vec::new();
1068            for &jc in j_info.ctors.iter() {
1069                let jc_const = self.get_const(jc)?;
1070                let name = self.s.names.replace_prefix(jc, j_name, aux_j);
1071                let t = self
1072                    .s
1073                    .instantiate_lparams(jc_const.ty, &jc_const.lparams, &i_lvl_list);
1074                let t = self.instantiate_forall_params(t, i_np, &args)?;
1075                ctors.push((name, self.mk_pi(as_, t)));
1076            }
1077            st.new_types.push(IndType {
1078                name: aux_j,
1079                ty: aux_ty,
1080                ctors,
1081            });
1082        }
1083        result
1084            .map(Some)
1085            .ok_or_else(|| reject("nested inductive datatype is not in its own block"))
1086    }
1087
1088    fn mk_unique_name(&mut self, base: NameId, st: &mut NestState) -> NameId {
1089        let mut i = st.next_idx;
1090        loop {
1091            let r = self.s.names.append_index_after(base, i);
1092            if !self.env.contains(r) {
1093                st.next_idx = i + 1;
1094                return r;
1095            }
1096            i += 1;
1097        }
1098    }
1099
1100    fn restore_nested(
1101        &mut self,
1102        decl: &InductiveDecl,
1103        nested: &Nested,
1104        generated: Vec<Const>,
1105    ) -> KResult<Vec<Const>> {
1106        let nparams = decl.nparams as usize;
1107        let ntypes = decl.types.len();
1108        let main = decl.types[0].name;
1109        let Some(Kind::Induct(main_info)) = generated
1110            .iter()
1111            .find(|c| c.name == main)
1112            .map(|c| c.kind.clone())
1113        else {
1114            return Err(reject("nested elaboration lost the main inductive"));
1115        };
1116        let all_orig: Rc<[NameId]> = decl.types.iter().map(|t| t.name).collect::<Vec<_>>().into();
1117        let main_rec = self.rec_name(main);
1118        let mut rec_map: Vec<(NameId, NameId)> = Vec::new();
1119        for (i, &ind) in main_info.all.iter().skip(ntypes).enumerate() {
1120            let old = self.rec_name(ind);
1121            let new = self.s.names.append_index_after(main_rec, i as u64 + 1);
1122            rec_map.push((old, new));
1123        }
1124        let aux_of: FxMap<NameId, ExprId> = nested.aux2nested.iter().copied().collect();
1125        let param_idx: Vec<u32> = nested.params.iter().map(|p| self.fvar_index(*p)).collect();
1126        let gen_by: FxMap<NameId, Const> = generated.iter().map(|c| (c.name, c.clone())).collect();
1127        let mut out = Vec::new();
1128        let process_rec = |k: &mut Kernel, rec: NameId, out: &mut Vec<Const>| -> KResult<()> {
1129            let new_name = rec_map
1130                .iter()
1131                .find(|(o, _)| *o == rec)
1132                .map_or(rec, |(_, n)| *n);
1133            let g = gen_by
1134                .get(&rec)
1135                .ok_or_else(|| reject("missing generated recursor"))?
1136                .clone();
1137            let Kind::Rec(info) = &g.kind else {
1138                unreachable!()
1139            };
1140            let ty =
1141                k.restore_expr(g.ty, nparams, &nested.params, &param_idx, &aux_of, &rec_map)?;
1142            let mut rules = Vec::new();
1143            for r in info.rules.iter() {
1144                let rhs = k.restore_expr(
1145                    r.rhs,
1146                    nparams,
1147                    &nested.params,
1148                    &param_idx,
1149                    &aux_of,
1150                    &rec_map,
1151                )?;
1152                let ctor = if new_name == rec {
1153                    r.ctor
1154                } else {
1155                    k.restore_ctor_name(r.ctor, &aux_of, &param_idx, &nested.params)?
1156                };
1157                rules.push(RecRule {
1158                    ctor,
1159                    nfields: r.nfields,
1160                    rhs,
1161                });
1162            }
1163            let major_induct = k.major_induct_of(ty, info.major_idx())?;
1164            out.push(Const {
1165                name: new_name,
1166                lparams: g.lparams.clone(),
1167                ty,
1168                kind: Kind::Rec(RecInfo {
1169                    all: all_orig.clone(),
1170                    rules: rules.into(),
1171                    major_induct,
1172                    ..info.clone()
1173                }),
1174            });
1175            Ok(())
1176        };
1177        for t in &decl.types {
1178            let g = gen_by
1179                .get(&t.name)
1180                .ok_or_else(|| reject("missing generated inductive"))?
1181                .clone();
1182            let Kind::Induct(info) = &g.kind else {
1183                unreachable!()
1184            };
1185            out.push(Const {
1186                kind: Kind::Induct(InductiveInfo {
1187                    all: all_orig.clone(),
1188                    ..info.clone()
1189                }),
1190                ..g.clone()
1191            });
1192            for &cn in info.ctors.iter() {
1193                let gc = gen_by
1194                    .get(&cn)
1195                    .ok_or_else(|| reject("missing generated constructor"))?
1196                    .clone();
1197                let ty =
1198                    self.restore_expr(gc.ty, nparams, &nested.params, &param_idx, &aux_of, &[])?;
1199                out.push(Const { ty, ..gc });
1200            }
1201            let r = self.rec_name(t.name);
1202            process_rec(self, r, &mut out)?;
1203        }
1204        for (old, _) in rec_map.clone() {
1205            process_rec(self, old, &mut out)?;
1206        }
1207        for (_, e) in &nested.aux2nested {
1208            self.check(*e)?;
1209        }
1210        Ok(out)
1211    }
1212
1213    fn major_induct_of(&self, mut ty: ExprId, major_idx: usize) -> KResult<NameId> {
1214        for _ in 0..major_idx {
1215            let Node::Pi(_, b) = self.s.node(ty) else {
1216                return Err(reject("ill-formed recursor type"));
1217            };
1218            ty = b;
1219        }
1220        let Node::Pi(dom, _) = self.s.node(ty) else {
1221            return Err(reject("ill-formed recursor type"));
1222        };
1223        self.s
1224            .const_head(dom)
1225            .map(|(n, _)| n)
1226            .ok_or_else(|| reject("ill-formed recursor major premise"))
1227    }
1228
1229    fn nested_of_aux_ctor(
1230        &self,
1231        c: NameId,
1232        aux_of: &FxMap<NameId, ExprId>,
1233    ) -> Option<(ExprId, NameId)> {
1234        let ci = self.env.ctor(c)?;
1235        aux_of.get(&ci.induct).map(|e| (*e, ci.induct))
1236    }
1237
1238    fn restore_ctor_name(
1239        &mut self,
1240        c: NameId,
1241        aux_of: &FxMap<NameId, ExprId>,
1242        _param_idx: &[u32],
1243        _params: &[ExprId],
1244    ) -> KResult<NameId> {
1245        let (nested, aux_name) = self
1246            .nested_of_aux_ctor(c, aux_of)
1247            .ok_or_else(|| reject("unknown auxiliary constructor"))?;
1248        let (i, _) = self
1249            .s
1250            .const_head(nested)
1251            .ok_or_else(|| reject("ill-formed nested occurrence"))?;
1252        Ok(self.s.names.replace_prefix(c, aux_name, i))
1253    }
1254
1255    #[allow(clippy::too_many_arguments)]
1256    fn restore_expr(
1257        &mut self,
1258        mut e: ExprId,
1259        nparams: usize,
1260        params: &[ExprId],
1261        param_idx: &[u32],
1262        aux_of: &FxMap<NameId, ExprId>,
1263        rec_map: &[(NameId, NameId)],
1264    ) -> KResult<ExprId> {
1265        let pi = matches!(self.s.node(e), Node::Pi(..));
1266        let mut as_ = Vec::new();
1267        for _ in 0..nparams {
1268            match self.s.node(e) {
1269                Node::Pi(d, b) | Node::Lam(d, b) => {
1270                    let a = self.push_local(d, None);
1271                    as_.push(a);
1272                    e = self.s.instantiate1(b, a);
1273                }
1274                _ => return Err(reject("ill-formed nested inductive expression")),
1275            }
1276        }
1277        let _ = params;
1278        let mut memo = FxMap::default();
1279        let r = self.restore_go(e, nparams, param_idx, &as_, aux_of, rec_map, &mut memo)?;
1280        Ok(if pi {
1281            self.mk_pi(&as_, r)
1282        } else {
1283            self.mk_lambda(&as_, r)
1284        })
1285    }
1286
1287    #[allow(clippy::too_many_arguments)]
1288    fn restore_go(
1289        &mut self,
1290        t: ExprId,
1291        nparams: usize,
1292        param_idx: &[u32],
1293        as_: &[ExprId],
1294        aux_of: &FxMap<NameId, ExprId>,
1295        rec_map: &[(NameId, NameId)],
1296        memo: &mut FxMap<ExprId, ExprId>,
1297    ) -> KResult<ExprId> {
1298        if let Some(r) = memo.get(&t) {
1299            return Ok(*r);
1300        }
1301        let replaced = 'rep: {
1302            if let Node::Const(c, ls) = self.s.node(t) {
1303                if let Some((_, n)) = rec_map.iter().find(|(o, _)| *o == c) {
1304                    break 'rep Some(self.s.cnst(*n, ls));
1305                }
1306            }
1307            let (head, args) = self.s.app_args(t);
1308            let Node::Const(c, _) = self.s.node(head) else {
1309                break 'rep None;
1310            };
1311            if let Some(nested) = aux_of.get(&c).copied() {
1312                if args.len() < nparams {
1313                    return Err(reject("ill-formed nested occurrence"));
1314                }
1315                let abs = self.s.abstract_fvars(nested, param_idx);
1316                let inst = self.s.instantiate_rev(abs, as_);
1317                break 'rep Some(self.s.mk_app_n(inst, &args[nparams..]));
1318            }
1319            if let Some((nested, aux_name)) = self.nested_of_aux_ctor(c, aux_of) {
1320                if args.len() < nparams {
1321                    return Err(reject("ill-formed nested constructor occurrence"));
1322                }
1323                let abs = self.s.abstract_fvars(nested, param_idx);
1324                let inst = self.s.instantiate_rev(abs, as_);
1325                let (ih, i_args) = self.s.app_args(inst);
1326                let Node::Const(i_c, i_ls) = self.s.node(ih) else {
1327                    return Err(reject("ill-formed nested occurrence"));
1328                };
1329                let new_c = self.s.names.replace_prefix(c, aux_name, i_c);
1330                let cc = self.s.cnst(new_c, i_ls);
1331                let ci = self.s.mk_app_n(cc, &i_args);
1332                break 'rep Some(self.s.mk_app_n(ci, &args[nparams..]));
1333            }
1334            None
1335        };
1336        let r = match replaced {
1337            Some(r) => r,
1338            None => match self.s.node(t) {
1339                Node::App(f, a) => {
1340                    let f2 = self.restore_go(f, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1341                    let a2 = self.restore_go(a, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1342                    self.s.app(f2, a2)
1343                }
1344                Node::Lam(d, b) => {
1345                    let d2 = self.restore_go(d, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1346                    let b2 = self.restore_go(b, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1347                    self.s.lam(d2, b2)
1348                }
1349                Node::Pi(d, b) => {
1350                    let d2 = self.restore_go(d, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1351                    let b2 = self.restore_go(b, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1352                    self.s.pi(d2, b2)
1353                }
1354                Node::Let(ty, v, b) => {
1355                    let t2 = self.restore_go(ty, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1356                    let v2 = self.restore_go(v, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1357                    let b2 = self.restore_go(b, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1358                    self.s.let_(t2, v2, b2)
1359                }
1360                Node::Proj(n, i, x) => {
1361                    let x2 = self.restore_go(x, nparams, param_idx, as_, aux_of, rec_map, memo)?;
1362                    self.s.proj(n, i, x2)
1363                }
1364                _ => t,
1365            },
1366        };
1367        memo.insert(t, r);
1368        Ok(r)
1369    }
1370}