about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-09-05 05:46:50 -0400
committerNiko Matsakis <niko@alum.mit.edu>2015-09-06 16:48:57 -0400
commitc8a661838ed3f4db7a9402df880e539b46f0a0f1 (patch)
tree14de0503ef8d35e19ac153671c9d885ab3d7a103
parent99f3bfc20c737a2d602cf396829d78c797c0fe0d (diff)
downloadrust-c8a661838ed3f4db7a9402df880e539b46f0a0f1.tar.gz
rust-c8a661838ed3f4db7a9402df880e539b46f0a0f1.zip
enable slice patterns and enable building rustdoc
-rw-r--r--mk/main.mk2
-rw-r--r--src/librustc_mir/build/matches/mod.rs26
-rw-r--r--src/librustc_mir/build/matches/simplify.rs44
-rw-r--r--src/librustc_mir/build/matches/test.rs172
-rw-r--r--src/librustc_mir/build/matches/util.rs55
-rw-r--r--src/librustc_mir/repr.rs17
6 files changed, 208 insertions, 108 deletions
diff --git a/mk/main.mk b/mk/main.mk
index c0c6161aa2d..9ede86937e8 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -182,7 +182,7 @@ RUSTFLAGS2_$(1) += -Z always-build-mir
 endef
 $(foreach crate,$(TARGET_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
 $(foreach crate,$(RUSTC_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
-$(foreach crate,syntax,$(eval $(call ADD_MIR_FLAG,$(crate))))
+$(foreach crate,$(HOST_CRATES),$(eval $(call ADD_MIR_FLAG,$(crate))))
 
 # platform-specific auto-configuration
 include $(CFG_SRC_DIR)mk/platform.mk
diff --git a/src/librustc_mir/build/matches/mod.rs b/src/librustc_mir/build/matches/mod.rs
index ff6e4997b79..7f0b3ee3b31 100644
--- a/src/librustc_mir/build/matches/mod.rs
+++ b/src/librustc_mir/build/matches/mod.rs
@@ -116,7 +116,7 @@ impl<H:Hair> Builder<H> {
     }
 
     pub fn lvalue_into_pattern(&mut self,
-                               block: BasicBlock,
+                               mut block: BasicBlock,
                                var_extent: H::CodeExtent,
                                irrefutable_pat: PatternRef<H>,
                                initializer: &Lvalue<H>)
@@ -132,7 +132,7 @@ impl<H:Hair> Builder<H> {
 
         // Simplify the candidate. Since the pattern is irrefutable, this should
         // always convert all match-pairs into bindings.
-        self.simplify_candidate(&mut candidate);
+        unpack!(block = self.simplify_candidate(block, &mut candidate));
 
         if !candidate.match_pairs.is_empty() {
             self.hir.span_bug(
@@ -233,15 +233,7 @@ enum TestKind<H:Hair> {
 #[derive(Debug)]
 struct Test<H:Hair> {
     span: H::Span,
-
-    // the kind of test to be performed,
     kind: TestKind<H>,
-
-    // the outcome we expect,
-    outcome: usize,
-
-    // and the match pairs that will result
-    match_pairs: Vec<MatchPair<H>>
 }
 
 ///////////////////////////////////////////////////////////////////////////
@@ -261,7 +253,7 @@ impl<H:Hair> Builder<H> {
         // complete, all the match pairs which remain require some
         // form of test, whether it be a switch or pattern comparison.
         for candidate in &mut candidates {
-            self.simplify_candidate(candidate);
+            unpack!(block = self.simplify_candidate(block, candidate));
         }
 
         // The candidates are inversely sorted by priority. Check to
@@ -293,14 +285,16 @@ impl<H:Hair> Builder<H> {
         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() {
+        for (outcome, mut target_block) in target_blocks.into_iter().enumerate() {
             let applicable_candidates: Vec<Candidate<H>> =
                 candidates.iter()
                           .filter_map(|candidate| {
-                              self.candidate_under_assumption(&match_pair.lvalue,
-                                                              &test.kind,
-                                                              outcome,
-                                                              candidate)
+                              unpack!(target_block =
+                                      self.candidate_under_assumption(target_block,
+                                                                      &match_pair.lvalue,
+                                                                      &test.kind,
+                                                                      outcome,
+                                                                      candidate))
                           })
                           .collect();
             self.match_candidates(span, var_extent, applicable_candidates, target_block);
diff --git a/src/librustc_mir/build/matches/simplify.rs b/src/librustc_mir/build/matches/simplify.rs
index 90d01b44345..f15b2ed5d4e 100644
--- a/src/librustc_mir/build/matches/simplify.rs
+++ b/src/librustc_mir/build/matches/simplify.rs
@@ -22,7 +22,7 @@
 //! sort of test: for example, testing which variant an enum is, or
 //! testing a value against a constant.
 
-use build::Builder;
+use build::{BlockAnd, Builder};
 use build::matches::{Binding, MatchPair, Candidate};
 use hair::*;
 use repr::*;
@@ -31,20 +31,25 @@ use std::mem;
 
 impl<H:Hair> Builder<H> {
     pub fn simplify_candidate(&mut self,
+                              mut block: BasicBlock,
                               candidate: &mut Candidate<H>)
+                              -> BlockAnd<()>
     {
         // repeatedly simplify match pairs until fixed point is reached
         loop {
             let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
             let mut progress = match_pairs.len(); // count how many were simplified
             for match_pair in match_pairs {
-                if let Err(match_pair) = self.simplify_match_pair(match_pair, candidate) {
-                    candidate.match_pairs.push(match_pair);
-                    progress -= 1; // this one was not simplified
+                match self.simplify_match_pair(block, match_pair, candidate) {
+                    Ok(b) => { block = b; }
+                    Err(match_pair) => {
+                        candidate.match_pairs.push(match_pair);
+                        progress -= 1; // this one was not simplified
+                    }
                 }
             }
             if progress == 0 {
-                return; // if we were not able to simplify any, done.
+                return block.unit(); // if we were not able to simplify any, done.
             }
         }
     }
@@ -54,14 +59,15 @@ impl<H:Hair> Builder<H> {
     /// have been pushed into the candidate. On failure (if false is
     /// returned), no changes are made to candidate.
     fn simplify_match_pair(&mut self,
+                           mut block: BasicBlock,
                            match_pair: MatchPair<H>,
                            candidate: &mut Candidate<H>)
-                           -> Result<(), MatchPair<H>> // returns Err() if cannot simplify
+                           -> Result<BasicBlock, MatchPair<H>> // returns Err() if cannot simplify
     {
         match match_pair.pattern.kind {
             PatternKind::Wild(..) => {
                 // nothing left to do
-                Ok(())
+                Ok(block)
             }
 
             PatternKind::Binding { name, mutability, mode, var, ty, subpattern } => {
@@ -81,7 +87,7 @@ impl<H:Hair> Builder<H> {
                     candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
                 }
 
-                Ok(())
+                Ok(block)
             }
 
             PatternKind::Constant { .. } => {
@@ -89,16 +95,14 @@ impl<H:Hair> Builder<H> {
                 Err(match_pair)
             }
 
-            PatternKind::Array { prefix, slice: None, suffix } => {
-                self.append_prefix_suffix_pairs(
-                    &mut candidate.match_pairs, match_pair.lvalue.clone(), prefix, suffix);
-                Ok(())
-            }
-
-            PatternKind::Array { prefix: _, slice: Some(_), suffix: _ } => {
-                self.hir.span_bug(
-                    match_pair.pattern.span,
-                    &format!("slice patterns not implemented in MIR"));
+            PatternKind::Array { prefix, slice, suffix } => {
+                unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
+                                                         block,
+                                                         match_pair.lvalue.clone(),
+                                                         prefix,
+                                                         slice,
+                                                         suffix));
+                Ok(block)
             }
 
             PatternKind::Slice { .. } |
@@ -112,14 +116,14 @@ impl<H:Hair> Builder<H> {
                 // tuple struct, match subpats (if any)
                 candidate.match_pairs.extend(
                     self.field_match_pairs(match_pair.lvalue, subpatterns));
-                Ok(())
+                Ok(block)
             }
 
             PatternKind::Deref { subpattern } => {
                 let lvalue = match_pair.lvalue.deref();
                 let subpattern = self.hir.mirror(subpattern);
                 candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
-                Ok(())
+                Ok(block)
             }
         }
     }
diff --git a/src/librustc_mir/build/matches/test.rs b/src/librustc_mir/build/matches/test.rs
index 181c947038c..2d0a6e61beb 100644
--- a/src/librustc_mir/build/matches/test.rs
+++ b/src/librustc_mir/build/matches/test.rs
@@ -15,7 +15,7 @@
 // identify what tests are needed, perform the tests, and then filter
 // the candidates based on the result.
 
-use build::Builder;
+use build::{BlockAnd, Builder};
 use build::matches::{Candidate, MatchPair, Test, TestKind};
 use hair::*;
 use repr::*;
@@ -25,72 +25,40 @@ impl<H:Hair> Builder<H> {
     ///
     /// It is a bug to call this with a simplifyable pattern.
     pub fn test(&mut self, match_pair: &MatchPair<H>) -> Test<H> {
-        match match_pair.pattern.kind.clone() {
-            PatternKind::Variant { adt_def, variant_index, subpatterns } => {
-                let elem = ProjectionElem::Downcast(adt_def, variant_index);
-                let downcast_lvalue = match_pair.lvalue.clone().elem(elem);
-
-                let consequent_match_pairs =
-                    subpatterns.into_iter()
-                               .map(|subpattern| {
-                                   let lvalue =
-                                       downcast_lvalue.clone().field(
-                                           subpattern.field);
-                                   self.match_pair(lvalue, subpattern.pattern)
-                               })
-                               .collect();
-
+        match match_pair.pattern.kind {
+            PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Switch { adt_def: adt_def },
-                    outcome: variant_index,
-                    match_pairs: consequent_match_pairs,
+                    kind: TestKind::Switch { adt_def: adt_def.clone() },
                 }
             }
 
-            PatternKind::Constant { expr } => {
-                let expr = self.as_constant(expr);
+            PatternKind::Constant { ref expr } => {
+                let expr = self.as_constant(expr.clone());
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Eq { value: expr,
-                                         ty: match_pair.pattern.ty.clone() },
-                    outcome: 0, // 0 == true, of course. :)
-                    match_pairs: vec![]
+                    kind: TestKind::Eq { value: expr, ty: match_pair.pattern.ty.clone() },
                 }
             }
 
-            PatternKind::Range { lo, hi } => {
-                let lo = self.as_constant(lo);
-                let hi = self.as_constant(hi);
+            PatternKind::Range { ref lo, ref hi } => {
+                let lo = self.as_constant(lo.clone());
+                let hi = self.as_constant(hi.clone());
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Range { lo: lo,
-                                            hi: hi,
-                                            ty: match_pair.pattern.ty.clone() },
-                    outcome: 0, // 0 == true, of course. :)
-                    match_pairs: vec![]
+                    kind: TestKind::Range { lo: lo, hi: hi, ty: match_pair.pattern.ty.clone() },
                 }
             }
 
-            PatternKind::Slice { prefix, slice: None, suffix } => {
+            PatternKind::Slice { ref prefix, ref slice, ref suffix } => {
                 let len = prefix.len() + suffix.len();
-                let mut consequent_match_pairs = vec![];
-                self.append_prefix_suffix_pairs(
-                    &mut consequent_match_pairs, match_pair.lvalue.clone(), prefix, suffix);
+                let op = if slice.is_some() {BinOp::Ge} else {BinOp::Eq};
                 Test {
                     span: match_pair.pattern.span,
-                    kind: TestKind::Len { len: len, op: BinOp::Eq },
-                    outcome: 0, // 0 == true, of course. :)
-                    match_pairs: consequent_match_pairs
+                    kind: TestKind::Len { len: len, op: op },
                 }
             }
 
-            PatternKind::Slice { prefix: _, slice: Some(_), suffix: _ } => {
-                self.hir.span_bug(
-                    match_pair.pattern.span,
-                    &format!("slice patterns not implemented in MIR"));
-            }
-
             PatternKind::Array { .. } |
             PatternKind::Wild |
             PatternKind::Binding { .. } |
@@ -225,28 +193,36 @@ impl<H:Hair> Builder<H> {
     /// were `Ok`, we would return `Some([x.0.downcast<Ok>.0 @ P1, x.1
     /// @ 22])`.
     pub fn candidate_under_assumption(&mut self,
+                                      mut block: BasicBlock,
                                       test_lvalue: &Lvalue<H>,
                                       test_kind: &TestKind<H>,
                                       test_outcome: usize,
                                       candidate: &Candidate<H>)
-                                      -> Option<Candidate<H>> {
+                                      -> BlockAnd<Option<Candidate<H>>> {
         let candidate = candidate.clone();
         let match_pairs = candidate.match_pairs;
-        match self.match_pairs_under_assumption(test_lvalue, test_kind, test_outcome, match_pairs) {
+        let result = unpack!(block = self.match_pairs_under_assumption(block,
+                                                                       test_lvalue,
+                                                                       test_kind,
+                                                                       test_outcome,
+                                                                       match_pairs));
+        block.and(match result {
             Some(match_pairs) => Some(Candidate { match_pairs: match_pairs, ..candidate }),
             None => None
-        }
+        })
     }
 
     /// Helper for candidate_under_assumption that does the actual
     /// work of transforming the list of match pairs.
     fn match_pairs_under_assumption(&mut self,
+                                    mut block: BasicBlock,
                                     test_lvalue: &Lvalue<H>,
                                     test_kind: &TestKind<H>,
                                     test_outcome: usize,
                                     match_pairs: Vec<MatchPair<H>>)
-                                    -> Option<Vec<MatchPair<H>>> {
+                                    -> BlockAnd<Option<Vec<MatchPair<H>>>> {
         let mut result = vec![];
+
         for match_pair in match_pairs {
             // if the match pair is testing a different lvalue, it
             // is unaffected by this test.
@@ -275,22 +251,92 @@ impl<H:Hair> Builder<H> {
                 continue;
             }
 
-            if test_outcome != desired_test.outcome {
-                // if we did the right kind of test, but it had the
-                // wrong outcome, then this *entire candidate* can no
-                // longer apply, huzzah! Therefore, we can stop this
-                // iteration and just return `None` to our caller.
-                return None;
+            let opt_consequent_match_pairs =
+                unpack!(block = self.consequent_match_pairs_under_assumption(block,
+                                                                             match_pair,
+                                                                             test_outcome));
+            match opt_consequent_match_pairs {
+                None => {
+                    // Right kind of test, but wrong outcome. That
+                    // means this **entire candidate** is
+                    // inapplicable, since the candidate is only
+                    // applicable if all of its match-pairs apply (and
+                    // this one doesn't).
+                    return block.and(None);
+                }
+
+                Some(consequent_match_pairs) => {
+                    // Test passed; add any new patterns we have to test to the final result.
+                    result.extend(consequent_match_pairs)
+                }
+            }
+        }
+        block.and(Some(result))
+    }
+
+    /// Identifies what test is needed to decide if `match_pair` is applicable.
+    ///
+    /// It is a bug to call this with a simplifyable pattern.
+    pub fn consequent_match_pairs_under_assumption(&mut self,
+                                                   mut block: BasicBlock,
+                                                   match_pair: MatchPair<H>,
+                                                   test_outcome: usize)
+                                                   -> BlockAnd<Option<Vec<MatchPair<H>>>> {
+        match match_pair.pattern.kind {
+            PatternKind::Variant { adt_def, variant_index, subpatterns } => {
+                if test_outcome != variant_index {
+                    return block.and(None);
+                }
+
+                let elem = ProjectionElem::Downcast(adt_def, variant_index);
+                let downcast_lvalue = match_pair.lvalue.clone().elem(elem);
+                let consequent_match_pairs =
+                    subpatterns.into_iter()
+                               .map(|subpattern| {
+                                   let lvalue =
+                                       downcast_lvalue.clone().field(
+                                           subpattern.field);
+                                   self.match_pair(lvalue, subpattern.pattern)
+                               })
+                               .collect();
+                block.and(Some(consequent_match_pairs))
+            }
+
+            PatternKind::Constant { .. } |
+            PatternKind::Range { .. } => {
+                // these are boolean tests: if we are on the 0th
+                // successor, then they passed, and otherwise they
+                // failed, but there are never any more tests to come.
+                if test_outcome == 0 {
+                    block.and(Some(vec![]))
+                } else {
+                    block.and(None)
+                }
+            }
+
+            PatternKind::Slice { prefix, slice, suffix } => {
+                if test_outcome == 0 {
+                    let mut consequent_match_pairs = vec![];
+                    unpack!(block = self.prefix_suffix_slice(&mut consequent_match_pairs,
+                                                             block,
+                                                             match_pair.lvalue,
+                                                             prefix,
+                                                             slice,
+                                                             suffix));
+                    block.and(Some(consequent_match_pairs))
+                } else {
+                    block.and(None)
+                }
             }
 
-            // otherwise, the test passed, so we now have to include the
-            // "unlocked" set of match pairs. For example, if we had `x @
-            // Some(P1)`, and here we `test_kind==Switch` and
-            // `outcome=Some`, then we would return `x.downcast<Some>.0 @
-            // P1`.
-            result.extend(desired_test.match_pairs);
+            PatternKind::Array { .. } |
+            PatternKind::Wild |
+            PatternKind::Binding { .. } |
+            PatternKind::Leaf { .. } |
+            PatternKind::Deref { .. } => {
+                self.error_simplifyable(&match_pair)
+            }
         }
-        Some(result)
     }
 
     fn error_simplifyable(&mut self, match_pair: &MatchPair<H>) -> ! {
diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs
index e0357196434..65a08868666 100644
--- a/src/librustc_mir/build/matches/util.rs
+++ b/src/librustc_mir/build/matches/util.rs
@@ -8,7 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
-use build::Builder;
+use build::{BlockAnd, Builder};
 use build::matches::MatchPair;
 use hair::*;
 use repr::*;
@@ -32,11 +32,54 @@ impl<H:Hair> Builder<H> {
         MatchPair::new(lvalue, pattern)
     }
 
-    pub fn append_prefix_suffix_pairs(&mut self,
-                                      match_pairs: &mut Vec<MatchPair<H>>,
-                                      lvalue: Lvalue<H>,
-                                      prefix: Vec<PatternRef<H>>,
-                                      suffix: Vec<PatternRef<H>>)
+    /// When processing an array/slice pattern like `lv @ [x, y, ..s, z]`,
+    /// this function converts the prefix (`x`, `y`) and suffix (`z`) into
+    /// distinct match pairs:
+    ///
+    ///     lv[0 of 3] @ x  // see ProjectionElem::ConstantIndex (and its Debug impl)
+    ///     lv[1 of 3] @ y  // to explain the `[x of y]` notation
+    ///     lv[-1 of 3] @ z
+    ///
+    /// If a slice like `s` is present, then the function also creates
+    /// a temporary like:
+    ///
+    ///     tmp0 = lv[2..-1] // using the special Rvalue::Slice
+    ///
+    /// and creates a match pair `tmp0 @ s`
+    pub fn prefix_suffix_slice(&mut self,
+                               match_pairs: &mut Vec<MatchPair<H>>,
+                               block: BasicBlock,
+                               lvalue: Lvalue<H>,
+                               prefix: Vec<PatternRef<H>>,
+                               opt_slice: Option<PatternRef<H>>,
+                               suffix: Vec<PatternRef<H>>)
+                               -> BlockAnd<()>
+    {
+        // If there is a `..P` pattern, create a temporary `t0` for
+        // the slice and then a match pair `t0 @ P`:
+        if let Some(slice) = opt_slice {
+            let slice = self.hir.mirror(slice);
+            let prefix_len = prefix.len();
+            let suffix_len = suffix.len();
+            let rvalue = Rvalue::Slice { input: lvalue.clone(),
+                                         from_start: prefix_len,
+                                         from_end: suffix_len };
+            let temp = self.temp(slice.ty.clone()); // no need to schedule drop, temp is always copy
+            self.cfg.push_assign(block, slice.span, &temp, rvalue);
+            match_pairs.push(MatchPair::new(temp, slice));
+        }
+
+        self.prefix_suffix(match_pairs, lvalue, prefix, suffix);
+
+        block.unit()
+    }
+
+    /// Helper for `prefix_suffix_slice` which just processes the prefix and suffix.
+    fn prefix_suffix(&mut self,
+                     match_pairs: &mut Vec<MatchPair<H>>,
+                     lvalue: Lvalue<H>,
+                     prefix: Vec<PatternRef<H>>,
+                     suffix: Vec<PatternRef<H>>)
     {
         let min_length = prefix.len() + suffix.len();
         assert!(min_length < u32::MAX as usize);
diff --git a/src/librustc_mir/repr.rs b/src/librustc_mir/repr.rs
index ea62be26225..a54942144c5 100644
--- a/src/librustc_mir/repr.rs
+++ b/src/librustc_mir/repr.rs
@@ -471,9 +471,9 @@ impl<H:Hair> Debug for Lvalue<H> {
                     ProjectionElem::Index(ref index) =>
                         write!(fmt,"{:?}[{:?}]", data.base, index),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end: false } =>
-                        write!(fmt,"{:?}[{:?}; {:?}]", data.base, offset, min_length),
+                        write!(fmt,"{:?}[{:?} of {:?}]", data.base, offset, min_length),
                     ProjectionElem::ConstantIndex { offset, min_length, from_end: true } =>
-                        write!(fmt,"{:?}[-{:?}; {:?}]", data.base, offset, min_length),
+                        write!(fmt,"{:?}[-{:?} of {:?}]", data.base, offset, min_length),
                 },
         }
     }
@@ -535,6 +535,17 @@ pub enum Rvalue<H:Hair> {
     // away after type-checking and before lowering.
     Aggregate(AggregateKind<H>, Vec<Operand<H>>),
 
+    // Generates a slice of the form `&input[from_start..L-from_end]`
+    // where `L` is the length of the slice. This is only created by
+    // slice pattern matching, so e.g. a pattern of the form `[x, y,
+    // .., z]` might create a slice with `from_start=2` and
+    // `from_end=1`.
+    Slice {
+        input: Lvalue<H>,
+        from_start: usize,
+        from_end: usize,
+    },
+
     InlineAsm(H::InlineAsm),
 }
 
@@ -623,6 +634,8 @@ impl<H:Hair> Debug for Rvalue<H> {
             Box(ref t) => write!(fmt, "Box {:?}", t),
             Aggregate(ref kind, ref lvs) => write!(fmt, "Aggregate<{:?}>({:?})", kind, lvs),
             InlineAsm(ref asm) => write!(fmt, "InlineAsm({:?})", asm),
+            Slice { ref input, from_start, from_end } => write!(fmt, "{:?}[{:?}..-{:?}]",
+                                                                input, from_start, from_end),
         }
     }
 }