1
use super::categories::{Category, CategoryOf};
2
use super::name::Name;
3
use super::serde::{DefaultWithId, HasId, IdPtr, ObjId, PtrAsInner};
4
use super::{
5
    DecisionVariable, DomainPtr, Expression, GroundDomain, HasDomain, Moo, RecordEntry, Reference,
6
    ReturnType, Typeable,
7
};
8
use parking_lot::{
9
    MappedRwLockReadGuard, MappedRwLockWriteGuard, RwLock, RwLockReadGuard, RwLockWriteGuard,
10
};
11
use serde::{Deserialize, Serialize};
12
use serde_with::serde_as;
13
use std::any::TypeId;
14
use std::collections::VecDeque;
15
use std::fmt::{Debug, Display};
16
use std::mem;
17
use std::sync::Arc;
18
use std::sync::atomic::{AtomicU32, Ordering};
19
use uniplate::{Biplate, Tree, Uniplate};
20

            
21
/// Global counter of declarations.
22
/// Note that the counter is shared between all threads
23
/// Thus, when running multiple models in parallel, IDs may
24
/// be different with every run depending on scheduling order
25
static DECLARATION_PTR_ID_COUNTER: AtomicU32 = const { AtomicU32::new(0) };
26

            
27
#[doc(hidden)]
28
/// Resets the id counter of `DeclarationPtr` to 0.
29
///
30
/// This is probably always a bad idea.
31
pub fn reset_declaration_id_unchecked() {
32
    let _ = DECLARATION_PTR_ID_COUNTER.swap(0, Ordering::Relaxed);
33
}
34

            
35
/// A shared pointer to a [`Declaration`].
36
///
37
/// Two declaration pointers are equal if they point to the same underlying declaration.
38
///
39
/// # Id
40
///
41
///  The id of `DeclarationPtr` obeys the following invariants:
42
///
43
/// 1. Declaration pointers have the same id if they point to the same
44
///    underlying declaration.
45
///
46
/// 2. The id is immutable.
47
///
48
/// 3. Changing the declaration pointed to by the declaration pointer does not change the id. This
49
///    allows declarations to be updated by replacing them with a newer version of themselves.
50
///
51
/// `Ord`, `Hash`, and `Eq` use id for comparisons.
52
/// # Serde
53
///
54
/// Declaration pointers can be serialised using the following serializers:
55
///
56
/// + [`DeclarationPtrFull`](serde::DeclarationPtrFull)
57
/// + [`DeclarationPtrAsId`](serde::DeclarationPtrAsId)
58
///
59
/// See their documentation for more information.
60
#[derive(Clone, Debug)]
61
pub struct DeclarationPtr
62
where
63
    Self: Send + Sync,
