]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/hair/mod.rs
188c73e105a49997fda863036945658085e92262
[rust.git] / src / librustc_mir / hair / mod.rs
1 //! The MIR is built from some high-level abstract IR
2 //! (HAIR). This section defines the HAIR along with a trait for
3 //! accessing it. The intention is to allow MIR construction to be
4 //! unit-tested and separated from the Rust source and compiler data
5 //! structures.
6
7 use self::cx::Cx;
8 use rustc::hir;
9 use rustc::hir::def_id::DefId;
10 use rustc::infer::canonical::Canonical;
11 use rustc::middle::region;
12 use rustc::mir::{BinOp, BorrowKind, Field, UnOp};
13 use rustc::ty::adjustment::PointerCast;
14 use rustc::ty::layout::VariantIdx;
15 use rustc::ty::subst::SubstsRef;
16 use rustc::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType};
17 use syntax_pos::Span;
18
19 mod constant;
20 pub mod cx;
21
22 pub mod pattern;
23 pub(crate) use self::pattern::PatTyProj;
24 pub use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange};
25
26 mod util;
27
28 #[derive(Copy, Clone, Debug)]
29 pub enum LintLevel {
30     Inherited,
31     Explicit(hir::HirId),
32 }
33
34 #[derive(Clone, Debug)]
35 pub struct Block<'tcx> {
36     pub targeted_by_break: bool,
37     pub region_scope: region::Scope,
38     pub opt_destruction_scope: Option<region::Scope>,
39     pub span: Span,
40     pub stmts: Vec<StmtRef<'tcx>>,
41     pub expr: Option<ExprRef<'tcx>>,
42     pub safety_mode: BlockSafety,
43 }
44
45 #[derive(Copy, Clone, Debug)]
46 pub enum BlockSafety {
47     Safe,
48     ExplicitUnsafe(hir::HirId),
49     PushUnsafe,
50     PopUnsafe,
51 }
52
53 #[derive(Clone, Debug)]
54 pub enum StmtRef<'tcx> {
55     Mirror(Box<Stmt<'tcx>>),
56 }
57
58 #[derive(Clone, Debug)]
59 pub struct Stmt<'tcx> {
60     pub kind: StmtKind<'tcx>,
61     pub opt_destruction_scope: Option<region::Scope>,
62 }
63
64 #[derive(Clone, Debug)]
65 pub enum StmtKind<'tcx> {
66     Expr {
67         /// scope for this statement; may be used as lifetime of temporaries
68         scope: region::Scope,
69
70         /// expression being evaluated in this statement
71         expr: ExprRef<'tcx>,
72     },
73
74     Let {
75         /// scope for variables bound in this let; covers this and
76         /// remaining statements in block
77         remainder_scope: region::Scope,
78
79         /// scope for the initialization itself; might be used as
80         /// lifetime of temporaries
81         init_scope: region::Scope,
82
83         /// `let <PAT> = ...`
84         ///
85         /// if a type is included, it is added as an ascription pattern
86         pattern: Pat<'tcx>,
87
88         /// let pat: ty = <INIT> ...
89         initializer: Option<ExprRef<'tcx>>,
90
91         /// the lint level for this let-statement
92         lint_level: LintLevel,
93     },
94 }
95
96 // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger.
97 #[cfg(target_arch = "x86_64")]
98 rustc_data_structures::static_assert_size!(Expr<'_>, 168);
99
100 /// The Hair trait implementor lowers their expressions (`&'tcx H::Expr`)
101 /// into instances of this `Expr` enum. This lowering can be done
102 /// basically as lazily or as eagerly as desired: every recursive
103 /// reference to an expression in this enum is an `ExprRef<'tcx>`, which
104 /// may in turn be another instance of this enum (boxed), or else an
105 /// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very
106 /// short-lived. They are created by `Hair::to_expr`, analyzed and
107 /// converted into MIR, and then discarded.
108 ///
109 /// If you compare `Expr` to the full compiler AST, you will see it is
110 /// a good bit simpler. In fact, a number of the more straight-forward
111 /// MIR simplifications are already done in the impl of `Hair`. For
112 /// example, method calls and overloaded operators are absent: they are
113 /// expected to be converted into `Expr::Call` instances.
114 #[derive(Clone, Debug)]
115 pub struct Expr<'tcx> {
116     /// type of this expression
117     pub ty: Ty<'tcx>,
118
119     /// lifetime of this expression if it should be spilled into a
120     /// temporary; should be None only if in a constant context
121     pub temp_lifetime: Option<region::Scope>,
122
123     /// span of the expression in the source
124     pub span: Span,
125
126     /// kind of expression
127     pub kind: ExprKind<'tcx>,
128 }
129
130 #[derive(Clone, Debug)]
131 pub enum ExprKind<'tcx> {
132     Scope {
133         region_scope: region::Scope,
134         lint_level: LintLevel,
135         value: ExprRef<'tcx>,
136     },
137     Box {
138         value: ExprRef<'tcx>,
139     },
140     Call {
141         ty: Ty<'tcx>,
142         fun: ExprRef<'tcx>,
143         args: Vec<ExprRef<'tcx>>,
144         // Whether this is from a call in HIR, rather than from an overloaded
145         // operator. True for overloaded function call.
146         from_hir_call: bool,
147     },
148     Deref {
149         arg: ExprRef<'tcx>,
150     }, // NOT overloaded!
151     Binary {
152         op: BinOp,
153         lhs: ExprRef<'tcx>,
154         rhs: ExprRef<'tcx>,
155     }, // NOT overloaded!
156     LogicalOp {
157         op: LogicalOp,
158         lhs: ExprRef<'tcx>,
159         rhs: ExprRef<'tcx>,
160     }, // NOT overloaded!
161     // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
162     Unary {
163         op: UnOp,
164         arg: ExprRef<'tcx>,
165     }, // NOT overloaded!
166     Cast {
167         source: ExprRef<'tcx>,
168     },
169     Use {
170         source: ExprRef<'tcx>,
171     }, // Use a lexpr to get a vexpr.
172     NeverToAny {
173         source: ExprRef<'tcx>,
174     },
175     Pointer {
176         cast: PointerCast,
177         source: ExprRef<'tcx>,
178     },
179     Loop {
180         body: ExprRef<'tcx>,
181     },
182     Match {
183         scrutinee: ExprRef<'tcx>,
184         arms: Vec<Arm<'tcx>>,
185     },
186     Block {
187         body: &'tcx hir::Block,
188     },
189     Assign {
190         lhs: ExprRef<'tcx>,
191         rhs: ExprRef<'tcx>,
192     },
193     AssignOp {
194         op: BinOp,
195         lhs: ExprRef<'tcx>,
196         rhs: ExprRef<'tcx>,
197     },
198     Field {
199         lhs: ExprRef<'tcx>,
200         name: Field,
201     },
202     Index {
203         lhs: ExprRef<'tcx>,
204         index: ExprRef<'tcx>,
205     },
206     VarRef {
207         id: hir::HirId,
208     },
209     /// first argument, used for self in a closure
210     SelfRef,
211     Borrow {
212         borrow_kind: BorrowKind,
213         arg: ExprRef<'tcx>,
214     },
215     /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`.
216     AddressOf {
217         mutability: hir::Mutability,
218         arg: ExprRef<'tcx>,
219     },
220     Break {
221         label: region::Scope,
222         value: Option<ExprRef<'tcx>>,
223     },
224     Continue {
225         label: region::Scope,
226     },
227     Return {
228         value: Option<ExprRef<'tcx>>,
229     },
230     Repeat {
231         value: ExprRef<'tcx>,
232         count: u64,
233     },
234     Array {
235         fields: Vec<ExprRef<'tcx>>,
236     },
237     Tuple {
238         fields: Vec<ExprRef<'tcx>>,
239     },
240     Adt {
241         adt_def: &'tcx AdtDef,
242         variant_index: VariantIdx,
243         substs: SubstsRef<'tcx>,
244
245         /// Optional user-given substs: for something like `let x =
246         /// Bar::<T> { ... }`.
247         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
248
249         fields: Vec<FieldExprRef<'tcx>>,
250         base: Option<FruInfo<'tcx>>,
251     },
252     PlaceTypeAscription {
253         source: ExprRef<'tcx>,
254         /// Type that the user gave to this expression
255         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
256     },
257     ValueTypeAscription {
258         source: ExprRef<'tcx>,
259         /// Type that the user gave to this expression
260         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
261     },
262     Closure {
263         closure_id: DefId,
264         substs: UpvarSubsts<'tcx>,
265         upvars: Vec<ExprRef<'tcx>>,
266         movability: Option<hir::Movability>,
267     },
268     Literal {
269         literal: &'tcx Const<'tcx>,
270         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
271     },
272     /// A literal containing the address of a `static`.
273     ///
274     /// This is only distinguished from `Literal` so that we can register some
275     /// info for diagnostics.
276     StaticRef {
277         literal: &'tcx Const<'tcx>,
278         def_id: DefId,
279     },
280     InlineAsm {
281         asm: &'tcx hir::InlineAsmInner,
282         outputs: Vec<ExprRef<'tcx>>,
283         inputs: Vec<ExprRef<'tcx>>,
284     },
285     Yield {
286         value: ExprRef<'tcx>,
287     },
288 }
289
290 #[derive(Clone, Debug)]
291 pub enum ExprRef<'tcx> {
292     Hair(&'tcx hir::Expr),
293     Mirror(Box<Expr<'tcx>>),
294 }
295
296 #[derive(Clone, Debug)]
297 pub struct FieldExprRef<'tcx> {
298     pub name: Field,
299     pub expr: ExprRef<'tcx>,
300 }
301
302 #[derive(Clone, Debug)]
303 pub struct FruInfo<'tcx> {
304     pub base: ExprRef<'tcx>,
305     pub field_types: Vec<Ty<'tcx>>,
306 }
307
308 #[derive(Clone, Debug)]
309 pub struct Arm<'tcx> {
310     pub pattern: Pat<'tcx>,
311     pub guard: Option<Guard<'tcx>>,
312     pub body: ExprRef<'tcx>,
313     pub lint_level: LintLevel,
314     pub scope: region::Scope,
315     pub span: Span,
316 }
317
318 impl Arm<'tcx> {
319     // HACK(or_patterns; Centril | dlrobertson): Remove this and
320     // correctly handle each case in which this method is used.
321     pub fn top_pats_hack(&self) -> &[Pat<'tcx>] {
322         match &*self.pattern.kind {
323             PatKind::Or { pats } => pats,
324             _ => std::slice::from_ref(&self.pattern),
325         }
326     }
327 }
328
329 #[derive(Clone, Debug)]
330 pub enum Guard<'tcx> {
331     If(ExprRef<'tcx>),
332 }
333
334 #[derive(Copy, Clone, Debug)]
335 pub enum LogicalOp {
336     And,
337     Or,
338 }
339
340 impl<'tcx> ExprRef<'tcx> {
341     pub fn span(&self) -> Span {
342         match self {
343             ExprRef::Hair(expr) => expr.span,
344             ExprRef::Mirror(expr) => expr.span,
345         }
346     }
347 }
348
349 ///////////////////////////////////////////////////////////////////////////
350 // The Mirror trait
351
352 /// "Mirroring" is the process of converting from a HIR type into one
353 /// of the HAIR types defined in this file. This is basically a "on
354 /// the fly" desugaring step that hides a lot of the messiness in the
355 /// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
356 /// `Expr<'tcx>`.
357 ///
358 /// Mirroring is gradual: when you mirror an outer expression like `e1
359 /// + e2`, the references to the inner expressions `e1` and `e2` are
360 /// `ExprRef<'tcx>` instances, and they may or may not be eagerly
361 /// mirrored. This allows a single AST node from the compiler to
362 /// expand into one or more Hair nodes, which lets the Hair nodes be
363 /// simpler.
364 pub trait Mirror<'tcx> {
365     type Output;
366
367     fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
368 }
369
370 impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
371     type Output = Expr<'tcx>;
372
373     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
374         self
375     }
376 }
377
378 impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
379     type Output = Expr<'tcx>;
380
381     fn make_mirror(self, hir: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
382         match self {
383             ExprRef::Hair(h) => h.make_mirror(hir),
384             ExprRef::Mirror(m) => *m,
385         }
386     }
387 }
388
389 impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
390     type Output = Stmt<'tcx>;
391
392     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
393         self
394     }
395 }
396
397 impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
398     type Output = Stmt<'tcx>;
399
400     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
401         match self {
402             StmtRef::Mirror(m) => *m,
403         }
404     }
405 }
406
407 impl<'tcx> Mirror<'tcx> for Block<'tcx> {
408     type Output = Block<'tcx>;
409
410     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
411         self
412     }
413 }