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, Reference, ReturnType,
6
    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
3927050
    fn new(value: RwLock<Declaration>) -> Arc<DeclarationPtrInner> {
84
3927050
        Arc::new(DeclarationPtrInner {
85
3927050
            id: ObjId {
86
3927050
                type_name: ustr::ustr(DeclarationPtr::TYPE_NAME),
87
3927050
                object_id: DECLARATION_PTR_ID_COUNTER.fetch_add(1, Ordering::Relaxed),
88
3927050
            },
89
3927050
            value,
90
3927050
        })
91
3927050
    }
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
7520
    fn new_with_id_unchecked(value: RwLock<Declaration>, id: ObjId) -> Arc<DeclarationPtrInner> {
96
7520
        Arc::new(DeclarationPtrInner { id, value })
97
7520
    }
98
}
99

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

            
106
    /// Creates a `DeclarationPtr` for the given `Declaration`.
107
3925990
    fn from_declaration(declaration: Declaration) -> DeclarationPtr {
108
3925990
        DeclarationPtr {
109
3925990
            inner: DeclarationPtrInner::new(RwLock::new(declaration)),
110
3925990
        }
111
3925990
    }
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
3925990
    pub fn new(name: Name, kind: DeclarationKind) -> DeclarationPtr {
127
3925990
        DeclarationPtr::from_declaration(Declaration::new(name, kind))
128
3925990
    }
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
3907673
    pub fn new_find(name: Name, domain: DomainPtr) -> DeclarationPtr {
144
3907673
        let kind = DeclarationKind::Find(DecisionVariable::new(domain));
145
3907673
        DeclarationPtr::new(name, kind)
146
3907673
    }
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
516
    pub fn new_given(name: Name, domain: DomainPtr) -> DeclarationPtr {
162
516
        let kind = DeclarationKind::Given(domain);
163
516
        DeclarationPtr::new(name, kind)
164
516
    }
165

            
166
    /// Creates a new quantified declaration for local comprehension scopes.
167
    ///
168
    /// Used when creating the quantified variable in a generator.
169
9548
    pub fn new_quantified(name: Name, domain: DomainPtr) -> DeclarationPtr {
170
9548
        DeclarationPtr::new(
171
9548
            name,
172
9548
            DeclarationKind::Quantified(Quantified {
173
9548
                domain,
174
9548
                generator: None,
175
9548
            }),
176
        )
177
9548
    }
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
132
    pub fn new_quantified_expr(name: Name, expr: Expression) -> DeclarationPtr {
191
132
        let kind = DeclarationKind::QuantifiedExpr(expr);
192
132
        DeclarationPtr::new(name, kind)
193
132
    }
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
6841
    pub fn new_value_letting(name: Name, expression: Expression) -> DeclarationPtr {
213
6841
        let kind = DeclarationKind::ValueLetting(expression, None);
214
6841
        DeclarationPtr::new(name, kind)
215
6841
    }
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
1240
    pub fn new_domain_letting(name: Name, domain: DomainPtr) -> DeclarationPtr {
259
1240
        let kind = DeclarationKind::DomainLetting(domain);
260
1240
        DeclarationPtr::new(name, kind)
261
1240
    }
262

            
263
    /**********************************************/
264
    /*        Declaration accessor methods        */
265
    /**********************************************/
266

            
267
    /// Gets the domain of the declaration, if it has one.
268
    ///
269
    /// # Examples
270
    ///
271
    /// ```
272
    /// use conjure_cp_core::ast::{DeclarationPtr, Name, Domain, Range, GroundDomain};
273
    ///
274
    /// // find a: int(1..5)
275
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
276
    ///
277
    /// assert!(declaration.domain().is_some_and(|x| x.as_ground().unwrap() == &GroundDomain::Int(vec![Range::Bounded(1,5)])))
278
    ///
279
    /// ```
