Skip to main content

oxilean_kernel/inductive/
types.rs

1//! Auto-generated module
2//!
3//! 🤖 Generated with [SplitRS](https://github.com/cool-japan/splitrs)
4
5use super::functions::*;
6use crate::declaration::{
7    ConstantInfo, ConstantVal, ConstructorVal, InductiveVal, RecursorRule, RecursorVal,
8};
9use crate::{Expr, KernelError, Level, Name};
10use std::collections::HashMap;
11
12/// A generic counter that tracks min/max/sum for statistical summaries.
13#[allow(dead_code)]
14pub struct StatSummary {
15    count: u64,
16    sum: f64,
17    min: f64,
18    max: f64,
19}
20#[allow(dead_code)]
21impl StatSummary {
22    /// Creates an empty summary.
23    pub fn new() -> Self {
24        Self {
25            count: 0,
26            sum: 0.0,
27            min: f64::INFINITY,
28            max: f64::NEG_INFINITY,
29        }
30    }
31    /// Records a sample.
32    pub fn record(&mut self, val: f64) {
33        self.count += 1;
34        self.sum += val;
35        if val < self.min {
36            self.min = val;
37        }
38        if val > self.max {
39            self.max = val;
40        }
41    }
42    /// Returns the mean, or `None` if no samples.
43    pub fn mean(&self) -> Option<f64> {
44        if self.count == 0 {
45            None
46        } else {
47            Some(self.sum / self.count as f64)
48        }
49    }
50    /// Returns the minimum, or `None` if no samples.
51    pub fn min(&self) -> Option<f64> {
52        if self.count == 0 {
53            None
54        } else {
55            Some(self.min)
56        }
57    }
58    /// Returns the maximum, or `None` if no samples.
59    pub fn max(&self) -> Option<f64> {
60        if self.count == 0 {
61            None
62        } else {
63            Some(self.max)
64        }
65    }
66    /// Returns the count of recorded samples.
67    pub fn count(&self) -> u64 {
68        self.count
69    }
70}
71/// Errors that can occur when checking an inductive type definition.
72#[derive(Clone, Debug, PartialEq)]
73pub enum InductiveError {
74    /// The type name is already defined.
75    AlreadyDefined(Name),
76    /// A constructor references a type that is not in scope.
77    UndefinedType(Name),
78    /// A constructor has an invalid type (not a Pi ending in the inductive type).
79    InvalidConstructorType(Name),
80    /// The universe level is not large enough.
81    UniverseTooSmall(String),
82    /// A non-strictly positive occurrence of the type.
83    NonStrictlyPositive(Name),
84    /// General error.
85    Other(String),
86}
87/// An introduction rule (constructor) for an inductive type.
88#[derive(Clone, Debug, PartialEq)]
89pub struct IntroRule {
90    /// Constructor name
91    pub name: Name,
92    /// Constructor type (as a Pi-type)
93    pub ty: Expr,
94}
95/// A mutually inductive family of types.
96///
97/// Lean 4 supports mutual induction (e.g., `Even` and `Odd` defined together).
98/// This struct holds a group of inductive types that are checked together.
99#[derive(Clone, Debug)]
100pub struct InductiveFamily {
101    /// The inductive types in the family.
102    pub types: Vec<InductiveType>,
103    /// Shared universe parameters.
104    pub univ_params: Vec<Name>,
105}
106impl InductiveFamily {
107    /// Create a single-type family.
108    pub fn singleton(ty: InductiveType) -> Self {
109        let univ_params = ty.univ_params.clone();
110        Self {
111            types: vec![ty],
112            univ_params,
113        }
114    }
115    /// Create a mutually inductive family.
116    pub fn new(types: Vec<InductiveType>, univ_params: Vec<Name>) -> Self {
117        Self { types, univ_params }
118    }
119    /// Number of types in the family.
120    pub fn len(&self) -> usize {
121        self.types.len()
122    }
123    /// Whether the family contains a single type.
124    pub fn is_singleton(&self) -> bool {
125        self.types.len() == 1
126    }
127    /// Whether the family is empty.
128    pub fn is_empty(&self) -> bool {
129        self.types.is_empty()
130    }
131    /// All type names in the family.
132    pub fn type_names(&self) -> Vec<&Name> {
133        self.types.iter().map(|t| &t.name).collect()
134    }
135    /// All constructor names across all types.
136    pub fn all_constructor_names(&self) -> Vec<&Name> {
137        self.types
138            .iter()
139            .flat_map(|t| t.intro_rules.iter().map(|r| &r.name))
140            .collect()
141    }
142    /// Find a type by name.
143    pub fn find_type(&self, name: &Name) -> Option<&InductiveType> {
144        self.types.iter().find(|t| &t.name == name)
145    }
146    /// Total number of constructors across all types.
147    pub fn total_constructors(&self) -> usize {
148        self.types.iter().map(|t| t.intro_rules.len()).sum()
149    }
150}
151/// A simple key-value store backed by a sorted Vec for small maps.
152#[allow(dead_code)]
153pub struct SmallMap<K: Ord + Clone, V: Clone> {
154    entries: Vec<(K, V)>,
155}
156#[allow(dead_code)]
157impl<K: Ord + Clone, V: Clone> SmallMap<K, V> {
158    /// Creates a new empty small map.
159    pub fn new() -> Self {
160        Self {
161            entries: Vec::new(),
162        }
163    }
164    /// Inserts or replaces the value for `key`.
165    pub fn insert(&mut self, key: K, val: V) {
166        match self.entries.binary_search_by_key(&&key, |(k, _)| k) {
167            Ok(i) => self.entries[i].1 = val,
168            Err(i) => self.entries.insert(i, (key, val)),
169        }
170    }
171    /// Returns the value for `key`, or `None`.
172    pub fn get(&self, key: &K) -> Option<&V> {
173        self.entries
174            .binary_search_by_key(&key, |(k, _)| k)
175            .ok()
176            .map(|i| &self.entries[i].1)
177    }
178    /// Returns the number of entries.
179    pub fn len(&self) -> usize {
180        self.entries.len()
181    }
182    /// Returns `true` if empty.
183    pub fn is_empty(&self) -> bool {
184        self.entries.is_empty()
185    }
186    /// Returns all keys.
187    pub fn keys(&self) -> Vec<&K> {
188        self.entries.iter().map(|(k, _)| k).collect()
189    }
190    /// Returns all values.
191    pub fn values(&self) -> Vec<&V> {
192        self.entries.iter().map(|(_, v)| v).collect()
193    }
194}
195/// A hierarchical configuration tree.
196#[allow(dead_code)]
197pub struct ConfigNode {
198    key: String,
199    value: Option<String>,
200    children: Vec<ConfigNode>,
201}
202#[allow(dead_code)]
203impl ConfigNode {
204    /// Creates a leaf config node with a value.
205    pub fn leaf(key: impl Into<String>, value: impl Into<String>) -> Self {
206        Self {
207            key: key.into(),
208            value: Some(value.into()),
209            children: Vec::new(),
210        }
211    }
212    /// Creates a section node with children.
213    pub fn section(key: impl Into<String>) -> Self {
214        Self {
215            key: key.into(),
216            value: None,
217            children: Vec::new(),
218        }
219    }
220    /// Adds a child node.
221    pub fn add_child(&mut self, child: ConfigNode) {
222        self.children.push(child);
223    }
224    /// Returns the key.
225    pub fn key(&self) -> &str {
226        &self.key
227    }
228    /// Returns the value, or `None` for section nodes.
229    pub fn value(&self) -> Option<&str> {
230        self.value.as_deref()
231    }
232    /// Returns the number of children.
233    pub fn num_children(&self) -> usize {
234        self.children.len()
235    }
236    /// Looks up a dot-separated path.
237    pub fn lookup(&self, path: &str) -> Option<&str> {
238        let mut parts = path.splitn(2, '.');
239        let head = parts.next()?;
240        let tail = parts.next();
241        if head != self.key {
242            return None;
243        }
244        match tail {
245            None => self.value.as_deref(),
246            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
247        }
248    }
249    fn lookup_relative(&self, path: &str) -> Option<&str> {
250        let mut parts = path.splitn(2, '.');
251        let head = parts.next()?;
252        let tail = parts.next();
253        if head != self.key {
254            return None;
255        }
256        match tail {
257            None => self.value.as_deref(),
258            Some(rest) => self.children.iter().find_map(|c| c.lookup_relative(rest)),
259        }
260    }
261}
262/// A simple directed acyclic graph.
263#[allow(dead_code)]
264pub struct SimpleDag {
265    /// `edges[i]` is the list of direct successors of node `i`.
266    edges: Vec<Vec<usize>>,
267}
268#[allow(dead_code)]
269impl SimpleDag {
270    /// Creates a DAG with `n` nodes and no edges.
271    pub fn new(n: usize) -> Self {
272        Self {
273            edges: vec![Vec::new(); n],
274        }
275    }
276    /// Adds an edge from `from` to `to`.
277    pub fn add_edge(&mut self, from: usize, to: usize) {
278        if from < self.edges.len() {
279            self.edges[from].push(to);
280        }
281    }
282    /// Returns the successors of `node`.
283    pub fn successors(&self, node: usize) -> &[usize] {
284        self.edges.get(node).map(|v| v.as_slice()).unwrap_or(&[])
285    }
286    /// Returns `true` if `from` can reach `to` via DFS.
287    pub fn can_reach(&self, from: usize, to: usize) -> bool {
288        let mut visited = vec![false; self.edges.len()];
289        self.dfs(from, to, &mut visited)
290    }
291    fn dfs(&self, cur: usize, target: usize, visited: &mut Vec<bool>) -> bool {
292        if cur == target {
293            return true;
294        }
295        if cur >= visited.len() || visited[cur] {
296            return false;
297        }
298        visited[cur] = true;
299        for &next in self.successors(cur) {
300            if self.dfs(next, target, visited) {
301                return true;
302            }
303        }
304        false
305    }
306    /// Returns the topological order of nodes, or `None` if a cycle is detected.
307    pub fn topological_sort(&self) -> Option<Vec<usize>> {
308        let n = self.edges.len();
309        let mut in_degree = vec![0usize; n];
310        for succs in &self.edges {
311            for &s in succs {
312                if s < n {
313                    in_degree[s] += 1;
314                }
315            }
316        }
317        let mut queue: std::collections::VecDeque<usize> =
318            (0..n).filter(|&i| in_degree[i] == 0).collect();
319        let mut order = Vec::new();
320        while let Some(node) = queue.pop_front() {
321            order.push(node);
322            for &s in self.successors(node) {
323                if s < n {
324                    in_degree[s] -= 1;
325                    if in_degree[s] == 0 {
326                        queue.push_back(s);
327                    }
328                }
329            }
330        }
331        if order.len() == n {
332            Some(order)
333        } else {
334            None
335        }
336    }
337    /// Returns the number of nodes.
338    pub fn num_nodes(&self) -> usize {
339        self.edges.len()
340    }
341}
342/// A window iterator that yields overlapping windows of size `n`.
343#[allow(dead_code)]
344pub struct WindowIterator<'a, T> {
345    pub(super) data: &'a [T],
346    pub(super) pos: usize,
347    pub(super) window: usize,
348}
349#[allow(dead_code)]
350impl<'a, T> WindowIterator<'a, T> {
351    /// Creates a new window iterator.
352    pub fn new(data: &'a [T], window: usize) -> Self {
353        Self {
354            data,
355            pos: 0,
356            window,
357        }
358    }
359}
360/// Environment extension for inductive types.
361pub struct InductiveEnv {
362    /// Map from type name to inductive declaration
363    inductives: HashMap<Name, InductiveType>,
364    /// Map from constructor name to parent type
365    constructors: HashMap<Name, Name>,
366    /// Map from recursor name to parent type
367    recursors: HashMap<Name, Name>,
368}
369impl InductiveEnv {
370    /// Create a new empty inductive environment.
371    pub fn new() -> Self {
372        Self {
373            inductives: HashMap::new(),
374            constructors: HashMap::new(),
375            recursors: HashMap::new(),
376        }
377    }
378    /// Add an inductive type to the environment.
379    #[allow(clippy::result_large_err)]
380    pub fn add(&mut self, ind: InductiveType) -> Result<(), KernelError> {
381        if self.inductives.contains_key(&ind.name) {
382            return Err(KernelError::Other(format!(
383                "inductive type already declared: {}",
384                ind.name
385            )));
386        }
387        for intro in &ind.intro_rules {
388            if self.constructors.contains_key(&intro.name) {
389                return Err(KernelError::Other(format!(
390                    "constructor already declared: {}",
391                    intro.name
392                )));
393            }
394            self.constructors
395                .insert(intro.name.clone(), ind.name.clone());
396        }
397        self.recursors
398            .insert(ind.recursor.clone(), ind.name.clone());
399        self.inductives.insert(ind.name.clone(), ind);
400        Ok(())
401    }
402    /// Get an inductive type by name.
403    pub fn get(&self, name: &Name) -> Option<&InductiveType> {
404        self.inductives.get(name)
405    }
406    /// Check if a name is a constructor.
407    pub fn is_constructor(&self, name: &Name) -> bool {
408        self.constructors.contains_key(name)
409    }
410    /// Get the parent type of a constructor.
411    pub fn get_constructor_parent(&self, name: &Name) -> Option<&Name> {
412        self.constructors.get(name)
413    }
414    /// Check if a name is a recursor.
415    pub fn is_recursor(&self, name: &Name) -> bool {
416        self.recursors.contains_key(name)
417    }
418    /// Get the parent type of a recursor.
419    pub fn get_recursor_parent(&self, name: &Name) -> Option<&Name> {
420        self.recursors.get(name)
421    }
422    /// Register an InductiveType into an Environment via ConstantInfo.
423    #[allow(clippy::result_large_err)]
424    pub fn register_in_env(
425        &mut self,
426        ind: &InductiveType,
427        env: &mut crate::Environment,
428    ) -> Result<(), KernelError> {
429        let (ind_ci, ctor_cis, rec_ci) = ind.to_constant_infos();
430        env.add_constant(ind_ci)
431            .map_err(|e| KernelError::Other(e.to_string()))?;
432        for ctor_ci in ctor_cis {
433            env.add_constant(ctor_ci)
434                .map_err(|e| KernelError::Other(e.to_string()))?;
435        }
436        env.add_constant(rec_ci)
437            .map_err(|e| KernelError::Other(e.to_string()))?;
438        self.add(ind.clone())?;
439        Ok(())
440    }
441}
442/// A non-empty list (at least one element guaranteed).
443#[allow(dead_code)]
444pub struct NonEmptyVec<T> {
445    head: T,
446    tail: Vec<T>,
447}
448#[allow(dead_code)]
449impl<T> NonEmptyVec<T> {
450    /// Creates a non-empty vec with a single element.
451    pub fn singleton(val: T) -> Self {
452        Self {
453            head: val,
454            tail: Vec::new(),
455        }
456    }
457    /// Pushes an element.
458    pub fn push(&mut self, val: T) {
459        self.tail.push(val);
460    }
461    /// Returns a reference to the first element.
462    pub fn first(&self) -> &T {
463        &self.head
464    }
465    /// Returns a reference to the last element.
466    pub fn last(&self) -> &T {
467        self.tail.last().unwrap_or(&self.head)
468    }
469    /// Returns the number of elements.
470    pub fn len(&self) -> usize {
471        1 + self.tail.len()
472    }
473    /// Returns whether the collection is empty.
474    pub fn is_empty(&self) -> bool {
475        self.len() == 0
476    }
477    /// Returns all elements as a Vec.
478    pub fn to_vec(&self) -> Vec<&T> {
479        let mut v = vec![&self.head];
480        v.extend(self.tail.iter());
481        v
482    }
483}
484/// A pair of `StatSummary` values tracking before/after a transformation.
485#[allow(dead_code)]
486pub struct TransformStat {
487    before: StatSummary,
488    after: StatSummary,
489}
490#[allow(dead_code)]
491impl TransformStat {
492    /// Creates a new transform stat recorder.
493    pub fn new() -> Self {
494        Self {
495            before: StatSummary::new(),
496            after: StatSummary::new(),
497        }
498    }
499    /// Records a before value.
500    pub fn record_before(&mut self, v: f64) {
501        self.before.record(v);
502    }
503    /// Records an after value.
504    pub fn record_after(&mut self, v: f64) {
505        self.after.record(v);
506    }
507    /// Returns the mean reduction ratio (after/before).
508    pub fn mean_ratio(&self) -> Option<f64> {
509        let b = self.before.mean()?;
510        let a = self.after.mean()?;
511        if b.abs() < f64::EPSILON {
512            return None;
513        }
514        Some(a / b)
515    }
516}
517/// A label set for a graph node.
518#[allow(dead_code)]
519pub struct LabelSet {
520    labels: Vec<String>,
521}
522#[allow(dead_code)]
523impl LabelSet {
524    /// Creates a new empty label set.
525    pub fn new() -> Self {
526        Self { labels: Vec::new() }
527    }
528    /// Adds a label (deduplicates).
529    pub fn add(&mut self, label: impl Into<String>) {
530        let s = label.into();
531        if !self.labels.contains(&s) {
532            self.labels.push(s);
533        }
534    }
535    /// Returns `true` if `label` is present.
536    pub fn has(&self, label: &str) -> bool {
537        self.labels.iter().any(|l| l == label)
538    }
539    /// Returns the count of labels.
540    pub fn count(&self) -> usize {
541        self.labels.len()
542    }
543    /// Returns all labels.
544    pub fn all(&self) -> &[String] {
545        &self.labels
546    }
547}
548/// A versioned record that stores a history of values.
549#[allow(dead_code)]
550pub struct VersionedRecord<T: Clone> {
551    history: Vec<T>,
552}
553#[allow(dead_code)]
554impl<T: Clone> VersionedRecord<T> {
555    /// Creates a new record with an initial value.
556    pub fn new(initial: T) -> Self {
557        Self {
558            history: vec![initial],
559        }
560    }
561    /// Updates the record with a new version.
562    pub fn update(&mut self, val: T) {
563        self.history.push(val);
564    }
565    /// Returns the current (latest) value.
566    pub fn current(&self) -> &T {
567        self.history
568            .last()
569            .expect("VersionedRecord history is always non-empty after construction")
570    }
571    /// Returns the value at version `n` (0-indexed), or `None`.
572    pub fn at_version(&self, n: usize) -> Option<&T> {
573        self.history.get(n)
574    }
575    /// Returns the version number of the current value.
576    pub fn version(&self) -> usize {
577        self.history.len() - 1
578    }
579    /// Returns `true` if more than one version exists.
580    pub fn has_history(&self) -> bool {
581        self.history.len() > 1
582    }
583}
584/// An inductive type declaration.
585#[derive(Clone, Debug, PartialEq)]
586pub struct InductiveType {
587    /// Type name
588    pub name: Name,
589    /// Universe parameters
590    pub univ_params: Vec<Name>,
591    /// Number of parameters (non-varying arguments)
592    pub num_params: u32,
593    /// Number of indices (varying arguments)
594    pub num_indices: u32,
595    /// Type of the inductive type (Pi type over params and indices)
596    pub ty: Expr,
597    /// Introduction rules (constructors)
598    pub intro_rules: Vec<IntroRule>,
599    /// Recursor name (generated automatically)
600    pub recursor: Name,
601    /// Whether this is a nested inductive type
602    pub is_nested: bool,
603    /// Whether this type is in Prop (proof-irrelevant)
604    pub is_prop: bool,
605}
606impl InductiveType {
607    /// Create a new inductive type.
608    pub fn new(
609        name: Name,
610        univ_params: Vec<Name>,
611        num_params: u32,
612        num_indices: u32,
613        ty: Expr,
614        intro_rules: Vec<IntroRule>,
615    ) -> Self {
616        let recursor = Name::Str(Box::new(name.clone()), "rec".to_string());
617        Self {
618            name,
619            univ_params,
620            num_params,
621            num_indices,
622            ty,
623            intro_rules,
624            recursor,
625            is_nested: false,
626            is_prop: false,
627        }
628    }
629    /// Get the arity (total number of arguments).
630    pub fn arity(&self) -> u32 {
631        self.num_params + self.num_indices
632    }
633    /// Check if this inductive type is recursive.
634    pub fn is_recursive(&self) -> bool {
635        self.intro_rules
636            .iter()
637            .any(|rule| self.occurs_in_arguments(&self.name, &rule.ty))
638    }
639    /// Return a vector of references to constructor names.
640    pub fn constructor_names(&self) -> Vec<&Name> {
641        self.intro_rules.iter().map(|r| &r.name).collect()
642    }
643    /// Return the number of constructors.
644    pub fn num_constructors(&self) -> usize {
645        self.intro_rules.len()
646    }
647    fn occurs_in_arguments(&self, name: &Name, ty: &Expr) -> bool {
648        match ty {
649            Expr::Pi(_, _, dom, cod) => {
650                self.occurs_in_type(name, dom) || self.occurs_in_arguments(name, cod)
651            }
652            _ => false,
653        }
654    }
655    fn occurs_in_type(&self, name: &Name, ty: &Expr) -> bool {
656        match ty {
657            Expr::Const(n, _) => n == name,
658            Expr::App(f, a) => self.occurs_in_type(name, f) || self.occurs_in_type(name, a),
659            Expr::Pi(_, _, dom, cod) => {
660                self.occurs_in_type(name, dom) || self.occurs_in_type(name, cod)
661            }
662            Expr::Lam(_, _, ty_inner, body) => {
663                self.occurs_in_type(name, ty_inner) || self.occurs_in_type(name, body)
664            }
665            _ => false,
666        }
667    }
668    /// Generate ConstantInfo declarations for this inductive type.
669    ///
670    /// Returns: (InductiveVal, `Vec<ConstructorVal>`, RecursorVal)
671    pub fn to_constant_infos(&self) -> (ConstantInfo, Vec<ConstantInfo>, ConstantInfo) {
672        let ind_val = self.make_inductive_val();
673        let ctor_vals: Vec<ConstantInfo> = self.make_constructor_vals();
674        let rec_val = self.make_recursor_val();
675        (ind_val, ctor_vals, rec_val)
676    }
677    fn make_inductive_val(&self) -> ConstantInfo {
678        ConstantInfo::Inductive(InductiveVal {
679            common: ConstantVal {
680                name: self.name.clone(),
681                level_params: self.univ_params.clone(),
682                ty: self.ty.clone(),
683            },
684            num_params: self.num_params,
685            num_indices: self.num_indices,
686            all: vec![self.name.clone()],
687            ctors: self.intro_rules.iter().map(|r| r.name.clone()).collect(),
688            num_nested: 0,
689            is_rec: self.is_recursive(),
690            is_unsafe: false,
691            is_reflexive: false,
692            is_prop: self.is_prop,
693        })
694    }
695    fn make_constructor_vals(&self) -> Vec<ConstantInfo> {
696        self.intro_rules
697            .iter()
698            .enumerate()
699            .map(|(i, rule)| {
700                let num_fields = count_pi_args(&rule.ty).saturating_sub(self.num_params);
701                ConstantInfo::Constructor(ConstructorVal {
702                    common: ConstantVal {
703                        name: rule.name.clone(),
704                        level_params: self.univ_params.clone(),
705                        ty: rule.ty.clone(),
706                    },
707                    induct: self.name.clone(),
708                    cidx: i as u32,
709                    num_params: self.num_params,
710                    num_fields,
711                    is_unsafe: false,
712                })
713            })
714            .collect()
715    }
716    fn make_recursor_val(&self) -> ConstantInfo {
717        let num_minors = self.intro_rules.len() as u32;
718        let rules: Vec<RecursorRule> = self
719            .intro_rules
720            .iter()
721            .enumerate()
722            .map(|(cidx, rule)| {
723                let nfields = count_pi_args(&rule.ty).saturating_sub(self.num_params);
724                let rhs = self.build_recursor_rhs(rule, cidx as u32, nfields, num_minors);
725                RecursorRule {
726                    ctor: rule.name.clone(),
727                    nfields,
728                    rhs,
729                }
730            })
731            .collect();
732        let k = self.is_prop && self.intro_rules.len() <= 1;
733        let mut rec_level_params = self.univ_params.clone();
734        if !self.is_prop {
735            rec_level_params.insert(0, Name::str("u_1"));
736        }
737        let rec_ty = self.build_recursor_type(&rec_level_params);
738        ConstantInfo::Recursor(RecursorVal {
739            common: ConstantVal {
740                name: self.recursor.clone(),
741                level_params: rec_level_params,
742                ty: rec_ty,
743            },
744            all: vec![self.name.clone()],
745            num_params: self.num_params,
746            num_indices: self.num_indices,
747            num_motives: 1,
748            num_minors,
749            rules,
750            k,
751            is_unsafe: false,
752        })
753    }
754    /// Collect the field types (domains) for a constructor, skipping num_params params.
755    /// Returns a Vec<(field_domain_Expr, is_recursive)>.
756    fn collect_field_info(&self, rule: &IntroRule) -> Vec<(Expr, bool)> {
757        let mut current = &rule.ty;
758        for _ in 0..self.num_params {
759            match current {
760                Expr::Pi(_, _, _, body) => current = body,
761                _ => return vec![],
762            }
763        }
764        let mut fields = Vec::new();
765        while let Expr::Pi(_, _, dom, body) = current {
766            let is_rec = self.head_is_inductive(dom);
767            fields.push((dom.as_ref().clone(), is_rec));
768            current = body;
769        }
770        fields
771    }
772    /// Check if the head of an expression is the inductive type constant.
773    fn head_is_inductive(&self, expr: &Expr) -> bool {
774        match expr {
775            Expr::Const(n, _) => n == &self.name,
776            Expr::App(f, _) => self.head_is_inductive(f),
777            _ => false,
778        }
779    }
780    /// Build the recursor type Pi-expression.
781    ///
782    /// The recursor type has the form:
783    ///   forall params... motive minor_0... minor_{m-1} indices... (major : T p i), motive i major
784    fn build_recursor_type(&self, rec_level_params: &[Name]) -> Expr {
785        use crate::BinderInfo;
786        let np = self.num_params as usize;
787        let ni = self.num_indices as usize;
788        let nminors = self.intro_rules.len();
789        let (all_binders, _result_sort) = peel_pi_binders(&self.ty);
790        let motive_sort = if self.is_prop {
791            Level::zero()
792        } else if let Some(name) = rec_level_params.first() {
793            Level::Param(name.clone())
794        } else {
795            Level::zero()
796        };
797        let ind_applied_major = {
798            let mut e: Expr = Expr::Const(self.name.clone(), vec![]);
799            for k in 0..np {
800                let bvar = Expr::BVar((ni + nminors + 1 + np - k) as u32);
801                e = Expr::App(Box::new(e), Box::new(bvar));
802            }
803            for k in 0..ni {
804                let bvar = Expr::BVar((ni - k) as u32);
805                e = Expr::App(Box::new(e), Box::new(bvar));
806            }
807            e
808        };
809        let conclusion = {
810            let mut e: Expr = Expr::BVar((1 + ni + nminors) as u32);
811            for k in 0..ni {
812                let bvar = Expr::BVar((ni - k) as u32);
813                e = Expr::App(Box::new(e), Box::new(bvar));
814            }
815            e = Expr::App(Box::new(e), Box::new(Expr::BVar(0)));
816            e
817        };
818        let mut result = Expr::Pi(
819            BinderInfo::Default,
820            Name::str("t"),
821            Box::new(ind_applied_major),
822            Box::new(conclusion),
823        );
824        for k in (0..ni).rev() {
825            let idx_ty = if np + k < all_binders.len() {
826                lift_expr_bvars(&all_binders[np + k], (1 + nminors) as u32)
827            } else {
828                Expr::Sort(Level::zero())
829            };
830            result = Expr::Pi(
831                BinderInfo::Default,
832                Name::str("i"),
833                Box::new(idx_ty),
834                Box::new(result),
835            );
836        }
837        for cidx in (0..nminors).rev() {
838            let minor_ty = self.build_minor_type(cidx, nminors, np, ni, &all_binders);
839            result = Expr::Pi(
840                BinderInfo::Default,
841                Name::str("minor"),
842                Box::new(minor_ty),
843                Box::new(result),
844            );
845        }
846        let motive_ty = self.build_motive_type(np, ni, &all_binders, motive_sort);
847        result = Expr::Pi(
848            BinderInfo::Default,
849            Name::str("motive"),
850            Box::new(motive_ty),
851            Box::new(result),
852        );
853        for k in (0..np).rev() {
854            let param_ty = if k < all_binders.len() {
855                all_binders[k].clone()
856            } else {
857                Expr::Sort(Level::succ(Level::zero()))
858            };
859            result = Expr::Pi(
860                BinderInfo::Default,
861                Name::str("param"),
862                Box::new(param_ty),
863                Box::new(result),
864            );
865        }
866        result
867    }
868    /// Build the motive type at depth np (inside np param binders):
869    ///   forall (i_0 : I_0)...(i_{ni-1} : I_{ni-1}), T p i -> Sort v
870    fn build_motive_type(
871        &self,
872        np: usize,
873        ni: usize,
874        all_binders: &[Expr],
875        motive_sort: Level,
876    ) -> Expr {
877        use crate::BinderInfo;
878        let ind_applied = {
879            let mut e: Expr = Expr::Const(self.name.clone(), vec![]);
880            for k in 0..np {
881                let bvar = Expr::BVar((np + ni - 1 - k) as u32);
882                e = Expr::App(Box::new(e), Box::new(bvar));
883            }
884            for k in 0..ni {
885                let bvar = Expr::BVar((ni - 1 - k) as u32);
886                e = Expr::App(Box::new(e), Box::new(bvar));
887            }
888            e
889        };
890        let inner = Expr::Pi(
891            BinderInfo::Default,
892            Name::str("x"),
893            Box::new(ind_applied),
894            Box::new(Expr::Sort(motive_sort)),
895        );
896        let mut result = inner;
897        for k in (0..ni).rev() {
898            let idx_ty = if np + k < all_binders.len() {
899                all_binders[np + k].clone()
900            } else {
901                Expr::Sort(Level::zero())
902            };
903            result = Expr::Pi(
904                BinderInfo::Default,
905                Name::str("i"),
906                Box::new(idx_ty),
907                Box::new(result),
908            );
909        }
910        result
911    }
912    /// Build the minor premise type for constructor at `cidx`.
913    ///
914    /// The minor type for constructor `cidx` (with `nf` fields) is built in the context:
915    ///   np param binders + 1 motive binder + cidx outer minor binders (already wrapped)
916    ///
917    /// The resulting type is a Pi chain over the field types ending with:
918    ///   motive [return_indices] (ctor p_0 ... p_{np-1} y_0 ... y_{nf-1})
919    ///
920    /// At the body (depth = nf inside the field Pi chain):
921    ///   y_j     = BVar(nf - 1 - j)        for j = 0..nf-1
922    ///   motive  = BVar(nf + cidx)
923    ///   p_k     = BVar(nf + cidx + np - k) for k = 0..np-1
924    fn build_minor_type(
925        &self,
926        cidx: usize,
927        _nminors: usize,
928        np: usize,
929        ni: usize,
930        _all_binders: &[Expr],
931    ) -> Expr {
932        use crate::BinderInfo;
933        let rule = &self.intro_rules[cidx];
934        let field_info = self.collect_field_info(rule);
935        let nf = field_info.len();
936        let return_indices: Vec<Expr> = if ni > 0 {
937            let mut cod: &Expr = &rule.ty;
938            for _ in 0..(np + nf) {
939                match cod {
940                    Expr::Pi(_, _, _, body) => cod = body,
941                    _ => break,
942                }
943            }
944            let mut args: Vec<Expr> = Vec::new();
945            let mut cur = cod;
946            while let Expr::App(f, a) = cur {
947                args.push(a.as_ref().clone());
948                cur = f;
949            }
950            args.reverse();
951            let start = args.len().saturating_sub(ni);
952            args[start..]
953                .iter()
954                .map(|e| lift_expr_bvars(e, (1 + cidx) as u32))
955                .collect()
956        } else {
957            vec![]
958        };
959        let mut ctor_app: Expr = Expr::Const(rule.name.clone(), vec![]);
960        for k in 0..np {
961            let bvar = Expr::BVar((nf + cidx + np - k) as u32);
962            ctor_app = Expr::App(Box::new(ctor_app), Box::new(bvar));
963        }
964        for j in 0..nf {
965            let bvar = Expr::BVar((nf - 1 - j) as u32);
966            ctor_app = Expr::App(Box::new(ctor_app), Box::new(bvar));
967        }
968        let mut conclusion: Expr = Expr::BVar((nf + cidx) as u32);
969        for idx in &return_indices {
970            conclusion = Expr::App(Box::new(conclusion), Box::new(idx.clone()));
971        }
972        conclusion = Expr::App(Box::new(conclusion), Box::new(ctor_app));
973        let mut result = conclusion;
974        for j in (0..nf).rev() {
975            let (field_ty, _is_rec) = &field_info[j];
976            let adjusted = lift_expr_bvars(field_ty, (1 + cidx) as u32);
977            result = Expr::Pi(
978                BinderInfo::Default,
979                Name::str("y"),
980                Box::new(adjusted),
981                Box::new(result),
982            );
983        }
984        result
985    }
986    /// Build the recursor rule RHS for a constructor.
987    ///
988    /// The `instantiate_recursor_rhs` function builds a substitution array:
989    ///   subst = [p_0, ..., p_{np-1}, motive, minor_0, ..., minor_{nm-1}, f_0, ..., f_{nf-1}]
990    ///   len = np + 1 + nm + nf
991    ///
992    /// `instantiate_rev` maps BVar(i) -> subst[len - 1 - i]:
993    ///   f_j     -> BVar(nf - 1 - j)         (j = 0..nf-1)
994    ///   minor_k -> BVar(nf + nm - 1 - k)    (k = 0..nm-1)
995    ///   motive  -> BVar(nf + nm)
996    ///   p_j     -> BVar(nf + nm + 1 + np - 1 - j) = BVar(nf + nm + np - j)
997    ///
998    /// The RHS is: minor_cidx f_0 [IH_0] f_1 [IH_1] ... f_{nf-1} [IH_{nf-1}]
999    /// where IH_j = rec_name p_0...p_{np-1} motive minor_0...minor_{nm-1} f_j
1000    fn build_recursor_rhs(&self, rule: &IntroRule, cidx: u32, nfields: u32, nminors: u32) -> Expr {
1001        let np = self.num_params;
1002        let nf = nfields;
1003        let nm = nminors;
1004        let field_info = self.collect_field_info(rule);
1005        let mut result = Expr::BVar(nf + nm - 1 - cidx);
1006        for (j, (_field_ty, is_rec)) in field_info.iter().enumerate() {
1007            let j = j as u32;
1008            let field_bvar = Expr::BVar(nf - 1 - j);
1009            result = Expr::App(Box::new(result), Box::new(field_bvar.clone()));
1010            if *is_rec {
1011                let ih = self.build_ih(field_bvar, np, nm, nf);
1012                result = Expr::App(Box::new(result), Box::new(ih));
1013            }
1014        }
1015        result
1016    }
1017    /// Build the inductive hypothesis for a recursive field:
1018    ///   IH = rec_name p_0...p_{np-1} motive minor_0...minor_{nm-1} field_expr
1019    fn build_ih(&self, field_expr: Expr, np: u32, nm: u32, nf: u32) -> Expr {
1020        let mut ih = Expr::Const(self.recursor.clone(), vec![]);
1021        for j in 0..np {
1022            let bvar = Expr::BVar(nf + nm + np - j);
1023            ih = Expr::App(Box::new(ih), Box::new(bvar));
1024        }
1025        ih = Expr::App(Box::new(ih), Box::new(Expr::BVar(nf + nm)));
1026        for k in 0..nm {
1027            let bvar = Expr::BVar(nf + nm - 1 - k);
1028            ih = Expr::App(Box::new(ih), Box::new(bvar));
1029        }
1030        ih = Expr::App(Box::new(ih), Box::new(field_expr));
1031        ih
1032    }
1033}
1034/// Summary information about an inductive type (for display/LSP use).
1035#[derive(Clone, Debug)]
1036pub struct InductiveTypeInfo {
1037    /// Type name.
1038    pub name: Name,
1039    /// Number of parameters.
1040    pub num_params: u32,
1041    /// Number of indices.
1042    pub num_indices: u32,
1043    /// Number of constructors.
1044    pub num_constructors: usize,
1045    /// Whether the type is in Prop.
1046    pub is_prop: bool,
1047    /// Whether the type is recursive (has recursive constructors).
1048    pub is_recursive: bool,
1049    /// Whether the type is mutually inductive.
1050    pub is_mutual: bool,
1051    /// Constructor names.
1052    pub constructor_names: Vec<Name>,
1053}
1054impl InductiveTypeInfo {
1055    /// Build info from an `InductiveType`.
1056    pub fn from_type(ty: &InductiveType, is_mutual: bool) -> Self {
1057        Self {
1058            name: ty.name.clone(),
1059            num_params: ty.num_params,
1060            num_indices: ty.num_indices,
1061            num_constructors: ty.intro_rules.len(),
1062            is_prop: ty.is_prop,
1063            is_recursive: ty.is_recursive(),
1064            is_mutual,
1065            constructor_names: ty.intro_rules.iter().map(|r| r.name.clone()).collect(),
1066        }
1067    }
1068    /// Human-readable summary.
1069    pub fn summary(&self) -> String {
1070        format!(
1071            "{}: {} params, {} indices, {} ctors, prop={}, recursive={}, mutual={}",
1072            self.name,
1073            self.num_params,
1074            self.num_indices,
1075            self.num_constructors,
1076            self.is_prop,
1077            self.is_recursive,
1078            self.is_mutual
1079        )
1080    }
1081}
1082/// A mutable reference stack for tracking the current "focus" in a tree traversal.
1083#[allow(dead_code)]
1084pub struct FocusStack<T> {
1085    items: Vec<T>,
1086}
1087#[allow(dead_code)]
1088impl<T> FocusStack<T> {
1089    /// Creates an empty focus stack.
1090    pub fn new() -> Self {
1091        Self { items: Vec::new() }
1092    }
1093    /// Focuses on `item`.
1094    pub fn focus(&mut self, item: T) {
1095        self.items.push(item);
1096    }
1097    /// Blurs (pops) the current focus.
1098    pub fn blur(&mut self) -> Option<T> {
1099        self.items.pop()
1100    }
1101    /// Returns the current focus, or `None`.
1102    pub fn current(&self) -> Option<&T> {
1103        self.items.last()
1104    }
1105    /// Returns the focus depth.
1106    pub fn depth(&self) -> usize {
1107        self.items.len()
1108    }
1109    /// Returns `true` if there is no current focus.
1110    pub fn is_empty(&self) -> bool {
1111        self.items.is_empty()
1112    }
1113}
1114/// Builder for constructing `InductiveType` declarations incrementally.
1115#[allow(dead_code)]
1116pub struct InductiveTypeBuilder {
1117    name: Option<Name>,
1118    univ_params: Vec<Name>,
1119    num_params: u32,
1120    num_indices: u32,
1121    ty: Option<Expr>,
1122    intro_rules: Vec<IntroRule>,
1123    is_prop: bool,
1124    is_nested: bool,
1125}
1126#[allow(dead_code)]
1127impl InductiveTypeBuilder {
1128    /// Create an empty builder.
1129    pub fn new() -> Self {
1130        Self {
1131            name: None,
1132            univ_params: vec![],
1133            num_params: 0,
1134            num_indices: 0,
1135            ty: None,
1136            intro_rules: vec![],
1137            is_prop: false,
1138            is_nested: false,
1139        }
1140    }
1141    /// Set the inductive type name.
1142    pub fn name(mut self, name: Name) -> Self {
1143        self.name = Some(name);
1144        self
1145    }
1146    /// Set universe parameters.
1147    pub fn univ_params(mut self, params: Vec<Name>) -> Self {
1148        self.univ_params = params;
1149        self
1150    }
1151    /// Set number of type parameters.
1152    pub fn num_params(mut self, n: u32) -> Self {
1153        self.num_params = n;
1154        self
1155    }
1156    /// Set number of type indices.
1157    pub fn num_indices(mut self, n: u32) -> Self {
1158        self.num_indices = n;
1159        self
1160    }
1161    /// Set the sort of the inductive type.
1162    pub fn ty(mut self, ty: Expr) -> Self {
1163        self.ty = Some(ty);
1164        self
1165    }
1166    /// Add a constructor/introduction rule.
1167    pub fn intro_rule(mut self, name: Name, ty: Expr) -> Self {
1168        self.intro_rules.push(IntroRule { name, ty });
1169        self
1170    }
1171    /// Mark as a Prop-valued inductive type (proof-irrelevant).
1172    pub fn is_prop(mut self, v: bool) -> Self {
1173        self.is_prop = v;
1174        self
1175    }
1176    /// Mark as a nested inductive type.
1177    pub fn is_nested(mut self, v: bool) -> Self {
1178        self.is_nested = v;
1179        self
1180    }
1181    /// Build the `InductiveType`. Returns `Err` if name or ty is missing.
1182    pub fn build(self) -> Result<InductiveType, String> {
1183        let name = self
1184            .name
1185            .ok_or_else(|| "InductiveTypeBuilder: name not set".to_string())?;
1186        let ty = self
1187            .ty
1188            .ok_or_else(|| "InductiveTypeBuilder: ty not set".to_string())?;
1189        let mut ind = InductiveType::new(
1190            name,
1191            self.univ_params,
1192            self.num_params,
1193            self.num_indices,
1194            ty,
1195            self.intro_rules,
1196        );
1197        ind.is_prop = self.is_prop;
1198        ind.is_nested = self.is_nested;
1199        Ok(ind)
1200    }
1201}
1202/// A builder for constructing recursor definitions programmatically.
1203///
1204/// Recursors (eliminators) are the fundamental way to consume inductive types.
1205/// This builder provides a fluent API for constructing them.
1206#[derive(Clone, Debug)]
1207pub struct RecursorBuilder {
1208    /// Name of the recursor (typically `T.rec` or `T.recOn`).
1209    pub name: Name,
1210    /// Universe parameters.
1211    pub univ_params: Vec<Name>,
1212    /// Number of type parameters.
1213    pub num_params: u32,
1214    /// Number of indices.
1215    pub num_indices: u32,
1216    /// Number of motives (typically 1).
1217    pub num_motives: u32,
1218    /// Number of minor premises (one per constructor).
1219    pub num_minor_premises: u32,
1220    /// Recursor rules (one per constructor).
1221    pub rules: Vec<RecursorRule>,
1222    /// Whether the recursor targets `Prop`.
1223    pub is_prop: bool,
1224}
1225impl RecursorBuilder {
1226    /// Create a new builder.
1227    pub fn new(name: Name) -> Self {
1228        Self {
1229            name,
1230            univ_params: vec![],
1231            num_params: 0,
1232            num_indices: 0,
1233            num_motives: 1,
1234            num_minor_premises: 0,
1235            rules: vec![],
1236            is_prop: false,
1237        }
1238    }
1239    /// Set universe parameters.
1240    pub fn univ_params(mut self, params: Vec<Name>) -> Self {
1241        self.univ_params = params;
1242        self
1243    }
1244    /// Set the number of parameters.
1245    pub fn num_params(mut self, n: u32) -> Self {
1246        self.num_params = n;
1247        self
1248    }
1249    /// Set the number of indices.
1250    pub fn num_indices(mut self, n: u32) -> Self {
1251        self.num_indices = n;
1252        self
1253    }
1254    /// Set whether the recursor targets Prop.
1255    pub fn is_prop(mut self, b: bool) -> Self {
1256        self.is_prop = b;
1257        self
1258    }
1259    /// Add a recursor rule.
1260    pub fn add_rule(mut self, rule: RecursorRule) -> Self {
1261        self.rules.push(rule);
1262        self.num_minor_premises += 1;
1263        self
1264    }
1265    /// Validate the builder state.
1266    ///
1267    /// Returns `Ok(())` if the builder is consistent.
1268    pub fn validate(&self) -> Result<(), String> {
1269        if self.name.is_anonymous() {
1270            return Err("recursor name must not be anonymous".to_string());
1271        }
1272        if self.num_motives == 0 {
1273            return Err("recursor must have at least one motive".to_string());
1274        }
1275        Ok(())
1276    }
1277    /// Return the name of the recursor.
1278    pub fn build_name(&self) -> Name {
1279        self.name.clone()
1280    }
1281    /// Build a complete [`RecursorVal`] from the builder state.
1282    ///
1283    /// `ty` is the type of the recursor (must be supplied by the caller since
1284    /// this builder does not reconstruct the Pi telescope).
1285    /// `all` is the list of inductive type names in the mutual family.
1286    pub fn build(&self, ty: Expr, all: Vec<Name>) -> Result<RecursorVal, String> {
1287        self.validate()?;
1288        if self.rules.len() != self.num_minor_premises as usize {
1289            return Err(format!(
1290                "RecursorBuilder: num_minor_premises ({}) does not match rule count ({})",
1291                self.num_minor_premises,
1292                self.rules.len()
1293            ));
1294        }
1295        Ok(RecursorVal {
1296            common: ConstantVal {
1297                name: self.name.clone(),
1298                level_params: self.univ_params.clone(),
1299                ty,
1300            },
1301            all,
1302            num_params: self.num_params,
1303            num_indices: self.num_indices,
1304            num_motives: self.num_motives,
1305            num_minors: self.num_minor_premises,
1306            rules: self.rules.clone(),
1307            k: false,
1308            is_unsafe: false,
1309        })
1310    }
1311}