// Copyright 2015 The Rust Project Developers. See the COPYRIGHT // file at the top-level directory of this distribution and at // http://rust-lang.org/COPYRIGHT. // // Licensed under the Apache License, Version 2.0 or the MIT license // , at your // option. This file may not be copied, modified, or distributed // except according to those terms. //! The MIR is translated from some high-level abstract IR //! (HAIR). This section defines the HAIR 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 repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp}; use std::fmt::Debug; use std::hash::Hash; pub trait Hair: Sized+Debug+Clone+Eq+Hash { // (*) // (*) the `Sized` and Debug` bounds are the only ones that really // make sense. The rest are just there so that we can // `#[derive(Clone)]` on things that are parameterized over // `H:HAIR`. It's kind of lame. type VarId: Copy+Debug+Eq+Hash; // e.g., NodeId for a variable type DefId: Copy+Debug+Eq+Hash; // e.g., DefId type AdtDef: Copy+Debug+Eq+Hash; // e.g., AdtDef<'tcx> type Name: Copy+Debug+Eq+Hash; // e.g., ast::Name type Ident: Copy+Debug+Eq+Hash; // e.g., ast::Ident type InternedString: Clone+Debug+Eq+Hash; // e.g., InternedString type Bytes: Clone+Debug+Eq+Hash; // e.g., Rc> type Span: Copy+Debug+Eq; // e.g., syntax::codemap::Span type Projection: Clone+Debug+Eq; // e.g., ty::ProjectionTy<'tcx> type Substs: Clone+Debug+Eq; // e.g., substs::Substs<'tcx> type ClosureSubsts: Clone+Debug+Eq; // e.g., ty::ClosureSubsts<'tcx> type Ty: Clone+Debug+Eq; // e.g., ty::Ty<'tcx> type Region: Copy+Debug; // e.g., ty::Region type CodeExtent: Copy+Debug+Hash+Eq; // e.g., region::CodeExtent type Pattern: Clone+Debug+Mirror>; // e.g., &P type Expr: Clone+Debug+Mirror>; // e.g., &P type Stmt: Clone+Debug+Mirror>; // e.g., &P type Block: Clone+Debug+Mirror>; // e.g., &P type InlineAsm: Clone+Debug+Eq+Hash; // e.g., ast::InlineAsm /// Normalizes `ast` into the appropriate `mirror` type. fn mirror>(&mut self, ast: M) -> M::Output { ast.make_mirror(self) } /// Returns the unit type `()` fn unit_ty(&mut self) -> Self::Ty; /// Returns the type `usize`. fn usize_ty(&mut self) -> Self::Ty; /// Returns the type `bool`. fn bool_ty(&mut self) -> Self::Ty; /// Returns a reference to `PartialEq::::eq` fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef; /// Returns a reference to `PartialOrd::::le` fn partial_le(&mut self, ty: Self::Ty) -> ItemRef; /// Returns the number of variants for the given enum fn num_variants(&mut self, adt: Self::AdtDef) -> usize; fn fields(&mut self, adt: Self::AdtDef, variant_index: usize) -> Vec>; /// true if a value of type `ty` (may) need to be dropped; this /// may return false even for non-Copy types if there is no /// destructor to execute. If correct result is not known, may be /// approximated by returning `true`; this will result in more /// drops but not incorrect code. fn needs_drop(&mut self, ty: Self::Ty, span: Self::Span) -> bool; /// Report an internal inconsistency. fn span_bug(&mut self, span: Self::Span, message: &str) -> !; } #[derive(Clone, Debug)] pub struct ItemRef { pub ty: H::Ty, pub def_id: H::DefId, pub substs: H::Substs, } #[derive(Clone, Debug)] pub struct Block { pub extent: H::CodeExtent, pub span: H::Span, pub stmts: Vec>, pub expr: Option>, } #[derive(Clone, Debug)] pub enum StmtRef { Hair(H::Stmt), Mirror(Box>), } #[derive(Clone, Debug)] pub struct Stmt { pub span: H::Span, pub kind: StmtKind, } #[derive(Clone, Debug)] pub enum StmtKind { Expr { /// scope for this statement; may be used as lifetime of temporaries scope: H::CodeExtent, /// expression being evaluated in this statement expr: ExprRef }, Let { /// scope for variables bound in this let; covers this and /// remaining statements in block remainder_scope: H::CodeExtent, /// scope for the initialization itself; might be used as /// lifetime of temporaries init_scope: H::CodeExtent, /// let = ... pattern: PatternRef, /// let pat = ... initializer: Option>, /// let pat = init; stmts: Vec> }, } // The Hair trait implementor translates their expressions (`H::Expr`) // into instances of this `Expr` enum. This translation can be done // basically as lazilly or as eagerly as desired: every recursive // reference to an expression in this enum is an `ExprRef`, which // may in turn be another instance of this enum (boxed), or else an // untranslated `H::Expr`. Note that instances of `Expr` are very // shortlived. They are created by `Hair::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 `Hair`. For // example, method calls and overloaded operators are absent: they are // expected to be converted into `Expr::Call` instances. #[derive(Clone, Debug)] pub struct Expr { // type of this expression pub ty: H::Ty, // lifetime of this expression if it should be spilled into a // temporary; should be None only if in a constant context pub temp_lifetime: Option, // span of the expression in the source pub span: H::Span, // kind of expression pub kind: ExprKind, } #[derive(Clone, Debug)] pub enum ExprKind { Scope { extent: H::CodeExtent, value: ExprRef }, Paren { arg: ExprRef }, // ugh. should be able to remove this! Box { place: Option>, value: ExprRef }, Call { fun: ExprRef, args: Vec> }, Deref { arg: ExprRef }, // NOT overloaded! Binary { op: BinOp, lhs: ExprRef, rhs: ExprRef }, // NOT overloaded! LogicalOp { op: LogicalOp, lhs: ExprRef, rhs: ExprRef }, Unary { op: UnOp, arg: ExprRef }, // NOT overloaded! Cast { source: ExprRef }, ReifyFnPointer { source: ExprRef }, UnsafeFnPointer { source: ExprRef }, Unsize { source: ExprRef }, If { condition: ExprRef, then: ExprRef, otherwise: Option> }, Loop { condition: Option>, body: ExprRef, }, Match { discriminant: ExprRef, arms: Vec> }, Block { body: H::Block }, Assign { lhs: ExprRef, rhs: ExprRef }, AssignOp { op: BinOp, lhs: ExprRef, rhs: ExprRef }, Field { lhs: ExprRef, name: Field }, Index { lhs: ExprRef, index: ExprRef }, VarRef { id: H::VarId }, SelfRef, // first argument, used for self in a closure StaticRef { id: H::DefId }, Borrow { region: H::Region, borrow_kind: BorrowKind, arg: ExprRef }, Break { label: Option }, Continue { label: Option }, Return { value: Option> }, Repeat { value: ExprRef, count: ExprRef }, Vec { fields: Vec> }, Tuple { fields: Vec> }, Adt { adt_def: H::AdtDef, variant_index: usize, substs: H::Substs, fields: Vec>, base: Option> }, Closure { closure_id: H::DefId, substs: H::ClosureSubsts, upvars: Vec> }, Literal { literal: Literal }, InlineAsm { asm: H::InlineAsm }, } #[derive(Clone, Debug)] pub enum ExprRef { Hair(H::Expr), Mirror(Box>), } #[derive(Clone, Debug)] pub struct FieldExprRef { pub name: Field, pub expr: ExprRef, } #[derive(Clone, Debug)] pub struct Arm { pub patterns: Vec>, pub guard: Option>, pub body: ExprRef, } #[derive(Clone, Debug)] pub struct Pattern { pub ty: H::Ty, pub span: H::Span, pub kind: PatternKind, } #[derive(Copy, Clone, Debug)] pub enum LogicalOp { And, Or } #[derive(Clone, Debug)] pub enum PatternKind { Wild, // x, ref x, x @ P, etc Binding { mutability: Mutability, name: H::Ident, mode: BindingMode, var: H::VarId, ty: H::Ty, subpattern: Option> }, // Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants Variant { adt_def: H::AdtDef, variant_index: usize, subpatterns: Vec> }, // (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant Leaf { subpatterns: Vec> }, Deref { subpattern: PatternRef }, // box P, &P, &mut P, etc Constant { expr: ExprRef }, Range { lo: ExprRef, hi: ExprRef }, // matches against a slice, checking the length and extracting elements Slice { prefix: Vec>, slice: Option>, suffix: Vec> }, // fixed match against an array, irrefutable Array { prefix: Vec>, slice: Option>, suffix: Vec> }, } #[derive(Copy, Clone, Debug)] pub enum BindingMode { ByValue, ByRef(H::Region, BorrowKind), } #[derive(Clone, Debug)] pub enum PatternRef { Hair(H::Pattern), Mirror(Box>), } #[derive(Clone, Debug)] pub struct FieldPatternRef { pub field: Field, pub pattern: PatternRef, } /////////////////////////////////////////////////////////////////////////// // The Mirror trait /// "Mirroring" is the process of converting from a Hair type into one /// of the types in this file. For example, the mirror of a `H::Expr` /// is an `Expr`. Mirroring is the point at which the actual IR is /// converting into the more idealized representation described in /// this file. Mirroring is gradual: when you mirror an outer /// expression like `e1 + e2`, the references to the inner expressions /// `e1` and `e2` are `ExprRef` 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 Hair nodes, which lets the Hair /// nodes be simpler. pub trait Mirror { type Output; fn make_mirror(self, hir: &mut H) -> Self::Output; } impl Mirror for Expr { type Output = Expr; fn make_mirror(self, _: &mut H) -> Expr { self } } impl Mirror for ExprRef { type Output = Expr; fn make_mirror(self, hir: &mut H) -> Expr { match self { ExprRef::Hair(h) => h.make_mirror(hir), ExprRef::Mirror(m) => *m, } } } impl Mirror for Stmt { type Output = Stmt; fn make_mirror(self, _: &mut H) -> Stmt { self } } impl Mirror for StmtRef { type Output = Stmt; fn make_mirror(self, hir: &mut H) -> Stmt { match self { StmtRef::Hair(h) => h.make_mirror(hir), StmtRef::Mirror(m) => *m, } } } impl Mirror for Pattern { type Output = Pattern; fn make_mirror(self, _: &mut H) -> Pattern { self } } impl Mirror for PatternRef { type Output = Pattern; fn make_mirror(self, hir: &mut H) -> Pattern { match self { PatternRef::Hair(h) => h.make_mirror(hir), PatternRef::Mirror(m) => *m, } } } impl Mirror for Block { type Output = Block; fn make_mirror(self, _: &mut H) -> Block { self } }