280
53960214
    pub fn domain(&self) -> Option<DomainPtr> {
281
53960214
        match &self.kind() as &DeclarationKind {
282
52637968
            DeclarationKind::Find(var) => Some(var.domain_of()),
283
330294
            DeclarationKind::ValueLetting(e, _) | DeclarationKind::TemporaryValueLetting(e) => {
284
330294
                e.domain_of()
285
            }
286
68308
            DeclarationKind::DomainLetting(domain) => Some(domain.clone()),
287
2400
            DeclarationKind::Given(domain) => Some(domain.clone()),
288
921020
            DeclarationKind::Quantified(inner) => Some(inner.domain.clone()),
289
224
            DeclarationKind::QuantifiedExpr(expr) => expr.domain_of(),
290
        }
291
53960214
    }
292

            
293
    /// Gets the domain of the declaration and fully resolve it
294
71656
    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
295
71656
        self.domain()?.resolve().ok()
296
71656
    }
297

            
298
    /// Gets the kind of the declaration.
299
    ///
300
    /// # Examples
301
    ///
302
    /// ```
303
    /// use conjure_cp_core::ast::{DeclarationPtr,DeclarationKind,Name,Domain,Range};
304
    ///
305
    /// // find a: int(1..5)
306
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
307
    /// assert!(matches!(&declaration.kind() as &DeclarationKind, DeclarationKind::Find(_)))
308
    /// ```
309
368142970
    pub fn kind(&self) -> MappedRwLockReadGuard<'_, DeclarationKind> {
310
368142970
        self.map(|x| &x.kind)
311
368142970
    }
312

            
313
    /// Gets the name of the declaration.
314
    ///
315
    /// # Examples
316
    ///
317
    /// ```
318
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
319
    ///
320
    /// // find a: int(1..5)
321
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
322
    ///
323
    /// assert_eq!(&declaration.name() as &Name, &Name::User("a".into()))
324
    /// ```
325
372972367
    pub fn name(&self) -> MappedRwLockReadGuard<'_, Name> {
326
372972367
        self.map(|x| &x.name)
327
372972367
    }
328

            
329
    /// This declaration as a decision variable, if it is one.
330
1246872480
    pub fn as_find(&self) -> Option<MappedRwLockReadGuard<'_, DecisionVariable>> {
331
1246872480
        RwLockReadGuard::try_map(self.read(), |x| {
332
1246872480
            if let DeclarationKind::Find(var) = &x.kind {
333
1241680664
                Some(var)
334
            } else {
335
5191816
                None
336
            }
337
1246872480
        })
338
1246872480
        .ok()
339
1246872480
    }
340

            
341
    /// This declaration as a mutable decision variable, if it is one.
342
32184
    pub fn as_find_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, DecisionVariable>> {
343
32184
        RwLockWriteGuard::try_map(self.write(), |x| {
344
32184
            if let DeclarationKind::Find(var) = &mut x.kind {
345
32184
                Some(var)
346
            } else {
347
                None
348
            }
349
32184
        })
350
32184
        .ok()
351
32184
    }
352

            
353
    /// This declaration as a domain letting, if it is one.
354
650272
    pub fn as_domain_letting(&self) -> Option<MappedRwLockReadGuard<'_, DomainPtr>> {
355
650272
        RwLockReadGuard::try_map(self.read(), |x| {
356
650272
            if let DeclarationKind::DomainLetting(domain) = &x.kind {
357
650252
                Some(domain)
358
            } else {
359
20
                None
360
            }
361
650272
        })
362
650272
        .ok()
363
650272
    }
364

            
365
    /// This declaration as a mutable domain letting, if it is one.
366
    pub fn as_domain_letting_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, DomainPtr>> {
367
        RwLockWriteGuard::try_map(self.write(), |x| {
368
            if let DeclarationKind::DomainLetting(domain) = &mut x.kind {
369
                Some(domain)
370
            } else {
371
                None
372
            }
373
        })
374
        .ok()
375
    }
376

            
377
    /// This declaration as a value letting, if it is one.
378
705600468
    pub fn as_value_letting(&self) -> Option<MappedRwLockReadGuard<'_, Expression>> {
379
705600468
        RwLockReadGuard::try_map(self.read(), |x| {
380
2344116
            if let DeclarationKind::ValueLetting(expression, _)
381
705600468
            | DeclarationKind::TemporaryValueLetting(expression) = &x.kind
382
            {
383
4591236
                Some(expression)
384
            } else {
385
701009232
                None
386
            }
387
705600468
        })
