]> git.lizzy.rs Git - rust.git/blob - src/librustc_mir/hair/mod.rs
Rollup merge of #61785 - RalfJung:as-ref, r=rkruppe
[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 rustc::mir::{BinOp, BorrowKind, Field, UnOp};
8 use rustc::hir::def_id::DefId;
9 use rustc::infer::canonical::Canonical;
10 use rustc::middle::region;
11 use rustc::ty::subst::SubstsRef;
12 use rustc::ty::{AdtDef, UpvarSubsts, Ty, Const, UserType};
13 use rustc::ty::adjustment::{PointerCast};
14 use rustc::ty::layout::VariantIdx;
15 use rustc::hir;
16 use syntax_pos::Span;
17 use self::cx::Cx;
18
19 pub mod cx;
20 mod constant;
21
22 pub mod pattern;
23 pub use self::pattern::{BindingMode, Pattern, PatternKind, PatternRange, FieldPattern};
24 pub(crate) use self::pattern::PatternTypeProjection;
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 StatementSpan(pub Span);
60
61 #[derive(Clone, Debug)]
62 pub struct Stmt<'tcx> {
63     pub kind: StmtKind<'tcx>,
64     pub opt_destruction_scope: Option<region::Scope>,
65     pub span: StatementSpan,
66 }
67
68 #[derive(Clone, Debug)]
69 pub enum StmtKind<'tcx> {
70     Expr {
71         /// scope for this statement; may be used as lifetime of temporaries
72         scope: region::Scope,
73
74         /// expression being evaluated in this statement
75         expr: ExprRef<'tcx>,
76     },
77
78     Let {
79         /// scope for variables bound in this let; covers this and
80         /// remaining statements in block
81         remainder_scope: region::Scope,
82
83         /// scope for the initialization itself; might be used as
84         /// lifetime of temporaries
85         init_scope: region::Scope,
86
87         /// `let <PAT> = ...`
88         ///
89         /// if a type is included, it is added as an ascription pattern
90         pattern: Pattern<'tcx>,
91
92         /// let pat: ty = <INIT> ...
93         initializer: Option<ExprRef<'tcx>>,
94
95         /// the lint level for this let-statement
96         lint_level: LintLevel,
97     },
98 }
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         condition: Option<ExprRef<'tcx>>,
181         body: ExprRef<'tcx>,
182     },
183     Match {
184         scrutinee: ExprRef<'tcx>,
185         arms: Vec<Arm<'tcx>>,
186     },
187     Block {
188         body: &'tcx hir::Block,
189     },
190     Assign {
191         lhs: ExprRef<'tcx>,
192         rhs: ExprRef<'tcx>,
193     },
194     AssignOp {
195         op: BinOp,
196         lhs: ExprRef<'tcx>,
197         rhs: ExprRef<'tcx>,
198     },
199     Field {
200         lhs: ExprRef<'tcx>,
201         name: Field,
202     },
203     Index {
204         lhs: ExprRef<'tcx>,
205         index: ExprRef<'tcx>,
206     },
207     VarRef {
208         id: hir::HirId,
209     },
210     /// first argument, used for self in a closure
211     SelfRef,
212     StaticRef {
213         id: DefId,
214     },
215     Borrow {
216         borrow_kind: BorrowKind,
217         arg: ExprRef<'tcx>,
218     },
219     Break {
220         label: region::Scope,
221         value: Option<ExprRef<'tcx>>,
222     },
223     Continue {
224         label: region::Scope,
225     },
226     Return {
227         value: Option<ExprRef<'tcx>>,
228     },
229     Repeat {
230         value: ExprRef<'tcx>,
231         count: u64,
232     },
233     Array {
234         fields: Vec<ExprRef<'tcx>>,
235     },
236     Tuple {
237         fields: Vec<ExprRef<'tcx>>,
238     },
239     Adt {
240         adt_def: &'tcx AdtDef,
241         variant_index: VariantIdx,
242         substs: SubstsRef<'tcx>,
243
244         /// Optional user-given substs: for something like `let x =
245         /// Bar::<T> { ... }`.
246         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
247
248         fields: Vec<FieldExprRef<'tcx>>,
249         base: Option<FruInfo<'tcx>>
250     },
251     PlaceTypeAscription {
252         source: ExprRef<'tcx>,
253         /// Type that the user gave to this expression
254         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
255     },
256     ValueTypeAscription {
257         source: ExprRef<'tcx>,
258         /// Type that the user gave to this expression
259         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
260     },
261     Closure {
262         closure_id: DefId,
263         substs: UpvarSubsts<'tcx>,
264         upvars: Vec<ExprRef<'tcx>>,
265         movability: Option<hir::GeneratorMovability>,
266     },
267     Literal {
268         literal: &'tcx Const<'tcx>,
269         user_ty: Option<Canonical<'tcx, UserType<'tcx>>>,
270     },
271     InlineAsm {
272         asm: &'tcx hir::InlineAsm,
273         outputs: Vec<ExprRef<'tcx>>,
274         inputs: Vec<ExprRef<'tcx>>
275     },
276     Yield {
277         value: ExprRef<'tcx>,
278     },
279 }
280
281 #[derive(Clone, Debug)]
282 pub enum ExprRef<'tcx> {
283     Hair(&'tcx hir::Expr),
284     Mirror(Box<Expr<'tcx>>),
285 }
286
287 #[derive(Clone, Debug)]
288 pub struct FieldExprRef<'tcx> {
289     pub name: Field,
290     pub expr: ExprRef<'tcx>,
291 }
292
293 #[derive(Clone, Debug)]
294 pub struct FruInfo<'tcx> {
295     pub base: ExprRef<'tcx>,
296     pub field_types: Vec<Ty<'tcx>>
297 }
298
299 #[derive(Clone, Debug)]
300 pub struct Arm<'tcx> {
301     pub patterns: Vec<Pattern<'tcx>>,
302     pub guard: Option<Guard<'tcx>>,
303     pub body: ExprRef<'tcx>,
304     pub lint_level: LintLevel,
305     pub scope: region::Scope,
306     pub span: Span,
307 }
308
309 #[derive(Clone, Debug)]
310 pub enum Guard<'tcx> {
311     If(ExprRef<'tcx>),
312 }
313
314 #[derive(Copy, Clone, Debug)]
315 pub enum LogicalOp {
316     And,
317     Or,
318 }
319
320 impl<'tcx> ExprRef<'tcx> {
321     pub fn span(&self) -> Span {
322         match self {
323             ExprRef::Hair(expr) => expr.span,
324             ExprRef::Mirror(expr) => expr.span,
325         }
326     }
327 }
328
329 ///////////////////////////////////////////////////////////////////////////
330 // The Mirror trait
331
332 /// "Mirroring" is the process of converting from a HIR type into one
333 /// of the HAIR types defined in this file. This is basically a "on
334 /// the fly" desugaring step that hides a lot of the messiness in the
335 /// tcx. For example, the mirror of a `&'tcx hir::Expr` is an
336 /// `Expr<'tcx>`.
337 ///
338 /// Mirroring is gradual: when you mirror an outer expression like `e1
339 /// + e2`, the references to the inner expressions `e1` and `e2` are
340 /// `ExprRef<'tcx>` instances, and they may or may not be eagerly
341 /// mirrored. This allows a single AST node from the compiler to
342 /// expand into one or more Hair nodes, which lets the Hair nodes be
343 /// simpler.
344 pub trait Mirror<'tcx> {
345     type Output;
346
347     fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output;
348 }
349
350 impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
351     type Output = Expr<'tcx>;
352
353     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> {
354         self
355     }
356 }
357
358 impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
359     type Output = Expr<'tcx>;
360
361     fn make_mirror(self, hir: &mut Cx<'a, 'tcx>) -> Expr<'tcx> {
362         match self {
363             ExprRef::Hair(h) => h.make_mirror(hir),
364             ExprRef::Mirror(m) => *m,
365         }
366     }
367 }
368
369 impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
370     type Output = Stmt<'tcx>;
371
372     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
373         self
374     }
375 }
376
377 impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
378     type Output = Stmt<'tcx>;
379
380     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> {
381         match self {
382             StmtRef::Mirror(m) => *m,
383         }
384     }
385 }
386
387 impl<'tcx> Mirror<'tcx> for Block<'tcx> {
388     type Output = Block<'tcx>;
389
390     fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> {
391         self
392     }
393 }