]> git.lizzy.rs Git - rust.git/blob - src/librustc_front/util.rs
Auto merge of #31077 - nagisa:mir-temp-promotion, r=dotdash
[rust.git] / src / librustc_front / util.rs
1 // Copyright 2015 The Rust Project Developers. See the COPYRIGHT
2 // file at the top-level directory of this distribution and at
3 // http://rust-lang.org/COPYRIGHT.
4 //
5 // Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6 // http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7 // <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8 // option. This file may not be copied, modified, or distributed
9 // except according to those terms.
10
11 use hir;
12 use hir::*;
13 use intravisit::{self, Visitor, FnKind};
14 use syntax::ast_util;
15 use syntax::ast::{Name, NodeId, DUMMY_NODE_ID};
16 use syntax::codemap::Span;
17 use syntax::ptr::P;
18
19 pub fn walk_pat<F>(pat: &Pat, mut it: F) -> bool
20     where F: FnMut(&Pat) -> bool
21 {
22     // FIXME(#19596) this is a workaround, but there should be a better way
23     fn walk_pat_<G>(pat: &Pat, it: &mut G) -> bool
24         where G: FnMut(&Pat) -> bool
25     {
26         if !(*it)(pat) {
27             return false;
28         }
29
30         match pat.node {
31             PatIdent(_, _, Some(ref p)) => walk_pat_(&**p, it),
32             PatStruct(_, ref fields, _) => {
33                 fields.iter().all(|field| walk_pat_(&*field.node.pat, it))
34             }
35             PatEnum(_, Some(ref s)) | PatTup(ref s) => {
36                 s.iter().all(|p| walk_pat_(&**p, it))
37             }
38             PatBox(ref s) | PatRegion(ref s, _) => {
39                 walk_pat_(&**s, it)
40             }
41             PatVec(ref before, ref slice, ref after) => {
42                 before.iter().all(|p| walk_pat_(&**p, it)) &&
43                 slice.iter().all(|p| walk_pat_(&**p, it)) &&
44                 after.iter().all(|p| walk_pat_(&**p, it))
45             }
46             PatWild |
47             PatLit(_) |
48             PatRange(_, _) |
49             PatIdent(_, _, _) |
50             PatEnum(_, _) |
51             PatQPath(_, _) => {
52                 true
53             }
54         }
55     }
56
57     walk_pat_(pat, &mut it)
58 }
59
60 pub fn binop_to_string(op: BinOp_) -> &'static str {
61     match op {
62         BiAdd => "+",
63         BiSub => "-",
64         BiMul => "*",
65         BiDiv => "/",
66         BiRem => "%",
67         BiAnd => "&&",
68         BiOr => "||",
69         BiBitXor => "^",
70         BiBitAnd => "&",
71         BiBitOr => "|",
72         BiShl => "<<",
73         BiShr => ">>",
74         BiEq => "==",
75         BiLt => "<",
76         BiLe => "<=",
77         BiNe => "!=",
78         BiGe => ">=",
79         BiGt => ">",
80     }
81 }
82
83 pub fn stmt_id(s: &Stmt) -> NodeId {
84     match s.node {
85         StmtDecl(_, id) => id,
86         StmtExpr(_, id) => id,
87         StmtSemi(_, id) => id,
88     }
89 }
90
91 pub fn lazy_binop(b: BinOp_) -> bool {
92     match b {
93         BiAnd => true,
94         BiOr => true,
95         _ => false,
96     }
97 }
98
99 pub fn is_shift_binop(b: BinOp_) -> bool {
100     match b {
101         BiShl => true,
102         BiShr => true,
103         _ => false,
104     }
105 }
106
107 pub fn is_comparison_binop(b: BinOp_) -> bool {
108     match b {
109         BiEq | BiLt | BiLe | BiNe | BiGt | BiGe => true,
110         BiAnd |
111         BiOr |
112         BiAdd |
113         BiSub |
114         BiMul |
115         BiDiv |
116         BiRem |
117         BiBitXor |
118         BiBitAnd |
119         BiBitOr |
120         BiShl |
121         BiShr => false,
122     }
123 }
124
125 /// Returns `true` if the binary operator takes its arguments by value
126 pub fn is_by_value_binop(b: BinOp_) -> bool {
127     !is_comparison_binop(b)
128 }
129
130 /// Returns `true` if the unary operator takes its argument by value
131 pub fn is_by_value_unop(u: UnOp) -> bool {
132     match u {
133         UnNeg | UnNot => true,
134         _ => false,
135     }
136 }
137
138 pub fn unop_to_string(op: UnOp) -> &'static str {
139     match op {
140         UnDeref => "*",
141         UnNot => "!",
142         UnNeg => "-",
143     }
144 }
145
146 pub struct IdVisitor<'a, O: 'a> {
147     operation: &'a mut O,
148
149     // In general, the id visitor visits the contents of an item, but
150     // not including nested trait/impl items, nor other nested items.
151     // The base visitor itself always skips nested items, but not
152     // trait/impl items. This means in particular that if you start by
153     // visiting a trait or an impl, you should not visit the
154     // trait/impl items respectively.  This is handled by setting
155     // `skip_members` to true when `visit_item` is on the stack. This
156     // way, if the user begins by calling `visit_trait_item`, we will
157     // visit the trait item, but if they begin with `visit_item`, we
158     // won't visit the (nested) trait items.
159     skip_members: bool,
160 }
161
162 impl<'a, O: ast_util::IdVisitingOperation> IdVisitor<'a, O> {
163     pub fn new(operation: &'a mut O) -> IdVisitor<'a, O> {
164         IdVisitor { operation: operation, skip_members: false }
165     }
166
167     fn visit_generics_helper(&mut self, generics: &Generics) {
168         for type_parameter in generics.ty_params.iter() {
169             self.operation.visit_id(type_parameter.id)
170         }
171         for lifetime in &generics.lifetimes {
172             self.operation.visit_id(lifetime.lifetime.id)
173         }
174     }
175 }
176
177 impl<'a, 'v, O: ast_util::IdVisitingOperation> Visitor<'v> for IdVisitor<'a, O> {
178     fn visit_mod(&mut self, module: &Mod, _: Span, node_id: NodeId) {
179         self.operation.visit_id(node_id);
180         intravisit::walk_mod(self, module)
181     }
182
183     fn visit_foreign_item(&mut self, foreign_item: &ForeignItem) {
184         self.operation.visit_id(foreign_item.id);
185         intravisit::walk_foreign_item(self, foreign_item)
186     }
187
188     fn visit_item(&mut self, item: &Item) {
189         assert!(!self.skip_members);
190         self.skip_members = true;
191
192         self.operation.visit_id(item.id);
193         match item.node {
194             ItemUse(ref view_path) => {
195                 match view_path.node {
196                     ViewPathSimple(_, _) |
197                     ViewPathGlob(_) => {}
198                     ViewPathList(_, ref paths) => {
199                         for path in paths {
200                             self.operation.visit_id(path.node.id())
201                         }
202                     }
203                 }
204             }
205             _ => {}
206         }
207         intravisit::walk_item(self, item);
208
209         self.skip_members = false;
210     }
211
212     fn visit_local(&mut self, local: &Local) {
213         self.operation.visit_id(local.id);
214         intravisit::walk_local(self, local)
215     }
216
217     fn visit_block(&mut self, block: &Block) {
218         self.operation.visit_id(block.id);
219         intravisit::walk_block(self, block)
220     }
221
222     fn visit_stmt(&mut self, statement: &Stmt) {
223         self.operation.visit_id(stmt_id(statement));
224         intravisit::walk_stmt(self, statement)
225     }
226
227     fn visit_pat(&mut self, pattern: &Pat) {
228         self.operation.visit_id(pattern.id);
229         intravisit::walk_pat(self, pattern)
230     }
231
232     fn visit_expr(&mut self, expression: &Expr) {
233         self.operation.visit_id(expression.id);
234         intravisit::walk_expr(self, expression)
235     }
236
237     fn visit_ty(&mut self, typ: &Ty) {
238         self.operation.visit_id(typ.id);
239         intravisit::walk_ty(self, typ)
240     }
241
242     fn visit_generics(&mut self, generics: &Generics) {
243         self.visit_generics_helper(generics);
244         intravisit::walk_generics(self, generics)
245     }
246
247     fn visit_fn(&mut self,
248                 function_kind: FnKind<'v>,
249                 function_declaration: &'v FnDecl,
250                 block: &'v Block,
251                 span: Span,
252                 node_id: NodeId) {
253         self.operation.visit_id(node_id);
254
255         match function_kind {
256             FnKind::ItemFn(_, generics, _, _, _, _) => {
257                 self.visit_generics_helper(generics)
258             }
259             FnKind::Method(_, sig, _) => {
260                 self.visit_generics_helper(&sig.generics)
261             }
262             FnKind::Closure => {}
263         }
264
265         for argument in &function_declaration.inputs {
266             self.operation.visit_id(argument.id)
267         }
268
269         intravisit::walk_fn(self, function_kind, function_declaration, block, span);
270     }
271
272     fn visit_struct_field(&mut self, struct_field: &StructField) {
273         self.operation.visit_id(struct_field.node.id);
274         intravisit::walk_struct_field(self, struct_field)
275     }
276
277     fn visit_variant_data(&mut self,
278                           struct_def: &VariantData,
279                           _: Name,
280                           _: &hir::Generics,
281                           _: NodeId,
282                           _: Span) {
283         self.operation.visit_id(struct_def.id());
284         intravisit::walk_struct_def(self, struct_def);
285     }
286
287     fn visit_trait_item(&mut self, ti: &hir::TraitItem) {
288         if !self.skip_members {
289             self.operation.visit_id(ti.id);
290             intravisit::walk_trait_item(self, ti);
291         }
292     }
293
294     fn visit_impl_item(&mut self, ii: &hir::ImplItem) {
295         if !self.skip_members {
296             self.operation.visit_id(ii.id);
297             intravisit::walk_impl_item(self, ii);
298         }
299     }
300
301     fn visit_lifetime(&mut self, lifetime: &Lifetime) {
302         self.operation.visit_id(lifetime.id);
303     }
304
305     fn visit_lifetime_def(&mut self, def: &LifetimeDef) {
306         self.visit_lifetime(&def.lifetime);
307     }
308
309     fn visit_trait_ref(&mut self, trait_ref: &TraitRef) {
310         self.operation.visit_id(trait_ref.ref_id);
311         intravisit::walk_trait_ref(self, trait_ref);
312     }
313 }
314
315 /// Computes the id range for a single fn body, ignoring nested items.
316 pub fn compute_id_range_for_fn_body(fk: FnKind,
317                                     decl: &FnDecl,
318                                     body: &Block,
319                                     sp: Span,
320                                     id: NodeId)
321                                     -> ast_util::IdRange {
322     let mut visitor = ast_util::IdRangeComputingVisitor { result: ast_util::IdRange::max() };
323     let mut id_visitor = IdVisitor::new(&mut visitor);
324     id_visitor.visit_fn(fk, decl, body, sp, id);
325     id_visitor.operation.result
326 }
327
328 pub fn is_path(e: P<Expr>) -> bool {
329     match e.node {
330         ExprPath(..) => true,
331         _ => false,
332     }
333 }
334
335 pub fn empty_generics() -> Generics {
336     Generics {
337         lifetimes: HirVec::new(),
338         ty_params: HirVec::new(),
339         where_clause: WhereClause {
340             id: DUMMY_NODE_ID,
341             predicates: HirVec::new(),
342         },
343     }
344 }
345
346 // convert a span and an identifier to the corresponding
347 // 1-segment path
348 pub fn ident_to_path(s: Span, ident: Ident) -> Path {
349     hir::Path {
350         span: s,
351         global: false,
352         segments: hir_vec![hir::PathSegment {
353             identifier: ident,
354             parameters: hir::AngleBracketedParameters(hir::AngleBracketedParameterData {
355                 lifetimes: HirVec::new(),
356                 types: HirVec::new(),
357                 bindings: HirVec::new(),
358             }),
359         }],
360     }
361 }