388
705600468
        .ok()
389
705600468
    }
390

            
391
    /// This declaration as a mutable value letting, if it is one.
392
876
    pub fn as_value_letting_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, Expression>> {
393
876
        RwLockWriteGuard::try_map(self.write(), |x| {
394
876
            if let DeclarationKind::ValueLetting(expression, _)
395
876
            | DeclarationKind::TemporaryValueLetting(expression) = &mut x.kind
396
            {
397
876
                Some(expression)
398
            } else {
399
                None
400
            }
401
876
        })
402
876
        .ok()
403
876
    }
404

            
405
    /// This declaration as a given statement, if it is one.
406
1372
    pub fn as_given(&self) -> Option<MappedRwLockReadGuard<'_, DomainPtr>> {
407
1372
        RwLockReadGuard::try_map(self.read(), |x| {
408
1372
            if let DeclarationKind::Given(domain) = &x.kind {
409
952
                Some(domain)
410
            } else {
411
420
                None
412
            }
413
1372
        })
414
1372
        .ok()
415
1372
    }
416

            
417
    /// This declaration as a mutable given statement, if it is one.
418
    pub fn as_given_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, DomainPtr>> {
419
        RwLockWriteGuard::try_map(self.write(), |x| {
420
            if let DeclarationKind::Given(domain) = &mut x.kind {
421
                Some(domain)
422
            } else {
423
                None
424
            }
425
        })
426
        .ok()
427
    }
428

            
429
    /// This declaration as a quantified expression, if it is one.
430
1576
    pub fn as_quantified_expr(&self) -> Option<MappedRwLockReadGuard<'_, Expression>> {
431
1576
        RwLockReadGuard::try_map(self.read(), |x| {
432
1576
            if let DeclarationKind::QuantifiedExpr(expr) = &x.kind {
433
1576
                Some(expr)
434
            } else {
435
                None
436
            }
437
1576
        })
438
1576
        .ok()
439
1576
    }
440

            
441
    /// This declaration as a mutable quantified expression, if it is one.
442
    pub fn as_quantified_expr_mut(&mut self) -> Option<MappedRwLockWriteGuard<'_, Expression>> {
443
        RwLockWriteGuard::try_map(self.write(), |x| {
444
            if let DeclarationKind::QuantifiedExpr(expr) = &mut x.kind {
445
                Some(expr)
446
            } else {
447
                None
448
            }
449
        })
450
        .ok()
451
    }
452

            
453
    /// Changes the name in this declaration, returning the old one.
454
    ///
455
    /// # Examples
456
    ///
457
    /// ```
458
    /// use conjure_cp_core::ast::{DeclarationPtr, Domain, Range, Name};
459
    ///
460
    /// // find a: int(1..5)
461
    /// let mut declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
462
    ///
463
    /// let old_name = declaration.replace_name(Name::User("b".into()));
464
    /// assert_eq!(old_name,Name::User("a".into()));
465
    /// assert_eq!(&declaration.name() as &Name,&Name::User("b".into()));
466
    /// ```
467
1100
    pub fn replace_name(&mut self, name: Name) -> Name {
468
1100
        let mut decl = self.write();
469
1100
        std::mem::replace(&mut decl.name, name)
470
1100
    }
471

            
472
    /// Replaces the underlying declaration kind and returns the previous kind.
473
    /// Note: this affects all cloned `DeclarationPtr`s pointing to the same declaration.
474
2085600
    pub fn replace_kind(&mut self, kind: DeclarationKind) -> DeclarationKind {
475
2085600
        let mut decl = self.write();
476
2085600
        std::mem::replace(&mut decl.kind, kind)
477
2085600
    }
478

            
479
    /*****************************************/
480
    /*        Pointer utility methods        */
481
    /*****************************************/
482

            
483
    // These are mostly wrappers over RefCell, Ref, and RefMut methods, re-exported here for
484
    // convenience.
485

            
486
    /// Read the underlying [Declaration].
487
    ///
488
    /// Will block the current thread until no other thread has a write lock.
489
    /// Attempting to get a read lock if the current thread already has one
490
    /// **will** cause it to deadlock.
