|
| 1 | +//! # The MIR Visitor |
| 2 | +//! |
| 3 | +//! ## Overview |
| 4 | +//! |
| 5 | +//! There are two visitors, one for immutable and one for mutable references, |
| 6 | +//! but both are generated by the following macro. The code is written according |
| 7 | +//! to the following conventions: |
| 8 | +//! |
| 9 | +//! - introduce a `visit_foo` and a `super_foo` method for every MIR type |
| 10 | +//! - `visit_foo`, by default, calls `super_foo` |
| 11 | +//! - `super_foo`, by default, destructures the `foo` and calls `visit_foo` |
| 12 | +//! |
| 13 | +//! This allows you as a user to override `visit_foo` for types are |
| 14 | +//! interested in, and invoke (within that method) call |
| 15 | +//! `self.super_foo` to get the default behavior. Just as in an OO |
| 16 | +//! language, you should never call `super` methods ordinarily except |
| 17 | +//! in that circumstance. |
| 18 | +//! |
| 19 | +//! For the most part, we do not destructure things external to the |
| 20 | +//! MIR, e.g., types, spans, etc, but simply visit them and stop. This |
| 21 | +//! avoids duplication with other visitors like `TypeFoldable`. |
| 22 | +//! |
| 23 | +//! ## Updating |
| 24 | +//! |
| 25 | +//! The code is written in a very deliberate style intended to minimize |
| 26 | +//! the chance of things being overlooked. You'll notice that we always |
| 27 | +//! use pattern matching to reference fields and we ensure that all |
| 28 | +//! matches are exhaustive. |
| 29 | +//! |
| 30 | +//! For example, the `super_basic_block_data` method begins like this: |
| 31 | +//! |
| 32 | +//! ```rust |
| 33 | +//! fn super_basic_block_data(&mut self, |
| 34 | +//! block: BasicBlock, |
| 35 | +//! data: & $($mutability)? BasicBlockData<'tcx>) { |
| 36 | +//! let BasicBlockData { |
| 37 | +//! statements, |
| 38 | +//! terminator, |
| 39 | +//! is_cleanup: _ |
| 40 | +//! } = *data; |
| 41 | +//! |
| 42 | +//! for statement in statements { |
| 43 | +//! self.visit_statement(block, statement); |
| 44 | +//! } |
| 45 | +//! |
| 46 | +//! ... |
| 47 | +//! } |
| 48 | +//! ``` |
| 49 | +//! |
| 50 | +//! Here we used `let BasicBlockData { <fields> } = *data` deliberately, |
| 51 | +//! rather than writing `data.statements` in the body. This is because if one |
| 52 | +//! adds a new field to `BasicBlockData`, one will be forced to revise this code, |
| 53 | +//! and hence one will (hopefully) invoke the correct visit methods (if any). |
| 54 | +//! |
| 55 | +//! For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. |
| 56 | +//! That means you never write `..` to skip over fields, nor do you write `_` |
| 57 | +//! to skip over variants in a `match`. |
| 58 | +//! |
| 59 | +//! The only place that `_` is acceptable is to match a field (or |
| 60 | +//! variant argument) that does not require visiting, as in |
| 61 | +//! `is_cleanup` above. |
| 62 | +
|
1 | 63 | use crate::mir::*;
|
2 | 64 | use crate::ty::subst::SubstsRef;
|
3 | 65 | use crate::ty::{CanonicalUserTypeAnnotation, Ty};
|
4 | 66 | use rustc_span::Span;
|
5 | 67 |
|
6 |
| -// # The MIR Visitor |
7 |
| -// |
8 |
| -// ## Overview |
9 |
| -// |
10 |
| -// There are two visitors, one for immutable and one for mutable references, |
11 |
| -// but both are generated by the following macro. The code is written according |
12 |
| -// to the following conventions: |
13 |
| -// |
14 |
| -// - introduce a `visit_foo` and a `super_foo` method for every MIR type |
15 |
| -// - `visit_foo`, by default, calls `super_foo` |
16 |
| -// - `super_foo`, by default, destructures the `foo` and calls `visit_foo` |
17 |
| -// |
18 |
| -// This allows you as a user to override `visit_foo` for types are |
19 |
| -// interested in, and invoke (within that method) call |
20 |
| -// `self.super_foo` to get the default behavior. Just as in an OO |
21 |
| -// language, you should never call `super` methods ordinarily except |
22 |
| -// in that circumstance. |
23 |
| -// |
24 |
| -// For the most part, we do not destructure things external to the |
25 |
| -// MIR, e.g., types, spans, etc, but simply visit them and stop. This |
26 |
| -// avoids duplication with other visitors like `TypeFoldable`. |
27 |
| -// |
28 |
| -// ## Updating |
29 |
| -// |
30 |
| -// The code is written in a very deliberate style intended to minimize |
31 |
| -// the chance of things being overlooked. You'll notice that we always |
32 |
| -// use pattern matching to reference fields and we ensure that all |
33 |
| -// matches are exhaustive. |
34 |
| -// |
35 |
| -// For example, the `super_basic_block_data` method begins like this: |
36 |
| -// |
37 |
| -// ```rust |
38 |
| -// fn super_basic_block_data(&mut self, |
39 |
| -// block: BasicBlock, |
40 |
| -// data: & $($mutability)? BasicBlockData<'tcx>) { |
41 |
| -// let BasicBlockData { |
42 |
| -// statements, |
43 |
| -// terminator, |
44 |
| -// is_cleanup: _ |
45 |
| -// } = *data; |
46 |
| -// |
47 |
| -// for statement in statements { |
48 |
| -// self.visit_statement(block, statement); |
49 |
| -// } |
50 |
| -// |
51 |
| -// ... |
52 |
| -// } |
53 |
| -// ``` |
54 |
| -// |
55 |
| -// Here we used `let BasicBlockData { <fields> } = *data` deliberately, |
56 |
| -// rather than writing `data.statements` in the body. This is because if one |
57 |
| -// adds a new field to `BasicBlockData`, one will be forced to revise this code, |
58 |
| -// and hence one will (hopefully) invoke the correct visit methods (if any). |
59 |
| -// |
60 |
| -// For this to work, ALL MATCHES MUST BE EXHAUSTIVE IN FIELDS AND VARIANTS. |
61 |
| -// That means you never write `..` to skip over fields, nor do you write `_` |
62 |
| -// to skip over variants in a `match`. |
63 |
| -// |
64 |
| -// The only place that `_` is acceptable is to match a field (or |
65 |
| -// variant argument) that does not require visiting, as in |
66 |
| -// `is_cleanup` above. |
67 |
| - |
68 | 68 | macro_rules! make_mir_visitor {
|
69 | 69 | ($visitor_trait_name:ident, $($mutability:ident)?) => {
|
70 | 70 | pub trait $visitor_trait_name<'tcx> {
|
|
0 commit comments