|
| 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