491
    /// The lock is released when the returned guard goes out of scope.
492
2780279725
    fn read(&self) -> RwLockReadGuard<'_, Declaration> {
493
2780279725
        self.inner.value.read()
494
2780279725
    }
495

            
496
    /// Write the underlying [Declaration].
497
    ///
498
    /// Will block the current thread until no other thread has a read or write lock.
499
    /// The lock is released when the returned guard goes out of scope.
500
6162792
    fn write(&mut self) -> RwLockWriteGuard<'_, Declaration> {
501
6162792
        self.inner.value.write()
502
6162792
    }
503

            
504
    /// Creates a new declaration pointer with the same contents as `self` that is not shared with
505
    /// anyone else.
506
    ///
507
    /// As the resulting pointer is unshared, it will have a new id.
508
    ///
509
    /// # Examples
510
    ///
511
    /// ```
512
    /// use conjure_cp_core::ast::{DeclarationPtr,Name,Domain,Range};
513
    ///
514
    /// // find a: int(1..5)
515
    /// let declaration = DeclarationPtr::new_find(Name::User("a".into()),Domain::int(vec![Range::Bounded(1,5)]));
516
    ///
517
    /// let mut declaration2 = declaration.clone();
518
    ///
519
    /// declaration2.replace_name(Name::User("b".into()));
520
    ///
521
    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
522
    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
523
    ///
524
    /// declaration2 = declaration2.detach();
525
    ///
526
    /// assert_eq!(&declaration2.name() as &Name, &Name::User("b".into()));
527
    ///
528
    /// declaration2.replace_name(Name::User("c".into()));
529
    ///
530
    /// assert_eq!(&declaration.name() as &Name, &Name::User("b".into()));
531
    /// assert_eq!(&declaration2.name() as &Name, &Name::User("c".into()));
532
    /// ```
533
1060
    pub fn detach(self) -> DeclarationPtr {
534
        // despite having the same contents, the new declaration pointer is unshared, so it should
535
        // get a new id.
536
1060
        let value = self.inner.value.read().clone();
537
1060
        DeclarationPtr {
538
1060
            inner: DeclarationPtrInner::new(RwLock::new(value)),
539
1060
        }
540
1060
    }
541

            
542
    /// Applies `f` to the declaration, returning the result as a reference.
543
741115337
    fn map<U>(&self, f: impl FnOnce(&Declaration) -> &U) -> MappedRwLockReadGuard<'_, U> {
544
741115337
        RwLockReadGuard::map(self.read(), f)
545
741115337
    }
546

            
547
    /// Applies mutable function `f` to the declaration, returning the result as a mutable reference.
548
    fn map_mut<U>(
549
        &mut self,
550
        f: impl FnOnce(&mut Declaration) -> &mut U,
551
    ) -> MappedRwLockWriteGuard<'_, U> {
552
        RwLockWriteGuard::map(self.write(), f)
553
    }
554

            
555
    /// Replaces the declaration with a new one, returning the old value, without deinitialising
556
    /// either one.
557
420
    pub fn replace(&mut self, declaration: Declaration) -> Declaration {
558
420
        let mut guard = self.write();
559
420
        let ans = mem::replace(&mut *guard, declaration);
560
420
        drop(guard);
561
420
        ans
562
420
    }
