Skip to main content

conjure_cp_core/ast/
declaration.rs

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