//! The MIR is built from some typed high-level IR //! (THIR). This section defines the THIR along with a trait for //! accessing it. The intention is to allow MIR construction to be //! unit-tested and separated from the Rust source and compiler data //! structures. use self::cx::Cx; use rustc_ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_hir as hir; use rustc_hir::def_id::DefId; use rustc_middle::infer::canonical::Canonical; use rustc_middle::middle::region; use rustc_middle::mir::{BinOp, BorrowKind, Field, UnOp}; use rustc_middle::ty::adjustment::PointerCast; use rustc_middle::ty::subst::SubstsRef; use rustc_middle::ty::{AdtDef, Const, Ty, UpvarSubsts, UserType}; use rustc_span::Span; use rustc_target::abi::VariantIdx; use rustc_target::asm::InlineAsmRegOrRegClass; crate mod constant; crate mod cx; crate mod pattern; crate use self::pattern::PatTyProj; crate use self::pattern::{BindingMode, FieldPat, Pat, PatKind, PatRange}; mod util; #[derive(Copy, Clone, Debug)] crate enum LintLevel { Inherited, Explicit(hir::HirId), } #[derive(Clone, Debug)] crate struct Block<'tcx> { crate targeted_by_break: bool, crate region_scope: region::Scope, crate opt_destruction_scope: Option, crate span: Span, crate stmts: Vec>, crate expr: Option>, crate safety_mode: BlockSafety, } #[derive(Copy, Clone, Debug)] crate enum BlockSafety { Safe, ExplicitUnsafe(hir::HirId), PushUnsafe, PopUnsafe, } #[derive(Clone, Debug)] crate enum StmtRef<'tcx> { Mirror(Box>), } #[derive(Clone, Debug)] crate struct Stmt<'tcx> { crate kind: StmtKind<'tcx>, crate opt_destruction_scope: Option, } #[derive(Clone, Debug)] crate enum StmtKind<'tcx> { Expr { /// scope for this statement; may be used as lifetime of temporaries scope: region::Scope, /// expression being evaluated in this statement expr: ExprRef<'tcx>, }, Let { /// scope for variables bound in this let; covers this and /// remaining statements in block remainder_scope: region::Scope, /// scope for the initialization itself; might be used as /// lifetime of temporaries init_scope: region::Scope, /// `let = ...` /// /// if a type is included, it is added as an ascription pattern pattern: Pat<'tcx>, /// let pat: ty = ... initializer: Option>, /// the lint level for this let-statement lint_level: LintLevel, }, } // `Expr` is used a lot. Make sure it doesn't unintentionally get bigger. #[cfg(target_arch = "x86_64")] rustc_data_structures::static_assert_size!(Expr<'_>, 168); /// The Thir trait implementor lowers their expressions (`&'tcx H::Expr`) /// into instances of this `Expr` enum. This lowering can be done /// basically as lazily or as eagerly as desired: every recursive /// reference to an expression in this enum is an `ExprRef<'tcx>`, which /// may in turn be another instance of this enum (boxed), or else an /// unlowered `&'tcx H::Expr`. Note that instances of `Expr` are very /// short-lived. They are created by `Thir::to_expr`, analyzed and /// converted into MIR, and then discarded. /// /// If you compare `Expr` to the full compiler AST, you will see it is /// a good bit simpler. In fact, a number of the more straight-forward /// MIR simplifications are already done in the impl of `Thir`. For /// example, method calls and overloaded operators are absent: they are /// expected to be converted into `Expr::Call` instances. #[derive(Clone, Debug)] crate struct Expr<'tcx> { /// type of this expression crate ty: Ty<'tcx>, /// lifetime of this expression if it should be spilled into a /// temporary; should be None only if in a constant context crate temp_lifetime: Option, /// span of the expression in the source crate span: Span, /// kind of expression crate kind: ExprKind<'tcx>, } #[derive(Clone, Debug)] crate enum ExprKind<'tcx> { Scope { region_scope: region::Scope, lint_level: LintLevel, value: ExprRef<'tcx>, }, Box { value: ExprRef<'tcx>, }, Call { ty: Ty<'tcx>, fun: ExprRef<'tcx>, args: Vec>, // Whether this is from a call in HIR, rather than from an overloaded // operator. True for overloaded function call. from_hir_call: bool, /// This `Span` is the span of the function, without the dot and receiver /// (e.g. `foo(a, b)` in `x.foo(a, b)` fn_span: Span, }, Deref { arg: ExprRef<'tcx>, }, // NOT overloaded! Binary { op: BinOp, lhs: ExprRef<'tcx>, rhs: ExprRef<'tcx>, }, // NOT overloaded! LogicalOp { op: LogicalOp, lhs: ExprRef<'tcx>, rhs: ExprRef<'tcx>, }, // NOT overloaded! // LogicalOp is distinct from BinaryOp because of lazy evaluation of the operands. Unary { op: UnOp, arg: ExprRef<'tcx>, }, // NOT overloaded! Cast { source: ExprRef<'tcx>, }, Use { source: ExprRef<'tcx>, }, // Use a lexpr to get a vexpr. NeverToAny { source: ExprRef<'tcx>, }, Pointer { cast: PointerCast, source: ExprRef<'tcx>, }, Loop { body: ExprRef<'tcx>, }, Match { scrutinee: ExprRef<'tcx>, arms: Vec>, }, Block { body: &'tcx hir::Block<'tcx>, }, Assign { lhs: ExprRef<'tcx>, rhs: ExprRef<'tcx>, }, AssignOp { op: BinOp, lhs: ExprRef<'tcx>, rhs: ExprRef<'tcx>, }, Field { lhs: ExprRef<'tcx>, name: Field, }, Index { lhs: ExprRef<'tcx>, index: ExprRef<'tcx>, }, VarRef { id: hir::HirId, }, /// first argument, used for self in a closure SelfRef, Borrow { borrow_kind: BorrowKind, arg: ExprRef<'tcx>, }, /// A `&raw [const|mut] $place_expr` raw borrow resulting in type `*[const|mut] T`. AddressOf { mutability: hir::Mutability, arg: ExprRef<'tcx>, }, Break { label: region::Scope, value: Option>, }, Continue { label: region::Scope, }, Return { value: Option>, }, ConstBlock { value: &'tcx Const<'tcx>, }, Repeat { value: ExprRef<'tcx>, count: &'tcx Const<'tcx>, }, Array { fields: Vec>, }, Tuple { fields: Vec>, }, Adt { adt_def: &'tcx AdtDef, variant_index: VariantIdx, substs: SubstsRef<'tcx>, /// Optional user-given substs: for something like `let x = /// Bar:: { ... }`. user_ty: Option>>, fields: Vec>, base: Option>, }, PlaceTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression user_ty: Option>>, }, ValueTypeAscription { source: ExprRef<'tcx>, /// Type that the user gave to this expression user_ty: Option>>, }, Closure { closure_id: DefId, substs: UpvarSubsts<'tcx>, upvars: Vec>, movability: Option, }, Literal { literal: &'tcx Const<'tcx>, user_ty: Option>>, /// The `DefId` of the `const` item this literal /// was produced from, if this is not a user-written /// literal value. const_id: Option, }, /// A literal containing the address of a `static`. /// /// This is only distinguished from `Literal` so that we can register some /// info for diagnostics. StaticRef { literal: &'tcx Const<'tcx>, def_id: DefId, }, InlineAsm { template: &'tcx [InlineAsmTemplatePiece], operands: Vec>, options: InlineAsmOptions, line_spans: &'tcx [Span], }, /// An expression taking a reference to a thread local. ThreadLocalRef(DefId), LlvmInlineAsm { asm: &'tcx hir::LlvmInlineAsmInner, outputs: Vec>, inputs: Vec>, }, Yield { value: ExprRef<'tcx>, }, } #[derive(Clone, Debug)] crate enum ExprRef<'tcx> { Thir(&'tcx hir::Expr<'tcx>), Mirror(Box>), } #[derive(Clone, Debug)] crate struct FieldExprRef<'tcx> { crate name: Field, crate expr: ExprRef<'tcx>, } #[derive(Clone, Debug)] crate struct FruInfo<'tcx> { crate base: ExprRef<'tcx>, crate field_types: Vec>, } #[derive(Clone, Debug)] crate struct Arm<'tcx> { crate pattern: Pat<'tcx>, crate guard: Option>, crate body: ExprRef<'tcx>, crate lint_level: LintLevel, crate scope: region::Scope, crate span: Span, } #[derive(Clone, Debug)] crate enum Guard<'tcx> { If(ExprRef<'tcx>), } #[derive(Copy, Clone, Debug)] crate enum LogicalOp { And, Or, } impl<'tcx> ExprRef<'tcx> { crate fn span(&self) -> Span { match self { ExprRef::Thir(expr) => expr.span, ExprRef::Mirror(expr) => expr.span, } } } #[derive(Clone, Debug)] crate enum InlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, expr: ExprRef<'tcx>, }, Out { reg: InlineAsmRegOrRegClass, late: bool, expr: Option>, }, InOut { reg: InlineAsmRegOrRegClass, late: bool, expr: ExprRef<'tcx>, }, SplitInOut { reg: InlineAsmRegOrRegClass, late: bool, in_expr: ExprRef<'tcx>, out_expr: Option>, }, Const { expr: ExprRef<'tcx>, }, SymFn { expr: ExprRef<'tcx>, }, SymStatic { def_id: DefId, }, } /////////////////////////////////////////////////////////////////////////// // The Mirror trait /// "Mirroring" is the process of converting from a HIR type into one /// of the THIR types defined in this file. This is basically a "on /// the fly" desugaring step that hides a lot of the messiness in the /// tcx. For example, the mirror of a `&'tcx hir::Expr` is an /// `Expr<'tcx>`. /// /// Mirroring is gradual: when you mirror an outer expression like `e1 /// + e2`, the references to the inner expressions `e1` and `e2` are /// `ExprRef<'tcx>` instances, and they may or may not be eagerly /// mirrored. This allows a single AST node from the compiler to /// expand into one or more Thir nodes, which lets the Thir nodes be /// simpler. crate trait Mirror<'tcx> { type Output; fn make_mirror(self, cx: &mut Cx<'_, 'tcx>) -> Self::Output; } impl<'tcx> Mirror<'tcx> for Expr<'tcx> { type Output = Expr<'tcx>; fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Expr<'tcx> { self } } impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> { type Output = Expr<'tcx>; fn make_mirror(self, hir: &mut Cx<'_, 'tcx>) -> Expr<'tcx> { match self { ExprRef::Thir(h) => h.make_mirror(hir), ExprRef::Mirror(m) => *m, } } } impl<'tcx> Mirror<'tcx> for Stmt<'tcx> { type Output = Stmt<'tcx>; fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> { self } } impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> { type Output = Stmt<'tcx>; fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Stmt<'tcx> { match self { StmtRef::Mirror(m) => *m, } } } impl<'tcx> Mirror<'tcx> for Block<'tcx> { type Output = Block<'tcx>; fn make_mirror(self, _: &mut Cx<'_, 'tcx>) -> Block<'tcx> { self } }