563
}
564

            
565
impl CategoryOf for DeclarationPtr {
566
5679468
    fn category_of(&self) -> Category {
567
5679468
        match &self.kind() as &DeclarationKind {
568
5617316
            DeclarationKind::Find(decision_variable) => decision_variable.category_of(),
569
208
            DeclarationKind::ValueLetting(expression, _)
570
208
            | DeclarationKind::TemporaryValueLetting(expression) => expression.category_of(),
571
            DeclarationKind::DomainLetting(_) => Category::Constant,
572
488
            DeclarationKind::Given(_) => Category::Parameter,
573
59080
            DeclarationKind::Quantified(..) => Category::Quantified,
574
2376
            DeclarationKind::QuantifiedExpr(..) => Category::Quantified,
575
        }
576
5679468
    }
577
}
578
impl HasId for DeclarationPtr {
579
    const TYPE_NAME: &'static str = "DeclarationPtrInner";
580
13987616
    fn id(&self) -> ObjId {
581
13987616
        self.inner.id.clone()
582
13987616
    }
583
}
584

            
585
impl DefaultWithId for DeclarationPtr {
586
2800
    fn default_with_id(id: ObjId) -> Self {
587
2800
        DeclarationPtr {
588
2800
            inner: DeclarationPtrInner::new_with_id_unchecked(
589
2800
                RwLock::new(Declaration {
590
2800
                    name: Name::User("_UNKNOWN".into()),
591
2800
                    kind: DeclarationKind::ValueLetting(false.into(), None),
592
2800
                }),
593
2800
                id,
594
2800
            ),
595
2800
        }
596
2800
    }
597
}
598

            
599
impl Typeable for DeclarationPtr {
600
    fn return_type(&self) -> ReturnType {
601
        match &self.kind() as &DeclarationKind {
602
            DeclarationKind::Find(var) => var.return_type(),
603
            DeclarationKind::ValueLetting(expression, _)
604
            | DeclarationKind::TemporaryValueLetting(expression) => expression.return_type(),
605
            DeclarationKind::DomainLetting(domain) => domain.return_type(),
606
            DeclarationKind::Given(domain) => domain.return_type(),
607
            DeclarationKind::Quantified(inner) => inner.domain.return_type(),
608
            DeclarationKind::QuantifiedExpr(expr) => expr.return_type(),
609
        }
610
    }
611
}
612

            
613
impl Uniplate for DeclarationPtr {
614
4446332
    fn uniplate(&self) -> (Tree<Self>, Box<dyn Fn(Tree<Self>) -> Self>) {
615
4446332
        let decl = self.read();
616
4446332
        let (tree, recons) = Biplate::<DeclarationPtr>::biplate(&decl as &Declaration);
617

            
618
4446332
        let self2 = self.clone();
619
        (
620
4446332
            tree,
621
4446332
            Box::new(move |x| {
622
8456
                let mut self3 = self2.clone();
623
8456
                let inner = recons(x);
624
8456
                *(&mut self3.write() as &mut Declaration) = inner;
625
8456
                self3
626
8456
            }),
627
        )
628
4446332
    }
629
}
630

            
631
impl<To> Biplate<To> for DeclarationPtr
632
where
633
    Declaration: Biplate<To>,
634
    To: Uniplate,