64
{
65
    // the shared bits of the pointer
66
    inner: Arc<DeclarationPtrInner>,
67
}
68

            
69
// The bits of a declaration that are shared between all pointers.
70
#[derive(Debug)]
71
struct DeclarationPtrInner {
72
    // We don't want this to be mutable, as `HashMap` and `BTreeMap` rely on the hash or order of
73
    // keys to be unchanging.
74
    //
75
    // See:  https://rust-lang.github.io/rust-clippy/master/index.html#mutable_key_type
76
    id: ObjId,
77

            
78
    // The contents of the declaration itself should be mutable.
79
    value: RwLock<Declaration>,
80
}
81

            
82
impl DeclarationPtrInner {
83
3895069
    fn new(value: RwLock<Declaration>) -> Arc<DeclarationPtrInner> {
84
3895069
        Arc::new(DeclarationPtrInner {
85
3895069
            id: ObjId {
86
3895069
                type_name: ustr::ustr(DeclarationPtr::TYPE_NAME),
87
3895069
                object_id: DECLARATION_PTR_ID_COUNTER.fetch_add(1, Ordering::Relaxed),
88
3895069
            },
89
3895069
            value,
90
3895069
        })
91
3895069
    }
92

            
93
    // SAFETY: only use if you are really really sure you arn't going to break the id invariants of
94
    // DeclarationPtr and HasId!
95
3240
    fn new_with_id_unchecked(value: RwLock<Declaration>, id: ObjId) -> Arc<DeclarationPtrInner> {
96
3240
        Arc::new(DeclarationPtrInner { id, value })
97
3240
    }
98
}
99

            
100
#[allow(dead_code)]
101
impl DeclarationPtr {
102
    /******************************/
103
    /*        Constructors        */
104
    /******************************/
105

            
106
    /// Creates a `DeclarationPtr` for the given `Declaration`.
107
3894009
    fn from_declaration(declaration: Declaration) -> DeclarationPtr {
108
3894009
        DeclarationPtr {
109
3894009
            inner: DeclarationPtrInner::new(RwLock::new(declaration)),
110
3894009
        }
111
3894009
    }
112

            
113
    /// Creates a new declaration.
114
    ///
115
    /// # Examples
116
    ///
117
    /// ```
118
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
119
    ///
120
    /// // letting MyDomain be int(1..5)
121
    /// let declaration = DeclarationPtr::new(
122
    ///     Name::User("MyDomain".into()),
123
    ///     DeclarationKind::DomainLetting(Domain::int(vec![
124
    ///         Range::Bounded(1,5)])));
125
    /// ```
126
3894009
    pub fn new(name: Name, kind: DeclarationKind) -> DeclarationPtr {
127
3894009
        DeclarationPtr::from_declaration(Declaration::new(name, kind))
128
3894009
    }
129

            
130
    /// Creates a new find declaration.
131
    ///
132
    /// # Examples
133
    ///
134
    /// ```
135
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
136
    ///
137
    /// // find x: int(1..5)
138
    /// let declaration = DeclarationPtr::new_find(
139
    ///     Name::User("x".into()),
140
    ///     Domain::int(vec![Range::Bounded(1,5)]));
141
    ///
142
    /// ```
143
3877172
    pub fn new_find(name: Name, domain: DomainPtr) -> DeclarationPtr {
144
3877172
        let kind = DeclarationKind::Find(DecisionVariable::new(domain));
145
3877172
        DeclarationPtr::new(name, kind)
146
3877172
    }
147

            
148
    /// Creates a new given declaration.
149
    ///
150
    /// # Examples
151
    ///
152
    /// ```
153
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
154
    ///
155
    /// // given n: int(1..5)
156
    /// let declaration = DeclarationPtr::new_given(
157
    ///     Name::User("n".into()),
158
    ///     Domain::int(vec![Range::Bounded(1,5)]));
159
    ///
160
    /// ```
161
318
    pub fn new_given(name: Name, domain: DomainPtr) -> DeclarationPtr {
162
318
        let kind = DeclarationKind::Given(domain);
163
318
        DeclarationPtr::new(name, kind)
164
318
    }
165

            
166
    /// Creates a new quantified declaration for local comprehension scopes.
167
    ///
168
    /// Used when creating the quantified variable in a generator.
169
9104
    pub fn new_quantified(name: Name, domain: DomainPtr) -> DeclarationPtr {
170
9104
        DeclarationPtr::new(
171
9104
            name,
172
9104
            DeclarationKind::Quantified(Quantified {
173
9104
                domain,
174
9104
                generator: None,
175
9104
            }),
176
        )
177
9104
    }
178

            
179
    /// Creates a quantified declaration backed by a generator declaration.
180
    ///
181
    /// This is used in comprehensions to refer to a quantified variable that is already defined using a generator.
182
    pub fn new_quantified_from_generator(decl: &DeclarationPtr) -> Option<DeclarationPtr> {
183
        let kind = DeclarationKind::Quantified(Quantified {
184
            domain: decl.domain()?,
185
            generator: Some(decl.clone()),
186
        });
187
        Some(DeclarationPtr::new(decl.name().clone(), kind))
188
    }
189

            
190
80
    pub fn new_quantified_expr(name: Name, expr: Expression) -> DeclarationPtr {
191
80
        let kind = DeclarationKind::QuantifiedExpr(expr);
192
80
        DeclarationPtr::new(name, kind)
193
80
    }
194

            
195
    /// Creates a new value letting declaration.
196
    ///
197
    /// # Examples
198
    ///
199
    /// ```
200
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range, Expression,
201
    /// Literal,Atom,Moo};
202
    /// use conjure_cp_core::{matrix_expr,ast::Metadata};
203
    ///
204
    /// // letting n be 10 + 10
205
    /// let ten = Expression::Atomic(Metadata::new(),Atom::Literal(Literal::Int(10)));
206
    /// let expression = Expression::Sum(Metadata::new(),Moo::new(matrix_expr![ten.clone(),ten]));
207
    /// let declaration = DeclarationPtr::new_value_letting(
208
    ///     Name::User("n".into()),
209
    ///     expression);
210
    ///
211
    /// ```
212
5973
    pub fn new_value_letting(name: Name, expression: Expression) -> DeclarationPtr {
213
5973
        let kind = DeclarationKind::ValueLetting(expression, None);
214
5973
        DeclarationPtr::new(name, kind)
215
5973
    }
216

            
217
    /// Creates a new value letting declaration with domain.
218
    ///
219
    /// # Examples
220
    ///
221
    /// ```
222
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range, Expression,
223
    /// Literal,Atom,Moo,DomainPtr,Metadata};
224
    /// use conjure_cp_core::{matrix_expr};
225
    ///
226
    /// // letting n be 10 + 10
227
    /// let ten = Expression::Atomic(Metadata::new(),Atom::Literal(Literal::Int(10)));
228
    /// let expression = Expression::Sum(Metadata::new(),Moo::new(matrix_expr![ten.clone(),ten]));
229
    /// let domain = Domain::bool();
230
    /// let declaration = DeclarationPtr::new_value_letting_with_domain(
231
    ///     Name::User("n".into()),
232
    ///     expression,
233
    ///     domain,
234
    /// );
235
    /// ```
236
20
    pub fn new_value_letting_with_domain(
237
20
        name: Name,
238
20
        expression: Expression,
239
20
        domain: DomainPtr,
240
20
    ) -> DeclarationPtr {
241
20
        let kind = DeclarationKind::ValueLetting(expression, Some(domain));
242
20
        DeclarationPtr::new(name, kind)
243
20
    }
244

            
245
    /// Creates a new domain letting declaration.
246
    ///
247
    /// # Examples
248
    ///
249
    /// ```
250
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,DeclarationKind,Domain,Range};
251
    ///
