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