635
{
636
86019420
    fn biplate(&self) -> (Tree<To>, Box<dyn Fn(Tree<To>) -> Self>) {
637
86019420
        if TypeId::of::<To>() == TypeId::of::<Self>() {
638
            unsafe {
639
4446332
                let self_as_to = std::mem::transmute::<&Self, &To>(self).clone();
640
                (
641
4446332
                    Tree::One(self_as_to),
642
4446332
                    Box::new(move |x| {
643
3712
                        let Tree::One(x) = x else { panic!() };
644

            
645
3712
                        let x_as_self = std::mem::transmute::<&To, &Self>(&x);
646
3712
                        x_as_self.clone()
647
3712
                    }),
648
                )
649
            }
650
        } else {
651
            // call biplate on the enclosed declaration
652
81573088
            let decl = self.read();
653
81573088
            let (tree, recons) = Biplate::<To>::biplate(&decl as &Declaration);
654

            
655
81573088
            let self2 = self.clone();
656
            (
657
81573088
                tree,
658
81573088
                Box::new(move |x| {
659
4034156
                    let mut self3 = self2.clone();
660
4034156
                    let inner = recons(x);
661
4034156
                    *(&mut self3.write() as &mut Declaration) = inner;
662
4034156
                    self3
663
4034156
                }),
664
            )
665
        }
666
86019420
    }
667
}
668

            
669
type ReferenceTree = Tree<Reference>;
670
type ReferenceReconstructor<T> = Box<dyn Fn(ReferenceTree) -> T>;
671

            
672
impl Biplate<Reference> for DeclarationPtr {
673
228344320
    fn biplate(&self) -> (ReferenceTree, ReferenceReconstructor<Self>) {
674
228344320
        let (tree, recons_kind) = biplate_declaration_kind_references(self.kind().clone());
675

            
676
228344320
        let self2 = self.clone();
677
        (
678
228344320
            tree,
679
228344320
            Box::new(move |x| {
680
                let mut self3 = self2.clone();
681
                let _ = self3.replace_kind(recons_kind(x));
682
                self3
683
            }),
684
        )
685
228344320
    }
686
}
687

            
688
228339116
fn biplate_domain_ptr_references(
689
228339116
    domain: DomainPtr,
690
228339116
) -> (ReferenceTree, ReferenceReconstructor<DomainPtr>) {
691
228339116
    let domain_inner = domain.as_ref().clone();
692
228339116
    let (tree, recons_domain) = Biplate::<Reference>::biplate(&domain_inner);
693
228339116
    (tree, Box::new(move |x| Moo::new(recons_domain(x))))
694
228339116
}
695

            
696
228344320
fn biplate_declaration_kind_references(
697
228344320
    kind: DeclarationKind,
698
228344320
) -> (ReferenceTree, ReferenceReconstructor<DeclarationKind>) {
699
228344320
    match kind {
700
227817080
        DeclarationKind::Find(var) => {
701
227817080
            let (tree, recons_domain) = biplate_domain_ptr_references(var.domain.clone());
702
            (
703
227817080
                tree,
704
227817080
                Box::new(move |x| {
705
                    let mut var2 = var.clone();
706
                    var2.domain = recons_domain(x);
707
                    DeclarationKind::Find(var2)
708
                }),
709
            )
710
        }
711
104
        DeclarationKind::Given(domain) => {
712
104
            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
713
            (
714
104
                tree,
715
104
                Box::new(move |x| DeclarationKind::Given(recons_domain(x))),
716
            )
717
        }
718
521932
        DeclarationKind::DomainLetting(domain) => {
719
521932
            let (tree, recons_domain) = biplate_domain_ptr_references(domain);
720
            (
721
521932
                tree,
722
521932
                Box::new(move |x| DeclarationKind::DomainLetting(recons_domain(x))),
723
            )
724
        }
725
5204
        DeclarationKind::ValueLetting(expression, domain) => {
726
5204
            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expression);
727
            (
728
5204
                tree,
729
5204
                Box::new(move |x| DeclarationKind::ValueLetting(recons_expr(x), domain.clone())),
730
            )
731
        }
732
        DeclarationKind::TemporaryValueLetting(expression) => {
733
            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expression);
734
            (
735
                tree,
736
                Box::new(move |x| DeclarationKind::TemporaryValueLetting(recons_expr(x))),
737
            )
738
        }
739
        DeclarationKind::Quantified(quantified) => {
740
            let (domain_tree, recons_domain) =
741
                biplate_domain_ptr_references(quantified.domain.clone());
742

            
743
            let (generator_tree, recons_generator) = if let Some(generator) = quantified.generator()
744
            {
745
                let generator = generator.clone();
746
                let (tree, recons_declaration) = Biplate::<Reference>::biplate(&generator);
747
                (
748
                    tree,
749
                    Box::new(move |x| Some(recons_declaration(x)))
750
                        as ReferenceReconstructor<Option<DeclarationPtr>>,
751
                )
752
            } else {
753
                (
754
                    Tree::Zero,
755
                    Box::new(|_| None) as ReferenceReconstructor<Option<DeclarationPtr>>,
756
                )
757
            };
758

            
759
            (
760
                Tree::Many(VecDeque::from([domain_tree, generator_tree])),
761
                Box::new(move |x| {
762
                    let Tree::Many(mut children) = x else {
763
                        panic!("unexpected biplate tree shape for quantified declaration")
764
                    };
765

            
766
                    let domain = children.pop_front().unwrap_or(Tree::Zero);
767
                    let generator = children.pop_front().unwrap_or(Tree::Zero);
768

            
769
                    let mut quantified2 = quantified.clone();
770
                    quantified2.domain = recons_domain(domain);
771
                    quantified2.generator = recons_generator(generator);
772
                    DeclarationKind::Quantified(quantified2)
773
                }),
774
            )
775
        }
