1use 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 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 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 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 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 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 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 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 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 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 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 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 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(¶ms, &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, ¶m_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 ¶m_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, ¶m_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, ¶m_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}