rustc_mir_build/builder/matches/simplify.rs
1//! Simplifying Candidates
2//!
3//! *Simplifying* a match pair `place @ pattern` means breaking it down
4//! into bindings or other, simpler match pairs. For example:
5//!
6//! - `place @ (P1, P2)` can be simplified to `[place.0 @ P1, place.1 @ P2]`
7//! - `place @ x` can be simplified to `[]` by binding `x` to `place`
8//!
9//! The `simplify_match_pairs` routine just repeatedly applies these
10//! sort of simplifications until there is nothing left to
11//! simplify. Match pairs cannot be simplified if they require some
12//! sort of test: for example, testing which variant an enum is, or
13//! testing a value against a constant.
14
15use std::mem;
16
17use tracing::{debug, instrument};
18
19use crate::builder::Builder;
20use crate::builder::matches::{MatchPairTree, PatternExtraData, TestCase};
21
22impl<'a, 'tcx> Builder<'a, 'tcx> {
23 /// Simplify a list of match pairs so they all require a test. Stores relevant bindings and
24 /// ascriptions in `extra_data`.
25 #[instrument(skip(self), level = "debug")]
26 pub(super) fn simplify_match_pairs(
27 &mut self,
28 match_pairs: &mut Vec<MatchPairTree<'tcx>>,
29 extra_data: &mut PatternExtraData<'tcx>,
30 ) {
31 // In order to please the borrow checker, in a pattern like `x @ pat` we must lower the
32 // bindings in `pat` before `x`. E.g. (#69971):
33 //
34 // struct NonCopyStruct {
35 // copy_field: u32,
36 // }
37 //
38 // fn foo1(x: NonCopyStruct) {
39 // let y @ NonCopyStruct { copy_field: z } = x;
40 // // the above should turn into
41 // let z = x.copy_field;
42 // let y = x;
43 // }
44 //
45 // We therefore lower bindings from left-to-right, except we lower the `x` in `x @ pat`
46 // after any bindings in `pat`. This doesn't work for or-patterns: the current structure of
47 // match lowering forces us to lower bindings inside or-patterns last.
48 for mut match_pair in mem::take(match_pairs) {
49 self.simplify_match_pairs(&mut match_pair.subpairs, extra_data);
50 if let TestCase::Irrefutable { binding, ascription } = match_pair.test_case {
51 if let Some(binding) = binding {
52 extra_data.bindings.push(binding);
53 }
54 if let Some(ascription) = ascription {
55 extra_data.ascriptions.push(ascription);
56 }
57 // Simplifiable pattern; we replace it with its already simplified subpairs.
58 match_pairs.append(&mut match_pair.subpairs);
59 } else {
60 // Unsimplifiable pattern; we keep it.
61 match_pairs.push(match_pair);
62 }
63 }
64
65 // Move or-patterns to the end, because they can result in us
66 // creating additional candidates, so we want to test them as
67 // late as possible.
68 match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
69 debug!(simplified = ?match_pairs, "simplify_match_pairs");
70 }
71}