Refactor code so that block_context observations has nicely named (and documented) methods.
This commit is contained in:
parent
556f583587
commit
e7e1a52f63
@ -177,17 +177,7 @@ fn ast_block_stmts(&mut self,
|
||||
let destination_ty = destination.ty(&this.local_decls, tcx).to_ty(tcx);
|
||||
if let Some(expr) = expr {
|
||||
let tail_result_is_ignored = destination_ty.is_unit() ||
|
||||
match this.block_context.last() {
|
||||
// no context: conservatively assume result is read
|
||||
None => false,
|
||||
|
||||
// sub-expression: block result feeds into some computation
|
||||
Some(BlockFrame::SubExpr) => false,
|
||||
|
||||
// otherwise: use accumualated is_ignored state.
|
||||
Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) |
|
||||
Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
|
||||
};
|
||||
this.block_context.currently_ignores_tail_results();
|
||||
this.block_context.push(BlockFrame::TailExpr { tail_result_is_ignored });
|
||||
|
||||
unpack!(block = this.into(destination, block, expr));
|
||||
|
@ -10,7 +10,7 @@
|
||||
|
||||
//! See docs in build/expr/mod.rs
|
||||
|
||||
use build::{BlockAnd, BlockAndExtension, BlockFrame, Builder};
|
||||
use build::{BlockAnd, BlockAndExtension, Builder};
|
||||
use hair::*;
|
||||
use rustc::middle::region;
|
||||
use rustc::mir::*;
|
||||
@ -68,19 +68,9 @@ fn expr_as_temp(
|
||||
debug!("creating temp {:?} with block_context: {:?}", local_decl, this.block_context);
|
||||
// Find out whether this temp is being created within the
|
||||
// tail expression of a block whose result is ignored.
|
||||
for bf in this.block_context.iter().rev() {
|
||||
match bf {
|
||||
BlockFrame::SubExpr => continue,
|
||||
BlockFrame::Statement { .. } => break,
|
||||
&BlockFrame::TailExpr { tail_result_is_ignored } => {
|
||||
local_decl = local_decl.block_tail(BlockTailInfo {
|
||||
tail_result_is_ignored
|
||||
});
|
||||
break;
|
||||
}
|
||||
}
|
||||
if let Some(tail_info) = this.block_context.currently_in_block_tail() {
|
||||
local_decl = local_decl.block_tail(tail_info);
|
||||
}
|
||||
|
||||
this.local_decls.push(local_decl)
|
||||
};
|
||||
if !expr_ty.is_never() {
|
||||
|
@ -336,6 +336,9 @@ fn is_statement(&self) -> bool {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
struct BlockContext(Vec<BlockFrame>);
|
||||
|
||||
struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
hir: Cx<'a, 'gcx, 'tcx>,
|
||||
cfg: CFG<'tcx>,
|
||||
@ -359,7 +362,7 @@ struct Builder<'a, 'gcx: 'a+'tcx, 'tcx: 'a> {
|
||||
/// start just throwing new entries onto that vector in order to
|
||||
/// distinguish the context of EXPR1 from the context of EXPR2 in
|
||||
/// `{ STMTS; EXPR1 } + EXPR2`
|
||||
block_context: Vec<BlockFrame>,
|
||||
block_context: BlockContext,
|
||||
|
||||
/// The current unsafe block in scope, even if it is hidden by
|
||||
/// a PushUnsafeBlock
|
||||
@ -409,6 +412,55 @@ fn var_local_id(&self, id: ast::NodeId, for_guard: ForGuard) -> Local {
|
||||
}
|
||||
}
|
||||
|
||||
impl BlockContext {
|
||||
fn new() -> Self { BlockContext(vec![]) }
|
||||
fn push(&mut self, bf: BlockFrame) { self.0.push(bf); }
|
||||
fn pop(&mut self) -> Option<BlockFrame> { self.0.pop() }
|
||||
|
||||
/// Traverses the frames on the BlockContext, searching for either
|
||||
/// the first block-tail expression frame with no intervening
|
||||
/// statement frame.
|
||||
///
|
||||
/// Notably, this skips over `SubExpr` frames; this method is
|
||||
/// meant to be used in the context of understanding the
|
||||
/// relationship of a temp (created within some complicated
|
||||
/// expression) with its containing expression, and whether the
|
||||
/// value of that *containing expression* (not the temp!) is
|
||||
/// ignored.
|
||||
fn currently_in_block_tail(&self) -> Option<BlockTailInfo> {
|
||||
for bf in self.0.iter().rev() {
|
||||
match bf {
|
||||
BlockFrame::SubExpr => continue,
|
||||
BlockFrame::Statement { .. } => break,
|
||||
&BlockFrame::TailExpr { tail_result_is_ignored } =>
|
||||
return Some(BlockTailInfo { tail_result_is_ignored })
|
||||
}
|
||||
}
|
||||
|
||||
return None;
|
||||
}
|
||||
|
||||
/// Looks at the topmost frame on the BlockContext and reports
|
||||
/// whether its one that would discard a block tail result.
|
||||
///
|
||||
/// Unlike `currently_within_ignored_tail_expression`, this does
|
||||
/// *not* skip over `SubExpr` frames: here, we want to know
|
||||
/// whether the block result itself is discarded.
|
||||
fn currently_ignores_tail_results(&self) -> bool {
|
||||
match self.0.last() {
|
||||
// no context: conservatively assume result is read
|
||||
None => false,
|
||||
|
||||
// sub-expression: block result feeds into some computation
|
||||
Some(BlockFrame::SubExpr) => false,
|
||||
|
||||
// otherwise: use accumulated is_ignored state.
|
||||
Some(BlockFrame::TailExpr { tail_result_is_ignored: ignored }) |
|
||||
Some(BlockFrame::Statement { ignores_expr_result: ignored }) => *ignored,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
enum LocalsForNode {
|
||||
/// In the usual case, a node-id for an identifier maps to at most
|
||||
@ -764,7 +816,7 @@ fn new(hir: Cx<'a, 'gcx, 'tcx>,
|
||||
fn_span: span,
|
||||
arg_count,
|
||||
scopes: vec![],
|
||||
block_context: vec![],
|
||||
block_context: BlockContext::new(),
|
||||
source_scopes: IndexVec::new(),
|
||||
source_scope: OUTERMOST_SOURCE_SCOPE,
|
||||
source_scope_local_data: IndexVec::new(),
|
||||
|
Loading…
Reference in New Issue
Block a user