252
    /// // letting MyDomain be int(1..5)
253
    /// let declaration = DeclarationPtr::new_domain_letting(
254
    ///     Name::User("MyDomain".into()),
255
    ///     Domain::int(vec![Range::Bounded(1,5)]));
256
    ///
257
    /// ```
258
1142
    pub fn new_domain_letting(name: Name, domain: DomainPtr) -> DeclarationPtr {
259
1142
        let kind = DeclarationKind::DomainLetting(domain);
260
1142
        DeclarationPtr::new(name, kind)
261
1142
    }
262

            
263
    /// Creates a new record field declaration.
264
    ///
265
    /// # Examples
266
    ///
267
    /// ```
268
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,RecordEntry,Domain,Range};
269
    ///
270
    /// // create declaration for field A in `find rec: record {A: int(0..1), B: int(0..2)}`
271
    ///
272
    /// let field = RecordEntry {
273
    ///     name: Name::User("n".into()),
274
    ///     domain: Domain::int(vec![Range::Bounded(1,5)])
275
    /// };
276
    ///
277
    /// let declaration = DeclarationPtr::new_record_field(field);
278
    /// ```
279
180
    pub fn new_record_field(entry: RecordEntry) -> DeclarationPtr {
280
180
        let kind = DeclarationKind::RecordField(entry.domain);
281
180
        DeclarationPtr::new(entry.name, kind)
282
180
    }
283

            
284
    /**********************************************/
285
    /*        Declaration accessor methods        */
286
    /**********************************************/
287

            
288
    /// Gets the domain of the declaration, if it has one.
289
    ///
290
    /// # Examples
291
    ///
292
    /// ```
293
    /// use conjure_cp_core::ast::{DeclarationPtr, Name, Domain, Range, GroundDomain};
294
    ///
295
    /// // find a: int(1..5)
296
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
297
    ///
298
    /// assert!(declaration.domain().is_some_and(|x| x.as_ground().unwrap() == &GroundDomain::Int(vec![Range::Bounded(1,5)])))
299
    ///
300
    /// ```
301
89166748
    pub fn domain(&self) -> Option<DomainPtr> {
302
89166748
        match &self.kind() as &DeclarationKind {
303
88129358
            DeclarationKind::Find(var) => Some(var.domain_of()),
304
288824
            DeclarationKind::ValueLetting(e, _) | DeclarationKind::TemporaryValueLetting(e) => {
305
288824
                e.domain_of()
306
            }
307
66908
            DeclarationKind::DomainLetting(domain) => Some(domain.clone()),
308
968
            DeclarationKind::Given(domain) => Some(domain.clone()),
309
674950
            DeclarationKind::Quantified(inner) => Some(inner.domain.clone()),
310
140
            DeclarationKind::QuantifiedExpr(expr) => expr.domain_of(),
311
5600
            DeclarationKind::RecordField(domain) => Some(domain.clone()),
312
        }
313
89166748
    }
314

            
315
    /// Gets the domain of the declaration and fully resolve it
316
71650
    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
317
71650
        self.domain()?.resolve()
318
71650
    }
319

            
320
    /// Gets the kind of the declaration.
321
    ///
322
    /// # Examples
323
    ///
324
    /// ```
325
    /// use conjure_cp_core::ast::{DeclarationPtr,DeclarationKind,Name,Domain,Range};
326
    ///
327
    /// // find a: int(1..5)
