1
use crate::ast::serde::{AsId, HasId};
2
use crate::representation::types::ReprGetOrInitResult;
3
use crate::representation::{
4
    ReferenceReprError, ReprError, ReprRule, ReprRulePtr, ReprSelectError, ReprStateStored,
5
};
6
use crate::{ast::DeclarationPtr, bug};
7
use derivative::Derivative;
8
use parking_lot::{MappedRwLockReadGuard, RwLockReadGuard};
9
use serde::{Deserialize, Serialize};
10
use serde_with::serde_as;
11
use std::fmt::{Display, Formatter};
12
use uniplate::Uniplate;
13

            
14
use super::{
15
    Atom, DeclarationKind, DomainPtr, Expression, GroundDomain, Literal, Metadata, Moo, Name,
16
    ReturnType,
17
    categories::{Category, CategoryOf},
18
    domains::HasDomain,
19
};
20

            
21
/// A reference to a declaration (variable, parameter, etc.)
22
///
23
/// This is a thin wrapper around [`DeclarationPtr`] with two main purposes:
24
/// 1. Encapsulate the serde pragmas (e.g., serializing as IDs rather than full objects)
25
/// 2. Enable type-directed traversals of references via uniplate
26
#[serde_as]
27
#[derive(
28
    Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Serialize, Deserialize, Uniplate, Derivative,
29
)]
30
#[derivative(Hash)]
31
#[uniplate()]
32
#[biplate(to=DeclarationPtr)]
33
#[biplate(to=Name)]
34
pub struct Reference {
35
    #[serde_as(as = "AsId")]
36
    pub ptr: DeclarationPtr,
37
    pub repr: Option<ReprRulePtr>,
38
}
39

            
40
impl Reference {
41
765066000
    pub fn new(ptr: DeclarationPtr) -> Self {
42
765066000
        Reference { ptr, repr: None }
43
765066000
    }
44

            
45
3414414314
    pub fn ptr(&self) -> &DeclarationPtr {
46
3414414314
        &self.ptr
47
3414414314
    }
48

            
49
    pub fn into_ptr(self) -> DeclarationPtr {
50
        self.ptr
51
    }
52

            
53
4501084940
    pub fn name(&self) -> MappedRwLockReadGuard<'_, Name> {
54
4501084940
        self.ptr.name()
55
4501084940
    }
56

            
57
66991353
    pub fn id(&self) -> crate::ast::serde::ObjId {
58
66991353
        self.ptr.id()
59
66991353
    }
60

            
61
1978610679
    pub fn domain(&self) -> Option<DomainPtr> {
62
1978610679
        self.ptr.domain()
63
1978610679
    }
64

            
65
37692983
    pub fn resolved_domain(&self) -> Option<Moo<GroundDomain>> {
66
37692983
        self.domain()?.resolve().ok()
67
37692983
    }
68

            
69
    /// Select the given representation for this reference, if it is currently unrepresented
70
    /// and the representation exists for the underlying variable.
71
    ///
72
    /// # Errors
73
    /// - [ReprSelectError::AlreadySelected] if a different representation is already selected for this reference
74
    /// - [ReprSelectError::DoesNotExist] if the representation does not exist for this variable
75
    ///
76
    /// # Returns
77
    /// State of the initialised representation
78
22
    pub fn select_repr<R: ReprRule + ?Sized>(
79
22
        &mut self,
80
22
    ) -> Result<MappedRwLockReadGuard<'_, R::DeclLevel>, ReprSelectError> {
81
22
        let _ = self.select_repr_via(R::STORED);
82
22
        Ok(self.repr_state_as_unchecked::<R>())
83
22
    }
84

            
85
    /// Same as [Reference::select_repr], but type-erased
86
870
    pub fn select_repr_via(
87
870
        &mut self,
88
870
        rule: ReprRulePtr,
89
870
    ) -> Result<MappedRwLockReadGuard<'_, dyn ReprStateStored>, ReprSelectError> {
90
870
        if let Some(repr) = self.repr
91
            && repr != rule
