]> git.lizzy.rs Git - rust.git/commitdiff
rather than just passing the block around, track the candidate's index,
authorNiko Matsakis <niko@alum.mit.edu>
Tue, 29 Sep 2015 14:49:24 +0000 (10:49 -0400)
committerNiko Matsakis <niko@alum.mit.edu>
Mon, 5 Oct 2015 01:19:32 +0000 (21:19 -0400)
and track which arms are reached (though in fact we don't make use of
this right now -- we might later if we absorb the checking of patterns
into MIR, as I would like)

src/librustc_mir/build/matches/mod.rs

index 519c6117717c7f60086834d0367cfcc5cfda781c..ea415c21cd94bc0b8247d4ef89696ad2495f280b 100644 (file)
@@ -34,10 +34,11 @@ pub fn match_expr(&mut self,
         let discriminant_lvalue =
             unpack!(block = self.as_lvalue(block, discriminant));
 
-        let arm_blocks: Vec<BasicBlock> =
-            arms.iter()
-                .map(|_| self.cfg.start_new_block())
-                .collect();
+        let mut arm_blocks = ArmBlocks {
+            blocks: arms.iter()
+                        .map(|_| self.cfg.start_new_block())
+                        .collect(),
+        };
 
         let arm_bodies: Vec<ExprRef<H>> =
             arms.iter()
@@ -52,20 +53,20 @@ pub fn match_expr(&mut self,
         // source.
         let candidates: Vec<Candidate<H>> =
             arms.into_iter()
-                .zip(arm_blocks.iter())
+                .enumerate()
                 .rev() // highest priority comes last
-                .flat_map(|(arm, &arm_block)| {
+                .flat_map(|(arm_index, arm)| {
                     let guard = arm.guard;
                     arm.patterns.into_iter()
                                 .rev()
-                                .map(move |pat| (arm_block, pat, guard.clone()))
+                                .map(move |pat| (arm_index, pat, guard.clone()))
                 })
-                .map(|(arm_block, pattern, guard)| {
+                .map(|(arm_index, pattern, guard)| {
                     Candidate {
                         match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)],
                         bindings: vec![],
                         guard: guard,
-                        arm_block: arm_block,
+                        arm_index: arm_index,
                     }
                 })
                 .collect();
@@ -73,13 +74,13 @@ pub fn match_expr(&mut self,
         // 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, candidates, block);
+        self.match_candidates(span, var_extent, &mut arm_blocks, candidates, block);
 
         // all the arm blocks will rejoin here
         let end_block = self.cfg.start_new_block();
 
-        for (arm_body, &arm_block) in arm_bodies.into_iter().zip(arm_blocks.iter()) {
-            let mut arm_block = arm_block;
+        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 });
         }
@@ -127,7 +128,7 @@ pub fn lvalue_into_pattern(&mut self,
             match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat)],
             bindings: vec![],
             guard: None,
-            arm_block: block
+            arm_index: 0, // since we don't call `match_candidates`, this field is unused
         };
 
         // Simplify the candidate. Since the pattern is irrefutable, this should
@@ -180,6 +181,12 @@ pub fn declare_uninitialized_variables(&mut self,
     }
 }
 
+/// List of blocks for each arm (and potentially other metadata in the
+/// future).
+struct ArmBlocks {
+    blocks: Vec<BasicBlock>,
+}
+
 #[derive(Clone, Debug)]
 struct Candidate<H:Hair> {
     // all of these must be satisfied...
@@ -191,8 +198,8 @@ struct Candidate<H:Hair> {
     // ...and the guard must be evaluated...
     guard: Option<ExprRef<H>>,
 
-    // ...and then we branch here.
-    arm_block: BasicBlock,
+    // ...and then we branch to arm with this index.
+    arm_index: usize,
 }
 
 #[derive(Clone, Debug)]
@@ -243,6 +250,7 @@ impl<H:Hair> Builder<H> {
     fn match_candidates(&mut self,
                         span: H::Span,
                         var_extent: H::CodeExtent,
+                        arm_blocks: &mut ArmBlocks,
                         mut candidates: Vec<Candidate<H>>,
                         mut block: BasicBlock)
     {
@@ -267,7 +275,8 @@ fn match_candidates(&mut self,
             // 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, candidate) {
+            if let Some(b) = self.bind_and_guard_matched_candidate(block, var_extent,
+                                                                   arm_blocks, candidate) {
                 block = b;
             } else {
                 // if None is returned, then any remaining candidates
@@ -300,7 +309,7 @@ fn match_candidates(&mut self,
                                                                       candidate))
                           })
                           .collect();
-            self.match_candidates(span, var_extent, applicable_candidates, target_block);
+            self.match_candidates(span, var_extent, arm_blocks, applicable_candidates, target_block);
         }
     }
 
@@ -319,6 +328,7 @@ fn match_candidates(&mut self,
     fn bind_and_guard_matched_candidate(&mut self,
                                         mut block: BasicBlock,
                                         var_extent: H::CodeExtent,
+                                        arm_blocks: &mut ArmBlocks,
                                         candidate: Candidate<H>)
                                         -> Option<BasicBlock> {
         debug!("bind_and_guard_matched_candidate(block={:?}, var_extent={:?}, candidate={:?})",
@@ -328,16 +338,18 @@ fn bind_and_guard_matched_candidate(&mut self,
 
         self.bind_matched_candidate(block, var_extent, candidate.bindings);
 
+        let arm_block = arm_blocks.blocks[candidate.arm_index];
+
         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 cond = unpack!(block = self.as_operand(block, guard));
             let otherwise = self.cfg.start_new_block();
             self.cfg.terminate(block, Terminator::If { cond: cond,
-                                                       targets: [candidate.arm_block, otherwise]});
+                                                       targets: [arm_block, otherwise]});
             Some(otherwise)
         } else {
-            self.cfg.terminate(block, Terminator::Goto { target: candidate.arm_block });
+            self.cfg.terminate(block, Terminator::Goto { target: arm_block });
             None
         }
     }