328
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
329
    /// assert!(matches!(&declaration.kind() as &DeclarationKind, DeclarationKind::Find(_)))
330
    /// ```
331
399010306
    pub fn kind(&self) -> MappedRwLockReadGuard<'_, DeclarationKind> {
332
399010306
        self.map(|x| &x.kind)
333
399010306
    }
334

            
335
    /// Gets the name of the declaration.
336
    ///
337
    /// # Examples
338
    ///
339
    /// ```
340
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
341
    ///
342
    /// // find a: int(1..5)
343
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
344
    ///
345
    /// assert_eq!(&declaration.name() as &Name, &Name::User("a".into()))
346
    /// ```
347
360559259
    pub fn name(&self) -> MappedRwLockReadGuard<'_, Name> {
348
360559259
        self.map(|x| &x.name)
349
360559259
    }
350

            
351
    /// This declaration as a decision variable, if it is one.
352
1189129970
    pub fn as_find(&self) -> Option<MappedRwLockReadGuard<'_, DecisionVariable>> {
353
1189129970
        RwLockReadGuard::try_map(self.read(), |x| {
354
1189129970
            if let DeclarationKind::Find(var) = &x.kind {
355
1184629670
                Some(var)
356
            } else {
357
4500300
                None
358
            }
359
1189129970
        })
360
1189129970
        .ok()
361
1189129970
    }
362

            
363
    /// This declaration as a mutable decision variable, if it is one.
364
31582
    pub fn as_find_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, DecisionVariable>> {
365
31582
        RwLockWriteGuard::try_map(self.write(), |x| {
366
31582
            if let DeclarationKind::Find(var) = &mut x.kind {
367
31582
                Some(var)
368
            } else {
369
                None
370
            }
371
31582
        })
372
31582
        .ok()
373
31582
    }
374

            
375
    /// This declaration as a domain letting, if it is one.
376
567252
    pub fn as_domain_letting(&self) -> Option<MappedRwLockReadGuard<'_, DomainPtr>> {
377
567252
        RwLockReadGuard::try_map(self.read(), |x| {
378
567252
            if let DeclarationKind::DomainLetting(domain) = &x.kind {
379
567232
                Some(domain)
380
            } else {
381
20
                None
382
            }
383
567252
        })
384
567252
        .ok()
385
567252
    }
386

            
387
    /// This declaration as a mutable domain letting, if it is one.
388
    pub fn as_domain_letting_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, DomainPtr>> {
389
        RwLockWriteGuard::try_map(self.write(), |x| {
390
            if let DeclarationKind::DomainLetting(domain) = &mut x.kind {
391
                Some(domain)
392
            } else {
393
                None
394
            }
395
        })
396
        .ok()
397
    }
398

            
399
    /// This declaration as a value letting, if it is one.
400
693653060
    pub fn as_value_letting(&self) -> Option<MappedRwLockReadGuard<'_, Expression>> {
401
693653060
        RwLockReadGuard::try_map(self.read(), |x| {
402
1929592
            if let DeclarationKind::ValueLetting(expression, _)
403
693653060
            | DeclarationKind::TemporaryValueLetting(expression) = &x.kind
404
            {
405
4136672
                Some(expression)
406
            } else {
407
689516388
                None
408
            }
409
693653060
        })
410
693653060
        .ok()
411
693653060
    }
412

            
413
    /// This declaration as a mutable value letting, if it is one.
414
838
    pub fn as_value_letting_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, Expression>> {
415
838
        RwLockWriteGuard::try_map(self.write(), |x| {
416
838
            if let DeclarationKind::ValueLetting(expression, _)
417
838
            | DeclarationKind::TemporaryValueLetting(expression) = &mut x.kind
418
            {
419
838
                Some(expression)
420
            } else {
421
                None
422
            }
423
838
        })
424
838
        .ok()
425
838
    }
426

            
427
    /// This declaration as a given statement, if it is one.
428
866
    pub fn as_given(&self) -> Option<MappedRwLockReadGuard<'_, DomainPtr>> {
429
866
        RwLockReadGuard::try_map(self.read(), |x| {
430
866
            if let DeclarationKind::Given(domain) = &x.kind {
431
616
                Some(domain)
432
            } else {
433
250
                None
434
            }
435
866
        })
436
866
        .ok()
437
866
    }
438

            
439
    /// This declaration as a mutable given statement, if it is one.
440
    pub fn as_given_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, DomainPtr>> {
441
        RwLockWriteGuard::try_map(self.write(), |x| {
442
            if let DeclarationKind::Given(domain) = &mut x.kind {
443
                Some(domain)
444
            } else {
445
                None
446
            }
447
        })
448
        .ok()
449
    }
