mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-29 02:03:53 +00:00
Auto merge of #28866 - nikomatsakis:remove-hair-trait, r=nrc
As the subject says. This PR also removes the `Hair` trait, which was impeding the ability to build such a map, as described in this thread on internals: https://internals.rust-lang.org/t/removing-the-hair-trait-from-mir-construction/2732 r? @nrc
This commit is contained in:
commit
a63b0f045d
12
mk/main.mk
12
mk/main.mk
@ -175,18 +175,6 @@ ifdef CFG_DISABLE_STAGE0_LANDING_PADS
|
||||
RUSTFLAGS_STAGE0 += -Z no-landing-pads
|
||||
endif
|
||||
|
||||
# Enable MIR to "always build" for crates where this works. This is
|
||||
# just temporary while MIR is being actively built up -- it's just a
|
||||
# poor man's unit testing infrastructure. Anyway we only want this for
|
||||
# stage1/stage2.
|
||||
define ADD_MIR_FLAG
|
||||
RUSTFLAGS1_$(1) += -Z always-build-mir
|
||||
RUSTFLAGS2_$(1) += -Z always-build-mir
|
||||
endef
|
||||
$(foreach crate,$(TARGET_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
|
||||
$(foreach crate,$(RUSTC_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
|
||||
$(foreach crate,$(HOST_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
|
||||
|
||||
# platform-specific auto-configuration
|
||||
include $(CFG_SRC_DIR)mk/platform.mk
|
||||
|
||||
|
@ -101,7 +101,6 @@ pub struct Options {
|
||||
pub parse_only: bool,
|
||||
pub no_trans: bool,
|
||||
pub treat_err_as_bug: bool,
|
||||
pub always_build_mir: bool,
|
||||
pub no_analysis: bool,
|
||||
pub debugging_opts: DebuggingOptions,
|
||||
pub prints: Vec<PrintRequest>,
|
||||
@ -211,7 +210,6 @@ pub fn basic_options() -> Options {
|
||||
parse_only: false,
|
||||
no_trans: false,
|
||||
treat_err_as_bug: false,
|
||||
always_build_mir: false,
|
||||
no_analysis: false,
|
||||
debugging_opts: basic_debugging_options(),
|
||||
prints: Vec::new(),
|
||||
@ -578,8 +576,6 @@ options! {DebuggingOptions, DebuggingSetter, basic_debugging_options,
|
||||
"Run all passes except translation; no output"),
|
||||
treat_err_as_bug: bool = (false, parse_bool,
|
||||
"Treat all errors that occur as bugs"),
|
||||
always_build_mir: bool = (false, parse_bool,
|
||||
"Always build MIR for all fns, even without a #[rustc_mir] annotation"),
|
||||
no_analysis: bool = (false, parse_bool,
|
||||
"Parse and expand the source, but run no analysis"),
|
||||
extra_plugins: Vec<String> = (Vec::new(), parse_list,
|
||||
@ -895,7 +891,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
let parse_only = debugging_opts.parse_only;
|
||||
let no_trans = debugging_opts.no_trans;
|
||||
let treat_err_as_bug = debugging_opts.treat_err_as_bug;
|
||||
let always_build_mir = debugging_opts.always_build_mir;
|
||||
let no_analysis = debugging_opts.no_analysis;
|
||||
|
||||
if debugging_opts.debug_llvm {
|
||||
@ -1049,7 +1044,6 @@ pub fn build_session_options(matches: &getopts::Matches) -> Options {
|
||||
parse_only: parse_only,
|
||||
no_trans: no_trans,
|
||||
treat_err_as_bug: treat_err_as_bug,
|
||||
always_build_mir: always_build_mir,
|
||||
no_analysis: no_analysis,
|
||||
debugging_opts: debugging_opts,
|
||||
prints: prints,
|
||||
|
@ -738,8 +738,9 @@ pub fn phase_3_run_analysis_passes<'tcx, F, R>(sess: Session,
|
||||
time(time_passes, "match checking", ||
|
||||
middle::check_match::check_crate(tcx));
|
||||
|
||||
time(time_passes, "MIR dump", ||
|
||||
mir::dump::dump_crate(tcx));
|
||||
let _mir_map =
|
||||
time(time_passes, "MIR dump", ||
|
||||
mir::mir_map::build_mir_for_crate(tcx));
|
||||
|
||||
time(time_passes, "liveness checking", ||
|
||||
middle::liveness::check_crate(tcx));
|
||||
|
@ -8,15 +8,16 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use build::{BlockAnd, Builder};
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
use build::{BlockAnd, Builder};
|
||||
use rustc_front::hir;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
pub fn ast_block(&mut self,
|
||||
destination: &Lvalue<H>,
|
||||
destination: &Lvalue<'tcx>,
|
||||
mut block: BasicBlock,
|
||||
ast_block: H::Block)
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> BlockAnd<()> {
|
||||
let this = self;
|
||||
let Block { extent, span: _, stmts, expr } = this.hir.mirror(ast_block);
|
||||
|
@ -14,15 +14,15 @@
|
||||
//! Routines for manipulating the control-flow graph.
|
||||
|
||||
use build::CFG;
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
impl<H:Hair> CFG<H> {
|
||||
pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<H> {
|
||||
impl<'tcx> CFG<'tcx> {
|
||||
pub fn block_data(&self, blk: BasicBlock) -> &BasicBlockData<'tcx> {
|
||||
&self.basic_blocks[blk.index()]
|
||||
}
|
||||
|
||||
pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<H> {
|
||||
pub fn block_data_mut(&mut self, blk: BasicBlock) -> &mut BasicBlockData<'tcx> {
|
||||
&mut self.basic_blocks[blk.index()]
|
||||
}
|
||||
|
||||
@ -39,21 +39,21 @@ impl<H:Hair> CFG<H> {
|
||||
BasicBlock::new(node_index)
|
||||
}
|
||||
|
||||
pub fn push(&mut self, block: BasicBlock, statement: Statement<H>) {
|
||||
pub fn push(&mut self, block: BasicBlock, statement: Statement<'tcx>) {
|
||||
debug!("push({:?}, {:?})", block, statement);
|
||||
self.block_data_mut(block).statements.push(statement);
|
||||
}
|
||||
|
||||
pub fn push_assign_constant(&mut self,
|
||||
block: BasicBlock,
|
||||
span: H::Span,
|
||||
temp: &Lvalue<H>,
|
||||
constant: Constant<H>) {
|
||||
span: Span,
|
||||
temp: &Lvalue<'tcx>,
|
||||
constant: Constant<'tcx>) {
|
||||
self.push_assign(block, span, temp, Rvalue::Use(Operand::Constant(constant)));
|
||||
}
|
||||
|
||||
pub fn push_drop(&mut self, block: BasicBlock, span: H::Span,
|
||||
kind: DropKind, lvalue: &Lvalue<H>) {
|
||||
pub fn push_drop(&mut self, block: BasicBlock, span: Span,
|
||||
kind: DropKind, lvalue: &Lvalue<'tcx>) {
|
||||
self.push(block, Statement {
|
||||
span: span,
|
||||
kind: StatementKind::Drop(kind, lvalue.clone())
|
||||
@ -62,9 +62,9 @@ impl<H:Hair> CFG<H> {
|
||||
|
||||
pub fn push_assign(&mut self,
|
||||
block: BasicBlock,
|
||||
span: H::Span,
|
||||
lvalue: &Lvalue<H>,
|
||||
rvalue: Rvalue<H>) {
|
||||
span: Span,
|
||||
lvalue: &Lvalue<'tcx>,
|
||||
rvalue: Rvalue<'tcx>) {
|
||||
self.push(block, Statement {
|
||||
span: span,
|
||||
kind: StatementKind::Assign(lvalue.clone(), rvalue)
|
||||
@ -73,7 +73,7 @@ impl<H:Hair> CFG<H> {
|
||||
|
||||
pub fn terminate(&mut self,
|
||||
block: BasicBlock,
|
||||
terminator: Terminator<H>) {
|
||||
terminator: Terminator<'tcx>) {
|
||||
// Check whether this block has already been terminated. For
|
||||
// this, we rely on the fact that the initial state is to have
|
||||
// a Diverge terminator and an empty list of targets (which
|
||||
|
@ -14,17 +14,17 @@ use build::{Builder};
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Compile `expr`, yielding a compile-time constant. Assumes that
|
||||
/// `expr` is a valid compile-time constant!
|
||||
pub fn as_constant<M>(&mut self, expr: M) -> Constant<H>
|
||||
where M: Mirror<H, Output=Expr<H>>
|
||||
pub fn as_constant<M>(&mut self, expr: M) -> Constant<'tcx>
|
||||
where M: Mirror<'tcx, Output=Expr<'tcx>>
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_constant(expr)
|
||||
}
|
||||
|
||||
fn expr_as_constant(&mut self, expr: Expr<H>) -> Constant<H> {
|
||||
fn expr_as_constant(&mut self, expr: Expr<'tcx>) -> Constant<'tcx> {
|
||||
let this = self;
|
||||
let Expr { ty, temp_lifetime: _, span, kind } = expr;
|
||||
match kind {
|
||||
|
@ -15,13 +15,13 @@ use build::expr::category::Category;
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Compile `expr`, yielding an lvalue that we can move from etc.
|
||||
pub fn as_lvalue<M>(&mut self,
|
||||
block: BasicBlock,
|
||||
expr: M)
|
||||
-> BlockAnd<Lvalue<H>>
|
||||
where M: Mirror<H, Output=Expr<H>>
|
||||
-> BlockAnd<Lvalue<'tcx>>
|
||||
where M: Mirror<'tcx, Output=Expr<'tcx>>
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_lvalue(block, expr)
|
||||
@ -29,8 +29,8 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
fn expr_as_lvalue(&mut self,
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<H>)
|
||||
-> BlockAnd<Lvalue<H>>
|
||||
expr: Expr<'tcx>)
|
||||
-> BlockAnd<Lvalue<'tcx>>
|
||||
{
|
||||
debug!("expr_as_lvalue(block={:?}, expr={:?})",
|
||||
block, expr);
|
||||
|
@ -15,7 +15,7 @@ use build::expr::category::Category;
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Compile `expr` into a value that can be used as an operand.
|
||||
/// If `expr` is an lvalue like `x`, this will introduce a
|
||||
/// temporary `tmp = x`, so that we capture the value of `x` at
|
||||
@ -23,8 +23,8 @@ impl<H:Hair> Builder<H> {
|
||||
pub fn as_operand<M>(&mut self,
|
||||
block: BasicBlock,
|
||||
expr: M)
|
||||
-> BlockAnd<Operand<H>>
|
||||
where M: Mirror<H, Output=Expr<H>>
|
||||
-> BlockAnd<Operand<'tcx>>
|
||||
where M: Mirror<'tcx, Output=Expr<'tcx>>
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_operand(block, expr)
|
||||
@ -32,8 +32,8 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
fn expr_as_operand(&mut self,
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<H>)
|
||||
-> BlockAnd<Operand<H>>
|
||||
expr: Expr<'tcx>)
|
||||
-> BlockAnd<Operand<'tcx>>
|
||||
{
|
||||
debug!("expr_as_operand(block={:?}, expr={:?})",
|
||||
block, expr);
|
||||
|
@ -17,13 +17,13 @@ use build::expr::category::{Category, RvalueFunc};
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Compile `expr`, yielding an rvalue.
|
||||
pub fn as_rvalue<M>(&mut self,
|
||||
block: BasicBlock,
|
||||
expr: M)
|
||||
-> BlockAnd<Rvalue<H>>
|
||||
where M: Mirror<H, Output=Expr<H>>
|
||||
-> BlockAnd<Rvalue<'tcx>>
|
||||
where M: Mirror<'tcx, Output=Expr<'tcx>>
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_rvalue(block, expr)
|
||||
@ -31,8 +31,8 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
fn expr_as_rvalue(&mut self,
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<H>)
|
||||
-> BlockAnd<Rvalue<H>>
|
||||
expr: Expr<'tcx>)
|
||||
-> BlockAnd<Rvalue<'tcx>>
|
||||
{
|
||||
debug!("expr_as_rvalue(block={:?}, expr={:?})",
|
||||
block, expr);
|
||||
|
@ -15,14 +15,14 @@ use build::expr::category::Category;
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Compile `expr` into a fresh temporary. This is used when building
|
||||
/// up rvalues so as to freeze the value that will be consumed.
|
||||
pub fn as_temp<M>(&mut self,
|
||||
block: BasicBlock,
|
||||
expr: M)
|
||||
-> BlockAnd<Lvalue<H>>
|
||||
where M: Mirror<H, Output=Expr<H>>
|
||||
-> BlockAnd<Lvalue<'tcx>>
|
||||
where M: Mirror<'tcx, Output=Expr<'tcx>>
|
||||
{
|
||||
let expr = self.hir.mirror(expr);
|
||||
self.expr_as_temp(block, expr)
|
||||
@ -30,8 +30,8 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
fn expr_as_temp(&mut self,
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<H>)
|
||||
-> BlockAnd<Lvalue<H>>
|
||||
expr: Expr<'tcx>)
|
||||
-> BlockAnd<Lvalue<'tcx>>
|
||||
{
|
||||
debug!("expr_as_temp(block={:?}, expr={:?})",
|
||||
block, expr);
|
||||
|
@ -41,7 +41,7 @@ pub enum RvalueFunc {
|
||||
/// Determines the category for a given expression. Note that scope
|
||||
/// and paren expressions have no category.
|
||||
impl Category {
|
||||
pub fn of<H:Hair>(ek: &ExprKind<H>) -> Option<Category> {
|
||||
pub fn of<'tcx>(ek: &ExprKind<'tcx>) -> Option<Category> {
|
||||
match *ek {
|
||||
ExprKind::Scope { .. } => None,
|
||||
|
||||
|
@ -15,14 +15,16 @@ use build::expr::category::{Category, RvalueFunc};
|
||||
use build::scope::LoopScope;
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Compile `expr`, storing the result into `destination`, which
|
||||
/// is assumed to be uninitialized.
|
||||
pub fn into_expr(&mut self,
|
||||
destination: &Lvalue<H>,
|
||||
destination: &Lvalue<'tcx>,
|
||||
mut block: BasicBlock,
|
||||
expr: Expr<H>)
|
||||
expr: Expr<'tcx>)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
debug!("into_expr(destination={:?}, block={:?}, expr={:?})",
|
||||
@ -266,12 +268,12 @@ impl<H:Hair> Builder<H> {
|
||||
}
|
||||
|
||||
fn break_or_continue<F>(&mut self,
|
||||
span: H::Span,
|
||||
label: Option<H::CodeExtent>,
|
||||
span: Span,
|
||||
label: Option<CodeExtent>,
|
||||
block: BasicBlock,
|
||||
exit_selector: F)
|
||||
-> BlockAnd<()>
|
||||
where F: FnOnce(&LoopScope<H>) -> BasicBlock
|
||||
where F: FnOnce(&LoopScope) -> BasicBlock
|
||||
{
|
||||
let loop_scope = self.find_loop_scope(span, label);
|
||||
let exit_block = exit_selector(&loop_scope);
|
||||
|
@ -18,50 +18,50 @@ use build::{BlockAnd, Builder};
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
pub trait EvalInto<H:Hair> {
|
||||
fn eval_into(self, builder: &mut Builder<H>, destination: &Lvalue<H>,
|
||||
block: BasicBlock) -> BlockAnd<()>;
|
||||
pub trait EvalInto<'tcx> {
|
||||
fn eval_into<'a>(self, builder: &mut Builder<'a,'tcx>, destination: &Lvalue<'tcx>,
|
||||
block: BasicBlock) -> BlockAnd<()>;
|
||||
}
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
pub fn into<E>(&mut self,
|
||||
destination: &Lvalue<H>,
|
||||
destination: &Lvalue<'tcx>,
|
||||
block: BasicBlock,
|
||||
expr: E)
|
||||
-> BlockAnd<()>
|
||||
where E: EvalInto<H>
|
||||
where E: EvalInto<'tcx>
|
||||
{
|
||||
expr.eval_into(self, destination, block)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> EvalInto<H> for ExprRef<H> {
|
||||
fn eval_into(self,
|
||||
builder: &mut Builder<H>,
|
||||
destination: &Lvalue<H>,
|
||||
block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
impl<'tcx> EvalInto<'tcx> for ExprRef<'tcx> {
|
||||
fn eval_into<'a>(self,
|
||||
builder: &mut Builder<'a,'tcx>,
|
||||
destination: &Lvalue<'tcx>,
|
||||
block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
let expr = builder.hir.mirror(self);
|
||||
builder.into_expr(destination, block, expr)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> EvalInto<H> for Expr<H> {
|
||||
fn eval_into(self,
|
||||
builder: &mut Builder<H>,
|
||||
destination: &Lvalue<H>,
|
||||
block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
impl<'tcx> EvalInto<'tcx> for Expr<'tcx> {
|
||||
fn eval_into<'a>(self,
|
||||
builder: &mut Builder<'a,'tcx>,
|
||||
destination: &Lvalue<'tcx>,
|
||||
block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
builder.into_expr(destination, block, self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> EvalInto<H> for Option<ExprRef<H>> {
|
||||
fn eval_into(self,
|
||||
builder: &mut Builder<H>,
|
||||
destination: &Lvalue<H>,
|
||||
block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
impl<'tcx> EvalInto<'tcx> for Option<ExprRef<'tcx>> {
|
||||
fn eval_into<'a>(self,
|
||||
builder: &mut Builder<'a,'tcx>,
|
||||
destination: &Lvalue<'tcx>,
|
||||
block: BasicBlock)
|
||||
-> BlockAnd<()> {
|
||||
match self {
|
||||
Some(expr) => builder.into(destination, block, expr),
|
||||
None => block.unit()
|
||||
|
@ -15,20 +15,24 @@
|
||||
|
||||
use build::{BlockAnd, Builder};
|
||||
use repr::*;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::ty::{AdtDef, Ty};
|
||||
use hair::*;
|
||||
use syntax::ast::{Name, NodeId};
|
||||
use syntax::codemap::Span;
|
||||
|
||||
// helper functions, broken out by category:
|
||||
mod simplify;
|
||||
mod test;
|
||||
mod util;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
pub fn match_expr(&mut self,
|
||||
destination: &Lvalue<H>,
|
||||
span: H::Span,
|
||||
destination: &Lvalue<'tcx>,
|
||||
span: Span,
|
||||
mut block: BasicBlock,
|
||||
discriminant: ExprRef<H>,
|
||||
arms: Vec<Arm<H>>)
|
||||
discriminant: ExprRef<'tcx>,
|
||||
arms: Vec<Arm<'tcx>>)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
let discriminant_lvalue =
|
||||
@ -49,7 +53,7 @@ impl<H:Hair> Builder<H> {
|
||||
.collect(),
|
||||
};
|
||||
|
||||
let arm_bodies: Vec<ExprRef<H>> =
|
||||
let arm_bodies: Vec<ExprRef<'tcx>> =
|
||||
arms.iter()
|
||||
.map(|arm| arm.body.clone())
|
||||
.collect();
|
||||
@ -60,7 +64,7 @@ impl<H:Hair> Builder<H> {
|
||||
// highest priority candidate comes last in the list. This the
|
||||
// reverse of the order in which candidates are written in the
|
||||
// source.
|
||||
let candidates: Vec<Candidate<H>> =
|
||||
let candidates: Vec<Candidate<'tcx>> =
|
||||
arms.iter()
|
||||
.enumerate()
|
||||
.rev() // highest priority comes last
|
||||
@ -97,9 +101,9 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
pub fn expr_into_pattern(&mut self,
|
||||
mut block: BasicBlock,
|
||||
var_extent: H::CodeExtent, // lifetime of vars
|
||||
irrefutable_pat: PatternRef<H>,
|
||||
initializer: ExprRef<H>)
|
||||
var_extent: CodeExtent, // lifetime of vars
|
||||
irrefutable_pat: PatternRef<'tcx>,
|
||||
initializer: ExprRef<'tcx>)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
// optimize the case of `let x = ...`
|
||||
@ -125,16 +129,16 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
pub fn lvalue_into_pattern(&mut self,
|
||||
mut block: BasicBlock,
|
||||
var_extent: H::CodeExtent,
|
||||
irrefutable_pat: PatternRef<H>,
|
||||
initializer: &Lvalue<H>)
|
||||
var_extent: CodeExtent,
|
||||
irrefutable_pat: PatternRef<'tcx>,
|
||||
initializer: &Lvalue<'tcx>)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
// first, creating the bindings
|
||||
self.declare_bindings(var_extent, irrefutable_pat.clone());
|
||||
|
||||
// create a dummy candidate
|
||||
let mut candidate = Candidate::<H> {
|
||||
let mut candidate = Candidate::<'tcx> {
|
||||
match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
|
||||
bindings: vec![],
|
||||
guard: None,
|
||||
@ -159,8 +163,8 @@ impl<H:Hair> Builder<H> {
|
||||
}
|
||||
|
||||
pub fn declare_bindings(&mut self,
|
||||
var_extent: H::CodeExtent,
|
||||
pattern: PatternRef<H>)
|
||||
var_extent: CodeExtent,
|
||||
pattern: PatternRef<'tcx>)
|
||||
{
|
||||
let pattern = self.hir.mirror(pattern);
|
||||
match pattern.kind {
|
||||
@ -198,69 +202,69 @@ struct ArmBlocks {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Candidate<H:Hair> {
|
||||
struct Candidate<'tcx> {
|
||||
// all of these must be satisfied...
|
||||
match_pairs: Vec<MatchPair<H>>,
|
||||
match_pairs: Vec<MatchPair<'tcx>>,
|
||||
|
||||
// ...these bindings established...
|
||||
bindings: Vec<Binding<H>>,
|
||||
bindings: Vec<Binding<'tcx>>,
|
||||
|
||||
// ...and the guard must be evaluated...
|
||||
guard: Option<ExprRef<H>>,
|
||||
guard: Option<ExprRef<'tcx>>,
|
||||
|
||||
// ...and then we branch to arm with this index.
|
||||
arm_index: usize,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct Binding<H:Hair> {
|
||||
span: H::Span,
|
||||
source: Lvalue<H>,
|
||||
name: H::Name,
|
||||
var_id: H::VarId,
|
||||
var_ty: H::Ty,
|
||||
struct Binding<'tcx> {
|
||||
span: Span,
|
||||
source: Lvalue<'tcx>,
|
||||
name: Name,
|
||||
var_id: NodeId,
|
||||
var_ty: Ty<'tcx>,
|
||||
mutability: Mutability,
|
||||
binding_mode: BindingMode<H>,
|
||||
binding_mode: BindingMode,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
struct MatchPair<H:Hair> {
|
||||
struct MatchPair<'tcx> {
|
||||
// this lvalue...
|
||||
lvalue: Lvalue<H>,
|
||||
lvalue: Lvalue<'tcx>,
|
||||
|
||||
// ... must match this pattern.
|
||||
pattern: Pattern<H>,
|
||||
pattern: Pattern<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
enum TestKind<H:Hair> {
|
||||
enum TestKind<'tcx> {
|
||||
// test the branches of enum
|
||||
Switch { adt_def: H::AdtDef },
|
||||
Switch { adt_def: AdtDef<'tcx> },
|
||||
|
||||
// test for equality
|
||||
Eq { value: Literal<H>, ty: H::Ty },
|
||||
Eq { value: Literal<'tcx>, ty: Ty<'tcx> },
|
||||
|
||||
// test whether the value falls within an inclusive range
|
||||
Range { lo: Literal<H>, hi: Literal<H>, ty: H::Ty },
|
||||
Range { lo: Literal<'tcx>, hi: Literal<'tcx>, ty: Ty<'tcx> },
|
||||
|
||||
// test length of the slice is equal to len
|
||||
Len { len: usize, op: BinOp },
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct Test<H:Hair> {
|
||||
span: H::Span,
|
||||
kind: TestKind<H>,
|
||||
struct Test<'tcx> {
|
||||
span: Span,
|
||||
kind: TestKind<'tcx>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Main matching algorithm
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
fn match_candidates(&mut self,
|
||||
span: H::Span,
|
||||
span: Span,
|
||||
arm_blocks: &mut ArmBlocks,
|
||||
mut candidates: Vec<Candidate<H>>,
|
||||
mut candidates: Vec<Candidate<'tcx>>,
|
||||
mut block: BasicBlock)
|
||||
{
|
||||
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
|
||||
@ -306,7 +310,7 @@ impl<H:Hair> Builder<H> {
|
||||
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
|
||||
|
||||
for (outcome, mut target_block) in target_blocks.into_iter().enumerate() {
|
||||
let applicable_candidates: Vec<Candidate<H>> =
|
||||
let applicable_candidates: Vec<Candidate<'tcx>> =
|
||||
candidates.iter()
|
||||
.filter_map(|candidate| {
|
||||
unpack!(target_block =
|
||||
@ -336,7 +340,7 @@ impl<H:Hair> Builder<H> {
|
||||
fn bind_and_guard_matched_candidate(&mut self,
|
||||
mut block: BasicBlock,
|
||||
arm_blocks: &mut ArmBlocks,
|
||||
candidate: Candidate<H>)
|
||||
candidate: Candidate<'tcx>)
|
||||
-> Option<BasicBlock> {
|
||||
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
|
||||
block, candidate);
|
||||
@ -363,7 +367,7 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
fn bind_matched_candidate(&mut self,
|
||||
block: BasicBlock,
|
||||
bindings: Vec<Binding<H>>) {
|
||||
bindings: Vec<Binding<'tcx>>) {
|
||||
debug!("bind_matched_candidate(block={:?}, bindings={:?})",
|
||||
block, bindings);
|
||||
|
||||
@ -386,19 +390,19 @@ impl<H:Hair> Builder<H> {
|
||||
}
|
||||
|
||||
fn declare_binding(&mut self,
|
||||
var_extent: H::CodeExtent,
|
||||
var_extent: CodeExtent,
|
||||
mutability: Mutability,
|
||||
name: H::Name,
|
||||
var_id: H::VarId,
|
||||
var_ty: H::Ty,
|
||||
span: H::Span)
|
||||
name: Name,
|
||||
var_id: NodeId,
|
||||
var_ty: Ty<'tcx>,
|
||||
span: Span)
|
||||
-> u32
|
||||
{
|
||||
debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_extent={:?}, span={:?})",
|
||||
var_id, name, var_ty, var_extent, span);
|
||||
|
||||
let index = self.var_decls.len();
|
||||
self.var_decls.push(VarDecl::<H> {
|
||||
self.var_decls.push(VarDecl::<'tcx> {
|
||||
mutability: mutability,
|
||||
name: name,
|
||||
ty: var_ty.clone(),
|
||||
|
@ -29,10 +29,10 @@ use repr::*;
|
||||
|
||||
use std::mem;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
pub fn simplify_candidate(&mut self,
|
||||
mut block: BasicBlock,
|
||||
candidate: &mut Candidate<H>)
|
||||
candidate: &mut Candidate<'tcx>)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
// repeatedly simplify match pairs until fixed point is reached
|
||||
@ -56,13 +56,14 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
/// Tries to simplify `match_pair`, returning true if
|
||||
/// successful. If successful, new match pairs and bindings will
|
||||
/// have been pushed into the candidate. On failure (if false is
|
||||
/// returned), no changes are made to candidate.
|
||||
/// have been pushed into the candidate. If no simplification is
|
||||
/// possible, Err is returned and no changes are made to
|
||||
/// candidate.
|
||||
fn simplify_match_pair(&mut self,
|
||||
mut block: BasicBlock,
|
||||
match_pair: MatchPair<H>,
|
||||
candidate: &mut Candidate<H>)
|
||||
-> Result<BasicBlock, MatchPair<H>> // returns Err() if cannot simplify
|
||||
match_pair: MatchPair<'tcx>,
|
||||
candidate: &mut Candidate<'tcx>)
|
||||
-> Result<BasicBlock, MatchPair<'tcx>>
|
||||
{
|
||||
match match_pair.pattern.kind {
|
||||
PatternKind::Wild(..) => {
|
||||
|
@ -19,12 +19,13 @@ use build::{BlockAnd, Builder};
|
||||
use build::matches::{Candidate, MatchPair, Test, TestKind};
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Identifies what test is needed to decide if `match_pair` is applicable.
|
||||
///
|
||||
/// It is a bug to call this with a simplifyable pattern.
|
||||
pub fn test(&mut self, match_pair: &MatchPair<H>) -> Test<H> {
|
||||
pub fn test(&mut self, match_pair: &MatchPair<'tcx>) -> Test<'tcx> {
|
||||
match match_pair.pattern.kind {
|
||||
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
|
||||
Test {
|
||||
@ -72,8 +73,8 @@ impl<H:Hair> Builder<H> {
|
||||
/// Generates the code to perform a test.
|
||||
pub fn perform_test(&mut self,
|
||||
block: BasicBlock,
|
||||
lvalue: &Lvalue<H>,
|
||||
test: &Test<H>)
|
||||
lvalue: &Lvalue<'tcx>,
|
||||
test: &Test<'tcx>)
|
||||
-> Vec<BasicBlock> {
|
||||
match test.kind.clone() {
|
||||
TestKind::Switch { adt_def } => {
|
||||
@ -149,10 +150,10 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
fn call_comparison_fn(&mut self,
|
||||
block: BasicBlock,
|
||||
span: H::Span,
|
||||
item_ref: ItemRef<H>,
|
||||
lvalue1: Lvalue<H>,
|
||||
lvalue2: Lvalue<H>)
|
||||
span: Span,
|
||||
item_ref: ItemRef<'tcx>,
|
||||
lvalue1: Lvalue<'tcx>,
|
||||
lvalue2: Lvalue<'tcx>)
|
||||
-> Vec<BasicBlock> {
|
||||
let target_blocks = vec![self.cfg.start_new_block(),
|
||||
self.cfg.start_new_block()];
|
||||
@ -194,11 +195,11 @@ impl<H:Hair> Builder<H> {
|
||||
/// @ 22])`.
|
||||
pub fn candidate_under_assumption(&mut self,
|
||||
mut block: BasicBlock,
|
||||
test_lvalue: &Lvalue<H>,
|
||||
test_kind: &TestKind<H>,
|
||||
test_lvalue: &Lvalue<'tcx>,
|
||||
test_kind: &TestKind<'tcx>,
|
||||
test_outcome: usize,
|
||||
candidate: &Candidate<H>)
|
||||
-> BlockAnd<Option<Candidate<H>>> {
|
||||
candidate: &Candidate<'tcx>)
|
||||
-> BlockAnd<Option<Candidate<'tcx>>> {
|
||||
let candidate = candidate.clone();
|
||||
let match_pairs = candidate.match_pairs;
|
||||
let result = unpack!(block = self.match_pairs_under_assumption(block,
|
||||
@ -216,11 +217,11 @@ impl<H:Hair> Builder<H> {
|
||||
/// work of transforming the list of match pairs.
|
||||
fn match_pairs_under_assumption(&mut self,
|
||||
mut block: BasicBlock,
|
||||
test_lvalue: &Lvalue<H>,
|
||||
test_kind: &TestKind<H>,
|
||||
test_lvalue: &Lvalue<'tcx>,
|
||||
test_kind: &TestKind<'tcx>,
|
||||
test_outcome: usize,
|
||||
match_pairs: Vec<MatchPair<H>>)
|
||||
-> BlockAnd<Option<Vec<MatchPair<H>>>> {
|
||||
match_pairs: Vec<MatchPair<'tcx>>)
|
||||
-> BlockAnd<Option<Vec<MatchPair<'tcx>>>> {
|
||||
let mut result = vec![];
|
||||
|
||||
for match_pair in match_pairs {
|
||||
@ -279,9 +280,9 @@ impl<H:Hair> Builder<H> {
|
||||
/// It is a bug to call this with a simplifyable pattern.
|
||||
pub fn consequent_match_pairs_under_assumption(&mut self,
|
||||
mut block: BasicBlock,
|
||||
match_pair: MatchPair<H>,
|
||||
match_pair: MatchPair<'tcx>,
|
||||
test_outcome: usize)
|
||||
-> BlockAnd<Option<Vec<MatchPair<H>>>> {
|
||||
-> BlockAnd<Option<Vec<MatchPair<'tcx>>>> {
|
||||
match match_pair.pattern.kind {
|
||||
PatternKind::Variant { adt_def, variant_index, subpatterns } => {
|
||||
if test_outcome != variant_index {
|
||||
@ -339,7 +340,7 @@ impl<H:Hair> Builder<H> {
|
||||
}
|
||||
}
|
||||
|
||||
fn error_simplifyable(&mut self, match_pair: &MatchPair<H>) -> ! {
|
||||
fn error_simplifyable(&mut self, match_pair: &MatchPair<'tcx>) -> ! {
|
||||
self.hir.span_bug(
|
||||
match_pair.pattern.span,
|
||||
&format!("simplifyable pattern found: {:?}", match_pair.pattern))
|
||||
|
@ -14,11 +14,11 @@ use hair::*;
|
||||
use repr::*;
|
||||
use std::u32;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
pub fn field_match_pairs(&mut self,
|
||||
lvalue: Lvalue<H>,
|
||||
subpatterns: Vec<FieldPatternRef<H>>)
|
||||
-> Vec<MatchPair<H>> {
|
||||
lvalue: Lvalue<'tcx>,
|
||||
subpatterns: Vec<FieldPatternRef<'tcx>>)
|
||||
-> Vec<MatchPair<'tcx>> {
|
||||
subpatterns.into_iter()
|
||||
.map(|fieldpat| {
|
||||
let lvalue = lvalue.clone().field(fieldpat.field);
|
||||
@ -27,7 +27,8 @@ impl<H:Hair> Builder<H> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn match_pair(&mut self, lvalue: Lvalue<H>, pattern: PatternRef<H>) -> MatchPair<H> {
|
||||
pub fn match_pair(&mut self, lvalue: Lvalue<'tcx>, pattern: PatternRef<'tcx>)
|
||||
-> MatchPair<'tcx> {
|
||||
let pattern = self.hir.mirror(pattern);
|
||||
MatchPair::new(lvalue, pattern)
|
||||
}
|
||||
@ -47,12 +48,12 @@ impl<H:Hair> Builder<H> {
|
||||
///
|
||||
/// and creates a match pair `tmp0 @ s`
|
||||
pub fn prefix_suffix_slice(&mut self,
|
||||
match_pairs: &mut Vec<MatchPair<H>>,
|
||||
match_pairs: &mut Vec<MatchPair<'tcx>>,
|
||||
block: BasicBlock,
|
||||
lvalue: Lvalue<H>,
|
||||
prefix: Vec<PatternRef<H>>,
|
||||
opt_slice: Option<PatternRef<H>>,
|
||||
suffix: Vec<PatternRef<H>>)
|
||||
lvalue: Lvalue<'tcx>,
|
||||
prefix: Vec<PatternRef<'tcx>>,
|
||||
opt_slice: Option<PatternRef<'tcx>>,
|
||||
suffix: Vec<PatternRef<'tcx>>)
|
||||
-> BlockAnd<()>
|
||||
{
|
||||
// If there is a `..P` pattern, create a temporary `t0` for
|
||||
@ -76,10 +77,10 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
/// Helper for `prefix_suffix_slice` which just processes the prefix and suffix.
|
||||
fn prefix_suffix(&mut self,
|
||||
match_pairs: &mut Vec<MatchPair<H>>,
|
||||
lvalue: Lvalue<H>,
|
||||
prefix: Vec<PatternRef<H>>,
|
||||
suffix: Vec<PatternRef<H>>)
|
||||
match_pairs: &mut Vec<MatchPair<'tcx>>,
|
||||
lvalue: Lvalue<'tcx>,
|
||||
prefix: Vec<PatternRef<'tcx>>,
|
||||
suffix: Vec<PatternRef<'tcx>>)
|
||||
{
|
||||
let min_length = prefix.len() + suffix.len();
|
||||
assert!(min_length < u32::MAX as usize);
|
||||
@ -118,8 +119,8 @@ impl<H:Hair> Builder<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> MatchPair<H> {
|
||||
pub fn new(lvalue: Lvalue<H>, pattern: Pattern<H>) -> MatchPair<H> {
|
||||
impl<'tcx> MatchPair<'tcx> {
|
||||
pub fn new(lvalue: Lvalue<'tcx>, pattern: Pattern<'tcx>) -> MatchPair<'tcx> {
|
||||
MatchPair { lvalue: lvalue, pattern: pattern }
|
||||
}
|
||||
}
|
||||
|
@ -14,16 +14,17 @@
|
||||
use build::Builder;
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
use rustc::middle::ty::Ty;
|
||||
use std::u32;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Add a new temporary value of type `ty` storing the result of
|
||||
/// evaluating `expr`.
|
||||
///
|
||||
/// NB: **No cleanup is scheduled for this temporary.** You should
|
||||
/// call `schedule_drop` once the temporary is initialized.
|
||||
pub fn temp(&mut self, ty: H::Ty) -> Lvalue<H> {
|
||||
pub fn temp(&mut self, ty: Ty<'tcx>) -> Lvalue<'tcx> {
|
||||
let index = self.temp_decls.len();
|
||||
self.temp_decls.push(TempDecl { ty: ty });
|
||||
assert!(index < (u32::MAX) as usize);
|
||||
@ -35,10 +36,10 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
pub fn push_literal(&mut self,
|
||||
block: BasicBlock,
|
||||
span: H::Span,
|
||||
ty: H::Ty,
|
||||
literal: Literal<H>)
|
||||
-> Lvalue<H> {
|
||||
span: Span,
|
||||
ty: Ty<'tcx>,
|
||||
literal: Literal<'tcx>)
|
||||
-> Lvalue<'tcx> {
|
||||
let temp = self.temp(ty.clone());
|
||||
let constant = Constant { span: span, ty: ty, literal: literal };
|
||||
self.cfg.push_assign_constant(block, span, &temp, constant);
|
||||
@ -47,9 +48,9 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
pub fn push_usize(&mut self,
|
||||
block: BasicBlock,
|
||||
span: H::Span,
|
||||
span: Span,
|
||||
value: usize)
|
||||
-> Lvalue<H> {
|
||||
-> Lvalue<'tcx> {
|
||||
let usize_ty = self.hir.usize_ty();
|
||||
let temp = self.temp(usize_ty);
|
||||
self.cfg.push_assign_constant(
|
||||
@ -64,9 +65,9 @@ impl<H:Hair> Builder<H> {
|
||||
|
||||
pub fn push_item_ref(&mut self,
|
||||
block: BasicBlock,
|
||||
span: H::Span,
|
||||
item_ref: ItemRef<H>)
|
||||
-> Lvalue<H> {
|
||||
span: Span,
|
||||
item_ref: ItemRef<'tcx>)
|
||||
-> Lvalue<'tcx> {
|
||||
let literal = Literal::Item { def_id: item_ref.def_id, substs: item_ref.substs };
|
||||
self.push_literal(block, span, item_ref.ty, literal)
|
||||
}
|
||||
|
@ -8,24 +8,30 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use hair::{self, Hair};
|
||||
use hair;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::ty::Ty;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use rustc_front::hir;
|
||||
use repr::*;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use tcx::{Cx, PatNode};
|
||||
|
||||
struct Builder<H:Hair> {
|
||||
hir: H,
|
||||
extents: FnvHashMap<H::CodeExtent, Vec<GraphExtent>>,
|
||||
cfg: CFG<H>,
|
||||
scopes: Vec<scope::Scope<H>>,
|
||||
loop_scopes: Vec<scope::LoopScope<H>>,
|
||||
unit_temp: Lvalue<H>,
|
||||
var_decls: Vec<VarDecl<H>>,
|
||||
var_indices: FnvHashMap<H::VarId, u32>,
|
||||
temp_decls: Vec<TempDecl<H>>,
|
||||
struct Builder<'a,'tcx:'a> {
|
||||
hir: Cx<'a, 'tcx>,
|
||||
extents: FnvHashMap<CodeExtent, Vec<GraphExtent>>,
|
||||
cfg: CFG<'tcx>,
|
||||
scopes: Vec<scope::Scope<'tcx>>,
|
||||
loop_scopes: Vec<scope::LoopScope>,
|
||||
unit_temp: Lvalue<'tcx>,
|
||||
var_decls: Vec<VarDecl<'tcx>>,
|
||||
var_indices: FnvHashMap<ast::NodeId, u32>,
|
||||
temp_decls: Vec<TempDecl<'tcx>>,
|
||||
}
|
||||
|
||||
struct CFG<H:Hair> {
|
||||
basic_blocks: Vec<BasicBlockData<H>>
|
||||
struct CFG<'tcx> {
|
||||
basic_blocks: Vec<BasicBlockData<'tcx>>
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -69,18 +75,18 @@ macro_rules! unpack {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// construct() -- the main entry point for building MIR for a function
|
||||
|
||||
pub fn construct<H:Hair>(mut hir: H,
|
||||
_span: H::Span,
|
||||
implicit_arguments: Vec<H::Ty>,
|
||||
explicit_arguments: Vec<(H::Ty, H::Pattern)>,
|
||||
argument_extent: H::CodeExtent,
|
||||
ast_block: H::Block)
|
||||
-> Mir<H> {
|
||||
pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
|
||||
_span: Span,
|
||||
implicit_arguments: Vec<Ty<'tcx>>,
|
||||
explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
|
||||
argument_extent: CodeExtent,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> Mir<'tcx> {
|
||||
let cfg = CFG { basic_blocks: vec![] };
|
||||
|
||||
// it's handy to have a temporary of type `()` sometimes, so make
|
||||
// one from the start and keep it available
|
||||
let temp_decls = vec![TempDecl::<H> { ty: hir.unit_ty() }];
|
||||
let temp_decls = vec![TempDecl::<'tcx> { ty: hir.unit_ty() }];
|
||||
let unit_temp = Lvalue::Temp(0);
|
||||
|
||||
let mut builder = Builder {
|
||||
@ -118,14 +124,14 @@ pub fn construct<H:Hair>(mut hir: H,
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
fn args_and_body(&mut self,
|
||||
mut block: BasicBlock,
|
||||
implicit_arguments: Vec<H::Ty>,
|
||||
explicit_arguments: Vec<(H::Ty, H::Pattern)>,
|
||||
argument_extent: H::CodeExtent,
|
||||
ast_block: H::Block)
|
||||
-> BlockAnd<Vec<ArgDecl<H>>>
|
||||
implicit_arguments: Vec<Ty<'tcx>>,
|
||||
explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
|
||||
argument_extent: CodeExtent,
|
||||
ast_block: &'tcx hir::Block)
|
||||
-> BlockAnd<Vec<ArgDecl<'tcx>>>
|
||||
{
|
||||
self.in_scope(argument_extent, block, |this| {
|
||||
let arg_decls = {
|
||||
|
@ -12,7 +12,7 @@
|
||||
Managing the scope stack. The scopes are tied to lexical scopes, so as
|
||||
we descend the HAIR, we push a scope on the stack, translate ite
|
||||
contents, and then pop it off. Every scope is named by a
|
||||
`H::CodeExtent`.
|
||||
`CodeExtent`.
|
||||
|
||||
### SEME Regions
|
||||
|
||||
@ -23,7 +23,7 @@ via a `break` or `return` or just by fallthrough, that marks an exit
|
||||
from the scope. Each lexical scope thus corresponds to a single-entry,
|
||||
multiple-exit (SEME) region in the control-flow graph.
|
||||
|
||||
For now, we keep a mapping from each `H::CodeExtent` to its
|
||||
For now, we keep a mapping from each `CodeExtent` to its
|
||||
corresponding SEME region for later reference (see caveat in next
|
||||
paragraph). This is because region scopes are tied to
|
||||
them. Eventually, when we shift to non-lexical lifetimes, three should
|
||||
@ -87,24 +87,26 @@ should go to.
|
||||
*/
|
||||
|
||||
use build::{BlockAnd, Builder, CFG};
|
||||
use hair::Hair;
|
||||
use repr::*;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::ty::Ty;
|
||||
use syntax::codemap::Span;
|
||||
|
||||
pub struct Scope<H:Hair> {
|
||||
extent: H::CodeExtent,
|
||||
pub struct Scope<'tcx> {
|
||||
extent: CodeExtent,
|
||||
exits: Vec<ExecutionPoint>,
|
||||
drops: Vec<(DropKind, H::Span, Lvalue<H>)>,
|
||||
drops: Vec<(DropKind, Span, Lvalue<'tcx>)>,
|
||||
cached_block: Option<BasicBlock>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LoopScope<H:Hair> {
|
||||
pub extent: H::CodeExtent, // extent of the loop
|
||||
pub struct LoopScope {
|
||||
pub extent: CodeExtent, // extent of the loop
|
||||
pub continue_block: BasicBlock, // where to go on a `loop`
|
||||
pub break_block: BasicBlock, // where to go on a `break
|
||||
}
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
/// Start a loop scope, which tracks where `continue` and `break`
|
||||
/// should branch to. See module comment for more details.
|
||||
pub fn in_loop_scope<F,R>(&mut self,
|
||||
@ -112,12 +114,12 @@ impl<H:Hair> Builder<H> {
|
||||
break_block: BasicBlock,
|
||||
f: F)
|
||||
-> BlockAnd<R>
|
||||
where F: FnOnce(&mut Builder<H>) -> BlockAnd<R>
|
||||
where F: FnOnce(&mut Builder<'a,'tcx>) -> BlockAnd<R>
|
||||
{
|
||||
let extent = self.extent_of_innermost_scope().unwrap();
|
||||
let loop_scope = LoopScope::<H> { extent: extent.clone(),
|
||||
continue_block: loop_block,
|
||||
break_block: break_block };
|
||||
let loop_scope = LoopScope { extent: extent.clone(),
|
||||
continue_block: loop_block,
|
||||
break_block: break_block };
|
||||
self.loop_scopes.push(loop_scope);
|
||||
let r = f(self);
|
||||
assert!(self.loop_scopes.pop().unwrap().extent == extent);
|
||||
@ -127,11 +129,11 @@ impl<H:Hair> Builder<H> {
|
||||
/// Start a scope. The closure `f` should translate the contents
|
||||
/// of the scope. See module comment for more details.
|
||||
pub fn in_scope<F,R>(&mut self,
|
||||
extent: H::CodeExtent,
|
||||
extent: CodeExtent,
|
||||
block: BasicBlock,
|
||||
f: F)
|
||||
-> BlockAnd<R>
|
||||
where F: FnOnce(&mut Builder<H>) -> BlockAnd<R>
|
||||
where F: FnOnce(&mut Builder<'a,'tcx>) -> BlockAnd<R>
|
||||
{
|
||||
debug!("in_scope(extent={:?}, block={:?})", extent, block);
|
||||
|
||||
@ -180,9 +182,9 @@ impl<H:Hair> Builder<H> {
|
||||
/// Finds the loop scope for a given label. This is used for
|
||||
/// resolving `break` and `continue`.
|
||||
pub fn find_loop_scope(&mut self,
|
||||
span: H::Span,
|
||||
label: Option<H::CodeExtent>)
|
||||
-> LoopScope<H> {
|
||||
span: Span,
|
||||
label: Option<CodeExtent>)
|
||||
-> LoopScope {
|
||||
let loop_scope =
|
||||
match label {
|
||||
None => {
|
||||
@ -211,8 +213,8 @@ impl<H:Hair> Builder<H> {
|
||||
/// needed, as well as tracking this exit for the SEME region. See
|
||||
/// module comment for details.
|
||||
pub fn exit_scope(&mut self,
|
||||
span: H::Span,
|
||||
extent: H::CodeExtent,
|
||||
span: Span,
|
||||
extent: CodeExtent,
|
||||
block: BasicBlock,
|
||||
target: BasicBlock) {
|
||||
let popped_scopes =
|
||||
@ -249,11 +251,11 @@ impl<H:Hair> Builder<H> {
|
||||
/// Indicates that `lvalue` should be dropped on exit from
|
||||
/// `extent`.
|
||||
pub fn schedule_drop(&mut self,
|
||||
span: H::Span,
|
||||
extent: H::CodeExtent,
|
||||
span: Span,
|
||||
extent: CodeExtent,
|
||||
kind: DropKind,
|
||||
lvalue: &Lvalue<H>,
|
||||
lvalue_ty: H::Ty)
|
||||
lvalue: &Lvalue<'tcx>,
|
||||
lvalue_ty: Ty<'tcx>)
|
||||
{
|
||||
if self.hir.needs_drop(lvalue_ty, span) {
|
||||
match self.scopes.iter_mut().rev().find(|s| s.extent == extent) {
|
||||
@ -267,18 +269,18 @@ impl<H:Hair> Builder<H> {
|
||||
}
|
||||
}
|
||||
|
||||
pub fn extent_of_innermost_scope(&self) -> Option<H::CodeExtent> {
|
||||
pub fn extent_of_innermost_scope(&self) -> Option<CodeExtent> {
|
||||
self.scopes.last().map(|scope| scope.extent)
|
||||
}
|
||||
|
||||
pub fn extent_of_outermost_scope(&self) -> Option<H::CodeExtent> {
|
||||
pub fn extent_of_outermost_scope(&self) -> Option<CodeExtent> {
|
||||
self.scopes.first().map(|scope| scope.extent)
|
||||
}
|
||||
}
|
||||
|
||||
fn diverge_cleanup_helper<H:Hair>(cfg: &mut CFG<H>,
|
||||
scopes: &mut [Scope<H>])
|
||||
-> BasicBlock {
|
||||
fn diverge_cleanup_helper<'tcx>(cfg: &mut CFG<'tcx>,
|
||||
scopes: &mut [Scope<'tcx>])
|
||||
-> BasicBlock {
|
||||
let len = scopes.len();
|
||||
|
||||
if len == 0 {
|
||||
|
@ -12,15 +12,15 @@ use build::{BlockAnd, Builder};
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
impl<H:Hair> Builder<H> {
|
||||
pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec<StmtRef<H>>) -> BlockAnd<()> {
|
||||
impl<'a,'tcx> Builder<'a,'tcx> {
|
||||
pub fn stmts(&mut self, mut block: BasicBlock, stmts: Vec<StmtRef<'tcx>>) -> BlockAnd<()> {
|
||||
for stmt in stmts {
|
||||
unpack!(block = self.stmt(block, stmt));
|
||||
}
|
||||
block.unit()
|
||||
}
|
||||
|
||||
pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef<H>) -> BlockAnd<()> {
|
||||
pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef<'tcx>) -> BlockAnd<()> {
|
||||
let this = self;
|
||||
let Stmt { span, kind } = this.hir.mirror(stmt);
|
||||
match kind {
|
||||
|
@ -9,7 +9,6 @@
|
||||
// except according to those terms.
|
||||
|
||||
use dot;
|
||||
use hair::Hair;
|
||||
use repr::*;
|
||||
use std::borrow::IntoCow;
|
||||
|
||||
@ -20,7 +19,7 @@ pub struct EdgeIndex {
|
||||
index: usize,
|
||||
}
|
||||
|
||||
impl<'a,H:Hair> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<H> {
|
||||
impl<'a,'tcx> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
|
||||
fn graph_id(&'a self) -> dot::Id<'a> {
|
||||
dot::Id::new("Mir").unwrap()
|
||||
}
|
||||
@ -62,7 +61,7 @@ impl<'a,H:Hair> dot::Labeller<'a, BasicBlock, EdgeIndex> for Mir<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,H:Hair> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<H> {
|
||||
impl<'a,'tcx> dot::GraphWalk<'a, BasicBlock, EdgeIndex> for Mir<'tcx> {
|
||||
fn nodes(&'a self) -> dot::Nodes<'a, BasicBlock> {
|
||||
self.all_basic_blocks().into_cow()
|
||||
}
|
||||
|
@ -15,144 +15,78 @@
|
||||
//! structures.
|
||||
|
||||
use repr::{BinOp, BorrowKind, Field, Literal, Mutability, UnOp};
|
||||
use std::fmt::Debug;
|
||||
use std::hash::Hash;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::subst::Substs;
|
||||
use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
|
||||
use rustc_front::hir;
|
||||
use syntax::ast;
|
||||
use syntax::codemap::Span;
|
||||
use tcx::{Cx, PatNode};
|
||||
|
||||
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 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 ConstVal: Clone+Debug+PartialEq; // e.g., ConstVal
|
||||
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 literal for `value` as a `usize`.
|
||||
fn usize_literal(&mut self, value: usize) -> Literal<Self>;
|
||||
|
||||
/// Returns the type `bool`.
|
||||
fn bool_ty(&mut self) -> Self::Ty;
|
||||
|
||||
/// Returns the literal for `true`
|
||||
fn true_literal(&mut self) -> Literal<Self>;
|
||||
|
||||
/// Returns the literal for `false`
|
||||
fn false_literal(&mut self) -> Literal<Self>;
|
||||
|
||||
/// 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<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub def_id: DefId,
|
||||
pub substs: &'tcx Substs<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct ItemRef<H:Hair> {
|
||||
pub ty: H::Ty,
|
||||
pub def_id: H::DefId,
|
||||
pub substs: H::Substs,
|
||||
pub struct Block<'tcx> {
|
||||
pub extent: CodeExtent,
|
||||
pub span: Span,
|
||||
pub stmts: Vec<StmtRef<'tcx>>,
|
||||
pub expr: Option<ExprRef<'tcx>>,
|
||||
}
|
||||
|
||||
#[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>>,
|
||||
pub enum StmtRef<'tcx> {
|
||||
Hair(&'tcx hir::Stmt),
|
||||
Mirror(Box<Stmt<'tcx>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StmtRef<H:Hair> {
|
||||
Hair(H::Stmt),
|
||||
Mirror(Box<Stmt<H>>),
|
||||
pub struct Stmt<'tcx> {
|
||||
pub span: Span,
|
||||
pub kind: StmtKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Stmt<H:Hair> {
|
||||
pub span: H::Span,
|
||||
pub kind: StmtKind<H>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum StmtKind<H:Hair> {
|
||||
pub enum StmtKind<'tcx> {
|
||||
Expr {
|
||||
/// scope for this statement; may be used as lifetime of temporaries
|
||||
scope: H::CodeExtent,
|
||||
scope: CodeExtent,
|
||||
|
||||
/// expression being evaluated in this statement
|
||||
expr: ExprRef<H>
|
||||
expr: ExprRef<'tcx>
|
||||
},
|
||||
|
||||
Let {
|
||||
/// scope for variables bound in this let; covers this and
|
||||
/// remaining statements in block
|
||||
remainder_scope: H::CodeExtent,
|
||||
remainder_scope: CodeExtent,
|
||||
|
||||
/// scope for the initialization itself; might be used as
|
||||
/// lifetime of temporaries
|
||||
init_scope: H::CodeExtent,
|
||||
init_scope: CodeExtent,
|
||||
|
||||
/// let <PAT> = ...
|
||||
pattern: PatternRef<H>,
|
||||
pattern: PatternRef<'tcx>,
|
||||
|
||||
/// let pat = <INIT> ...
|
||||
initializer: Option<ExprRef<H>>,
|
||||
initializer: Option<ExprRef<'tcx>>,
|
||||
|
||||
/// let pat = init; <STMTS>
|
||||
stmts: Vec<StmtRef<H>>
|
||||
stmts: Vec<StmtRef<'tcx>>
|
||||
},
|
||||
}
|
||||
|
||||
// The Hair trait implementor translates their expressions (`H::Expr`)
|
||||
// The Hair trait implementor translates their expressions (`&'tcx 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
|
||||
// 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
|
||||
// untranslated `H::Expr`. Note that instances of `Expr` are very
|
||||
// untranslated `&'tcx 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.
|
||||
//
|
||||
@ -162,87 +96,88 @@ pub enum StmtKind<H:Hair> {
|
||||
// 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> {
|
||||
pub struct Expr<'tcx> {
|
||||
// type of this expression
|
||||
pub ty: H::Ty,
|
||||
pub ty: Ty<'tcx>,
|
||||
|
||||
// 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>,
|
||||
pub temp_lifetime: Option<CodeExtent>,
|
||||
|
||||
// span of the expression in the source
|
||||
pub span: H::Span,
|
||||
pub span: Span,
|
||||
|
||||
// kind of expression
|
||||
pub kind: ExprKind<H>,
|
||||
pub kind: ExprKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExprKind<H:Hair> {
|
||||
Scope { extent: H::CodeExtent, value: ExprRef<H> },
|
||||
Box { 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 },
|
||||
pub enum ExprKind<'tcx> {
|
||||
Scope { extent: CodeExtent, value: ExprRef<'tcx> },
|
||||
Box { value: ExprRef<'tcx> },
|
||||
Call { fun: ExprRef<'tcx>, args: Vec<ExprRef<'tcx>> },
|
||||
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> },
|
||||
Unary { op: UnOp, arg: ExprRef<'tcx> }, // NOT overloaded!
|
||||
Cast { source: ExprRef<'tcx> },
|
||||
ReifyFnPointer { source: ExprRef<'tcx> },
|
||||
UnsafeFnPointer { source: ExprRef<'tcx> },
|
||||
Unsize { source: ExprRef<'tcx> },
|
||||
If { condition: ExprRef<'tcx>, then: ExprRef<'tcx>, otherwise: Option<ExprRef<'tcx>> },
|
||||
Loop { condition: Option<ExprRef<'tcx>>, body: ExprRef<'tcx>, },
|
||||
Match { discriminant: ExprRef<'tcx>, arms: Vec<Arm<'tcx>> },
|
||||
Block { body: &'tcx hir::Block },
|
||||
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: ast::NodeId },
|
||||
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,
|
||||
StaticRef { id: DefId },
|
||||
Borrow { region: Region, borrow_kind: BorrowKind, arg: ExprRef<'tcx> },
|
||||
Break { label: Option<CodeExtent> },
|
||||
Continue { label: Option<CodeExtent> },
|
||||
Return { value: Option<ExprRef<'tcx>> },
|
||||
Repeat { value: ExprRef<'tcx>, count: ExprRef<'tcx> },
|
||||
Vec { fields: Vec<ExprRef<'tcx>> },
|
||||
Tuple { fields: Vec<ExprRef<'tcx>> },
|
||||
Adt { adt_def: AdtDef<'tcx>,
|
||||
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 },
|
||||
substs: &'tcx Substs<'tcx>,
|
||||
fields: Vec<FieldExprRef<'tcx>>,
|
||||
base: Option<ExprRef<'tcx>> },
|
||||
Closure { closure_id: DefId,
|
||||
substs: &'tcx ClosureSubsts<'tcx>,
|
||||
upvars: Vec<ExprRef<'tcx>> },
|
||||
Literal { literal: Literal<'tcx> },
|
||||
InlineAsm { asm: &'tcx hir::InlineAsm },
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum ExprRef<H:Hair> {
|
||||
Hair(H::Expr),
|
||||
Mirror(Box<Expr<H>>),
|
||||
pub enum ExprRef<'tcx> {
|
||||
Hair(&'tcx hir::Expr),
|
||||
Mirror(Box<Expr<'tcx>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FieldExprRef<H:Hair> {
|
||||
pub name: Field<H>,
|
||||
pub expr: ExprRef<H>,
|
||||
pub struct FieldExprRef<'tcx> {
|
||||
pub name: Field,
|
||||
pub expr: ExprRef<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Arm<H:Hair> {
|
||||
pub patterns: Vec<PatternRef<H>>,
|
||||
pub guard: Option<ExprRef<H>>,
|
||||
pub body: ExprRef<H>,
|
||||
pub struct Arm<'tcx> {
|
||||
pub patterns: Vec<PatternRef<'tcx>>,
|
||||
pub guard: Option<ExprRef<'tcx>>,
|
||||
pub body: ExprRef<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct Pattern<H:Hair> {
|
||||
pub ty: H::Ty,
|
||||
pub span: H::Span,
|
||||
pub kind: PatternKind<H>,
|
||||
pub struct Pattern<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
pub span: Span,
|
||||
pub kind: PatternKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
@ -252,89 +187,93 @@ pub enum LogicalOp {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PatternKind<H:Hair> {
|
||||
pub enum PatternKind<'tcx> {
|
||||
Wild,
|
||||
|
||||
// x, ref x, x @ P, etc
|
||||
Binding { mutability: Mutability,
|
||||
name: H::Name,
|
||||
mode: BindingMode<H>,
|
||||
var: H::VarId,
|
||||
ty: H::Ty,
|
||||
subpattern: Option<PatternRef<H>> },
|
||||
name: ast::Name,
|
||||
mode: BindingMode,
|
||||
var: ast::NodeId,
|
||||
ty: Ty<'tcx>,
|
||||
subpattern: Option<PatternRef<'tcx>> },
|
||||
|
||||
// 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>> },
|
||||
Variant { adt_def: AdtDef<'tcx>,
|
||||
variant_index: usize,
|
||||
subpatterns: Vec<FieldPatternRef<'tcx>> },
|
||||
|
||||
// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
|
||||
Leaf { subpatterns: Vec<FieldPatternRef<H>> },
|
||||
Leaf { subpatterns: Vec<FieldPatternRef<'tcx>> },
|
||||
|
||||
Deref { subpattern: PatternRef<H> }, // box P, &P, &mut P, etc
|
||||
Deref { subpattern: PatternRef<'tcx> }, // box P, &P, &mut P, etc
|
||||
|
||||
Constant { value: Literal<H> },
|
||||
Constant { value: Literal<'tcx> },
|
||||
|
||||
Range { lo: Literal<H>, hi: Literal<H> },
|
||||
Range { lo: Literal<'tcx>, hi: Literal<'tcx> },
|
||||
|
||||
// matches against a slice, checking the length and extracting elements
|
||||
Slice { prefix: Vec<PatternRef<H>>,
|
||||
slice: Option<PatternRef<H>>,
|
||||
suffix: Vec<PatternRef<H>> },
|
||||
Slice { prefix: Vec<PatternRef<'tcx>>,
|
||||
slice: Option<PatternRef<'tcx>>,
|
||||
suffix: Vec<PatternRef<'tcx>> },
|
||||
|
||||
// fixed match against an array, irrefutable
|
||||
Array { prefix: Vec<PatternRef<H>>,
|
||||
slice: Option<PatternRef<H>>,
|
||||
suffix: Vec<PatternRef<H>> },
|
||||
Array { prefix: Vec<PatternRef<'tcx>>,
|
||||
slice: Option<PatternRef<'tcx>>,
|
||||
suffix: Vec<PatternRef<'tcx>> },
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug)]
|
||||
pub enum BindingMode<H:Hair> {
|
||||
pub enum BindingMode {
|
||||
ByValue,
|
||||
ByRef(H::Region, BorrowKind),
|
||||
ByRef(Region, BorrowKind),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub enum PatternRef<H:Hair> {
|
||||
Hair(H::Pattern),
|
||||
Mirror(Box<Pattern<H>>),
|
||||
pub enum PatternRef<'tcx> {
|
||||
Hair(PatNode<'tcx>),
|
||||
Mirror(Box<Pattern<'tcx>>),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct FieldPatternRef<H:Hair> {
|
||||
pub field: Field<H>,
|
||||
pub pattern: PatternRef<H>,
|
||||
pub struct FieldPatternRef<'tcx> {
|
||||
pub field: Field,
|
||||
pub pattern: PatternRef<'tcx>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// 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> {
|
||||
/// "Mirroring" is the process of converting from a HIR type into one
|
||||
/// of the HAIR 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 Hair nodes, which lets the Hair nodes be
|
||||
/// simpler.
|
||||
pub trait Mirror<'tcx> {
|
||||
type Output;
|
||||
|
||||
fn make_mirror(self, hir: &mut H) -> Self::Output;
|
||||
fn make_mirror<'a>(self, cx: &mut Cx<'a,'tcx>) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for Expr<H> {
|
||||
type Output = Expr<H>;
|
||||
impl<'tcx> Mirror<'tcx> for Expr<'tcx> {
|
||||
type Output = Expr<'tcx>;
|
||||
|
||||
fn make_mirror(self, _: &mut H) -> Expr<H> {
|
||||
fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Expr<'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for ExprRef<H> {
|
||||
type Output = Expr<H>;
|
||||
impl<'tcx> Mirror<'tcx> for ExprRef<'tcx> {
|
||||
type Output = Expr<'tcx>;
|
||||
|
||||
fn make_mirror(self, hir: &mut H) -> Expr<H> {
|
||||
fn make_mirror<'a>(self, hir: &mut Cx<'a,'tcx>) -> Expr<'tcx> {
|
||||
match self {
|
||||
ExprRef::Hair(h) => h.make_mirror(hir),
|
||||
ExprRef::Mirror(m) => *m,
|
||||
@ -342,18 +281,18 @@ impl<H:Hair> Mirror<H> for ExprRef<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for Stmt<H> {
|
||||
type Output = Stmt<H>;
|
||||
impl<'tcx> Mirror<'tcx> for Stmt<'tcx> {
|
||||
type Output = Stmt<'tcx>;
|
||||
|
||||
fn make_mirror(self, _: &mut H) -> Stmt<H> {
|
||||
fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Stmt<'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for StmtRef<H> {
|
||||
type Output = Stmt<H>;
|
||||
impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
|
||||
type Output = Stmt<'tcx>;
|
||||
|
||||
fn make_mirror(self, hir: &mut H) -> Stmt<H> {
|
||||
fn make_mirror<'a>(self, hir: &mut Cx<'a,'tcx>) -> Stmt<'tcx> {
|
||||
match self {
|
||||
StmtRef::Hair(h) => h.make_mirror(hir),
|
||||
StmtRef::Mirror(m) => *m,
|
||||
@ -361,18 +300,18 @@ impl<H:Hair> Mirror<H> for StmtRef<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for Pattern<H> {
|
||||
type Output = Pattern<H>;
|
||||
impl<'tcx> Mirror<'tcx> for Pattern<'tcx> {
|
||||
type Output = Pattern<'tcx>;
|
||||
|
||||
fn make_mirror(self, _: &mut H) -> Pattern<H> {
|
||||
fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Pattern<'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for PatternRef<H> {
|
||||
type Output = Pattern<H>;
|
||||
impl<'tcx> Mirror<'tcx> for PatternRef<'tcx> {
|
||||
type Output = Pattern<'tcx>;
|
||||
|
||||
fn make_mirror(self, hir: &mut H) -> Pattern<H> {
|
||||
fn make_mirror<'a>(self, hir: &mut Cx<'a,'tcx>) -> Pattern<'tcx> {
|
||||
match self {
|
||||
PatternRef::Hair(h) => h.make_mirror(hir),
|
||||
PatternRef::Mirror(m) => *m,
|
||||
@ -380,10 +319,10 @@ impl<H:Hair> Mirror<H> for PatternRef<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Mirror<H> for Block<H> {
|
||||
type Output = Block<H>;
|
||||
impl<'tcx> Mirror<'tcx> for Block<'tcx> {
|
||||
type Output = Block<'tcx>;
|
||||
|
||||
fn make_mirror(self, _: &mut H) -> Block<H> {
|
||||
fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Block<'tcx> {
|
||||
self
|
||||
}
|
||||
}
|
||||
|
@ -24,10 +24,13 @@ Rust MIR: a lowered representation of Rust. Also: an experiment!
|
||||
|
||||
#[macro_use] extern crate log;
|
||||
extern crate graphviz as dot;
|
||||
extern crate rustc;
|
||||
extern crate rustc_data_structures;
|
||||
extern crate rustc_front;
|
||||
extern crate syntax;
|
||||
|
||||
pub mod build;
|
||||
pub mod dump;
|
||||
pub mod mir_map;
|
||||
pub mod hair;
|
||||
pub mod repr;
|
||||
mod graphviz;
|
||||
|
@ -30,15 +30,22 @@ use self::rustc::middle::infer;
|
||||
use self::rustc::middle::region::CodeExtentData;
|
||||
use self::rustc::middle::ty::{self, Ty};
|
||||
use self::rustc::util::common::ErrorReported;
|
||||
use self::rustc::util::nodemap::NodeMap;
|
||||
use self::rustc_front::hir;
|
||||
use self::rustc_front::visit;
|
||||
use self::syntax::ast;
|
||||
use self::syntax::attr::AttrMetaMethods;
|
||||
use self::syntax::codemap::Span;
|
||||
|
||||
pub fn dump_crate(tcx: &ty::ctxt) {
|
||||
let mut dump = OuterDump { tcx: tcx };
|
||||
visit::walk_crate(&mut dump, tcx.map.krate());
|
||||
pub type MirMap<'tcx> = NodeMap<Mir<'tcx>>;
|
||||
|
||||
pub fn build_mir_for_crate<'tcx>(tcx: &ty::ctxt<'tcx>) -> MirMap<'tcx>{
|
||||
let mut map = NodeMap();
|
||||
{
|
||||
let mut dump = OuterDump { tcx: tcx, map: &mut map };
|
||||
visit::walk_crate(&mut dump, tcx.map.krate());
|
||||
}
|
||||
map
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -46,27 +53,20 @@ pub fn dump_crate(tcx: &ty::ctxt) {
|
||||
|
||||
struct OuterDump<'a,'tcx:'a> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
map: &'a mut MirMap<'tcx>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> OuterDump<'a, 'tcx> {
|
||||
fn visit_mir<OP>(&self, attributes: &'tcx [ast::Attribute], mut walk_op: OP)
|
||||
where OP: FnMut(&mut InnerDump<'a,'tcx>)
|
||||
fn visit_mir<OP>(&mut self, attributes: &'a [ast::Attribute], mut walk_op: OP)
|
||||
where OP: for<'m> FnMut(&mut InnerDump<'a,'m,'tcx>)
|
||||
{
|
||||
let mut built_mir = false;
|
||||
|
||||
let mut closure_dump = InnerDump { tcx: self.tcx, attr: None, map: &mut *self.map };
|
||||
for attr in attributes {
|
||||
if attr.check_name("rustc_mir") {
|
||||
let mut closure_dump = InnerDump { tcx: self.tcx, attr: Some(attr) };
|
||||
walk_op(&mut closure_dump);
|
||||
built_mir = true;
|
||||
closure_dump.attr = Some(attr);
|
||||
}
|
||||
}
|
||||
|
||||
let always_build_mir = true;
|
||||
if !built_mir && always_build_mir {
|
||||
let mut closure_dump = InnerDump { tcx: self.tcx, attr: None };
|
||||
walk_op(&mut closure_dump);
|
||||
}
|
||||
walk_op(&mut closure_dump);
|
||||
}
|
||||
}
|
||||
|
||||
@ -82,25 +82,47 @@ impl<'a, 'tcx> visit::Visitor<'tcx> for OuterDump<'a, 'tcx> {
|
||||
hir::MethodTraitItem(_, Some(_)) => {
|
||||
self.visit_mir(&trait_item.attrs, |c| visit::walk_trait_item(c, trait_item));
|
||||
}
|
||||
_ => { }
|
||||
hir::MethodTraitItem(_, None) |
|
||||
hir::ConstTraitItem(..) |
|
||||
hir::TypeTraitItem(..) => {
|
||||
}
|
||||
}
|
||||
visit::walk_trait_item(self, trait_item);
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, impl_item: &'tcx hir::ImplItem) {
|
||||
match impl_item.node {
|
||||
hir::MethodImplItem(..) => {
|
||||
self.visit_mir(&impl_item.attrs, |c| visit::walk_impl_item(c, impl_item));
|
||||
}
|
||||
hir::ConstImplItem(..) | hir::TypeImplItem(..) => { }
|
||||
}
|
||||
visit::walk_impl_item(self, impl_item);
|
||||
}
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// InnerDump -- dumps MIR for a single fn and its contained closures
|
||||
|
||||
struct InnerDump<'a,'tcx:'a> {
|
||||
struct InnerDump<'a,'m,'tcx:'a+'m> {
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
map: &'m mut MirMap<'tcx>,
|
||||
attr: Option<&'a ast::Attribute>,
|
||||
}
|
||||
|
||||
impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> {
|
||||
impl<'a, 'm, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'m,'tcx> {
|
||||
fn visit_item(&mut self, _: &'tcx hir::Item) {
|
||||
// ignore nested items; they need their own graphviz annotation
|
||||
}
|
||||
|
||||
fn visit_trait_item(&mut self, _: &'tcx hir::TraitItem) {
|
||||
// ignore nested items; they need their own graphviz annotation
|
||||
}
|
||||
|
||||
fn visit_impl_item(&mut self, _: &'tcx hir::ImplItem) {
|
||||
// ignore nested items; they need their own graphviz annotation
|
||||
}
|
||||
|
||||
fn visit_fn(&mut self,
|
||||
fk: visit::FnKind<'tcx>,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
@ -155,6 +177,9 @@ impl<'a, 'tcx> visit::Visitor<'tcx> for InnerDump<'a,'tcx> {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
let previous = self.map.insert(id, mir);
|
||||
assert!(previous.is_none());
|
||||
}
|
||||
Err(ErrorReported) => { }
|
||||
}
|
||||
@ -169,18 +194,18 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
|
||||
span: Span,
|
||||
decl: &'tcx hir::FnDecl,
|
||||
body: &'tcx hir::Block)
|
||||
-> Result<Mir<Cx<'a,'tcx>>, ErrorReported> {
|
||||
-> Result<Mir<'tcx>, ErrorReported> {
|
||||
let arguments =
|
||||
decl.inputs
|
||||
.iter()
|
||||
.map(|arg| {
|
||||
let ty = cx.tcx.node_id_to_type(arg.id);
|
||||
let ty = cx.tcx().node_id_to_type(arg.id);
|
||||
(ty, PatNode::irrefutable(&arg.pat))
|
||||
})
|
||||
.collect();
|
||||
|
||||
let parameter_scope =
|
||||
cx.tcx.region_maps.lookup_code_extent(
|
||||
cx.tcx().region_maps.lookup_code_extent(
|
||||
CodeExtentData::ParameterScope { fn_id: fn_id, body_id: body.id });
|
||||
Ok(build::construct(cx,
|
||||
span,
|
@ -8,22 +8,29 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
use hair::Hair;
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::subst::Substs;
|
||||
use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use rustc_front::hir::InlineAsm;
|
||||
use syntax::ast::Name;
|
||||
use syntax::codemap::Span;
|
||||
use std::fmt::{Debug, Formatter, Error};
|
||||
use std::slice;
|
||||
use std::u32;
|
||||
|
||||
/// Lowered representation of a single function.
|
||||
pub struct Mir<H:Hair> {
|
||||
pub basic_blocks: Vec<BasicBlockData<H>>,
|
||||
pub struct Mir<'tcx> {
|
||||
pub basic_blocks: Vec<BasicBlockData<'tcx>>,
|
||||
|
||||
// for every node id
|
||||
pub extents: FnvHashMap<H::CodeExtent, Vec<GraphExtent>>,
|
||||
pub extents: FnvHashMap<CodeExtent, Vec<GraphExtent>>,
|
||||
|
||||
pub var_decls: Vec<VarDecl<H>>,
|
||||
pub arg_decls: Vec<ArgDecl<H>>,
|
||||
pub temp_decls: Vec<TempDecl<H>>,
|
||||
pub var_decls: Vec<VarDecl<'tcx>>,
|
||||
pub arg_decls: Vec<ArgDecl<'tcx>>,
|
||||
pub temp_decls: Vec<TempDecl<'tcx>>,
|
||||
}
|
||||
|
||||
/// where execution begins
|
||||
@ -35,18 +42,18 @@ pub const END_BLOCK: BasicBlock = BasicBlock(1);
|
||||
/// where execution ends, on panic
|
||||
pub const DIVERGE_BLOCK: BasicBlock = BasicBlock(2);
|
||||
|
||||
impl<H:Hair> Mir<H> {
|
||||
impl<'tcx> Mir<'tcx> {
|
||||
pub fn all_basic_blocks(&self) -> Vec<BasicBlock> {
|
||||
(0..self.basic_blocks.len())
|
||||
.map(|i| BasicBlock::new(i))
|
||||
.collect()
|
||||
}
|
||||
|
||||
pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<H> {
|
||||
pub fn basic_block_data(&self, bb: BasicBlock) -> &BasicBlockData<'tcx> {
|
||||
&self.basic_blocks[bb.index()]
|
||||
}
|
||||
|
||||
pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<H> {
|
||||
pub fn basic_block_data_mut(&mut self, bb: BasicBlock) -> &mut BasicBlockData<'tcx> {
|
||||
&mut self.basic_blocks[bb.index()]
|
||||
}
|
||||
}
|
||||
@ -111,16 +118,16 @@ pub enum BorrowKind {
|
||||
|
||||
// A "variable" is a binding declared by the user as part of the fn
|
||||
// decl, a let, etc.
|
||||
pub struct VarDecl<H:Hair> {
|
||||
pub struct VarDecl<'tcx> {
|
||||
pub mutability: Mutability,
|
||||
pub name: H::Name,
|
||||
pub ty: H::Ty,
|
||||
pub name: Name,
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
// A "temp" is a temporary that we place on the stack. They are
|
||||
// anonymous, always mutable, and have only a type.
|
||||
pub struct TempDecl<H:Hair> {
|
||||
pub ty: H::Ty,
|
||||
pub struct TempDecl<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
// A "arg" is one of the function's formal arguments. These are
|
||||
@ -134,8 +141,8 @@ pub struct TempDecl<H:Hair> {
|
||||
//
|
||||
// there is only one argument, of type `(i32, u32)`, but two bindings
|
||||
// (`x` and `y`).
|
||||
pub struct ArgDecl<H:Hair> {
|
||||
pub ty: H::Ty,
|
||||
pub struct ArgDecl<'tcx> {
|
||||
pub ty: Ty<'tcx>,
|
||||
}
|
||||
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
@ -212,12 +219,12 @@ impl Debug for BasicBlock {
|
||||
// BasicBlock and Terminator
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct BasicBlockData<H:Hair> {
|
||||
pub statements: Vec<Statement<H>>,
|
||||
pub terminator: Terminator<H>,
|
||||
pub struct BasicBlockData<'tcx> {
|
||||
pub statements: Vec<Statement<'tcx>>,
|
||||
pub terminator: Terminator<'tcx>,
|
||||
}
|
||||
|
||||
pub enum Terminator<H:Hair> {
|
||||
pub enum Terminator<'tcx> {
|
||||
/// block should have one successor in the graph; we jump there
|
||||
Goto { target: BasicBlock },
|
||||
|
||||
@ -226,10 +233,10 @@ pub enum Terminator<H:Hair> {
|
||||
Panic { target: BasicBlock },
|
||||
|
||||
/// jump to branch 0 if this lvalue evaluates to true
|
||||
If { cond: Operand<H>, targets: [BasicBlock; 2] },
|
||||
If { cond: Operand<'tcx>, targets: [BasicBlock; 2] },
|
||||
|
||||
/// lvalue evaluates to some enum; jump depending on the branch
|
||||
Switch { discr: Lvalue<H>, targets: Vec<BasicBlock> },
|
||||
Switch { discr: Lvalue<'tcx>, targets: Vec<BasicBlock> },
|
||||
|
||||
/// Indicates that the last statement in the block panics, aborts,
|
||||
/// etc. No successors. This terminator appears on exactly one
|
||||
@ -247,10 +254,10 @@ pub enum Terminator<H:Hair> {
|
||||
/// block ends with a call; it should have two successors. The
|
||||
/// first successor indicates normal return. The second indicates
|
||||
/// unwinding.
|
||||
Call { data: CallData<H>, targets: [BasicBlock; 2] },
|
||||
Call { data: CallData<'tcx>, targets: [BasicBlock; 2] },
|
||||
}
|
||||
|
||||
impl<H:Hair> Terminator<H> {
|
||||
impl<'tcx> Terminator<'tcx> {
|
||||
pub fn successors(&self) -> &[BasicBlock] {
|
||||
use self::Terminator::*;
|
||||
match *self {
|
||||
@ -266,19 +273,19 @@ impl<H:Hair> Terminator<H> {
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub struct CallData<H:Hair> {
|
||||
pub struct CallData<'tcx> {
|
||||
/// where the return value is written to
|
||||
pub destination: Lvalue<H>,
|
||||
pub destination: Lvalue<'tcx>,
|
||||
|
||||
/// the fn being called
|
||||
pub func: Lvalue<H>,
|
||||
pub func: Lvalue<'tcx>,
|
||||
|
||||
/// the arguments
|
||||
pub args: Vec<Lvalue<H>>,
|
||||
pub args: Vec<Lvalue<'tcx>>,
|
||||
}
|
||||
|
||||
impl<H:Hair> BasicBlockData<H> {
|
||||
pub fn new(terminator: Terminator<H>) -> BasicBlockData<H> {
|
||||
impl<'tcx> BasicBlockData<'tcx> {
|
||||
pub fn new(terminator: Terminator<'tcx>) -> BasicBlockData<'tcx> {
|
||||
BasicBlockData {
|
||||
statements: vec![],
|
||||
terminator: terminator,
|
||||
@ -286,7 +293,7 @@ impl<H:Hair> BasicBlockData<H> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Debug for Terminator<H> {
|
||||
impl<'tcx> Debug for Terminator<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
use self::Terminator::*;
|
||||
match *self {
|
||||
@ -318,15 +325,15 @@ impl<H:Hair> Debug for Terminator<H> {
|
||||
///////////////////////////////////////////////////////////////////////////
|
||||
// Statements
|
||||
|
||||
pub struct Statement<H:Hair> {
|
||||
pub span: H::Span,
|
||||
pub kind: StatementKind<H>,
|
||||
pub struct Statement<'tcx> {
|
||||
pub span: Span,
|
||||
pub kind: StatementKind<'tcx>,
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
pub enum StatementKind<H:Hair> {
|
||||
Assign(Lvalue<H>, Rvalue<H>),
|
||||
Drop(DropKind, Lvalue<H>),
|
||||
pub enum StatementKind<'tcx> {
|
||||
Assign(Lvalue<'tcx>, Rvalue<'tcx>),
|
||||
Drop(DropKind, Lvalue<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@ -335,7 +342,7 @@ pub enum DropKind {
|
||||
Deep
|
||||
}
|
||||
|
||||
impl<H:Hair> Debug for Statement<H> {
|
||||
impl<'tcx> Debug for Statement<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
use self::StatementKind::*;
|
||||
match self.kind {
|
||||
@ -351,7 +358,7 @@ impl<H:Hair> Debug for Statement<H> {
|
||||
/// A path to a value; something that can be evaluated without
|
||||
/// changing or disturbing program state.
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Lvalue<H:Hair> {
|
||||
pub enum Lvalue<'tcx> {
|
||||
/// local variable declared by the user
|
||||
Var(u32),
|
||||
|
||||
@ -363,13 +370,13 @@ pub enum Lvalue<H:Hair> {
|
||||
Arg(u32),
|
||||
|
||||
/// static or static mut variable
|
||||
Static(H::DefId),
|
||||
Static(DefId),
|
||||
|
||||
/// the return pointer of the fn
|
||||
ReturnPointer,
|
||||
|
||||
/// projection out of an lvalue (access a field, deref a pointer, etc)
|
||||
Projection(Box<LvalueProjection<H>>)
|
||||
Projection(Box<LvalueProjection<'tcx>>)
|
||||
}
|
||||
|
||||
/// The `Projection` data structure defines things of the form `B.x`
|
||||
@ -377,15 +384,15 @@ pub enum Lvalue<H:Hair> {
|
||||
/// shared between `Constant` and `Lvalue`. See the aliases
|
||||
/// `LvalueProjection` etc below.
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Projection<H:Hair,B,V> {
|
||||
pub struct Projection<'tcx,B,V> {
|
||||
pub base: B,
|
||||
pub elem: ProjectionElem<H,V>,
|
||||
pub elem: ProjectionElem<'tcx,V>,
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum ProjectionElem<H:Hair,V> {
|
||||
pub enum ProjectionElem<'tcx,V> {
|
||||
Deref,
|
||||
Field(Field<H>),
|
||||
Field(Field),
|
||||
Index(V),
|
||||
|
||||
// These indices are generated by slice patterns. Easiest to explain
|
||||
@ -406,44 +413,44 @@ pub enum ProjectionElem<H:Hair,V> {
|
||||
// "Downcast" to a variant of an ADT. Currently, we only introduce
|
||||
// this for ADTs with more than one variant. It may be better to
|
||||
// just introduce it always, or always for enums.
|
||||
Downcast(H::AdtDef, usize),
|
||||
Downcast(AdtDef<'tcx>, usize),
|
||||
}
|
||||
|
||||
/// Alias for projections as they appear in lvalues, where the base is an lvalue
|
||||
/// and the index is an operand.
|
||||
pub type LvalueProjection<H> =
|
||||
Projection<H,Lvalue<H>,Operand<H>>;
|
||||
pub type LvalueProjection<'tcx> =
|
||||
Projection<'tcx,Lvalue<'tcx>,Operand<'tcx>>;
|
||||
|
||||
/// Alias for projections as they appear in lvalues, where the base is an lvalue
|
||||
/// and the index is an operand.
|
||||
pub type LvalueElem<H> =
|
||||
ProjectionElem<H,Operand<H>>;
|
||||
pub type LvalueElem<'tcx> =
|
||||
ProjectionElem<'tcx,Operand<'tcx>>;
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)]
|
||||
pub enum Field<H:Hair> {
|
||||
Named(H::Name),
|
||||
pub enum Field {
|
||||
Named(Name),
|
||||
Indexed(usize),
|
||||
}
|
||||
|
||||
impl<H:Hair> Lvalue<H> {
|
||||
pub fn field(self, f: Field<H>) -> Lvalue<H> {
|
||||
impl<'tcx> Lvalue<'tcx> {
|
||||
pub fn field(self, f: Field) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Field(f))
|
||||
}
|
||||
|
||||
pub fn deref(self) -> Lvalue<H> {
|
||||
pub fn deref(self) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Deref)
|
||||
}
|
||||
|
||||
pub fn index(self, index: Operand<H>) -> Lvalue<H> {
|
||||
pub fn index(self, index: Operand<'tcx>) -> Lvalue<'tcx> {
|
||||
self.elem(ProjectionElem::Index(index))
|
||||
}
|
||||
|
||||
pub fn elem(self, elem: LvalueElem<H>) -> Lvalue<H> {
|
||||
pub fn elem(self, elem: LvalueElem<'tcx>) -> Lvalue<'tcx> {
|
||||
Lvalue::Projection(Box::new(LvalueProjection { base: self, elem: elem }))
|
||||
}
|
||||
}
|
||||
|
||||
impl<H:Hair> Debug for Lvalue<H> {
|
||||
impl<'tcx> Debug for Lvalue<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
use self::Lvalue::*;
|
||||
|
||||
@ -487,12 +494,12 @@ impl<H:Hair> Debug for Lvalue<H> {
|
||||
// being nested in one another.
|
||||
|
||||
#[derive(Clone, PartialEq)]
|
||||
pub enum Operand<H:Hair> {
|
||||
Consume(Lvalue<H>),
|
||||
Constant(Constant<H>),
|
||||
pub enum Operand<'tcx> {
|
||||
Consume(Lvalue<'tcx>),
|
||||
Constant(Constant<'tcx>),
|
||||
}
|
||||
|
||||
impl<H:Hair> Debug for Operand<H> {
|
||||
impl<'tcx> Debug for Operand<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
use self::Operand::*;
|
||||
match *self {
|
||||
@ -506,34 +513,34 @@ impl<H:Hair> Debug for Operand<H> {
|
||||
// Rvalues
|
||||
|
||||
#[derive(Clone)]
|
||||
pub enum Rvalue<H:Hair> {
|
||||
pub enum Rvalue<'tcx> {
|
||||
// x (either a move or copy, depending on type of x)
|
||||
Use(Operand<H>),
|
||||
Use(Operand<'tcx>),
|
||||
|
||||
// [x; 32]
|
||||
Repeat(Operand<H>, Operand<H>),
|
||||
Repeat(Operand<'tcx>, Operand<'tcx>),
|
||||
|
||||
// &x or &mut x
|
||||
Ref(H::Region, BorrowKind, Lvalue<H>),
|
||||
Ref(Region, BorrowKind, Lvalue<'tcx>),
|
||||
|
||||
// length of a [X] or [X;n] value
|
||||
Len(Lvalue<H>),
|
||||
Len(Lvalue<'tcx>),
|
||||
|
||||
Cast(CastKind, Operand<H>, H::Ty),
|
||||
Cast(CastKind, Operand<'tcx>, Ty<'tcx>),
|
||||
|
||||
BinaryOp(BinOp, Operand<H>, Operand<H>),
|
||||
BinaryOp(BinOp, Operand<'tcx>, Operand<'tcx>),
|
||||
|
||||
UnaryOp(UnOp, Operand<H>),
|
||||
UnaryOp(UnOp, Operand<'tcx>),
|
||||
|
||||
// Creates an *uninitialized* Box
|
||||
Box(H::Ty),
|
||||
Box(Ty<'tcx>),
|
||||
|
||||
// Create an aggregate value, like a tuple or struct. This is
|
||||
// only needed because we want to distinguish `dest = Foo { x:
|
||||
// ..., y: ... }` from `dest.x = ...; dest.y = ...;` in the case
|
||||
// that `Foo` has a destructor. These rvalues can be optimized
|
||||
// away after type-checking and before lowering.
|
||||
Aggregate(AggregateKind<H>, Vec<Operand<H>>),
|
||||
Aggregate(AggregateKind<'tcx>, Vec<Operand<'tcx>>),
|
||||
|
||||
// Generates a slice of the form `&input[from_start..L-from_end]`
|
||||
// where `L` is the length of the slice. This is only created by
|
||||
@ -541,12 +548,12 @@ pub enum Rvalue<H:Hair> {
|
||||
// .., z]` might create a slice with `from_start=2` and
|
||||
// `from_end=1`.
|
||||
Slice {
|
||||
input: Lvalue<H>,
|
||||
input: Lvalue<'tcx>,
|
||||
from_start: usize,
|
||||
from_end: usize,
|
||||
},
|
||||
|
||||
InlineAsm(H::InlineAsm),
|
||||
InlineAsm(&'tcx InlineAsm),
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
@ -568,11 +575,11 @@ pub enum CastKind {
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq, Eq)]
|
||||
pub enum AggregateKind<H:Hair> {
|
||||
pub enum AggregateKind<'tcx> {
|
||||
Vec,
|
||||
Tuple,
|
||||
Adt(H::AdtDef, usize, H::Substs),
|
||||
Closure(H::DefId, H::ClosureSubsts),
|
||||
Adt(AdtDef<'tcx>, usize, &'tcx Substs<'tcx>),
|
||||
Closure(DefId, &'tcx ClosureSubsts<'tcx>),
|
||||
}
|
||||
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
@ -619,7 +626,7 @@ pub enum UnOp {
|
||||
Neg
|
||||
}
|
||||
|
||||
impl<H:Hair> Debug for Rvalue<H> {
|
||||
impl<'tcx> Debug for Rvalue<'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
use self::Rvalue::*;
|
||||
|
||||
@ -648,15 +655,15 @@ impl<H:Hair> Debug for Rvalue<H> {
|
||||
// particular one must be wary of `NaN`!
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub struct Constant<H:Hair> {
|
||||
pub span: H::Span,
|
||||
pub ty: H::Ty,
|
||||
pub literal: Literal<H>
|
||||
pub struct Constant<'tcx> {
|
||||
pub span: Span,
|
||||
pub ty: Ty<'tcx>,
|
||||
pub literal: Literal<'tcx>
|
||||
}
|
||||
|
||||
#[derive(Clone, Debug, PartialEq)]
|
||||
pub enum Literal<H:Hair> {
|
||||
Item { def_id: H::DefId, substs: H::Substs },
|
||||
Value { value: H::ConstVal },
|
||||
pub enum Literal<'tcx> {
|
||||
Item { def_id: DefId, substs: &'tcx Substs<'tcx> },
|
||||
Value { value: ConstVal },
|
||||
}
|
||||
|
||||
|
@ -12,16 +12,16 @@ use hair::*;
|
||||
|
||||
use tcx::Cx;
|
||||
use tcx::pattern::PatNode;
|
||||
use tcx::rustc::middle::region::{BlockRemainder, CodeExtentData};
|
||||
use tcx::rustc_front::hir;
|
||||
use tcx::syntax::ast;
|
||||
use tcx::syntax::ptr::P;
|
||||
use tcx::to_ref::ToRef;
|
||||
use rustc::middle::region::{BlockRemainder, CodeExtentData};
|
||||
use rustc_front::hir;
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
|
||||
impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Block {
|
||||
type Output = Block<Cx<'a,'tcx>>;
|
||||
impl<'tcx> Mirror<'tcx> for &'tcx hir::Block {
|
||||
type Output = Block<'tcx>;
|
||||
|
||||
fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Block<Cx<'a,'tcx>> {
|
||||
fn make_mirror<'a>(self, cx: &mut Cx<'a,'tcx>) -> Block<'tcx> {
|
||||
// We have to eagerly translate the "spine" of the statements
|
||||
// in order to get the lexical scoping correctly.
|
||||
let stmts = mirror_stmts(cx, self.id, self.stmts.iter().enumerate());
|
||||
@ -34,10 +34,10 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Block {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Stmt {
|
||||
type Output = Stmt<Cx<'a,'tcx>>;
|
||||
impl<'tcx> Mirror<'tcx> for &'tcx hir::Stmt {
|
||||
type Output = Stmt<'tcx>;
|
||||
|
||||
fn make_mirror(self, _cx: &mut Cx<'a,'tcx>) -> Stmt<Cx<'a,'tcx>> {
|
||||
fn make_mirror<'a>(self, _cx: &mut Cx<'a,'tcx>) -> Stmt<'tcx> {
|
||||
// In order to get the scoping correct, we eagerly mirror
|
||||
// statements when we translate the enclosing block, so we
|
||||
// should in fact never get to this point.
|
||||
@ -48,7 +48,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Stmt {
|
||||
fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
|
||||
block_id: ast::NodeId,
|
||||
mut stmts: STMTS)
|
||||
-> Vec<StmtRef<Cx<'a,'tcx>>>
|
||||
-> Vec<StmtRef<'tcx>>
|
||||
where STMTS: Iterator<Item=(usize, &'tcx P<hir::Stmt>)>
|
||||
{
|
||||
let mut result = vec![];
|
||||
@ -101,7 +101,7 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
|
||||
|
||||
pub fn to_expr_ref<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
block: &'tcx hir::Block)
|
||||
-> ExprRef<Cx<'a, 'tcx>> {
|
||||
-> ExprRef<'tcx> {
|
||||
let block_ty = cx.tcx.node_id_to_type(block.id);
|
||||
let temp_lifetime = cx.tcx.region_maps.temporary_scope(block.id);
|
||||
let expr = Expr {
|
||||
|
@ -15,22 +15,22 @@ use std::rc::Rc;
|
||||
use tcx::Cx;
|
||||
use tcx::block;
|
||||
use tcx::pattern::PatNode;
|
||||
use tcx::rustc::front::map;
|
||||
use tcx::rustc::middle::const_eval;
|
||||
use tcx::rustc::middle::def;
|
||||
use tcx::rustc::middle::region::CodeExtent;
|
||||
use tcx::rustc::middle::pat_util;
|
||||
use tcx::rustc::middle::ty::{self, Ty};
|
||||
use tcx::rustc_front::hir;
|
||||
use tcx::rustc_front::util as hir_util;
|
||||
use tcx::syntax::parse::token;
|
||||
use tcx::syntax::ptr::P;
|
||||
use tcx::to_ref::ToRef;
|
||||
use rustc::front::map;
|
||||
use rustc::middle::const_eval;
|
||||
use rustc::middle::def;
|
||||
use rustc::middle::region::CodeExtent;
|
||||
use rustc::middle::pat_util;
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use rustc_front::hir;
|
||||
use rustc_front::util as hir_util;
|
||||
use syntax::parse::token;
|
||||
use syntax::ptr::P;
|
||||
|
||||
impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
|
||||
type Output = Expr<Cx<'a,'tcx>>;
|
||||
impl<'tcx> Mirror<'tcx> for &'tcx hir::Expr {
|
||||
type Output = Expr<'tcx>;
|
||||
|
||||
fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Expr<Cx<'a,'tcx>> {
|
||||
fn make_mirror<'a>(self, cx: &mut Cx<'a,'tcx>) -> Expr<'tcx> {
|
||||
debug!("Expr::make_mirror(): id={}, span={:?}", self.id, self.span);
|
||||
|
||||
let expr_ty = cx.tcx.expr_ty(self); // note: no adjustments (yet)!
|
||||
@ -427,7 +427,7 @@ impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for &'tcx hir::Expr {
|
||||
fn method_callee<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
expr: &hir::Expr,
|
||||
method_call: ty::MethodCall)
|
||||
-> Expr<Cx<'a,'tcx>> {
|
||||
-> Expr<'tcx> {
|
||||
let tables = cx.tcx.tables.borrow();
|
||||
let callee = &tables.method_map[&method_call];
|
||||
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
|
||||
@ -451,7 +451,7 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
|
||||
}
|
||||
}
|
||||
|
||||
fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<Cx<'a,'tcx>> {
|
||||
fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
|
||||
let map = if arm.pats.len() == 1 {
|
||||
None
|
||||
} else {
|
||||
@ -469,7 +469,7 @@ fn convert_arm<'a,'tcx:'a>(cx: &Cx<'a,'tcx>, arm: &'tcx hir::Arm) -> Arm<Cx<'a,'
|
||||
|
||||
fn convert_path_expr<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
expr: &'tcx hir::Expr)
|
||||
-> ExprKind<Cx<'a,'tcx>>
|
||||
-> ExprKind<'tcx>
|
||||
{
|
||||
let substs = cx.tcx.mk_substs(cx.tcx.node_id_item_substs(expr.id).substs);
|
||||
match cx.tcx.def_map.borrow()[&expr.id].full_def() {
|
||||
@ -502,7 +502,7 @@ fn convert_path_expr<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
fn convert_var<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
def: def::Def)
|
||||
-> ExprKind<Cx<'a,'tcx>>
|
||||
-> ExprKind<'tcx>
|
||||
{
|
||||
let temp_lifetime = cx.tcx.region_maps.temporary_scope(expr.id);
|
||||
|
||||
@ -665,9 +665,9 @@ fn overloaded_operator<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
method_call: ty::MethodCall,
|
||||
pass_args: PassArgs,
|
||||
receiver: ExprRef<Cx<'a,'tcx>>,
|
||||
receiver: ExprRef<'tcx>,
|
||||
args: Vec<&'tcx P<hir::Expr>>)
|
||||
-> ExprKind<Cx<'a,'tcx>>
|
||||
-> ExprKind<'tcx>
|
||||
{
|
||||
// the receiver has all the adjustments that are needed, so we can
|
||||
// just push a reference to it
|
||||
@ -718,9 +718,9 @@ fn overloaded_lvalue<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
expr: &'tcx hir::Expr,
|
||||
method_call: ty::MethodCall,
|
||||
pass_args: PassArgs,
|
||||
receiver: ExprRef<Cx<'a,'tcx>>,
|
||||
receiver: ExprRef<'tcx>,
|
||||
args: Vec<&'tcx P<hir::Expr>>)
|
||||
-> ExprKind<Cx<'a,'tcx>>
|
||||
-> ExprKind<'tcx>
|
||||
{
|
||||
// For an overloaded *x or x[y] expression of type T, the method
|
||||
// call returns an &T and we must add the deref so that the types
|
||||
@ -754,7 +754,7 @@ fn capture_freevar<'a,'tcx:'a>(cx: &mut Cx<'a,'tcx>,
|
||||
closure_expr: &'tcx hir::Expr,
|
||||
freevar: &ty::Freevar,
|
||||
freevar_ty: Ty<'tcx>)
|
||||
-> ExprRef<Cx<'a,'tcx>> {
|
||||
-> ExprRef<'tcx> {
|
||||
let id_var = freevar.def.var_id();
|
||||
let upvar_id = ty::UpvarId { var_id: id_var, closure_expr_id: closure_expr.id };
|
||||
let upvar_capture = cx.tcx.upvar_capture(upvar_id).unwrap();
|
||||
|
@ -8,31 +8,28 @@
|
||||
// option. This file may not be copied, modified, or distributed
|
||||
// except according to those terms.
|
||||
|
||||
/*!
|
||||
* This module contains the code to convert from the wacky tcx data
|
||||
* structures into the hair. The `builder` is generally ignorant of
|
||||
* the tcx etc, and instead goes through the `Cx` for most of its
|
||||
* work.
|
||||
*/
|
||||
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
use std::fmt::{Debug, Formatter, Error};
|
||||
use std::hash::{Hash, Hasher};
|
||||
use std::rc::Rc;
|
||||
|
||||
use self::rustc::middle::const_eval::ConstVal;
|
||||
use self::rustc::middle::def_id::DefId;
|
||||
use self::rustc::middle::infer::InferCtxt;
|
||||
use self::rustc::middle::region::CodeExtent;
|
||||
use self::rustc::middle::subst::{self, Subst, Substs};
|
||||
use self::rustc::middle::ty::{self, Ty};
|
||||
use self::rustc_front::hir;
|
||||
use self::syntax::ast;
|
||||
use self::syntax::codemap::Span;
|
||||
use self::syntax::parse::token::{self, special_idents, InternedString};
|
||||
|
||||
extern crate rustc;
|
||||
extern crate rustc_front;
|
||||
extern crate syntax;
|
||||
use rustc::middle::const_eval::ConstVal;
|
||||
use rustc::middle::def_id::DefId;
|
||||
use rustc::middle::infer::InferCtxt;
|
||||
use rustc::middle::subst::{Subst, Substs};
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use syntax::codemap::Span;
|
||||
use syntax::parse::token::{self, special_idents};
|
||||
|
||||
#[derive(Copy, Clone)]
|
||||
pub struct Cx<'a,'tcx:'a> {
|
||||
pub tcx: &'a ty::ctxt<'tcx>,
|
||||
pub infcx: &'a InferCtxt<'a,'tcx>,
|
||||
tcx: &'a ty::ctxt<'tcx>,
|
||||
infcx: &'a InferCtxt<'a,'tcx>,
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Cx<'a,'tcx> {
|
||||
@ -43,66 +40,51 @@ impl<'a,'tcx> Cx<'a,'tcx> {
|
||||
|
||||
pub use self::pattern::PatNode;
|
||||
|
||||
impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
|
||||
type VarId = ast::NodeId;
|
||||
type DefId = DefId;
|
||||
type AdtDef = ty::AdtDef<'tcx>;
|
||||
type Name = ast::Name;
|
||||
type InternedString = InternedString;
|
||||
type Bytes = Rc<Vec<u8>>;
|
||||
type Span = Span;
|
||||
type Projection = ty::ProjectionTy<'tcx>;
|
||||
type Substs = &'tcx subst::Substs<'tcx>;
|
||||
type ClosureSubsts = &'tcx ty::ClosureSubsts<'tcx>;
|
||||
type Ty = Ty<'tcx>;
|
||||
type Region = ty::Region;
|
||||
type CodeExtent = CodeExtent;
|
||||
type ConstVal = ConstVal;
|
||||
type Pattern = PatNode<'tcx>;
|
||||
type Expr = &'tcx hir::Expr;
|
||||
type Stmt = &'tcx hir::Stmt;
|
||||
type Block = &'tcx hir::Block;
|
||||
type InlineAsm = &'tcx hir::InlineAsm;
|
||||
impl<'a,'tcx:'a> Cx<'a, 'tcx> {
|
||||
/// Normalizes `ast` into the appropriate `mirror` type.
|
||||
pub fn mirror<M:Mirror<'tcx>>(&mut self, ast: M) -> M::Output {
|
||||
ast.make_mirror(self)
|
||||
}
|
||||
|
||||
fn unit_ty(&mut self) -> Ty<'tcx> {
|
||||
pub fn unit_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.mk_nil()
|
||||
}
|
||||
|
||||
fn usize_ty(&mut self) -> Ty<'tcx> {
|
||||
pub fn usize_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.types.usize
|
||||
}
|
||||
|
||||
fn usize_literal(&mut self, value: usize) -> Literal<Self> {
|
||||
pub fn usize_literal(&mut self, value: usize) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Uint(value as u64) }
|
||||
}
|
||||
|
||||
fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||
pub fn bool_ty(&mut self) -> Ty<'tcx> {
|
||||
self.tcx.types.bool
|
||||
}
|
||||
|
||||
fn true_literal(&mut self) -> Literal<Self> {
|
||||
pub fn true_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(true) }
|
||||
}
|
||||
|
||||
fn false_literal(&mut self) -> Literal<Self> {
|
||||
pub fn false_literal(&mut self) -> Literal<'tcx> {
|
||||
Literal::Value { value: ConstVal::Bool(false) }
|
||||
}
|
||||
|
||||
fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<Self> {
|
||||
pub fn partial_eq(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
|
||||
let eq_def_id = self.tcx.lang_items.eq_trait().unwrap();
|
||||
self.cmp_method_ref(eq_def_id, "eq", ty)
|
||||
}
|
||||
|
||||
fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<Self> {
|
||||
pub fn partial_le(&mut self, ty: Ty<'tcx>) -> ItemRef<'tcx> {
|
||||
let ord_def_id = self.tcx.lang_items.ord_trait().unwrap();
|
||||
self.cmp_method_ref(ord_def_id, "le", ty)
|
||||
}
|
||||
|
||||
fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
|
||||
pub fn num_variants(&mut self, adt_def: ty::AdtDef<'tcx>) -> usize {
|
||||
adt_def.variants.len()
|
||||
}
|
||||
|
||||
fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field<Self>> {
|
||||
pub fn fields(&mut self, adt_def: ty::AdtDef<'tcx>, variant_index: usize) -> Vec<Field> {
|
||||
adt_def.variants[variant_index]
|
||||
.fields
|
||||
.iter()
|
||||
@ -117,7 +99,7 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
|
||||
.collect()
|
||||
}
|
||||
|
||||
fn needs_drop(&mut self, ty: Ty<'tcx>, span: Self::Span) -> bool {
|
||||
pub fn needs_drop(&mut self, ty: Ty<'tcx>, span: Span) -> bool {
|
||||
if self.infcx.type_moves_by_default(ty, span) {
|
||||
// FIXME(#21859) we should do an add'l check here to determine if
|
||||
// any dtor will execute, but the relevant fn
|
||||
@ -130,17 +112,19 @@ impl<'a,'tcx:'a> Hair for Cx<'a, 'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
fn span_bug(&mut self, span: Self::Span, message: &str) -> ! {
|
||||
pub fn span_bug(&mut self, span: Span, message: &str) -> ! {
|
||||
self.tcx.sess.span_bug(span, message)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> Cx<'a,'tcx> {
|
||||
pub fn tcx(&self) -> &'a ty::ctxt<'tcx> {
|
||||
self.tcx
|
||||
}
|
||||
|
||||
fn cmp_method_ref(&mut self,
|
||||
trait_def_id: DefId,
|
||||
method_name: &str,
|
||||
arg_ty: Ty<'tcx>)
|
||||
-> ItemRef<Cx<'a,'tcx>> {
|
||||
-> ItemRef<'tcx> {
|
||||
let method_name = token::intern(method_name);
|
||||
let substs = Substs::new_trait(vec![arg_ty], vec![], arg_ty);
|
||||
for trait_item in self.tcx.trait_items(trait_def_id).iter() {
|
||||
@ -167,29 +151,6 @@ impl<'a,'tcx:'a> Cx<'a,'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
// We only need this impl so that we do deriving for things that are
|
||||
// defined relative to the `Hair` trait. See `Hair` trait for more
|
||||
// details.
|
||||
impl<'a,'tcx> PartialEq for Cx<'a,'tcx> {
|
||||
fn eq(&self, _: &Cx<'a,'tcx>) -> bool {
|
||||
panic!("Cx should never ACTUALLY be compared for equality")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Eq for Cx<'a,'tcx> { }
|
||||
|
||||
impl<'a,'tcx> Hash for Cx<'a,'tcx> {
|
||||
fn hash<H: Hasher>(&self, _: &mut H) {
|
||||
panic!("Cx should never ACTUALLY be hashed")
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx> Debug for Cx<'a,'tcx> {
|
||||
fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
|
||||
write!(fmt, "Tcx")
|
||||
}
|
||||
}
|
||||
|
||||
mod block;
|
||||
mod expr;
|
||||
mod pattern;
|
||||
|
@ -14,15 +14,15 @@ use repr::*;
|
||||
use rustc_data_structures::fnv::FnvHashMap;
|
||||
use std::rc::Rc;
|
||||
use tcx::Cx;
|
||||
use tcx::rustc::middle::const_eval;
|
||||
use tcx::rustc::middle::def;
|
||||
use tcx::rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
|
||||
use tcx::rustc::middle::subst::Substs;
|
||||
use tcx::rustc::middle::ty::{self, Ty};
|
||||
use tcx::rustc_front::hir;
|
||||
use tcx::syntax::ast;
|
||||
use tcx::syntax::ptr::P;
|
||||
use tcx::to_ref::ToRef;
|
||||
use rustc::middle::const_eval;
|
||||
use rustc::middle::def;
|
||||
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
|
||||
use rustc::middle::subst::Substs;
|
||||
use rustc::middle::ty::{self, Ty};
|
||||
use rustc_front::hir;
|
||||
use syntax::ast;
|
||||
use syntax::ptr::P;
|
||||
|
||||
/// When there are multiple patterns in a single arm, each one has its
|
||||
/// own node-ids for the bindings. References to the variables always
|
||||
@ -58,15 +58,15 @@ impl<'tcx> PatNode<'tcx> {
|
||||
PatNode::new(pat, None)
|
||||
}
|
||||
|
||||
fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<Cx<'a,'tcx>> {
|
||||
fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<'tcx> {
|
||||
PatNode::new(pat, self.binding_map.clone()).to_ref()
|
||||
}
|
||||
|
||||
fn pat_refs<'a>(&self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<PatternRef<Cx<'a,'tcx>>> {
|
||||
fn pat_refs<'a>(&self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<PatternRef<'tcx>> {
|
||||
pats.iter().map(|p| self.pat_ref(p)).collect()
|
||||
}
|
||||
|
||||
fn opt_pat_ref<'a>(&self, pat: &'tcx Option<P<hir::Pat>>) -> Option<PatternRef<Cx<'a,'tcx>>> {
|
||||
fn opt_pat_ref<'a>(&self, pat: &'tcx Option<P<hir::Pat>>) -> Option<PatternRef<'tcx>> {
|
||||
pat.as_ref().map(|p| self.pat_ref(p))
|
||||
}
|
||||
|
||||
@ -76,7 +76,7 @@ impl<'tcx> PatNode<'tcx> {
|
||||
prefix: &'tcx Vec<P<hir::Pat>>,
|
||||
slice: &'tcx Option<P<hir::Pat>>,
|
||||
suffix: &'tcx Vec<P<hir::Pat>>)
|
||||
-> PatternKind<Cx<'a,'tcx>>
|
||||
-> PatternKind<'tcx>
|
||||
{
|
||||
match ty.sty {
|
||||
ty::TySlice(..) =>
|
||||
@ -107,8 +107,8 @@ impl<'tcx> PatNode<'tcx> {
|
||||
|
||||
fn variant_or_leaf<'a>(&self,
|
||||
cx: &mut Cx<'a, 'tcx>,
|
||||
subpatterns: Vec<FieldPatternRef<Cx<'a,'tcx>>>)
|
||||
-> PatternKind<Cx<'a,'tcx>>
|
||||
subpatterns: Vec<FieldPatternRef<'tcx>>)
|
||||
-> PatternKind<'tcx>
|
||||
{
|
||||
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
|
||||
match def {
|
||||
@ -138,10 +138,10 @@ impl<'tcx> PatNode<'tcx> {
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> Mirror<Cx<'a,'tcx>> for PatNode<'tcx> {
|
||||
type Output = Pattern<Cx<'a,'tcx>>;
|
||||
impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
|
||||
type Output = Pattern<'tcx>;
|
||||
|
||||
fn make_mirror(self, cx: &mut Cx<'a,'tcx>) -> Pattern<Cx<'a,'tcx>> {
|
||||
fn make_mirror<'a>(self, cx: &mut Cx<'a,'tcx>) -> Pattern<'tcx> {
|
||||
let kind = match self.pat.node {
|
||||
hir::PatWild(..) =>
|
||||
PatternKind::Wild,
|
||||
|
@ -11,58 +11,57 @@
|
||||
use hair::*;
|
||||
use repr::*;
|
||||
|
||||
use tcx::Cx;
|
||||
use tcx::pattern::PatNode;
|
||||
use tcx::rustc_front::hir;
|
||||
use tcx::syntax::ptr::P;
|
||||
use rustc_front::hir;
|
||||
use syntax::ptr::P;
|
||||
|
||||
pub trait ToRef<H> {
|
||||
pub trait ToRef {
|
||||
type Output;
|
||||
fn to_ref(self) -> Self::Output;
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for &'tcx hir::Expr {
|
||||
type Output = ExprRef<Cx<'a,'tcx>>;
|
||||
impl<'a,'tcx:'a> ToRef for &'tcx hir::Expr {
|
||||
type Output = ExprRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> ExprRef<Cx<'a,'tcx>> {
|
||||
fn to_ref(self) -> ExprRef<'tcx> {
|
||||
ExprRef::Hair(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for &'tcx P<hir::Expr> {
|
||||
type Output = ExprRef<Cx<'a,'tcx>>;
|
||||
impl<'a,'tcx:'a> ToRef for &'tcx P<hir::Expr> {
|
||||
type Output = ExprRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> ExprRef<Cx<'a,'tcx>> {
|
||||
fn to_ref(self) -> ExprRef<'tcx> {
|
||||
ExprRef::Hair(&**self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for Expr<Cx<'a,'tcx>> {
|
||||
type Output = ExprRef<Cx<'a,'tcx>>;
|
||||
impl<'a,'tcx:'a> ToRef for Expr<'tcx> {
|
||||
type Output = ExprRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> ExprRef<Cx<'a,'tcx>> {
|
||||
fn to_ref(self) -> ExprRef<'tcx> {
|
||||
ExprRef::Mirror(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for PatNode<'tcx> {
|
||||
type Output = PatternRef<Cx<'a,'tcx>>;
|
||||
impl<'a,'tcx:'a> ToRef for PatNode<'tcx> {
|
||||
type Output = PatternRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> PatternRef<Cx<'a,'tcx>> {
|
||||
fn to_ref(self) -> PatternRef<'tcx> {
|
||||
PatternRef::Hair(self)
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for Pattern<Cx<'a,'tcx>> {
|
||||
type Output = PatternRef<Cx<'a,'tcx>>;
|
||||
impl<'a,'tcx:'a> ToRef for Pattern<'tcx> {
|
||||
type Output = PatternRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> PatternRef<Cx<'a,'tcx>> {
|
||||
fn to_ref(self) -> PatternRef<'tcx> {
|
||||
PatternRef::Mirror(Box::new(self))
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a,T,U> ToRef<Cx<'a,'tcx>> for &'tcx Option<T>
|
||||
where &'tcx T: ToRef<Cx<'a,'tcx>, Output=U>
|
||||
impl<'a,'tcx:'a,T,U> ToRef for &'tcx Option<T>
|
||||
where &'tcx T: ToRef<Output=U>
|
||||
{
|
||||
type Output = Option<U>;
|
||||
|
||||
@ -71,8 +70,8 @@ impl<'a,'tcx:'a,T,U> ToRef<Cx<'a,'tcx>> for &'tcx Option<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a,T,U> ToRef<Cx<'a,'tcx>> for &'tcx Vec<T>
|
||||
where &'tcx T: ToRef<Cx<'a,'tcx>, Output=U>
|
||||
impl<'a,'tcx:'a,T,U> ToRef for &'tcx Vec<T>
|
||||
where &'tcx T: ToRef<Output=U>
|
||||
{
|
||||
type Output = Vec<U>;
|
||||
|
||||
@ -81,10 +80,10 @@ impl<'a,'tcx:'a,T,U> ToRef<Cx<'a,'tcx>> for &'tcx Vec<T>
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a,'tcx:'a> ToRef<Cx<'a,'tcx>> for &'tcx hir::Field {
|
||||
type Output = FieldExprRef<Cx<'a,'tcx>>;
|
||||
impl<'a,'tcx:'a> ToRef for &'tcx hir::Field {
|
||||
type Output = FieldExprRef<'tcx>;
|
||||
|
||||
fn to_ref(self) -> FieldExprRef<Cx<'a,'tcx>> {
|
||||
fn to_ref(self) -> FieldExprRef<'tcx> {
|
||||
FieldExprRef {
|
||||
name: Field::Named(self.name.node),
|
||||
expr: self.expr.to_ref()
|
||||
|
Loading…
Reference in New Issue
Block a user