1use crate::context::{Context, MutualInductive};
25use crate::error::{KernelError, KernelResult};
26use crate::term::Term;
27
28pub struct NestedDecl {
31 pub name: String,
32 pub sort: Term,
33 pub constructors: Vec<(String, Term)>,
34}
35
36#[derive(Debug, Clone)]
38pub struct IsoNames {
39 pub container: String,
41 pub sibling: String,
43 pub to_generic: String,
45 pub from_generic: String,
47}
48
49pub struct Compiled {
53 pub block: Vec<MutualInductive>,
54 pub isos: Vec<(String, Term, Term)>,
55 pub iso_names: Vec<IsoNames>,
56 pub siblings: Vec<String>,
57}
58
59#[derive(Debug, Clone)]
62pub struct NestedInfo {
63 pub siblings: Vec<String>,
64 pub isos: Vec<IsoNames>,
65}
66
67fn g(n: &str) -> Term {
69 Term::Global(n.to_string())
70}
71fn v(n: &str) -> Term {
72 Term::Var(n.to_string())
73}
74fn app(f: Term, x: Term) -> Term {
75 Term::App(Box::new(f), Box::new(x))
76}
77fn apps(f: Term, xs: Vec<Term>) -> Term {
78 xs.into_iter().fold(f, app)
79}
80fn pi(p: &str, t: Term, b: Term) -> Term {
81 Term::Pi { param: p.to_string(), param_type: Box::new(t), body_type: Box::new(b) }
82}
83fn arrow(a: Term, b: Term) -> Term {
84 pi("_", a, b)
85}
86fn lam(p: &str, t: Term, b: Term) -> Term {
87 Term::Lambda { param: p.to_string(), param_type: Box::new(t), body: Box::new(b) }
88}
89
90enum ArgKind {
93 Elem,
95 Recursive,
97 Other(Term),
99}
100
101fn peel_pis(t: &Term) -> (Vec<(String, Term)>, Term) {
103 let mut params = Vec::new();
104 let mut cur = t.clone();
105 while let Term::Pi { param, param_type, body_type } = cur {
106 params.push((param, *param_type));
107 cur = *body_type;
108 }
109 (params, cur)
110}
111
112fn is_global(t: &Term, name: &str) -> bool {
113 matches!(t, Term::Global(n) if n == name)
114}
115
116fn analyze_container_ctor(ctor_ty: &Term, container: &str) -> KernelResult<(String, Vec<ArgKind>)> {
119 let (params, _residual) = peel_pis(ctor_ty);
120 if params.is_empty() {
121 return Err(KernelError::CertificationError(format!(
122 "nested-compile: container '{container}' constructor has no element parameter"
123 )));
124 }
125 let a = params[0].0.clone();
126 let mut kinds = Vec::new();
127 for (_, ty) in ¶ms[1..] {
128 let kind = match ty {
129 Term::Var(n) if *n == a => ArgKind::Elem,
130 Term::App(f, x) if is_global(f, container) && matches!(x.as_ref(), Term::Var(n) if *n == a) => {
131 ArgKind::Recursive
132 }
133 _ => ArgKind::Other(ty.clone()),
134 };
135 kinds.push(kind);
136 }
137 Ok((a, kinds))
138}
139
140fn occurs_anywhere(ty: &Term, name: &str) -> bool {
142 match ty {
143 Term::Global(n) => n == name,
144 Term::App(f, x) => occurs_anywhere(f, name) || occurs_anywhere(x, name),
145 Term::Pi { param_type, body_type, .. } => {
146 occurs_anywhere(param_type, name) || occurs_anywhere(body_type, name)
147 }
148 Term::Lambda { param_type, body, .. } => {
149 occurs_anywhere(param_type, name) || occurs_anywhere(body, name)
150 }
151 _ => false,
152 }
153}
154
155fn is_nested_container_type(ctx: &Context, decl: &NestedDecl, ty: &Term) -> bool {
160 let mut head = ty;
161 while let Term::App(f, _) = head {
162 head = f;
163 }
164 matches!(head, Term::Global(c) if c != &decl.name && ctx.is_inductive(c))
165 && occurs_anywhere(ty, &decl.name)
166}
167
168struct Spec {
173 repr: String,
174 generic: Term,
175 to: Option<String>,
176 from: Option<String>,
177}
178
179struct SibNode {
183 container: String,
184 repr: String,
185 elem_repr: String,
186 elem_generic: Term,
187 inner_to: Option<String>,
188 inner_from: Option<String>,
189 ctors: Vec<(String, Vec<ArgKind>)>,
190 to_name: String,
191 from_name: String,
192}
193
194fn specialize(
199 ctx: &Context,
200 decl: &NestedDecl,
201 ty: &Term,
202 nodes: &mut Vec<SibNode>,
203 seen: &mut std::collections::HashSet<String>,
204) -> KernelResult<Spec> {
205 if is_global(ty, &decl.name) {
206 return Ok(Spec { repr: decl.name.clone(), generic: g(&decl.name), to: None, from: None });
207 }
208 if let Term::App(f, inner_ty) = ty {
209 if let Term::Global(c) = f.as_ref() {
210 if c != &decl.name && ctx.is_inductive(c) {
211 let inner = specialize(ctx, decl, inner_ty, nodes, seen)?;
212 let repr = format!("{}${}", inner.repr, c);
213 let generic = app(g(c), inner.generic.clone());
214 let to_name = format!("{repr}_to_{c}");
215 let from_name = format!("{repr}_from_{c}");
216 if seen.insert(repr.clone()) {
217 let mut ctors = Vec::new();
221 for (orig_ctor, orig_ty) in ctx.get_constructors(c) {
222 let (_a, kinds) = analyze_container_ctor(orig_ty, c)?;
223 if kinds.iter().any(|k| matches!(k, ArgKind::Other(_))) {
224 return Err(KernelError::CertificationError(format!(
225 "nested-compile: container '{c}' constructor '{orig_ctor}' has an \
226 argument that is neither the element nor a recursive occurrence \
227 — specializing it is not supported (only pure containers like \
228 `List`/`TList`)"
229 )));
230 }
231 ctors.push((orig_ctor.to_string(), kinds));
232 }
233 nodes.push(SibNode {
234 container: c.clone(),
235 repr: repr.clone(),
236 elem_repr: inner.repr.clone(),
237 elem_generic: inner.generic.clone(),
238 inner_to: inner.to.clone(),
239 inner_from: inner.from.clone(),
240 ctors,
241 to_name: to_name.clone(),
242 from_name: from_name.clone(),
243 });
244 }
245 return Ok(Spec { repr, generic, to: Some(to_name), from: Some(from_name) });
246 }
247 }
248 }
249 Err(KernelError::CertificationError(format!(
250 "nested-compile: '{}' occurs in argument type {ty} in a position that is not a nesting \
251 inside a registered unary container (only `Container …` nestings are specialized)",
252 decl.name
253 )))
254}
255
256pub fn compile_nested(ctx: &Context, decl: &NestedDecl) -> KernelResult<Compiled> {
260 if decl.sort != Term::Sort(crate::term::Universe::Type(0)) {
265 return Err(KernelError::CertificationError(format!(
266 "nested-compile: '{}' must be a `Type 0` inductive (specialized siblings are \
267 `Type 0`); higher-universe nesting is not supported",
268 decl.name
269 )));
270 }
271
272 let mut nodes: Vec<SibNode> = Vec::new();
276 let mut seen = std::collections::HashSet::new();
277 let mut own_ctors = Vec::new();
278 for (cname, cty) in &decl.constructors {
279 let (params, residual) = peel_pis(cty);
280 let mut rebuilt = residual;
281 for (pname, pty) in params.into_iter().rev() {
282 let pty2 = if is_nested_container_type(ctx, decl, &pty) {
283 g(&specialize(ctx, decl, &pty, &mut nodes, &mut seen)?.repr)
284 } else {
285 pty
286 };
287 rebuilt = pi(&pname, pty2, rebuilt);
288 }
289 own_ctors.push((cname.clone(), rebuilt));
290 }
291
292 if nodes.is_empty() {
293 return Err(KernelError::CertificationError(format!(
294 "nested-compile: '{}' has no nested container occurrence — register it directly",
295 decl.name
296 )));
297 }
298
299 let mut block = vec![MutualInductive {
301 name: decl.name.clone(),
302 sort: decl.sort.clone(),
303 num_params: 0,
304 constructors: own_ctors,
305 }];
306 let mut siblings = Vec::new();
307 for node in &nodes {
308 siblings.push(node.repr.clone());
309 let mut sib_ctors = Vec::new();
310 for (orig, kinds) in &node.ctors {
311 let mut sty = g(&node.repr);
312 for kind in kinds.iter().rev() {
313 let arg_ty = match kind {
314 ArgKind::Elem => g(&node.elem_repr),
315 ArgKind::Recursive => g(&node.repr),
316 ArgKind::Other(t) => t.clone(),
317 };
318 sty = arrow(arg_ty, sty);
319 }
320 sib_ctors.push((format!("{}_{}", node.repr, orig), sty));
321 }
322 block.push(MutualInductive {
323 name: node.repr.clone(),
324 sort: Term::Sort(crate::term::Universe::Type(0)),
325 num_params: 0,
326 constructors: sib_ctors,
327 });
328 }
329
330 let mut isos = Vec::new();
333 let mut iso_names = Vec::new();
334 for node in &nodes {
335 let to_ty = arrow(g(&node.repr), app(g(&node.container), node.elem_generic.clone()));
336 let from_ty = arrow(app(g(&node.container), node.elem_generic.clone()), g(&node.repr));
337 isos.push((node.to_name.clone(), to_ty, build_to_generic(node)));
338 isos.push((node.from_name.clone(), from_ty, build_from_generic(node)));
339 iso_names.push(IsoNames {
340 container: node.container.clone(),
341 sibling: node.repr.clone(),
342 to_generic: node.to_name.clone(),
343 from_generic: node.from_name.clone(),
344 });
345 }
346
347 Ok(Compiled { block, isos, iso_names, siblings })
348}
349
350fn build_to_generic(node: &SibNode) -> Term {
354 let mut cases = Vec::new();
355 for (orig_ctor, kinds) in &node.ctors {
356 let mut body = apps(g(orig_ctor), vec![node.elem_generic.clone()]);
358 for (i, kind) in kinds.iter().enumerate() {
359 body = app(body, convert_to(kind, v(&format!("a{i}")), "rec", &node.inner_to));
360 }
361 for (i, kind) in kinds.iter().enumerate().rev() {
362 let ty = match kind {
363 ArgKind::Elem => g(&node.elem_repr),
364 ArgKind::Recursive => g(&node.repr),
365 ArgKind::Other(t) => t.clone(),
366 };
367 body = lam(&format!("a{i}"), ty, body);
368 }
369 cases.push(body);
370 }
371 Term::Fix {
372 name: "rec".to_string(),
373 body: Box::new(lam(
374 "x",
375 g(&node.repr),
376 Term::Match {
377 discriminant: Box::new(v("x")),
378 motive: Box::new(lam("_", g(&node.repr), app(g(&node.container), node.elem_generic.clone()))),
379 cases,
380 },
381 )),
382 }
383}
384
385fn build_from_generic(node: &SibNode) -> Term {
389 let mut cases = Vec::new();
390 for (orig_ctor, kinds) in &node.ctors {
391 let mut body = g(&format!("{}_{}", node.repr, orig_ctor));
392 for (i, kind) in kinds.iter().enumerate() {
393 body = app(body, convert_from(kind, v(&format!("a{i}")), "rec", &node.inner_from));
394 }
395 for (i, kind) in kinds.iter().enumerate().rev() {
396 let ty = match kind {
398 ArgKind::Elem => node.elem_generic.clone(),
399 ArgKind::Recursive => app(g(&node.container), node.elem_generic.clone()),
400 ArgKind::Other(t) => t.clone(),
401 };
402 body = lam(&format!("a{i}"), ty, body);
403 }
404 cases.push(body);
405 }
406 Term::Fix {
407 name: "rec".to_string(),
408 body: Box::new(lam(
409 "x",
410 app(g(&node.container), node.elem_generic.clone()),
411 Term::Match {
412 discriminant: Box::new(v("x")),
413 motive: Box::new(lam("_", app(g(&node.container), node.elem_generic.clone()), g(&node.repr))),
414 cases,
415 },
416 )),
417 }
418}
419
420fn convert_to(kind: &ArgKind, a: Term, rec: &str, inner_to: &Option<String>) -> Term {
423 match kind {
424 ArgKind::Recursive => app(v(rec), a),
425 ArgKind::Elem => match inner_to {
426 Some(iso) => app(g(iso), a),
427 None => a,
428 },
429 ArgKind::Other(_) => a,
430 }
431}
432
433fn convert_from(kind: &ArgKind, a: Term, rec: &str, inner_from: &Option<String>) -> Term {
436 match kind {
437 ArgKind::Recursive => app(v(rec), a),
438 ArgKind::Elem => match inner_from {
439 Some(iso) => app(g(iso), a),
440 None => a,
441 },
442 ArgKind::Other(_) => a,
443 }
444}