提交 f1f5c04c 编写于 作者: B bors

Auto merge of #29763 - nikomatsakis:mir-29227, r=nikomatsakis

The older algorithm was pretty inefficient for big matches. Fixes #29227. (On my computer, MIR construction on this test case goes from 9.9s to 0.025s.) Whereas before we had a loop like:

- for all outcomes of the test we are performing
    - for all candidates
        - check whether candidate is relevant to outcome

We now do:

- for all candidates
    - determine which outcomes the candidate is relevant to

Since the number of outcomes in this case is proportional to the number of candidates, the original algorithm turned out to be O(n^2), and the newer one is just O(n).

This PR also does some minor speedups by eagerly mirroring all patterns, so that we can just pass around `&Pattern<'tcx>`, which makes cloning cheaper. We could probably go a bit further in this direction.

r? @Aatch
......@@ -44,7 +44,7 @@ pub fn match_expr(&mut self,
// 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 @@ pub fn match_expr(&mut self,
// 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 @@ pub fn match_expr(&mut self,
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 @@ pub fn expr_into_pattern(&mut self,
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 @@ pub fn lvalue_into_pattern(&mut self,
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);
......@@ -346,17 +345,20 @@ 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() {
let applicable_candidates: Vec<Candidate<'tcx>> =
candidates.iter()
.filter_map(|candidate| {
self.candidate_under_assumption(&match_pair.lvalue,
&test.kind,
outcome,
candidate)
})
.collect();
self.match_candidates(span, arm_blocks, applicable_candidates, target_block);
let mut target_candidates: Vec<_> = (0..target_blocks.len()).map(|_| vec![]).collect();
for candidate in &candidates {
self.sort_candidate(&match_pair.lvalue,
&test,
candidate,
&mut target_candidates);
}
for (target_block, target_candidates) in
target_blocks.into_iter()
.zip(target_candidates.into_iter())
{
self.match_candidates(span, arm_blocks, target_candidates, target_block);
}
}
......@@ -372,11 +374,11 @@ fn match_candidates(&mut self,
/// 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);
......
......@@ -30,10 +30,10 @@
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 @@ pub fn simplify_candidate(&mut self,
/// 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 @@ fn simplify_match_pair(&mut self,
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 @@ fn simplify_match_pair(&mut self,
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 @@ fn simplify_match_pair(&mut self,
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)
}
......
......@@ -15,26 +15,18 @@
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 @@ pub fn match_pair(&mut self,
/// 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 @@ pub fn prefix_suffix_slice(&mut self,
}
/// 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 @@ fn prefix_suffix(&mut self,
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 @@ fn prefix_suffix(&mut self,
from_end: true,
};
let lvalue = lvalue.clone().elem(elem);
self.match_pair(lvalue, subpattern)
MatchPair::new(lvalue, subpattern)
})
.collect();
......@@ -121,8 +112,8 @@ fn prefix_suffix(&mut self,
}
}
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,
......
......@@ -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 @@ fn unit(self) -> BlockAnd<()> {
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 @@ fn args_and_body(&mut self,
.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 }
});
......
......@@ -40,7 +40,7 @@ pub fn stmt(&mut self, mut block: BasicBlock, stmt: StmtRef<'tcx>) -> BlockAnd<(
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)
......
......@@ -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,
},
......
......@@ -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(),
}
......
......@@ -41,8 +41,6 @@ pub fn new(infcx: &'a InferCtxt<'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 {
......
......@@ -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 @@
/// _ => { ... }
/// }
/// ```
#[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,
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()
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)
}
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");
}
}
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)
}
}
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<'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,
}
}
}
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 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'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 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'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 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'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 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'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 @@ fn make_mirror<'a>(self, cx: &mut Cx<'a, 'tcx>) -> Pattern<'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));
}
}
}
}
......@@ -10,7 +10,6 @@
use hair::*;
use hair::cx::pattern::PatNode;
use rustc_front::hir;
use syntax::ptr::P;
......@@ -43,22 +42,6 @@ fn to_ref(self) -> ExprRef<'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>
{
......
......@@ -22,7 +22,7 @@
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 @@ fn make_mirror<'a>(self, _: &mut Cx<'a,'tcx>) -> Stmt<'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>;
......
......@@ -23,7 +23,7 @@
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();
......
此差异已折叠。
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册