Skip to main content

conjure_cp_core/ast/
declaration.rs

1use super::categories::{Category, CategoryOf};
2use super::name::Name;
3use super::serde::{DefaultWithId, HasId, IdPtr, ObjId, PtrAsInner};
4use super::{
5    DecisionVariable, DomainPtr, Expression, GroundDomain, HasDomain, Moo, Reference, ReturnType,
6    Typeable,
7};
8use crate::representation::{ReprRule, ReprStore};
9use parking_lot::{
10    MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
11};
12use serde::{Deserialize, Serialize};
13use serde_with::serde_as;
14use std::any::TypeId;
15use std::collections::BTreeSet;
16use std::collections::VecDeque;
17use std::fmt::{Debug, Display};
18use std::hash::{DefaultHasher, Hash, Hasher};
19use std::mem;
20use std::ops::{Deref, DerefMut};
21use std::sync::Arc;
22use std::sync::atomic::{AtomicU32, AtomicU64, Ordering};
23use uniplate::{Biplate, Tree, Uniplate};
24
25/// Global counter of declarations.
26/// Note that the counter is shared between all threads
27/// Thus, when running multiple models in parallel, IDs may
28/// be different with every run depending on scheduling order
29static DECLARATION_PTR_ID_COUNTER: AtomicU32 = const { AtomicU32::new(0) };
30
31/// Global generation of declaration contents.
32///
33/// Declaration pointers are shared across symbol tables, so an in-place update cannot cheaply
34/// notify every table that contains the pointer. Symbol-table content caches compare against this
35/// generation instead.
36static DECLARATION_CONTENT_GENERATION: AtomicU64 = const { AtomicU64::new(1) };
37
38/// Returns the generation shared by all mutable declaration contents.
39pub(crate) fn declaration_content_generation() -> u64 {
40    DECLARATION_CONTENT_GENERATION.load(Ordering::Acquire)
41}
42
43/// Records that a declaration's contents may have changed.
44fn mark_declaration_content_changed() {
45    DECLARATION_CONTENT_GENERATION.fetch_add(1, Ordering::AcqRel);
46}
47
48/// Mutable access to part of a declaration that records a semantic change when released.
49pub struct DeclarationMutGuard<'a, T: ?Sized> {
50    inner: Option<MappedRwLockWriteGuard<'a, T>>,
51}
52
53impl<'a, T: ?Sized> DeclarationMutGuard<'a, T> {
54    /// Wraps a mapped write guard so dropping it records a content change.
55    fn new(inner: MappedRwLockWriteGuard<'a, T>) -> Self {
56        Self { inner: Some(inner) }
57    }
58}
59
60impl<T: ?Sized> Deref for DeclarationMutGuard<'_, T> {
61    type Target = T;
62
63    fn deref(&self) -> &Self::Target {
64        self.inner.as_deref().expect("declaration guard is live")
65    }
66}
67
68impl<T: ?Sized> DerefMut for DeclarationMutGuard<'_, T> {
69    fn deref_mut(&mut self) -> &mut Self::Target {
70        self.inner
71            .as_deref_mut()
72            .expect("declaration guard is live")
73    }
74}
75
76impl<T: ?Sized> Drop for DeclarationMutGuard<'_, T> {
77    fn drop(&mut self) {
78        drop(self.inner.take());
79        mark_declaration_content_changed();
80    }
81}
82
83#[doc(hidden)]
84/// Resets the id counter of `DeclarationPtr` to 0.
85///
86/// This is probably always a bad idea.
87pub fn reset_declaration_id_unchecked() {
88    let _ = DECLARATION_PTR_ID_COUNTER.swap(0, Ordering::Relaxed);
89}
90
91/// A shared pointer to a [`Declaration`].
92///
93/// Two declaration pointers are equal if they point to the same underlying declaration.
94///
95/// # Id
96///
97///  The id of `DeclarationPtr` obeys the following invariants:
98///
99/// 1. Declaration pointers have the same id if they point to the same
100///    underlying declaration.
101///
102/// 2. The id is immutable.
103///
104/// 3. Changing the declaration pointed to by the declaration pointer does not change the id. This
105///    allows declarations to be updated by replacing them with a newer version of themselves.
106///
107/// `Ord`, `Hash`, and `Eq` use id for comparisons.
108/// # Serde
109///
110/// Declaration pointers can be serialised using the following serializers:
111///
112/// + [`DeclarationPtrFull`](serde::DeclarationPtrFull)
113/// + [`DeclarationPtrAsId`](serde::DeclarationPtrAsId)
114///
115/// See their documentation for more information.
116#[derive(Clone, Debug)]
117pub struct DeclarationPtr
118where
119    Self: Send + Sync,
120{
121    // the shared bits of the pointer
122    inner: Arc<DeclarationPtrInner>,
123}
124
125// The bits of a declaration that are shared between all pointers.
126#[derive(Debug)]
127struct DeclarationPtrInner {
128    // Identity hash/order key. Declaration content is mutable and is hashed separately by
129    // `DeclarationPtr::content_hash`.
130    // We don't want this to be mutable, as `HashMap` and `BTreeMap` rely on the hash or order of
131    // keys to be unchanging.
132    //
133    // See:  https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
134    id: ObjId,
135
136    // The contents of the declaration itself should be mutable.
137    value: RwLock<Declaration>,
138
139    /// Representations initialised for this declaration.
140    representations: RwLock<ReprStore>,
141
142    /// The declaration from which this auxiliary declaration was created.
143    source: RwLock<Option<DeclarationPtr>>,
144}
145
146impl DeclarationPtrInner {
147    fn new(value: RwLock<Declaration>) -> Arc<DeclarationPtrInner> {
148        Arc::new(DeclarationPtrInner {
149            id: ObjId {
150                type_name: ustr::ustr(DeclarationPtr::TYPE_NAME),
151                object_id: DECLARATION_PTR_ID_COUNTER.fetch_add(1, Ordering::Relaxed),
152            },
153            value,
154            representations: RwLock::new(ReprStore::new()),
155            source: RwLock::new(None),
156        })
157    }
158
159    // SAFETY: only use if you are really really sure you arn't going to break the id invariants of
160    // DeclarationPtr and HasId!
161    fn new_with_id_unchecked(value: RwLock<Declaration>, id: ObjId) -> Arc<DeclarationPtrInner> {
162        Arc::new(DeclarationPtrInner {
163            id,
164            value,
165            representations: RwLock::new(ReprStore::new()),
166            source: RwLock::new(None),
167        })
168    }
169}
170
171#[allow(dead_code)]
172impl DeclarationPtr {
173    /******************************/
174    /*        Constructors        */
175    /******************************/
176
177    /// Creates a `DeclarationPtr` for the given `Declaration`.
178    fn from_declaration(declaration: Declaration) -> DeclarationPtr {
179        DeclarationPtr {
180            inner: DeclarationPtrInner::new(RwLock::new(declaration)),
181        }
182    }
183
184    /// Gets the declaration from which this auxiliary declaration was created.
185    pub fn source(&self) -> RwLockReadGuard<'_, Option<DeclarationPtr>> {
186        self.inner.source.read()
187    }
188
189    /// Mutates the declaration from which this auxiliary declaration was created.
190    pub fn source_mut(&mut self) -> RwLockWriteGuard<'_, Option<DeclarationPtr>> {
191        self.inner.source.write()
192    }
193
194    /// Gets the representations initialised for this declaration.
195    pub fn reprs(&self) -> RwLockReadGuard<'_, ReprStore> {
196        self.inner.representations.read()
197    }
198
199    /// Mutates the representations initialised for this declaration.
200    pub fn reprs_mut(&mut self) -> RwLockWriteGuard<'_, ReprStore> {
201        self.inner.representations.write()
202    }
203
204    /// Gets a particular representation state, if it has been initialised.
205    pub fn get_repr<T: ReprRule + ?Sized>(
206        &self,
207    ) -> Option<MappedRwLockReadGuard<'_, T::DeclLevel>> {
208        RwLockReadGuard::try_map(self.inner.representations.read(), |reprs| reprs.get::<T>()).ok()
209    }
210
211    /// Creates a new declaration.
212    ///
213    /// # Examples
214    ///
215    /// ```
216    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
217    ///
218    /// // letting MyDomain be int(1..5)
219    /// let declaration = DeclarationPtr::new(
220    ///     Name::User("MyDomain".into()),
221    ///     DeclarationKind::DomainLetting(Domain::int(vec![
222    ///         Range::Bounded(1,5)])));
223    /// ```
224    pub fn new(name: Name, kind: DeclarationKind) -> DeclarationPtr {
225        DeclarationPtr::from_declaration(Declaration::new(name, kind))
226    }
227
228    /// Creates a new find declaration.
229    ///
230    /// # Examples
231    ///
232    /// ```
233    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
234    ///
235    /// // find x: int(1..5)
236    /// let declaration = DeclarationPtr::new_find(
237    ///     Name::User("x".into()),
238    ///     Domain::int(vec![Range::Bounded(1,5)]));
239    ///
240    /// ```
241    pub fn new_find(name: Name, domain: DomainPtr) -> DeclarationPtr {
242        let kind = DeclarationKind::Find(DecisionVariable::new(domain));
243        DeclarationPtr::new(name, kind)
244    }
245
246    /// Creates a new auxiliary find declaration.
247    ///
248    /// Auxiliary finds are introduced by rewriting (for example, turning a top-level `exists`
249    /// into constraints), and can also be written in Essence as `findAux`.
250    /// They are decision variables for solvers, but must not be branched on during search:
251    /// different assignments to them must not produce distinct user-facing solutions.
252    pub fn new_find_auxiliary(name: Name, domain: DomainPtr) -> DeclarationPtr {
253        let kind = DeclarationKind::FindAuxiliary(DecisionVariable::new(domain));
254        DeclarationPtr::new(name, kind)
255    }
256
257    /// Creates a new given declaration.
258    ///
259    /// # Examples
260    ///
261    /// ```
262    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
263    ///
264    /// // given n: int(1..5)
265    /// let declaration = DeclarationPtr::new_given(
266    ///     Name::User("n".into()),
267    ///     Domain::int(vec![Range::Bounded(1,5)]));
268    ///
269    /// ```
270    pub fn new_given(name: Name, domain: DomainPtr) -> DeclarationPtr {
271        let kind = DeclarationKind::Given(domain);
272        DeclarationPtr::new(name, kind)
273    }
274
275    /// Creates a new quantified declaration for local comprehension scopes.
276    ///
277    /// Used when creating the quantified variable in a generator.
278    pub fn new_quantified(name: Name, domain: DomainPtr) -> DeclarationPtr {
279        DeclarationPtr::new(
280            name,
281            DeclarationKind::Quantified(Quantified {
282                domain,
283                generator: None,
284            }),
285        )
286    }
287
288    /// Creates a quantified declaration backed by a generator declaration.
289    ///
290    /// This is used in comprehensions to refer to a quantified variable that is already defined using a generator.
291    pub fn new_quantified_from_generator(decl: &DeclarationPtr) -> Option<DeclarationPtr> {
292        let kind = DeclarationKind::Quantified(Quantified {
293            domain: decl.domain()?,
294            generator: Some(decl.clone()),
295        });
296        Some(DeclarationPtr::new(decl.name().clone(), kind))
297    }
298
299    pub fn new_quantified_expr(name: Name, expr: Expression) -> DeclarationPtr {
300        let kind = DeclarationKind::QuantifiedExpr(expr);
301        DeclarationPtr::new(name, kind)
302    }
303
304    /// Creates a new value letting declaration.
305    ///
306    /// # Examples
307    ///
308    /// ```
309    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range, Expression,
310    /// Literal,Atom,Moo};
311    /// use conjure_cp_core::{matrix_expr,ast::Metadata};
312    ///
313    /// // letting n be 10 + 10
314    /// let ten = Expression::Atomic(Metadata::new(),Atom::Literal(Literal::Int(10)));
315    /// let expression = Expression::Sum(Metadata::new(),Moo::new(matrix_expr![ten.clone(),ten]));
316    /// let declaration = DeclarationPtr::new_value_letting(
317    ///     Name::User("n".into()),
318    ///     expression);
319    ///
320    /// ```
321    pub fn new_value_letting(name: Name, expression: Expression) -> DeclarationPtr {
322        let kind = DeclarationKind::ValueLetting(expression, None);
323        DeclarationPtr::new(name, kind)
324    }
325
326    /// Creates a new value letting declaration with domain.
327    ///
328    /// # Examples
329    ///
330    /// ```
331    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range, Expression,
332    /// Literal,Atom,Moo,DomainPtr,Metadata};
333    /// use conjure_cp_core::{matrix_expr};
334    ///
335    /// // letting n be 10 + 10
336    /// let ten = Expression::Atomic(Metadata::new(),Atom::Literal(Literal::Int(10)));
337    /// let expression = Expression::Sum(Metadata::new(),Moo::new(matrix_expr![ten.clone(),ten]));
338    /// let domain = Domain::bool();
339    /// let declaration = DeclarationPtr::new_value_letting_with_domain(
340    ///     Name::User("n".into()),
341    ///     expression,
342    ///     domain,
343    /// );
344    /// ```
345    pub fn new_value_letting_with_domain(
346        name: Name,
347        expression: Expression,
348        domain: DomainPtr,
349    ) -> DeclarationPtr {
350        let kind = DeclarationKind::ValueLetting(expression, Some(domain));
351        DeclarationPtr::new(name, kind)
352    }
353
354    /// Creates a new domain letting declaration.
355    ///
356    /// # Examples
357    ///
358    /// ```
359    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
360    ///
361    /// // letting MyDomain be int(1..5)
362    /// let declaration = DeclarationPtr::new_domain_letting(
363    ///     Name::User("MyDomain".into()),
364    ///     Domain::int(vec![Range::Bounded(1,5)]));
365    ///
366    /// ```
367    pub fn new_domain_letting(name: Name, domain: DomainPtr) -> DeclarationPtr {
368        let kind = DeclarationKind::DomainLetting(domain);
369        DeclarationPtr::new(name, kind)
370    }
371
372    /**********************************************/
373    /*        Declaration accessor methods        */
374    /**********************************************/
375
376    /// Gets the domain of the declaration, if it has one.
377    ///
378    /// # Examples
379    ///
380    /// ```
381    /// use conjure_cp_core::ast::{DeclarationPtr, Name, Domain, Range, GroundDomain};
382    ///
383    /// // find a: int(1..5)
384    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
385    ///
386    /// assert!(declaration.domain().is_some_and(|x| x.as_ground().unwrap() == &GroundDomain::Int(vec![Range::Bounded(1,5)])))
387    ///
388    /// ```
389    pub fn domain(&self) -> Option<DomainPtr> {
390        // Expressions stored inside a declaration (as opposed to the constraint tree the rewrite
391        // engine walks) can be mutated in place by substitution utilities that never touch
392        // the constraint-tree metadata cache, so `domain_of`'s cache would go stale silently for
393        // them. Use the uncached path here.
394        match &self.kind() as &DeclarationKind {
395            DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => {
396                Some(var.domain_of())
397            }
398            DeclarationKind::ValueLetting(e, domain) => {
399                domain.clone().or_else(|| e.domain_of_uncached())
400            }
401            DeclarationKind::TemporaryValueLetting(e) => e.domain_of_uncached(),
402            DeclarationKind::DomainLetting(domain) => Some(domain.clone()),
403            DeclarationKind::Given(domain) => Some(domain.clone()),
404            DeclarationKind::Quantified(inner) => Some(inner.domain.clone()),
405            DeclarationKind::QuantifiedExpr(expr) => expr.domain_of_uncached()?.element_domain(),
406        }
407    }
408
409    /// Returns true if this declaration is an auxiliary find.
410    ///
411    /// Auxiliary finds are solver variables that must not be included in the search/branching
412    /// order (see [`DeclarationKind::FindAuxiliary`]).
413    pub fn is_find_auxiliary(&self) -> bool {
414        matches!(
415            &self.kind() as &DeclarationKind,
416            DeclarationKind::FindAuxiliary(_)
417        )
418    }
419
420    /// Gets the domain of the declaration and fully resolve it
421    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
422        self.domain()?.resolve().ok()
423    }
424
425    /// Gets the kind of the declaration.
426    ///
427    /// # Examples
428    ///
429    /// ```
430    /// use conjure_cp_core::ast::{DeclarationPtr,DeclarationKind,Name,Domain,Range};
431    ///
432    /// // find a: int(1..5)
433    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
434    /// assert!(matches!(&declaration.kind() as &DeclarationKind, DeclarationKind::Find(_)))
435    /// ```
436    pub fn kind(&self) -> MappedRwLockReadGuard<'_, DeclarationKind> {
437        self.map(|x| &x.kind)
438    }
439
440    /// Gets the name of the declaration.
441    ///
442    /// # Examples
443    ///
444    /// ```
445    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
446    ///
447    /// // find a: int(1..5)
448    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
449    ///
450    /// assert_eq!(&declaration.name() as &Name, &Name::User("a".into()))
451    /// ```
452    pub fn name(&self) -> MappedRwLockReadGuard<'_, Name> {
453        self.map(|x| &x.name)
454    }
455
456    /// This declaration as a decision variable, if it is one.
457    ///
458    /// Both user [`DeclarationKind::Find`] and rewriter-introduced
459    /// [`DeclarationKind::FindAuxiliary`] declarations are treated as decision variables.
460    pub fn as_find(&self) -> Option<MappedRwLockReadGuard<'_, DecisionVariable>> {
461        RwLockReadGuard::try_map(self.read(), |x| match &x.kind {
462            DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => Some(var),
463            _ => None,
464        })
465        .ok()
466    }
467
468    /// This declaration as a mutable decision variable, if it is one.
469    ///
470    /// Both user [`DeclarationKind::Find`] and rewriter-introduced
471    /// [`DeclarationKind::FindAuxiliary`] declarations are treated as decision variables.
472    pub fn as_find_mut(&mut self) -> Option<DeclarationMutGuard<'_, DecisionVariable>> {
473        RwLockWriteGuard::try_map(self.write(), |x| match &mut x.kind {
474            DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => Some(var),
475            _ => None,
476        })
477        .ok()
478        .map(DeclarationMutGuard::new)
479    }
480
481    /// This declaration as a domain letting, if it is one.
482    pub fn as_domain_letting(&self) -> Option<MappedRwLockReadGuard<'_, DomainPtr>> {
483        RwLockReadGuard::try_map(self.read(), |x| {
484            if let DeclarationKind::DomainLetting(domain) = &x.kind {
485                Some(domain)
486            } else {
487                None
488            }
489        })
490        .ok()
491    }
492
493    /// This declaration as a mutable domain letting, if it is one.
494    pub fn as_domain_letting_mut(&mut self) -> Option<DeclarationMutGuard<'_, DomainPtr>> {
495        RwLockWriteGuard::try_map(self.write(), |x| {
496            if let DeclarationKind::DomainLetting(domain) = &mut x.kind {
497                Some(domain)
498            } else {
499                None
500            }
501        })
502        .ok()
503        .map(DeclarationMutGuard::new)
504    }
505
506    /// This declaration as a value letting, if it is one.
507    pub fn as_value_letting(&self) -> Option<MappedRwLockReadGuard<'_, Expression>> {
508        RwLockReadGuard::try_map(self.read(), |x| {
509            if let DeclarationKind::ValueLetting(expression, _)
510            | DeclarationKind::TemporaryValueLetting(expression) = &x.kind
511            {
512                Some(expression)
513            } else {
514                None
515            }
516        })
517        .ok()
518    }
519
520    /// This declaration as a mutable value letting, if it is one.
521    pub fn as_value_letting_mut(&mut self) -> Option<DeclarationMutGuard<'_, Expression>> {
522        RwLockWriteGuard::try_map(self.write(), |x| {
523            if let DeclarationKind::ValueLetting(expression, _)
524            | DeclarationKind::TemporaryValueLetting(expression) = &mut x.kind
525            {
526                Some(expression)
527            } else {
528                None
529            }
530        })
531        .ok()
532        .map(DeclarationMutGuard::new)
533    }
534
535    /// This declaration as a given statement, if it is one.
536    pub fn as_given(&self) -> Option<MappedRwLockReadGuard<'_, DomainPtr>> {
537        RwLockReadGuard::try_map(self.read(), |x| {
538            if let DeclarationKind::Given(domain) = &x.kind {
539                Some(domain)
540            } else {
541                None
542            }
543        })
544        .ok()
545    }
546
547    /// This declaration as a mutable given statement, if it is one.
548    pub fn as_given_mut(&mut self) -> Option<DeclarationMutGuard<'_, DomainPtr>> {
549        RwLockWriteGuard::try_map(self.write(), |x| {
550            if let DeclarationKind::Given(domain) = &mut x.kind {
551                Some(domain)
552            } else {
553                None
554            }
555        })
556        .ok()
557        .map(DeclarationMutGuard::new)
558    }
559
560    /// This declaration as a quantified expression, if it is one.
561    pub fn as_quantified_expr(&self) -> Option<MappedRwLockReadGuard<'_, Expression>> {
562        RwLockReadGuard::try_map(self.read(), |x| {
563            if let DeclarationKind::QuantifiedExpr(expr) = &x.kind {
564                Some(expr)
565            } else {
566                None
567            }
568        })
569        .ok()
570    }
571
572    /// This declaration as a mutable quantified expression, if it is one.
573    pub fn as_quantified_expr_mut(&mut self) -> Option<DeclarationMutGuard<'_, Expression>> {
574        RwLockWriteGuard::try_map(self.write(), |x| {
575            if let DeclarationKind::QuantifiedExpr(expr) = &mut x.kind {
576                Some(expr)
577            } else {
578                None
579            }
580        })
581        .ok()
582        .map(DeclarationMutGuard::new)
583    }
584
585    /// Changes the name in this declaration, returning the old one.
586    ///
587    /// # Examples
588    ///
589    /// ```
590    /// use conjure_cp_core::ast::{DeclarationPtr, Domain, Range, Name};
591    ///
592    /// // find a: int(1..5)
593    /// let mut declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
594    ///
595    /// let old_name = declaration.replace_name(Name::User("b".into()));
596    /// assert_eq!(old_name,Name::User("a".into()));
597    /// assert_eq!(&declaration.name() as &Name,&Name::User("b".into()));
598    /// ```
599    pub fn replace_name(&mut self, name: Name) -> Name {
600        let mut current_name = self.map_mut(|decl| &mut decl.name);
601        std::mem::replace(&mut *current_name, name)
602    }
603
604    /// Replaces the underlying declaration kind and returns the previous kind.
605    /// Note: this affects all cloned `DeclarationPtr`s pointing to the same declaration.
606    pub fn replace_kind(&mut self, kind: DeclarationKind) -> DeclarationKind {
607        let mut current_kind = self.map_mut(|decl| &mut decl.kind);
608        std::mem::replace(&mut *current_kind, kind)
609    }
610
611    /*****************************************/
612    /*        Pointer utility methods        */
613    /*****************************************/
614
615    // These are mostly wrappers over RefCell, Ref, and RefMut methods, re-exported here for
616    // convenience.
617
618    /// Read the underlying [Declaration].
619    ///
620    /// Will block the current thread until no other thread has a write lock.
621    /// Attempting to get a read lock if the current thread already has one
622    /// **will** cause it to deadlock.
623    /// The lock is released when the returned guard goes out of scope.
624    fn read(&self) -> RwLockReadGuard<'_, Declaration> {
625        self.inner.value.read()
626    }
627
628    /// Write the underlying [Declaration].
629    ///
630    /// Will block the current thread until no other thread has a read or write lock.
631    /// The lock is released when the returned guard goes out of scope.
632    fn write(&mut self) -> RwLockWriteGuard<'_, Declaration> {
633        self.inner.value.write()
634    }
635
636    /// Creates a new declaration pointer with the same contents as `self` that is not shared with
637    /// anyone else.
638    ///
639    /// As the resulting pointer is unshared, it will have a new id.
640    ///
641    /// # Examples
642    ///
643    /// ```
644    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
645    ///
646    /// // find a: int(1..5)
647    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
648    ///
649    /// let mut declaration2 = declaration.clone();
650    ///
651    /// declaration2.replace_name(Name::User("b".into()));
652    ///
653    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
654    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
655    ///
656    /// declaration2 = declaration2.detach();
657    ///
658    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
659    ///
660    /// declaration2.replace_name(Name::User("c".into()));
661    ///
662    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
663    /// assert_eq!(&declaration2.name() as &Name, &Name::User("c".into()));
664    /// ```
665    pub fn detach(self) -> DeclarationPtr {
666        // despite having the same contents, the new declaration pointer is unshared, so it should
667        // get a new id.
668        let value = self.inner.value.read().clone();
669        let representations = self.inner.representations.read().clone();
670        let source = self.inner.source.read().clone();
671        let detached = DeclarationPtr {
672            inner: DeclarationPtrInner::new(RwLock::new(value)),
673        };
674        *detached.inner.representations.write() = representations;
675        *detached.inner.source.write() = source;
676        detached
677    }
678
679    /// Applies `f` to the declaration, returning the result as a reference.
680    fn map<U>(&self, f: impl FnOnce(&Declaration) -> &U) -> MappedRwLockReadGuard<'_, U> {
681        RwLockReadGuard::map(self.read(), f)
682    }
683
684    /// Applies mutable function `f` to the declaration, returning the result as a mutable reference.
685    fn map_mut<U>(
686        &mut self,
687        f: impl FnOnce(&mut Declaration) -> &mut U,
688    ) -> DeclarationMutGuard<'_, U> {
689        DeclarationMutGuard::new(RwLockWriteGuard::map(self.write(), f))
690    }
691
692    /// Replaces the declaration with a new one, returning the old value, without deinitialising
693    /// either one.
694    pub fn replace(&mut self, declaration: Declaration) -> Declaration {
695        let mut guard = self.write();
696        let ans = mem::replace(&mut *guard, declaration);
697        drop(guard);
698        mark_declaration_content_changed();
699        ans
700    }
701
702    /// Hashes the declaration contents rather than the stable declaration pointer id.
703    ///
704    /// Pointer hashing intentionally remains id-based for map/set invariants. This helper is for
705    /// rewrite caches that need to be invalidated when the declaration value behind a reference
706    /// changes.
707    pub(crate) fn content_hash(&self) -> u64 {
708        let mut hasher = DefaultHasher::new();
709        let mut seen = BTreeSet::new();
710        self.hash_content(&mut hasher, &mut seen);
711        hasher.finish()
712    }
713
714    /// Compares current declaration contents without considering pointer identity.
715    pub(crate) fn content_eq(&self, other: &Self) -> bool {
716        if self.id() == other.id() {
717            return true;
718        }
719        let this = self.read().clone();
720        let other = other.read().clone();
721        this == other
722    }
723
724    /// Hashes this declaration's value into `state`, guarding against declaration-reference cycles.
725    fn hash_content<H: Hasher>(&self, state: &mut H, seen: &mut BTreeSet<ObjId>) {
726        let id = self.id();
727        if !seen.insert(id.clone()) {
728            "recursive-declaration".hash(state);
729            return;
730        }
731
732        let declaration = self.read();
733        declaration.name.hash(state);
734        declaration.kind.hash_content(state, seen);
735        seen.remove(&id);
736    }
737}
738
739impl CategoryOf for DeclarationPtr {
740    fn category_of(&self) -> Category {
741        match &self.kind() as &DeclarationKind {
742            DeclarationKind::Find(decision_variable)
743            | DeclarationKind::FindAuxiliary(decision_variable) => decision_variable.category_of(),
744            DeclarationKind::ValueLetting(expression, _)
745            | DeclarationKind::TemporaryValueLetting(expression) => expression.category_of(),
746            DeclarationKind::DomainLetting(_) => Category::Constant,
747            DeclarationKind::Given(_) => Category::Parameter,
748            DeclarationKind::Quantified(..) => Category::Quantified,
749            DeclarationKind::QuantifiedExpr(..) => Category::Quantified,
750        }
751    }
752}
753impl HasId for DeclarationPtr {
754    const TYPE_NAME: &'static str = "DeclarationPtrInner";
755    fn id(&self) -> ObjId {
756        self.inner.id.clone()
757    }
758}
759
760impl DefaultWithId for DeclarationPtr {
761    fn default_with_id(id: ObjId) -> Self {
762        DeclarationPtr {
763            inner: DeclarationPtrInner::new_with_id_unchecked(
764                RwLock::new(Declaration {
765                    name: Name::User("_UNKNOWN".into()),
766                    kind: DeclarationKind::ValueLetting(false.into(), None),
767                }),
768                id,
769            ),
770        }
771    }
772}
773
774impl Typeable for DeclarationPtr {
775    fn return_type(&self) -> ReturnType {
776        match &self.kind() as &DeclarationKind {
777            DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => var.return_type(),
778            DeclarationKind::ValueLetting(expression, _)
779            | DeclarationKind::TemporaryValueLetting(expression) => expression.return_type(),
780            DeclarationKind::DomainLetting(domain) => domain.return_type(),
781            DeclarationKind::Given(domain) => domain.return_type(),
782            DeclarationKind::Quantified(inner) => inner.domain.return_type(),
783            DeclarationKind::QuantifiedExpr(expr) => expr.return_type(),
784        }
785    }
786}
787
788impl Uniplate for DeclarationPtr {
789    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
790        let decl = self.read();
791        let (tree, recons) = Biplate::<DeclarationPtr>::biplate(&decl as &Declaration);
792
793        let self2 = self.clone();
794        (
795            tree,
796            Box::new(move |x| {
797                let mut self3 = self2.clone();
798                let inner = recons(x);
799                let _ = self3.replace(inner);
800                self3
801            }),
802        )
803    }
804}
805
806impl<To> Biplate<To> for DeclarationPtr
807where
808    Declaration: Biplate<To>,
809    To: Uniplate,
810{
811    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
812        if TypeId::of::<To>() == TypeId::of::<Self>() {
813            unsafe {
814                let self_as_to = std::mem::transmute::<&Self, &To>(self).clone();
815                (
816                    Tree::One(self_as_to),
817                    Box::new(move |x| {
818                        let Tree::One(x) = x else { panic!() };
819
820                        let x_as_self = std::mem::transmute::<&To, &Self>(&x);
821                        x_as_self.clone()
822                    }),
823                )
824            }
825        } else {
826            // call biplate on the enclosed declaration
827            let decl = self.read();
828            let (tree, recons) = Biplate::<To>::biplate(&decl as &Declaration);
829
830            let self2 = self.clone();
831            (
832                tree,
833                Box::new(move |x| {
834                    let mut self3 = self2.clone();
835                    let inner = recons(x);
836                    let _ = self3.replace(inner);
837                    self3
838                }),
839            )
840        }
841    }
842}
843
844type ReferenceTree = Tree<Reference>;
845type ReferenceReconstructor<T> = Box<dyn Fn(ReferenceTree) -> T>;
846
847impl Biplate<Reference> for DeclarationPtr {
848    fn biplate(&self) -> (ReferenceTree, ReferenceReconstructor<Self>) {
849        let (tree, recons_kind) = biplate_declaration_kind_references(self.kind().clone());
850
851        let self2 = self.clone();
852        (
853            tree,
854            Box::new(move |x| {
855                let mut self3 = self2.clone();
856                let _ = self3.replace_kind(recons_kind(x));
857                self3
858            }),
859        )
860    }
861}
862
863fn biplate_domain_ptr_references(
864    domain: DomainPtr,
865) -> (ReferenceTree, ReferenceReconstructor<DomainPtr>) {
866    let domain_inner = domain.as_ref().clone();
867    let (tree, recons_domain) = Biplate::<Reference>::biplate(&domain_inner);
868    (tree, Box::new(move |x| Moo::new(recons_domain(x))))
869}
870
871fn biplate_declaration_kind_references(
872    kind: DeclarationKind,
873) -> (ReferenceTree, ReferenceReconstructor<DeclarationKind>) {
874    match kind {
875        DeclarationKind::Find(var) => {
876            let (tree, recons_domain) = biplate_domain_ptr_references(var.domain.clone());
877            (
878                tree,
879                Box::new(move |x| {
880                    let mut var2 = var.clone();
881                    var2.domain = recons_domain(x);
882                    DeclarationKind::Find(var2)
883                }),
884            )
885        }
886        DeclarationKind::FindAuxiliary(var) => {
887            let (tree, recons_domain) = biplate_domain_ptr_references(var.domain.clone());
888            (
889                tree,
890                Box::new(move |x| {
891                    let mut var2 = var.clone();
892                    var2.domain = recons_domain(x);
893                    DeclarationKind::FindAuxiliary(var2)
894                }),
895            )
896        }
897        DeclarationKind::Given(domain) => {
898            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
899            (
900                tree,
901                Box::new(move |x| DeclarationKind::Given(recons_domain(x))),
902            )
903        }
904        DeclarationKind::DomainLetting(domain) => {
905            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
906            (
907                tree,
908                Box::new(move |x| DeclarationKind::DomainLetting(recons_domain(x))),
909            )
910        }
911        DeclarationKind::ValueLetting(expression, domain) => {
912            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expression);
913            (
914                tree,
915                Box::new(move |x| DeclarationKind::ValueLetting(recons_expr(x), domain.clone())),
916            )
917        }
918        DeclarationKind::TemporaryValueLetting(expression) => {
919            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expression);
920            (
921                tree,
922                Box::new(move |x| DeclarationKind::TemporaryValueLetting(recons_expr(x))),
923            )
924        }
925        DeclarationKind::Quantified(quantified) => {
926            let (domain_tree, recons_domain) =
927                biplate_domain_ptr_references(quantified.domain.clone());
928
929            let (generator_tree, recons_generator) = if let Some(generator) = quantified.generator()
930            {
931                let generator = generator.clone();
932                let (tree, recons_declaration) = Biplate::<Reference>::biplate(&generator);
933                (
934                    tree,
935                    Box::new(move |x| Some(recons_declaration(x)))
936                        as ReferenceReconstructor<Option<DeclarationPtr>>,
937                )
938            } else {
939                (
940                    Tree::Zero,
941                    Box::new(|_| None) as ReferenceReconstructor<Option<DeclarationPtr>>,
942                )
943            };
944
945            (
946                Tree::Many(VecDeque::from([domain_tree, generator_tree])),
947                Box::new(move |x| {
948                    let Tree::Many(mut children) = x else {
949                        panic!("unexpected biplate tree shape for quantified declaration")
950                    };
951
952                    let domain = children.pop_front().unwrap_or(Tree::Zero);
953                    let generator = children.pop_front().unwrap_or(Tree::Zero);
954
955                    let mut quantified2 = quantified.clone();
956                    quantified2.domain = recons_domain(domain);
957                    quantified2.generator = recons_generator(generator);
958                    DeclarationKind::Quantified(quantified2)
959                }),
960            )
961        }
962        DeclarationKind::QuantifiedExpr(expr) => {
963            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expr);
964            (
965                tree,
966                Box::new(move |x| DeclarationKind::QuantifiedExpr(recons_expr(x))),
967            )
968        }
969    }
970}
971
972impl IdPtr for DeclarationPtr {
973    type Data = Declaration;
974
975    fn get_data(&self) -> Self::Data {
976        self.read().clone()
977    }
978
979    fn with_id_and_data(id: ObjId, data: Self::Data) -> Self {
980        Self {
981            inner: DeclarationPtrInner::new_with_id_unchecked(RwLock::new(data), id),
982        }
983    }
984}
985
986impl Ord for DeclarationPtr {
987    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
988        self.inner.id.cmp(&other.inner.id)
989    }
990}
991
992impl PartialOrd for DeclarationPtr {
993    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
994        Some(self.cmp(other))
995    }
996}
997
998impl PartialEq for DeclarationPtr {
999    fn eq(&self, other: &Self) -> bool {
1000        self.inner.id == other.inner.id
1001    }
1002}
1003
1004impl Eq for DeclarationPtr {}
1005
1006impl std::hash::Hash for DeclarationPtr {
1007    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
1008        // invariant: x == y -> hash(x) == hash(y)
1009        self.inner.id.hash(state);
1010    }
1011}
1012
1013impl Display for DeclarationPtr {
1014    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
1015        let value: &Declaration = &self.read();
1016        value.fmt(f)
1017    }
1018}
1019
1020#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq, Uniplate)]
1021#[biplate(to=Expression)]
1022#[biplate(to=DeclarationPtr)]
1023#[biplate(to=Name)]
1024/// The contents of a declaration
1025pub struct Declaration {
1026    /// The name of the declared symbol.
1027    name: Name,
1028
1029    /// The kind of the declaration.
1030    kind: DeclarationKind,
1031}
1032
1033impl Declaration {
1034    /// Creates a new declaration.
1035    pub fn new(name: Name, kind: DeclarationKind) -> Declaration {
1036        Declaration { name, kind }
1037    }
1038}
1039
1040/// A specific kind of declaration.
1041#[non_exhaustive]
1042#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
1043#[biplate(to=Expression)]
1044#[biplate(to=DeclarationPtr)]
1045#[biplate(to=Declaration)]
1046pub enum DeclarationKind {
1047    Find(DecisionVariable),
1048
1049    /// A rewriter-introduced or `findAux`-declared decision variable that must not be branched on
1050    /// during search.
1051    ///
1052    /// Used for auxiliaries such as those created when rewriting `exists` into constraints.
1053    FindAuxiliary(DecisionVariable),
1054
1055    Given(DomainPtr),
1056    Quantified(Quantified),
1057    QuantifiedExpr(Expression),
1058
1059    /// Carries an optional domain so instantiated `given`s can retain their declared domain.
1060    ValueLetting(Expression, Option<DomainPtr>),
1061    DomainLetting(DomainPtr),
1062
1063    /// A short-lived value binding used internally during rewrites (e.g. comprehension unrolling).
1064    ///
1065    /// Unlike `ValueLetting`, this is not intended to represent a user-visible top-level `letting`.
1066    TemporaryValueLetting(Expression),
1067}
1068
1069impl DeclarationKind {
1070    /// Hashes declaration-kind contents without using declaration pointer identity.
1071    fn hash_content<H: Hasher>(&self, state: &mut H, seen: &mut BTreeSet<ObjId>) {
1072        mem::discriminant(self).hash(state);
1073        match self {
1074            DeclarationKind::Find(var) | DeclarationKind::FindAuxiliary(var) => {
1075                var.domain.hash(state);
1076                for representation in &var.representations {
1077                    for repr in representation {
1078                        repr.repr_name().hash(state);
1079                        if let Ok(declarations) = repr.declaration_down() {
1080                            for declaration in declarations {
1081                                declaration.hash_content(state, seen);
1082                            }
1083                        } else {
1084                            "unavailable-representation-declarations".hash(state);
1085                        }
1086                    }
1087                }
1088            }
1089            DeclarationKind::Given(domain) | DeclarationKind::DomainLetting(domain) => {
1090                domain.hash(state);
1091            }
1092            DeclarationKind::Quantified(quantified) => {
1093                quantified.domain.hash(state);
1094                if let Some(generator) = quantified.generator() {
1095                    generator.hash_content(state, seen);
1096                }
1097            }
1098            DeclarationKind::QuantifiedExpr(expr)
1099            | DeclarationKind::TemporaryValueLetting(expr) => {
1100                expr.cached_content_hash().hash(state);
1101                expr.to_string().hash(state);
1102            }
1103            DeclarationKind::ValueLetting(expr, domain) => {
1104                expr.cached_content_hash().hash(state);
1105                expr.to_string().hash(state);
1106                domain.hash(state);
1107            }
1108        }
1109    }
1110}
1111
1112#[serde_as]
1113#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
1114pub struct Quantified {
1115    domain: DomainPtr,
1116
1117    #[serde_as(as = "Option<PtrAsInner>")]
1118    generator: Option<DeclarationPtr>,
1119}
1120
1121impl Quantified {
1122    pub fn domain(&self) -> &DomainPtr {
1123        &self.domain
1124    }
1125
1126    pub fn generator(&self) -> Option<&DeclarationPtr> {
1127        self.generator.as_ref()
1128    }
1129}