450

            
451
    /// This declaration as a quantified expression, if it is one.
452
922
    pub fn as_quantified_expr(&self) -> Option<MappedRwLockReadGuard<'_, Expression>> {
453
922
        RwLockReadGuard::try_map(self.read(), |x| {
454
922
            if let DeclarationKind::QuantifiedExpr(expr) = &x.kind {
455
922
                Some(expr)
456
            } else {
457
                None
458
            }
459
922
        })
460
922
        .ok()
461
922
    }
462

            
463
    /// This declaration as a mutable quantified expression, if it is one.
464
    pub fn as_quantified_expr_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, Expression>> {
465
        RwLockWriteGuard::try_map(self.write(), |x| {
466
            if let DeclarationKind::QuantifiedExpr(expr) = &mut x.kind {
467
                Some(expr)
468
            } else {
469
                None
470
            }
471
        })
472
        .ok()
473
    }
474

            
475
    /// Changes the name in this declaration, returning the old one.
476
    ///
477
    /// # Examples
478
    ///
479
    /// ```
480
    /// use conjure_cp_core::ast::{DeclarationPtr, Domain, Range, Name};
481
    ///
482
    /// // find a: int(1..5)
483
    /// let mut declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
484
    ///
485
    /// let old_name = declaration.replace_name(Name::User("b".into()));
486
    /// assert_eq!(old_name,Name::User("a".into()));
487
    /// assert_eq!(&declaration.name() as &Name,&Name::User("b".into()));
488
    /// ```
489
1100
    pub fn replace_name(&mut self, name: Name) -> Name {
490
1100
        let mut decl = self.write();
491
1100
        std::mem::replace(&mut decl.name, name)
492
1100
    }
493

            
494
    /// Replaces the underlying declaration kind and returns the previous kind.
495
    /// Note: this affects all cloned `DeclarationPtr`s pointing to the same declaration.
496
1707148
    pub fn replace_kind(&mut self, kind: DeclarationKind) -> DeclarationKind {
497
1707148
        let mut decl = self.write();
498
1707148
        std::mem::replace(&mut decl.kind, kind)
499
1707148
    }
500

            
501
    /*****************************************/
502
    /*        Pointer utility methods        */
503
    /*****************************************/
504

            
505
    // These are mostly wrappers over RefCell, Ref, and RefMut methods, re-exported here for
506
    // convenience.
507

            
508
    /// Read the underlying [Declaration].
509
    ///
510
    /// Will block the current thread until no other thread has a write lock.
511
    /// Attempting to get a read lock if the current thread already has one
512
    /// **will** cause it to deadlock.
513
    /// The lock is released when the returned guard goes out of scope.
514
2726556303
    fn read(&self) -> RwLockReadGuard<'_, Declaration> {
515
2726556303
        self.inner.value.read()
516
2726556303
    }
517

            
518
    /// Write the underlying [Declaration].
519
    ///
520
    /// Will block the current thread until no other thread has a read or write lock.
521
    /// The lock is released when the returned guard goes out of scope.
522
5674952
    fn write(&mut self) -> RwLockWriteGuard<'_, Declaration> {
523
5674952
        self.inner.value.write()
524
5674952
    }
525

            
526
    /// Creates a new declaration pointer with the same contents as `self` that is not shared with
527
    /// anyone else.
528
    ///
529
    /// As the resulting pointer is unshared, it will have a new id.
530
    ///
531
    /// # Examples
532
    ///
533
    /// ```
534
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
535
    ///
536
    /// // find a: int(1..5)
537
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
538
    ///
539
    /// let mut declaration2 = declaration.clone();
540
    ///
541
    /// declaration2.replace_name(Name::User("b".into()));
542
    ///
543
    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
544
    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
545
    ///
546
    /// declaration2 = declaration2.detach();
547
    ///
548
    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
549
    ///
550
    /// declaration2.replace_name(Name::User("c".into()));
551
    ///
552
    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
553
    /// assert_eq!(&declaration2.name() as &Name, &Name::User("c".into()));
554
    /// ```
555
1060
    pub fn detach(self) -> DeclarationPtr {
556
        // despite having the same contents, the new declaration pointer is unshared, so it should
557
        // get a new id.
558
1060
        let value = self.inner.value.read().clone();
559
1060
        DeclarationPtr {
560
1060
            inner: DeclarationPtrInner::new(RwLock::new(value)),
561
1060
        }
562
1060
    }
563

            
564
    /// Applies `f` to the declaration, returning the result as a reference.
565
759569565
    fn map<U>(&self, f: impl FnOnce(&Declaration) -> &U) -> MappedRwLockReadGuard<'_, U> {
566
759569565
        RwLockReadGuard::map(self.read(), f)
