Skip to main content

conjure_cp_core/ast/domains/
unresolved.rs

1use crate::ast::domains::attrs::MSetAttr;
2use crate::ast::domains::attrs::PartitionAttr;
3use crate::ast::domains::attrs::SetAttr;
4use crate::ast::{
5    DeclarationKind, DomainOpError, Expression, FieldEntryGround, FuncAttr, Literal, Metadata, Moo,
6    Reference, RelAttr, SequenceAttr, Typeable,
7    domains::{
8        GroundDomain,
9        domain::{DomainPtr, Int},
10        range::Range,
11    },
12};
13use crate::{bug, domain_int, matrix_expr, range};
14use conjure_cp_core::ast::pretty::pretty_vec;
15use conjure_cp_core::ast::{Name, ReturnType, eval_constant};
16use itertools::Itertools;
17use polyquine::Quine;
18use serde::{Deserialize, Serialize};
19use std::fmt::{Display, Formatter};
20use std::iter::zip;
21use std::ops::Deref;
22use uniplate::Uniplate;
23
24#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
25#[path_prefix(conjure_cp::ast)]
26#[biplate(to=Expression)]
27#[biplate(to=Reference)]
28pub enum IntVal {
29    Const(Int),
30    #[polyquine_skip]
31    Reference(Reference),
32    Expr(Moo<Expression>),
33}
34
35impl From<Int> for IntVal {
36    fn from(value: Int) -> Self {
37        Self::Const(value)
38    }
39}
40
41impl TryInto<Int> for IntVal {
42    type Error = DomainOpError;
43
44    fn try_into(self) -> Result<Int, Self::Error> {
45        match self {
46            IntVal::Const(val) => Ok(val),
47            _ => Err(DomainOpError::NotGround),
48        }
49    }
50}
51
52impl From<Range<Int>> for Range<IntVal> {
53    fn from(value: Range<Int>) -> Self {
54        match value {
55            Range::Single(x) => Range::Single(x.into()),
56            Range::Bounded(l, r) => Range::Bounded(l.into(), r.into()),
57            Range::UnboundedL(r) => Range::UnboundedL(r.into()),
58            Range::UnboundedR(l) => Range::UnboundedR(l.into()),
59            Range::Unbounded => Range::Unbounded,
60        }
61    }
62}
63
64impl TryInto<Range<Int>> for Range<IntVal> {
65    type Error = DomainOpError;
66
67    fn try_into(self) -> Result<Range<Int>, Self::Error> {
68        match self {
69            Range::Single(x) => Ok(Range::Single(x.try_into()?)),
70            Range::Bounded(l, r) => Ok(Range::Bounded(l.try_into()?, r.try_into()?)),
71            Range::UnboundedL(r) => Ok(Range::UnboundedL(r.try_into()?)),
72            Range::UnboundedR(l) => Ok(Range::UnboundedR(l.try_into()?)),
73            Range::Unbounded => Ok(Range::Unbounded),
74        }
75    }
76}
77
78impl From<SetAttr<Int>> for SetAttr<IntVal> {
79    fn from(value: SetAttr<Int>) -> Self {
80        SetAttr {
81            size: value.size.into(),
82        }
83    }
84}
85
86impl TryInto<SetAttr<Int>> for SetAttr<IntVal> {
87    type Error = DomainOpError;
88
89    fn try_into(self) -> Result<SetAttr<Int>, Self::Error> {
90        let size: Range<Int> = self.size.try_into()?;
91        Ok(SetAttr { size })
92    }
93}
94
95impl From<MSetAttr<Int>> for MSetAttr<IntVal> {
96    fn from(value: MSetAttr<Int>) -> Self {
97        MSetAttr {
98            size: value.size.into(),
99            occurrence: value.occurrence.into(),
100        }
101    }
102}
103
104impl TryInto<MSetAttr<Int>> for MSetAttr<IntVal> {
105    type Error = DomainOpError;
106
107    fn try_into(self) -> Result<MSetAttr<Int>, Self::Error> {
108        let size: Range<Int> = self.size.try_into()?;
109        let occurrence: Range<Int> = self.occurrence.try_into()?;
110        Ok(MSetAttr { size, occurrence })
111    }
112}
113
114impl From<FuncAttr<Int>> for FuncAttr<IntVal> {
115    fn from(value: FuncAttr<Int>) -> Self {
116        FuncAttr {
117            size: value.size.into(),
118            partiality: value.partiality,
119            jectivity: value.jectivity,
120        }
121    }
122}
123
124impl TryInto<FuncAttr<Int>> for FuncAttr<IntVal> {
125    type Error = DomainOpError;
126
127    fn try_into(self) -> Result<FuncAttr<Int>, Self::Error> {
128        let size: Range<Int> = self.size.try_into()?;
129        Ok(FuncAttr {
130            size,
131            jectivity: self.jectivity,
132            partiality: self.partiality,
133        })
134    }
135}
136
137impl From<RelAttr<Int>> for RelAttr<IntVal> {
138    fn from(value: RelAttr<Int>) -> Self {
139        RelAttr {
140            size: value.size.into(),
141            binary: value.binary,
142        }
143    }
144}
145
146impl TryInto<RelAttr<Int>> for RelAttr<IntVal> {
147    type Error = DomainOpError;
148
149    fn try_into(self) -> Result<RelAttr<Int>, Self::Error> {
150        let size: Range<Int> = self.size.try_into()?;
151        Ok(RelAttr {
152            size,
153            binary: self.binary,
154        })
155    }
156}
157
158impl From<PartitionAttr<Int>> for PartitionAttr<IntVal> {
159    fn from(value: PartitionAttr<Int>) -> Self {
160        PartitionAttr {
161            num_parts: value.num_parts.into(),
162            part_len: value.part_len.into(),
163            is_regular: value.is_regular,
164        }
165    }
166}
167
168impl TryInto<PartitionAttr<Int>> for PartitionAttr<IntVal> {
169    type Error = DomainOpError;
170
171    fn try_into(self) -> Result<PartitionAttr<Int>, Self::Error> {
172        let num_parts: Range<Int> = self.num_parts.try_into()?;
173        let part_len: Range<Int> = self.part_len.try_into()?;
174        let is_regular: bool = self.is_regular;
175        Ok(PartitionAttr {
176            num_parts,
177            part_len,
178            is_regular,
179        })
180    }
181}
182
183impl From<SequenceAttr<Int>> for SequenceAttr<IntVal> {
184    fn from(value: SequenceAttr<Int>) -> Self {
185        SequenceAttr {
186            size: value.size.into(),
187            jectivity: value.jectivity,
188        }
189    }
190}
191
192impl TryInto<SequenceAttr<Int>> for SequenceAttr<IntVal> {
193    type Error = DomainOpError;
194
195    fn try_into(self) -> Result<SequenceAttr<Int>, Self::Error> {
196        let size: Range<Int> = self.size.try_into()?;
197        Ok(SequenceAttr {
198            size,
199            jectivity: self.jectivity,
200        })
201    }
202}
203
204impl Display for IntVal {
205    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
206        match self {
207            IntVal::Const(val) => write!(f, "{val}"),
208            IntVal::Reference(re) => write!(f, "{re}"),
209            IntVal::Expr(expr) => write!(f, "({expr})"),
210        }
211    }
212}
213
214impl IntVal {
215    pub fn new_ref(re: &Reference) -> Option<IntVal> {
216        match re.ptr.kind().deref() {
217            DeclarationKind::ValueLetting(expr, _)
218            | DeclarationKind::TemporaryValueLetting(expr)
219            | DeclarationKind::QuantifiedExpr(expr) => match expr.return_type() {
220                ReturnType::Int => Some(IntVal::Reference(re.clone())),
221                _ => None,
222            },
223            DeclarationKind::Given(dom) => match dom.return_type() {
224                ReturnType::Int => Some(IntVal::Reference(re.clone())),
225                _ => None,
226            },
227            DeclarationKind::Quantified(inner) => match inner.domain().return_type() {
228                ReturnType::Int => Some(IntVal::Reference(re.clone())),
229                _ => None,
230            },
231            DeclarationKind::Find(var) => match var.return_type() {
232                ReturnType::Int => Some(IntVal::Reference(re.clone())),
233                _ => None,
234            },
235            DeclarationKind::DomainLetting(_) | DeclarationKind::Field(_) => None,
236        }
237    }
238
239    pub fn new_expr(value: Moo<Expression>) -> Option<IntVal> {
240        if value.return_type() != ReturnType::Int {
241            return None;
242        }
243        Some(IntVal::Expr(value))
244    }
245
246    pub fn resolve(&self) -> Option<Int> {
247        match self {
248            IntVal::Const(value) => Some(*value),
249            IntVal::Expr(expr) => eval_expr_to_int(expr),
250            IntVal::Reference(re) => match re.ptr.kind().deref() {
251                DeclarationKind::ValueLetting(expr, _)
252                | DeclarationKind::TemporaryValueLetting(expr) => eval_expr_to_int(expr),
253                // If this is an int given we will be able to resolve it eventually, but not yet
254                DeclarationKind::Given(_) => None,
255                DeclarationKind::Quantified(inner) => {
256                    if let Some(generator) = inner.generator()
257                        && let Some(expr) = generator.as_value_letting()
258                    {
259                        eval_expr_to_int(&expr)
260                    } else {
261                        None
262                    }
263                }
264                // TODO: idk what this whole file does but I very much doubt it affects this
265                DeclarationKind::QuantifiedExpr(_) => None,
266                // Decision variables inside domains are unresolved until solving.
267                DeclarationKind::Find(_) => None,
268                DeclarationKind::DomainLetting(_) | DeclarationKind::Field(_) => bug!(
269                    "Expected integer expression, given, or letting inside int domain; Got: {re}"
270                ),
271            },
272        }
273    }
274}
275
276fn eval_expr_to_int(expr: &Expression) -> Option<Int> {
277    match eval_constant(expr)? {
278        Literal::Int(v) => Some(v),
279        _ => bug!("Expected integer expression, got: {expr}"),
280    }
281}
282
283impl From<IntVal> for Expression {
284    fn from(value: IntVal) -> Self {
285        match value {
286            IntVal::Const(val) => val.into(),
287            IntVal::Reference(re) => re.into(),
288            IntVal::Expr(expr) => expr.as_ref().clone(),
289        }
290    }
291}
292
293impl From<IntVal> for Moo<Expression> {
294    fn from(value: IntVal) -> Self {
295        match value {
296            IntVal::Const(val) => Moo::new(val.into()),
297            IntVal::Reference(re) => Moo::new(re.into()),
298            IntVal::Expr(expr) => expr,
299        }
300    }
301}
302
303impl std::ops::Neg for IntVal {
304    type Output = IntVal;
305
306    fn neg(self) -> Self::Output {
307        match self {
308            IntVal::Const(val) => IntVal::Const(-val),
309            IntVal::Reference(_) | IntVal::Expr(_) => {
310                IntVal::Expr(Moo::new(Expression::Neg(Metadata::new(), self.into())))
311            }
312        }
313    }
314}
315
316impl<T> std::ops::Add<T> for IntVal
317where
318    T: Into<Expression>,
319{
320    type Output = IntVal;
321
322    fn add(self, rhs: T) -> Self::Output {
323        let lhs: Expression = self.into();
324        let rhs: Expression = rhs.into();
325        let sum = matrix_expr!(lhs, rhs; domain_int!(1..));
326        IntVal::Expr(Moo::new(Expression::Sum(Metadata::new(), Moo::new(sum))))
327    }
328}
329
330impl Range<IntVal> {
331    pub fn resolve(&self) -> Option<Range<Int>> {
332        match self {
333            Range::Single(x) => Some(Range::Single(x.resolve()?)),
334            Range::Bounded(l, r) => Some(Range::Bounded(l.resolve()?, r.resolve()?)),
335            Range::UnboundedL(r) => Some(Range::UnboundedL(r.resolve()?)),
336            Range::UnboundedR(l) => Some(Range::UnboundedR(l.resolve()?)),
337            Range::Unbounded => Some(Range::Unbounded),
338        }
339    }
340}
341
342impl SetAttr<IntVal> {
343    pub fn resolve(&self) -> Option<SetAttr<Int>> {
344        Some(SetAttr {
345            size: self.size.resolve()?,
346        })
347    }
348}
349
350impl SequenceAttr<IntVal> {
351    pub fn resolve(&self) -> Option<SequenceAttr<Int>> {
352        Some(SequenceAttr {
353            size: self.size.resolve()?,
354            jectivity: self.jectivity.clone(),
355        })
356    }
357}
358
359impl MSetAttr<IntVal> {
360    pub fn resolve(&self) -> Option<MSetAttr<Int>> {
361        Some(MSetAttr {
362            size: self.size.resolve()?,
363            occurrence: self.occurrence.resolve()?,
364        })
365    }
366}
367
368impl PartitionAttr<IntVal> {
369    pub fn resolve(&self) -> Option<PartitionAttr<Int>> {
370        Some(PartitionAttr {
371            num_parts: self.num_parts.resolve()?,
372            part_len: self.part_len.resolve()?,
373            is_regular: self.is_regular,
374        })
375    }
376}
377
378impl FuncAttr<IntVal> {
379    pub fn resolve(&self) -> Option<FuncAttr<Int>> {
380        Some(FuncAttr {
381            size: self.size.resolve()?,
382            partiality: self.partiality.clone(),
383            jectivity: self.jectivity.clone(),
384        })
385    }
386}
387
388impl RelAttr<IntVal> {
389    pub fn resolve(&self) -> Option<RelAttr<Int>> {
390        Some(RelAttr {
391            size: self.size.resolve()?,
392            binary: self.binary.clone(),
393        })
394    }
395}
396
397#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Uniplate, Quine)]
398#[path_prefix(conjure_cp::ast)]
399pub struct FieldEntry {
400    pub name: Name,
401    pub domain: DomainPtr,
402}
403
404impl FieldEntry {
405    pub fn resolve(self) -> Option<FieldEntryGround> {
406        Some(FieldEntryGround {
407            name: self.name,
408            domain: self.domain.resolve()?,
409        })
410    }
411}
412
413#[derive(Clone, Debug, PartialEq, Eq, Hash, Serialize, Deserialize, Quine, Uniplate)]
414#[path_prefix(conjure_cp::ast)]
415#[biplate(to=Expression)]
416#[biplate(to=Reference)]
417#[biplate(to=IntVal)]
418#[biplate(to=DomainPtr)]
419#[biplate(to=FieldEntry)]
420pub enum UnresolvedDomain {
421    Int(Vec<Range<IntVal>>),
422    /// A set of elements drawn from the inner domain
423    Set(SetAttr<IntVal>, DomainPtr),
424    MSet(MSetAttr<IntVal>, DomainPtr),
425    /// A n-dimensional matrix with a value domain and n-index domains
426    Matrix(DomainPtr, Vec<DomainPtr>),
427    /// A tuple of N elements, each with its own domain
428    Tuple(Vec<DomainPtr>),
429    Sequence(SequenceAttr<IntVal>, DomainPtr),
430    /// A reference to a domain letting
431    #[polyquine_skip]
432    Reference(Reference),
433    /// A record
434    Record(Vec<FieldEntry>),
435    /// A function with attributes, domain, and range
436    Function(FuncAttr<IntVal>, DomainPtr, DomainPtr),
437    /// A variant domain with its domain options (reusing field entries)
438    Variant(Vec<FieldEntry>),
439    /// A relation as a set of tuples
440    Relation(RelAttr<IntVal>, Vec<DomainPtr>),
441    Partition(PartitionAttr<IntVal>, DomainPtr),
442}
443
444impl UnresolvedDomain {
445    pub fn resolve(&self) -> Option<GroundDomain> {
446        match self {
447            UnresolvedDomain::Int(rngs) => rngs
448                .iter()
449                .map(Range::<IntVal>::resolve)
450                .collect::<Option<_>>()
451                .map(GroundDomain::Int),
452            UnresolvedDomain::Set(attr, inner) => {
453                Some(GroundDomain::Set(attr.resolve()?, inner.resolve()?))
454            }
455            UnresolvedDomain::MSet(attr, inner) => {
456                Some(GroundDomain::MSet(attr.resolve()?, inner.resolve()?))
457            }
458            UnresolvedDomain::Partition(attr, inner) => {
459                Some(GroundDomain::Partition(attr.resolve()?, inner.resolve()?))
460            }
461            UnresolvedDomain::Matrix(inner, idx_doms) => {
462                let inner_gd = inner.resolve()?;
463                idx_doms
464                    .iter()
465                    .map(DomainPtr::resolve)
466                    .collect::<Option<_>>()
467                    .map(|idx| GroundDomain::Matrix(inner_gd, idx))
468            }
469            UnresolvedDomain::Sequence(attr, inner) => {
470                Some(GroundDomain::Sequence(attr.resolve()?, inner.resolve()?))
471            }
472            UnresolvedDomain::Tuple(inners) => inners
473                .iter()
474                .map(DomainPtr::resolve)
475                .collect::<Option<_>>()
476                .map(GroundDomain::Tuple),
477            UnresolvedDomain::Record(entries) => entries
478                .iter()
479                .map(|f| {
480                    f.domain.resolve().map(|gd| FieldEntryGround {
481                        name: f.name.clone(),
482                        domain: gd,
483                    })
484                })
485                .collect::<Option<_>>()
486                .map(GroundDomain::Record),
487            UnresolvedDomain::Reference(re) => re
488                .ptr
489                .as_domain_letting()
490                .unwrap_or_else(|| {
491                    bug!("Reference domain should point to domain letting, but got {re}")
492                })
493                .resolve()
494                .map(Moo::unwrap_or_clone),
495            UnresolvedDomain::Function(attr, dom, cdom) => {
496                if let Some(attr_gd) = attr.resolve()
497                    && let Some(dom_gd) = dom.resolve()
498                    && let Some(cdom_gd) = cdom.resolve()
499                {
500                    return Some(GroundDomain::Function(attr_gd, dom_gd, cdom_gd));
501                }
502                None
503            }
504            UnresolvedDomain::Variant(entries) => entries
505                .iter()
506                .map(|f| {
507                    f.domain.resolve().map(|gd| FieldEntryGround {
508                        name: f.name.clone(),
509                        domain: gd,
510                    })
511                })
512                .collect::<Option<_>>()
513                .map(GroundDomain::Variant),
514            UnresolvedDomain::Relation(attr, inners) => {
515                let resolved_attr = attr.resolve()?;
516                inners
517                    .iter()
518                    .map(DomainPtr::resolve)
519                    .collect::<Option<_>>()
520                    .map(|items| GroundDomain::Relation(resolved_attr, items))
521            }
522        }
523    }
524
525    pub(super) fn union_unresolved(
526        &self,
527        other: &UnresolvedDomain,
528    ) -> Result<UnresolvedDomain, DomainOpError> {
529        match (self, other) {
530            (UnresolvedDomain::Int(lhs), UnresolvedDomain::Int(rhs)) => {
531                let merged = lhs.iter().chain(rhs.iter()).cloned().collect_vec();
532                Ok(UnresolvedDomain::Int(merged))
533            }
534            (UnresolvedDomain::Int(_), _) | (_, UnresolvedDomain::Int(_)) => {
535                Err(DomainOpError::WrongType)
536            }
537            (UnresolvedDomain::Set(_, in1), UnresolvedDomain::Set(_, in2)) => {
538                Ok(UnresolvedDomain::Set(SetAttr::default(), in1.union(in2)?))
539            }
540            (UnresolvedDomain::Set(_, _), _) | (_, UnresolvedDomain::Set(_, _)) => {
541                Err(DomainOpError::WrongType)
542            }
543            (UnresolvedDomain::MSet(_, in1), UnresolvedDomain::MSet(_, in2)) => {
544                Ok(UnresolvedDomain::MSet(MSetAttr::default(), in1.union(in2)?))
545            }
546            (UnresolvedDomain::MSet(_, _), _) | (_, UnresolvedDomain::MSet(_, _)) => {
547                Err(DomainOpError::WrongType)
548            }
549            (UnresolvedDomain::Matrix(in1, idx1), UnresolvedDomain::Matrix(in2, idx2))
550                if idx1 == idx2 =>
551            {
552                Ok(UnresolvedDomain::Matrix(in1.union(in2)?, idx1.clone()))
553            }
554            (UnresolvedDomain::Matrix(_, _), _) | (_, UnresolvedDomain::Matrix(_, _)) => {
555                Err(DomainOpError::WrongType)
556            }
557            (UnresolvedDomain::Tuple(lhs), UnresolvedDomain::Tuple(rhs))
558                if lhs.len() == rhs.len() =>
559            {
560                let mut merged = Vec::new();
561                for (l, r) in zip(lhs, rhs) {
562                    merged.push(l.union(r)?)
563                }
564                Ok(UnresolvedDomain::Tuple(merged))
565            }
566            (UnresolvedDomain::Tuple(_), _) | (_, UnresolvedDomain::Tuple(_)) => {
567                Err(DomainOpError::WrongType)
568            }
569            (UnresolvedDomain::Relation(_, in1s), UnresolvedDomain::Relation(_, in2s)) => {
570                let mut inners = Vec::new();
571                for (in1, in2) in in1s.iter().zip(in2s.iter()) {
572                    inners.push(in1.union(in2)?)
573                }
574                Ok(UnresolvedDomain::Relation(RelAttr::default(), inners))
575            }
576            (UnresolvedDomain::Relation(_, _), _) | (_, UnresolvedDomain::Relation(_, _)) => {
577                Err(DomainOpError::WrongType)
578            }
579            // TODO: Could we support unions of reference domains symbolically?
580            (UnresolvedDomain::Reference(_), _) | (_, UnresolvedDomain::Reference(_)) => {
581                Err(DomainOpError::NotGround)
582            }
583            // TODO: Could we define semantics for merging record domains?
584            #[allow(unreachable_patterns)] // Technically redundant but logically makes sense
585            (UnresolvedDomain::Record(_), _) | (_, UnresolvedDomain::Record(_)) => {
586                Err(DomainOpError::WrongType)
587            }
588            #[allow(unreachable_patterns)]
589            // Technically redundant but logically clearer to have both
590            (UnresolvedDomain::Function(_, _, _), _) | (_, UnresolvedDomain::Function(_, _, _)) => {
591                Err(DomainOpError::WrongType)
592            }
593            #[allow(unreachable_patterns)]
594            // Technically redundant but logically clearer to have both
595            (UnresolvedDomain::Partition(_, _), _) | (_, UnresolvedDomain::Partition(_, _)) => {
596                Err(DomainOpError::WrongType)
597            }
598            #[allow(unreachable_patterns)]
599            (UnresolvedDomain::Variant(_), _) | (_, UnresolvedDomain::Variant(_)) => {
600                Err(DomainOpError::WrongType)
601            }
602            #[allow(unreachable_patterns)]
603            (UnresolvedDomain::Sequence(_, _), _) | (_, UnresolvedDomain::Sequence(_, _)) => {
604                Err(DomainOpError::WrongType)
605            }
606        }
607    }
608
609    pub fn element_domain(&self) -> Option<DomainPtr> {
610        match self {
611            UnresolvedDomain::Set(_, inner_dom) => Some(inner_dom.clone()),
612            UnresolvedDomain::Sequence(_, inner_dom) => Some(inner_dom.clone()),
613            UnresolvedDomain::Matrix(_, _) => {
614                todo!("Unwrap one dimension of the domain")
615            }
616            _ => None,
617        }
618    }
619}
620
621impl Typeable for UnresolvedDomain {
622    fn return_type(&self) -> ReturnType {
623        match self {
624            UnresolvedDomain::Reference(re) => re.return_type(),
625            UnresolvedDomain::Int(_) => ReturnType::Int,
626            UnresolvedDomain::Set(_attr, inner) => ReturnType::Set(Box::new(inner.return_type())),
627            UnresolvedDomain::MSet(_attr, inner) => ReturnType::MSet(Box::new(inner.return_type())),
628            UnresolvedDomain::Partition(_, inner) => {
629                ReturnType::Partition(Box::new(inner.return_type()))
630            }
631            UnresolvedDomain::Sequence(_attr, inner) => {
632                ReturnType::Sequence(Box::new(inner.return_type()))
633            }
634            UnresolvedDomain::Matrix(inner, _idx) => {
635                ReturnType::Matrix(Box::new(inner.return_type()))
636            }
637            UnresolvedDomain::Tuple(inners) => {
638                let mut inner_types = Vec::new();
639                for inner in inners {
640                    inner_types.push(inner.return_type());
641                }
642                ReturnType::Tuple(inner_types)
643            }
644            UnresolvedDomain::Record(entries) => {
645                let mut entry_types = Vec::new();
646                for entry in entries {
647                    entry_types.push(entry.domain.return_type());
648                }
649                ReturnType::Record(entry_types)
650            }
651            UnresolvedDomain::Function(_, dom, cdom) => {
652                ReturnType::Function(Box::new(dom.return_type()), Box::new(cdom.return_type()))
653            }
654            UnresolvedDomain::Variant(entries) => {
655                let mut entry_types = Vec::new();
656                for entry in entries {
657                    entry_types.push(entry.domain.return_type());
658                }
659                ReturnType::Variant(entry_types)
660            }
661            UnresolvedDomain::Relation(_, inners) => {
662                let mut inner_types = Vec::new();
663                for inner in inners {
664                    inner_types.push(inner.return_type());
665                }
666                ReturnType::Relation(inner_types)
667            }
668        }
669    }
670}
671
672impl Display for UnresolvedDomain {
673    fn fmt(&self, f: &mut Formatter<'_>) -> std::fmt::Result {
674        match &self {
675            UnresolvedDomain::Reference(re) => write!(f, "{re}"),
676            UnresolvedDomain::Int(ranges) => {
677                if ranges.iter().all(Range::is_lower_or_upper_bounded) {
678                    let rngs: String = ranges.iter().map(|r| format!("{r}")).join(", ");
679                    write!(f, "int({})", rngs)
680                } else {
681                    write!(f, "int")
682                }
683            }
684            UnresolvedDomain::Set(attrs, inner_dom) => write!(f, "set {attrs} of {inner_dom}"),
685            UnresolvedDomain::MSet(attrs, inner_dom) => write!(f, "mset {attrs} of {inner_dom}"),
686            UnresolvedDomain::Partition(attrs, inner_dom) => {
687                write!(f, "partition {attrs} from {inner_dom}")
688            }
689            UnresolvedDomain::Sequence(attrs, inner_dom) => {
690                write!(f, "sequence {attrs} of {inner_dom}")
691            }
692            UnresolvedDomain::Matrix(value_domain, index_domains) => {
693                write!(
694                    f,
695                    "matrix indexed by {} of {value_domain}",
696                    pretty_vec(&index_domains.iter().collect_vec())
697                )
698            }
699            UnresolvedDomain::Tuple(domains) => {
700                write!(f, "tuple ({})", &domains.iter().join(","))
701            }
702            UnresolvedDomain::Record(entries) => {
703                write!(
704                    f,
705                    "record {{{}}}",
706                    entries
707                        .iter()
708                        .map(|entry| format!("{}: {}", entry.name, entry.domain))
709                        .join(", ")
710                )
711            }
712            UnresolvedDomain::Function(attribute, domain, codomain) => {
713                write!(f, "function {} {} --> {} ", attribute, domain, codomain)
714            }
715            UnresolvedDomain::Variant(entries) => {
716                write!(
717                    f,
718                    "variant {{{}}}",
719                    entries
720                        .iter()
721                        .map(|entry| format!("{}: {}", entry.name, entry.domain))
722                        .join(", ")
723                )
724            }
725            UnresolvedDomain::Relation(attrs, domains) => {
726                write!(f, "relation {} of ({})", attrs, domains.iter().join(" * "))
727            }
728        }
729    }
730}