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