rem_constraint/
common.rs

1use itertools::Itertools;
2
3use nom::{
4    branch::alt,
5    bytes::complete::tag,
6    character::complete::char,
7    sequence::{self, delimited},
8    IResult,
9};
10use proc_macro2::{Ident, Span};
11
12use rem_utils::annotation::Annotations;
13use rem_utils::labelling::Label;
14use syn::{visit_mut::VisitMut, Expr, ExprAssign, FnArg, Stmt, Type};
15
16/// Aliasing Constraints
17#[derive(Clone, Debug, PartialEq, Eq, Hash)]
18pub enum AliasConstraints {
19    Ref(Label),
20    Alias(Label, Label),
21    Assign(Label, Label),
22}
23
24impl std::fmt::Display for AliasConstraints {
25    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
26        match self {
27            AliasConstraints::Ref(r) => write!(f, "ref({})", r),
28            AliasConstraints::Alias(l, r) => write!(f, "alias({}, {})", l, r),
29            AliasConstraints::Assign(l, r) => write!(f, "assign({}, {})", l, r),
30        }
31    }
32}
33
34#[allow(suspicious_double_ref_op)]
35impl crate::LocalConstraint for AliasConstraints {
36    const CHR_RULES: &'static str = include_str!("constraint_rules/alias_constraint_rules.pl");
37    fn parse(s: &str) -> nom::IResult<&str, Self> {
38        use rem_utils::parser::{label, ws};
39        fn ref_(s: &str) -> IResult<&str, AliasConstraints> {
40            let (s, _) = tag("ref")(s)?;
41            let (s, l1) = delimited(char('('), label, char(')'))(s)?;
42            Ok((s, AliasConstraints::Ref(l1)))
43        }
44
45        fn alias(s: &str) -> IResult<&str, AliasConstraints> {
46            let (s, _) = tag("alias")(s)?;
47            let (s, (l1, l2)) = delimited(
48                char('('),
49                sequence::separated_pair(label, ws(char(',')), label),
50                char(')'),
51            )(s)?;
52            Ok((s, AliasConstraints::Alias(l1, l2)))
53        }
54
55        fn assign(s: &str) -> IResult<&str, AliasConstraints> {
56            let (s, _) = tag("assign")(s)?;
57            let (s, (l1, l2)) = delimited(
58                char('('),
59                sequence::separated_pair(label, ws(char(',')), label),
60                char(')'),
61            )(s)?;
62            Ok((s, AliasConstraints::Assign(l1, l2)))
63        }
64
65        alt((ref_, alias, assign))(s)
66    }
67
68    fn collect<'a>(
69        (map, fun): &rem_utils::annotation::Annotated<'a, &'a syn::ItemFn>,
70    ) -> Vec<Self> {
71        use rem_utils::labelling::ASTKey;
72
73        struct Traverse<'a> {
74            ast: &'a Annotations<'a>,
75            constraints: &'a mut Vec<AliasConstraints>,
76        }
77
78        fn lookup_ast<'a>(ast: &Annotations<'a>, ident: &dyn ASTKey) -> Option<Label> {
79            ast.get(&ident).map(|v| *v)
80        }
81        fn add_constraint(constraints: &mut Vec<AliasConstraints>, constraint: AliasConstraints) {
82            constraints.push(constraint)
83        }
84
85        struct IdentHelper<'a> {
86            lhs: &'a Label,
87            ast: &'a Annotations<'a>,
88            constraints: &'a mut Vec<AliasConstraints>,
89        }
90
91        impl VisitMut for IdentHelper<'_> {
92            fn visit_ident_mut(&mut self, i: &mut Ident) {
93                // println!("in ident: {}", i.clone().to_string());
94                lookup_ast(self.ast, i).and_then(|rhs| {
95                    if *self.lhs.clone().to_string() != rhs.clone().to_string() {
96                        add_constraint(
97                            self.constraints,
98                            AliasConstraints::Assign(self.lhs.clone(), rhs),
99                        );
100                    }
101                    Some(())
102                });
103                syn::visit_mut::visit_ident_mut(self, i)
104            }
105        }
106
107        struct ExprHelper<'a> {
108            lhs: &'a Label,
109            ast: &'a Annotations<'a>,
110            constraints: &'a mut Vec<AliasConstraints>,
111        }
112
113        impl VisitMut for ExprHelper<'_> {
114            fn visit_expr_mut(&mut self, i: &mut Expr) {
115                let mut id_helper = IdentHelper {
116                    lhs: self.lhs,
117                    ast: self.ast,
118                    constraints: self.constraints,
119                };
120                id_helper.visit_expr_mut(i);
121                match &i {
122                    Expr::Reference(_) => {
123                        add_constraint(self.constraints, AliasConstraints::Ref(*self.lhs))
124                    }
125                    _ => (),
126                }
127                syn::visit_mut::visit_expr_mut(self, i)
128            }
129        }
130
131        struct StmtHelper<'a> {
132            lhs: &'a Label,
133            ast: &'a Annotations<'a>,
134            constraints: &'a mut Vec<AliasConstraints>,
135        }
136
137        impl VisitMut for StmtHelper<'_> {
138            fn visit_stmt_mut(&mut self, i: &mut Stmt) {
139                match i {
140                    Stmt::Expr(e) => {
141                        let mut ident = Ident::new("__IDENT__", Span::call_site());
142                        let mut rhs_helper = LHSHelper { ident: &mut ident };
143                        rhs_helper.visit_expr_mut(e);
144                        if ident.to_string() != "__IDENT__" {
145                            lookup_ast(self.ast, &ident).and_then(|rhs| {
146                                if *self.lhs.clone().to_string() != rhs.clone().to_string() {
147                                    add_constraint(
148                                        self.constraints,
149                                        AliasConstraints::Assign(*self.lhs, rhs),
150                                    );
151                                }
152                                Some(())
153                            });
154                        } else {
155                            lookup_ast(self.ast, e).and_then(|rhs| {
156                                if *self.lhs.clone().to_string() != rhs.clone().to_string() {
157                                    add_constraint(
158                                        self.constraints,
159                                        AliasConstraints::Assign(*self.lhs, rhs),
160                                    );
161                                }
162                                Some(())
163                            });
164                        }
165
166                        match e {
167                            Expr::MethodCall(_) => {} // can ret ref but no idea the ret ty
168                            Expr::Call(_) => {}
169
170                            Expr::Block(b) => match b.block.stmts.last_mut() {
171                                None => {}
172                                Some(s) => self.visit_stmt_mut(s),
173                            },
174                            Expr::Box(b) => {
175                                let mut expr_helper = ExprHelper {
176                                    lhs: self.lhs,
177                                    ast: self.ast,
178                                    constraints: self.constraints,
179                                };
180                                expr_helper.visit_expr_mut(b.expr.as_mut())
181                            }
182                            Expr::Cast(c) => {
183                                let mut expr_helper = ExprHelper {
184                                    lhs: self.lhs,
185                                    ast: self.ast,
186                                    constraints: self.constraints,
187                                };
188                                match c.ty.as_ref() {
189                                    Type::Reference(_) => {
190                                        expr_helper.visit_expr_mut(c.expr.as_mut())
191                                    }
192                                    _ => (),
193                                }
194                            }
195                            Expr::If(i) => {
196                                match i.then_branch.stmts.last_mut() {
197                                    None => {}
198                                    Some(s) => self.visit_stmt_mut(s),
199                                }
200                                match &mut i.else_branch {
201                                    None => {}
202                                    Some((_, s)) => {
203                                        self.visit_stmt_mut(&mut Stmt::Expr(*s.clone().clone()))
204                                    }
205                                }
206                            }
207
208                            Expr::Match(m) => m.arms.iter_mut().for_each(|arm| {
209                                self.visit_stmt_mut(&mut Stmt::Expr(arm.body.as_mut().clone()))
210                            }),
211                            Expr::Paren(e) => self.visit_stmt_mut(&mut Stmt::Expr(*e.expr.clone())),
212
213                            Expr::Reference(r) => {
214                                add_constraint(self.constraints, AliasConstraints::Ref(*self.lhs));
215                                let mut expr_helper = ExprHelper {
216                                    lhs: self.lhs,
217                                    ast: self.ast,
218                                    constraints: self.constraints,
219                                };
220                                expr_helper.visit_expr_mut(r.expr.as_mut())
221                            }
222                            _ => syn::visit_mut::visit_stmt_mut(self, i),
223                        }
224                    }
225                    _ => syn::visit_mut::visit_stmt_mut(self, i),
226                }
227            }
228        }
229
230        struct LHSHelper<'a> {
231            ident: &'a mut Ident,
232        }
233
234        impl VisitMut for LHSHelper<'_> {
235            fn visit_ident_mut(&mut self, i: &mut Ident) {
236                *self.ident = i.clone()
237            }
238        }
239
240        impl VisitMut for Traverse<'_> {
241            fn visit_item_fn_mut(&mut self, f: &mut syn::ItemFn) {
242                self.visit_block_mut(f.block.as_mut());
243                for arg in &f.sig.inputs {
244                    match arg {
245                        FnArg::Typed(ty) => match ty.ty.as_ref() {
246                            Type::Reference(_) => {
247                                let mut ident = Ident::new("IDENT", Span::call_site());
248                                let mut ident_helper = LHSHelper { ident: &mut ident };
249                                ident_helper.visit_pat_mut(ty.pat.clone().as_mut());
250                                lookup_ast(self.ast, &ident).and_then(|label| {
251                                    add_constraint(self.constraints, AliasConstraints::Ref(label));
252                                    Some(())
253                                });
254                            }
255                            _ => (),
256                        },
257                        FnArg::Receiver(_) => (),
258                    }
259                }
260            }
261
262            fn visit_expr_assign_mut(&mut self, i: &mut ExprAssign) {
263                let mut ident = Ident::new("IDENT", Span::call_site());
264                let mut ident_helper = LHSHelper { ident: &mut ident };
265                ident_helper.visit_expr_mut(i.left.as_mut());
266                lookup_ast(self.ast, &ident).and_then(|label| {
267                    let lhs = &label;
268                    let mut expr_helper = StmtHelper {
269                        lhs,
270                        ast: self.ast,
271                        constraints: self.constraints,
272                    };
273                    expr_helper.visit_stmt_mut(&mut Stmt::Expr(*i.right.clone()));
274                    Some(())
275                });
276            }
277
278            fn visit_local_mut(&mut self, i: &mut syn::Local) {
279                let pat = &i.pat;
280                // println!("local: {}", i.clone().into_token_stream().to_string());
281                match &*pat {
282                    // Case of the form `let lhs : T = rhs`
283                    syn::Pat::Type(syn::PatType {
284                        pat: box syn::Pat::Ident(p),
285                        ty: box ty,
286                        ..
287                    }) => {
288                        match ty {
289                            Type::Reference(_) => {
290                                let ident = &p.ident;
291                                lookup_ast(self.ast, ident).and_then(|label| {
292                                    let lhs = &label;
293                                    add_constraint(self.constraints, AliasConstraints::Ref(label));
294                                    match i.init.clone() {
295                                        None => (),
296                                        Some((_, init)) => {
297                                            let mut expr_helper = StmtHelper {
298                                                lhs,
299                                                ast: self.ast,
300                                                constraints: self.constraints,
301                                            };
302                                            expr_helper
303                                                .visit_stmt_mut(&mut Stmt::Expr(*init.clone()))
304                                        }
305                                    };
306                                    Some(())
307                                });
308                            }
309                            _ => {}
310                        }
311                        syn::visit_mut::visit_local_mut(self, i);
312                    }
313                    syn::Pat::Ident(syn::PatIdent { ident, .. }) => match i.init.clone() {
314                        None => (),
315                        Some((_, init)) => {
316                            lookup_ast(self.ast, ident).and_then(|label| {
317                                let lhs = &label;
318                                let mut expr_helper = StmtHelper {
319                                    lhs,
320                                    ast: self.ast,
321                                    constraints: self.constraints,
322                                };
323                                expr_helper.visit_stmt_mut(&mut Stmt::Expr(*init.clone()));
324                                Some(())
325                            });
326                        }
327                    },
328                    _ => syn::visit_mut::visit_local_mut(self, i),
329                }
330            }
331        }
332
333        let mut constraints = vec![];
334        let mut collector = Traverse {
335            ast: map,
336            constraints: &mut constraints,
337        };
338        collector.visit_item_fn_mut(&mut fun.clone().clone());
339        constraints.into_iter().unique().collect()
340    }
341}