]> git.proxmox.com Git - rustc.git/blob - src/librustc_mir/hair/mod.rs
New upstream version 1.26.0+dfsg1
[rustc.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 translated 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, Literal, UnOp};
18 use rustc::hir::def_id::DefId;
19 use rustc::middle::region;
20 use rustc::ty::subst::Substs;
21 use rustc::ty::{AdtDef, ClosureSubsts, Region, Ty, GeneratorInterior};
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 translates their expressions (`&'tcx H::Expr`)
111 /// into instances of this `Expr` enum. This translation 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 /// untranslated `&'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 fields: Vec<FieldExprRef<'tcx>>,
265 base: Option<FruInfo<'tcx>>
266 },
267 Closure {
268 closure_id: DefId,
269 substs: ClosureSubsts<'tcx>,
270 upvars: Vec<ExprRef<'tcx>>,
271 interior: Option<GeneratorInterior<'tcx>>,
272 },
273 Literal {
274 literal: Literal<'tcx>,
275 },
276 InlineAsm {
277 asm: &'tcx hir::InlineAsm,
278 outputs: Vec<ExprRef<'tcx>>,
279 inputs: Vec<ExprRef<'tcx>>
280 },
281 Yield {
282 value: ExprRef<'tcx>,
283 },
284 }
285
286 #[derive(Clone, Debug)]
287 pub enum ExprRef<'tcx> {
288 Hair(&'tcx hir::Expr),
289 Mirror(Box<Expr<'tcx>>),
290 }
291
292 #[derive(Clone, Debug)]
293 pub struct FieldExprRef<'tcx> {
294 pub name: Field,
295 pub expr: ExprRef<'tcx>,
296 }
297
298 #[derive(Clone, Debug)]
299 pub struct FruInfo<'tcx> {
300 pub base: ExprRef<'tcx>,
301 pub field_types: Vec<Ty<'tcx>>
302 }
303
304 #[derive(Clone, Debug)]
305 pub struct Arm<'tcx> {
306 pub patterns: Vec<Pattern<'tcx>>,
307 pub guard: Option<ExprRef<'tcx>>,
308 pub body: ExprRef<'tcx>,
309 pub lint_level: LintLevel,
310 }
311
312 #[derive(Copy, Clone, Debug)]
313 pub enum LogicalOp {
314 And,
315 Or,
316 }
317
318 ///////////////////////////////////////////////////////////////////////////
319 // The Mirror trait
320
321 /// "Mirroring" is the process of converting from a HIR type into one
322 /// of the HAIR types defined in this file. This is basically a "on
323 /// the fly" desugaring step that hides a lot of the messiness in the
324 /// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
325 /// `Expr<'tcx>`.
326 ///
327 /// Mirroring is gradual: when you mirror an outer expression like `e1
328 /// + e2`, the references to the inner expressions `e1` and `e2` are
329 /// `ExprRef<'tcx>` instances, and they may or may not be eagerly
330 /// mirrored. This allows a single AST node from the compiler to
331 /// expand into one or more Hair nodes, which lets the Hair nodes be
332 /// simpler.
333 pub trait Mirror<'tcx> {
334 type Output;
335
336 fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Self::Output;
337 }
338
339 impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
340 type Output = Expr<'tcx>;
341
342 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
343 self
344 }
345 }
346
347 impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
348 type Output = Expr<'tcx>;
349
350 fn make_mirror<'a, 'gcx>(self, hir: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
351 match self {
352 ExprRef::Hair(h) => h.make_mirror(hir),
353 ExprRef::Mirror(m) => *m,
354 }
355 }
356 }
357
358 impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
359 type Output = Stmt<'tcx>;
360
361 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> {
362 self
363 }
364 }
365
366 impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
367 type Output = Stmt<'tcx>;
368
369 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> {
370 match self {
371 StmtRef::Mirror(m) => *m,
372 }
373 }
374 }
375
376 impl<'tcx> Mirror<'tcx> for Block<'tcx> {
377 type Output = Block<'tcx>;
378
379 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> {
380 self
381 }
382 }