1use crate::*;
26use formally::support::*;
27
28use derive_more::{Display, From};
29use transitive::Transitive;
30
31use std::{
32 collections::HashMap,
33 fmt::{Debug, Display, Formatter},
34 iter::zip,
35 sync::Arc,
36};
37
38pub trait ToSort: Resolve + TypeCheck + TryInto<Sort, Error: Emit> {}
54
55impl<T: Resolve + TypeCheck + TryInto<Sort, Error: Emit>> ToSort for T {}
56
57#[derive(Clone, Copy)]
62pub struct Infer;
63
64impl Resolve for Infer {
65 fn resolve(&self, _env: &Env, _pool: &dyn TermPool, _role: Role) -> Result<Self> {
66 Ok(*self)
67 }
68}
69
70impl TypeCheck for Infer {
71 fn type_check(&self) -> Result<Sort> {
72 internal!(None, "type checking of an inference placeholder");
73 Err(DiagnosticEmitted)
74 }
75}
76
77impl TryFrom<Infer> for Sort {
78 type Error = Diagnostic;
79
80 fn try_from(_value: Infer) -> Result<Self, Diagnostic> {
81 Err(Diagnostic::new(
82 None,
83 "type checking of an inference place holder".to_string(),
84 ))
85 }
86}
87
88#[derive(Clone, Debug, Hash, PartialEq, Eq, Transitive)]
90#[allow(clippy::duplicated_attributes)]
91pub enum SortArgument {
92 Value(Arc<Integer>),
94 Sort(Sort),
96}
97
98impl SortArgument {
99 #[allow(clippy::mutable_key_type)]
100 pub(crate) fn matches_with(
101 &self,
102 instance: &SortArgument,
103 matches: &mut HashMap<Variable, Sort>,
104 ) -> bool {
105 match (self, instance) {
106 (SortArgument::Value(this), SortArgument::Value(inst)) => this == inst,
107 (SortArgument::Sort(this), SortArgument::Sort(inst)) => {
108 this.matches_with(inst, matches)
109 }
110 _ => false,
111 }
112 }
113}
114
115impl From<Integer> for SortArgument {
116 fn from(value: Integer) -> Self {
117 SortArgument::Value(Arc::new(value))
118 }
119}
120
121impl<T: Into<Sort>> From<T> for SortArgument {
122 fn from(value: T) -> Self {
123 SortArgument::Sort(value.into())
124 }
125}
126
127#[derive(Debug, Clone, Hash, PartialEq, Eq, From, Transitive)]
134#[allow(clippy::duplicated_attributes)]
135#[transitive(from(Variable, Function))]
136#[transitive(from(Primitive, Function))]
137#[transitive(from(UserFunction, Function))]
138#[transitive(from(Declared, UserFunction))]
139#[transitive(from(Defined, UserFunction))]
140pub enum SortHead {
141 Bound(Function),
142 Unbound(Identifier<'static>),
143}
144
145impl SortHead {
146 pub fn name(&self) -> &Identifier<'static> {
147 match self {
148 SortHead::Bound(bound) => bound.name(),
149 SortHead::Unbound(name) => name,
150 }
151 }
152}
153
154impl From<FunctionRef> for SortHead {
155 fn from(funcref: FunctionRef) -> Self {
156 match funcref {
157 FunctionRef::Bound(bound) => SortHead::Bound(bound.function),
158 FunctionRef::Unbound(unbound) => SortHead::Unbound(unbound),
159 }
160 }
161}
162
163impl From<SortHead> for FunctionRef {
164 fn from(head: SortHead) -> Self {
165 match head {
166 SortHead::Bound(function) => FunctionRef::Bound(BoundRef {
167 function,
168 span: None,
169 }),
170 SortHead::Unbound(name) => FunctionRef::Unbound(name),
171 }
172 }
173}
174
175impl Display for SortHead {
176 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
177 match self {
178 SortHead::Bound(func) => write!(f, "{}", func.name()),
179 SortHead::Unbound(name) => write!(f, "{name}"),
180 }
181 }
182}
183
184#[allow(clippy::duplicated_attributes)]
195#[derive(Clone, Hash, PartialEq, Eq)]
196pub struct Sort {
197 pub head: SortHead,
199 pub arguments: SArc<[SortArgument]>,
201}
202
203impl<T: Into<Function>> From<T> for Sort {
204 fn from(value: T) -> Self {
205 Sort {
206 head: SortHead::Bound(value.into()),
207 arguments: SArc::default(),
208 }
209 }
210}
211
212impl From<Identifier<'_>> for Sort {
213 fn from(value: Identifier<'_>) -> Self {
214 Sort {
215 head: SortHead::Unbound(value.into_owned()),
216 arguments: SArc::default(),
217 }
218 }
219}
220
221impl Debug for Sort {
222 fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
223 if *self == Sort::sort() {
224 write!(f, "Sort::sort()")
225 } else {
226 f.debug_struct("Sort").field("head", &self.head).finish()
227 }
228 }
229}
230
231#[derive(Debug, Clone, Located, Display)]
233#[display("sort term must be an atom")]
234pub struct InvalidSortTerm {
235 span: Option<Span>,
236}
237
238impl Diagnosable for InvalidSortTerm {}
239
240impl TryFrom<Term> for Sort {
241 type Error = InvalidSortTerm;
242
243 fn try_from(term: Term) -> Result<Sort, InvalidSortTerm> {
244 let TermKind::Atom(atom) = term.kind() else {
245 return Err(InvalidSortTerm { span: term.span() });
246 };
247
248 let mut arguments = Vec::with_capacity(atom.arguments.len());
249 for arg in &*atom.arguments {
250 match arg.kind() {
251 TermKind::Constant(c) => match c {
252 Constant::Integer { value, .. } => {
253 arguments.push(SortArgument::Value((*value).clone()))
254 }
255 Constant::Rational { .. } => return Err(InvalidSortTerm { span: term.span() }),
256 },
257 _ => arguments.push(SortArgument::Sort(Sort::try_from(arg.clone())?)),
258 }
259 }
260
261 let head = SortHead::from(atom.head.clone());
262
263 Ok(Sort {
264 head,
265 arguments: SArc::from(arguments.into_boxed_slice()),
266 })
267 }
268}
269
270impl Sort {
271 pub fn of(term: &Term) -> Result<Sort> {
273 term.type_check()
274 }
275
276 #[allow(clippy::mutable_key_type)]
277 pub(crate) fn matches_with(
278 &self,
279 argument: &Sort,
280 matches: &mut HashMap<Variable, Sort>,
281 ) -> bool {
282 let SortHead::Bound(func) = &self.head else {
283 return false;
284 };
285
286 let SortHead::Bound(argfunc) = &argument.head else {
287 return false;
288 };
289
290 match (&func, &argfunc) {
291 (Function::Variable(this), _) => {
292 if let Some(this) = matches.get(this).cloned() {
293 this.head == argument.head
294 && this.arguments.len() == argument.arguments.len()
295 && zip(&*this.arguments, &*argument.arguments)
296 .all(|(this, arg)| this.matches_with(arg, matches))
297 } else {
298 matches.insert(this.clone(), argument.clone());
299 true
300 }
301 }
302 (Function::Primitive(this), Function::Primitive(inst)) => {
303 this == inst
304 && self.arguments.len() == argument.arguments.len()
305 && zip(self.arguments.iter(), argument.arguments.iter())
306 .all(|(this, inst)| this.matches_with(inst, matches))
307 }
308 (Function::User(this), Function::User(inst)) => match (this, inst) {
309 (UserFunction::Declared(this), UserFunction::Declared(inst)) => {
310 this == inst
311 && self.arguments.len() == argument.arguments.len()
312 && zip(self.arguments.iter(), argument.arguments.iter())
313 .all(|(this, inst)| this.matches_with(inst, matches))
314 }
315 (UserFunction::Defined(_), UserFunction::Defined(_)) => {
316 todo!() }
318 _ => false,
319 },
320 _ => false,
321 }
322 }
323
324 #[allow(clippy::mutable_key_type)]
325 pub(crate) fn instantiate(&self, matches: &HashMap<Variable, Sort>) -> Result<Sort> {
326 match &self.head {
327 SortHead::Bound(func) if let Function::Variable(var) = &func => {
328 return matches.get(var).cloned().ok_or_else(|| {
329 internal!(
330 None,
331 "usage of unconstrained sort parameter: {}",
332 var.name()
333 );
334 DiagnosticEmitted
335 });
336 }
337 _ => {}
338 }
339
340 let mut arguments = Vec::with_capacity(self.arguments.len());
341 for arg in &*self.arguments {
342 match arg {
343 SortArgument::Value(term) => arguments.push(SortArgument::Value(term.clone())),
344 SortArgument::Sort(sort) => {
345 arguments.push(SortArgument::Sort(sort.instantiate(matches)?))
346 }
347 }
348 }
349
350 Ok(Sort {
351 head: self.head.clone(),
352 arguments: SArc::from(arguments.into_boxed_slice()),
353 })
354 }
355}