about summary refs log tree commit diff
path: root/compiler/rustc_mir_build/src/build
diff options
context:
space:
mode:
authorZalathar <Zalathar@users.noreply.github.com>2024-07-18 20:58:52 +1000
committerZalathar <Zalathar@users.noreply.github.com>2024-07-20 12:45:11 +1000
commite091c356fa0e47251f6c7d11cbc7043213df48c6 (patch)
tree4dc0f3cda944dde5205b7248fff6646a9eb99cfc /compiler/rustc_mir_build/src/build
parent3b7e4bc77a83c1101e8799739504b0a53f0d0619 (diff)
downloadrust-e091c356fa0e47251f6c7d11cbc7043213df48c6.tar.gz
rust-e091c356fa0e47251f6c7d11cbc7043213df48c6.zip
Improve `merge_trivial_subcandidates`
Diffstat (limited to 'compiler/rustc_mir_build/src/build')
-rw-r--r--compiler/rustc_mir_build/src/build/matches/mod.rs20
1 files changed, 15 insertions, 5 deletions
diff --git a/compiler/rustc_mir_build/src/build/matches/mod.rs b/compiler/rustc_mir_build/src/build/matches/mod.rs
index 6bd2c308128..d18e59759e2 100644
--- a/compiler/rustc_mir_build/src/build/matches/mod.rs
+++ b/compiler/rustc_mir_build/src/build/matches/mod.rs
@@ -1744,8 +1744,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
     /// Try to merge all of the subcandidates of the given candidate into one. This avoids
     /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been
     /// expanded with `create_or_subcandidates`.
+    ///
+    /// Note that this takes place _after_ the subcandidates have participated
+    /// in match tree lowering.
     fn merge_trivial_subcandidates(&mut self, candidate: &mut Candidate<'_, 'tcx>) {
-        if candidate.subcandidates.is_empty() || candidate.has_guard {
+        assert!(!candidate.subcandidates.is_empty());
+        if candidate.has_guard {
             // FIXME(or_patterns; matthewjasper) Don't give up if we have a guard.
             return;
         }
@@ -1759,7 +1763,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
         }
 
         let mut last_otherwise = None;
-        let any_matches = self.cfg.start_new_block();
+        let shared_pre_binding_block = self.cfg.start_new_block();
+        // This candidate is about to become a leaf, so unset `or_span`.
         let or_span = candidate.or_span.take().unwrap();
         let source_info = self.source_info(or_span);
 
@@ -1767,12 +1772,17 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
             candidate.false_edge_start_block = candidate.subcandidates[0].false_edge_start_block;
         }
 
+        // Remove the (known-trivial) subcandidates from the candidate tree,
+        // so that they aren't visible after match tree lowering, and wire them
+        // all to join up at a single shared pre-binding block.
+        // (Note that the subcandidates have already had their part of the match
+        // tree lowered by this point, which is why we can add a goto to them.)
         for subcandidate in mem::take(&mut candidate.subcandidates) {
-            let or_block = subcandidate.pre_binding_block.unwrap();
-            self.cfg.goto(or_block, source_info, any_matches);
+            let subcandidate_block = subcandidate.pre_binding_block.unwrap();
+            self.cfg.goto(subcandidate_block, source_info, shared_pre_binding_block);
             last_otherwise = subcandidate.otherwise_block;
         }
-        candidate.pre_binding_block = Some(any_matches);
+        candidate.pre_binding_block = Some(shared_pre_binding_block);
         assert!(last_otherwise.is_some());
         candidate.otherwise_block = last_otherwise;
     }