92
        {
93
            return Err(ReprSelectError::AlreadySelected(repr));
94
870
        }
95
870
        if !self.ptr.reprs().has_repr(rule) {
96
            return Err(ReprSelectError::DoesNotExist(self.ptr.clone(), rule.name()));
97
870
        }
98
870
        self.repr = Some(rule);
99
870
        Ok(self.repr_state_unchecked())
100
870
    }
101

            
102
    /// Same as [Reference::select_or_init_repr], but type-erased
103
17561521
    pub fn select_or_init_repr_via(
104
17561521
        &mut self,
105
17561521
        rule: ReprRulePtr,
106
17561521
    ) -> ReprGetOrInitResult<'_, dyn ReprStateStored, ReferenceReprError> {
107
17561521
        if let Some(repr) = self.repr
108
            && repr != rule
109
        {
110
            return Err(ReprSelectError::AlreadySelected(repr).into());
111
17561521
        }
112
17561521
        self.update_or_init_repr_via(rule).map_err(Into::into)
113
17561521
    }
114

            
115
    /// Select the given representation for this reference, initialising it if necessary.
116
    /// Will fail if a different representation is already selected.
117
    ///
118
    /// # Errors
119
    /// - [ReprSelectError] if a different representation is already selected for this reference
120
    /// - [ReprInitError] | [ReprInstantiateError] if the representation could not be initialised
121
    ///
122
    /// # Returns
123
    ///
124
    /// `(state, symbols, constraints)`
125
    /// where:
126
    /// - `state` is an instance of the given representation
127
    /// - `symbols` are new variables created by the representation
128
    /// - `constraints` are new top-level constraints created by the representation
129
    pub fn select_or_init_repr<R: ReprRule + ?Sized>(
130
        &mut self,
131
    ) -> ReprGetOrInitResult<'_, R::DeclLevel, ReferenceReprError> {
132
        let (_, symbols, constraints) = self.select_or_init_repr_via(R::STORED)?;
133
        let state = self.repr_state_as_unchecked::<R>();
134
        Ok((state, symbols, constraints))
135
    }
136

            
137
    /// Select the given representation for this reference, initialising it if necessary.
138
    /// Will overwrite the existing selection.
139
    ///
140
    /// # Errors
141
    /// - [ReprInitError] | [ReprInstantiateError] if the representation could not be initialised
142
    ///
143
    /// # Returns
144
    ///
145
    /// `(state, symbols, constraints)`
146
    /// where:
147
    /// - `state` is an instance of the given representation
148
    /// - `symbols` are new variables created by the representation
149
    /// - `constraints` are new top-level constraints created by the representation
150
    pub fn update_or_init_repr<R: ReprRule + ?Sized>(
151
        &mut self,
152
    ) -> ReprGetOrInitResult<'_, R::DeclLevel, ReprError> {
153
        let (_, symbols, constraints) = self.update_or_init_repr_via(R::STORED)?;
154
        let state = self.repr_state_as_unchecked::<R>();
155
        Ok((state, symbols, constraints))
156
    }
157

            
158
    /// Same as [Reference::update_or_init_repr], but type-erased
159
17561558
    pub fn update_or_init_repr_via(
160
17561558
        &mut self,
161
17561558
        rule: ReprRulePtr,
162
17561558
    ) -> ReprGetOrInitResult<'_, dyn ReprStateStored, ReprError> {
163
17561558
        let (symbols, constraints) = rule.init_for_if_not_exists(&mut self.ptr)?;
164
17561558
        self.repr = Some(rule);
165
17561558
        let state = self.repr_state_unchecked();
166
17561558
        Ok((state, symbols, constraints))
167
17561558
    }
168

            
169
    /// If this reference has a representation selected, return `(rule, state)`
170
    /// where
171
    /// - `rule` is a pointer to the representation rule
172
    /// - `state` is an instance of that representation
173
4623979
    pub fn get_repr(
174
4623979
        &self,
175
4623979
    ) -> Option<(ReprRulePtr, MappedRwLockReadGuard<'_, dyn ReprStateStored>)> {
176
4623979
        let rule = self.repr?;
177
2255533
        Some((rule, self.repr_state_unchecked()))
178
4623979
    }
