]> git.lizzy.rs Git - rust.git/blob - src/librustc/mir/visit.rs
mir: store the span of a scope in the ScopeData.
[rust.git] / src / librustc / mir / visit.rs
1 // Copyright 2012-2014 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 middle::const_val::ConstVal;
12 use hir::def_id::DefId;
13 use ty::subst::Substs;
14 use ty::{ClosureSubsts, FnOutput, Region, Ty};
15 use mir::repr::*;
16 use rustc_const_math::ConstUsize;
17 use rustc_data_structures::tuple_slice::TupleSlice;
18 use syntax::codemap::Span;
19
20 // # The MIR Visitor
21 //
22 // ## Overview
23 //
24 // There are two visitors, one for immutable and one for mutable references,
25 // but both are generated by the following macro. The code is written according
26 // to the following conventions:
27 //
28 // - introduce a `visit_foo` and a `super_foo` method for every MIR type
29 // - `visit_foo`, by default, calls `super_foo`
30 // - `super_foo`, by default, destructures the `foo` and calls `visit_foo`
31 //
32 // This allows you as a user to override `visit_foo` for types are
33 // interested in, and invoke (within that method) call
34 // `self.super_foo` to get the default behavior. Just as in an OO
35 // language, you should never call `super` methods ordinarily except
36 // in that circumstance.
37 //
38 // For the most part, we do not destructure things external to the
39 // MIR, e.g. types, spans, etc, but simply visit them and stop. This
40 // avoids duplication with other visitors like `TypeFoldable`. But
41 // there is one exception: we do destructure the `FnOutput` to reach
42 // the type within. Just because.
43 //
44 // ## Updating
45 //
46 // The code is written in a very deliberate style intended to minimize
47 // the chance of things being overlooked. You'll notice that we always
48 // use pattern matching to reference fields and we ensure that all
49 // matches are exhaustive.
50 //
51 // For example, the `super_basic_block_data` method begins like this:
52 //
53 // ```rust
54 // fn super_basic_block_data(&mut self,
55 //                           block: BasicBlock,
56 //                           data: & $($mutability)* BasicBlockData<'tcx>) {
57 //     let BasicBlockData {
58 //         ref $($mutability)* statements,
59 //         ref $($mutability)* terminator,
60 //         is_cleanup: _
61 //     } = *data;
62 //
63 //     for statement in statements {
64 //         self.visit_statement(block, statement);
65 //     }
66 //
67 //     ...
68 // }
69 // ```
70 //
71 // Here we used `let BasicBlockData { <fields> } = *data` deliberately,
72 // rather than writing `data.statements` in the body. This is because if one
73 // adds a new field to `BasicBlockData`, one will be forced to revise this code,
74 // and hence one will (hopefully) invoke the correct visit methods (if any).
75 //
76 // For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS.
77 // That means you never write `..` to skip over fields, nor do you write `_`
78 // to skip over variants in a `match`.
79 //
80 // The only place that `_` is acceptable is to match a field (or
81 // variant argument) that does not require visiting, as in
82 // `is_cleanup` above.
83
84 macro_rules! make_mir_visitor {
85     ($visitor_trait_name:ident, $($mutability:ident)*) => {
86         pub trait $visitor_trait_name<'tcx> {
87             // Override these, and call `self.super_xxx` to revert back to the
88             // default behavior.
89
90             fn visit_mir(&mut self, mir: & $($mutability)* Mir<'tcx>) {
91                 self.super_mir(mir);
92             }
93
94             fn visit_basic_block_data(&mut self,
95                                       block: BasicBlock,
96                                       data: & $($mutability)* BasicBlockData<'tcx>) {
97                 self.super_basic_block_data(block, data);
98             }
99
100             fn visit_scope_data(&mut self,
101                                 scope_data: & $($mutability)* ScopeData) {
102                 self.super_scope_data(scope_data);
103             }
104
105             fn visit_statement(&mut self,
106                                block: BasicBlock,
107                                statement: & $($mutability)* Statement<'tcx>) {
108                 self.super_statement(block, statement);
109             }
110
111             fn visit_assign(&mut self,
112                             block: BasicBlock,
113                             lvalue: & $($mutability)* Lvalue<'tcx>,
114                             rvalue: & $($mutability)* Rvalue<'tcx>) {
115                 self.super_assign(block, lvalue, rvalue);
116             }
117
118             fn visit_terminator(&mut self,
119                                 block: BasicBlock,
120                                 terminator: & $($mutability)* Terminator<'tcx>) {
121                 self.super_terminator(block, terminator);
122             }
123
124             fn visit_terminator_kind(&mut self,
125                                      block: BasicBlock,
126                                      kind: & $($mutability)* TerminatorKind<'tcx>) {
127                 self.super_terminator_kind(block, kind);
128             }
129
130             fn visit_rvalue(&mut self,
131                             rvalue: & $($mutability)* Rvalue<'tcx>) {
132                 self.super_rvalue(rvalue);
133             }
134
135             fn visit_operand(&mut self,
136                              operand: & $($mutability)* Operand<'tcx>) {
137                 self.super_operand(operand);
138             }
139
140             fn visit_lvalue(&mut self,
141                             lvalue: & $($mutability)* Lvalue<'tcx>,
142                             context: LvalueContext) {
143                 self.super_lvalue(lvalue, context);
144             }
145
146             fn visit_projection(&mut self,
147                                 lvalue: & $($mutability)* LvalueProjection<'tcx>,
148                                 context: LvalueContext) {
149                 self.super_projection(lvalue, context);
150             }
151
152             fn visit_projection_elem(&mut self,
153                                      lvalue: & $($mutability)* LvalueElem<'tcx>,
154                                      context: LvalueContext) {
155                 self.super_projection_elem(lvalue, context);
156             }
157
158             fn visit_branch(&mut self,
159                             source: BasicBlock,
160                             target: BasicBlock) {
161                 self.super_branch(source, target);
162             }
163
164             fn visit_constant(&mut self,
165                               constant: & $($mutability)* Constant<'tcx>) {
166                 self.super_constant(constant);
167             }
168
169             fn visit_literal(&mut self,
170                              literal: & $($mutability)* Literal<'tcx>) {
171                 self.super_literal(literal);
172             }
173
174             fn visit_def_id(&mut self,
175                             def_id: & $($mutability)* DefId) {
176                 self.super_def_id(def_id);
177             }
178
179             fn visit_span(&mut self,
180                           span: & $($mutability)* Span) {
181                 self.super_span(span);
182             }
183
184             fn visit_fn_output(&mut self,
185                                fn_output: & $($mutability)* FnOutput<'tcx>) {
186                 self.super_fn_output(fn_output);
187             }
188
189             fn visit_ty(&mut self,
190                         ty: & $($mutability)* Ty<'tcx>) {
191                 self.super_ty(ty);
192             }
193
194             fn visit_substs(&mut self,
195                             substs: & $($mutability)* &'tcx Substs<'tcx>) {
196                 self.super_substs(substs);
197             }
198
199             fn visit_closure_substs(&mut self,
200                                     substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
201                 self.super_closure_substs(substs);
202             }
203
204             fn visit_const_val(&mut self,
205                                const_val: & $($mutability)* ConstVal) {
206                 self.super_const_val(const_val);
207             }
208
209             fn visit_const_usize(&mut self,
210                                  const_usize: & $($mutability)* ConstUsize) {
211                 self.super_const_usize(const_usize);
212             }
213
214             fn visit_typed_const_val(&mut self,
215                                      val: & $($mutability)* TypedConstVal<'tcx>) {
216                 self.super_typed_const_val(val);
217             }
218
219             fn visit_var_decl(&mut self,
220                               var_decl: & $($mutability)* VarDecl<'tcx>) {
221                 self.super_var_decl(var_decl);
222             }
223
224             fn visit_temp_decl(&mut self,
225                                temp_decl: & $($mutability)* TempDecl<'tcx>) {
226                 self.super_temp_decl(temp_decl);
227             }
228
229             fn visit_arg_decl(&mut self,
230                               arg_decl: & $($mutability)* ArgDecl<'tcx>) {
231                 self.super_arg_decl(arg_decl);
232             }
233
234             fn visit_scope_id(&mut self,
235                               scope_id: & $($mutability)* ScopeId) {
236                 self.super_scope_id(scope_id);
237             }
238
239             // The `super_xxx` methods comprise the default behavior and are
240             // not meant to be overridden.
241
242             fn super_mir(&mut self,
243                          mir: & $($mutability)* Mir<'tcx>) {
244                 let Mir {
245                     ref $($mutability)* basic_blocks,
246                     ref $($mutability)* scopes,
247                     ref $($mutability)* return_ty,
248                     ref $($mutability)* var_decls,
249                     ref $($mutability)* arg_decls,
250                     ref $($mutability)* temp_decls,
251                     ref $($mutability)* span,
252                 } = *mir;
253
254                 for (index, data) in basic_blocks.into_iter().enumerate() {
255                     let block = BasicBlock::new(index);
256                     self.visit_basic_block_data(block, data);
257                 }
258
259                 for scope in scopes {
260                     self.visit_scope_data(scope);
261                 }
262
263                 self.visit_fn_output(return_ty);
264
265                 for var_decl in var_decls {
266                     self.visit_var_decl(var_decl);
267                 }
268
269                 for arg_decl in arg_decls {
270                     self.visit_arg_decl(arg_decl);
271                 }
272
273                 for temp_decl in temp_decls {
274                     self.visit_temp_decl(temp_decl);
275                 }
276
277                 self.visit_span(span);
278             }
279
280             fn super_basic_block_data(&mut self,
281                                       block: BasicBlock,
282                                       data: & $($mutability)* BasicBlockData<'tcx>) {
283                 let BasicBlockData {
284                     ref $($mutability)* statements,
285                     ref $($mutability)* terminator,
286                     is_cleanup: _
287                 } = *data;
288
289                 for statement in statements {
290                     self.visit_statement(block, statement);
291                 }
292
293                 if let Some(ref $($mutability)* terminator) = *terminator {
294                     self.visit_terminator(block, terminator);
295                 }
296             }
297
298             fn super_scope_data(&mut self,
299                                 scope_data: & $($mutability)* ScopeData) {
300                 let ScopeData {
301                     ref $($mutability)* span,
302                     ref $($mutability)* parent_scope,
303                 } = *scope_data;
304
305                 self.visit_span(span);
306                 if let Some(ref $($mutability)* parent_scope) = *parent_scope {
307                     self.visit_scope_id(parent_scope);
308                 }
309             }
310
311             fn super_statement(&mut self,
312                                block: BasicBlock,
313                                statement: & $($mutability)* Statement<'tcx>) {
314                 let Statement {
315                     ref $($mutability)* span,
316                     ref $($mutability)* scope,
317                     ref $($mutability)* kind,
318                 } = *statement;
319
320                 self.visit_span(span);
321                 self.visit_scope_id(scope);
322                 match *kind {
323                     StatementKind::Assign(ref $($mutability)* lvalue,
324                                           ref $($mutability)* rvalue) => {
325                         self.visit_assign(block, lvalue, rvalue);
326                     }
327                 }
328             }
329
330             fn super_assign(&mut self,
331                             _block: BasicBlock,
332                             lvalue: &$($mutability)* Lvalue<'tcx>,
333                             rvalue: &$($mutability)* Rvalue<'tcx>) {
334                 self.visit_lvalue(lvalue, LvalueContext::Store);
335                 self.visit_rvalue(rvalue);
336             }
337
338             fn super_terminator(&mut self,
339                                 block: BasicBlock,
340                                 terminator: &$($mutability)* Terminator<'tcx>) {
341                 let Terminator {
342                     ref $($mutability)* span,
343                     ref $($mutability)* scope,
344                     ref $($mutability)* kind,
345                 } = *terminator;
346
347                 self.visit_span(span);
348                 self.visit_scope_id(scope);
349                 self.visit_terminator_kind(block, kind);
350             }
351
352             fn super_terminator_kind(&mut self,
353                                      block: BasicBlock,
354                                      kind: & $($mutability)* TerminatorKind<'tcx>) {
355                 match *kind {
356                     TerminatorKind::Goto { target } => {
357                         self.visit_branch(block, target);
358                     }
359
360                     TerminatorKind::If { ref $($mutability)* cond,
361                                          ref $($mutability)* targets } => {
362                         self.visit_operand(cond);
363                         for &target in targets.as_slice() {
364                             self.visit_branch(block, target);
365                         }
366                     }
367
368                     TerminatorKind::Switch { ref $($mutability)* discr,
369                                              adt_def: _,
370                                              ref targets } => {
371                         self.visit_lvalue(discr, LvalueContext::Inspect);
372                         for &target in targets {
373                             self.visit_branch(block, target);
374                         }
375                     }
376
377                     TerminatorKind::SwitchInt { ref $($mutability)* discr,
378                                                 ref $($mutability)* switch_ty,
379                                                 ref $($mutability)* values,
380                                                 ref targets } => {
381                         self.visit_lvalue(discr, LvalueContext::Inspect);
382                         self.visit_ty(switch_ty);
383                         for value in values {
384                             self.visit_const_val(value);
385                         }
386                         for &target in targets {
387                             self.visit_branch(block, target);
388                         }
389                     }
390
391                     TerminatorKind::Resume |
392                     TerminatorKind::Return => {
393                     }
394
395                     TerminatorKind::Drop { ref $($mutability)* value,
396                                            target,
397                                            unwind } => {
398                         self.visit_lvalue(value, LvalueContext::Drop);
399                         self.visit_branch(block, target);
400                         unwind.map(|t| self.visit_branch(block, t));
401                     }
402
403                     TerminatorKind::Call { ref $($mutability)* func,
404                                            ref $($mutability)* args,
405                                            ref $($mutability)* destination,
406                                            cleanup } => {
407                         self.visit_operand(func);
408                         for arg in args {
409                             self.visit_operand(arg);
410                         }
411                         if let Some((ref $($mutability)* destination, target)) = *destination {
412                             self.visit_lvalue(destination, LvalueContext::Call);
413                             self.visit_branch(block, target);
414                         }
415                         cleanup.map(|t| self.visit_branch(block, t));
416                     }
417                 }
418             }
419
420             fn super_rvalue(&mut self,
421                             rvalue: & $($mutability)* Rvalue<'tcx>) {
422                 match *rvalue {
423                     Rvalue::Use(ref $($mutability)* operand) => {
424                         self.visit_operand(operand);
425                     }
426
427                     Rvalue::Repeat(ref $($mutability)* value,
428                                    ref $($mutability)* typed_const_val) => {
429                         self.visit_operand(value);
430                         self.visit_typed_const_val(typed_const_val);
431                     }
432
433                     Rvalue::Ref(r, bk, ref $($mutability)* path) => {
434                         self.visit_lvalue(path, LvalueContext::Borrow {
435                             region: r,
436                             kind: bk
437                         });
438                     }
439
440                     Rvalue::Len(ref $($mutability)* path) => {
441                         self.visit_lvalue(path, LvalueContext::Inspect);
442                     }
443
444                     Rvalue::Cast(_cast_kind,
445                                  ref $($mutability)* operand,
446                                  ref $($mutability)* ty) => {
447                         self.visit_operand(operand);
448                         self.visit_ty(ty);
449                     }
450
451                     Rvalue::BinaryOp(_bin_op,
452                                      ref $($mutability)* lhs,
453                                      ref $($mutability)* rhs) => {
454                         self.visit_operand(lhs);
455                         self.visit_operand(rhs);
456                     }
457
458                     Rvalue::UnaryOp(_un_op, ref $($mutability)* op) => {
459                         self.visit_operand(op);
460                     }
461
462                     Rvalue::Box(ref $($mutability)* ty) => {
463                         self.visit_ty(ty);
464                     }
465
466                     Rvalue::Aggregate(ref $($mutability)* kind,
467                                       ref $($mutability)* operands) => {
468                         match *kind {
469                             AggregateKind::Vec => {
470                             }
471                             AggregateKind::Tuple => {
472                             }
473                             AggregateKind::Adt(_adt_def,
474                                                _variant_index,
475                                                ref $($mutability)* substs) => {
476                                 self.visit_substs(substs);
477                             }
478                             AggregateKind::Closure(ref $($mutability)* def_id,
479                                                    ref $($mutability)* closure_substs) => {
480                                 self.visit_def_id(def_id);
481                                 self.visit_closure_substs(closure_substs);
482                             }
483                         }
484
485                         for operand in operands {
486                             self.visit_operand(operand);
487                         }
488                     }
489
490                     Rvalue::Slice { ref $($mutability)* input,
491                                     from_start,
492                                     from_end } => {
493                         self.visit_lvalue(input, LvalueContext::Slice {
494                             from_start: from_start,
495                             from_end: from_end,
496                         });
497                     }
498
499                     Rvalue::InlineAsm { ref $($mutability)* outputs,
500                                         ref $($mutability)* inputs,
501                                         asm: _ } => {
502                         for output in & $($mutability)* outputs[..] {
503                             self.visit_lvalue(output, LvalueContext::Store);
504                         }
505                         for input in & $($mutability)* inputs[..] {
506                             self.visit_operand(input);
507                         }
508                     }
509                 }
510             }
511
512             fn super_operand(&mut self,
513                              operand: & $($mutability)* Operand<'tcx>) {
514                 match *operand {
515                     Operand::Consume(ref $($mutability)* lvalue) => {
516                         self.visit_lvalue(lvalue, LvalueContext::Consume);
517                     }
518                     Operand::Constant(ref $($mutability)* constant) => {
519                         self.visit_constant(constant);
520                     }
521                 }
522             }
523
524             fn super_lvalue(&mut self,
525                             lvalue: & $($mutability)* Lvalue<'tcx>,
526                             context: LvalueContext) {
527                 match *lvalue {
528                     Lvalue::Var(_) |
529                     Lvalue::Temp(_) |
530                     Lvalue::Arg(_) |
531                     Lvalue::ReturnPointer => {
532                     }
533                     Lvalue::Static(ref $($mutability)* def_id) => {
534                         self.visit_def_id(def_id);
535                     }
536                     Lvalue::Projection(ref $($mutability)* proj) => {
537                         self.visit_projection(proj, context);
538                     }
539                 }
540             }
541
542             fn super_projection(&mut self,
543                                 proj: & $($mutability)* LvalueProjection<'tcx>,
544                                 context: LvalueContext) {
545                 let Projection {
546                     ref $($mutability)* base,
547                     ref $($mutability)* elem,
548                 } = *proj;
549                 self.visit_lvalue(base, LvalueContext::Projection);
550                 self.visit_projection_elem(elem, context);
551             }
552
553             fn super_projection_elem(&mut self,
554                                      proj: & $($mutability)* LvalueElem<'tcx>,
555                                      _context: LvalueContext) {
556                 match *proj {
557                     ProjectionElem::Deref => {
558                     }
559                     ProjectionElem::Field(_field, ref $($mutability)* ty) => {
560                         self.visit_ty(ty);
561                     }
562                     ProjectionElem::Index(ref $($mutability)* operand) => {
563                         self.visit_operand(operand);
564                     }
565                     ProjectionElem::ConstantIndex { offset: _,
566                                                     min_length: _,
567                                                     from_end: _ } => {
568                     }
569                     ProjectionElem::Downcast(_adt_def, _variant_index) => {
570                     }
571                 }
572             }
573
574             fn super_var_decl(&mut self,
575                               var_decl: & $($mutability)* VarDecl<'tcx>) {
576                 let VarDecl {
577                     mutability: _,
578                     name: _,
579                     ref $($mutability)* ty,
580                     ref $($mutability)* scope,
581                     ref $($mutability)* span,
582                 } = *var_decl;
583
584                 self.visit_ty(ty);
585                 self.visit_scope_id(scope);
586                 self.visit_span(span);
587             }
588
589             fn super_temp_decl(&mut self,
590                                temp_decl: & $($mutability)* TempDecl<'tcx>) {
591                 let TempDecl {
592                     ref $($mutability)* ty,
593                 } = *temp_decl;
594
595                 self.visit_ty(ty);
596             }
597
598             fn super_arg_decl(&mut self,
599                               arg_decl: & $($mutability)* ArgDecl<'tcx>) {
600                 let ArgDecl {
601                     ref $($mutability)* ty,
602                     spread: _
603                 } = *arg_decl;
604
605                 self.visit_ty(ty);
606             }
607
608             fn super_scope_id(&mut self,
609                               _scope_id: & $($mutability)* ScopeId) {
610             }
611
612             fn super_branch(&mut self,
613                             _source: BasicBlock,
614                             _target: BasicBlock) {
615             }
616
617             fn super_constant(&mut self,
618                               constant: & $($mutability)* Constant<'tcx>) {
619                 let Constant {
620                     ref $($mutability)* span,
621                     ref $($mutability)* ty,
622                     ref $($mutability)* literal,
623                 } = *constant;
624
625                 self.visit_span(span);
626                 self.visit_ty(ty);
627                 self.visit_literal(literal);
628             }
629
630             fn super_typed_const_val(&mut self,
631                                      constant: & $($mutability)* TypedConstVal<'tcx>) {
632                 let TypedConstVal {
633                     ref $($mutability)* span,
634                     ref $($mutability)* ty,
635                     ref $($mutability)* value,
636                 } = *constant;
637
638                 self.visit_span(span);
639                 self.visit_ty(ty);
640                 self.visit_const_usize(value);
641             }
642
643             fn super_literal(&mut self,
644                              literal: & $($mutability)* Literal<'tcx>) {
645                 match *literal {
646                     Literal::Item { ref $($mutability)* def_id,
647                                     ref $($mutability)* substs } => {
648                         self.visit_def_id(def_id);
649                         self.visit_substs(substs);
650                     },
651                     Literal::Value { ref $($mutability)* value } => {
652                         self.visit_const_val(value);
653                     }
654                 }
655             }
656
657             fn super_def_id(&mut self, _def_id: & $($mutability)* DefId) {
658             }
659
660             fn super_span(&mut self, _span: & $($mutability)* Span) {
661             }
662
663             fn super_fn_output(&mut self, fn_output: & $($mutability)* FnOutput<'tcx>) {
664                 match *fn_output {
665                     FnOutput::FnConverging(ref $($mutability)* ty) => {
666                         self.visit_ty(ty);
667                     }
668                     FnOutput::FnDiverging => {
669                     }
670                 }
671             }
672
673             fn super_ty(&mut self, _ty: & $($mutability)* Ty<'tcx>) {
674             }
675
676             fn super_substs(&mut self, _substs: & $($mutability)* &'tcx Substs<'tcx>) {
677             }
678
679             fn super_closure_substs(&mut self,
680                                     _substs: & $($mutability)* &'tcx ClosureSubsts<'tcx>) {
681             }
682
683             fn super_const_val(&mut self, _substs: & $($mutability)* ConstVal) {
684             }
685
686             fn super_const_usize(&mut self, _substs: & $($mutability)* ConstUsize) {
687             }
688         }
689     }
690 }
691
692 make_mir_visitor!(Visitor,);
693 make_mir_visitor!(MutVisitor,mut);
694
695 #[derive(Copy, Clone, Debug)]
696 pub enum LvalueContext {
697     // Appears as LHS of an assignment
698     Store,
699
700     // Dest of a call
701     Call,
702
703     // Being dropped
704     Drop,
705
706     // Being inspected in some way, like loading a len
707     Inspect,
708
709     // Being borrowed
710     Borrow { region: Region, kind: BorrowKind },
711
712     // Being sliced -- this should be same as being borrowed, probably
713     Slice { from_start: usize, from_end: usize },
714
715     // Used as base for another lvalue, e.g. `x` in `x.y`
716     Projection,
717
718     // Consumed as part of an operand
719     Consume,
720 }