ftml_solver/impls/
inference.rs1use ftml_ontology::terms::{ComponentVar, Term, Variable};
2
3use crate::{
4 CheckRef, impls::solving::is_solvable_var, rules::InferenceRule, split::SplitStrategy,
5 trace::CheckingTask,
6};
7
8impl<'t, Split: SplitStrategy> CheckRef<'t, '_, Split> {
9 pub fn infer_type(&mut self, t: &'t Term) -> Option<Term> {
10 tracing::debug!("Inferring type of {:?}", t.debug_short());
11 let r = self.wrap_check(CheckingTask::Inference(t), |slf| slf.infer_type_i(t));
12 if let Some(r) = &r {
13 tracing::debug!("Inferred: {:?}", r.debug_short());
14 } else {
15 tracing::debug!("Inferrence failed");
16 }
17 r
18 }
19 pub(crate) fn infer_type_i(&mut self, t: &'t Term) -> Option<Term> {
20 match t {
21 Term::Symbol { uri, .. } => {
22 self.comment("Looking up symbol");
23 let ret = self.get_symbol_type(uri);
24
25 if ret.is_none() {
26 self.failure("Symbol has no type");
27 }
28 return ret;
29 }
30 Term::Var { variable, .. } => {
31 return self.infer_var_type_i(variable);
32 }
33 _ => (),
34 }
35 self.simplify_rules(
36 self.top.rules.inference(),
37 t,
38 InferenceRule::applicable,
39 |slf, rl, t| rl.infer(slf, t),
40 )
41 }
57
58 pub fn infer_var_type(&mut self, var: &'t Variable) -> Option<Term> {
59 self.wrap_check(CheckingTask::VariableInference(var.name()), |slf| {
60 slf.infer_var_type_i(var)
61 })
62 }
63 pub(crate) fn infer_var_type_i(&mut self, var: &Variable) -> Option<Term> {
64 if let Some(id) = is_solvable_var(var) {
65 return Some(self.get_solvable_type(id));
66 }
67 let (ctx, mut msgs) = self.split();
68 for v in ctx.iter().rev().map(|v| &**v) {
69 match (v, var) {
70 (
71 ComponentVar {
72 var: Variable::Name { name, .. },
73 tp,
74 ..
75 },
76 Variable::Name { name: n2, .. },
77 ) if *name == *n2 => {
78 if tp.is_some() {
79 msgs.comment("Found type in context");
80 } else {
81 msgs.failure("variable untyped in context");
82 }
83 return tp.clone().map(|t| self.subst(t));
84 }
85 (
86 ComponentVar {
87 var: Variable::Name { name, .. },
88 tp,
89 ..
90 },
91 Variable::Ref { declaration, .. },
92 ) if name.as_ref() == declaration.name().last() && tp.is_some() => {
93 if tp.is_some() {
94 msgs.comment("Found type in context");
95 } else {
96 msgs.failure("Variable untyped in context");
97 }
98 return tp.clone().map(|t| self.subst(t));
99 }
100 (
101 ComponentVar {
102 var: Variable::Ref { declaration, .. },
103 tp,
104 ..
105 },
106 Variable::Name { name, .. },
107 ) if name.as_ref() == declaration.name().last() => {
108 return if tp.is_some() {
109 msgs.comment("Found type in context");
110 tp.clone().map(|t| self.subst(t))
111 } else {
112 msgs.comment("Getting variable globally");
113 let declaration = declaration.clone();
114 let var = self.get_variable(&declaration).ok()?;
115 var.data.tp.checked_or_parsed().map(|(t, _)| {
116 if var.data.is_seq && t.as_sequence_type().is_none() {
117 t.into_seq_type()
118 } else {
119 t
120 }
121 })
122 };
123 }
124 (
125 ComponentVar {
126 var: Variable::Ref { declaration, .. },
127 tp,
128 ..
129 },
130 Variable::Ref {
131 declaration: d2, ..
132 },
133 ) if *declaration == *d2 => {
134 return if tp.is_some() {
135 msgs.comment("Found type in context");
136 tp.clone().map(|t| self.subst(t))
137 } else {
138 msgs.comment("Getting variable globally");
139 let declaration = declaration.clone();
140 let var = self.get_variable(&declaration).ok()?;
141 var.data.tp.checked_or_parsed().map(|(t, _)| {
142 if var.data.is_seq && t.as_sequence_type().is_none() {
143 t.into_seq_type()
144 } else {
145 t
146 }
147 })
148 };
149 }
150 _ => (),
151 }
152 }
153 if let Variable::Ref { declaration, .. } = var {
154 self.comment("Getting variable globally");
155 let var = self.get_variable(declaration).ok()?;
156 var.data.tp.checked_or_parsed().map(|(t, _)| {
157 if var.data.is_seq && t.as_sequence_type().is_none() {
158 t.into_seq_type()
159 } else {
160 t
161 }
162 })
163 } else {
164 Some(self.new_solvable())
165 }
166 }
167}