179

            
180
    /// If this reference has this specific representation selected, get its state as a concrete type
181
234022666
    pub fn get_repr_as<R: ReprRule + ?Sized>(
182
234022666
        &self,
183
234022666
    ) -> Option<MappedRwLockReadGuard<'_, R::DeclLevel>> {
184
234022666
        if let Some(rule) = self.repr
185
58286742
            && rule == R::STORED
186
        {
187
4239235
            return Some(self.repr_state_as_unchecked::<R>());
188
229783431
        }
189
229783431
        None
190
234022666
    }
191

            
192
    /// If this reference has a representation selected, return its state, otherwise crash
193
19817961
    fn repr_state_unchecked(&self) -> MappedRwLockReadGuard<'_, dyn ReprStateStored> {
194
19817961
        let rule = self
195
19817961
            .repr
196
            .unwrap_or_else(|| bug!("`{}` had no representation", self.name()));
197
19817961
        RwLockReadGuard::map(self.ptr.reprs(), |reprs| {
198
19817961
            reprs.get_by_rule(rule).unwrap_or_else(|| {
199
                bug!(
200
                    "Representation '{}' was selected for '{}' but its state was not stored!",
201
                    rule.name(),
202
                    self.name()
203
                )
204
            })
205
19817961
        })
206
19817961
    }
207

            
208
    /// If this reference has this specific representation selected, return its state
209
    /// as a concrete type, otherwise crash
210
4239257
    fn repr_state_as_unchecked<R: ReprRule + ?Sized>(
211
4239257
        &self,
212
4239257
    ) -> MappedRwLockReadGuard<'_, R::DeclLevel> {
213
4239257
        R::get_for(&self.ptr).unwrap_or_else(|| {
214
            bug!(
215
                "`{}` did not have the expected representation `{}`",
216
                self.name(),
217
                R::NAME
218
            )
219
        })
220
4239257
    }
221

            
222
    /// Returns the expression behind a value-letting reference, if this is one.
223
    ///
224
    /// Prefer [`Reference::with_resolved_expression`] when the expression only needs to be
225
    /// inspected. Returning an owned value here necessarily clones collection-bearing
226
    /// expressions such as matrix literals.
227
2024689489
    pub fn resolve_expression(&self) -> Option<Expression> {
228
2024689489
        if let Some(expr) = self.ptr().as_value_letting() {
229
17904
            return Some(expr.clone());
230
2024671585
        }
231

            
232
        let generator = {
233
2024671585
            let kind = self.ptr.kind();
234
2024671585
            if let DeclarationKind::Quantified(inner) = &*kind {
235
                inner.generator().cloned()
236
            } else {
237
2024671585
                None
238
            }
239
        };
240

            
241
2024671585
        if let Some(generator) = generator
242
            && let Some(expr) = generator.as_value_letting()
243
        {
244
            return Some(expr.clone());
245
2024671585
        }
246

            
247
2024671585
        None
248
2024689489
    }
249

            
250
    /// The formula named by this boolean value letting, when that formula is not an atom.
251
    ///
252
    /// Constants and aliases of decision variables return [`None`]: those names already stand for
253
    /// a value. An alias of another value letting returns that reference, so the caller can follow
254
    /// the chain. Unit `or`/`and` removal rewrites a singleton connective down to the remaining
255
    /// name, and that name is still a connective.
256
939279
    pub fn boolean_formula_letting_body(&self) -> Option<Expression> {
257
939279
        let body = self.resolve_expression()?;
258
2893
        boolean_formula_letting(&body).then_some(body)
259
939279
    }
260

            
261
    /// Calls `inspect` with the expression behind a value-letting reference.
262
    ///
263
    /// The declaration is kept read-locked for the duration of `inspect`, allowing callers to ask
264
    /// questions about large value lettings without cloning them. Quantified declarations may
265
    /// delegate their value to an expression generator; those are handled here as well.
