Skip to main content

ftml_solver/impls/
typing.rs

1use std::borrow::Cow;
2
3use crate::{
4    CheckRef,
5    impls::solving::TermExtSolvable,
6    rules::{InhabitableRule, UniverseRule},
7    split::SplitStrategy,
8    trace::CheckingTask,
9};
10use ftml_ontology::terms::Term;
11use smallvec::SmallVec;
12
13impl<'t, Split: SplitStrategy> CheckRef<'t, '_, Split> {
14    pub fn check_type(&mut self, tm: &'t Term, tp: &'t Term) -> Option<bool> {
15        tracing::debug!(
16            "Checking Typing {:?}   ::   {:?}",
17            tm.debug_short(),
18            tp.debug_short()
19        );
20        //crate::pause();
21        self.wrap_check(CheckingTask::HasType(tm, tp), |slf| {
22            slf.check_type_i(tm, tp)
23        })
24    }
25
26    pub fn check_subtype(&mut self, sub: &'t Term, sup: &'t Term) -> Option<bool> {
27        tracing::debug!(
28            "Checking Subtyping {:?}   <:   {:?}",
29            sub.debug_short(),
30            sup.debug_short()
31        );
32        //crate::pause();
33
34        self.wrap_check(CheckingTask::Subtype(sub, sup), |slf| {
35            slf.check_subtype_i(sub, sup)
36        })
37    }
38
39    pub fn check_inhabitable(&mut self, t: &'t Term) -> Option<bool> {
40        tracing::debug!("Checking Inhabitability of {:?}", t.debug_short());
41        if t.has_solvable() {
42            let nt = self.subst(t.clone());
43            self.scoped(|slf| {
44                slf.wrap_check(CheckingTask::Inhabitable(&nt), |slf| {
45                    slf.check_inhabitable_i(&nt)
46                })
47            })
48        } else {
49            self.wrap_check(CheckingTask::Inhabitable(t), |slf| {
50                slf.check_inhabitable_i(t)
51            })
52        }
53    }
54
55    pub fn check_universe(&mut self, t: &'t Term) -> Option<bool> {
56        tracing::debug!("Checking Universe {:?}", t.debug_short());
57        //self.wrap_check(CheckingTask::Universe(t), |slf| slf.check_universe_i(t))
58        if t.has_solvable() {
59            let nt = self.subst(t.clone());
60            self.scoped(|slf| {
61                slf.wrap_check(CheckingTask::Universe(&nt), |slf| slf.check_universe_i(&nt))
62            })
63        } else {
64            self.wrap_check(CheckingTask::Universe(t), |slf| slf.check_universe_i(t))
65        }
66    }
67
68    pub(crate) fn check_type_i(&mut self, tm: &'t Term, tp: &'t Term) -> Option<bool> {
69        //self.cancellable(|slf| {
70        Split::strategies(
71            self,
72            "Using checking rules",
73            |slf| {
74                if let either::Left(r) = slf.simplify_rules_two(
75                    self.top.rules.checking(),
76                    tm,
77                    tp,
78                    |slf, rl, tm, tp| rl.applicable(slf, tm, tp),
79                    |slf, rl, tm, tp| rl.apply(slf, tm, tp),
80                    |_, _| false,
81                ) {
82                    r
83                } else {
84                    None
85                }
86                /*
87                let rules = slf
88                    .top
89                    .rules
90                    .checking()
91                    .iter()
92                    .filter_map(|rl| {
93                        if rl.applicable(slf, tm, tp) {
94                            Some(&**rl)
95                        } else {
96                            None
97                        }
98                    })
99                    .collect::<smallvec::SmallVec<_, 2>>();
100                Split::split(slf, true, rules, |slf, rl| rl.apply(slf, tm, tp))
101                */
102            },
103            "Using type inference",
104            |slf| {
105                let subtp = slf.infer_type(tm)?;
106                slf.scoped(|slf| slf.check_subtype(&subtp, tp))
107            },
108        )
109        //})
110    }
111
112    pub(crate) fn check_subtype_i(&mut self, sub: &'t Term, sup: &'t Term) -> Option<bool> {
113        if sub.alpha_equal(sup) {
114            self.comment("trivial");
115            tracing::debug!("trivial");
116            return Some(true);
117        }
118        if let Some(unk) = sub.is_solvable() {
119            return self.solve_upper_bound(unk, sup);
120        }
121        if let Some(unk) = sup.is_solvable() {
122            return self.solve_lower_bound(unk, sub);
123        }
124        match self.simplify_rules_two(
125            self.top.rules.subtyping(),
126            sub,
127            sup,
128            |slf, rl, sub, sup| rl.applicable(slf, sub, sup),
129            |slf, rl, sub, sup| rl.apply(slf, sub, sup),
130            |sub, sup| {
131                sub.alpha_equal(sup) || sub.is_solvable().is_some() || sup.is_solvable().is_some()
132            },
133        ) {
134            either::Left(opt) => {
135                if opt.is_some() {
136                    return opt;
137                }
138                tracing::debug!("Proving subtyping failed; Falling back to checking equality");
139                match self.traced(
140                    CheckingTask::Strategy(
141                        "Proving subtyping failed; Falling back to checking equality",
142                    ),
143                    |slf| slf.check_equality_i(sub, sup),
144                ) {
145                    Ok(r) => Some(r),
146                    Err(ls) => {
147                        self.add_msg(ls.into());
148                        None
149                    }
150                }
151            }
152            either::Right((sub, sup)) => {
153                if sub.alpha_equal(&sup) {
154                    self.comment("trivial");
155                    tracing::debug!("trivial");
156                    return Some(true);
157                }
158                self.scoped(|slf| {
159                    if let Some(unk) = sub.is_solvable() {
160                        tracing::debug!("solving");
161                        return slf.solve_upper_bound(unk, &sup);
162                    }
163                    if let Some(unk) = sup.is_solvable() {
164                        tracing::debug!("solving");
165                        return slf.solve_lower_bound(unk, &sub);
166                    }
167                    tracing::debug!("Proving subtyping failed; Falling back to checking equality");
168                    match slf.traced(
169                        CheckingTask::Strategy(
170                            "Proving subtyping failed; Falling back to checking equality",
171                        ),
172                        |slf| slf.check_equality_i(&sub, &sup),
173                    ) {
174                        Ok(r) => Some(r),
175                        Err(ls) => {
176                            slf.add_msg(ls.into());
177                            None
178                        }
179                    }
180                })
181            }
182        }
183
184        /*
185        let sub = self
186            .simplify_full(false, sub)
187            .map_or(Cow::Borrowed(sub), Cow::Owned);
188        let sup = self
189            .simplify_full(false, sup)
190            .map_or(Cow::Borrowed(sup), Cow::Owned);
191        if self.alpha_equal(&sub, &sup) {
192            self.comment("trivial");
193            return Some(true);
194        }
195        self.scoped(|slf| {
196            if let Some(unk) = sub.is_solvable() {
197                tracing::debug!("solving");
198                return slf.solve_upper_bound(unk, &sup);
199            }
200            if let Some(unk) = sup.is_solvable() {
201                tracing::debug!("solving");
202                return slf.solve_lower_bound(unk, &sub);
203            }
204            let rules = slf
205                .top
206                .rules
207                .subtyping()
208                .iter()
209                .filter_map(|rl| {
210                    if rl.applicable(slf, &sub, &sup) {
211                        Some(&**rl)
212                    } else {
213                        None
214                    }
215                })
216                .collect::<smallvec::SmallVec<_, 2>>();
217            let lines = match Split::split_i(slf, true, rules, |slf, rl| rl.apply(slf, &sub, &sup))
218            {
219                Ok(r) => return Some(r),
220                Err(ls) => ls,
221            };
222            match slf.traced(
223                CheckingTask::Strategy(
224                    "Proving subtyping failed; Falling back to checking equality",
225                ),
226                |slf| slf.check_equality_i(&sub, &sup),
227            ) {
228                Ok(b) => Some(b),
229                Err(l) => {
230                    for l in lines {
231                        slf.add_msg(l.into());
232                    }
233                    slf.add_msg(l.into());
234                    None
235                }
236            }
237        })
238         */
239    }
240
241    pub(crate) fn check_inhabitable_i(&mut self, tm: &'t Term) -> Option<bool> {
242        Split::strategies(
243            self,
244            "Using type inference",
245            |slf| {
246                let tp = slf.infer_type(tm)?;
247                slf.scoped(|slf| slf.check_universe(&tp))
248            },
249            "Using inhabitable rules",
250            |slf| {
251                slf.simplify_rules(
252                    slf.top.rules.inhabitable(),
253                    tm,
254                    InhabitableRule::applicable,
255                    |slf, rl, t| rl.apply(slf, t),
256                )
257            },
258        )
259    }
260
261    fn check_universe_i(&mut self, tm: &'t Term) -> Option<bool> {
262        //self.comment(format!("{:?}", self.top.rules.universe()));
263        self.simplify_rules(
264            self.top.rules.universe(),
265            tm,
266            UniverseRule::applicable,
267            |slf, rl, t| rl.apply(slf, t),
268        )
269
270        /*let rules = self
271            .top
272            .rules
273            .universe()
274            .iter()
275            .filter_map(|rl| if rl.applicable(t) { Some(&**rl) } else { None });
276        Split::split(self, true, rules, |slf, rl| rl.apply(slf, t))*/
277    }
278}