Skip to main content

chomsky_uir/
constraint.rs

1use crate::egraph::HasDebugInfo;
2use chomsky_types::Loc;
3use serde::{Deserialize, Serialize};
4
5#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
6pub enum Effect {
7    Pure,
8    ReadOnly,
9    WriteOnly,
10    ReadWrite,
11    Panic,
12    Diverge,
13}
14
15impl Effect {
16    pub fn join(&self, other: &Self) -> Self {
17        match (self, other) {
18            (Effect::Diverge, _) | (_, Effect::Diverge) => Effect::Diverge,
19            (Effect::Panic, _) | (_, Effect::Panic) => Effect::Panic,
20            (Effect::ReadWrite, _) | (_, Effect::ReadWrite) => Effect::ReadWrite,
21            (Effect::WriteOnly, Effect::ReadOnly) | (Effect::ReadOnly, Effect::WriteOnly) => {
22                Effect::ReadWrite
23            }
24            (Effect::WriteOnly, _) | (_, Effect::WriteOnly) => Effect::WriteOnly,
25            (Effect::ReadOnly, _) | (_, Effect::ReadOnly) => Effect::ReadOnly,
26            (Effect::Pure, other) => *other,
27        }
28    }
29}
30
31#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash, Serialize, Deserialize)]
32pub enum Ownership {
33    Borrowed,
34    Owned,
35    Shared,
36    Linear,
37}
38
39#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
40pub enum Constraint {
41    Effect(Effect),
42    Ownership(Ownership),
43    Atomic,
44    Type(String),
45}
46
47#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
48pub struct ConstraintSet {
49    pub effect: Effect,
50    pub ownership: Option<Ownership>,
51    pub is_atomic: bool,
52    pub r#type: Option<String>,
53}
54
55impl Default for ConstraintSet {
56    fn default() -> Self {
57        Self {
58            effect: Effect::Pure,
59            ownership: None,
60            is_atomic: false,
61            r#type: None,
62        }
63    }
64}
65
66impl ConstraintSet {
67    pub fn merge(&mut self, other: &Self) -> bool {
68        let mut changed = false;
69
70        let new_effect = self.effect.join(&other.effect);
71        if new_effect != self.effect {
72            self.effect = new_effect;
73            changed = true;
74        }
75
76        if let Some(o) = &other.ownership {
77            if self.ownership.as_ref() != Some(o) {
78                if self.ownership.is_none() {
79                    self.ownership = Some(*o);
80                    changed = true;
81                }
82            }
83        }
84
85        if other.is_atomic && !self.is_atomic {
86            self.is_atomic = true;
87            changed = true;
88        }
89
90        if let Some(t) = &other.r#type {
91            if self.r#type.as_ref() != Some(t) {
92                if self.r#type.is_none() {
93                    self.r#type = Some(t.clone());
94                    changed = true;
95                }
96            }
97        }
98
99        changed
100    }
101}
102
103impl HasDebugInfo for ConstraintSet {
104    fn get_locs(&self) -> &[Loc] {
105        &[]
106    }
107}
108
109impl ConstraintSet {
110    pub fn check_conflict(&self, other: &Self) -> Option<String> {
111        // Ownership conflict: cannot merge different ownerships (except maybe some subtyping)
112        if let (Some(o1), Some(o2)) = (&self.ownership, &other.ownership) {
113            if o1 != o2 {
114                return Some(format!("Ownership conflict: {:?} vs {:?}", o1, o2));
115            }
116        }
117
118        // Type conflict: cannot merge different types
119        if let (Some(t1), Some(t2)) = (&self.r#type, &other.r#type) {
120            if t1 != t2 {
121                return Some(format!("Type conflict: {} vs {}", t1, t2));
122            }
123        }
124
125        None
126    }
127
128    pub fn can_merge(&self, other: &Self) -> bool {
129        self.check_conflict(other).is_none()
130    }
131}