Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Change match desugaring in MIR to be O(n) instead of O(n^2) #29763

Merged
merged 6 commits into from
Nov 11, 2015
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
102 changes: 52 additions & 50 deletions src/librustc_mir/build/matches/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// be unreachable or reachable multiple times.
let var_extent = self.extent_of_innermost_scope().unwrap();
for arm in &arms {
self.declare_bindings(var_extent, arm.patterns[0].clone());
self.declare_bindings(var_extent, &arm.patterns[0]);
}

let mut arm_blocks = ArmBlocks {
Expand All @@ -64,18 +64,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// 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<'tcx>> =
let candidates: Vec<_> =
arms.iter()
.enumerate()
.rev() // highest priority comes last
.flat_map(|(arm_index, arm)| {
arm.patterns.iter()
.rev()
.map(move |pat| (arm_index, pat.clone(), arm.guard.clone()))
.map(move |pat| (arm_index, pat, arm.guard.clone()))
})
.map(|(arm_index, pattern, guard)| {
Candidate {
match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)],
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
bindings: vec![],
guard: guard,
arm_index: arm_index,
Expand All @@ -102,12 +102,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
pub fn expr_into_pattern(&mut self,
mut block: BasicBlock,
var_extent: CodeExtent, // lifetime of vars
irrefutable_pat: PatternRef<'tcx>,
irrefutable_pat: Pattern<'tcx>,
initializer: ExprRef<'tcx>)
-> BlockAnd<()> {
// optimize the case of `let x = ...`
let irrefutable_pat = self.hir.mirror(irrefutable_pat);
match irrefutable_pat.kind {
match *irrefutable_pat.kind {
PatternKind::Binding { mutability,
name,
mode: BindingMode::ByValue,
Expand All @@ -128,22 +127,22 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let lvalue = unpack!(block = self.as_lvalue(block, initializer));
self.lvalue_into_pattern(block,
var_extent,
PatternRef::Mirror(Box::new(irrefutable_pat)),
irrefutable_pat,
&lvalue)
}

pub fn lvalue_into_pattern(&mut self,
mut block: BasicBlock,
var_extent: CodeExtent,
irrefutable_pat: PatternRef<'tcx>,
irrefutable_pat: Pattern<'tcx>,
initializer: &Lvalue<'tcx>)
-> BlockAnd<()> {
// first, creating the bindings
self.declare_bindings(var_extent, irrefutable_pat.clone());
self.declare_bindings(var_extent, &irrefutable_pat);

// create a dummy candidate
let mut candidate = Candidate::<'tcx> {
match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
let mut candidate = Candidate {
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
bindings: vec![],
guard: None,
arm_index: 0, // since we don't call `match_candidates`, this field is unused
Expand All @@ -166,29 +165,29 @@ impl<'a,'tcx> Builder<'a,'tcx> {
block.unit()
}

pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: PatternRef<'tcx>) {
let pattern = self.hir.mirror(pattern);
match pattern.kind {
PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => {
pub fn declare_bindings(&mut self, var_extent: CodeExtent, 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);
if let Some(subpattern) = subpattern {
if let Some(subpattern) = subpattern.as_ref() {
self.declare_bindings(var_extent, subpattern);
}
}
PatternKind::Array { prefix, slice, suffix } |
PatternKind::Slice { prefix, slice, suffix } => {
for subpattern in prefix.into_iter().chain(slice).chain(suffix) {
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);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
PatternKind::Deref { subpattern } => {
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
}
PatternKind::Deref { ref subpattern } => {
self.declare_bindings(var_extent, subpattern);
}
PatternKind::Leaf { subpatterns } |
PatternKind::Variant { subpatterns, .. } => {
PatternKind::Leaf { ref subpatterns } |
PatternKind::Variant { ref subpatterns, .. } => {
for subpattern in subpatterns {
self.declare_bindings(var_extent, subpattern.pattern);
self.declare_bindings(var_extent, &subpattern.pattern);
}
}
}
Expand All @@ -202,9 +201,9 @@ struct ArmBlocks {
}

#[derive(Clone, Debug)]
struct Candidate<'tcx> {
struct Candidate<'pat, 'tcx:'pat> {
// all of these must be satisfied...
match_pairs: Vec<MatchPair<'tcx>>,
match_pairs: Vec<MatchPair<'pat, 'tcx>>,

// ...these bindings established...
bindings: Vec<Binding<'tcx>>,
Expand All @@ -228,12 +227,12 @@ struct Binding<'tcx> {
}

#[derive(Clone, Debug)]
struct MatchPair<'tcx> {
struct MatchPair<'pat, 'tcx:'pat> {
// this lvalue...
lvalue: Lvalue<'tcx>,

// ... must match this pattern.
pattern: Pattern<'tcx>,
pattern: &'pat Pattern<'tcx>,
}

#[derive(Clone, Debug, PartialEq)]
Expand Down Expand Up @@ -280,11 +279,11 @@ struct Test<'tcx> {
// Main matching algorithm

impl<'a,'tcx> Builder<'a,'tcx> {
fn match_candidates(&mut self,
span: Span,
arm_blocks: &mut ArmBlocks,
mut candidates: Vec<Candidate<'tcx>>,
mut block: BasicBlock)
fn match_candidates<'pat>(&mut self,
span: Span,
arm_blocks: &mut ArmBlocks,
mut candidates: Vec<Candidate<'pat, 'tcx>>,
mut block: BasicBlock)
{
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
span, block, candidates);
Expand Down Expand Up @@ -346,17 +345,20 @@ impl<'a,'tcx> Builder<'a,'tcx> {
debug!("match_candidates: test={:?} match_pair={:?}", test, match_pair);
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);

for (outcome, target_block) in target_blocks.into_iter().enumerate() {
let applicable_candidates: Vec<Candidate<'tcx>> =
candidates.iter()
.filter_map(|candidate| {
self.candidate_under_assumption(&match_pair.lvalue,
&test.kind,
outcome,
candidate)
})
.collect();
self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();

for candidate in &candidates {
self.sort_candidate(&match_pair.lvalue,
&test,
candidate,
&mut target_candidates);
}

for (target_block, target_candidates) in
target_blocks.into_iter()
.zip(target_candidates.into_iter())
{
self.match_candidates(span, arm_blocks, target_candidates, target_block);
}
}

Expand All @@ -372,11 +374,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// bindings, further tests would be a use-after-move (which would
/// in turn be detected by the borrowck code that runs on the
/// MIR).
fn bind_and_guard_matched_candidate(&mut self,
mut block: BasicBlock,
arm_blocks: &mut ArmBlocks,
candidate: Candidate<'tcx>)
-> Option<BasicBlock> {
fn bind_and_guard_matched_candidate<'pat>(&mut self,
mut block: BasicBlock,
arm_blocks: &mut ArmBlocks,
candidate: Candidate<'pat, 'tcx>)
-> Option<BasicBlock> {
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
block, candidate);

Expand Down
34 changes: 16 additions & 18 deletions src/librustc_mir/build/matches/simplify.rs
Original file line number Diff line number Diff line change
Expand Up @@ -30,10 +30,10 @@ use repr::*;
use std::mem;

impl<'a,'tcx> Builder<'a,'tcx> {
pub fn simplify_candidate(&mut self,
mut block: BasicBlock,
candidate: &mut Candidate<'tcx>)
-> BlockAnd<()> {
pub fn simplify_candidate<'pat>(&mut self,
mut block: BasicBlock,
candidate: &mut Candidate<'pat, 'tcx>)
-> BlockAnd<()> {
// repeatedly simplify match pairs until fixed point is reached
loop {
let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
Expand All @@ -60,18 +60,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// 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<'tcx>,
candidate: &mut Candidate<'tcx>)
-> Result<BasicBlock, MatchPair<'tcx>> {
match match_pair.pattern.kind {
fn simplify_match_pair<'pat>(&mut self,
mut block: BasicBlock,
match_pair: MatchPair<'pat, 'tcx>,
candidate: &mut Candidate<'pat, 'tcx>)
-> Result<BasicBlock, MatchPair<'pat, 'tcx>> {
match *match_pair.pattern.kind {
PatternKind::Wild(..) => {
// nothing left to do
Ok(block)
}

PatternKind::Binding { name, mutability, mode, var, ty, subpattern } => {
PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
candidate.bindings.push(Binding {
name: name,
mutability: mutability,
Expand All @@ -82,9 +82,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
binding_mode: mode,
});

if let Some(subpattern) = subpattern {
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
let subpattern = self.hir.mirror(subpattern);
candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
}

Expand All @@ -96,12 +95,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
Err(match_pair)
}

PatternKind::Array { prefix, slice, suffix } => {
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
block,
match_pair.lvalue.clone(),
prefix,
slice,
slice.as_ref(),
suffix));
Ok(block)
}
Expand All @@ -113,16 +112,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
Err(match_pair)
}

PatternKind::Leaf { subpatterns } => {
PatternKind::Leaf { ref subpatterns } => {
// tuple struct, match subpats (if any)
candidate.match_pairs
.extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
Ok(block)
}

PatternKind::Deref { subpattern } => {
PatternKind::Deref { ref subpattern } => {
let lvalue = match_pair.lvalue.deref();
let subpattern = self.hir.mirror(subpattern);
candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
Ok(block)
}
Expand Down
Loading