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.
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.
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
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};
30 pub use self::pattern::{BindingMode, Pattern, PatternKind, FieldPattern};
32 #[derive(Copy, Clone, Debug)]
39 pub fn is_explicit(self) -> bool {
41 LintLevel::Inherited => false,
42 LintLevel::Explicit(_) => true
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>,
53 pub stmts: Vec<StmtRef<'tcx>>,
54 pub expr: Option<ExprRef<'tcx>>,
55 pub safety_mode: BlockSafety,
58 #[derive(Copy, Clone, Debug)]
59 pub enum BlockSafety {
61 ExplicitUnsafe(ast::NodeId),
66 #[derive(Clone, Debug)]
67 pub enum StmtRef<'tcx> {
68 Mirror(Box<Stmt<'tcx>>),
71 #[derive(Clone, Debug)]
72 pub struct Stmt<'tcx> {
73 pub kind: StmtKind<'tcx>,
74 pub opt_destruction_scope: Option<region::Scope>,
77 #[derive(Clone, Debug)]
78 pub enum StmtKind<'tcx> {
80 /// scope for this statement; may be used as lifetime of temporaries
83 /// expression being evaluated in this statement
88 /// scope for variables bound in this let; covers this and
89 /// remaining statements in block
90 remainder_scope: region::Scope,
92 /// scope for the initialization itself; might be used as
93 /// lifetime of temporaries
94 init_scope: region::Scope,
96 /// let <PAT>: ty = ...
97 pattern: Pattern<'tcx>,
99 /// let pat: <TY> = init ...
100 ty: Option<hir::HirId>,
102 /// let pat: ty = <INIT> ...
103 initializer: Option<ExprRef<'tcx>>,
105 /// the lint level for this let-statement
106 lint_level: LintLevel,
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.
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
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>,
133 /// span of the expression in the source
136 /// kind of expression
137 pub kind: ExprKind<'tcx>,
140 #[derive(Clone, Debug)]
141 pub enum ExprKind<'tcx> {
143 region_scope: region::Scope,
144 lint_level: LintLevel,
145 value: ExprRef<'tcx>,
148 value: ExprRef<'tcx>,
153 args: Vec<ExprRef<'tcx>>,
157 }, // NOT overloaded!
162 }, // NOT overloaded!
167 }, // NOT overloaded!
168 // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands.
172 }, // NOT overloaded!
174 source: ExprRef<'tcx>,
177 source: ExprRef<'tcx>,
178 }, // Use a lexpr to get a vexpr.
180 source: ExprRef<'tcx>,
183 source: ExprRef<'tcx>,
186 source: ExprRef<'tcx>,
189 source: ExprRef<'tcx>,
192 source: ExprRef<'tcx>,
195 condition: ExprRef<'tcx>,
197 otherwise: Option<ExprRef<'tcx>>,
200 condition: Option<ExprRef<'tcx>>,
204 discriminant: ExprRef<'tcx>,
205 arms: Vec<Arm<'tcx>>,
208 body: &'tcx hir::Block,
225 index: ExprRef<'tcx>,
230 /// first argument, used for self in a closure
236 region: Region<'tcx>,
237 borrow_kind: BorrowKind,
241 label: region::Scope,
242 value: Option<ExprRef<'tcx>>,
245 label: region::Scope,
248 value: Option<ExprRef<'tcx>>,
251 value: ExprRef<'tcx>,
255 fields: Vec<ExprRef<'tcx>>,
258 fields: Vec<ExprRef<'tcx>>,
261 adt_def: &'tcx AdtDef,
262 variant_index: usize,
263 substs: &'tcx Substs<'tcx>,
265 /// Optional user-given substs: for something like `let x =
266 /// Bar::<T> { ... }`.
267 user_ty: Option<CanonicalTy<'tcx>>,
269 fields: Vec<FieldExprRef<'tcx>>,
270 base: Option<FruInfo<'tcx>>
274 substs: UpvarSubsts<'tcx>,
275 upvars: Vec<ExprRef<'tcx>>,
276 movability: Option<hir::GeneratorMovability>,
279 literal: &'tcx Const<'tcx>,
281 /// Optional user-given type: for something like
282 /// `collect::<Vec<_>>`, this would be present and would
283 /// indicate that `Vec<_>` was explicitly specified.
285 /// Needed for NLL to impose user-given type constraints.
286 user_ty: Option<CanonicalTy<'tcx>>,
289 asm: &'tcx hir::InlineAsm,
290 outputs: Vec<ExprRef<'tcx>>,
291 inputs: Vec<ExprRef<'tcx>>
294 value: ExprRef<'tcx>,
298 #[derive(Clone, Debug)]
299 pub enum ExprRef<'tcx> {
300 Hair(&'tcx hir::Expr),
301 Mirror(Box<Expr<'tcx>>),
304 #[derive(Clone, Debug)]
305 pub struct FieldExprRef<'tcx> {
307 pub expr: ExprRef<'tcx>,
310 #[derive(Clone, Debug)]
311 pub struct FruInfo<'tcx> {
312 pub base: ExprRef<'tcx>,
313 pub field_types: Vec<Ty<'tcx>>
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,
324 #[derive(Clone, Debug)]
325 pub enum Guard<'tcx> {
329 #[derive(Copy, Clone, Debug)]
335 impl<'tcx> ExprRef<'tcx> {
336 pub fn span(&self) -> Span {
338 ExprRef::Hair(expr) => expr.span,
339 ExprRef::Mirror(expr) => expr.span,
344 ///////////////////////////////////////////////////////////////////////////
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
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
359 pub trait Mirror<'tcx> {
362 fn make_mirror<'a, 'gcx>(self, cx: &mut Cx<'a, 'gcx, 'tcx>) -> Self::Output;
365 impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
366 type Output = Expr<'tcx>;
368 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
373 impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
374 type Output = Expr<'tcx>;
376 fn make_mirror<'a, 'gcx>(self, hir: &mut Cx<'a, 'gcx, 'tcx>) -> Expr<'tcx> {
378 ExprRef::Hair(h) => h.make_mirror(hir),
379 ExprRef::Mirror(m) => *m,
384 impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
385 type Output = Stmt<'tcx>;
387 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> {
392 impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
393 type Output = Stmt<'tcx>;
395 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Stmt<'tcx> {
397 StmtRef::Mirror(m) => *m,
402 impl<'tcx> Mirror<'tcx> for Block<'tcx> {
403 type Output = Block<'tcx>;
405 fn make_mirror<'a, 'gcx>(self, _: &mut Cx<'a, 'gcx, 'tcx>) -> Block<'tcx> {