Remove the mirroring for patterns and just convert them eagerly; then,

pass around references instead of boxed values to save on clone costs.
This commit is contained in:
Niko Matsakis 2015-11-09 20:54:17 -05:00
parent ad3bd1b46d
commit 87358728a4
13 changed files with 290 additions and 348 deletions

View file

@ -44,7 +44,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// be unreachable or reachable multiple times.
let var_extent = self.extent_of_innermost_scope().unwrap();
for arm in &arms {
self.declare_bindings(var_extent, arm.patterns[0].clone());
self.declare_bindings(var_extent, &arm.patterns[0]);
}
let mut arm_blocks = ArmBlocks {
@ -64,18 +64,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
// highest priority candidate comes last in the list. This the
// reverse of the order in which candidates are written in the
// source.
let candidates: Vec<Candidate<'tcx>> =
let candidates: Vec<_> =
arms.iter()
.enumerate()
.rev() // highest priority comes last
.flat_map(|(arm_index, arm)| {
arm.patterns.iter()
.rev()
.map(move |pat| (arm_index, pat.clone(), arm.guard.clone()))
.map(move |pat| (arm_index, pat, arm.guard.clone()))
})
.map(|(arm_index, pattern, guard)| {
Candidate {
match_pairs: vec![self.match_pair(discriminant_lvalue.clone(), pattern)],
match_pairs: vec![MatchPair::new(discriminant_lvalue.clone(), pattern)],
bindings: vec![],
guard: guard,
arm_index: arm_index,
@ -102,12 +102,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
pub fn expr_into_pattern(&mut self,
mut block: BasicBlock,
var_extent: CodeExtent, // lifetime of vars
irrefutable_pat: PatternRef<'tcx>,
irrefutable_pat: Pattern<'tcx>,
initializer: ExprRef<'tcx>)
-> BlockAnd<()> {
// optimize the case of `let x = ...`
let irrefutable_pat = self.hir.mirror(irrefutable_pat);
match irrefutable_pat.kind {
match *irrefutable_pat.kind {
PatternKind::Binding { mutability,
name,
mode: BindingMode::ByValue,
@ -128,22 +127,22 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let lvalue = unpack!(block = self.as_lvalue(block, initializer));
self.lvalue_into_pattern(block,
var_extent,
PatternRef::Mirror(Box::new(irrefutable_pat)),
irrefutable_pat,
&lvalue)
}
pub fn lvalue_into_pattern(&mut self,
mut block: BasicBlock,
var_extent: CodeExtent,
irrefutable_pat: PatternRef<'tcx>,
irrefutable_pat: Pattern<'tcx>,
initializer: &Lvalue<'tcx>)
-> BlockAnd<()> {
// first, creating the bindings
self.declare_bindings(var_extent, irrefutable_pat.clone());
self.declare_bindings(var_extent, &irrefutable_pat);
// create a dummy candidate
let mut candidate = Candidate::<'tcx> {
match_pairs: vec![self.match_pair(initializer.clone(), irrefutable_pat.clone())],
let mut candidate = Candidate {
match_pairs: vec![MatchPair::new(initializer.clone(), &irrefutable_pat)],
bindings: vec![],
guard: None,
arm_index: 0, // since we don't call `match_candidates`, this field is unused
@ -166,29 +165,29 @@ impl<'a,'tcx> Builder<'a,'tcx> {
block.unit()
}
pub fn declare_bindings(&mut self, var_extent: CodeExtent, pattern: PatternRef<'tcx>) {
let pattern = self.hir.mirror(pattern);
match pattern.kind {
PatternKind::Binding { mutability, name, mode: _, var, ty, subpattern } => {
pub fn declare_bindings(&mut self, var_extent: CodeExtent, 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);
if let Some(subpattern) = subpattern {
if let Some(subpattern) = subpattern.as_ref() {
self.declare_bindings(var_extent, subpattern);
}
}
PatternKind::Array { prefix, slice, suffix } |
PatternKind::Slice { prefix, slice, suffix } => {
for subpattern in prefix.into_iter().chain(slice).chain(suffix) {
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);
}
}
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {}
PatternKind::Deref { subpattern } => {
PatternKind::Constant { .. } | PatternKind::Range { .. } | PatternKind::Wild => {
}
PatternKind::Deref { ref subpattern } => {
self.declare_bindings(var_extent, subpattern);
}
PatternKind::Leaf { subpatterns } |
PatternKind::Variant { subpatterns, .. } => {
PatternKind::Leaf { ref subpatterns } |
PatternKind::Variant { ref subpatterns, .. } => {
for subpattern in subpatterns {
self.declare_bindings(var_extent, subpattern.pattern);
self.declare_bindings(var_extent, &subpattern.pattern);
}
}
}
@ -202,9 +201,9 @@ struct ArmBlocks {
}
#[derive(Clone, Debug)]
struct Candidate<'tcx> {
struct Candidate<'pat, 'tcx:'pat> {
// all of these must be satisfied...
match_pairs: Vec<MatchPair<'tcx>>,
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
// ...these bindings established...
bindings: Vec<Binding<'tcx>>,
@ -228,12 +227,12 @@ struct Binding<'tcx> {
}
#[derive(Clone, Debug)]
struct MatchPair<'tcx> {
struct MatchPair<'pat, 'tcx:'pat> {
// this lvalue...
lvalue: Lvalue<'tcx>,
// ... must match this pattern.
pattern: Pattern<'tcx>,
pattern: &'pat Pattern<'tcx>,
}
#[derive(Clone, Debug, PartialEq)]
@ -280,11 +279,11 @@ struct Test<'tcx> {
// Main matching algorithm
impl<'a,'tcx> Builder<'a,'tcx> {
fn match_candidates(&mut self,
span: Span,
arm_blocks: &mut ArmBlocks,
mut candidates: Vec<Candidate<'tcx>>,
mut block: BasicBlock)
fn match_candidates<'pat>(&mut self,
span: Span,
arm_blocks: &mut ArmBlocks,
mut candidates: Vec<Candidate<'pat, 'tcx>>,
mut block: BasicBlock)
{
debug!("matched_candidate(span={:?}, block={:?}, candidates={:?})",
span, block, candidates);
@ -347,7 +346,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let target_blocks = self.perform_test(block, &match_pair.lvalue, &test);
for (outcome, target_block) in target_blocks.into_iter().enumerate() {
let applicable_candidates: Vec<Candidate<'tcx>> =
let applicable_candidates: Vec<_> =
candidates.iter()
.filter_map(|candidate| {
self.candidate_under_assumption(&match_pair.lvalue,
@ -372,11 +371,11 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// bindings, further tests would be a use-after-move (which would
/// in turn be detected by the borrowck code that runs on the
/// MIR).
fn bind_and_guard_matched_candidate(&mut self,
mut block: BasicBlock,
arm_blocks: &mut ArmBlocks,
candidate: Candidate<'tcx>)
-> Option<BasicBlock> {
fn bind_and_guard_matched_candidate<'pat>(&mut self,
mut block: BasicBlock,
arm_blocks: &mut ArmBlocks,
candidate: Candidate<'pat, 'tcx>)
-> Option<BasicBlock> {
debug!("bind_and_guard_matched_candidate(block={:?}, candidate={:?})",
block, candidate);

View file

@ -30,10 +30,10 @@ use repr::*;
use std::mem;
impl<'a,'tcx> Builder<'a,'tcx> {
pub fn simplify_candidate(&mut self,
mut block: BasicBlock,
candidate: &mut Candidate<'tcx>)
-> BlockAnd<()> {
pub fn simplify_candidate<'pat>(&mut self,
mut block: BasicBlock,
candidate: &mut Candidate<'pat, 'tcx>)
-> BlockAnd<()> {
// repeatedly simplify match pairs until fixed point is reached
loop {
let match_pairs = mem::replace(&mut candidate.match_pairs, vec![]);
@ -60,18 +60,18 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// have been pushed into the candidate. If no simplification is
/// possible, Err is returned and no changes are made to
/// candidate.
fn simplify_match_pair(&mut self,
mut block: BasicBlock,
match_pair: MatchPair<'tcx>,
candidate: &mut Candidate<'tcx>)
-> Result<BasicBlock, MatchPair<'tcx>> {
match match_pair.pattern.kind {
fn simplify_match_pair<'pat>(&mut self,
mut block: BasicBlock,
match_pair: MatchPair<'pat, 'tcx>,
candidate: &mut Candidate<'pat, 'tcx>)
-> Result<BasicBlock, MatchPair<'pat, 'tcx>> {
match *match_pair.pattern.kind {
PatternKind::Wild(..) => {
// nothing left to do
Ok(block)
}
PatternKind::Binding { name, mutability, mode, var, ty, subpattern } => {
PatternKind::Binding { name, mutability, mode, var, ty, ref subpattern } => {
candidate.bindings.push(Binding {
name: name,
mutability: mutability,
@ -82,9 +82,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
binding_mode: mode,
});
if let Some(subpattern) = subpattern {
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
let subpattern = self.hir.mirror(subpattern);
candidate.match_pairs.push(MatchPair::new(match_pair.lvalue, subpattern));
}
@ -96,12 +95,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
Err(match_pair)
}
PatternKind::Array { prefix, slice, suffix } => {
PatternKind::Array { ref prefix, ref slice, ref suffix } => {
unpack!(block = self.prefix_suffix_slice(&mut candidate.match_pairs,
block,
match_pair.lvalue.clone(),
prefix,
slice,
slice.as_ref(),
suffix));
Ok(block)
}
@ -113,16 +112,15 @@ impl<'a,'tcx> Builder<'a,'tcx> {
Err(match_pair)
}
PatternKind::Leaf { subpatterns } => {
PatternKind::Leaf { ref subpatterns } => {
// tuple struct, match subpats (if any)
candidate.match_pairs
.extend(self.field_match_pairs(match_pair.lvalue, subpatterns));
Ok(block)
}
PatternKind::Deref { subpattern } => {
PatternKind::Deref { ref subpattern } => {
let lvalue = match_pair.lvalue.deref();
let subpattern = self.hir.mirror(subpattern);
candidate.match_pairs.push(MatchPair::new(lvalue, subpattern));
Ok(block)
}

View file

@ -28,8 +28,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// 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 test(&mut self, match_pair: &MatchPair<'tcx>) -> Test<'tcx> {
match match_pair.pattern.kind {
pub fn test<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> Test<'tcx> {
match *match_pair.pattern.kind {
PatternKind::Variant { ref adt_def, variant_index: _, subpatterns: _ } => {
Test {
span: match_pair.pattern.span,
@ -99,19 +99,19 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
}
pub fn add_cases_to_switch(&mut self,
test_lvalue: &Lvalue<'tcx>,
candidate: &Candidate<'tcx>,
switch_ty: Ty<'tcx>,
options: &mut Vec<ConstVal>,
indices: &mut FnvHashMap<ConstVal, usize>)
pub fn add_cases_to_switch<'pat>(&mut self,
test_lvalue: &Lvalue<'tcx>,
candidate: &Candidate<'pat, 'tcx>,
switch_ty: Ty<'tcx>,
options: &mut Vec<ConstVal>,
indices: &mut FnvHashMap<ConstVal, usize>)
{
let match_pair = match candidate.match_pairs.iter().find(|mp| mp.lvalue == *test_lvalue) {
Some(match_pair) => match_pair,
_ => { return; }
};
match match_pair.pattern.kind {
match *match_pair.pattern.kind {
PatternKind::Constant { value: Literal::Value { ref value } } => {
// if the lvalues match, the type should match
assert_eq!(match_pair.pattern.ty, switch_ty);
@ -282,12 +282,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// parameter), we would return `None`. But if the test_outcome
/// were `Ok`, we would return `Some([x.0.downcast<Ok>.0 @ P1, x.1
/// @ 22])`.
pub fn candidate_under_assumption(&mut self,
test_lvalue: &Lvalue<'tcx>,
test_kind: &TestKind<'tcx>,
test_outcome: usize,
candidate: &Candidate<'tcx>)
-> Option<Candidate<'tcx>> {
pub fn candidate_under_assumption<'pat>(&mut self,
test_lvalue: &Lvalue<'tcx>,
test_kind: &TestKind<'tcx>,
test_outcome: usize,
candidate: &Candidate<'pat, 'tcx>)
-> Option<Candidate<'pat, 'tcx>> {
let candidate = candidate.clone();
let match_pairs = candidate.match_pairs;
let result = self.match_pairs_under_assumption(test_lvalue,
@ -302,12 +302,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// Helper for candidate_under_assumption that does the actual
/// work of transforming the list of match pairs.
fn match_pairs_under_assumption(&mut self,
test_lvalue: &Lvalue<'tcx>,
test_kind: &TestKind<'tcx>,
test_outcome: usize,
match_pairs: Vec<MatchPair<'tcx>>)
-> Option<Vec<MatchPair<'tcx>>> {
fn match_pairs_under_assumption<'pat>(&mut self,
test_lvalue: &Lvalue<'tcx>,
test_kind: &TestKind<'tcx>,
test_outcome: usize,
match_pairs: Vec<MatchPair<'pat, 'tcx>>)
-> Option<Vec<MatchPair<'pat, 'tcx>>> {
let mut result = vec![];
for match_pair in match_pairs {
@ -357,12 +357,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// the discriminant equals 4, and we find that it does not,
/// but the `match_pair` is testing if the discriminant equals 5,
/// that does not help us.
fn test_informs_match_pair(&mut self,
match_pair: &MatchPair<'tcx>,
test_kind: &TestKind<'tcx>,
_test_outcome: usize)
-> bool {
match match_pair.pattern.kind {
fn test_informs_match_pair<'pat>(&mut self,
match_pair: &MatchPair<'pat, 'tcx>,
test_kind: &TestKind<'tcx>,
_test_outcome: usize)
-> bool {
match *match_pair.pattern.kind {
PatternKind::Variant { .. } => {
match *test_kind {
TestKind::Switch { .. } => true,
@ -444,13 +444,13 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// On the second arm, a `None` will be returned, because if we
/// observed that `option` has the discriminant `Ok`, then the
/// second arm cannot apply.
pub fn consequent_match_pairs_under_assumption(&mut self,
match_pair: MatchPair<'tcx>,
test_kind: &TestKind<'tcx>,
test_outcome: usize)
-> Option<Vec<MatchPair<'tcx>>> {
match match_pair.pattern.kind {
PatternKind::Variant { adt_def, variant_index, subpatterns } => {
pub fn consequent_match_pairs_under_assumption<'pat>(&mut self,
match_pair: MatchPair<'pat, 'tcx>,
test_kind: &TestKind<'tcx>,
test_outcome: usize)
-> Option<Vec<MatchPair<'pat, 'tcx>>> {
match *match_pair.pattern.kind {
PatternKind::Variant { adt_def, variant_index, ref subpatterns } => {
assert!(match *test_kind { TestKind::Switch { .. } => true,
_ => false });
@ -464,12 +464,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
let elem = ProjectionElem::Downcast(adt_def, variant_index);
let downcast_lvalue = match_pair.lvalue.clone().elem(elem);
let consequent_match_pairs =
subpatterns.into_iter()
subpatterns.iter()
.map(|subpattern| {
let lvalue =
downcast_lvalue.clone().field(
subpattern.field);
self.match_pair(lvalue, subpattern.pattern)
MatchPair::new(lvalue, &subpattern.pattern)
})
.collect();
Some(consequent_match_pairs)
@ -516,7 +516,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
}
fn error_simplifyable(&mut self, match_pair: &MatchPair<'tcx>) -> ! {
fn error_simplifyable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {
self.hir.span_bug(match_pair.pattern.span,
&format!("simplifyable pattern found: {:?}", match_pair.pattern))
}

View file

@ -15,26 +15,18 @@ use repr::*;
use std::u32;
impl<'a,'tcx> Builder<'a,'tcx> {
pub fn field_match_pairs(&mut self,
lvalue: Lvalue<'tcx>,
subpatterns: Vec<FieldPatternRef<'tcx>>)
-> Vec<MatchPair<'tcx>> {
subpatterns.into_iter()
pub fn field_match_pairs<'pat>(&mut self,
lvalue: Lvalue<'tcx>,
subpatterns: &'pat [FieldPattern<'tcx>])
-> Vec<MatchPair<'pat, 'tcx>> {
subpatterns.iter()
.map(|fieldpat| {
let lvalue = lvalue.clone().field(fieldpat.field);
self.match_pair(lvalue, fieldpat.pattern)
MatchPair::new(lvalue, &fieldpat.pattern)
})
.collect()
}
pub fn match_pair(&mut self,
lvalue: Lvalue<'tcx>,
pattern: PatternRef<'tcx>)
-> MatchPair<'tcx> {
let pattern = self.hir.mirror(pattern);
MatchPair::new(lvalue, pattern)
}
/// 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:
@ -49,18 +41,17 @@ impl<'a,'tcx> Builder<'a,'tcx> {
/// 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<'tcx>>,
block: BasicBlock,
lvalue: Lvalue<'tcx>,
prefix: Vec<PatternRef<'tcx>>,
opt_slice: Option<PatternRef<'tcx>>,
suffix: Vec<PatternRef<'tcx>>)
-> BlockAnd<()> {
pub fn prefix_suffix_slice<'pat>(&mut self,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
block: BasicBlock,
lvalue: Lvalue<'tcx>,
prefix: &'pat [Pattern<'tcx>],
opt_slice: Option<&'pat Pattern<'tcx>>,
suffix: &'pat [Pattern<'tcx>])
-> 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 {
@ -79,17 +70,17 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
/// Helper for `prefix_suffix_slice` which just processes the prefix and suffix.
fn prefix_suffix(&mut self,
match_pairs: &mut Vec<MatchPair<'tcx>>,
lvalue: Lvalue<'tcx>,
prefix: Vec<PatternRef<'tcx>>,
suffix: Vec<PatternRef<'tcx>>) {
fn prefix_suffix<'pat>(&mut self,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
lvalue: Lvalue<'tcx>,
prefix: &'pat [Pattern<'tcx>],
suffix: &'pat [Pattern<'tcx>]) {
let min_length = prefix.len() + suffix.len();
assert!(min_length < u32::MAX as usize);
let min_length = min_length as u32;
let prefix_pairs: Vec<_> =
prefix.into_iter()
prefix.iter()
.enumerate()
.map(|(idx, subpattern)| {
let elem = ProjectionElem::ConstantIndex {
@ -98,12 +89,12 @@ impl<'a,'tcx> Builder<'a,'tcx> {
from_end: false,
};
let lvalue = lvalue.clone().elem(elem);
self.match_pair(lvalue, subpattern)
MatchPair::new(lvalue, subpattern)
})
.collect();
let suffix_pairs: Vec<_> =
suffix.into_iter()
suffix.iter()
.rev()
.enumerate()
.map(|(idx, subpattern)| {
@ -113,7 +104,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
from_end: true,
};
let lvalue = lvalue.clone().elem(elem);
self.match_pair(lvalue, subpattern)
MatchPair::new(lvalue, subpattern)
})
.collect();
@ -121,8 +112,8 @@ impl<'a,'tcx> Builder<'a,'tcx> {
}
}
impl<'tcx> MatchPair<'tcx> {
pub fn new(lvalue: Lvalue<'tcx>, pattern: Pattern<'tcx>) -> MatchPair<'tcx> {
impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
pub fn new(lvalue: Lvalue<'tcx>, pattern: &'pat Pattern<'tcx>) -> MatchPair<'pat, 'tcx> {
MatchPair {
lvalue: lvalue,
pattern: pattern,

View file

@ -8,8 +8,7 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
use hair;
use hair::cx::{Cx, PatNode};
use hair::cx::Cx;
use rustc::middle::region::CodeExtent;
use rustc::middle::ty::{FnOutput, Ty};
use rustc_data_structures::fnv::FnvHashMap;
@ -78,7 +77,7 @@ macro_rules! unpack {
pub fn construct<'a,'tcx>(mut hir: Cx<'a,'tcx>,
_span: Span,
implicit_arguments: Vec<Ty<'tcx>>,
explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
argument_extent: CodeExtent,
return_ty: FnOutput<'tcx>,
ast_block: &'tcx hir::Block)
@ -130,7 +129,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
fn args_and_body(&mut self,
mut block: BasicBlock,
implicit_arguments: Vec<Ty<'tcx>>,
explicit_arguments: Vec<(Ty<'tcx>, PatNode<'tcx>)>,
explicit_arguments: Vec<(Ty<'tcx>, &'tcx hir::Pat)>,
argument_extent: CodeExtent,
ast_block: &'tcx hir::Block)
-> BlockAnd<Vec<ArgDecl<'tcx>>>
@ -148,9 +147,10 @@ impl<'a,'tcx> Builder<'a,'tcx> {
.enumerate()
.map(|(index, (ty, pattern))| {
let lvalue = Lvalue::Arg(index as u32);
let pattern = this.hir.irrefutable_pat(pattern);
unpack!(block = this.lvalue_into_pattern(block,
argument_extent,
hair::PatternRef::Hair(pattern),
pattern,
&lvalue));
ArgDecl { ty: ty }
});

View file

@ -40,7 +40,7 @@ impl<'a,'tcx> Builder<'a,'tcx> {
StmtKind::Let { remainder_scope, init_scope, pattern, initializer: None, stmts } => {
this.in_scope(remainder_scope, block, |this| {
unpack!(block = this.in_scope(init_scope, block, |this| {
this.declare_bindings(remainder_scope, pattern);
this.declare_bindings(remainder_scope, &pattern);
block.unit()
}));
this.stmts(block, stmts)

View file

@ -10,7 +10,6 @@
use hair::*;
use hair::cx::Cx;
use hair::cx::pattern::PatNode;
use hair::cx::to_ref::ToRef;
use rustc::middle::region::{BlockRemainder, CodeExtentData};
use rustc_front::hir;
@ -65,12 +64,13 @@ fn mirror_stmts<'a,'tcx:'a,STMTS>(cx: &mut Cx<'a,'tcx>,
// they are within the scope of this let:
let following_stmts = mirror_stmts(cx, block_id, stmts);
let pattern = cx.irrefutable_pat(&local.pat);
result.push(StmtRef::Mirror(Box::new(Stmt {
span: stmt.span,
kind: StmtKind::Let {
remainder_scope: remainder_extent,
init_scope: cx.tcx.region_maps.node_extent(id),
pattern: PatNode::irrefutable(&local.pat).to_ref(),
pattern: pattern,
initializer: local.init.to_ref(),
stmts: following_stmts,
},

View file

@ -11,10 +11,8 @@
use hair::*;
use repr::*;
use rustc_data_structures::fnv::FnvHashMap;
use std::rc::Rc;
use hair::cx::Cx;
use hair::cx::block;
use hair::cx::pattern::PatNode;
use hair::cx::to_ref::ToRef;
use rustc::front::map;
use rustc::middle::const_eval;
@ -486,19 +484,20 @@ fn to_borrow_kind(m: hir::Mutability) -> BorrowKind {
}
}
fn convert_arm<'a, 'tcx: 'a>(cx: &Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
let map = if arm.pats.len() == 1 {
fn convert_arm<'a, 'tcx: 'a>(cx: &mut Cx<'a, 'tcx>, arm: &'tcx hir::Arm) -> Arm<'tcx> {
let mut map;
let opt_map = if arm.pats.len() == 1 {
None
} else {
let mut map = FnvHashMap();
map = FnvHashMap();
pat_util::pat_bindings(&cx.tcx.def_map, &arm.pats[0], |_, p_id, _, path| {
map.insert(path.node, p_id);
});
Some(Rc::new(map))
Some(&map)
};
Arm {
patterns: arm.pats.iter().map(|p| PatNode::new(p, map.clone()).to_ref()).collect(),
patterns: arm.pats.iter().map(|p| cx.refutable_pat(opt_map, p)).collect(),
guard: arm.guard.to_ref(),
body: arm.body.to_ref(),
}

View file

@ -41,8 +41,6 @@ impl<'a,'tcx> Cx<'a,'tcx> {
}
}
pub use self::pattern::PatNode;
impl<'a,'tcx:'a> Cx<'a, 'tcx> {
/// Normalizes `ast` into the appropriate `mirror` type.
pub fn mirror<M: Mirror<'tcx>>(&mut self, ast: M) -> M::Output {

View file

@ -10,10 +10,8 @@
use hair::*;
use hair::cx::Cx;
use hair::cx::to_ref::ToRef;
use repr::*;
use rustc_data_structures::fnv::FnvHashMap;
use std::rc::Rc;
use rustc::middle::const_eval;
use rustc::middle::def;
use rustc::middle::pat_util::{pat_is_resolved_const, pat_is_binding};
@ -36,183 +34,111 @@ use syntax::ptr::P;
/// _ => { ... }
/// }
/// ```
#[derive(Clone, Debug)]
pub struct PatNode<'tcx> {
pat: &'tcx hir::Pat,
binding_map: Option<Rc<FnvHashMap<ast::Name, ast::NodeId>>>,
struct PatCx<'patcx, 'cx: 'patcx, 'tcx: 'cx> {
cx: &'patcx mut Cx<'cx, 'tcx>,
binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>,
}
impl<'tcx> PatNode<'tcx> {
pub fn new(pat: &'tcx hir::Pat,
binding_map: Option<Rc<FnvHashMap<ast::Name, ast::NodeId>>>)
-> PatNode<'tcx> {
PatNode {
pat: pat,
impl<'cx, 'tcx> Cx<'cx, 'tcx> {
pub fn irrefutable_pat(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
PatCx::new(self, None).to_pat(pat)
}
pub fn refutable_pat(&mut self,
binding_map: Option<&FnvHashMap<ast::Name, ast::NodeId>>,
pat: &'tcx hir::Pat)
-> Pattern<'tcx> {
PatCx::new(self, binding_map).to_pat(pat)
}
}
impl<'patcx, 'cx, 'tcx> PatCx<'patcx, 'cx, 'tcx> {
fn new(cx: &'patcx mut Cx<'cx, 'tcx>,
binding_map: Option<&'patcx FnvHashMap<ast::Name, ast::NodeId>>)
-> PatCx<'patcx, 'cx, 'tcx> {
PatCx {
cx: cx,
binding_map: binding_map,
}
}
pub fn irrefutable(pat: &'tcx hir::Pat) -> PatNode<'tcx> {
PatNode::new(pat, None)
}
fn pat_ref<'a>(&self, pat: &'tcx hir::Pat) -> PatternRef<'tcx> {
PatNode::new(pat, self.binding_map.clone()).to_ref()
}
fn pat_refs<'a>(&self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<PatternRef<'tcx>> {
pats.iter().map(|p| self.pat_ref(p)).collect()
}
fn opt_pat_ref<'a>(&self, pat: &'tcx Option<P<hir::Pat>>) -> Option<PatternRef<'tcx>> {
pat.as_ref().map(|p| self.pat_ref(p))
}
fn slice_or_array_pattern<'a>(&self,
cx: &mut Cx<'a, 'tcx>,
ty: Ty<'tcx>,
prefix: &'tcx Vec<P<hir::Pat>>,
slice: &'tcx Option<P<hir::Pat>>,
suffix: &'tcx Vec<P<hir::Pat>>)
-> PatternKind<'tcx> {
match ty.sty {
ty::TySlice(..) =>
// matching a slice or fixed-length array
PatternKind::Slice {
prefix: self.pat_refs(prefix),
slice: self.opt_pat_ref(slice),
suffix: self.pat_refs(suffix),
},
ty::TyArray(_, len) => {
// fixed-length array
assert!(len >= prefix.len() + suffix.len());
PatternKind::Array {
prefix: self.pat_refs(prefix),
slice: self.opt_pat_ref(slice),
suffix: self.pat_refs(suffix),
}
}
_ => {
cx.tcx.sess.span_bug(self.pat.span, "unexpanded macro or bad constant etc");
}
}
}
fn variant_or_leaf<'a>(&self,
cx: &mut Cx<'a, 'tcx>,
subpatterns: Vec<FieldPatternRef<'tcx>>)
-> PatternKind<'tcx> {
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
match def {
def::DefVariant(enum_id, variant_id, _) => {
let adt_def = cx.tcx.lookup_adt_def(enum_id);
if adt_def.variants.len() > 1 {
PatternKind::Variant {
adt_def: adt_def,
variant_index: adt_def.variant_index_with_id(variant_id),
subpatterns: subpatterns,
}
} else {
PatternKind::Leaf { subpatterns: subpatterns }
}
}
// NB: resolving to DefStruct means the struct *constructor*,
// not the struct as a type.
def::DefStruct(..) | def::DefTy(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}
_ => {
cx.tcx.sess.span_bug(self.pat.span,
&format!("inappropriate def for pattern: {:?}", def));
}
}
}
}
impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
type Output = Pattern<'tcx>;
fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> {
let kind = match self.pat.node {
fn to_pat(&mut self, pat: &'tcx hir::Pat) -> Pattern<'tcx> {
let kind = match pat.node {
hir::PatWild => PatternKind::Wild,
hir::PatLit(ref value) => {
let value = const_eval::eval_const_expr(cx.tcx, value);
let value = const_eval::eval_const_expr(self.cx.tcx, value);
let value = Literal::Value { value: value };
PatternKind::Constant { value: value }
}
hir::PatRange(ref lo, ref hi) => {
let lo = const_eval::eval_const_expr(cx.tcx, lo);
let lo = const_eval::eval_const_expr(self.cx.tcx, lo);
let lo = Literal::Value { value: lo };
let hi = const_eval::eval_const_expr(cx.tcx, hi);
let hi = const_eval::eval_const_expr(self.cx.tcx, hi);
let hi = Literal::Value { value: hi };
PatternKind::Range { lo: lo, hi: hi }
},
hir::PatEnum(..) | hir::PatIdent(..) | hir::PatQPath(..)
if pat_is_resolved_const(&cx.tcx.def_map.borrow(), self.pat) =>
if pat_is_resolved_const(&self.cx.tcx.def_map.borrow(), pat) =>
{
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
match def {
def::DefConst(def_id) | def::DefAssociatedConst(def_id) =>
match const_eval::lookup_const_by_id(cx.tcx, def_id, Some(self.pat.id)) {
match const_eval::lookup_const_by_id(self.cx.tcx, def_id, Some(pat.id)) {
Some(const_expr) => {
let opt_value =
const_eval::eval_const_expr_partial(
cx.tcx, const_expr,
self.cx.tcx, const_expr,
const_eval::EvalHint::ExprTypeChecked,
None);
let literal = if let Ok(value) = opt_value {
Literal::Value { value: value }
} else {
let substs = cx.tcx.mk_substs(Substs::empty());
let substs = self.cx.tcx.mk_substs(Substs::empty());
Literal::Item { def_id: def_id, substs: substs }
};
PatternKind::Constant { value: literal }
}
None => {
cx.tcx.sess.span_bug(
self.pat.span,
self.cx.tcx.sess.span_bug(
pat.span,
&format!("cannot eval constant: {:?}", def_id))
}
},
_ =>
cx.tcx.sess.span_bug(
self.pat.span,
self.cx.tcx.sess.span_bug(
pat.span,
&format!("def not a constant: {:?}", def)),
}
}
hir::PatRegion(ref subpattern, _) |
hir::PatBox(ref subpattern) => {
PatternKind::Deref { subpattern: self.pat_ref(subpattern) }
PatternKind::Deref { subpattern: self.to_pat(subpattern) }
}
hir::PatVec(ref prefix, ref slice, ref suffix) => {
let ty = cx.tcx.node_id_to_type(self.pat.id);
let ty = self.cx.tcx.node_id_to_type(pat.id);
match ty.sty {
ty::TyRef(_, mt) =>
PatternKind::Deref {
subpattern: Pattern {
ty: mt.ty,
span: self.pat.span,
kind: self.slice_or_array_pattern(cx, mt.ty, prefix,
slice, suffix),
}.to_ref()
span: pat.span,
kind: Box::new(self.slice_or_array_pattern(pat, mt.ty, prefix,
slice, suffix)),
},
},
ty::TySlice(..) |
ty::TyArray(..) =>
self.slice_or_array_pattern(cx, ty, prefix, slice, suffix),
self.slice_or_array_pattern(pat, ty, prefix, slice, suffix),
ref sty =>
cx.tcx.sess.span_bug(
self.pat.span,
self.cx.tcx.sess.span_bug(
pat.span,
&format!("unexpanded type for vector pattern: {:?}", sty)),
}
}
@ -221,9 +147,9 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
let subpatterns =
subpatterns.iter()
.enumerate()
.map(|(i, subpattern)| FieldPatternRef {
.map(|(i, subpattern)| FieldPattern {
field: Field::new(i),
pattern: self.pat_ref(subpattern),
pattern: self.to_pat(subpattern),
})
.collect();
@ -231,13 +157,13 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
}
hir::PatIdent(bm, ref ident, ref sub)
if pat_is_binding(&cx.tcx.def_map.borrow(), self.pat) =>
if pat_is_binding(&self.cx.tcx.def_map.borrow(), pat) =>
{
let id = match self.binding_map {
None => self.pat.id,
None => pat.id,
Some(ref map) => map[&ident.node.name],
};
let var_ty = cx.tcx.node_id_to_type(self.pat.id);
let var_ty = self.cx.tcx.node_id_to_type(pat.id);
let region = match var_ty.sty {
ty::TyRef(&r, _) => Some(r),
_ => None,
@ -258,12 +184,12 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
name: ident.node.name,
var: id,
ty: var_ty,
subpattern: self.opt_pat_ref(sub),
subpattern: self.to_opt_pat(sub),
}
}
hir::PatIdent(..) => {
self.variant_or_leaf(cx, vec![])
self.variant_or_leaf(pat, vec![])
}
hir::PatEnum(_, ref opt_subpatterns) => {
@ -271,26 +197,26 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
opt_subpatterns.iter()
.flat_map(|v| v.iter())
.enumerate()
.map(|(i, field)| FieldPatternRef {
.map(|(i, field)| FieldPattern {
field: Field::new(i),
pattern: self.pat_ref(field),
pattern: self.to_pat(field),
})
.collect();
self.variant_or_leaf(cx, subpatterns)
self.variant_or_leaf(pat, subpatterns)
}
hir::PatStruct(_, ref fields, _) => {
let pat_ty = cx.tcx.node_id_to_type(self.pat.id);
let pat_ty = self.cx.tcx.node_id_to_type(pat.id);
let adt_def = match pat_ty.sty {
ty::TyStruct(adt_def, _) | ty::TyEnum(adt_def, _) => adt_def,
_ => {
cx.tcx.sess.span_bug(
self.pat.span,
self.cx.tcx.sess.span_bug(
pat.span,
"struct pattern not applied to struct or enum");
}
};
let def = cx.tcx.def_map.borrow().get(&self.pat.id).unwrap().full_def();
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
let variant_def = adt_def.variant_of_def(def);
let subpatterns =
@ -298,31 +224,104 @@ impl<'tcx> Mirror<'tcx> for PatNode<'tcx> {
.map(|field| {
let index = variant_def.index_of_field_named(field.node.name);
let index = index.unwrap_or_else(|| {
cx.tcx.sess.span_bug(
self.pat.span,
self.cx.tcx.sess.span_bug(
pat.span,
&format!("no field with name {:?}", field.node.name));
});
FieldPatternRef {
FieldPattern {
field: Field::new(index),
pattern: self.pat_ref(&field.node.pat),
pattern: self.to_pat(&field.node.pat),
}
})
.collect();
self.variant_or_leaf(cx, subpatterns)
self.variant_or_leaf(pat, subpatterns)
}
hir::PatQPath(..) => {
cx.tcx.sess.span_bug(self.pat.span, "unexpanded macro or bad constant etc");
self.cx.tcx.sess.span_bug(pat.span, "unexpanded macro or bad constant etc");
}
};
let ty = cx.tcx.node_id_to_type(self.pat.id);
let ty = self.cx.tcx.node_id_to_type(pat.id);
Pattern {
span: self.pat.span,
span: pat.span,
ty: ty,
kind: kind,
kind: Box::new(kind),
}
}
fn to_pats(&mut self, pats: &'tcx Vec<P<hir::Pat>>) -> Vec<Pattern<'tcx>> {
pats.iter().map(|p| self.to_pat(p)).collect()
}
fn to_opt_pat(&mut self, pat: &'tcx Option<P<hir::Pat>>) -> Option<Pattern<'tcx>> {
pat.as_ref().map(|p| self.to_pat(p))
}
fn slice_or_array_pattern(&mut self,
pat: &'tcx hir::Pat,
ty: Ty<'tcx>,
prefix: &'tcx Vec<P<hir::Pat>>,
slice: &'tcx Option<P<hir::Pat>>,
suffix: &'tcx Vec<P<hir::Pat>>)
-> PatternKind<'tcx> {
match ty.sty {
ty::TySlice(..) => {
// matching a slice or fixed-length array
PatternKind::Slice {
prefix: self.to_pats(prefix),
slice: self.to_opt_pat(slice),
suffix: self.to_pats(suffix),
}
}
ty::TyArray(_, len) => {
// fixed-length array
assert!(len >= prefix.len() + suffix.len());
PatternKind::Array {
prefix: self.to_pats(prefix),
slice: self.to_opt_pat(slice),
suffix: self.to_pats(suffix),
}
}
_ => {
self.cx.tcx.sess.span_bug(pat.span, "unexpanded macro or bad constant etc");
}
}
}
fn variant_or_leaf(&mut self,
pat: &'tcx hir::Pat,
subpatterns: Vec<FieldPattern<'tcx>>)
-> PatternKind<'tcx> {
let def = self.cx.tcx.def_map.borrow().get(&pat.id).unwrap().full_def();
match def {
def::DefVariant(enum_id, variant_id, _) => {
let adt_def = self.cx.tcx.lookup_adt_def(enum_id);
if adt_def.variants.len() > 1 {
PatternKind::Variant {
adt_def: adt_def,
variant_index: adt_def.variant_index_with_id(variant_id),
subpatterns: subpatterns,
}
} else {
PatternKind::Leaf { subpatterns: subpatterns }
}
}
// NB: resolving to DefStruct means the struct *constructor*,
// not the struct as a type.
def::DefStruct(..) | def::DefTy(..) => {
PatternKind::Leaf { subpatterns: subpatterns }
}
_ => {
self.cx.tcx.sess.span_bug(pat.span,
&format!("inappropriate def for pattern: {:?}", def));
}
}
}
}

View file

@ -10,7 +10,6 @@
use hair::*;
use hair::cx::pattern::PatNode;
use rustc_front::hir;
use syntax::ptr::P;
@ -43,22 +42,6 @@ impl<'a,'tcx:'a> ToRef for Expr<'tcx> {
}
}
impl<'a,'tcx:'a> ToRef for PatNode<'tcx> {
type Output = PatternRef<'tcx>;
fn to_ref(self) -> PatternRef<'tcx> {
PatternRef::Hair(self)
}
}
impl<'a,'tcx:'a> ToRef for Pattern<'tcx> {
type Output = PatternRef<'tcx>;
fn to_ref(self) -> PatternRef<'tcx> {
PatternRef::Mirror(Box::new(self))
}
}
impl<'a,'tcx:'a,T,U> ToRef for &'tcx Option<T>
where &'tcx T: ToRef<Output=U>
{

View file

@ -22,7 +22,7 @@ use rustc::middle::ty::{AdtDef, ClosureSubsts, Region, Ty};
use rustc_front::hir;
use syntax::ast;
use syntax::codemap::Span;
use self::cx::{Cx, PatNode};
use self::cx::Cx;
pub mod cx;
@ -72,7 +72,7 @@ pub enum StmtKind<'tcx> {
init_scope: CodeExtent,
/// let <PAT> = ...
pattern: PatternRef<'tcx>,
pattern: Pattern<'tcx>,
/// let pat = <INIT> ...
initializer: Option<ExprRef<'tcx>>,
@ -252,7 +252,7 @@ pub struct FieldExprRef<'tcx> {
#[derive(Clone, Debug)]
pub struct Arm<'tcx> {
pub patterns: Vec<PatternRef<'tcx>>,
pub patterns: Vec<Pattern<'tcx>>,
pub guard: Option<ExprRef<'tcx>>,
pub body: ExprRef<'tcx>,
}
@ -261,7 +261,7 @@ pub struct Arm<'tcx> {
pub struct Pattern<'tcx> {
pub ty: Ty<'tcx>,
pub span: Span,
pub kind: PatternKind<'tcx>,
pub kind: Box<PatternKind<'tcx>>,
}
#[derive(Copy, Clone, Debug)]
@ -281,23 +281,23 @@ pub enum PatternKind<'tcx> {
mode: BindingMode,
var: ast::NodeId,
ty: Ty<'tcx>,
subpattern: Option<PatternRef<'tcx>>,
subpattern: Option<Pattern<'tcx>>,
},
// Foo(...) or Foo{...} or Foo, where `Foo` is a variant name from an adt with >1 variants
Variant {
adt_def: AdtDef<'tcx>,
variant_index: usize,
subpatterns: Vec<FieldPatternRef<'tcx>>,
subpatterns: Vec<FieldPattern<'tcx>>,
},
// (...), Foo(...), Foo{...}, or Foo, where `Foo` is a variant name from an adt with 1 variant
Leaf {
subpatterns: Vec<FieldPatternRef<'tcx>>,
subpatterns: Vec<FieldPattern<'tcx>>,
},
Deref {
subpattern: PatternRef<'tcx>,
subpattern: Pattern<'tcx>,
}, // box P, &P, &mut P, etc
Constant {
@ -311,16 +311,16 @@ pub enum PatternKind<'tcx> {
// matches against a slice, checking the length and extracting elements
Slice {
prefix: Vec<PatternRef<'tcx>>,
slice: Option<PatternRef<'tcx>>,
suffix: Vec<PatternRef<'tcx>>,
prefix: Vec<Pattern<'tcx>>,
slice: Option<Pattern<'tcx>>,
suffix: Vec<Pattern<'tcx>>,
},
// fixed match against an array, irrefutable
Array {
prefix: Vec<PatternRef<'tcx>>,
slice: Option<PatternRef<'tcx>>,
suffix: Vec<PatternRef<'tcx>>,
prefix: Vec<Pattern<'tcx>>,
slice: Option<Pattern<'tcx>>,
suffix: Vec<Pattern<'tcx>>,
},
}
@ -331,15 +331,9 @@ pub enum BindingMode {
}
#[derive(Clone, Debug)]
pub enum PatternRef<'tcx> {
Hair(PatNode<'tcx>),
Mirror(Box<Pattern<'tcx>>),
}
#[derive(Clone, Debug)]
pub struct FieldPatternRef<'tcx> {
pub struct FieldPattern<'tcx> {
pub field: Field,
pub pattern: PatternRef<'tcx>,
pub pattern: Pattern<'tcx>,
}
///////////////////////////////////////////////////////////////////////////
@ -400,25 +394,6 @@ impl<'tcx> Mirror<'tcx> for StmtRef<'tcx> {
}
}
impl<'tcx> Mirror<'tcx> for Pattern<'tcx> {
type Output = Pattern<'tcx>;
fn make_mirror<'a>(self, _: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> {
self
}
}
impl<'tcx> Mirror<'tcx> for PatternRef<'tcx> {
type Output = Pattern<'tcx>;
fn make_mirror<'a>(self, hir: &mut Cx<'a, 'tcx>) -> Pattern<'tcx> {
match self {
PatternRef::Hair(h) => h.make_mirror(hir),
PatternRef::Mirror(m) => *m,
}
}
}
impl<'tcx> Mirror<'tcx> for Block<'tcx> {
type Output = Block<'tcx>;

View file

@ -23,7 +23,7 @@ extern crate rustc_front;
use build;
use dot;
use repr::Mir;
use hair::cx::{PatNode, Cx};
use hair::cx::Cx;
use std::fs::File;
use self::rustc::middle::infer;
@ -211,7 +211,7 @@ fn build_mir<'a,'tcx:'a>(cx: Cx<'a,'tcx>,
.iter()
.enumerate()
.map(|(index, arg)| {
(fn_sig.inputs[index], PatNode::irrefutable(&arg.pat))
(fn_sig.inputs[index], &*arg.pat)
})
.collect();