1use super::env::{Const, Hint, Kind, QuotKind, Safety};
4use super::error::{KResult, KernelFailure};
5use super::expr::{ExprId, Node};
6use super::level::{LevelId, LevelsId};
7use super::name::NameId;
8use super::tc::{Engine, Kernel, Theory};
9use super::wellknown::QuotNames;
10use std::rc::Rc;
11
12#[derive(Clone, Debug)]
13pub struct Header {
14 pub name: NameId,
15 pub lparams: Rc<[NameId]>,
16 pub ty: ExprId,
17}
18
19#[derive(Clone, Debug)]
20pub struct DefnDecl {
21 pub header: Header,
22 pub value: ExprId,
23 pub hint: Hint,
24 pub safety: Safety,
25}
26
27#[derive(Clone, Debug)]
28pub enum Decl {
29 Axiom {
30 header: Header,
31 is_unsafe: bool,
32 },
33 Defn(DefnDecl),
34 Thm {
35 header: Header,
36 value: ExprId,
37 },
38 Opaque {
39 header: Header,
40 value: ExprId,
41 is_unsafe: bool,
42 },
43 Mutual(Vec<DefnDecl>),
44 Quot {
45 header: Header,
46 kind: QuotKind,
47 },
48}
49
50impl Decl {
51 pub fn name(&self) -> NameId {
53 match self {
54 Decl::Axiom { header, .. }
55 | Decl::Thm { header, .. }
56 | Decl::Opaque { header, .. }
57 | Decl::Quot { header, .. } => header.name,
58 Decl::Defn(d) => d.header.name,
59 Decl::Mutual(ds) => ds.first().map_or(NameId::ANON, |d| d.header.name),
60 }
61 }
62
63 pub fn kind_name(&self) -> &'static str {
65 match self {
66 Decl::Axiom { .. } => "axiom",
67 Decl::Defn(_) => "def",
68 Decl::Thm { .. } => "thm",
69 Decl::Opaque { .. } => "opaque",
70 Decl::Mutual(_) => "mutual",
71 Decl::Quot { .. } => "quot",
72 }
73 }
74}
75
76impl Kernel {
77 pub fn check_name(&self, n: NameId, allow_primitive: bool) -> KResult<()> {
78 if self.env.contains(n) {
79 return Err(KernelFailure::reject(format!(
80 "'{}' has already been declared",
81 self.s.names.display(n)
82 )));
83 }
84 if !allow_primitive && self.theory == Theory::Lean && self.wk.primitives().contains(&n) {
85 return Err(KernelFailure::reject(format!(
86 "unexpected declaration of the primitive '{}' in a non-canonical form",
87 self.s.names.display(n)
88 )));
89 }
90 Ok(())
91 }
92
93 pub fn check_duplicate_lparams(&self, ps: &[NameId]) -> KResult<()> {
94 for (i, p) in ps.iter().enumerate() {
95 if ps[i + 1..].contains(p) {
96 return Err(KernelFailure::reject(format!(
97 "duplicate universe level parameter '{}'",
98 self.s.names.display(*p)
99 )));
100 }
101 }
102 Ok(())
103 }
104
105 fn check_closed(&self, e: ExprId) -> KResult<()> {
106 if self.s.has_fvar(e) || self.s.has_loose_bvars(e) {
107 return Err(KernelFailure::reject(
108 "declaration contains free or loose bound variables",
109 ));
110 }
111 Ok(())
112 }
113
114 fn check_constant_val(&mut self, h: &Header, allow_primitive: bool) -> KResult<LevelId> {
116 self.check_name(h.name, allow_primitive)?;
117 self.check_duplicate_lparams(&h.lparams)?;
118 self.check_closed(h.ty)?;
119 match self.engine {
120 Engine::Sem => self.with_sem(|sem| sem.check_type(h.ty)),
121 Engine::Classic | Engine::Dual => {
122 let sort = self.check(h.ty)?;
123 let sort = self.ensure_sort(sort)?;
124 Ok(self.sort_level(sort))
125 }
126 }
127 }
128
129 fn check_value(&mut self, h: &Header, value: ExprId) -> KResult<()> {
130 self.check_closed(value)?;
131 if self.engine == Engine::Sem {
132 return self.with_sem(|sem| sem.check_value(value, h.ty));
133 }
134 if self.theory == Theory::Logos && self.check_fix_against(value, h.ty)? {
135 return Ok(());
136 }
137 let vt = self.check(value)?;
138 if !self.conforms(vt, h.ty)? {
139 return Err(
140 KernelFailure::reject("declaration type mismatch").with_detail(format!(
141 "the value has type\n {}\n but is declared with type\n {}",
142 self.show(vt),
143 self.show(h.ty)
144 )),
145 );
146 }
147 Ok(())
148 }
149
150 pub fn with_decl<T>(
153 &mut self,
154 lparams: Rc<[NameId]>,
155 safety: Safety,
156 f: impl FnOnce(&mut Kernel) -> KResult<T>,
157 ) -> KResult<T> {
158 self.begin_decl(lparams, safety);
159 let r = f(self);
160 self.end_decl();
161 r
162 }
163
164 pub fn may_trust(&self, d: &Decl) -> bool {
167 !matches!(d, Decl::Quot { .. }) && !self.wk.primitives().contains(&d.name())
168 }
169
170 pub fn may_trust_block(&self, claimed: &[Const]) -> bool {
173 let prims = self.wk.primitives();
174 claimed.iter().all(|c| !prims.contains(&c.name))
175 }
176
177 pub fn admit_trusted(&mut self, d: Decl) {
179 self.admit(d);
180 }
181
182 pub fn admit_trusted_block(&mut self, claimed: Vec<Const>) {
185 for c in claimed {
186 self.env.add(c);
187 }
188 }
189
190 #[cfg(feature = "shadow")]
192 pub(crate) fn check_without_admitting(&mut self, decl: &Decl) -> KResult<()> {
193 let name = decl.name();
194 self.check_decl(decl)
195 .map_err(|e| e.in_declaration(self.s.names.display(name)))
196 }
197
198 pub fn add_decl(&mut self, decl: Decl) -> KResult<()> {
199 let name = decl.name();
200 self.add_decl_inner(decl)
201 .map_err(|e| e.in_declaration(self.s.names.display(name)))
202 }
203
204 fn add_decl_inner(&mut self, decl: Decl) -> KResult<()> {
205 if let Decl::Quot { header, kind } = decl {
206 return self.add_quot(header, kind, self.wk.eq);
207 }
208 if self.engine == Engine::Dual {
209 self.check_decl_by_both(&decl)?;
210 } else {
211 self.check_decl(&decl)?;
212 }
213 self.admit(decl);
214 Ok(())
215 }
216
217 fn check_decl_by_both(&mut self, decl: &Decl) -> KResult<()> {
221 self.engine = Engine::Sem;
222 let by_value = self.check_decl(decl);
223 self.engine = Engine::Classic;
224 let by_substitution = self.check_decl(decl);
225 self.engine = Engine::Dual;
226 let verdict = |r: &KResult<()>| match r {
227 Ok(()) => "accepts",
228 Err(e) if e.is_reject() => "rejects",
229 Err(_) => "declines",
230 };
231 match (by_value, by_substitution) {
232 (Ok(()), Ok(())) => Ok(()),
233 (Err(v), Err(s)) if v.is_reject() && s.is_reject() => Err(s),
234 (Err(e), _) | (_, Err(e)) if !e.is_reject() => Err(e),
235 (v, s) => Err(KernelFailure::resource(format!(
236 "the two engines disagree: evaluation {}, substitution {}",
237 verdict(&v),
238 verdict(&s)
239 ))
240 .with_detail(match (v, s) {
241 (Err(e), _) | (_, Err(e)) => e.to_string(),
242 _ => unreachable!(),
243 })),
244 }
245 }
246
247 fn check_decl(&mut self, decl: &Decl) -> KResult<()> {
250 match decl {
251 Decl::Axiom { header, is_unsafe } => {
252 let safety = if *is_unsafe {
253 Safety::Unsafe
254 } else {
255 Safety::Safe
256 };
257 self.with_decl(header.lparams.clone(), safety, |k| {
258 k.check_constant_val(header, false)
259 })?;
260 Ok(())
261 }
262 Decl::Defn(d) => self.check_definition(d),
263 Decl::Thm { header, value } => {
264 self.with_decl(header.lparams.clone(), Safety::Safe, |k| {
265 let level = k.check_constant_val(header, false)?;
266 if !k.s.levels.is_always_zero(level) {
267 return Err(KernelFailure::reject("theorem type is not a proposition")
268 .with_detail(format!("its type is {}", k.show(header.ty))));
269 }
270 k.check_value(header, *value)
271 })
272 }
273 Decl::Opaque { header, value, .. } => {
274 self.with_decl(header.lparams.clone(), Safety::Safe, |k| {
275 k.check_constant_val(header, false)?;
276 k.check_value(header, *value)
277 })
278 }
279 Decl::Mutual(ds) => self.check_mutual(ds),
280 Decl::Quot { .. } => unreachable!("quotients are admitted by add_quot"),
281 }
282 }
283
284 fn admit(&mut self, decl: Decl) {
285 let defn = |d: DefnDecl| Const {
286 name: d.header.name,
287 lparams: d.header.lparams,
288 ty: d.header.ty,
289 kind: Kind::Defn {
290 value: d.value,
291 hint: d.hint,
292 safety: d.safety,
293 },
294 };
295 match decl {
296 Decl::Axiom { header, is_unsafe } => self.env.add(Const {
297 name: header.name,
298 lparams: header.lparams,
299 ty: header.ty,
300 kind: Kind::Axiom { is_unsafe },
301 }),
302 Decl::Defn(d) => self.env.add(defn(d)),
303 Decl::Thm { header, value } => self.env.add(Const {
304 name: header.name,
305 lparams: header.lparams,
306 ty: header.ty,
307 kind: Kind::Thm { value },
308 }),
309 Decl::Opaque {
310 header,
311 value,
312 is_unsafe,
313 } => self.env.add(Const {
314 name: header.name,
315 lparams: header.lparams,
316 ty: header.ty,
317 kind: Kind::Opaque { value, is_unsafe },
318 }),
319 Decl::Mutual(ds) => {
320 for d in ds {
321 self.env.add(defn(d));
322 }
323 }
324 Decl::Quot { .. } => unreachable!("quotients are admitted by add_quot"),
325 }
326 }
327
328 fn check_definition(&mut self, d: &DefnDecl) -> KResult<()> {
329 let h = &d.header;
330 if d.safety == Safety::Unsafe {
331 self.with_decl(h.lparams.clone(), Safety::Unsafe, |k| {
332 k.check_constant_val(h, false)
333 })?;
334 self.env.add_provisional(Const {
335 name: h.name,
336 lparams: h.lparams.clone(),
337 ty: h.ty,
338 kind: Kind::Axiom { is_unsafe: true },
339 });
340 let r = self.with_decl(h.lparams.clone(), Safety::Unsafe, |k| {
341 k.check_value(h, d.value)
342 });
343 self.env.remove(h.name);
344 r
345 } else {
346 self.with_decl(h.lparams.clone(), Safety::Safe, |k| {
347 let allow = k.check_primitive_def(d)?;
348 k.check_constant_val(h, allow)?;
349 k.check_value(h, d.value)
350 })
351 }
352 }
353
354 fn check_mutual(&mut self, ds: &[DefnDecl]) -> KResult<()> {
355 let Some(first) = ds.first() else {
356 return Err(KernelFailure::reject("empty mutual definition"));
357 };
358 if first.safety == Safety::Safe {
359 return Err(KernelFailure::reject(
360 "invalid mutual definition, declaration is not tagged as unsafe/partial",
361 ));
362 }
363 let safety = first.safety;
364 let lparams = first.header.lparams.clone();
365 self.with_decl(lparams.clone(), safety, |k| {
366 let mut seen = Vec::new();
367 for d in ds {
368 if d.safety != safety {
369 return Err(KernelFailure::reject(
370 "mutual declarations must have the same safety annotation",
371 ));
372 }
373 if d.header.lparams != lparams {
374 return Err(KernelFailure::reject(
375 "mutual declarations must have the same universe parameters",
376 ));
377 }
378 if seen.contains(&d.header.name) {
379 return Err(KernelFailure::reject(
380 "duplicate declaration name in mutual block",
381 ));
382 }
383 seen.push(d.header.name);
384 k.check_constant_val(&d.header, false)?;
385 }
386 Ok(())
387 })?;
388 for d in ds {
389 self.env.add_provisional(Const {
390 name: d.header.name,
391 lparams: d.header.lparams.clone(),
392 ty: d.header.ty,
393 kind: Kind::Axiom {
394 is_unsafe: safety == Safety::Unsafe,
395 },
396 });
397 }
398 let r = self.with_decl(lparams, safety, |k| {
399 for d in ds {
400 k.check_value(&d.header, d.value)?;
401 }
402 Ok(())
403 });
404 for d in ds {
405 self.env.remove(d.header.name);
406 }
407 r
408 }
409
410 fn check_eq_type(&mut self, eq: NameId) -> KResult<()> {
415 let fail =
416 |m: &str| KernelFailure::reject(format!("failed to initialize quot module, {m}"));
417 let c = self
418 .env
419 .get(eq)
420 .cloned()
421 .ok_or_else(|| fail("environment does not have 'Eq' type"))?;
422 let Kind::Induct(info) = &c.kind else {
423 return Err(fail("'Eq' is not an inductive type"));
424 };
425 if c.lparams.len() != 1 {
426 return Err(fail("unexpected number of universe params at 'Eq' type"));
427 }
428 if info.ctors.len() != 1 {
429 return Err(fail("unexpected number of constructors for 'Eq' type"));
430 }
431 let u = self.s.levels.param(c.lparams[0]);
432 let sort_u = self.s.sort(u);
433 let alpha = self.push_local(sort_u, None);
434 let prop = self.s.prop();
435 let inner = self.s.pi(alpha, prop);
436 let arrow = self.s.pi(alpha, inner);
437 let expected = self.mk_pi(&[alpha], arrow);
438 if c.ty != expected {
439 return Err(fail("'Eq' has an unexpected type"));
440 }
441 let refl = self.get_const(info.ctors[0])?;
442 if refl.lparams.len() != 1 {
443 return Err(fail(
444 "unexpected number of universe params at 'Eq' type constructor",
445 ));
446 }
447 let u = self.s.levels.param(refl.lparams[0]);
448 let sort_u = self.s.sort(u);
449 let alpha = self.push_local(sort_u, None);
450 let a = self.push_local(alpha, None);
451 let eq_c = self.s.cnst_levels(eq, &[u]);
452 let body = self.s.mk_app_n(eq_c, &[alpha, a, a]);
453 let expected = self.mk_pi(&[alpha, a], body);
454 if refl.ty != expected {
455 return Err(fail("unexpected type for 'Eq' type constructor"));
456 }
457 Ok(())
458 }
459
460 fn quot_canonical(
463 &mut self,
464 kind: QuotKind,
465 ps: &[NameId],
466 set: QuotNames,
467 eq: NameId,
468 ) -> KResult<ExprId> {
469 let need = if kind == QuotKind::Lift { 2 } else { 1 };
470 if ps.len() != need {
471 return Err(KernelFailure::reject(
472 "unexpected number of universe parameters for a quotient constant",
473 ));
474 }
475 let u = self.s.levels.param(ps[0]);
476 let sort_u = self.s.sort(u);
477 let prop = self.s.prop();
478 let alpha = self.push_local(sort_u, None);
479 let a_prop = self.s.pi(alpha, prop);
480 let rel_ty = self.s.pi(alpha, a_prop);
481 let ul = self.s.levels.list(&[u]);
482 let quot = self.s.cnst(set.ty, ul);
483 Ok(match kind {
484 QuotKind::Type => {
485 let r = self.push_local(rel_ty, None);
486 self.mk_pi(&[alpha, r], sort_u)
487 }
488 QuotKind::Ctor => {
489 let r = self.push_local(rel_ty, None);
490 let a = self.push_local(alpha, None);
491 let qr = self.s.mk_app_n(quot, &[alpha, r]);
492 self.mk_pi(&[alpha, r, a], qr)
493 }
494 QuotKind::Lift => {
495 let v = self.s.levels.param(ps[1]);
496 let sort_v = self.s.sort(v);
497 let r = self.push_local(rel_ty, None);
498 let beta = self.push_local(sort_v, None);
499 let f_ty = self.s.pi(alpha, beta);
500 let f = self.push_local(f_ty, None);
501 let a = self.push_local(alpha, None);
502 let b = self.push_local(alpha, None);
503 let rab = self.s.mk_app_n(r, &[a, b]);
504 let vl = self.s.levels.list(&[v]);
505 let eqv = self.s.cnst(eq, vl);
506 let fa = self.s.app(f, a);
507 let fb = self.s.app(f, b);
508 let feq = self.s.mk_app_n(eqv, &[beta, fa, fb]);
509 let rab_to = self.s.pi(rab, feq);
510 let sanity = self.mk_pi(&[a, b], rab_to);
511 let qr = self.s.mk_app_n(quot, &[alpha, r]);
512 let qr_to_beta = self.s.pi(qr, beta);
513 let body = self.s.pi(sanity, qr_to_beta);
514 self.mk_pi(&[alpha, r, beta, f], body)
515 }
516 QuotKind::Ind => {
517 let r = self.push_local(rel_ty, None);
518 let qr = self.s.mk_app_n(quot, &[alpha, r]);
519 let qr_prop = self.s.pi(qr, prop);
520 let beta = self.push_local(qr_prop, None);
521 let a = self.push_local(alpha, None);
522 let mk = self.s.cnst(set.mk, ul);
523 let mk_a = self.s.mk_app_n(mk, &[alpha, r, a]);
524 let b_mk = self.s.app(beta, mk_a);
525 let all_quot = self.mk_pi(&[a], b_mk);
526 let q = self.push_local(qr, None);
527 let bq = self.s.app(beta, q);
528 let concl = self.mk_pi(&[q], bq);
529 let body = self.s.pi(all_quot, concl);
530 self.mk_pi(&[alpha, r, beta], body)
531 }
532 })
533 }
534
535 pub(crate) fn add_quotient(&mut self, h: Header, kind: QuotKind, eq: NameId) -> KResult<()> {
538 let name = h.name;
539 self.add_quot(h, kind, eq)
540 .map_err(|e| e.in_declaration(self.s.names.display(name)))
541 }
542
543 fn add_quot(&mut self, h: Header, kind: QuotKind, eq: NameId) -> KResult<()> {
544 let named = |set: &QuotNames| match kind {
545 QuotKind::Type => set.ty,
546 QuotKind::Ctor => set.mk,
547 QuotKind::Lift => set.lift,
548 QuotKind::Ind => set.ind,
549 };
550 let set = [Some(self.wk.quot_names()), self.wk.installed_quot]
551 .into_iter()
552 .flatten()
553 .find(|set| named(set) == h.name)
554 .ok_or_else(|| {
555 KernelFailure::reject("quotient declaration with a non-canonical name")
556 })?;
557 if kind != QuotKind::Type && !self.env.contains(set.ty) {
558 return Err(KernelFailure::reject(format!(
559 "quotient constant declared before '{}'",
560 self.s.names.display(set.ty)
561 )));
562 }
563 self.with_decl(h.lparams.clone(), Safety::Safe, |k| {
564 k.check_name(h.name, false)?;
565 k.check_duplicate_lparams(&h.lparams)?;
566 k.check_eq_type(eq)?;
567 let canonical = k.quot_canonical(kind, &h.lparams, set, eq)?;
568 if canonical != h.ty {
569 return Err(
570 KernelFailure::reject("quotient constant has a non-canonical type")
571 .with_detail(format!(
572 "expected {}\n found {}",
573 k.show(canonical),
574 k.show(h.ty)
575 )),
576 );
577 }
578 Ok(())
579 })?;
580 self.env.add(Const {
581 name: h.name,
582 lparams: h.lparams,
583 ty: h.ty,
584 kind: Kind::Quot(kind),
585 });
586 if [set.ty, set.mk, set.lift, set.ind]
587 .iter()
588 .all(|n| self.env.contains(*n))
589 && !self.env.quotients.contains(&set)
590 {
591 self.env.quotients.push(set);
592 }
593 self.env.quot_init = !self.env.quotients.is_empty();
594 Ok(())
595 }
596
597 pub fn const_levels_of(&mut self, ps: &[NameId]) -> LevelsId {
598 let ls: Vec<LevelId> = ps.iter().map(|p| self.s.levels.param(*p)).collect();
599 self.s.levels.list(&ls)
600 }
601
602 pub fn is_sort(&self, e: ExprId) -> bool {
603 matches!(self.s.node(e), Node::Sort(_))
604 }
605}