Skip to main content

ftml_solver/
lib.rs

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;
14//pub mod patterns;
15pub 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    // SAFETY: "DUMMY" is a valid ID
73    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::</*RayonStrategiesDepth<4>*/ 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
119/*
120static MINIMAL_STACK: std::sync::atomic::AtomicUsize =
121    std::sync::atomic::AtomicUsize::new(usize::MAX - 10);
122pub fn minimal_stack() -> usize {
123    MINIMAL_STACK.load(std::sync::atomic::Ordering::Acquire)
124}
125pub(crate) fn update_stack() {
126    let curr = MINIMAL_STACK.load(std::sync::atomic::Ordering::Acquire);
127    let Some(rem) = stacker::remaining_stack() else {
128        return;
129    };
130    let min = curr.min(rem);
131    if min < curr {
132        MINIMAL_STACK.store(min, std::sync::atomic::Ordering::Release);
133    }
134}
135 */
136
137pub 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            //println!("update: {:?}", t); //t.debug_short());
173            $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    /// #### Errors
223    /// if a module dependency is missing
224    #[allow(clippy::too_many_lines)]
225    pub fn check_document(
226        &mut self,
227        d: &Document,
228    ) -> Result<(DocumentCheckResult, Vec<Module>), ModuleUri> {
229        /*tracing::error!(
230            "Current: {}",
231            bytesize::ByteSize::b(stacker::remaining_stack().expect("wut") as _)
232                .display()
233                .iec_short()
234        );*/
235
236        //let mut all = Vec::new();
237        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::UseModule { uri: module, .. } => all.push(module.clone()),
243                DocumentElementRef::Module { module, .. } => {
244                    //all.push(module.clone());
245                    modules.push(module.clone());
246                }
247                _ => (),
248            }
249        }
250        //self.set_context_i(all)?;
251        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                    //let _ = self.get_module(module).map_err(|_| module.clone())?;
262                    /*if self.get_module(module).is_err() {
263                        results.push(CheckResult::Missing(module.clone()));
264                    }*/
265                }
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.set_hoas();
302                    self.reset();
303                    tracing::debug!("Checking term {:?}", top.get_parsed().debug_short());
304                    //println!("All rules: {:#?}", self.rules);
305                    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.set_hoas();
328                    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.set_hoas();
339                    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.set_hoas();
350                    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    // TODO return checked Module
367    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        //self.set_hoas();
371        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.set_hoas();
410        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        //ctx.reverse();
418        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        /*
493        let mut frees = nt.free_variables();
494        for v in r.as_ref().map(|t| t.free_variables()).unwrap_or_default() {
495            if !frees.contains(&v) {
496                frees.push(v);
497            }
498        }
499         */
500        /*let context = ctx
501        .into_iter()
502        //.filter(|v| frees.iter().any(|f| f.name() == v.var.name()))
503        .cloned()
504        .collect();*/
505        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        //drop(frees);
517        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        //self.set_hoas();
540        match (tp, df) {
541            (Some(tp), None) => {
542                tracing::debug!("Checking Type: {:?}", tp.debug_short());
543                //tracing::debug!("Facts: {:#?}", self.facts);
544                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                    //tracing::debug!("Facts: {:#?}", self.facts);
575                    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        //tracing::debug!("Facts: {:#?}", self.facts);
592        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()], /*format!(
772                                                                                           "Unsolved unkowns remain in {:?}\n\n{unks:#?}",
773                                                                                           df.debug_short()
774                                                                                       )
775                                                                                       .into()*/
776                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    // TODO return checked term
811    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    // TODO return checked term
822    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                    // TODO:
903                    // - check that a *refined type* is a subtype of the original type's translation
904                    // - check that an *assigned definies* is ???? the original definiens
905                    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    /// #### Errors
919    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    /// #### Errors
931    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        //, todos: &mut Vec<ModuleUri>) {
957        tracing::trace!("Loading: {}", m.uri);
958        for d in m.dfs() {
959            match d {
960                /*
961                AnyDeclarationRef::Import { uri: m, .. } if !self.modules.contains(m) => {
962                    if m.is_top() {
963                        todos.push(m.clone());
964                    } else {
965                        let uri = !m.clone();
966                        if !self.modules.contains(&uri) {
967                            todos.push(uri);
968                        }
969                    }
970                } */
971                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(&parameters, &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}