567
759569565
    }
568

            
569
    /// Applies mutable function `f` to the declaration, returning the result as a mutable reference.
570
    fn map_mut<U>(
571
        &mut self,
572
        f: impl FnOnce(&mut Declaration) -> &mut U,
573
    ) -> MappedRwLockWriteGuard<'_, U> {
574
        RwLockWriteGuard::map(self.write(), f)
575
    }
576

            
577
    /// Replaces the declaration with a new one, returning the old value, without deinitialising
578
    /// either one.
579
230
    pub fn replace(&mut self, declaration: Declaration) -> Declaration {
580
230
        let mut guard = self.write();
581
230
        let ans = mem::replace(&mut *guard, declaration);
582
230
        drop(guard);
583
230
        ans
584
230
    }
585
}
586

            
587
impl CategoryOf for DeclarationPtr {
588
5464022
    fn category_of(&self) -> Category {
589
5464022
        match &self.kind() as &DeclarationKind {
590
5403578
            DeclarationKind::Find(decision_variable) => decision_variable.category_of(),
591
184
            DeclarationKind::ValueLetting(expression, _)
592
184
            | DeclarationKind::TemporaryValueLetting(expression) => expression.category_of(),
593
            DeclarationKind::DomainLetting(_) => Category::Constant,
594
244
            DeclarationKind::Given(_) => Category::Parameter,
595
58860
            DeclarationKind::Quantified(..) => Category::Quantified,
596
1156
            DeclarationKind::QuantifiedExpr(..) => Category::Quantified,
597
            DeclarationKind::RecordField(_) => Category::Bottom,
598
        }
599
5464022
    }
600
}
601
impl HasId for DeclarationPtr {
602
    const TYPE_NAME: &'static str = "DeclarationPtrInner";
603
13709132
    fn id(&self) -> ObjId {
604
13709132
        self.inner.id.clone()
605
13709132
    }
606
}
607

            
608
impl DefaultWithId for DeclarationPtr {
609
1240
    fn default_with_id(id: ObjId) -> Self {
610
1240
        DeclarationPtr {
611
1240
            inner: DeclarationPtrInner::new_with_id_unchecked(
612
1240
                RwLock::new(Declaration {
613
1240
                    name: Name::User("_UNKNOWN".into()),
614
1240
                    kind: DeclarationKind::ValueLetting(false.into(), None),
615
1240
                }),
616
1240
                id,
617
1240
            ),
618
1240
        }
619
1240
    }
620
}
621

            
622
impl Typeable for DeclarationPtr {
623
    fn return_type(&self) -> ReturnType {
624
        match &self.kind() as &DeclarationKind {
625
            DeclarationKind::Find(var) => var.return_type(),
626
            DeclarationKind::ValueLetting(expression, _)
627
            | DeclarationKind::TemporaryValueLetting(expression) => expression.return_type(),
628
            DeclarationKind::DomainLetting(domain) => domain.return_type(),
629
            DeclarationKind::Given(domain) => domain.return_type(),
630
            DeclarationKind::Quantified(inner) => inner.domain.return_type(),
631
            DeclarationKind::QuantifiedExpr(expr) => expr.return_type(),
632
            DeclarationKind::RecordField(domain) => domain.return_type(),
633
        }
634
    }
635
}
636

            
637
impl Uniplate for DeclarationPtr {
638
4334368
    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
639
4334368
        let decl = self.read();
640
4334368
        let (tree, recons) = Biplate::<DeclarationPtr>::biplate(&decl as &Declaration);
641

            
642
4334368
        let self2 = self.clone();
643
        (
644
4334368
            tree,
645
4334368
            Box::new(move |x| {
646
6956
                let mut self3 = self2.clone();
647
6956
                let inner = recons(x);
648
6956
                *(&mut self3.write() as &mut Declaration) = inner;
649
6956
                self3
650
6956
            }),
651
        )
652
4334368
    }
653
}
654

            
655
impl<To> Biplate<To> for DeclarationPtr
656
where
657
    Declaration: Biplate<To>,
658
    To: Uniplate,
