383 lines
13 KiB
Rust
383 lines
13 KiB
Rust
// 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 <LICENSE-APACHE or
|
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, 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<Vec<u8>>
|
|
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<Self,Output=Pattern<Self>>; // e.g., &P<ast::Pat>
|
|
type Expr: Clone+Debug+Mirror<Self,Output=Expr<Self>>; // e.g., &P<ast::Expr>
|
|
type Stmt: Clone+Debug+Mirror<Self,Output=Stmt<Self>>; // e.g., &P<ast::Stmt>
|
|
type Block: Clone+Debug+Mirror<Self,Output=Block<Self>>; // e.g., &P<ast::Block>
|
|
type InlineAsm: Clone+Debug+Eq+Hash; // e.g., ast::InlineAsm
|
|
|
|
/// Normalizes `ast` into the appropriate `mirror` type.
|
|
fn mirror<M:Mirror<Self>>(&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::<T,T>::eq`
|
|
fn partial_eq(&mut self, ty: Self::Ty) -> ItemRef<Self>;
|
|
|
|
/// Returns a reference to `PartialOrd::<T,T>::le`
|
|
fn partial_le(&mut self, ty: Self::Ty) -> ItemRef<Self>;
|
|
|
|
/// 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<Field<Self>>;
|
|
|
|
/// 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<H:Hair> {
|
|
pub ty: H::Ty,
|
|
pub def_id: H::DefId,
|
|
pub substs: H::Substs,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Block<H:Hair> {
|
|
pub extent: H::CodeExtent,
|
|
pub span: H::Span,
|
|
pub stmts: Vec<StmtRef<H>>,
|
|
pub expr: Option<ExprRef<H>>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum StmtRef<H:Hair> {
|
|
Hair(H::Stmt),
|
|
Mirror(Box<Stmt<H>>),
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Stmt<H:Hair> {
|
|
pub span: H::Span,
|
|
pub kind: StmtKind<H>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum StmtKind<H:Hair> {
|
|
Expr {
|
|
/// scope for this statement; may be used as lifetime of temporaries
|
|
scope: H::CodeExtent,
|
|
|
|
/// expression being evaluated in this statement
|
|
expr: ExprRef<H>
|
|
},
|
|
|
|
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 <PAT> = ...
|
|
pattern: PatternRef<H>,
|
|
|
|
/// let pat = <INIT> ...
|
|
initializer: Option<ExprRef<H>>,
|
|
|
|
/// let pat = init; <STMTS>
|
|
stmts: Vec<StmtRef<H>>
|
|
},
|
|
}
|
|
|
|
// 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<H>`, 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<H:Hair> {
|
|
// 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<H::CodeExtent>,
|
|
|
|
// span of the expression in the source
|
|
pub span: H::Span,
|
|
|
|
// kind of expression
|
|
pub kind: ExprKind<H>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum ExprKind<H:Hair> {
|
|
Scope { extent: H::CodeExtent, value: ExprRef<H> },
|
|
Paren { arg: ExprRef<H> }, // ugh. should be able to remove this!
|
|
Box { place: Option<ExprRef<H>>, value: ExprRef<H> },
|
|
Call { fun: ExprRef<H>, args: Vec<ExprRef<H>> },
|
|
Deref { arg: ExprRef<H> }, // NOT overloaded!
|
|
Binary { op: BinOp, lhs: ExprRef<H>, rhs: ExprRef<H> }, // NOT overloaded!
|
|
LogicalOp { op: LogicalOp, lhs: ExprRef<H>, rhs: ExprRef<H> },
|
|
Unary { op: UnOp, arg: ExprRef<H> }, // NOT overloaded!
|
|
Cast { source: ExprRef<H> },
|
|
ReifyFnPointer { source: ExprRef<H> },
|
|
UnsafeFnPointer { source: ExprRef<H> },
|
|
Unsize { source: ExprRef<H> },
|
|
If { condition: ExprRef<H>, then: ExprRef<H>, otherwise: Option<ExprRef<H>> },
|
|
Loop { condition: Option<ExprRef<H>>, body: ExprRef<H>, },
|
|
Match { discriminant: ExprRef<H>, arms: Vec<Arm<H>> },
|
|
Block { body: H::Block },
|
|
Assign { lhs: ExprRef<H>, rhs: ExprRef<H> },
|
|
AssignOp { op: BinOp, lhs: ExprRef<H>, rhs: ExprRef<H> },
|
|
Field { lhs: ExprRef<H>, name: Field<H> },
|
|
Index { lhs: ExprRef<H>, index: ExprRef<H> },
|
|
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<H> },
|
|
Break { label: Option<H::CodeExtent> },
|
|
Continue { label: Option<H::CodeExtent> },
|
|
Return { value: Option<ExprRef<H>> },
|
|
Repeat { value: ExprRef<H>, count: ExprRef<H> },
|
|
Vec { fields: Vec<ExprRef<H>> },
|
|
Tuple { fields: Vec<ExprRef<H>> },
|
|
Adt { adt_def: H::AdtDef,
|
|
variant_index: usize,
|
|
substs: H::Substs,
|
|
fields: Vec<FieldExprRef<H>>,
|
|
base: Option<ExprRef<H>> },
|
|
Closure { closure_id: H::DefId, substs: H::ClosureSubsts,
|
|
upvars: Vec<ExprRef<H>> },
|
|
Literal { literal: Literal<H> },
|
|
InlineAsm { asm: H::InlineAsm },
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum ExprRef<H:Hair> {
|
|
Hair(H::Expr),
|
|
Mirror(Box<Expr<H>>),
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct FieldExprRef<H:Hair> {
|
|
pub name: Field<H>,
|
|
pub expr: ExprRef<H>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Arm<H:Hair> {
|
|
pub patterns: Vec<PatternRef<H>>,
|
|
pub guard: Option<ExprRef<H>>,
|
|
pub body: ExprRef<H>,
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct Pattern<H:Hair> {
|
|
pub ty: H::Ty,
|
|
pub span: H::Span,
|
|
pub kind: PatternKind<H>,
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub enum LogicalOp {
|
|
And,
|
|
Or
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum PatternKind<H:Hair> {
|
|
Wild,
|
|
|
|
// x, ref x, x @ P, etc
|
|
Binding { mutability: Mutability,
|
|
name: H::Ident,
|
|
mode: BindingMode<H>,
|
|
var: H::VarId,
|
|
ty: H::Ty,
|
|
subpattern: Option<PatternRef<H>> },
|
|
|
|
// 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<FieldPatternRef<H>> },
|
|
|
|
// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
|
|
Leaf { subpatterns: Vec<FieldPatternRef<H>> },
|
|
|
|
Deref { subpattern: PatternRef<H> }, // box P, &P, &mut P, etc
|
|
|
|
Constant { expr: ExprRef<H> },
|
|
|
|
Range { lo: ExprRef<H>, hi: ExprRef<H> },
|
|
|
|
// matches against a slice, checking the length and extracting elements
|
|
Slice { prefix: Vec<PatternRef<H>>,
|
|
slice: Option<PatternRef<H>>,
|
|
suffix: Vec<PatternRef<H>> },
|
|
|
|
// fixed match against an array, irrefutable
|
|
Array { prefix: Vec<PatternRef<H>>,
|
|
slice: Option<PatternRef<H>>,
|
|
suffix: Vec<PatternRef<H>> },
|
|
}
|
|
|
|
#[derive(Copy, Clone, Debug)]
|
|
pub enum BindingMode<H:Hair> {
|
|
ByValue,
|
|
ByRef(H::Region, BorrowKind),
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub enum PatternRef<H:Hair> {
|
|
Hair(H::Pattern),
|
|
Mirror(Box<Pattern<H>>),
|
|
}
|
|
|
|
#[derive(Clone, Debug)]
|
|
pub struct FieldPatternRef<H:Hair> {
|
|
pub field: Field<H>,
|
|
pub pattern: PatternRef<H>,
|
|
}
|
|
|
|
///////////////////////////////////////////////////////////////////////////
|
|
// 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<H>`. 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<H>` 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<H:Hair> {
|
|
type Output;
|
|
|
|
fn make_mirror(self, hir: &mut H) -> Self::Output;
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for Expr<H> {
|
|
type Output = Expr<H>;
|
|
|
|
fn make_mirror(self, _: &mut H) -> Expr<H> {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for ExprRef<H> {
|
|
type Output = Expr<H>;
|
|
|
|
fn make_mirror(self, hir: &mut H) -> Expr<H> {
|
|
match self {
|
|
ExprRef::Hair(h) => h.make_mirror(hir),
|
|
ExprRef::Mirror(m) => *m,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for Stmt<H> {
|
|
type Output = Stmt<H>;
|
|
|
|
fn make_mirror(self, _: &mut H) -> Stmt<H> {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for StmtRef<H> {
|
|
type Output = Stmt<H>;
|
|
|
|
fn make_mirror(self, hir: &mut H) -> Stmt<H> {
|
|
match self {
|
|
StmtRef::Hair(h) => h.make_mirror(hir),
|
|
StmtRef::Mirror(m) => *m,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for Pattern<H> {
|
|
type Output = Pattern<H>;
|
|
|
|
fn make_mirror(self, _: &mut H) -> Pattern<H> {
|
|
self
|
|
}
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for PatternRef<H> {
|
|
type Output = Pattern<H>;
|
|
|
|
fn make_mirror(self, hir: &mut H) -> Pattern<H> {
|
|
match self {
|
|
PatternRef::Hair(h) => h.make_mirror(hir),
|
|
PatternRef::Mirror(m) => *m,
|
|
}
|
|
}
|
|
}
|
|
|
|
impl<H:Hair> Mirror<H> for Block<H> {
|
|
type Output = Block<H>;
|
|
|
|
fn make_mirror(self, _: &mut H) -> Block<H> {
|
|
self
|
|
}
|
|
}
|
|
|