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#[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 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(_) => {} 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 match &*pat {
282 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}