use build::{BlockAnd, BlockAndExtension, Builder};
use rustc_data_structures::fnv::FnvHashMap;
-use rustc::middle::const_eval::ConstVal;
-use rustc::middle::region::CodeExtent;
-use rustc::middle::ty::{AdtDef, Ty};
+use rustc::middle::const_val::ConstVal;
+use rustc::ty::{AdtDef, Ty};
use rustc::mir::repr::*;
use hair::*;
use syntax::ast::{Name, NodeId};
// suitable extent for all of the bindings in this match. It's
// easiest to do this up front because some of these arms may
// be unreachable or reachable multiple times.
- let var_extent = self.extent_of_innermost_scope();
+ let var_scope_id = self.innermost_scope_id();
for arm in &arms {
- self.declare_bindings(var_extent, &arm.patterns[0]);
+ self.declare_bindings(var_scope_id, &arm.patterns[0]);
}
let mut arm_blocks = ArmBlocks {
})
.map(|(arm_index, pattern, guard)| {
Candidate {
+ span: pattern.span,
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
bindings: vec![],
guard: guard,
// an empty vector to be returned here, but the algorithm is
// not entirely precise
if !otherwise.is_empty() {
- let join_block = self.join_otherwise_blocks(otherwise);
+ let join_block = self.join_otherwise_blocks(span, otherwise);
self.panic(join_block, "something about matches algorithm not being precise", span);
}
for (arm_index, arm_body) in arm_bodies.into_iter().enumerate() {
let mut arm_block = arm_blocks.blocks[arm_index];
unpack!(arm_block = self.into(destination, arm_block, arm_body));
- self.cfg.terminate(arm_block, Terminator::Goto { target: end_block });
+ self.cfg.terminate(arm_block,
+ var_scope_id,
+ span,
+ TerminatorKind::Goto { target: end_block });
}
end_block.unit()
pub fn expr_into_pattern(&mut self,
mut block: BasicBlock,
- var_extent: CodeExtent, // lifetime of vars
+ var_scope_id: ScopeId, // lifetime of vars
irrefutable_pat: Pattern<'tcx>,
initializer: ExprRef<'tcx>)
-> BlockAnd<()> {
var,
ty,
subpattern: None } => {
- let index = self.declare_binding(var_extent,
+ let index = self.declare_binding(var_scope_id,
mutability,
name,
var,
}
let lvalue = unpack!(block = self.as_lvalue(block, initializer));
self.lvalue_into_pattern(block,
- var_extent,
+ var_scope_id,
irrefutable_pat,
&lvalue)
}
pub fn lvalue_into_pattern(&mut self,
mut block: BasicBlock,
- var_extent: CodeExtent,
+ var_scope_id: ScopeId,
irrefutable_pat: Pattern<'tcx>,
initializer: &Lvalue<'tcx>)
-> BlockAnd<()> {
// first, creating the bindings
- self.declare_bindings(var_extent, &irrefutable_pat);
+ self.declare_bindings(var_scope_id, &irrefutable_pat);
// create a dummy candidate
let mut candidate = Candidate {
+ span: irrefutable_pat.span,
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
bindings: vec![],
guard: None,
unpack!(block = self.simplify_candidate(block, &mut candidate));
if !candidate.match_pairs.is_empty() {
- self.hir.span_bug(candidate.match_pairs[0].pattern.span,
- &format!("match pairs {:?} remaining after simplifying \
- irrefutable pattern",
- candidate.match_pairs));
+ span_bug!(candidate.match_pairs[0].pattern.span,
+ "match pairs {:?} remaining after simplifying \
+ irrefutable pattern",
+ candidate.match_pairs);
}
// now apply the bindings, which will also declare the variables
block.unit()
}
- pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: &Pattern<'tcx>) {
+ pub fn declare_bindings(&mut self, var_scope_id: ScopeId, pattern: &Pattern<'tcx>) {
match *pattern.kind {
PatternKind::Binding { mutability, name, mode: _, var, ty, ref subpattern } => {
- self.declare_binding(var_extent, mutability, name, var, ty, pattern.span);
+ self.declare_binding(var_scope_id, mutability, name, var, ty, pattern.span);
if let Some(subpattern) = subpattern.as_ref() {
- self.declare_bindings(var_extent, subpattern);
+ self.declare_bindings(var_scope_id, subpattern);
}
}
PatternKind::Array { ref prefix, ref slice, ref suffix } |
PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
for subpattern in prefix.iter().chain(slice).chain(suffix) {
- self.declare_bindings(var_extent, subpattern);
+ self.declare_bindings(var_scope_id, subpattern);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
}
PatternKind::Deref { ref subpattern } => {
- self.declare_bindings(var_extent, subpattern);
+ self.declare_bindings(var_scope_id, subpattern);
}
PatternKind::Leaf { ref subpatterns } |
PatternKind::Variant { ref subpatterns, .. } => {
for subpattern in subpatterns {
- self.declare_bindings(var_extent, &subpattern.pattern);
+ self.declare_bindings(var_scope_id, &subpattern.pattern);
}
}
}
#[derive(Clone, Debug)]
pub struct Candidate<'pat, 'tcx:'pat> {
+ // span of the original pattern that gave rise to this candidate
+ span: Span,
+
// all of these must be satisfied...
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
// ... must match this pattern.
pattern: &'pat Pattern<'tcx>,
+
+ // HACK(eddyb) This is used to toggle whether a Slice pattern
+ // has had its length checked. This is only necessary because
+ // the "rest" part of the pattern right now has type &[T] and
+ // as such, it requires an Rvalue::Slice to be generated.
+ // See RFC 495 / issue #23121 for the eventual (proper) solution.
+ slice_len_checked: bool
}
#[derive(Clone, Debug, PartialEq)]
// test length of the slice is equal to len
Len {
- len: usize,
+ len: u64,
op: BinOp,
},
}
}
// Otherwise, let's process those remaining candidates.
- let join_block = self.join_otherwise_blocks(otherwise);
+ let join_block = self.join_otherwise_blocks(span, otherwise);
self.match_candidates(span, arm_blocks, untested_candidates, join_block)
}
fn join_otherwise_blocks(&mut self,
+ span: Span,
otherwise: Vec<BasicBlock>)
-> BasicBlock
{
+ let scope_id = self.innermost_scope_id();
if otherwise.len() == 1 {
otherwise[0]
} else {
let join_block = self.cfg.start_new_block();
for block in otherwise {
- self.cfg.terminate(block, Terminator::Goto { target: join_block });
+ self.cfg.terminate(block,
+ scope_id,
+ span,
+ TerminatorKind::Goto { target: join_block });
}
join_block
}
let arm_block = arm_blocks.blocks[candidate.arm_index];
+ let scope_id = self.innermost_scope_id();
if let Some(guard) = candidate.guard {
// the block to branch to if the guard fails; if there is no
// guard, this block is simply unreachable
+ let guard = self.hir.mirror(guard);
+ let guard_span = guard.span;
let cond = unpack!(block = self.as_operand(block, guard));
let otherwise = self.cfg.start_new_block();
- self.cfg.terminate(block, Terminator::If { cond: cond,
- targets: (arm_block, otherwise)});
+ self.cfg.terminate(block,
+ scope_id,
+ guard_span,
+ TerminatorKind::If { cond: cond,
+ targets: (arm_block, otherwise)});
Some(otherwise)
} else {
- self.cfg.terminate(block, Terminator::Goto { target: arm_block });
+ self.cfg.terminate(block,
+ scope_id,
+ candidate.span,
+ TerminatorKind::Goto { target: arm_block });
None
}
}
Rvalue::Ref(region, borrow_kind, binding.source),
};
- self.cfg.push_assign(block, binding.span, &Lvalue::Var(var_index), rvalue);
+ let scope_id = self.innermost_scope_id();
+ self.cfg.push_assign(block, scope_id, binding.span,
+ &Lvalue::Var(var_index), rvalue);
}
}
fn declare_binding(&mut self,
- var_extent: CodeExtent,
+ var_scope_id: ScopeId,
mutability: Mutability,
name: Name,
var_id: NodeId,
span: Span)
-> u32
{
- debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_extent={:?}, span={:?})",
- var_id, name, var_ty, var_extent, span);
+ debug!("declare_binding(var_id={:?}, name={:?}, var_ty={:?}, var_scope_id={:?}, span={:?})",
+ var_id, name, var_ty, var_scope_id, span);
let index = self.var_decls.len();
self.var_decls.push(VarDecl::<'tcx> {
+ scope: var_scope_id,
mutability: mutability,
name: name,
ty: var_ty.clone(),
+ span: span,
});
let index = index as u32;
- self.schedule_drop(span, var_extent, &Lvalue::Var(index), var_ty);
+ let extent = self.scope_auxiliary[var_scope_id].extent;
+ self.schedule_drop(span, extent, &Lvalue::Var(index), var_ty);
self.var_indices.insert(var_id, index);
debug!("declare_binding: index={:?}", index);