776
        DeclarationKind::QuantifiedExpr(expr) => {
777
            let (tree, recons_expr) = Biplate::<Reference>::biplate(&expr);
778
            (
779
                tree,
780
                Box::new(move |x| DeclarationKind::QuantifiedExpr(recons_expr(x))),
781
            )
782
        }
783
    }
784
228344320
}
785

            
786
impl IdPtr for DeclarationPtr {
787
    type Data = Declaration;
788

            
789
18800
    fn get_data(&self) -> Self::Data {
790
18800
        self.read().clone()
791
18800
    }
792

            
793
4720
    fn with_id_and_data(id: ObjId, data: Self::Data) -> Self {
794
4720
        Self {
795
4720
            inner: DeclarationPtrInner::new_with_id_unchecked(RwLock::new(data), id),
796
4720
        }
797
4720
    }
798
}
799

            
800
impl Ord for DeclarationPtr {
801
    fn cmp(&self, other: &Self) -> std::cmp::Ordering {
802
        self.inner.id.cmp(&other.inner.id)
803
    }
804
}
805

            
806
impl PartialOrd for DeclarationPtr {
807
    fn partial_cmp(&self, other: &Self) -> Option<std::cmp::Ordering> {
808
        Some(self.cmp(other))
809
    }
810
}
811

            
812
impl PartialEq for DeclarationPtr {
813
93851772
    fn eq(&self, other: &Self) -> bool {
814
93851772
        self.inner.id == other.inner.id
815
93851772
    }
816
}
817

            
818
impl Eq for DeclarationPtr {}
819

            
820
impl std::hash::Hash for DeclarationPtr {
821
38364
    fn hash<H: std::hash::Hasher>(&self, state: &mut H) {
822
        // invariant: x == y -> hash(x) == hash(y)
823
38364
        self.inner.id.hash(state);
824
38364
    }
825
}
826

            
827
impl Display for DeclarationPtr {
828
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
829
        let value: &Declaration = &self.read();
830
        value.fmt(f)
831
    }
832
}
833

            
834
#[derive(Clone, PartialEq, Debug, Serialize, Deserialize, Eq, Uniplate)]
835
#[biplate(to=Expression)]
836
#[biplate(to=DeclarationPtr)]
837
#[biplate(to=Name)]
838
/// The contents of a declaration
839
pub struct Declaration {
840
    /// The name of the declared symbol.
841
    name: Name,
842

            
843
    /// The kind of the declaration.
844
    kind: DeclarationKind,
845
}
846

            
847
impl Declaration {
848
    /// Creates a new declaration.
849
3926410
    pub fn new(name: Name, kind: DeclarationKind) -> Declaration {
850
3926410
        Declaration { name, kind }
851
3926410
    }
852
}
853

            
854
/// A specific kind of declaration.
855
#[non_exhaustive]
856
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
857
#[biplate(to=Expression)]
858
#[biplate(to=DeclarationPtr)]
859
#[biplate(to=Declaration)]
860
pub enum DeclarationKind {
861
    Find(DecisionVariable),
862
    Given(DomainPtr),
863
    Quantified(Quantified),
864
    QuantifiedExpr(Expression),
865

            
866
    /// Carries an optional domain so instantiated `given`s can retain their declared domain.
867
    ValueLetting(Expression, Option<DomainPtr>),
868
    DomainLetting(DomainPtr),
869

            
870
    /// A short-lived value binding used internally during rewrites (e.g. comprehension unrolling).
871
    ///
872
    /// Unlike `ValueLetting`, this is not intended to represent a user-visible top-level `letting`.
873
    TemporaryValueLetting(Expression),
874
}
875

            
876
#[serde_as]
877
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize, Uniplate)]
878
pub struct Quantified {
879
    domain: DomainPtr,
880

            
881
    #[serde_as(as = "Option<PtrAsInner>")]
882
    generator: Option<DeclarationPtr>,
883
}
884

            
885
impl Quantified {
886
360
    pub fn domain(&self) -> &DomainPtr {
887
360
        &self.domain
888
360
    }
889

            
890
1417832
    pub fn generator(&self) -> Option<&DeclarationPtr> {
891
1417832
        self.generator.as_ref()
892
1417832
    }
893
}