266
1262884484
    pub fn with_resolved_expression<T>(&self, inspect: impl FnOnce(&Expression) -> T) -> Option<T> {
267
1262884484
        if let Some(expr) = self.ptr().as_value_letting() {
268
65029259
            return Some(inspect(&expr));
269
1197855225
        }
270

            
271
        let generator = {
272
1197855225
            let kind = self.ptr.kind();
273
1197855225
            if let DeclarationKind::Quantified(inner) = &*kind {
274
51076
                inner.generator().cloned()
275
            } else {
276
1197804149
                None
277
            }
278
1197855225
        }?;
279
        let expr = generator.as_value_letting()?;
280
        Some(inspect(&expr))
281
1262884484
    }
282

            
283
    /// Evaluates this reference to a literal if it resolves to a constant.
284
1158917268
    pub fn resolve_constant(&self) -> Option<Literal> {
285
1158917268
        self.with_resolved_expression(super::eval::eval_constant)
286
1158917268
            .flatten()
287
1158917268
    }
288

            
289
    /// Resolves this reference to an atomic expression, if possible.
290
3063776
    pub fn resolve_atomic(&self) -> Option<Atom> {
291
3063776
        self.with_resolved_expression(|expr| match expr {
292
            Expression::Atomic(_, atom) => Some(atom.clone()),
293
            _ => None,
294
        })
295
        .flatten()
296
3063776
    }
297
}
298

            
299
/// True when a value-letting body should be read as a boolean formula rather than as an atom.
300
2893
fn boolean_formula_letting(body: &Expression) -> bool {
301
2893
    match body {
302
1033
        Expression::Atomic(_, Atom::Reference(next)) => next.resolve_expression().is_some(),
303
256
        Expression::Atomic(_, _) => false,
304
        other => {
305
1604
            other.try_return_type() == Some(ReturnType::Bool)
306
                || matches!(
307
                    other,
308
                    Expression::Not(_, _)
309
                        | Expression::Or(_, _)
310
                        | Expression::And(_, _)
311
                        | Expression::Imply(_, _, _)
312
                        | Expression::Iff(_, _, _)
313
                        | Expression::Eq(_, _, _)
314
                        | Expression::Neq(_, _, _)
315
                        | Expression::Geq(_, _, _)
316
                        | Expression::Leq(_, _, _)
317
                        | Expression::Gt(_, _, _)
318
                        | Expression::Lt(_, _, _)
319
                        | Expression::FlatIneq(_, _, _, _)
320
                        | Expression::MinionReify(_, _, _)
321
                        | Expression::MinionReifyImply(_, _, _)
322
                )
323
        }
324
    }
325
2893
}
326

            
327
impl From<Reference> for Expression {
328
178835988
    fn from(value: Reference) -> Self {
329
178835988
        Expression::Atomic(Metadata::new(), value.into())
330
178835988
    }
331
}
332

            
333
impl From<Reference> for Moo<Expression> {
334
8352
    fn from(value: Reference) -> Self {
335
8352
        Moo::new(value.into())
336
8352
    }
337
}
338

            
339
impl From<DeclarationPtr> for Reference {
340
    fn from(ptr: DeclarationPtr) -> Self {
341
        Reference::new(ptr)
342
    }
343
}
344

            
345
impl CategoryOf for Reference {
346
10075345
    fn category_of(&self) -> Category {
347
10075345
        self.ptr.category_of()
348
10075345
    }
349
}
350

            
351
impl HasDomain for Reference {
352
459617070
    fn domain_of(&self) -> DomainPtr {
353
459617070
        self.ptr
354
459617070
            .domain()
355
8758
            .or_else(|| self.resolve_constant().map(|literal| literal.domain_of()))
356
            .unwrap_or_else(|| {
357
                bug!(
358
                    "reference ({name}) should have a domain",
359
                    name = self.ptr.name()
360
                )
361
            })
362
459617070
    }
363
}
364

            
365
impl Display for Reference {
366
17644659
    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
367
17644659
        self.ptr.name().fmt(f)
368
17644659
    }
369
}