1use crate::*;
26use formally::support::*;
27
28use std::panic::AssertUnwindSafe;
29use std::{collections::HashMap, iter::zip, sync::Arc};
30
31pub trait Resolve: Sized {
36 fn resolve(&self, env: &Env, pool: &dyn TermPool, role: Role) -> Result<Self>;
53}
54
55impl Resolve for Term {
56 fn resolve(&self, env: &Env, pool: &dyn TermPool, role: Role) -> Result<Term> {
57 if self.is_resolved() {
58 return Ok(self.clone());
59 }
60
61 Ok(match self.kind() {
62 TermKind::Constant(_) => self.clone(),
63 TermKind::Atom(atom) => Self::resolve_atom(atom, env, role, pool)?.into_term_in(pool),
64 TermKind::Quantified(quant) => {
65 TermKind::Quantified(Self::resolve_quant(quant, env, role, pool)?)
66 .into_term_in(pool)
67 }
68 TermKind::Let(let_) => {
69 TermKind::Let(Self::resolve_let(let_, env, role, pool)?).into_term_in(pool)
70 }
71 })
72 }
73}
74
75impl Term {
76 fn resolve_atom(atom: &Atom, env: &Env, role: Role, pool: &dyn TermPool) -> Result<Atom> {
77 match &atom.head {
78 FunctionRef::Bound(bound) => Self::resolve_bound(bound, env, &atom.arguments, pool),
79 FunctionRef::Unbound(unbound) => {
80 Self::resolve_unbound(unbound, env, &atom.arguments, role, pool)
81 }
82 }
83 }
84
85 fn resolve_bound(
86 head: &BoundRef,
87 env: &Env,
88 arguments: &[Term],
89 pool: &dyn TermPool,
90 ) -> Result<Atom> {
91 let domain = head.domain(arguments.len());
92
93 if domain.len() != arguments.len() {
94 error!(
95 head.span(),
96 "applied {} arguments to a function of {} parameters",
97 arguments.len(),
98 domain.len(),
99 );
100 return Err(DiagnosticEmitted);
101 }
102
103 let mut resolved = Vec::new();
104 for (sort, arg) in zip(domain, arguments) {
105 if sort == Sort::sort() {
106 resolved.push(arg.resolve(env, pool, Role::Sort)?);
107 } else {
108 resolved.push(arg.resolve(env, pool, Role::Function)?);
109 }
110 }
111
112 Ok(Atom {
113 head: FunctionRef::Bound(head.clone()),
114 arguments: Arc::from(resolved.into_boxed_slice()),
115 span: head.span.clone(),
116 })
117 }
118
119 fn resolve_unbound(
120 head: &Identifier<'static>,
121 env: &Env,
122 arguments: &[Term],
123 role: Role,
124 pool: &dyn TermPool,
125 ) -> Result<Atom> {
126 let mut resolved = Vec::with_capacity(arguments.len());
127 let mut argsorts = Vec::with_capacity(arguments.len());
128 for arg in arguments {
129 let t = arg.resolve(env, pool, role)?;
130 argsorts.push(Sort::of(&t)?);
131 resolved.push(t);
132 }
133
134 env.lookup(head.clone(), role)
135 .filter_map(move |f| Self::candidate(f, env, head, &argsorts, &resolved, pool))
136 .one()
137 }
138
139 fn candidate(
140 f: &Function,
141 env: &Env,
142 head: &Identifier<'_>,
143 argsorts: &[Sort],
144 arguments: &[Term],
145 pool: &dyn TermPool,
146 ) -> Option<Atom> {
147 let bound = BoundRef {
148 function: f.clone(),
149 span: head.span(),
150 };
151 let atom = Diagnostic::with(
152 NullEmitter,
153 AssertUnwindSafe(|| Self::resolve_bound(&bound, env, arguments, pool)),
154 )
155 .ok()?;
156
157 #[allow(clippy::mutable_key_type)]
158 let mut matches = HashMap::new();
159 let domain = bound.domain(arguments.len());
160 for (sort, arg) in zip(domain, argsorts) {
161 if !sort.matches_with(arg, &mut matches) {
162 return None;
163 }
164 }
165
166 Some(atom)
167 }
168
169 fn resolve_quant(
170 quant: &Quantified,
171 env: &Env,
172 role: Role,
173 pool: &dyn TermPool,
174 ) -> Result<Quantified> {
175 let mut nested = Env::new().with_parent(env.clone());
176
177 let mut variables = Vec::with_capacity(quant.variables.len());
178 for var in &*quant.variables {
179 let var = var.resolve(env, pool, role)?;
180 variables.push(var.clone());
181 nested
182 .functions
183 .add(var.name().name(), Function::from(var.clone()));
184 }
185
186 let body = quant.body.resolve(&nested, pool, role)?;
187
188 Ok(Quantified {
189 quantifier: quant.quantifier,
190 variables: Arc::from(variables.into_boxed_slice()),
191 body,
192 span: quant.span.clone(),
193 })
194 }
195
196 fn resolve_let(let_: &Let, env: &Env, role: Role, pool: &dyn TermPool) -> Result<Let> {
197 let mut nested = Env::new().with_parent(env.clone());
198
199 for bind in &*let_.bindings {
200 nested.functions.add(
201 bind.variable.name().name(),
202 Function::from(bind.variable.clone()),
203 );
204 }
205
206 let body = let_.body.resolve(&nested, pool, role)?;
207
208 Ok(Let {
209 bindings: let_.bindings.clone(),
210 body,
211 span: let_.span.clone(),
212 })
213 }
214}
215
216impl Resolve for Variable {
217 fn resolve(&self, env: &Env, pool: &dyn TermPool, _role: Role) -> Result<Self> {
218 Ok(Variable::new(
219 self.name().clone(),
220 self.sort().resolve(env, pool, Role::Sort)?,
221 )
222 .over(self.span()))
223 }
224}
225
226impl Resolve for Sort {
227 fn resolve(&self, env: &Env, pool: &dyn TermPool, role: Role) -> Result<Self> {
228 if role == Role::Function {
229 internal!(None, "cannot resolve a sort with Role::Function");
230 return Err(DiagnosticEmitted);
231 }
232
233 let term = self.to_term_in(pool);
234 let resolved = term.resolve(env, pool, Role::Sort)?;
235 let sort = Sort::try_from(resolved).ok().unwrap();
236
237 Ok(sort)
238 }
239}
240
241impl Resolve for Declared {
242 fn resolve(&self, _env: &Env, _pool: &dyn TermPool, _role: Role) -> Result<Self> {
243 Ok(self.clone())
244 }
245}
246
247impl Resolve for Defined {
248 fn resolve(&self, _env: &Env, _pool: &dyn TermPool, _role: Role) -> Result<Self> {
249 Ok(self.clone())
250 }
251}