diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs index ea415c21cd94b..4d0acd5fac924 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -34,6 +34,15 @@ impl Builder { let discriminant_lvalue = unpack!(block = self.as_lvalue(block, discriminant)); + // Before we do anything, create uninitialized variables with + // 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().unwrap(); + for arm in &arms { + self.declare_bindings(var_extent, arm.patterns[0].clone()); + } + let mut arm_blocks = ArmBlocks { blocks: arms.iter() .map(|_| self.cfg.start_new_block()) @@ -52,14 +61,13 @@ impl Builder { // reverse of the order in which candidates are written in the // source. let candidates: Vec> = - arms.into_iter() + arms.iter() .enumerate() .rev() // highest priority comes last .flat_map(|(arm_index, arm)| { - let guard = arm.guard; - arm.patterns.into_iter() + arm.patterns.iter() .rev() - .map(move |pat| (arm_index, pat, guard.clone())) + .map(move |pat| (arm_index, pat.clone(), arm.guard.clone())) }) .map(|(arm_index, pattern, guard)| { Candidate { @@ -73,8 +81,7 @@ impl Builder { // this will generate code to test discriminant_lvalue and // branch to the appropriate arm block - let var_extent = self.extent_of_innermost_scope().unwrap(); - self.match_candidates(span, var_extent, &mut arm_blocks, candidates, block); + self.match_candidates(span, &mut arm_blocks, candidates, block); // all the arm blocks will rejoin here let end_block = self.cfg.start_new_block(); @@ -123,9 +130,12 @@ impl Builder { initializer: &Lvalue) -> BlockAnd<()> { + // first, creating the bindings + self.declare_bindings(var_extent, irrefutable_pat.clone()); + // create a dummy candidate let mut candidate = Candidate:: { - match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)], + match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())], bindings: vec![], guard: None, arm_index: 0, // since we don't call `match_candidates`, this field is unused @@ -143,38 +153,38 @@ impl Builder { } // now apply the bindings, which will also declare the variables - self.bind_matched_candidate(block, var_extent, candidate.bindings); + self.bind_matched_candidate(block, candidate.bindings); block.unit() } - pub fn declare_uninitialized_variables(&mut self, - var_extent: H::CodeExtent, - pattern: PatternRef) + pub fn declare_bindings(&mut self, + var_extent: H::CodeExtent, + pattern: PatternRef) { let pattern = self.hir.mirror(pattern); match pattern.kind { PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => { self.declare_binding(var_extent, mutability, name, var, ty, pattern.span); if let Some(subpattern) = subpattern { - self.declare_uninitialized_variables(var_extent, subpattern); + 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) { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } } PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => { } PatternKind::Deref { subpattern } => { - self.declare_uninitialized_variables(var_extent, subpattern); + self.declare_bindings(var_extent, subpattern); } PatternKind::Leaf { subpatterns } | PatternKind::Variant { subpatterns, .. } => { for subpattern in subpatterns { - self.declare_uninitialized_variables(var_extent, subpattern.pattern); + self.declare_bindings(var_extent, subpattern.pattern); } } } @@ -249,13 +259,12 @@ struct Test { impl Builder { fn match_candidates(&mut self, span: H::Span, - var_extent: H::CodeExtent, arm_blocks: &mut ArmBlocks, mut candidates: Vec>, mut block: BasicBlock) { - debug!("matched_candidate(span={:?}, var_extent={:?}, block={:?}, candidates={:?})", - span, var_extent, block, candidates); + debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})", + span, block, candidates); // Start by simplifying candidates. Once this process is // complete, all the match pairs which remain require some @@ -275,8 +284,7 @@ impl Builder { // If so, apply any bindings, test the guard (if any), and // branch to the arm. let candidate = candidates.pop().unwrap(); - if let Some(b) = self.bind_and_guard_matched_candidate(block, var_extent, - arm_blocks, candidate) { + if let Some(b) = self.bind_and_guard_matched_candidate(block, arm_blocks, candidate) { block = b; } else { // if None is returned, then any remaining candidates @@ -309,7 +317,7 @@ impl Builder { candidate)) }) .collect(); - self.match_candidates(span, var_extent, arm_blocks, applicable_candidates, target_block); + self.match_candidates(span, arm_blocks, applicable_candidates, target_block); } } @@ -327,16 +335,15 @@ impl Builder { /// MIR). fn bind_and_guard_matched_candidate(&mut self, mut block: BasicBlock, - var_extent: H::CodeExtent, arm_blocks: &mut ArmBlocks, candidate: Candidate) -> Option { - debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})", - block, var_extent, candidate); + debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})", + block, candidate); debug_assert!(candidate.match_pairs.is_empty()); - self.bind_matched_candidate(block, var_extent, candidate.bindings); + self.bind_matched_candidate(block, candidate.bindings); let arm_block = arm_blocks.blocks[candidate.arm_index]; @@ -356,26 +363,16 @@ impl Builder { fn bind_matched_candidate(&mut self, block: BasicBlock, - var_extent: H::CodeExtent, bindings: Vec>) { - debug!("bind_matched_candidate(block={:?}, var_extent={:?}, bindings={:?})", - block, var_extent, bindings); + debug!("bind_matched_candidate(block={:?}, bindings={:?})", + block, bindings); // Assign each of the bindings. This may trigger moves out of the candidate. for binding in bindings { - // Create a variable for the `var_id` being bound. In the - // case where there are multiple patterns for a single - // arm, it may already exist. - let var_index = if !self.var_indices.contains_key(&binding.var_id) { - self.declare_binding(var_extent, - binding.mutability, - binding.name, - binding.var_id, - binding.var_ty, - binding.span) - } else { - self.var_indices[&binding.var_id] - }; + // Find the variable for the `var_id` being bound. It + // should have been created by a previous call to + // `declare_bindings`. + let var_index = self.var_indices[&binding.var_id]; let rvalue = match binding.binding_mode { BindingMode::ByValue => diff --git a/src/librustc_mir/build/stmt.rs b/src/librustc_mir/build/stmt.rs index 9d5a83154d402..3dd4f5f253c0a 100644 --- a/src/librustc_mir/build/stmt.rs +++ b/src/librustc_mir/build/stmt.rs @@ -40,7 +40,7 @@ impl Builder { StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => { this.in_scope(remainder_scope, block, |this| { unpack!(block = this.in_scope(init_scope, block, |this| { - this.declare_uninitialized_variables(remainder_scope, pattern); + this.declare_bindings(remainder_scope, pattern); block.unit() })); this.stmts(block, stmts)