enable slice patterns and enable building rustdoc

This commit is contained in:
Niko Matsakis 2015-09-05 05:46:50 -04:00
parent 99f3bfc20c
commit c8a661838e
6 changed files with 208 additions and 108 deletions

View file

@ -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

View file

@ -116,7 +116,7 @@ pub fn expr_into_pattern(&mut self,
}
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 @@ pub fn lvalue_into_pattern(&mut self,
// 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 @@ fn match_candidates(&mut self,
// 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 @@ fn match_candidates(&mut self,
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);

View file

@ -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 @@
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 @@ pub fn simplify_candidate(&mut self,
/// 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 @@ fn simplify_match_pair(&mut self,
candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
}
Ok(())
Ok(block)
}
PatternKind::Constant { .. } => {
@ -89,16 +95,14 @@ fn simplify_match_pair(&mut self,
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 @@ fn simplify_match_pair(&mut self,
// 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)
}
}
}

View file

@ -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 @@ fn call_comparison_fn(&mut self,
/// 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 @@ fn match_pairs_under_assumption(&mut self,
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))
}
// 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::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)
}
}
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>) -> ! {

View file

@ -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 @@ pub fn match_pair(&mut self, lvalue: Lvalue<H>, pattern: PatternRef<H>) -> Match
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);

View file

@ -471,9 +471,9 @@ fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
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 @@ fn fmt(&self, fmt: &mut Formatter) -> Result<(), Error> {
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),
}
}
}