659
{
660
83624958
    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
661
83624958
        if TypeId::of::<To>() == TypeId::of::<Self>() {
662
            unsafe {
663
4334368
                let self_as_to = std::mem::transmute::<&Self, &To>(self).clone();
664
                (
665
4334368
                    Tree::One(self_as_to),
666
4334368
                    Box::new(move |x| {
667
3612
                        let Tree::One(x) = x else { panic!() };
668

            
669
3612
                        let x_as_self = std::mem::transmute::<&To, &Self>(&x);
670
3612
                        x_as_self.clone()
671
3612
                    }),
672
                )
673
            }
674
        } else {
675
            // call biplate on the enclosed declaration
676
79290590
            let decl = self.read();
677
79290590
            let (tree, recons) = Biplate::<To>::biplate(&decl as &Declaration);
678

            
679
79290590
            let self2 = self.clone();
680
            (
681
79290590
                tree,
682
79290590
                Box::new(move |x| {
683
3927098
                    let mut self3 = self2.clone();
684
3927098
                    let inner = recons(x);
685
3927098
                    *(&mut self3.write() as &mut Declaration) = inner;
686
3927098
                    self3
687
3927098
                }),
688
            )
689
        }
690
83624958
    }
691
}
692

            
693
type ReferenceTree = Tree<Reference>;
694
type ReferenceReconstructor<T> = Box<dyn Fn(ReferenceTree) -> T>;
695

            
696
impl Biplate<Reference> for DeclarationPtr {
697
226159160
    fn biplate(&self) -> (ReferenceTree, ReferenceReconstructor<Self>) {
698
226159160
        let (tree, recons_kind) = biplate_declaration_kind_references(self.kind().clone());
699

            
700
226159160
        let self2 = self.clone();
701
        (
702
226159160
            tree,
703
226159160
            Box::new(move |x| {
704
                let mut self3 = self2.clone();
705
                let _ = self3.replace_kind(recons_kind(x));
706
                self3
707
            }),
708
        )
709
226159160
    }
710
}
711

            
712
226154118
fn biplate_domain_ptr_references(
713
226154118
    domain: DomainPtr,
714
226154118
) -> (ReferenceTree, ReferenceReconstructor<DomainPtr>) {
715
226154118
    let domain_inner = domain.as_ref().clone();
716
226154118
    let (tree, recons_domain) = Biplate::<Reference>::biplate(&domain_inner);
717
226154118
    (tree, Box::new(move |x| Moo::new(recons_domain(x))))
718
226154118
}
719

            
720
226159160
fn biplate_declaration_kind_references(
721
226159160
    kind: DeclarationKind,
722
226159160
) -> (ReferenceTree, ReferenceReconstructor<DeclarationKind>) {
723
226159160
    match kind {
724
225591390
        DeclarationKind::Find(var) => {
725
225591390
            let (tree, recons_domain) = biplate_domain_ptr_references(var.domain.clone());
726
            (
727
225591390
                tree,
728
225591390
                Box::new(move |x| {
729
                    let mut var2 = var.clone();
730
                    var2.domain = recons_domain(x);
731
                    DeclarationKind::Find(var2)
732
                }),
733
            )
734
        }
735
92
        DeclarationKind::Given(domain) => {
736
92
            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
737
            (
738
92
                tree,
739
92
                Box::new(move |x| DeclarationKind::Given(recons_domain(x))),
740
            )
741
        }
742
562196
        DeclarationKind::DomainLetting(domain) => {
743
562196
            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
744
            (
745
562196
                tree,
746
562196
                Box::new(move |x| DeclarationKind::DomainLetting(recons_domain(x))),
747
            )
748
        }
749
440
        DeclarationKind::RecordField(domain) => {
750
440
            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
751
            (
752
440
                tree,
753
440
                Box::new(move |x| DeclarationKind::RecordField(recons_domain(x))),
754
            )
755
        }
756
5042
        DeclarationKind::ValueLetting(expression, domain) => {
757
5042
            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expression);
758
            (
759
5042
                tree,
760
5042
                Box::new(move |x| DeclarationKind::ValueLetting(recons_expr(x), domain.clone())),
761
            )
762
        }
763
        DeclarationKind::TemporaryValueLetting(expression) => {
764
            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expression);
765
            (
766
                tree,
767
                Box::new(move |x| DeclarationKind::TemporaryValueLetting(recons_expr(x))),
768
            )
769
        }
770
        DeclarationKind::Quantified(quantified) => {
771
            let (domain_tree, recons_domain) =
772
                biplate_domain_ptr_references(quantified.domain.clone());
773

            
774
            let (generator_tree, recons_generator) = if let Some(generator) = quantified.generator()
775
            {
776
                let generator = generator.clone();
777
                let (tree, recons_declaration) = Biplate::<Reference>::biplate(&generator);
778
                (
779
                    tree,
780
                    Box::new(move |x| Some(recons_declaration(x)))
781
                        as ReferenceReconstructor<Option<DeclarationPtr>>,
782
                )
783
            } else {
784
                (
785
                    Tree::Zero,
786
                    Box::new(|_| None) as ReferenceReconstructor<Option<DeclarationPtr>>,
787
                )
788
            };
789

            
790
            (
791
                Tree::Many(VecDeque::from([domain_tree, generator_tree])),
792
                Box::new(move |x| {
793
                    let Tree::Many(mut children) = x else {
794
                        panic!("unexpected biplate tree shape for quantified declaration")
795
                    };
796

            
797
                    let domain = children.pop_front().unwrap_or(Tree::Zero);
798
                    let generator = children.pop_front().unwrap_or(Tree::Zero);
799

            
800
                    let mut quantified2 = quantified.clone();
801
                    quantified2.domain = recons_domain(domain);
802
                    quantified2.generator = recons_generator(generator);
803
                    DeclarationKind::Quantified(quantified2)
804
                }),
805
            )
806
        }
