formally_smt/decl.rs
1//
2// ::formally - the open-source formal methods toolchain
3//
4// Copyright (c) 2025 Nicola Gigante
5//
6// Permission is hereby granted, free of charge, to any person obtaining a copy
7// of this software and associated documentation files (the "Software"), to deal
8// in the Software without restriction, including without limitation the rights
9// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10// copies of the Software, and to permit persons to whom the Software is
11// furnished to do so, subject to the following conditions:
12//
13// The above copyright notice and this permission notice shall be included in
14// all copies or substantial portions of the Software.
15//
16// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
19// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
22// SOFTWARE.
23//
24
25use crate::*;
26
27use formally::support::*;
28
29use derive_more::{Deref, From};
30use transitive::Transitive;
31
32use std::{fmt::Debug, sync::Arc};
33
34/// Associativity attribute of a primitive function.
35///
36/// These correspond to the `:left-assoc`, `:right-assoc`, `:chainable` and `:pairwise`
37/// annotations supported by SMT-LIBv2 theory declarations. They are mostly used to express
38/// associativity and similar syntactic properties of functions such as binary arithmetic
39/// operations, equality, etc.
40///
41/// See Section 3.7 "Theory Declarations" of the SMT-LIBv2
42/// [specification manual](https://smt-lib.org/language.shtml).
43///
44/// These annotations look like syntactic properties, but in fact have nothing to do with the
45/// parser. When parsing `(+ a b c d)`, the parser only sees a term applying function `+` to four
46/// arguments. Then, the name resolver ([Resolve::resolve()]) and the type checker
47/// ([TypeCheck::type_check()]) look for those attributes and understand that, even if `+` is
48/// declared as a *binary* function, it can take more than two arguments in the way that the
49/// annotation specifies.
50///
51/// See also the [theories!] macro to see how to specify these annotations when declaring theory
52/// symbols.
53#[derive(Copy, Clone, Debug)]
54pub enum Associativity {
55 /// Equivalent to the `:left-assoc` annotation.
56 LeftAssoc,
57 /// Equivalent to the `:right-assoc` annotation.
58 RightAssoc,
59 /// Equivalent to the `:chainable` annotation.
60 Chainable,
61 /// Equivalent to the `:pairwise` annotation.
62 Pairwise,
63}
64
65/// A free variable.
66///
67/// [Variable] represents a free variable in a term that can be bound by `let` expressions,
68/// quantified by `forall` or `exists` quantifiers, or bound to function parameters.
69///
70/// [Variable] objects can be created using the [Variable::new()] constructor or with the [var!] or
71/// [vars!] macros.
72///
73/// For example:
74/// ```
75/// # mod formally {
76/// # pub extern crate formally_support as support;
77/// # pub extern crate formally_smt as smt;
78/// # }
79/// # use formally::{smt::*, support::*};
80/// # fn main() -> Result<()> {
81/// let config = Config::default();
82/// let mut solver = Solver::new(&config)?;
83///
84/// solver.define(Definition::function("f", [var!(x Int)], sort!(Int), term!(* x 2)));
85///
86/// solver.require(term!(not (= (f 21) 42)))?;
87///
88/// assert_eq!(solver.check()?, Answer::No);
89///
90/// # Ok(())
91/// # }
92/// ```
93///
94/// The [Variable] type is parametric in a [ToSort] type `S` used to represent the sort of the
95/// variable, such as [Sort] itself or the result of the [sort!] macro. See the documentation of
96/// [ToSort] for details.
97///
98/// Comparison of [Variable] objects is *nominal*, that is, equality and hashing operate on the
99/// identity of the objects, not on their values. In other words, two [Variable] objects with
100/// exactly the same fields (and in particular the same *name*) created by two different calls to
101/// [Variable::new()] will compare *different* and have a possibly different hash. Moreover,
102/// cloning a [Variable] object is a cheap operation and produces a second object which compares
103/// *equal* to the first. Under the hood, this is the behavior of `Nominal<Arc<T>>` for some inner
104/// type `T`, so we also refer to the [Nominal] type for details.
105#[derive(Clone, Debug, Hash, PartialEq, Eq, Located)]
106pub struct Variable<S: ToSort = Sort>(Nominal<Arc<VariableData<S>>>);
107
108#[derive(Clone, Debug, Located, Locatable)]
109struct VariableData<S: ToSort> {
110 pub name: Identifier<'static>,
111 pub sort: S,
112 pub span: Option<Span>,
113}
114
115impl<S: ToSort> Variable<S> {
116 /// Create a new [Variable].
117 pub fn new<'a>(name: impl Into<Identifier<'a>>, sort: S) -> Variable<S> {
118 Variable(Nominal(Arc::new(VariableData {
119 name: name.into().into_owned(),
120 sort,
121 span: None,
122 })))
123 }
124
125 /// Get the variable's name.
126 pub fn name(&self) -> &Identifier<'static> {
127 &self.0.name
128 }
129
130 /// Get the variable's sort.
131 pub fn sort(&self) -> &S {
132 &self.0.sort
133 }
134}
135
136impl<S: Clone + ToSort> Locatable for Variable<S> {
137 type Located = Variable<S>;
138
139 fn over(self, span: impl Into<Option<Span>>) -> Self::Located {
140 Variable(Nominal(Arc::new((**self.0).clone().over(span.into()))))
141 }
142}
143
144/// A primitive function (or constant, or sort).
145///
146/// [Primitive] represents a primitive symbol provided by a theory. As such it is usually not
147/// created directly by users of the framework but indirectly by the [theories!] macro.
148///
149/// Comparison of [Primitive] objects is *nominal*, that is, equality and hashing operate on the
150/// identity of the objects, not on their values. In other words, two [Primitive] objects with
151/// exactly the same fields (and in particular the same *name*) created by two different invocations
152/// of the [theories!] macro will compare *different* and have a possibly different hash. Moreover,
153/// cloning a [Primitive] object is a cheap operation and produces a second object which compares
154/// *equal* to the first. Under the hood, this is the behavior of `Nominal<Arc<T>>` for some inner
155/// type `T`, so we also refer to the [Nominal] type for details.
156#[derive(Clone, Debug, Hash, PartialEq, Eq)]
157pub struct Primitive(pub(crate) Nominal<SArc<PrimitiveData>>);
158
159#[derive(Clone, Debug)]
160pub(crate) struct PrimitiveData {
161 pub name: Identifier<'static>,
162 pub parameters: Vec<Variable>,
163 pub domain: Vec<Sort>,
164 pub range: Sort,
165 pub associativity: Option<Associativity>,
166}
167
168impl Located for Primitive {
169 fn span(&self) -> Option<Span> {
170 None
171 }
172}
173
174impl Primitive {
175 /// Create a new [Primitive].
176 ///
177 /// Using this method directly should very seldom be necessary, as the preferred way of
178 /// introducing primitive symbols if through the [theories!] macro.
179 pub fn new<'a>(
180 name: impl Into<Identifier<'a>>,
181 parameters: Vec<Variable>,
182 domain: Vec<Sort>,
183 range: Sort,
184 associativity: Option<Associativity>,
185 ) -> Primitive {
186 Primitive(Nominal(SArc::Arc(Arc::new(PrimitiveData {
187 name: name.into().into_owned(),
188 parameters,
189 domain,
190 range,
191 associativity,
192 }))))
193 }
194
195 /// Get the name of the primitive function.
196 pub fn name(&self) -> &Identifier<'static> {
197 &self.0.name
198 }
199
200 /// Get the *type-level parameters* of the primitive function.
201 ///
202 /// Only primitive functions can be parametric and the parameters returned here are the
203 /// ones that SMT-LIBv2 theory declarations introduce with the `par` keyword.
204 ///
205 /// These are *not* the sorts of the arguments of the function. For that, call
206 /// [domain()](Primitive::domain()).
207 pub fn parameters(&self) -> &[Variable] {
208 &self.0.parameters
209 }
210
211 /// Get the domain of the primitive function, i.e. the sorts of its arguments.
212 pub fn domain(&self) -> &[Sort] {
213 &self.0.domain
214 }
215
216 /// Get the range of the primitive function, i.e. the sort of its return value.
217 pub fn range(&self) -> &Sort {
218 &self.0.range
219 }
220
221 /// Get the associativity annotation, if any, of the primitive function.
222 ///
223 /// See [Associativity] for details.
224 pub fn associativity(&self) -> Option<Associativity> {
225 self.0.associativity
226 }
227}
228
229/// Specification for declarations of functions (and constants, and sorts).
230///
231/// [Declaration] objects are passed to the [Solver::declare()] method to declare entities in a
232/// solver, by specifying all the attributes of such declarations. Then, the method returns a
233/// [Declared] object which is an opaque shared reference to a specific [Declaration] object which
234/// represents the actual entity the solver is keeping track of.
235///
236/// The [Declaration<D, R>] type is parametric in two [ToSort] types `D` and `R` used to represent
237/// the sort of the domain and of the range of the function, respectively. These can be e.g.,
238/// [Sort] itself or the result of the [sort!] macro. See the documentation of [ToSort] for details.
239///
240/// The fields are public and the type can be constructed freely, but some constructors are also
241/// provided ([function()](Declaration::function), [constant()](Declaration::constant), and
242/// [sort()](Declaration::sort)), for common cases.
243#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Locatable)]
244pub struct Declaration<D: ToSort, R: ToSort> {
245 /// The name of the declared function.
246 pub name: Identifier<'static>,
247 /// The domain of the declared function, i.e. the sorts of its arguments.
248 pub domain: Vec<D>,
249 /// The range of the declared function, i.e. its return type.
250 pub range: R,
251 /// The optional source span the declaration comes from.
252 pub span: Option<Span>,
253}
254
255impl<D: ToSort, R: ToSort> Declaration<D, R> {
256 /// Declare a function (or a constant, or a sort).
257 ///
258 /// This is the most general constructor. It is more convenient than directly constructing the
259 /// [Declaration] struct because of implicit conversions of the arguments and the absence
260 /// of the `span` argument which is put to `None` by default, since most of the time when
261 /// using the API directly, declarations do not have a source span.
262 ///
263 /// If the declaration do have a span it can be set using [over()](Declaration::over()).
264 ///
265 /// In the following example we declare a function taking a integer argument and returning a
266 /// real and we set it to a given span.
267 /// ```
268 /// # mod formally {
269 /// # pub extern crate formally_smt as smt;
270 /// # pub extern crate formally_support as support;
271 /// # }
272 /// # use formally::{smt::*, support::*};
273 /// #
274 /// # fn main() -> Result<()> {
275 /// # let mut solver = Solver::new(&Config::new())?;
276 /// solver.declare(Declaration::function("f", [sort!(Int)], sort!(Real)))?;
277 /// # Ok(())
278 /// # }
279 /// ```
280 pub fn function<'a>(
281 name: impl Into<Identifier<'a>>,
282 domain: impl IntoIterator<Item = D>,
283 range: R,
284 ) -> Declaration<D, R> {
285 Declaration {
286 name: name.into().into_owned(),
287 domain: domain.into_iter().collect(),
288 range,
289 span: None,
290 }
291 }
292}
293
294impl<D: ToSort> Declaration<D, Sort> {
295 /// Declare a predicate (i.e. a function returning [Core::Bool()](theories::Core::Bool()).
296 ///
297 /// This is equivalent to `Declaration::function(name, domain, theories::Core::Bool())`.
298 pub fn predicate<'a>(
299 name: impl Into<Identifier<'a>>,
300 domain: impl IntoIterator<Item = D>,
301 ) -> Declaration<D, Sort> {
302 Declaration::function(name, domain, theories::Core::Bool())
303 }
304}
305
306impl<R: ToSort> Declaration<Sort, R> {
307 /// Declare a constant (i.e. a function with no arguments).
308 ///
309 /// This is equivalent to `Declaration::function(name, Vec::<Sort>::new(), sort)`.
310 pub fn constant<'a>(name: impl Into<Identifier<'a>>, sort: R) -> Declaration<Sort, R> {
311 Declaration::function(name, Vec::<Sort>::new(), sort)
312 }
313}
314
315impl Declaration<Sort, Sort> {
316 /// Declare a sort (i.e. a constant of the special sort [Sort::sort()]).
317 ///
318 /// This is equivalent to `Declaration::constant(name, Sort::sort())`.
319 pub fn sort<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
320 Declaration::constant(name, Sort::sort())
321 }
322
323 /// Declare a Boolean constant (i.e. a constant of sort [Core::Bool()](theories::Core::Bool()).
324 ///
325 /// This is equivalent to `Declaration::constant(name, theories::Core::Bool())`.
326 pub fn boolean<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
327 Declaration::constant(name, theories::Core::Bool())
328 }
329
330 /// Declare an integer constant (i.e. a constant of sort [Ints::Int()](theories::Ints::Int()).
331 ///
332 /// This is equivalent to `Declaration::constant(name, theories::Ints::Int())`.
333 pub fn integer<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
334 Declaration::constant(name, theories::Ints::Int())
335 }
336
337 /// Declare a real constant (i.e. a constant of sort [Reals::Real()](theories::Reals::Real()).
338 ///
339 /// This is equivalent to `Declaration::constant(name, theories::Reals::Real())`.
340 pub fn real<'a>(name: impl Into<Identifier<'a>>) -> Declaration<Sort, Sort> {
341 Declaration::constant(name, theories::Reals::Real())
342 }
343}
344
345/// Represent a specific function (or constant, or sort) declared in a [Solver].
346///
347/// [Declared] is an opaque shared reference to a [Declaration] declared in a [Solver].
348/// The only way to obtain a [Declared] is through [Solver::declare()]. [Declared] derefs to the
349/// underlying [Declaration] to immutably access its fields.
350///
351/// Comparison of [Declared] objects is *nominal*, that is, equality and hashing operate on the
352/// identity of the objects, not on their values. In other words, two [Declared] objects with
353/// exactly the same fields (and in particular the same *name*), created by two different calls to
354/// [Solver::declare()] will compare *different* and have a possibly different hash. Moreover,
355/// cloning a [Declared] object is a cheap operation and produces a second object which compares
356/// *equal* to the first. Under the hood, this is the behavior of `Nominal<Arc<Declaration>>`, so we
357/// also refer to the [Nominal] type for details.
358#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Deref)]
359pub struct Declared(pub(crate) Nominal<Arc<Declaration<Sort, Sort>>>);
360
361/// Specification for definitions of functions (and constants, and sorts).
362///
363/// [Definition] objects are passed to the [Solver::define()] method to define entities in a
364/// solver, by specifying all the attributes of such definitions. Then, the method returns a
365/// [Defined] object which is an opaque shared reference to a specific [Definition] object which
366/// represents the actual entity the solver is keeping track of.
367///
368/// The [Definition<V, R, B>] type is parametric in two [ToSort] types `V` and `R` used to
369/// represent the sort of the variables and of the range of the definition, respectively, and in
370/// a [ToTerm] `B` type used to represent the term of the body of the definition. See the
371/// documentation of [ToSort] and [ToTerm] for details.
372///
373/// The fields are public and the type can be constructed freely, but some constructors are also
374/// provided ([function()](Definition::function), [constant()](Definition::constant), and
375/// [sort()](Definition::sort)), for common cases.
376#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Locatable)]
377pub struct Definition<V: ToSort, R: ToSort, B: ToTerm> {
378 pub name: Identifier<'static>,
379 pub domain: Vec<Variable<V>>,
380 pub range: R,
381 pub body: B,
382 pub span: Option<Span>,
383}
384
385impl<V: ToSort, R: ToSort, B: ToTerm> Definition<V, R, B> {
386 /// Define a function (or a constant, or a sort).
387 ///
388 /// This is the most general constructor. It is more convenient than directly constructing the
389 /// [Definition] struct because of implicit conversions of the arguments and the absence
390 /// of the `span` argument which is put to `None` by default, since most of the time when
391 /// using the API directly, declarations do not have a source span.
392 ///
393 /// If the declaration do have a span it can be set using [over()](Definition::over()).
394 ///
395 /// The function parameters are created as objects of type [Variable] which are given to the
396 /// `domain` field and freely used in the body.
397 ///
398 /// In the following example we define a function `mult-add` taking three real arguments,
399 /// computing a *multiply-add* operation argument and returning it. Note that when defining
400 /// the body with the `term!` macro, the parameters are in scope and can just be referred to by
401 /// name (the same name given to the constructor of [Variable]).
402 /// ```
403 /// # mod formally {
404 /// # pub extern crate formally_smt as smt;
405 /// # pub extern crate formally_support as support;
406 /// # }
407 /// # use formally::{smt::{*, theories::*}, support::*};
408 /// # fn main() -> Result<()> {
409 /// # let mut solver = Solver::new(&Config::new().logic("NRA"))?;
410 ///
411 /// let a = var!(a Real);
412 /// let b = var!(b Real);
413 /// let c = var!(c Real);
414 ///
415 /// solver.define(
416 /// Definition::function("mult-add", [a, b, c], Reals::Real(), term!(+ (* a b) c))
417 /// )?;
418 /// # Ok(())
419 /// # }
420 /// ```
421 pub fn function<'a>(
422 name: impl Into<Identifier<'a>>,
423 domain: impl IntoIterator<Item = Variable<V>>,
424 range: R,
425 body: B,
426 ) -> Definition<V, R, B> {
427 Definition {
428 name: name.into().into_owned(),
429 domain: domain.into_iter().collect(),
430 range,
431 body,
432 span: None,
433 }
434 }
435}
436
437impl<V: ToSort, B: ToTerm> Definition<V, Sort, B> {
438 /// Define a predicate (i.e. a function returning [Core::Bool()](theories::Core::Bool()).
439 ///
440 /// This is equivalent to `Definition::function(name, domain, theories::Core::Bool(), body)`.
441 pub fn predicate<'a>(
442 name: impl Into<Identifier<'a>>,
443 domain: impl IntoIterator<Item = Variable<V>>,
444 body: B,
445 ) -> Definition<V, Sort, B> {
446 Definition::function(name, domain, theories::Core::Bool(), body)
447 }
448
449 /// Define a parametric sort (i.e. a function returning the special sort [Sort::sort()]).
450 ///
451 /// This is equivalent to `Definition::function(name, domain, Sort::sort(), body)`.
452 pub fn sort<'a>(
453 name: impl Into<Identifier<'a>>,
454 domain: impl IntoIterator<Item = Variable<V>>,
455 body: B,
456 ) -> Definition<V, Sort, B> {
457 Definition::function(name, domain, Sort::sort(), body)
458 }
459}
460
461impl<R: ToSort, B: ToTerm> Definition<Sort, R, B> {
462 /// Define a constant (i.e. a function with no arguments).
463 ///
464 /// This is equivalent to `Definition::function(name, [], sort, body)`.
465 pub fn constant<'a>(
466 name: impl Into<Identifier<'a>>,
467 sort: R,
468 body: B,
469 ) -> Definition<Sort, R, B> {
470 Definition::function(name, [], sort, body)
471 }
472}
473
474impl<B: ToTerm> Definition<Sort, Sort, B> {
475 /// Define a Boolean constant (i.e. a constant of sort [Core::Bool()](theories::Core::Bool()).
476 ///
477 /// This is equivalent to `Definition::constant(name, theories::Core::Bool(), value)`.
478 pub fn boolean<'a>(name: impl Into<Identifier<'a>>, value: B) -> Definition<Sort, Sort, B> {
479 Definition::constant(name, theories::Core::Bool(), value)
480 }
481
482 /// Define an integer constant (i.e. a constant of sort [Ints::Int()](theories::Ints::Int()).
483 ///
484 /// This is equivalent to `Definition::constant(name, theories::Ints::Int(), value)`.
485 pub fn integer<'a>(name: impl Into<Identifier<'a>>, value: B) -> Definition<Sort, Sort, B> {
486 Definition::constant(name, theories::Ints::Int(), value)
487 }
488
489 /// Define a real constant (i.e. a constant of sort [Reals::Real()](theories::Reals::Real()).
490 ///
491 /// This is equivalent to `Definition::constant(name, theories::Reals::Real(), value)`.
492 pub fn real<'a>(name: impl Into<Identifier<'a>>, value: B) -> Definition<Sort, Sort, B> {
493 Definition::constant(name, theories::Reals::Real(), value)
494 }
495}
496
497/// Represent a specific function (or constant, or sort) defined in a [Solver].
498///
499/// [Defined] is an opaque shared reference to a [Definition] defined in a [Solver].
500/// The only way to obtain a [Defined] is through [Solver::define()]. [Defined] derefs to the
501/// underlying [Definition] to immutably access its fields.
502///
503/// Comparison of [Defined] objects is *nominal*, that is, equality and hashing operate on the
504/// identity of the objects, not on their values. In other words, two [Defined] objects with
505/// exactly the same fields (and in particular the same *name*) created by two different calls to
506/// [Solver::define()] will compare *different* and have a possibly different hash. Moreover,
507/// cloning a [Defined] object is a cheap operation and produces a second object which compares
508/// *equal* to the first. Under the hood, this is the behavior of `Nominal<Arc<Definition>>`, so we
509/// also refer to the [Nominal] type for details.
510#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, Deref)]
511pub struct Defined(pub(crate) Nominal<Arc<Definition<Sort, Sort, Term>>>);
512
513/// A function.
514///
515/// The [Function] type represent any function usable to build terms.
516///
517/// A function can be a *user function*, i.e. a [UserFunction] object which in turn can be either
518/// [Declared] or [Defined], a [Variable], or a [Primitive].
519///
520/// Some accessor methods are provided to get fields in common between the variants avoiding
521/// redundant pattern matches.
522#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, From, Transitive)]
523#[allow(clippy::duplicated_attributes)]
524#[transitive(from(Declared, UserFunction))]
525#[transitive(from(Defined, UserFunction))]
526pub enum Function {
527 /// A variable.
528 Variable(Variable),
529 /// A primitive function declared by some theory.
530 Primitive(Primitive),
531 /// A user function, i.e. either [Declared] or [Defined].
532 User(UserFunction),
533}
534
535impl Function {
536 /// Get the name of the function.
537 pub fn name(&self) -> &Identifier<'static> {
538 match self {
539 Function::Variable(var) => var.name(),
540 Function::Primitive(prim) => prim.name(),
541 Function::User(user) => user.name(),
542 }
543 }
544
545 /// Get the *type-level parameters* of a function.
546 ///
547 /// Only primitive functions can be parametric and the parameters returned here are the
548 /// ones that SMT-LIBv2 theory declarations introduce with the `par` keyword.
549 ///
550 /// These are *not* the sorts of the arguments of the function. For that, call
551 /// [domain()](Function::domain()).
552 pub fn parameters(&self) -> Vec<Sort> {
553 match self {
554 Function::Variable(_) => Vec::new(),
555 Function::Primitive(prim) => {
556 prim.parameters().iter().map(|p| p.sort().clone()).collect()
557 }
558 Function::User(_) => Vec::new(),
559 }
560 }
561
562 /// Get the domain of the function, i.e. the sorts of its arguments.
563 pub fn domain(&self) -> Vec<Sort> {
564 match self {
565 Function::Variable(_) => Vec::new(),
566 Function::Primitive(prim) => prim.domain().to_vec(),
567 Function::User(user) => user.domain(),
568 }
569 }
570
571 /// Get the range of the function, i.e. the sort of its return value.
572 pub fn range(&self) -> &Sort {
573 match self {
574 Function::Variable(var) => var.sort(),
575 Function::Primitive(prim) => prim.range(),
576 Function::User(user) => user.range(),
577 }
578 }
579}
580
581/// A *user function*, i.e. a function either declared or defined in some [Solver].
582///
583/// Some accessor methods are provided to get fields in common between the variants avoiding
584/// redundant pattern matches.
585#[derive(Clone, Debug, Hash, PartialEq, Eq, Located, From)]
586pub enum UserFunction {
587 /// A declared function.
588 Declared(Declared),
589 /// A defined function.
590 Defined(Defined),
591}
592
593impl UserFunction {
594 /// Get the name of the function.
595 pub fn name(&self) -> &Identifier<'static> {
596 match self {
597 UserFunction::Declared(decl) => &decl.name,
598 UserFunction::Defined(def) => &def.name,
599 }
600 }
601
602 /// Get the domain of the function, i.e. the sorts of its arguments.
603 pub fn domain(&self) -> Vec<Sort> {
604 match self {
605 UserFunction::Declared(decl) => decl.domain.clone(),
606 UserFunction::Defined(def) => def.domain.iter().map(|p| p.sort().clone()).collect(),
607 }
608 }
609
610 /// Get the range of the function, i.e. the sort of its return value.
611 pub fn range(&self) -> &Sort {
612 match self {
613 UserFunction::Declared(decl) => &decl.range,
614 UserFunction::Defined(def) => &def.range,
615 }
616 }
617}