]> git.proxmox.com Git - rustc.git/blobdiff - src/librustc_mir/build/matches/mod.rs
Imported Upstream version 1.9.0+dfsg1
[rustc.git] / src / librustc_mir / build / matches / mod.rs
index e6430b7d63404cbff54f12d8543b37f7bc0cedc6..cabf5c955466c784db03f1a1393f581886594f16 100644 (file)
@@ -15,9 +15,8 @@
 
 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};
@@ -42,9 +41,9 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         // 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 {
@@ -72,6 +71,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                 })
                 .map(|(arm_index, pattern, guard)| {
                     Candidate {
+                        span: pattern.span,
                         match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
                         bindings: vec![],
                         guard: guard,
@@ -88,7 +88,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         // 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);
         }
 
@@ -98,7 +98,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         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()
@@ -106,7 +109,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
 
     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<()> {
@@ -118,7 +121,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                                    var,
                                    ty,
                                    subpattern: None } => {
-                let index = self.declare_binding(var_extent,
+                let index = self.declare_binding(var_scope_id,
                                                  mutability,
                                                  name,
                                                  var,
@@ -131,22 +134,23 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         }
         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,
@@ -158,10 +162,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         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
@@ -170,29 +174,29 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         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);
                 }
             }
         }
@@ -207,6 +211,9 @@ struct ArmBlocks {
 
 #[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>>,
 
@@ -238,6 +245,13 @@ pub struct MatchPair<'pat, 'tcx:'pat> {
 
     // ... 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)]
@@ -269,7 +283,7 @@ enum TestKind<'tcx> {
 
     // test length of the slice is equal to len
     Len {
-        len: usize,
+        len: u64,
         op: BinOp,
     },
 }
@@ -364,20 +378,25 @@ impl<'a,'tcx> Builder<'a,'tcx> {
         }
 
         // 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
         }
@@ -544,16 +563,25 @@ impl<'a,'tcx> Builder<'a,'tcx> {
 
         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
         }
     }
@@ -578,12 +606,14 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                     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,
@@ -591,17 +621,20 @@ impl<'a,'tcx> Builder<'a,'tcx> {
                        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);