807
        DeclarationKind::QuantifiedExpr(expr) => {
808
            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expr);
809
            (
810
                tree,
811
                Box::new(move |x| DeclarationKind::QuantifiedExpr(recons_expr(x))),
812
            )
813
        }
814
    }
815
226159160
}
816

            
817
impl IdPtr for DeclarationPtr {
818
    type Data = Declaration;
819

            
820
9710
    fn get_data(&self) -> Self::Data {
821
9710
        self.read().clone()
822
9710
    }
823

            
824
2000
    fn with_id_and_data(id: ObjId, data: Self::Data) -> Self {
825
2000
        Self {
826
2000
            inner: DeclarationPtrInner::new_with_id_unchecked(RwLock::new(data), id),
827
2000
        }
828
2000
    }
829
}
830

            
831
impl Ord for DeclarationPtr {
832
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
833
        self.inner.id.cmp(&other.inner.id)
834
    }
835
}
836

            
837
impl PartialOrd for DeclarationPtr {
838
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
839
        Some(self.cmp(other))
840
    }
841
}
842

            
843
impl PartialEq for DeclarationPtr {
844
86241774
    fn eq(&self, other: &Self) -> bool {
845
86241774
        self.inner.id == other.inner.id
846
86241774
    }
847
}
848

            
849
impl Eq for DeclarationPtr {}
850

            
851
impl std::hash::Hash for DeclarationPtr {
852
35452
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
853
        // invariant: x == y -> hash(x) == hash(y)
854
35452
        self.inner.id.hash(state);
855
35452
    }
856
}
857

            
858
impl Display for DeclarationPtr {
859
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
860
        let value: &Declaration = &self.read();
861
        value.fmt(f)
862
    }
863
}
864

            
865
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq, Uniplate)]
866
#[biplate(to=Expression)]
867
#[biplate(to=DeclarationPtr)]
868
#[biplate(to=Name)]
869
/// The contents of a declaration
870
pub struct Declaration {
871
    /// The name of the declared symbol.
872
    name: Name,
873

            
874
    /// The kind of the declaration.
875
    kind: DeclarationKind,
876
}
877

            
878
impl Declaration {
879
    /// Creates a new declaration.
880
3894239
    pub fn new(name: Name, kind: DeclarationKind) -> Declaration {
881
3894239
        Declaration { name, kind }
882
3894239
    }
883
}
884

            
885
/// A specific kind of declaration.
886
#[non_exhaustive]
887
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
888
#[biplate(to=Expression)]
889
#[biplate(to=DeclarationPtr)]
890
#[biplate(to=Declaration)]
891
pub enum DeclarationKind {
892
    Find(DecisionVariable),
893
    Given(DomainPtr),
894
    Quantified(Quantified),
895
    QuantifiedExpr(Expression),
896

            
897
    /// Carries an optional domain so instantiated `given`s can retain their declared domain.
898
    ValueLetting(Expression, Option<DomainPtr>),
899
    DomainLetting(DomainPtr),
900

            
901
    /// A short-lived value binding used internally during rewrites (e.g. comprehension unrolling).
902
    ///
903
    /// Unlike `ValueLetting`, this is not intended to represent a user-visible top-level `letting`.
904
    TemporaryValueLetting(Expression),
905

            
906
    /// A named field inside a record type.
907
    /// e.g. A, B in record{A: int(0..1), B: int(0..2)}
908
    RecordField(DomainPtr),
909
}
910

            
911
#[serde_as]
912
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
913
pub struct Quantified {
914
    domain: DomainPtr,
915

            
916
    #[serde_as(as = "Option<PtrAsInner>")]
917
    generator: Option<DeclarationPtr>,
918
}
919

            
920
impl Quantified {
921
80
    pub fn domain(&self) -> &DomainPtr {
922
80
        &self.domain
923
80
    }
924

            
925
1034416
    pub fn generator(&self) -> Option<&DeclarationPtr> {
926
1034416
        self.generator.as_ref()
927
1034416
    }
928
}