1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129
//! Simplifying Candidates
//!
//! *Simplifying* a match pair `place @ pattern` means breaking it down
//! into bindings or other, simpler match pairs. For example:
//!
//! - `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_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
//! testing a value against a constant.
use crate::build::expr::as_place::PlaceBuilder;
use crate::build::matches::{Ascription, Binding, Candidate, MatchPair, TestCase};
use crate::build::Builder;
use rustc_middle::thir::{Pat, PatKind};
use std::mem;
impl<'a, 'tcx> Builder<'a, 'tcx> {
/// 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,
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):
//
// struct NonCopyStruct {
// copy_field: u32,
// }
//
// fn foo1(x: NonCopyStruct) {
// let y @ NonCopyStruct { copy_field: z } = x;
// // the above should turn into
// let z = x.copy_field;
// let y = x;
// }
//
// We can't just reverse the binding order, because we must preserve pattern-order
// otherwise, e.g. in `let (Some(a), Some(b)) = (x, y)`. Our rule then is: deepest-first,
// and bindings at the same depth stay in source order.
//
// To do this, every time around the loop we prepend the newly found bindings to the
// bindings we already had.
//
// example:
// candidate.bindings = [1, 2, 3]
// bindings in iter 1: [4, 5]
// bindings in iter 2: [6, 7]
//
// final bindings: [6, 7, 4, 5, 1, 2, 3]
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 {
for mut match_pair in mem::take(match_pairs) {
if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
if let Some(binding) = binding {
candidate_bindings.push(binding);
}
if let Some(ascription) = ascription {
candidate_ascriptions.push(ascription);
}
// Simplifiable pattern; we replace it with its subpairs and simplify further.
match_pairs.append(&mut match_pair.subpairs);
} else {
// Unsimplifiable pattern; we recursively simplify its subpairs and don't
// process it further.
self.simplify_match_pairs(
&mut match_pair.subpairs,
candidate_bindings,
candidate_ascriptions,
);
simplified_match_pairs.push(match_pair);
}
}
// This does: accumulated_bindings = candidate.bindings.take() ++ accumulated_bindings
candidate_bindings.extend_from_slice(&accumulated_bindings);
mem::swap(candidate_bindings, &mut accumulated_bindings);
candidate_bindings.clear();
if match_pairs.is_empty() {
break;
}
}
// 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.
match_pairs.sort_by_key(|pair| matches!(pair.pattern.kind, PatKind::Or { .. }));
debug!(simplified = ?match_pairs, "simplify_match_pairs");
}
/// 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,
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, 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()
}
}