From c8a661838ed3f4db7a9402df880e539b46f0a0f1 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 5 Sep 2015 05:46:50 -0400 Subject: [PATCH] enable slice patterns and enable building rustdoc --- mk/main.mk | 2 +- src/librustc_mir/build/matches/mod.rs | 26 ++-- src/librustc_mir/build/matches/simplify.rs | 44 +++--- src/librustc_mir/build/matches/test.rs | 172 +++++++++++++-------- src/librustc_mir/build/matches/util.rs | 55 ++++++- src/librustc_mir/repr.rs | 17 +- 6 files changed, 208 insertions(+), 108 deletions(-) diff --git a/mk/main.mk b/mk/main.mk index c0c6161aa2d87..9ede86937e8af 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 ff6e4997b79dd..7f0b3ee3b316b 100644 --- a/src/librustc_mir/build/matches/mod.rs +++ b/src/librustc_mir/build/matches/mod.rs @@ -116,7 +116,7 @@ impl Builder { } pub fn lvalue_into_pattern(&mut self, - block: BasicBlock, + mut block: BasicBlock, var_extent: H::CodeExtent, irrefutable_pat: PatternRef, initializer: &Lvalue) @@ -132,7 +132,7 @@ impl Builder { // 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 { #[derive(Debug)] struct Test { span: H::Span, - - // the kind of test to be performed, kind: TestKind, - - // the outcome we expect, - outcome: usize, - - // and the match pairs that will result - match_pairs: Vec> } /////////////////////////////////////////////////////////////////////////// @@ -261,7 +253,7 @@ impl Builder { // 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 Builder { 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> = 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 90d01b44345f1..f15b2ed5d4e59 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 Builder { pub fn simplify_candidate(&mut self, + mut block: BasicBlock, candidate: &mut Candidate) + -> 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 Builder { /// 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, candidate: &mut Candidate) - -> Result<(), MatchPair> // returns Err() if cannot simplify + -> Result> // 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 Builder { candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern)); } - Ok(()) + Ok(block) } PatternKind::Constant { .. } => { @@ -89,16 +95,14 @@ impl Builder { 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 Builder { // 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 181c947038c07..2d0a6e61beb28 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 Builder { /// /// It is a bug to call this with a simplifyable pattern. pub fn test(&mut self, match_pair: &MatchPair) -> Test { - 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 Builder { /// were `Ok`, we would return `Some([x.0.downcast.0 @ P1, x.1 /// @ 22])`. pub fn candidate_under_assumption(&mut self, + mut block: BasicBlock, test_lvalue: &Lvalue, test_kind: &TestKind, test_outcome: usize, candidate: &Candidate) - -> Option> { + -> BlockAnd>> { 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, test_kind: &TestKind, test_outcome: usize, match_pairs: Vec>) - -> Option>> { + -> BlockAnd>>> { 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 Builder { 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, + test_outcome: usize) + -> BlockAnd>>> { + 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.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) -> ! { diff --git a/src/librustc_mir/build/matches/util.rs b/src/librustc_mir/build/matches/util.rs index e035719643429..65a0886866635 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 Builder { MatchPair::new(lvalue, pattern) } - pub fn append_prefix_suffix_pairs(&mut self, - match_pairs: &mut Vec>, - lvalue: Lvalue, - prefix: Vec>, - suffix: Vec>) + /// 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>, + block: BasicBlock, + lvalue: Lvalue, + prefix: Vec>, + opt_slice: Option>, + suffix: Vec>) + -> 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>, + lvalue: Lvalue, + prefix: Vec>, + suffix: Vec>) { 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 ea62be26225d6..a54942144c5ec 100644 --- a/src/librustc_mir/repr.rs +++ b/src/librustc_mir/repr.rs @@ -471,9 +471,9 @@ impl Debug for Lvalue { 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 { // away after type-checking and before lowering. Aggregate(AggregateKind, Vec>), + // 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, + from_start: usize, + from_end: usize, + }, + InlineAsm(H::InlineAsm), } @@ -623,6 +634,8 @@ impl Debug for Rvalue { 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), } } }