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