Auto merge of #120904 - Nadrieril:match-lowering-intermediate-repr, r=matthewjasper

match lowering: eagerly simplify match pairs

This removes one important complication from match lowering. Before this, match pair simplification (which includes collecting bindings and type ascriptions) was intertwined with the whole match lowering algorithm.

I'm avoiding this by storing in each `MatchPair` the sub-`MatchPair`s that correspond to its subfields. This makes it possible to simplify everything (except or-patterns) in `Candidate::new()`.

This should open up further simplifications. It will also give us proper control over the order of bindings.

r? `@matthewjasper`
This commit is contained in:
bors 2024-02-21 01:11:34 +00:00
commit 4e65074933
5 changed files with 219 additions and 260 deletions

View File

@ -22,8 +22,6 @@
use rustc_span::symbol::Symbol;
use rustc_span::{BytePos, Pos, Span};
use rustc_target::abi::VariantIdx;
use smallvec::{smallvec, SmallVec};
// helper functions, broken out by category:
mod simplify;
mod test;
@ -949,12 +947,16 @@ struct Candidate<'pat, 'tcx> {
has_guard: bool,
/// All of these must be satisfied...
match_pairs: SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
// Invariant: all the `MatchPair`s are recursively simplified.
// Invariant: or-patterns must be sorted at the end.
match_pairs: Vec<MatchPair<'pat, 'tcx>>,
/// ...these bindings established...
// Invariant: not mutated outside `Candidate::new()`.
bindings: Vec<Binding<'tcx>>,
/// ...and these types asserted...
// Invariant: not mutated outside `Candidate::new()`.
ascriptions: Vec<Ascription<'tcx>>,
/// ...and if this is non-empty, one of these subcandidates also has to match...
@ -974,19 +976,27 @@ fn new(
place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
has_guard: bool,
cx: &Builder<'_, 'tcx>,
cx: &mut Builder<'_, 'tcx>,
) -> Self {
Candidate {
let mut candidate = Candidate {
span: pattern.span,
has_guard,
match_pairs: smallvec![MatchPair::new(place, pattern, cx)],
match_pairs: vec![MatchPair::new(place, pattern, cx)],
bindings: Vec::new(),
ascriptions: Vec::new(),
subcandidates: Vec::new(),
otherwise_block: None,
pre_binding_block: None,
next_candidate_pre_binding_block: None,
}
};
cx.simplify_match_pairs(
&mut candidate.match_pairs,
&mut candidate.bindings,
&mut candidate.ascriptions,
);
candidate
}
/// Visit the leaf candidates (those with no subcandidates) contained in
@ -1042,13 +1052,18 @@ struct Ascription<'tcx> {
variance: ty::Variance,
}
#[derive(Clone, Debug)]
#[derive(Debug)]
pub(crate) struct MatchPair<'pat, 'tcx> {
// this place...
// This place...
place: PlaceBuilder<'tcx>,
// ... must match this pattern.
// Invariant: after creation and simplification in `Candidate::new()`, all match pairs must be
// simplified, i.e. require a test.
pattern: &'pat Pat<'tcx>,
/// Precomputed sub-match pairs of `pattern`.
subpairs: Vec<Self>,
}
/// See [`Test`] for more.
@ -1165,12 +1180,25 @@ fn match_candidates<'pat>(
candidates: &mut [&mut Candidate<'pat, 'tcx>],
fake_borrows: &mut Option<FxIndexSet<Place<'tcx>>>,
) {
// Start by simplifying candidates. Once this process is complete, all
// the match pairs which remain require some form of test, whether it
// be a switch or pattern comparison.
let mut split_or_candidate = false;
for candidate in &mut *candidates {
split_or_candidate |= self.simplify_candidate(candidate);
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
&*candidate.match_pairs
{
// Split a candidate in which the only match-pair is an or-pattern into multiple
// candidates. This is so that
//
// match x {
// 0 | 1 => { ... },
// 2 | 3 => { ... },
// }
//
// only generates a single switch.
candidate.subcandidates =
self.create_or_subcandidates(place, pats, candidate.has_guard);
candidate.match_pairs.pop();
split_or_candidate = true;
}
}
ensure_sufficient_stack(|| {

View File

@ -6,7 +6,7 @@
//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
//!
//! The `simplify_candidate` routine just repeatedly applies these
//! The `simplify_match_pairs` routine just repeatedly applies these
//! sort of simplifications until there is nothing left to
//! simplify. Match pairs cannot be simplified if they require some
//! sort of test: for example, testing which variant an enum is, or
@ -22,25 +22,15 @@
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// Simplify a candidate so that all match pairs require a test.
///
/// This method will also split a candidate, in which the only
/// match-pair is an or-pattern, into multiple candidates.
/// This is so that
///
/// match x {
/// 0 | 1 => { ... },
/// 2 | 3 => { ... },
/// }
///
/// only generates a single switch. If this happens this method returns
/// `true`.
#[instrument(skip(self, candidate), level = "debug")]
pub(super) fn simplify_candidate<'pat>(
/// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
/// ascriptions in the provided `Vec`s.
#[instrument(skip(self), level = "debug")]
pub(super) fn simplify_match_pairs<'pat>(
&mut self,
candidate: &mut Candidate<'pat, 'tcx>,
) -> bool {
debug!("{candidate:#?}");
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
candidate_bindings: &mut Vec<Binding<'tcx>>,
candidate_ascriptions: &mut Vec<Ascription<'tcx>>,
) {
// In order to please the borrow checker, in a pattern like `x @ pat` we must lower the
// bindings in `pat` before `x`. E.g. (#69971):
//
@ -68,105 +58,96 @@ pub(super) fn simplify_candidate<'pat>(
// bindings in iter 2: [6, 7]
//
// final bindings: [6, 7, 4, 5, 1, 2, 3]
let mut accumulated_bindings = mem::take(&mut candidate.bindings);
// Repeatedly simplify match pairs until fixed point is reached
let mut accumulated_bindings = mem::take(candidate_bindings);
let mut simplified_match_pairs = Vec::new();
// Repeatedly simplify match pairs until we're left with only unsimplifiable ones.
loop {
let mut changed = false;
for match_pair in mem::take(&mut candidate.match_pairs) {
match self.simplify_match_pair(match_pair, candidate) {
Ok(()) => {
changed = true;
}
Err(match_pair) => {
candidate.match_pairs.push(match_pair);
}
for match_pair in mem::take(match_pairs) {
if let Err(match_pair) = self.simplify_match_pair(
match_pair,
candidate_bindings,
candidate_ascriptions,
match_pairs,
) {
simplified_match_pairs.push(match_pair);
}
}
// This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
candidate.bindings.extend_from_slice(&accumulated_bindings);
mem::swap(&mut candidate.bindings, &mut accumulated_bindings);
candidate.bindings.clear();
candidate_bindings.extend_from_slice(&accumulated_bindings);
mem::swap(candidate_bindings, &mut accumulated_bindings);
candidate_bindings.clear();
if !changed {
// If we were not able to simplify anymore, done.
if match_pairs.is_empty() {
break;
}
}
// Store computed bindings back in `candidate`.
mem::swap(&mut candidate.bindings, &mut accumulated_bindings);
let did_expand_or =
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place }] =
&*candidate.match_pairs
{
candidate.subcandidates = self.create_or_subcandidates(candidate, place, pats);
candidate.match_pairs.clear();
true
} else {
false
};
// Store computed bindings back in `candidate_bindings`.
mem::swap(candidate_bindings, &mut accumulated_bindings);
// Store simplified match pairs back in `match_pairs`.
mem::swap(match_pairs, &mut simplified_match_pairs);
// Move or-patterns to the end, because they can result in us
// creating additional candidates, so we want to test them as
// late as possible.
candidate.match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
debug!(simplified = ?candidate, "simplify_candidate");
did_expand_or
match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
debug!(simplified = ?match_pairs, "simplify_match_pairs");
}
/// Given `candidate` that has a single or-pattern for its match-pairs,
/// creates a fresh candidate for each of its input subpatterns passed via
/// `pats`.
fn create_or_subcandidates<'pat>(
/// Create a new candidate for each pattern in `pats`, and recursively simplify tje
/// single-or-pattern case.
pub(super) fn create_or_subcandidates<'pat>(
&mut self,
candidate: &Candidate<'pat, 'tcx>,
place: &PlaceBuilder<'tcx>,
pats: &'pat [Box<Pat<'tcx>>],
has_guard: bool,
) -> Vec<Candidate<'pat, 'tcx>> {
pats.iter()
.map(|box pat| {
let mut candidate = Candidate::new(place.clone(), pat, candidate.has_guard, self);
self.simplify_candidate(&mut candidate);
let mut candidate = Candidate::new(place.clone(), pat, has_guard, self);
if let [MatchPair { pattern: Pat { kind: PatKind::Or { pats }, .. }, place, .. }] =
&*candidate.match_pairs
{
candidate.subcandidates =
self.create_or_subcandidates(place, pats, candidate.has_guard);
candidate.match_pairs.pop();
}
candidate
})
.collect()
}
/// Tries to simplify `match_pair`, returning `Ok(())` if
/// successful. If successful, new match pairs and bindings will
/// have been pushed into the candidate. If no simplification is
/// possible, `Err` is returned and no changes are made to
/// candidate.
/// Tries to simplify `match_pair`, returning `Ok(())` if successful. If successful, new match
/// pairs and bindings will have been pushed into the respective `Vec`s. If no simplification is
/// possible, `Err` is returned.
fn simplify_match_pair<'pat>(
&mut self,
match_pair: MatchPair<'pat, 'tcx>,
candidate: &mut Candidate<'pat, 'tcx>,
mut match_pair: MatchPair<'pat, 'tcx>,
bindings: &mut Vec<Binding<'tcx>>,
ascriptions: &mut Vec<Ascription<'tcx>>,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
) -> Result<(), MatchPair<'pat, 'tcx>> {
match match_pair.pattern.kind {
PatKind::Leaf { .. }
| PatKind::Deref { .. }
| PatKind::Array { .. }
| PatKind::Never
| PatKind::Wild
| PatKind::Error(_) => {}
PatKind::AscribeUserType {
ref subpattern,
ascription: thir::Ascription { ref annotation, variance },
..
} => {
// Apply the type ascription to the value at `match_pair.place`
if let Some(source) = match_pair.place.try_to_place(self) {
candidate.ascriptions.push(Ascription {
ascriptions.push(Ascription {
annotation: annotation.clone(),
source,
variance,
});
}
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
Ok(())
}
PatKind::Wild | PatKind::Error(_) => {
// nothing left to do
Ok(())
}
PatKind::Binding {
@ -175,35 +156,17 @@ fn simplify_match_pair<'pat>(
mode,
var,
ty: _,
ref subpattern,
subpattern: _,
is_primary: _,
} => {
if let Some(source) = match_pair.place.try_to_place(self) {
candidate.bindings.push(Binding {
bindings.push(Binding {
span: match_pair.pattern.span,
source,
var_id: var,
binding_mode: mode,
});
}
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
candidate.match_pairs.push(MatchPair::new(match_pair.place, subpattern, self));
}
Ok(())
}
PatKind::Never => {
// A never pattern acts like a load from the place.
// FIXME(never_patterns): load from the place
Ok(())
}
PatKind::Constant { .. } => {
// FIXME normalize patterns when possible
Err(match_pair)
}
PatKind::InlineConstant { subpattern: ref pattern, def } => {
@ -232,42 +195,33 @@ fn simplify_match_pair<'pat>(
span,
user_ty: Box::new(user_ty),
};
candidate.ascriptions.push(Ascription {
ascriptions.push(Ascription {
annotation,
source,
variance: ty::Contravariant,
});
}
candidate.match_pairs.push(MatchPair::new(match_pair.place, pattern, self));
}
Ok(())
PatKind::Constant { .. } => {
// FIXME normalize patterns when possible
return Err(match_pair);
}
PatKind::Range(ref range) => {
if let Some(true) = range.is_full_range(self.tcx) {
// Irrefutable pattern match.
return Ok(());
if range.is_full_range(self.tcx) != Some(true) {
return Err(match_pair);
}
Err(match_pair)
}
PatKind::Slice { ref prefix, ref slice, ref suffix } => {
if prefix.is_empty() && slice.is_some() && suffix.is_empty() {
// irrefutable
self.prefix_slice_suffix(
&mut candidate.match_pairs,
&match_pair.place,
prefix,
slice,
suffix,
);
Ok(())
} else {
Err(match_pair)
if !(prefix.is_empty() && slice.is_some() && suffix.is_empty()) {
self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
return Err(match_pair);
}
}
PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => {
PatKind::Variant { adt_def, args, variant_index, subpatterns: _ } => {
let irrefutable = adt_def.variants().iter_enumerated().all(|(i, v)| {
i == variant_index || {
(self.tcx.features().exhaustive_patterns
@ -279,41 +233,17 @@ fn simplify_match_pair<'pat>(
}
}) && (adt_def.did().is_local()
|| !adt_def.is_variant_list_non_exhaustive());
if irrefutable {
let place_builder = match_pair.place.downcast(adt_def, variant_index);
candidate
.match_pairs
.extend(self.field_match_pairs(place_builder, subpatterns));
Ok(())
} else {
Err(match_pair)
if !irrefutable {
self.simplify_match_pairs(&mut match_pair.subpairs, bindings, ascriptions);
return Err(match_pair);
}
}
PatKind::Array { ref prefix, ref slice, ref suffix } => {
self.prefix_slice_suffix(
&mut candidate.match_pairs,
&match_pair.place,
prefix,
slice,
suffix,
);
Ok(())
}
PatKind::Leaf { ref subpatterns } => {
// tuple struct, match subpats (if any)
candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns));
Ok(())
}
PatKind::Deref { ref subpattern } => {
let place_builder = match_pair.place.deref();
candidate.match_pairs.push(MatchPair::new(place_builder, subpattern, self));
Ok(())
}
PatKind::Or { .. } => Err(match_pair),
PatKind::Or { .. } => return Err(match_pair),
}
// Simplifiable pattern; we replace it with its subpairs.
match_pairs.append(&mut match_pair.subpairs);
Ok(())
}
}

View File

@ -590,25 +590,22 @@ pub(super) fn sort_candidate<'pat>(
let (match_pair_index, match_pair) =
candidate.match_pairs.iter().enumerate().find(|&(_, mp)| mp.place == *test_place)?;
match (&test.kind, &match_pair.pattern.kind) {
let fully_matched;
let ret = match (&test.kind, &match_pair.pattern.kind) {
// If we are performing a variant switch, then this
// informs variant patterns, but nothing else.
(
&TestKind::Switch { adt_def: tested_adt_def, .. },
&PatKind::Variant { adt_def, variant_index, ref subpatterns, .. },
&PatKind::Variant { adt_def, variant_index, .. },
) => {
assert_eq!(adt_def, tested_adt_def);
self.candidate_after_variant_switch(
match_pair_index,
adt_def,
variant_index,
subpatterns,
candidate,
);
fully_matched = true;
Some(variant_index.as_usize())
}
(&TestKind::Switch { .. }, _) => None,
(&TestKind::Switch { .. }, _) => {
fully_matched = false;
None
}
// If we are performing a switch over integers, then this informs integer
// equality, but nothing else.
@ -618,12 +615,12 @@ pub(super) fn sort_candidate<'pat>(
(TestKind::SwitchInt { switch_ty: _, options }, PatKind::Constant { value })
if is_switch_ty(match_pair.pattern.ty) =>
{
fully_matched = true;
let index = options.get_index_of(value).unwrap();
self.candidate_without_match_pair(match_pair_index, candidate);
Some(index)
}
(TestKind::SwitchInt { switch_ty: _, options }, PatKind::Range(range)) => {
fully_matched = false;
let not_contained =
self.values_not_contained_in_range(&*range, options).unwrap_or(false);
@ -633,8 +630,10 @@ pub(super) fn sort_candidate<'pat>(
options.len()
})
}
(&TestKind::SwitchInt { .. }, _) => None,
(&TestKind::SwitchInt { .. }, _) => {
fully_matched = false;
None
}
(
&TestKind::Len { len: test_len, op: BinOp::Eq },
@ -645,34 +644,30 @@ pub(super) fn sort_candidate<'pat>(
(Ordering::Equal, &None) => {
// on true, min_len = len = $actual_length,
// on false, len != $actual_length
self.candidate_after_slice_test(
match_pair_index,
candidate,
prefix,
slice,
suffix,
);
fully_matched = true;
Some(0)
}
(Ordering::Less, _) => {
// test_len < pat_len. If $actual_len = test_len,
// then $actual_len < pat_len and we don't have
// enough elements.
fully_matched = false;
Some(1)
}
(Ordering::Equal | Ordering::Greater, &Some(_)) => {
// This can match both if $actual_len = test_len >= pat_len,
// and if $actual_len > test_len. We can't advance.
fully_matched = false;
None
}
(Ordering::Greater, &None) => {
// test_len != pat_len, so if $actual_len = test_len, then
// $actual_len != pat_len.
fully_matched = false;
Some(1)
}
}
}
(
&TestKind::Len { len: test_len, op: BinOp::Ge },
PatKind::Slice { prefix, slice, suffix },
@ -683,29 +678,26 @@ pub(super) fn sort_candidate<'pat>(
(Ordering::Equal, &Some(_)) => {
// $actual_len >= test_len = pat_len,
// so we can match.
self.candidate_after_slice_test(
match_pair_index,
candidate,
prefix,
slice,
suffix,
);
fully_matched = true;
Some(0)
}
(Ordering::Less, _) | (Ordering::Equal, &None) => {
// test_len <= pat_len. If $actual_len < test_len,
// then it is also < pat_len, so the test passing is
// necessary (but insufficient).
fully_matched = false;
Some(0)
}
(Ordering::Greater, &None) => {
// test_len > pat_len. If $actual_len >= test_len > pat_len,
// then we know we won't have a match.
fully_matched = false;
Some(1)
}
(Ordering::Greater, &Some(_)) => {
// test_len < pat_len, and is therefore less
// strict. This can still go both ways.
fully_matched = false;
None
}
}
@ -713,16 +705,17 @@ pub(super) fn sort_candidate<'pat>(
(TestKind::Range(test), PatKind::Range(pat)) => {
if test == pat {
self.candidate_without_match_pair(match_pair_index, candidate);
return Some(0);
fully_matched = true;
Some(0)
} else {
fully_matched = false;
// If the testing range does not overlap with pattern range,
// the pattern can be matched only if this test fails.
if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
}
// If the testing range does not overlap with pattern range,
// the pattern can be matched only if this test fails.
if !test.overlaps(pat, self.tcx, self.param_env)? { Some(1) } else { None }
}
(TestKind::Range(range), &PatKind::Constant { value }) => {
fully_matched = false;
if !range.contains(value, self.tcx, self.param_env)? {
// `value` is not contained in the testing range,
// so `value` can be matched only if this test fails.
@ -731,8 +724,10 @@ pub(super) fn sort_candidate<'pat>(
None
}
}
(&TestKind::Range { .. }, _) => None,
(&TestKind::Range { .. }, _) => {
fully_matched = false;
None
}
(&TestKind::Eq { .. } | &TestKind::Len { .. }, _) => {
// The call to `self.test(&match_pair)` below is not actually used to generate any
@ -751,64 +746,26 @@ pub(super) fn sort_candidate<'pat>(
// FIXME(#29623) we can be more clever here
let pattern_test = self.test(match_pair);
if pattern_test.kind == test.kind {
self.candidate_without_match_pair(match_pair_index, candidate);
fully_matched = true;
Some(0)
} else {
fully_matched = false;
None
}
}
};
if fully_matched {
// Replace the match pair by its sub-pairs.
let match_pair = candidate.match_pairs.remove(match_pair_index);
candidate.match_pairs.extend(match_pair.subpairs);
// Move or-patterns to the end.
candidate
.match_pairs
.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
}
}
fn candidate_without_match_pair(
&mut self,
match_pair_index: usize,
candidate: &mut Candidate<'_, 'tcx>,
) {
candidate.match_pairs.remove(match_pair_index);
}
fn candidate_after_slice_test<'pat>(
&mut self,
match_pair_index: usize,
candidate: &mut Candidate<'pat, 'tcx>,
prefix: &'pat [Box<Pat<'tcx>>],
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
suffix: &'pat [Box<Pat<'tcx>>],
) {
let removed_place = candidate.match_pairs.remove(match_pair_index).place;
self.prefix_slice_suffix(
&mut candidate.match_pairs,
&removed_place,
prefix,
opt_slice,
suffix,
);
}
fn candidate_after_variant_switch<'pat>(
&mut self,
match_pair_index: usize,
adt_def: ty::AdtDef<'tcx>,
variant_index: VariantIdx,
subpatterns: &'pat [FieldPat<'tcx>],
candidate: &mut Candidate<'pat, 'tcx>,
) {
let match_pair = candidate.match_pairs.remove(match_pair_index);
// So, if we have a match-pattern like `x @ Enum::Variant(P1, P2)`,
// we want to create a set of derived match-patterns like
// `(x as Variant).0 @ P1` and `(x as Variant).1 @ P1`.
let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)`
let consequent_match_pairs = subpatterns.iter().map(|subpattern| {
// e.g., `(x as Variant).0`
let place = downcast_place
.clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty));
// e.g., `(x as Variant).0 @ P1`
MatchPair::new(place, &subpattern.pattern, self)
});
candidate.match_pairs.extend(consequent_match_pairs);
ret
}
fn error_simplifiable<'pat>(&mut self, match_pair: &MatchPair<'pat, 'tcx>) -> ! {

View File

@ -6,7 +6,6 @@
use rustc_middle::thir::*;
use rustc_middle::ty;
use rustc_middle::ty::TypeVisitableExt;
use smallvec::SmallVec;
impl<'a, 'tcx> Builder<'a, 'tcx> {
pub(crate) fn field_match_pairs<'pat>(
@ -26,7 +25,7 @@ pub(crate) fn field_match_pairs<'pat>(
pub(crate) fn prefix_slice_suffix<'pat>(
&mut self,
match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>,
match_pairs: &mut Vec<MatchPair<'pat, 'tcx>>,
place: &PlaceBuilder<'tcx>,
prefix: &'pat [Box<Pat<'tcx>>],
opt_slice: &'pat Option<Box<Pat<'tcx>>>,
@ -97,7 +96,7 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> {
pub(in crate::build) fn new(
mut place: PlaceBuilder<'tcx>,
pattern: &'pat Pat<'tcx>,
cx: &Builder<'_, 'tcx>,
cx: &mut Builder<'_, 'tcx>,
) -> MatchPair<'pat, 'tcx> {
// Force the place type to the pattern's type.
// FIXME(oli-obk): can we use this to simplify slice/array pattern hacks?
@ -117,6 +116,51 @@ pub(in crate::build) fn new(
if may_need_cast {
place = place.project(ProjectionElem::OpaqueCast(pattern.ty));
}
MatchPair { place, pattern }
let mut subpairs = Vec::new();
match pattern.kind {
PatKind::Constant { .. }
| PatKind::Range(_)
| PatKind::Or { .. }
| PatKind::Never
| PatKind::Wild
| PatKind::Error(_) => {}
PatKind::AscribeUserType { ref subpattern, .. } => {
subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
}
PatKind::Binding { ref subpattern, .. } => {
if let Some(subpattern) = subpattern.as_ref() {
// this is the `x @ P` case; have to keep matching against `P` now
subpairs.push(MatchPair::new(place.clone(), subpattern, cx));
}
}
PatKind::InlineConstant { subpattern: ref pattern, .. } => {
subpairs.push(MatchPair::new(place.clone(), pattern, cx));
}
PatKind::Slice { ref prefix, ref slice, ref suffix }
| PatKind::Array { ref prefix, ref slice, ref suffix } => {
cx.prefix_slice_suffix(&mut subpairs, &place, prefix, slice, suffix);
}
PatKind::Variant { adt_def, variant_index, ref subpatterns, .. } => {
let downcast_place = place.clone().downcast(adt_def, variant_index); // `(x as Variant)`
subpairs = cx.field_match_pairs(downcast_place, subpatterns);
}
PatKind::Leaf { ref subpatterns } => {
subpairs = cx.field_match_pairs(place.clone(), subpatterns);
}
PatKind::Deref { ref subpattern } => {
let place_builder = place.clone().deref();
subpairs.push(MatchPair::new(place_builder, subpattern, cx));
}
}
MatchPair { place, pattern, subpairs }
}
}

View File

@ -19,7 +19,8 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
bb0: {
PlaceMention(_1);
switchInt((_1.0: u32)) -> [1: bb2, 4: bb2, otherwise: bb1];
_2 = discriminant((_1.2: std::option::Option<i32>));
switchInt(move _2) -> [0: bb3, 1: bb2, otherwise: bb1];
}
bb1: {
@ -28,12 +29,11 @@ fn match_tuple(_1: (u32, bool, Option<i32>, u32)) -> u32 {
}
bb2: {
_2 = discriminant((_1.2: std::option::Option<i32>));
switchInt(move _2) -> [0: bb4, 1: bb3, otherwise: bb1];
switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb3, 8: bb3, otherwise: bb1];
}
bb3: {
switchInt((((_1.2: std::option::Option<i32>) as Some).0: i32)) -> [1: bb4, 8: bb4, otherwise: bb1];
switchInt((_1.0: u32)) -> [1: bb4, 4: bb4, otherwise: bb1];
}
bb4: {