1pub mod context;
2mod impls;
3pub mod results {
4 pub use ftml_solver_trace::results::*;
5}
6pub mod paragraphs;
7pub mod rules;
8pub mod split;
9pub mod trace {
10 pub use ftml_solver_trace::*;
11}
12pub mod facts;
13pub mod hoas;
14pub mod judgment_cache;
16pub mod utils;
17
18const TRUNCATE_PROOFS: bool = false;
19static DEBUG: std::sync::atomic::AtomicBool = std::sync::atomic::AtomicBool::new(false);
20
21pub fn pause() {
22 use std::io::Read;
23 if DEBUG.load(std::sync::atomic::Ordering::Relaxed) {
24 println!("Press Key...");
25 let _ = std::io::stdin().read(&mut [0u8]);
26 }
27}
28
29use crate::{
30 context::ContextWrap,
31 facts::GlobalFacts,
32 hoas::HOASSymbols,
33 impls::{
34 proving::ProverState,
35 solving::{Solutions, TermExtSolvable, is_solvable_var},
36 },
37 judgment_cache::JudgmentCache,
38 results::{
39 CheckResult, ContentCheckResult, DocumentCheckResult, SymbolCheckResult, TypeCheckResult,
40 },
41 rules::RuleSet,
42 split::{CancelToken, RayonStrategiesDepth, SingleThreadedSplit, SplitStrategy},
43 trace::{CheckLogCow, CheckingTask, PreCheckLog},
44 utils::MutableRefList,
45};
46use flams_math_archives::{
47 artifacts::{ContentUpdate, FileOrString},
48 backend::{AnyBackend, LocalBackend},
49 formats::{BuildResult, TaskDependency},
50};
51use ftml_ontology::{
52 domain::{
53 HasDeclarations,
54 declarations::{AnyDeclarationRef, morphisms::Morphism, symbols::Symbol},
55 modules::Module,
56 },
57 narrative::{
58 documents::Document,
59 elements::{
60 DocumentElementRef, LogicalParagraph, VariableDeclaration, paragraphs::ParagraphKind,
61 },
62 },
63 terms::{ComponentVar, Term, TermContainer, helpers::IntoTerm, termpaths::TermPath},
64 utils::RefTree,
65};
66use ftml_solver_trace::CheckLog;
67use ftml_uris::{Id, IsDomainUri, LeafUri, ModuleUri};
68use smallvec::SmallVec;
69use std::marker::PhantomData;
70
71pub static DUMMY: std::sync::LazyLock<Id> =
72 std::sync::LazyLock::new(|| unsafe { "DUMMY".parse().unwrap_unchecked() });
74
75flams_math_archives::build_target!(CHECK {
76 name: "typecheck",
77 description: "check the validity of formal/complex expressions",
78 run: check
79});
80
81#[allow(clippy::needless_pass_by_value)]
82fn check(task: flams_math_archives::formats::BuildSpec) -> BuildResult {
83 let d = match task.backend.get_document(task.uri) {
84 Ok(d) => d,
85 Err(e) => {
86 return BuildResult {
87 log: FileOrString::Str(
88 format!("Document not found {}: {e}", task.uri).into_boxed_str(),
89 ),
90 result: Err(Vec::new()),
91 };
92 }
93 };
94 let mut checker =
95 Checker::<SingleThreadedSplit>::new(task.backend.clone());
96 match checker.check_document(&d) {
97 Ok((logs, modules)) => {
98 let log = logs.to_json();
99 BuildResult {
100 log: FileOrString::Str(log.into_boxed_str()),
101 result: Ok(Some(Box::new(ContentUpdate {
102 document: Some(d),
103 modules,
104 }) as _)),
105 }
106 }
107 Err(e) => BuildResult {
108 log: FileOrString::Str(format!("Module missing: {e}").into_boxed_str()),
109 result: Err(vec![TaskDependency::Logical {
110 uri: e,
111 strict: true,
112 }]),
113 },
114 }
115}
116
117type BigSet<T> = dashmap::DashSet<T, rustc_hash::FxBuildHasher>;
118
119pub struct SubtermCheckResult {
138 pub simplified: Term,
139 pub inferred_type: Option<Term>,
140 pub context: Vec<ComponentVar>,
141 pub log: CheckLog,
142}
143
144pub struct Checker<Split: SplitStrategy> {
145 backend: AnyBackend,
146 rules: RuleSet<Split>,
147 modules: BigSet<Module>,
148 documents: BigSet<Document>,
149 facts: GlobalFacts,
150 hoas: Option<HOASSymbols>,
151 implicits: std::sync::atomic::AtomicUsize,
152 current: Vec<LeafUri>,
153 context: Vec<ModuleUri>,
154 __phantom: PhantomData<Split>,
155}
156
157pub struct CheckRef<'c, 'i, Split: SplitStrategy> {
158 pub(crate) top: &'c Checker<Split>,
159 pub(crate) context: ContextWrap<'c, 'i>,
160 pub(crate) proof_state: &'i ProverState,
161 pub(crate) judgment_cache: JudgmentCache<'c, 'i>,
162 pub(crate) solutions: MutableRefList<'i, Solutions>,
163 messages: &'i mut SmallVec<CheckLogCow<'c>, 2>,
164 pub(crate) cancel: &'i CancelToken<'i, Split::CancelToken>,
165 added: u8,
166 traced: bool,
167}
168
169macro_rules! update {
170 ($slf:ident $t:ident if $bind:expr) => {
171 if $bind && let Some(t) = $slf.bind_implicits(&$t) {
172 $t = t;
174 }
175 };
176}
177
178#[derive(Default)]
179pub struct CheckerCache {
180 modules: BigSet<Module>,
181 documents: BigSet<Document>,
182}
183
184impl<Split: SplitStrategy> Checker<Split> {
185 fn reset(&self) {
186 self.implicits
187 .store(0, std::sync::atomic::Ordering::Release);
188 }
189 pub fn into_cache(self) -> CheckerCache {
190 CheckerCache {
191 modules: self.modules,
192 documents: self.documents,
193 }
194 }
195 pub fn set_cache(&mut self, cache: CheckerCache) {
196 self.modules = cache.modules;
197 self.documents = cache.documents;
198 }
199 #[must_use]
200 pub fn new(backend: AnyBackend) -> Self {
201 Self {
202 backend,
203 modules: BigSet::default(),
204 documents: BigSet::default(),
205 rules: RuleSet::default(),
206 current: Vec::default(),
207 facts: GlobalFacts::default(),
208 context: Vec::default(),
209 hoas: None,
210 implicits: std::sync::atomic::AtomicUsize::new(1),
211 __phantom: PhantomData,
212 }
213 }
214
215 fn set_hoas(&mut self) {
216 self.hoas = HOASSymbols::get(self);
217 }
218 pub const fn hoas(&self) -> Option<&HOASSymbols> {
219 self.hoas.as_ref()
220 }
221
222 #[allow(clippy::too_many_lines)]
225 pub fn check_document(
226 &mut self,
227 d: &Document,
228 ) -> Result<(DocumentCheckResult, Vec<Module>), ModuleUri> {
229 let mut modules = Vec::new();
238 let mut results = Vec::new();
239 self.documents.insert(d.clone());
240 for e in d.dfs() {
241 match e {
242 DocumentElementRef::Module { module, .. } => {
244 modules.push(module.clone());
246 }
247 _ => (),
248 }
249 }
250 let modules: Vec<_> = modules
252 .into_iter()
253 .filter_map(|uri| self.get_module(&uri).ok())
254 .collect();
255 tracing::trace!("Rules: {:?}", self.rules);
256 for e in d.dfs() {
257 match e {
258 DocumentElementRef::Module { module, .. }
259 | DocumentElementRef::UseModule { uri: module, .. } => {
260 self.set_context(vec![module.clone()])?;
261 }
266 DocumentElementRef::Morphism { morphism, .. } => {
267 let top = morphism.clone().simple_module();
268 let Some(m) = self
269 .get_module(top.module_uri())
270 .ok()
271 .and_then(|m| m.get_as::<Morphism>(top.name()))
272 else {
273 results.push(CheckResult::Missing(morphism.module.clone()));
274 continue;
275 };
276 results.extend(self.check_morphism(&m));
277 }
278 DocumentElementRef::VariableDeclaration(v) => {
279 if let Some(r) = self.check_variable(v) {
280 results.push(CheckResult::Variable(v.uri.clone(), r));
281 }
282 }
283 DocumentElementRef::SymbolDeclaration(uri) => {
284 let top = uri.clone().simple_module();
285 if let Some(s) = modules
286 .iter()
287 .find(|m| m.uri == top.module)
288 .and_then(|m| m.find::<Symbol>(top.name.steps()))
289 {
290 if let Some(r) = self.check_symbol(s) {
291 results.push(CheckResult::Content(ContentCheckResult::Symbol(
292 uri.clone(),
293 r,
294 )));
295 }
296 } else {
297 results.push(CheckResult::Missing(uri.module.clone()));
298 }
299 }
300 DocumentElementRef::Term(top) => {
301 self.reset();
303 tracing::debug!("Checking term {:?}", top.get_parsed().debug_short());
304 let (unks, tm) = self.prepare(None, top.get_parsed().clone());
306 let (t, unks, log) = self.infer_type(Some(unks), &tm);
307 let t = t.map(|t| {
308 self.wrap_none(Some(unks), |slf| slf.revert_prepare(slf.subst(t)))
309 .1
310 });
311 if let Some(t) = &t {
312 top.set_type(t.clone());
313 }
314 results.push(CheckResult::Term {
315 uri: top.uri.clone(),
316 inferred: t,
317 log: CheckLog::from_pre(log, &mut |t| self.revert_prepare(t)),
318 });
319 }
320 DocumentElementRef::Paragraph(
321 p @ LogicalParagraph {
322 kind: ParagraphKind::Proof,
323 fors,
324 ..
325 },
326 ) if fors.len() == 1 => {
327 self.reset();
329 results.extend(self.check_proof(p));
330 }
331 DocumentElementRef::Paragraph(
332 p @ LogicalParagraph {
333 kind: ParagraphKind::Assertion,
334 fors,
335 ..
336 },
337 ) if p.fors.iter().any(|(_, t)| t.is_some()) => {
338 self.reset();
340 if let Some(r) = self.check_assertion(p) {
341 results.extend(r);
342 }
343 }
344 DocumentElementRef::Paragraph(
345 p @ LogicalParagraph {
346 kind, fors, styles, ..
347 },
348 ) if kind.is_definition_like(styles) && p.fors.iter().any(|(_, t)| t.is_some()) => {
349 self.reset();
351 results.extend(self.check_definition(p));
352 }
353 _ => (),
354 }
355 }
356
357 Ok((
358 DocumentCheckResult {
359 uri: d.uri.clone(),
360 checks: results.into_boxed_slice(),
361 },
362 modules,
363 ))
364 }
365
366 pub fn check_module(&mut self, m: &Module) -> Result<Vec<ContentCheckResult>, ModuleUri> {
368 self.modules.insert(m.clone());
369 self.set_context(vec![m.uri.clone()])?;
370 let mut ret = Vec::new();
372 for d in m.dfs().filter_map(|e| {
373 if let AnyDeclarationRef::Symbol(s) = e {
374 Some(s)
375 } else {
376 None
377 }
378 }) {
379 if let Some(r) = self.check_symbol(d) {
380 ret.push(ContentCheckResult::Symbol(d.uri.clone(), r));
381 }
382 }
383 Ok(ret)
384 }
385
386 pub fn check_subterm_term(&mut self, term: Term, sub: Term) -> Option<SubtermCheckResult> {
387 self.reset();
388 let (unks, nterm) = self.wrap_none(None, |mut slf| {
389 let (s, r) = slf.prepare(term, None);
390 slf.merge_solutions(s);
391 r
392 });
393 let (unks, nsub) = self.wrap_none(Some(unks), |mut slf| {
394 let (s, r) = slf.prepare(sub, None);
395 slf.merge_solutions(s);
396 r
397 });
398 let ctx = nterm
399 .path_of_subterm_with_ctx(&nsub)
400 .map_or(Vec::new(), |p| p.0);
401 Some(self.check_subterm_i(unks, &nsub, ctx))
402 }
403
404 pub fn check_subterm_path(
405 &mut self,
406 term: Term,
407 mut path: TermPath,
408 ) -> Option<SubtermCheckResult> {
409 self.reset();
411 let (unks, nterm) = self.wrap_none(None, |mut slf| {
412 let (s, r) = slf.prepare(term, Some(&mut path));
413 slf.merge_solutions(s);
414 r
415 });
416 let (ctx, t) = nterm.subterm_at_path(&path)?;
417 Some(self.check_subterm_i(unks, t, ctx))
419 }
420
421 fn check_subterm_i(
422 &self,
423 unks: Solutions,
424 sub: &Term,
425 ctx: Vec<&ComponentVar>,
426 ) -> SubtermCheckResult {
427 let mut ctx = ctx.into_iter().cloned().rev().collect::<Vec<_>>();
428 let mut nt = sub.clone();
429 let (r, s, log) = self.wrap_task(CheckingTask::Inference(sub), Some(unks), |mut slf| {
430 let allvars = sub.free_variables();
431 for v in allvars {
432 if is_solvable_var(v).is_none() && !ctx.iter().any(|cv| cv.var == *v) {
433 let tp = slf.infer_var_type_i(v);
434 let df = slf.get_var_definiens(v);
435 ctx.push(ComponentVar {
436 var: v.clone(),
437 tp,
438 df,
439 });
440 }
441 }
442 let mut i = 0;
443 while let Some(vd) = ctx.get(i) {
444 i += 1;
445 let tp = vd.tp.clone();
446 let df = vd.df.clone();
447 if let Some(t) = tp {
448 let allvars = t
449 .free_variables()
450 .into_iter()
451 .filter(|v| !ctx.iter().any(|cv| cv.var == **v))
452 .cloned()
453 .collect::<smallvec::SmallVec<_, 2>>();
454 for v in allvars {
455 if is_solvable_var(&v).is_none() {
456 let tp = slf.infer_var_type_i(&v);
457 let df = slf.get_var_definiens(&v);
458 ctx.push(ComponentVar { var: v, tp, df });
459 }
460 }
461 }
462 if let Some(t) = df {
463 let allvars = t
464 .free_variables()
465 .into_iter()
466 .filter(|v| !ctx.iter().any(|cv| cv.var == **v))
467 .cloned()
468 .collect::<smallvec::SmallVec<_, 2>>();
469 for v in allvars {
470 if is_solvable_var(&v).is_none() {
471 let tp = slf.infer_var_type_i(&v);
472 let df = slf.get_var_definiens(&v);
473 ctx.push(ComponentVar { var: v, tp, df });
474 }
475 }
476 }
477 }
478 ctx.reverse();
479 for c in &ctx {
480 slf.extend_context(c);
481 }
482
483 let tp = slf
484 .infer_type(sub)
485 .map(|t| slf.subst(slf.revert_prepare(t)));
486 let simp = slf
487 .simplify_full(impls::simplify::Expansion::NoNoexpands, sub)
488 .unwrap_or_else(|| sub.clone());
489 nt = slf.subst(slf.revert_prepare(simp));
490 tp
491 });
492 let (_, log) = self.wrap_none(None, |slf| {
506 for c in &mut ctx {
507 if let Some(tp) = c.tp.take() {
508 c.tp = Some(slf.revert_prepare(tp));
509 }
510 if let Some(df) = c.df.take() {
511 c.df = Some(slf.revert_prepare(df));
512 }
513 }
514 CheckLog::from_pre(log, &mut |t| slf.revert_prepare(t))
515 });
516 SubtermCheckResult {
518 simplified: nt,
519 inferred_type: r,
520 context: ctx,
521 log,
522 }
523 }
524
525 fn check_components(
526 &self,
527 tpc: &TermContainer,
528 dfc: &TermContainer,
529 bind: bool,
530 ) -> Option<SymbolCheckResult> {
531 self.reset();
532 let tp = tpc.get_parsed();
533 let df = dfc.get_parsed();
534 let df = if df.is_some_and(Term::is_marker) {
535 None
536 } else {
537 df
538 };
539 match (tp, df) {
541 (Some(tp), None) => {
542 tracing::debug!("Checking Type: {:?}", tp.debug_short());
543 let (unks, tp) = self.prepare(None, tp.clone());
545 let (b, unks, mut l) = self.check_inhabitable(Some(unks), &tp);
546 let mut tp = self.wrap_none(Some(unks), |slf| slf.subst(tp)).1;
547 if tp.has_solvable() {
548 l.push(PreCheckLog::Msg(
549 vec![format!("Unsolved unkowns remain: {:?}", tp.solvables()).into()],
550 ftml_solver_trace::MessageLevel::Failure,
551 ));
552 return Some(SymbolCheckResult::TypeOnly {
553 result: TypeCheckResult {
554 success: false,
555 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
556 },
557 });
558 }
559 update!(self tp if bind);
560 tpc.set_checked(tp);
561 Some(SymbolCheckResult::TypeOnly {
562 result: TypeCheckResult {
563 success: b.unwrap_or(false),
564 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
565 },
566 })
567 }
568 (None, Some(df)) => Some(self.df_only(df, dfc, tpc, bind, false)),
569 (Some(tp), Some(df)) => {
570 tracing::debug!("Checking Type and Definiens");
571 if ftml_uris::metatheory::AUTO_PROVE.term_is(df) {
572 Some(self.infer_df(dfc, tp, tpc, bind))
573 } else {
574 Some(self.df_and_tp(df, dfc, tp, tpc, bind, false))
576 }
577 }
578 (None, None) => None,
579 }
580 }
581
582 fn df_only(
583 &self,
584 df: &Term,
585 dfc: &TermContainer,
586 tpc: &TermContainer,
587 bind: bool,
588 set_presentation: bool,
589 ) -> SymbolCheckResult {
590 tracing::debug!("Checking Definiens");
591 let (unks, df) = self.prepare(None, df.clone());
593
594 let (tp, unks, mut l) = self.infer_type(Some(unks), &df);
595 let mut df = self.wrap_none(Some(unks), |slf| slf.subst(df)).1;
596
597 if df.has_solvable() {
598 l.push(PreCheckLog::Msg(
599 vec![format!("Unsolved unkowns remain: {:?}", df.solvables()).into()],
600 ftml_solver_trace::MessageLevel::Failure,
601 ));
602 return SymbolCheckResult::DefiniensOnly {
603 inferred: None,
604 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
605 };
606 }
607
608 update!(self df if bind);
609 if set_presentation {
610 dfc.set_presentation(self.revert_prepare(df.clone()));
611 }
612 dfc.set_checked(df);
613
614 if let Some(mut tp) = tp {
615 if tp.has_solvable() {
616 l.push(PreCheckLog::Msg(
617 vec![format!("Unsolved unkowns remain: {:?}", tp.solvables()).into()],
618 ftml_solver_trace::MessageLevel::Failure,
619 ));
620 return SymbolCheckResult::DefiniensOnly {
621 inferred: None,
622 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
623 };
624 }
625 update!(self tp if bind);
626 tpc.set_checked(tp.clone());
627 let tp = self.revert_prepare(tp);
628 tpc.set_presentation(tp.clone());
629 SymbolCheckResult::DefiniensOnly {
630 inferred: Some(tp),
631 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
632 }
633 } else {
634 SymbolCheckResult::DefiniensOnly {
635 inferred: None,
636 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
637 }
638 }
639 }
640
641 fn infer_df(
642 &self,
643 dfc: &TermContainer,
644 tp: &Term,
645 tpc: &TermContainer,
646 bind: bool,
647 ) -> SymbolCheckResult {
648 let (tunks, tp) = self.prepare(None, tp.clone());
649 let (b, tunks, mut l) = self.check_inhabitable(Some(tunks), &tp);
650 if b.is_some_and(|b| !b) {
651 let mut tp = self.wrap_none(Some(tunks), |slf| slf.subst(tp)).1;
652 update!(self tp if bind);
653 tpc.set_checked(tp);
654 return SymbolCheckResult::Both {
655 inhabitable: TypeCheckResult {
656 success: false,
657 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
658 },
659 matches: None,
660 };
661 }
662 let (tunks, mut tp) = self.wrap_none(Some(tunks), |slf| slf.subst(tp));
663
664 if tp.has_solvable() {
665 l.push(PreCheckLog::Msg(
666 vec![format!("Unsolved unkowns remain: {:?}", tp.solvables()).into()],
667 ftml_solver_trace::MessageLevel::Failure,
668 ));
669 return SymbolCheckResult::TypeOnly {
670 result: TypeCheckResult {
671 success: false,
672 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
673 },
674 };
675 }
676 let (ndf, _, mut l2) = self.prove(Some(tunks), &tp);
677
678 update!(self tp if bind);
679 tpc.set_checked(tp);
680 if let Some(mut df) = ndf {
681 if df.has_solvable() {
682 l2.push(PreCheckLog::Msg(
683 vec![format!("Unsolved unkowns remain: {:?}", df.solvables()).into()],
684 ftml_solver_trace::MessageLevel::Failure,
685 ));
686 return SymbolCheckResult::Both {
687 inhabitable: TypeCheckResult {
688 success: true,
689 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
690 },
691 matches: Some(TypeCheckResult {
692 success: false,
693 log: CheckLog::from_pre(l2, &mut |t| self.revert_prepare(t)),
694 }),
695 };
696 }
697
698 update!(self df if bind);
699 dfc.set_checked(df.clone());
700 let df = self.revert_prepare(df);
701 dfc.set_presentation(df);
702 SymbolCheckResult::Both {
703 inhabitable: TypeCheckResult {
704 success: true,
705 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
706 },
707 matches: Some(TypeCheckResult {
708 success: true,
709 log: CheckLog::from_pre(l2, &mut |t| self.revert_prepare(t)),
710 }),
711 }
712 } else {
713 SymbolCheckResult::Both {
714 inhabitable: TypeCheckResult {
715 success: true,
716 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
717 },
718 matches: Some(TypeCheckResult {
719 success: false,
720 log: CheckLog::from_pre(l2, &mut |t| self.revert_prepare(t)),
721 }),
722 }
723 }
724 }
725
726 fn df_and_tp(
727 &self,
728 df: &Term,
729 dfc: &TermContainer,
730 tp: &Term,
731 tpc: &TermContainer,
732 bind: bool,
733 set_df_presentation: bool,
734 ) -> SymbolCheckResult {
735 let (tunks, tp) = self.prepare(None, tp.clone());
736 let (b, tunks, mut l) = self.check_inhabitable(Some(tunks), &tp);
737 if b.is_some_and(|b| !b) {
738 let mut tp = self.wrap_none(Some(tunks), |slf| slf.subst(tp)).1;
739 if tp.has_solvable() {
740 l.push(PreCheckLog::Msg(
741 vec![format!("Unsolved unkowns remain: {:?}", tp.solvables()).into()],
742 ftml_solver_trace::MessageLevel::Failure,
743 ));
744 return SymbolCheckResult::TypeOnly {
745 result: TypeCheckResult {
746 success: false,
747 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
748 },
749 };
750 }
751
752 update!(self tp if bind);
753 tpc.set_checked(tp);
754 return SymbolCheckResult::Both {
755 inhabitable: TypeCheckResult {
756 success: false,
757 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
758 },
759 matches: None,
760 };
761 }
762 let (tunks, mut tp) = self.wrap_none(Some(tunks), |slf| slf.subst(tp));
763 tracing::debug!("Checking definiens");
764 let (dunks, df) = self.prepare(Some(tunks), df.clone());
765
766 let (b, unks, mut l2) = self.check_type(Some(dunks), &df, &tp);
767 let (unks, mut df) = self.wrap_none(Some(unks), |slf| slf.subst(df));
768
769 if df.has_solvable() {
770 l2.push(PreCheckLog::Msg(
771 vec![format!("Unsolved unkowns remain: {:?}", df.solvables()).into()], ftml_solver_trace::MessageLevel::Failure,
777 ));
778 return SymbolCheckResult::Both {
779 inhabitable: TypeCheckResult {
780 success: true,
781 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
782 },
783 matches: Some(TypeCheckResult {
784 success: false,
785 log: CheckLog::from_pre(l2, &mut |t| self.revert_prepare(t)),
786 }),
787 };
788 }
789
790 update!(self tp if bind);
791 update!(self df if bind);
792 tracing::debug!("Result:\n{:?}\n : {:?}", df.debug_short(), tp.debug_short());
793 tpc.set_checked(tp);
794 if set_df_presentation {
795 dfc.set_presentation(self.revert_prepare(df.clone()));
796 }
797 dfc.set_checked(df);
798 SymbolCheckResult::Both {
799 inhabitable: TypeCheckResult {
800 success: true,
801 log: CheckLog::from_pre(l, &mut |t| self.revert_prepare(t)),
802 },
803 matches: Some(TypeCheckResult {
804 success: b.unwrap_or(false),
805 log: CheckLog::from_pre(l2, &mut |t| self.revert_prepare(t)),
806 }),
807 }
808 }
809
810 pub fn check_symbol(&mut self, s: &Symbol) -> Option<SymbolCheckResult> {
812 tracing::debug!("Checking Symbol {}", s.uri);
813 tracing::trace!("{s:?}");
814 self.current.push(s.uri.clone().into());
815 let r = self.check_components(&s.data.tp, &s.data.df, true);
816 self.current.pop();
817 self.add_fact(s);
818 r
819 }
820
821 pub fn check_variable(&mut self, s: &VariableDeclaration) -> Option<SymbolCheckResult> {
823 tracing::debug!("Checking Variable {}", s.uri);
824 self.current.push(s.uri.clone().into());
825 let r = self.check_components(&s.data.tp, &s.data.df, false);
826 self.current.pop();
827 r
828 }
829
830 fn check_type(
831 &self,
832 unknowns: Option<Solutions>,
833 tm: &Term,
834 tp: &Term,
835 ) -> (Option<bool>, Solutions, PreCheckLog) {
836 self.wrap_task(CheckingTask::HasType(tm, tp), unknowns, |mut slf| {
837 slf.check_type_i(tm, tp)
838 })
839 }
840
841 fn prove(
842 &self,
843 unknowns: Option<Solutions>,
844 goal: &Term,
845 ) -> (Option<Term>, Solutions, PreCheckLog) {
846 self.wrap_task(CheckingTask::Proving(goal), unknowns, |mut slf| {
847 slf.prove(goal)
848 })
849 }
850
851 fn check_subtype(
852 &self,
853 unknowns: Option<Solutions>,
854 sub: &Term,
855 sup: &Term,
856 ) -> (Option<bool>, Solutions, PreCheckLog) {
857 self.wrap_task(CheckingTask::Subtype(sub, sup), unknowns, |mut slf| {
858 slf.check_subtype_i(sub, sup)
859 })
860 }
861
862 fn infer_type(
863 &self,
864 unknowns: Option<Solutions>,
865 t: &Term,
866 ) -> (Option<Term>, Solutions, PreCheckLog) {
867 self.wrap_task(CheckingTask::Inference(t), unknowns, |mut slf| {
868 slf.infer_type_i(t).map(|t| slf.subst(t))
869 })
870 }
871
872 fn check_inhabitable(
873 &self,
874 unknowns: Option<Solutions>,
875 t: &Term,
876 ) -> (Option<bool>, Solutions, PreCheckLog) {
877 self.wrap_task(CheckingTask::Inhabitable(t), unknowns, |mut slf| {
878 slf.check_inhabitable_i(t)
879 })
880 }
881
882 fn prepare(&self, unks: Option<Solutions>, t: Term) -> (Solutions, Term) {
883 self.wrap_none(unks, |mut slf| {
884 let (sols, r) = slf.prepare(t, None);
885 slf.merge_solutions(sols);
886 r
887 })
888 }
889 fn revert_prepare(&self, t: Term) -> Term {
890 self.wrap_none(None, |slf| slf.revert_prepare(t)).1
891 }
892
893 fn check_morphism(&self, m: &Morphism) -> Vec<CheckResult> {
894 let mut ret = Vec::new();
895 let Some(map) = m.elaboration.get_map() else {
896 ret.push(CheckResult::Missing(m.uri.clone().into_module()));
897 return ret;
898 };
899 for d in m.declarations() {
900 match d {
901 AnyDeclarationRef::Symbol(s) if map.values().any(|(u, b)| *b && *u == s.uri) => {
902 if let Some(r) = self.check_components(&s.data.tp, &s.data.df, true) {
906 ret.push(CheckResult::Content(ContentCheckResult::Symbol(
907 s.uri.clone(),
908 r,
909 )));
910 }
911 }
912 _ => (),
913 }
914 }
915 ret
916 }
917
918 pub fn add_modules(&mut self, modules: Vec<Module>) -> Result<(), ModuleUri> {
920 let mut todos = Vec::new();
921 for m in modules {
922 let _ = self.modules.remove(&m);
923 todos.push(m.uri.clone());
924 self.modules.insert(m);
925 }
926 self.set_context(todos)?;
927 Ok(())
928 }
929
930 pub fn set_context(&mut self, m: Vec<ModuleUri>) -> Result<(), ModuleUri> {
932 let new = self.sort(m);
933 for i in self.context.len() - new..self.context.len() {
934 let uri = &self.context[i];
935 let m = match self.get_module(uri).map_err(|()| uri.clone()) {
936 Ok(m) => m,
937 Err(m) => {
938 if uri.is_top() {
939 return Err(m);
940 }
941 continue;
942 }
943 };
944 if let Err(m) = m.initialize(&mut |uri| self.get_module_like(uri).ok()) {
945 if m.is_top() {
946 return Err(m);
947 }
948 continue;
949 }
950 self.load_context(&m);
951 }
952 Ok(())
953 }
954
955 fn load_context(&mut self, m: &Module) {
956 tracing::trace!("Loading: {}", m.uri);
958 for d in m.dfs() {
959 match d {
960 AnyDeclarationRef::Symbol(s) => {
972 let markers = self.rules.marker().len();
973 for e in Split::SYMBOL_EXTRACTORS {
974 e(s, &mut self.rules);
975 }
976 if self.rules.marker().len() > markers {
977 self.set_hoas();
978 }
979 self.add_fact(s);
980 }
981 AnyDeclarationRef::Rule { id, parameters, .. } => {
982 tracing::debug!("Rule: {id}");
983 let markers = self.rules.marker().len();
984 if let Some(rule) = Split::RULE_EXTRACTORS
985 .iter()
986 .find_map(|(s, f)| if id.as_ref() == *s { Some(f) } else { None })
987 {
988 let parameters = parameters
989 .iter()
990 .map(|t| self.prepare(None, t.clone()).1)
991 .collect::<Vec<_>>();
992 rule(¶meters, &mut self.rules);
993 }
994 if self.rules.marker().len() > markers {
995 self.set_hoas();
996 }
997 }
998 _ => (),
999 }
1000 }
1001 }
1002
1003 fn sort(&mut self, modules: Vec<ModuleUri>) -> usize {
1004 let mut ctx = std::mem::take(&mut self.context);
1005 let new = Module::topo_sort(modules, &mut ctx, |uri| self.get_module(uri).ok());
1006 self.context = ctx;
1007 new
1008 }
1009}