compiler/rustc_mir_build/src/builder/matches/mod.rs RUST 3,018 lines View on github.com → Search inside
File is large — showing lines 1–2,000 of 3,018.
1//! Code related to match expressions. These are sufficiently complex to2//! warrant their own module and submodules. :) This main module includes the3//! high-level algorithm, the submodules contain the details.4//!5//! This also includes code for pattern bindings in `let` statements and6//! function parameters.78use std::borrow::Borrow;9use std::sync::Arc;10use std::{debug_assert_matches, mem};1112use itertools::{Itertools, Position};13use rustc_abi::{FIRST_VARIANT, FieldIdx, VariantIdx};14use rustc_data_structures::fx::FxIndexMap;15use rustc_data_structures::stack::ensure_sufficient_stack;16use rustc_hir::{BindingMode, ByRef, LangItem, LetStmt, LocalSource, Node};17use rustc_middle::middle::region::{self, TempLifetime};18use rustc_middle::mir::*;19use rustc_middle::thir::{self, *};20use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, ValTree, ValTreeKind};21use rustc_middle::{bug, span_bug};22use rustc_pattern_analysis::constructor::RangeEnd;23use rustc_pattern_analysis::rustc::{DeconstructedPat, RustcPatCtxt};24use rustc_span::{BytePos, Pos, Span, Symbol, sym};25use tracing::{debug, instrument};2627use crate::builder::ForGuard::{self, OutsideGuard, RefWithinGuard};28use crate::builder::expr::as_place::PlaceBuilder;29use crate::builder::matches::buckets::PartitionedCandidates;30use crate::builder::matches::user_ty::ProjectedUserTypesNode;31use crate::builder::scope::{DropKind, LintLevel};32use crate::builder::{33    BlockAnd, BlockAndExtension, Builder, GuardFrame, GuardFrameLocal, LocalsForNode,34};3536// helper functions, broken out by category:37mod buckets;38mod match_pair;39mod test;40mod user_ty;41mod util;4243/// Arguments to [`Builder::then_else_break_inner`] that are usually forwarded44/// to recursive invocations.45#[derive(Clone, Copy)]46struct ThenElseArgs {47    /// Used as the temp scope for lowering `expr`. If absent (for match guards),48    /// `self.local_scope()` is used.49    temp_scope_override: Option<region::Scope>,50    variable_source_info: SourceInfo,51    /// Determines how bindings should be handled when lowering `let` expressions.52    ///53    /// Forwarded to [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`].54    declare_let_bindings: DeclareLetBindings,55}5657/// Should lowering a `let` expression also declare its bindings?58///59/// Used by [`Builder::lower_let_expr`] when lowering [`ExprKind::Let`].60#[derive(Clone, Copy)]61pub(crate) enum DeclareLetBindings {62    /// Yes, declare `let` bindings as normal for `if` conditions.63    Yes,64    /// No, don't declare `let` bindings, because the caller declares them65    /// separately due to special requirements.66    ///67    /// Used for match guards and let-else.68    No,69    /// Let expressions are not permitted in this context, so it is a bug to70    /// try to lower one (e.g inside lazy-boolean-or or boolean-not).71    LetNotPermitted,72}7374/// Used by [`Builder::storage_live_binding`] and [`Builder::bind_matched_candidate_for_arm_body`]75/// to decide whether to schedule drops.76#[derive(Clone, Copy, Debug)]77pub(crate) enum ScheduleDrops {78    /// Yes, the relevant functions should also schedule drops as appropriate.79    Yes,80    /// No, don't schedule drops. The caller has taken responsibility for any81    /// appropriate drops.82    No,83}8485impl<'a, 'tcx> Builder<'a, 'tcx> {86    /// Lowers a condition in a way that ensures that variables bound in any let87    /// expressions are definitely initialized in the if body.88    ///89    /// If `declare_let_bindings` is false then variables created in `let`90    /// expressions will not be declared. This is for if let guards on arms with91    /// an or pattern, where the guard is lowered multiple times.92    pub(crate) fn then_else_break(93        &mut self,94        block: BasicBlock,95        expr_id: ExprId,96        temp_scope_override: Option<region::Scope>,97        variable_source_info: SourceInfo,98        declare_let_bindings: DeclareLetBindings,99    ) -> BlockAnd<()> {100        self.then_else_break_inner(101            block,102            expr_id,103            ThenElseArgs { temp_scope_override, variable_source_info, declare_let_bindings },104        )105    }106107    fn then_else_break_inner(108        &mut self,109        block: BasicBlock, // Block that the condition and branch will be lowered into110        expr_id: ExprId,   // Condition expression to lower111        args: ThenElseArgs,112    ) -> BlockAnd<()> {113        let this = self; // See "LET_THIS_SELF".114        let expr = &this.thir[expr_id];115        let expr_span = expr.span;116117        match expr.kind {118            ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {119                let lhs_then_block = this.then_else_break_inner(block, lhs, args).into_block();120                let rhs_then_block =121                    this.then_else_break_inner(lhs_then_block, rhs, args).into_block();122                rhs_then_block.unit()123            }124            ExprKind::LogicalOp { op: LogicalOp::Or, lhs, rhs } => {125                let local_scope = this.local_scope();126                let (lhs_success_block, failure_block) =127                    this.in_if_then_scope(local_scope, expr_span, |this| {128                        this.then_else_break_inner(129                            block,130                            lhs,131                            ThenElseArgs {132                                declare_let_bindings: DeclareLetBindings::LetNotPermitted,133                                ..args134                            },135                        )136                    });137                let rhs_success_block = this138                    .then_else_break_inner(139                        failure_block,140                        rhs,141                        ThenElseArgs {142                            declare_let_bindings: DeclareLetBindings::LetNotPermitted,143                            ..args144                        },145                    )146                    .into_block();147148                // Make the LHS and RHS success arms converge to a common block.149                // (We can't just make LHS goto RHS, because `rhs_success_block`150                // might contain statements that we don't want on the LHS path.)151                let success_block = this.cfg.start_new_block();152                this.cfg.goto(lhs_success_block, args.variable_source_info, success_block);153                this.cfg.goto(rhs_success_block, args.variable_source_info, success_block);154                success_block.unit()155            }156            ExprKind::Unary { op: UnOp::Not, arg } => {157                // Improve branch coverage instrumentation by noting conditions158                // nested within one or more `!` expressions.159                // (Skipped if branch coverage is not enabled.)160                if let Some(coverage_info) = this.coverage_info.as_mut() {161                    coverage_info.visit_unary_not(this.thir, expr_id);162                }163164                let local_scope = this.local_scope();165                let (success_block, failure_block) =166                    this.in_if_then_scope(local_scope, expr_span, |this| {167                        // Help out coverage instrumentation by injecting a dummy statement with168                        // the original condition's span (including `!`). This fixes #115468.169                        if this.tcx.sess.instrument_coverage() {170                            this.cfg.push_coverage_span_marker(block, this.source_info(expr_span));171                        }172                        this.then_else_break_inner(173                            block,174                            arg,175                            ThenElseArgs {176                                declare_let_bindings: DeclareLetBindings::LetNotPermitted,177                                ..args178                            },179                        )180                    });181                this.break_for_else(success_block, args.variable_source_info);182                failure_block.unit()183            }184            ExprKind::Scope { region_scope, hir_id, value } => {185                let region_scope = (region_scope, this.source_info(expr_span));186                this.in_scope(region_scope, LintLevel::Explicit(hir_id), |this| {187                    this.then_else_break_inner(block, value, args)188                })189            }190            ExprKind::Use { source } => this.then_else_break_inner(block, source, args),191            ExprKind::Let { expr, ref pat } => this.lower_let_expr(192                block,193                expr,194                pat,195                Some(args.variable_source_info.scope),196                args.variable_source_info.span,197                args.declare_let_bindings,198            ),199            _ => {200                let mut block = block;201                let temp_scope = args.temp_scope_override.unwrap_or_else(|| this.local_scope());202                let mutability = Mutability::Mut;203204                let place = unpack!(205                    block = this.as_temp(206                        block,207                        TempLifetime {208                            temp_lifetime: Some(temp_scope),209                            backwards_incompatible: None210                        },211                        expr_id,212                        mutability213                    )214                );215216                let operand = Operand::Move(Place::from(place));217218                let then_block = this.cfg.start_new_block();219                let else_block = this.cfg.start_new_block();220                let term = TerminatorKind::if_(operand, then_block, else_block);221222                // Record branch coverage info for this condition.223                // (Does nothing if branch coverage is not enabled.)224                this.visit_coverage_branch_condition(expr_id, then_block, else_block);225226                let source_info = this.source_info(expr_span);227                this.cfg.terminate(block, source_info, term);228                this.break_for_else(else_block, source_info);229230                then_block.unit()231            }232        }233    }234235    /// Generates MIR for a `match` expression.236    ///237    /// The MIR that we generate for a match looks like this.238    ///239    /// ```text240    /// [ 0. Pre-match ]241    ///        |242    /// [ 1. Evaluate Scrutinee (expression being matched on) ]243    /// [ (PlaceMention of scrutinee) ]244    ///        |245    /// [ 2. Decision tree -- check discriminants ] <--------+246    ///        |                                             |247    ///        | (once a specific arm is chosen)             |248    ///        |                                             |249    /// [pre_binding_block]                           [otherwise_block]250    ///        |                                             |251    /// [ 3. Create "guard bindings" for arm ]               |252    /// [ (create fake borrows) ]                            |253    ///        |                                             |254    /// [ 4. Execute guard code ]                            |255    /// [ (read fake borrows) ] --(guard is false)-----------+256    ///        |257    ///        | (guard results in true)258    ///        |259    /// [ 5. Create real bindings and execute arm ]260    ///        |261    /// [ Exit match ]262    /// ```263    ///264    /// All of the different arms have been stacked on top of each other to265    /// simplify the diagram. For an arm with no guard the blocks marked 3 and266    /// 4 and the fake borrows are omitted.267    ///268    /// We generate MIR in the following steps:269    ///270    /// 1. Evaluate the scrutinee and add the PlaceMention of it ([Builder::lower_scrutinee]).271    /// 2. Create the decision tree ([Builder::lower_match_tree]).272    /// 3. Determine the fake borrows that are needed from the places that were273    ///    matched against and create the required temporaries for them274    ///    ([util::collect_fake_borrows]).275    /// 4. Create everything else: the guards and the arms ([Builder::lower_match_arms]).276    ///277    /// ## False edges278    ///279    /// We don't want to have the exact structure of the decision tree be visible through borrow280    /// checking. Specifically we want borrowck to think that:281    /// - at any point, any or none of the patterns and guards seen so far may have been tested;282    /// - after the match, any of the patterns may have matched.283    ///284    /// For example, all of these would fail to error if borrowck could see the real CFG (examples285    /// taken from `tests/ui/nll/match-cfg-fake-edges.rs`):286    /// ```ignore (too many errors, this is already in the test suite)287    /// let x = String::new();288    /// let _ = match true {289    ///     _ => {},290    ///     _ => drop(x),291    /// };292    /// // Borrowck must not know the second arm is never run.293    /// drop(x); //~ ERROR use of moved value294    ///295    /// let x;296    /// # let y = true;297    /// match y {298    ///     _ if { x = 2; true } => {},299    ///     // Borrowck must not know the guard is always run.300    ///     _ => drop(x), //~ ERROR used binding `x` is possibly-uninitialized301    /// };302    ///303    /// let x = String::new();304    /// # let y = true;305    /// match y {306    ///     false if { drop(x); true } => {},307    ///     // Borrowck must not know the guard is not run in the `true` case.308    ///     true => drop(x), //~ ERROR use of moved value: `x`309    ///     false => {},310    /// };311    ///312    /// # let mut y = (true, true);313    /// let r = &mut y.1;314    /// match y {315    ///     //~^ ERROR cannot use `y.1` because it was mutably borrowed316    ///     (false, true) => {}317    ///     // Borrowck must not know we don't test `y.1` when `y.0` is `true`.318    ///     (true, _) => drop(r),319    ///     (false, _) => {}320    /// };321    /// ```322    ///323    /// We add false edges to act as if we were naively matching each arm in order. What we need is324    /// a (fake) path from each candidate to the next, specifically from candidate C's pre-binding325    /// block to next candidate D's pre-binding block. For maximum precision (needed for deref326    /// patterns), we choose the earliest node on D's success path that doesn't also lead to C (to327    /// avoid loops).328    ///329    /// This turns out to be easy to compute: that block is the `start_block` of the first call to330    /// `match_candidates` where D is the first candidate in the list.331    ///332    /// For example:333    /// ```rust334    /// # let (x, y) = (true, true);335    /// match (x, y) {336    ///   (true, true) => 1,337    ///   (false, true) => 2,338    ///   (true, false) => 3,339    ///   _ => 4,340    /// }341    /// # ;342    /// ```343    /// In this example, the pre-binding block of arm 1 has a false edge to the block for result344    /// `false` of the first test on `x`. The other arms have false edges to the pre-binding blocks345    /// of the next arm.346    ///347    /// On top of this, we also add a false edge from the otherwise_block of each guard to the348    /// aforementioned start block of the next candidate, to ensure borrock doesn't rely on which349    /// guards may have run.350    #[instrument(level = "debug", skip(self, arms))]351    pub(crate) fn match_expr(352        &mut self,353        destination: Place<'tcx>,354        mut block: BasicBlock,355        scrutinee_id: ExprId,356        arms: &[ArmId],357        span: Span,358        scrutinee_span: Span,359    ) -> BlockAnd<()> {360        let scrutinee_place =361            unpack!(block = self.lower_scrutinee(block, scrutinee_id, scrutinee_span));362363        let match_start_span = span.shrink_to_lo().to(scrutinee_span);364        let patterns = arms365            .iter()366            .map(|&arm| {367                let arm = &self.thir[arm];368                let has_match_guard =369                    if arm.guard.is_some() { HasMatchGuard::Yes } else { HasMatchGuard::No };370                (&*arm.pattern, has_match_guard)371            })372            .collect();373        let built_tree = self.lower_match_tree(374            block,375            scrutinee_span,376            &scrutinee_place,377            match_start_span,378            patterns,379            Exhaustive::Yes,380        );381382        self.lower_match_arms(383            destination,384            scrutinee_place,385            scrutinee_span,386            arms,387            built_tree,388            self.source_info(span),389        )390    }391392    /// Evaluate the scrutinee and add the PlaceMention for it.393    pub(crate) fn lower_scrutinee(394        &mut self,395        mut block: BasicBlock,396        scrutinee_id: ExprId,397        scrutinee_span: Span,398    ) -> BlockAnd<PlaceBuilder<'tcx>> {399        let scrutinee_place_builder = unpack!(block = self.as_place_builder(block, scrutinee_id));400        if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {401            let source_info = self.source_info(scrutinee_span);402            self.cfg.push_place_mention(block, source_info, scrutinee_place);403        }404405        block.and(scrutinee_place_builder)406    }407408    /// Lower the bindings, guards and arm bodies of a `match` expression.409    ///410    /// The decision tree should have already been created411    /// (by [Builder::lower_match_tree]).412    ///413    /// `outer_source_info` is the SourceInfo for the whole match.414    pub(crate) fn lower_match_arms(415        &mut self,416        destination: Place<'tcx>,417        scrutinee_place_builder: PlaceBuilder<'tcx>,418        scrutinee_span: Span,419        arms: &[ArmId],420        built_match_tree: BuiltMatchTree<'tcx>,421        outer_source_info: SourceInfo,422    ) -> BlockAnd<()> {423        let arm_end_blocks: Vec<BasicBlock> = arms424            .iter()425            .map(|&arm| &self.thir[arm])426            .zip(built_match_tree.branches)427            .map(|(arm, branch)| {428                debug!("lowering arm {:?}\ncorresponding branch = {:?}", arm, branch);429430                let arm_source_info = self.source_info(arm.span);431                let arm_scope = (arm.scope, arm_source_info);432                let match_scope = self.local_scope();433                let guard_scope = arm434                    .guard435                    .map(|_| region::Scope { data: region::ScopeData::MatchGuard, ..arm.scope });436                self.in_scope(arm_scope, LintLevel::Explicit(arm.hir_id), |this| {437                    this.opt_in_scope(guard_scope.map(|scope| (scope, arm_source_info)), |this| {438                        // `if let` guard temps needing deduplicating will be in the guard scope.439                        let old_dedup_scope =440                            mem::replace(&mut this.fixed_temps_scope, guard_scope);441442                        // `try_to_place` may fail if it is unable to resolve the given443                        // `PlaceBuilder` inside a closure. In this case, we don't want to include444                        // a scrutinee place. `scrutinee_place_builder` will fail to be resolved445                        // if the only match arm is a wildcard (`_`).446                        // Example:447                        // ```448                        // let foo = (0, 1);449                        // let c = || {450                        //    match foo { _ => () };451                        // };452                        // ```453                        let scrutinee_place = scrutinee_place_builder.try_to_place(this);454                        let opt_scrutinee_place =455                            scrutinee_place.as_ref().map(|place| (Some(place), scrutinee_span));456                        let scope = this.declare_bindings(457                            None,458                            arm.span,459                            &arm.pattern,460                            arm.guard,461                            opt_scrutinee_place,462                        );463464                        let arm_block = this.bind_pattern(465                            outer_source_info,466                            branch,467                            &built_match_tree.fake_borrow_temps,468                            scrutinee_span,469                            Some((arm, match_scope)),470                        );471472                        this.fixed_temps_scope = old_dedup_scope;473474                        if let Some(source_scope) = scope {475                            this.source_scope = source_scope;476                        }477478                        this.expr_into_dest(destination, arm_block, arm.body)479                    })480                })481                .into_block()482            })483            .collect();484485        // all the arm blocks will rejoin here486        let end_block = self.cfg.start_new_block();487488        let end_brace = self.source_info(489            outer_source_info.span.with_lo(outer_source_info.span.hi() - BytePos::from_usize(1)),490        );491        for arm_block in arm_end_blocks {492            let block = &self.cfg.basic_blocks[arm_block];493            let last_location = block.statements.last().map(|s| s.source_info);494495            self.cfg.goto(arm_block, last_location.unwrap_or(end_brace), end_block);496        }497498        self.source_scope = outer_source_info.scope;499500        end_block.unit()501    }502503    /// For a top-level `match` arm or a `let` binding, binds the variables and504    /// ascribes types, and also checks the match arm guard (if present).505    ///506    /// `arm_scope` should be `Some` if and only if this is called for a507    /// `match` arm.508    ///509    /// In the presence of or-patterns, a match arm might have multiple510    /// sub-branches representing different ways to match, with each sub-branch511    /// requiring its own bindings and its own copy of the guard. This method512    /// handles those sub-branches individually, and then has them jump together513    /// to a common block.514    ///515    /// Returns a single block that the match arm can be lowered into.516    /// (For `let` bindings, this is the code that can use the bindings.)517    fn bind_pattern(518        &mut self,519        outer_source_info: SourceInfo,520        branch: MatchTreeBranch<'tcx>,521        fake_borrow_temps: &[(Place<'tcx>, Local, FakeBorrowKind)],522        scrutinee_span: Span,523        arm_match_scope: Option<(&Arm<'tcx>, region::Scope)>,524    ) -> BasicBlock {525        if branch.sub_branches.len() == 1 {526            let [sub_branch] = branch.sub_branches.try_into().unwrap();527            // Avoid generating another `BasicBlock` when we only have one sub branch.528            self.bind_and_guard_matched_candidate(529                sub_branch,530                fake_borrow_temps,531                scrutinee_span,532                arm_match_scope,533                ScheduleDrops::Yes,534            )535        } else {536            // It's helpful to avoid scheduling drops multiple times to save537            // drop elaboration from having to clean up the extra drops.538            //539            // If we are in a `let` then we only schedule drops for the first540            // candidate.541            //542            // If we're in a `match` arm then we could have a case like so:543            //544            // Ok(x) | Err(x) if return => { /* ... */ }545            //546            // In this case we don't want a drop of `x` scheduled when we547            // return: it isn't bound by move until right before enter the arm.548            // To handle this we instead unschedule it's drop after each time549            // we lower the guard.550            // As a result, we end up with the drop order of the last sub-branch we lower. To use551            // the drop order for the first sub-branch, we lower sub-branches in reverse (#142163).552            let target_block = self.cfg.start_new_block();553            for (pos, sub_branch) in branch.sub_branches.into_iter().rev().with_position() {554                debug_assert!(pos != Position::Only);555                let schedule_drops =556                    if pos == Position::Last { ScheduleDrops::Yes } else { ScheduleDrops::No };557                let binding_end = self.bind_and_guard_matched_candidate(558                    sub_branch,559                    fake_borrow_temps,560                    scrutinee_span,561                    arm_match_scope,562                    schedule_drops,563                );564                self.cfg.goto(binding_end, outer_source_info, target_block);565            }566567            target_block568        }569    }570571    pub(super) fn expr_into_pattern(572        &mut self,573        mut block: BasicBlock,574        irrefutable_pat: &Pat<'tcx>,575        initializer_id: ExprId,576    ) -> BlockAnd<()> {577        match irrefutable_pat.kind {578            // Optimize `let x = ...` and `let x: T = ...` to write directly into `x`,579            // and then require that `T == typeof(x)` if present.580            PatKind::Binding { mode: BindingMode(ByRef::No, _), var, subpattern: None, .. } => {581                let place = self.storage_live_binding(582                    block,583                    var,584                    irrefutable_pat.span,585                    false,586                    OutsideGuard,587                    ScheduleDrops::Yes,588                );589                block = self.expr_into_dest(place, block, initializer_id).into_block();590591                // Inject a fake read, see comments on `FakeReadCause::ForLet`.592                let source_info = self.source_info(irrefutable_pat.span);593                self.cfg.push_fake_read(block, source_info, FakeReadCause::ForLet(None), place);594595                let ascriptions: &[_] =596                    try { irrefutable_pat.extra.as_deref()?.ascriptions.as_slice() }597                        .unwrap_or_default();598                for thir::Ascription { annotation, variance: _ } in ascriptions {599                    let ty_source_info = self.source_info(annotation.span);600601                    let base = self.canonical_user_type_annotations.push(annotation.clone());602                    let stmt = Statement::new(603                        ty_source_info,604                        StatementKind::AscribeUserType(605                            Box::new((place, UserTypeProjection { base, projs: Vec::new() })),606                            // We always use invariant as the variance here. This is because the607                            // variance field from the ascription refers to the variance to use608                            // when applying the type to the value being matched, but this609                            // ascription applies rather to the type of the binding. e.g., in this610                            // example:611                            //612                            // ```613                            // let x: T = <expr>614                            // ```615                            //616                            // We are creating an ascription that defines the type of `x` to be617                            // exactly `T` (i.e., with invariance). The variance field, in618                            // contrast, is intended to be used to relate `T` to the type of619                            // `<expr>`.620                            ty::Invariant,621                        ),622                    );623                    self.cfg.push(block, stmt);624                }625626                self.schedule_drop_for_binding(var, irrefutable_pat.span, OutsideGuard);627                block.unit()628            }629630            _ => {631                let initializer = &self.thir[initializer_id];632                let place_builder =633                    unpack!(block = self.lower_scrutinee(block, initializer_id, initializer.span));634                self.place_into_pattern(block, irrefutable_pat, place_builder, true)635            }636        }637    }638639    pub(crate) fn place_into_pattern(640        &mut self,641        block: BasicBlock,642        irrefutable_pat: &Pat<'tcx>,643        initializer: PlaceBuilder<'tcx>,644        set_match_place: bool,645    ) -> BlockAnd<()> {646        let built_tree = self.lower_match_tree(647            block,648            irrefutable_pat.span,649            &initializer,650            irrefutable_pat.span,651            vec![(irrefutable_pat, HasMatchGuard::No)],652            Exhaustive::Yes,653        );654        let [branch] = built_tree.branches.try_into().unwrap();655656        // For matches and function arguments, the place that is being matched657        // can be set when creating the variables. But the place for658        // let PATTERN = ... might not even exist until we do the assignment.659        // so we set it here instead.660        if set_match_place {661            // `try_to_place` may fail if it is unable to resolve the given `PlaceBuilder` inside a662            // closure. In this case, we don't want to include a scrutinee place.663            // `scrutinee_place_builder` will fail for destructured assignments. This is because a664            // closure only captures the precise places that it will read and as a result a closure665            // may not capture the entire tuple/struct and rather have individual places that will666            // be read in the final MIR.667            // Example:668            // ```669            // let foo = (0, 1);670            // let c = || {671            //    let (v1, v2) = foo;672            // };673            // ```674            if let Some(place) = initializer.try_to_place(self) {675                // Because or-alternatives bind the same variables, we only explore the first one.676                let first_sub_branch = branch.sub_branches.first().unwrap();677                for binding in &first_sub_branch.bindings {678                    let local = self.var_local_id(binding.var_id, OutsideGuard);679                    if let LocalInfo::User(BindingForm::Var(VarBindingForm {680                        opt_match_place: Some((ref mut match_place, _)),681                        ..682                    })) = **self.local_decls[local].local_info.as_mut().unwrap_crate_local()683                    {684                        *match_place = Some(place);685                    } else {686                        bug!("Let binding to non-user variable.")687                    };688                }689            }690        }691692        self.bind_pattern(693            self.source_info(irrefutable_pat.span),694            branch,695            &[],696            irrefutable_pat.span,697            None,698        )699        .unit()700    }701702    /// Declares the bindings of the given patterns and returns the visibility703    /// scope for the bindings in these patterns, if such a scope had to be704    /// created. NOTE: Declaring the bindings should always be done in their705    /// drop scope.706    #[instrument(skip(self), level = "debug")]707    pub(crate) fn declare_bindings(708        &mut self,709        mut visibility_scope: Option<SourceScope>,710        scope_span: Span,711        pattern: &Pat<'tcx>,712        guard: Option<ExprId>,713        opt_match_place: Option<(Option<&Place<'tcx>>, Span)>,714    ) -> Option<SourceScope> {715        self.visit_primary_bindings_special(716            pattern,717            &ProjectedUserTypesNode::None,718            &mut |this, name, mode, var, span, ty, user_tys| {719                let saved_scope = this.source_scope;720                this.set_correct_source_scope_for_arg(var.0, saved_scope, span);721                let vis_scope = *visibility_scope722                    .get_or_insert_with(|| this.new_source_scope(scope_span, LintLevel::Inherited));723                let source_info = SourceInfo { span, scope: this.source_scope };724                let user_tys = user_tys.build_user_type_projections();725726                this.declare_binding(727                    source_info,728                    vis_scope,729                    name,730                    mode,731                    var,732                    ty,733                    user_tys,734                    ArmHasGuard(guard.is_some()),735                    opt_match_place.map(|(x, y)| (x.cloned(), y)),736                    pattern.span,737                );738                this.source_scope = saved_scope;739            },740        );741        if let Some(guard_expr) = guard {742            self.declare_guard_bindings(guard_expr, scope_span, visibility_scope);743        }744        visibility_scope745    }746747    /// Declare bindings in a guard. This has to be done when declaring bindings748    /// for an arm to ensure that or patterns only have one version of each749    /// variable.750    pub(crate) fn declare_guard_bindings(751        &mut self,752        guard_expr: ExprId,753        scope_span: Span,754        visibility_scope: Option<SourceScope>,755    ) {756        match self.thir.exprs[guard_expr].kind {757            ExprKind::Let { expr: _, pat: ref guard_pat } => {758                // FIXME: pass a proper `opt_match_place`759                self.declare_bindings(visibility_scope, scope_span, guard_pat, None, None);760            }761            ExprKind::Scope { value, .. } => {762                self.declare_guard_bindings(value, scope_span, visibility_scope);763            }764            ExprKind::Use { source } => {765                self.declare_guard_bindings(source, scope_span, visibility_scope);766            }767            ExprKind::LogicalOp { op: LogicalOp::And, lhs, rhs } => {768                self.declare_guard_bindings(lhs, scope_span, visibility_scope);769                self.declare_guard_bindings(rhs, scope_span, visibility_scope);770            }771            _ => {}772        }773    }774775    /// Emits a [`StatementKind::StorageLive`] for the given var, and also776    /// schedules a drop if requested (and possible).777    pub(crate) fn storage_live_binding(778        &mut self,779        block: BasicBlock,780        var: LocalVarId,781        span: Span,782        is_shorthand: bool,783        for_guard: ForGuard,784        schedule_drop: ScheduleDrops,785    ) -> Place<'tcx> {786        let local_id = self.var_local_id(var, for_guard);787        let source_info = self.source_info(span);788        self.cfg.push(block, Statement::new(source_info, StatementKind::StorageLive(local_id)));789        // Although there is almost always scope for given variable in corner cases790        // like #92893 we might get variable with no scope.791        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id)792            && matches!(schedule_drop, ScheduleDrops::Yes)793        {794            self.schedule_drop(span, region_scope, local_id, DropKind::Storage);795        }796        let local_info = self.local_decls[local_id].local_info.as_mut().unwrap_crate_local();797        if let LocalInfo::User(BindingForm::Var(var_info)) = &mut **local_info {798            var_info.introductions.push(VarBindingIntroduction { span, is_shorthand });799        }800        Place::from(local_id)801    }802803    pub(crate) fn schedule_drop_for_binding(804        &mut self,805        var: LocalVarId,806        span: Span,807        for_guard: ForGuard,808    ) {809        let local_id = self.var_local_id(var, for_guard);810        if let Some(region_scope) = self.region_scope_tree.var_scope(var.0.local_id) {811            self.schedule_drop(span, region_scope, local_id, DropKind::Value);812        }813    }814815    /// Visits all of the "primary" bindings in a pattern, i.e. the leftmost816    /// occurrence of each variable bound by the pattern.817    /// See [`PatKind::Binding::is_primary`] for more context.818    ///819    /// This variant provides only the limited subset of binding data needed820    /// by its callers, and should be a "pure" visit without side-effects.821    pub(super) fn visit_primary_bindings(822        &mut self,823        pattern: &Pat<'tcx>,824        f: &mut impl FnMut(&mut Self, LocalVarId, Span),825    ) {826        pattern.walk_always(|pat| {827            if let PatKind::Binding { var, is_primary: true, .. } = pat.kind {828                f(self, var, pat.span);829            }830        })831    }832833    /// Visits all of the "primary" bindings in a pattern, while preparing834    /// additional user-type-annotation data needed by `declare_bindings`.835    ///836    /// This also has the side-effect of pushing all user type annotations837    /// onto `canonical_user_type_annotations`, so that they end up in MIR838    /// even if they aren't associated with any bindings.839    #[instrument(level = "debug", skip(self, f))]840    fn visit_primary_bindings_special(841        &mut self,842        pattern: &Pat<'tcx>,843        user_tys: &ProjectedUserTypesNode<'_>,844        f: &mut impl FnMut(845            &mut Self,846            Symbol,847            BindingMode,848            LocalVarId,849            Span,850            Ty<'tcx>,851            &ProjectedUserTypesNode<'_>,852        ),853    ) {854        // Ascriptions correspond to user-written types like `let A::<'a>(_): A<'static> = ...;`.855        //856        // Caution: Pushing user types here is load-bearing even for857        // patterns containing no bindings, to ensure that the type ends858        // up represented in MIR _somewhere_.859        let user_tys = match pattern.extra.as_deref() {860            Some(PatExtra { ascriptions, .. }) if !ascriptions.is_empty() => {861                let base_user_tys = ascriptions862                    .iter()863                    .map(|thir::Ascription { annotation, variance: _ }| {864                        // Note that the variance doesn't apply here, as we are tracking the effect865                        // of user types on any bindings contained with subpattern.866                        self.canonical_user_type_annotations.push(annotation.clone())867                    })868                    .collect();869                &user_tys.push_user_types(base_user_tys)870            }871            _ => user_tys,872        };873874        // Avoid having to write the full method name at each recursive call.875        let visit_subpat = |this: &mut Self, subpat, user_tys: &_, f: &mut _| {876            this.visit_primary_bindings_special(subpat, user_tys, f)877        };878879        match pattern.kind {880            PatKind::Binding { name, mode, var, ty, ref subpattern, is_primary, .. } => {881                if is_primary {882                    f(self, name, mode, var, pattern.span, ty, user_tys);883                }884                if let Some(subpattern) = subpattern.as_ref() {885                    visit_subpat(self, subpattern, user_tys, f);886                }887            }888889            PatKind::Array { ref prefix, ref slice, ref suffix }890            | PatKind::Slice { ref prefix, ref slice, ref suffix } => {891                let from = u64::try_from(prefix.len()).unwrap();892                let to = u64::try_from(suffix.len()).unwrap();893                for subpattern in prefix.iter() {894                    visit_subpat(self, subpattern, &user_tys.index(), f);895                }896                if let Some(subpattern) = slice {897                    visit_subpat(self, subpattern, &user_tys.subslice(from, to), f);898                }899                for subpattern in suffix.iter() {900                    visit_subpat(self, subpattern, &user_tys.index(), f);901                }902            }903904            PatKind::Constant { .. }905            | PatKind::Range { .. }906            | PatKind::Missing907            | PatKind::Wild908            | PatKind::Never909            | PatKind::Error(_) => {}910911            PatKind::Deref { pin: Pinnedness::Pinned, ref subpattern } => {912                // Project into the `Pin(_)` struct, then deref the inner `&` or `&mut`.913                visit_subpat(self, subpattern, &user_tys.leaf(FieldIdx::ZERO).deref(), f);914            }915            PatKind::Deref { pin: Pinnedness::Not, ref subpattern } => {916                visit_subpat(self, subpattern, &user_tys.deref(), f);917            }918919            PatKind::DerefPattern { ref subpattern, .. } => {920                visit_subpat(self, subpattern, &ProjectedUserTypesNode::None, f);921            }922923            PatKind::Leaf { ref subpatterns } => {924                for subpattern in subpatterns {925                    let subpattern_user_tys = user_tys.leaf(subpattern.field);926                    debug!("visit_primary_bindings: subpattern_user_tys={subpattern_user_tys:?}");927                    visit_subpat(self, &subpattern.pattern, &subpattern_user_tys, f);928                }929            }930931            PatKind::Variant { adt_def, args: _, variant_index, ref subpatterns } => {932                for subpattern in subpatterns {933                    let subpattern_user_tys =934                        user_tys.variant(adt_def, variant_index, subpattern.field);935                    visit_subpat(self, &subpattern.pattern, &subpattern_user_tys, f);936                }937            }938            PatKind::Or { ref pats } => {939                // In cases where we recover from errors the primary bindings940                // may not all be in the leftmost subpattern. For example in941                // `let (x | y) = ...`, the primary binding of `y` occurs in942                // the right subpattern943                for subpattern in pats.iter() {944                    visit_subpat(self, subpattern, user_tys, f);945                }946            }947            PatKind::Guard { ref subpattern, .. } => {948                visit_subpat(self, subpattern, user_tys, f);949            }950        }951    }952}953954/// Data extracted from a pattern that doesn't affect which branch is taken. Collected during955/// pattern simplification and not mutated later.956#[derive(Debug, Clone)]957struct PatternExtraData<'tcx> {958    /// [`Span`] of the original pattern.959    span: Span,960961    /// Bindings that must be established.962    bindings: Vec<SubpatternBindings<'tcx>>,963964    /// Types that must be asserted.965    ascriptions: Vec<Ascription<'tcx>>,966967    /// Whether this corresponds to a never pattern.968    is_never: bool,969}970971impl<'tcx> PatternExtraData<'tcx> {972    fn is_empty(&self) -> bool {973        self.bindings.is_empty() && self.ascriptions.is_empty()974    }975}976977#[derive(Debug, Clone)]978enum SubpatternBindings<'tcx> {979    /// A single binding.980    One(Binding<'tcx>),981    /// Holds the place for an or-pattern's bindings. This ensures their drops are scheduled in the982    /// order the primary bindings appear. See rust-lang/rust#142163 for more information.983    FromOrPattern,984}985986/// A pattern in a form suitable for lowering the match tree, with all irrefutable987/// patterns simplified away.988///989/// Here, "flat" indicates that irrefutable nodes in the pattern tree have been990/// recursively replaced with their refutable subpatterns. They are not991/// necessarily flat in an absolute sense.992///993/// Will typically be incorporated into a [`Candidate`].994#[derive(Debug, Clone)]995struct FlatPat<'tcx> {996    /// To match the pattern, all of these must be satisfied...997    match_pairs: Vec<MatchPairTree<'tcx>>,998999    extra_data: PatternExtraData<'tcx>,1000}10011002/// Candidates are a generalization of (a) top-level match arms, and1003/// (b) sub-branches of or-patterns, allowing the match-lowering process to handle1004/// them both in a mostly-uniform way. For example, the list of candidates passed1005/// to [`Builder::match_candidates`] will often contain a mixture of top-level1006/// candidates and or-pattern subcandidates.1007///1008/// At the start of match lowering, there is one candidate for each match arm.1009/// During match lowering, arms with or-patterns will be expanded into a tree1010/// of candidates, where each "leaf" candidate represents one of the ways for1011/// the arm pattern to successfully match.1012#[derive(Debug)]1013struct Candidate<'tcx> {1014    /// For the candidate to match, all of these must be satisfied...1015    ///1016    /// ---1017    /// Initially contains a list of match pairs created by [`FlatPat`], but is1018    /// subsequently mutated (in a queue-like way) while lowering the match tree.1019    /// When this list becomes empty, the candidate is fully matched and becomes1020    /// a leaf (see [`Builder::select_matched_candidate`]).1021    ///1022    /// Key mutations include:1023    ///1024    /// - When a match pair is fully satisfied by a test, it is removed from the1025    ///   list, and its subpairs are added instead (see [`Builder::choose_bucket_for_candidate`]).1026    /// - During or-pattern expansion, any leading or-pattern is removed, and is1027    ///   converted into subcandidates (see [`Builder::expand_and_match_or_candidates`]).1028    /// - After a candidate's subcandidates have been lowered, a copy of any remaining1029    ///   or-patterns is added to each leaf subcandidate1030    ///   (see [`Builder::test_remaining_match_pairs_after_or`]).1031    ///1032    /// Invariants:1033    /// - All or-patterns ([`TestableCase::Or`]) have been sorted to the end.1034    match_pairs: Vec<MatchPairTree<'tcx>>,10351036    /// ...and if this is non-empty, one of these subcandidates also has to match...1037    ///1038    /// ---1039    /// Initially a candidate has no subcandidates; they are added (and then immediately1040    /// lowered) during or-pattern expansion. Their main function is to serve as _output_1041    /// of match tree lowering, allowing later steps to see the leaf candidates that1042    /// represent a match of the entire match arm.1043    ///1044    /// A candidate no subcandidates is either incomplete (if it has match pairs left),1045    /// or is a leaf in the match tree. A candidate with one or more subcandidates is1046    /// an internal node in the match tree.1047    ///1048    /// Invariant: at the end of match tree lowering, this must not contain an1049    /// `is_never` candidate, because that would break binding consistency.1050    /// - See [`Builder::remove_never_subcandidates`].1051    subcandidates: Vec<Candidate<'tcx>>,10521053    /// ...and if there is a guard it must be evaluated; if it's `false` then branch to `otherwise_block`.1054    ///1055    /// ---1056    /// For subcandidates, this is copied from the parent candidate, so it indicates1057    /// whether the enclosing match arm has a guard.1058    has_guard: bool,10591060    /// Holds extra pattern data that was prepared by [`FlatPat`], including bindings and1061    /// ascriptions that must be established if this candidate succeeds.1062    extra_data: PatternExtraData<'tcx>,10631064    /// When setting `self.subcandidates`, we store here the span of the or-pattern they came from.1065    ///1066    /// ---1067    /// Invariant: it is `None` iff `subcandidates.is_empty()`.1068    /// - FIXME: We sometimes don't unset this when clearing `subcandidates`.1069    or_span: Option<Span>,10701071    /// The block before the `bindings` have been established.1072    ///1073    /// After the match tree has been lowered, [`Builder::lower_match_arms`]1074    /// will use this as the start point for lowering bindings and guards, and1075    /// then jump to a shared block containing the arm body.1076    pre_binding_block: Option<BasicBlock>,10771078    /// The block to branch to if the guard or a nested candidate fails to match.1079    otherwise_block: Option<BasicBlock>,10801081    /// The earliest block that has only candidates >= this one as descendents. Used for false1082    /// edges, see the doc for [`Builder::match_expr`].1083    false_edge_start_block: Option<BasicBlock>,1084}10851086impl<'tcx> Candidate<'tcx> {1087    fn new(1088        place: PlaceBuilder<'tcx>,1089        pattern: &Pat<'tcx>,1090        has_guard: HasMatchGuard,1091        cx: &mut Builder<'_, 'tcx>,1092    ) -> Self {1093        // Use `FlatPat` to build simplified match pairs, then immediately1094        // incorporate them into a new candidate.1095        Self::from_flat_pat(1096            FlatPat::new(place, pattern, cx),1097            matches!(has_guard, HasMatchGuard::Yes),1098        )1099    }11001101    /// Incorporates an already-simplified [`FlatPat`] into a new candidate.1102    fn from_flat_pat(flat_pat: FlatPat<'tcx>, has_guard: bool) -> Self {1103        let mut this = Candidate {1104            match_pairs: flat_pat.match_pairs,1105            extra_data: flat_pat.extra_data,1106            has_guard,1107            subcandidates: Vec::new(),1108            or_span: None,1109            otherwise_block: None,1110            pre_binding_block: None,1111            false_edge_start_block: None,1112        };1113        this.sort_match_pairs();1114        this1115    }11161117    /// Restores the invariant that or-patterns must be sorted to the end.1118    fn sort_match_pairs(&mut self) {1119        self.match_pairs.sort_by_key(|pair| matches!(pair.testable_case, TestableCase::Or { .. }));1120    }11211122    /// Returns whether the first match pair of this candidate is an or-pattern.1123    fn starts_with_or_pattern(&self) -> bool {1124        matches!(1125            &*self.match_pairs,1126            [MatchPairTree { testable_case: TestableCase::Or { .. }, .. }, ..]1127        )1128    }11291130    /// Visit the leaf candidates (those with no subcandidates) contained in1131    /// this candidate.1132    fn visit_leaves<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) {1133        traverse_candidate(1134            self,1135            &mut (),1136            &mut move |c, _| visit_leaf(c),1137            move |c, _| c.subcandidates.iter_mut(),1138            |_| {},1139        );1140    }11411142    /// Visit the leaf candidates in reverse order.1143    fn visit_leaves_rev<'a>(&'a mut self, mut visit_leaf: impl FnMut(&'a mut Self)) {1144        traverse_candidate(1145            self,1146            &mut (),1147            &mut move |c, _| visit_leaf(c),1148            move |c, _| c.subcandidates.iter_mut().rev(),1149            |_| {},1150        );1151    }1152}11531154/// A depth-first traversal of the `Candidate` and all of its recursive1155/// subcandidates.1156///1157/// This signature is very generic, to support traversing candidate trees by1158/// reference or by value, and to allow a mutable "context" to be shared by the1159/// traversal callbacks. Most traversals can use the simpler1160/// [`Candidate::visit_leaves`] wrapper instead.1161fn traverse_candidate<'tcx, C, T, I>(1162    candidate: C,1163    context: &mut T,1164    // Called when visiting a "leaf" candidate (with no subcandidates).1165    visit_leaf: &mut impl FnMut(C, &mut T),1166    // Called when visiting a "node" candidate (with one or more subcandidates).1167    // Returns an iterator over the candidate's children (by value or reference).1168    // Can perform setup before visiting the node's children.1169    get_children: impl Copy + Fn(C, &mut T) -> I,1170    // Called after visiting a "node" candidate's children.1171    complete_children: impl Copy + Fn(&mut T),1172) where1173    C: Borrow<Candidate<'tcx>>, // Typically `Candidate` or `&mut Candidate`1174    I: Iterator<Item = C>,1175{1176    if candidate.borrow().subcandidates.is_empty() {1177        visit_leaf(candidate, context)1178    } else {1179        for child in get_children(candidate, context) {1180            traverse_candidate(child, context, visit_leaf, get_children, complete_children);1181        }1182        complete_children(context)1183    }1184}11851186#[derive(Clone, Copy, Debug)]1187struct Binding<'tcx> {1188    span: Span,1189    source: Place<'tcx>,1190    var_id: LocalVarId,1191    binding_mode: BindingMode,1192    is_shorthand: bool,1193}11941195/// Indicates that the type of `source` must be a subtype of the1196/// user-given type `user_ty`; this is basically a no-op but can1197/// influence region inference.1198#[derive(Clone, Debug)]1199struct Ascription<'tcx> {1200    source: Place<'tcx>,1201    annotation: CanonicalUserTypeAnnotation<'tcx>,1202    variance: ty::Variance,1203}12041205/// Partial summary of a [`thir::Pat`], indicating what sort of test should be1206/// performed to match/reject the pattern, and what the desired test outcome is.1207/// This avoids having to perform a full match on [`thir::PatKind`] in some places,1208/// and helps [`TestKind::Switch`] and [`TestKind::SwitchInt`] know what target1209/// values to use.1210///1211/// Created by [`MatchPairTree`], and then inspected primarily by:1212/// - [`Builder::pick_test_for_match_pair`] (to choose a test)1213/// - [`Builder::choose_bucket_for_candidate`] (to see how the test interacts with a match pair)1214///1215/// Note that or-patterns are not tested directly like the other variants.1216/// Instead they participate in or-pattern expansion, where they are transformed into1217/// subcandidates. See [`Builder::expand_and_match_or_candidates`].1218#[derive(Debug, Clone)]1219enum TestableCase<'tcx> {1220    Variant { adt_def: ty::AdtDef<'tcx>, variant_index: VariantIdx },1221    Constant { value: ty::Value<'tcx>, kind: PatConstKind },1222    Range(Arc<PatRange<'tcx>>),1223    Slice { len: u64, op: SliceLenOp },1224    Deref { temp: Place<'tcx>, mutability: Mutability },1225    Never,1226    Or { pats: Box<[FlatPat<'tcx>]> },1227}12281229impl<'tcx> TestableCase<'tcx> {1230    fn as_range(&self) -> Option<&PatRange<'tcx>> {1231        if let Self::Range(v) = self { Some(v.as_ref()) } else { None }1232    }1233}12341235/// Sub-classification of [`TestableCase::Constant`], which helps to avoid1236/// some redundant ad-hoc checks when preparing and lowering tests.1237#[derive(Debug, Clone)]1238enum PatConstKind {1239    /// The primitive `bool` type, which is like an integer but simpler,1240    /// having only two values.1241    Bool,1242    /// Primitive unsigned/signed integer types, plus `char`.1243    /// These types interact nicely with `SwitchInt`.1244    IntOrChar,1245    /// Floating-point primitives, e.g. `f32`, `f64`.1246    /// These types don't support `SwitchInt` and require an equality test,1247    /// but can also interact with range pattern tests.1248    Float,1249    /// Constant string values, tested via string equality.1250    String,1251    /// Any other constant-pattern is usually tested via some kind of equality1252    /// check. Types that might be encountered here include:1253    /// - raw pointers derived from integer values1254    /// - pattern types, e.g. `pattern_type!(u32 is 1..)`1255    Other,1256}12571258/// Node in a tree of "match pairs", where each pair consists of a place to be1259/// tested, and a test to perform on that place.1260///1261/// Each node also has a list of subpairs (possibly empty) that must also match,1262/// and some additional information from the THIR pattern it represents.1263#[derive(Debug, Clone)]1264pub(crate) struct MatchPairTree<'tcx> {1265    /// This place...1266    ///1267    /// ---1268    /// This can be `None` if it referred to a non-captured place in a closure.1269    ///1270    /// Invariant: Can only be `None` when `testable_case` is `Or`.1271    /// Therefore this must be `Some(_)` after or-pattern expansion.1272    place: Option<Place<'tcx>>,12731274    /// ... must pass this test...1275    testable_case: TestableCase<'tcx>,12761277    /// ... and these subpairs must match.1278    ///1279    /// ---1280    /// Subpairs typically represent tests that can only be performed after their1281    /// parent has succeeded. For example, the pattern `Some(3)` might have an1282    /// outer match pair that tests for the variant `Some`, and then a subpair1283    /// that tests its field for the value `3`.1284    subpairs: Vec<Self>,12851286    /// Span field of the THIR pattern this node was created from.1287    pattern_span: Span,1288}12891290/// A runtime test to perform to determine which candidates match a scrutinee place.1291///1292/// The kind of test to perform is indicated by [`TestKind`].1293#[derive(Debug)]1294pub(crate) struct Test<'tcx> {1295    span: Span,1296    kind: TestKind<'tcx>,1297}12981299/// The kind of runtime test to perform to determine which candidates match a1300/// scrutinee place. This is the main component of [`Test`].1301///1302/// Some of these variants don't contain the constant value(s) being tested1303/// against, because those values are stored in the corresponding bucketed1304/// candidates instead.1305#[derive(Clone, Debug, PartialEq)]1306enum TestKind<'tcx> {1307    /// Test what enum variant a value is.1308    ///1309    /// The subset of expected variants is not stored here; instead they are1310    /// extracted from the [`TestableCase`]s of the candidates participating in the1311    /// test.1312    Switch {1313        /// The enum type being tested.1314        adt_def: ty::AdtDef<'tcx>,1315    },13161317    /// Test what value an integer or `char` has.1318    ///1319    /// The test's target values are not stored here; instead they are extracted1320    /// from the [`TestableCase`]s of the candidates participating in the test.1321    SwitchInt,13221323    /// Test whether a `bool` is `true` or `false`.1324    If,13251326    /// Tests the place against a string constant using string equality.1327    StringEq {1328        /// Constant string value to test against.1329        /// Note that this value has type `str` (not `&str`).1330        value: ty::Value<'tcx>,1331    },13321333    /// Tests the place against a constant using scalar equality.1334    ScalarEq { value: ty::Value<'tcx> },13351336    /// Test whether the value falls within an inclusive or exclusive range.1337    Range(Arc<PatRange<'tcx>>),13381339    /// Test that the length of the slice is `== len` or `>= len`.1340    SliceLen { len: u64, op: SliceLenOp },13411342    /// Call `Deref::deref[_mut]` on the value.1343    Deref {1344        /// Temporary to store the result of `deref()`/`deref_mut()`.1345        temp: Place<'tcx>,1346        mutability: Mutability,1347    },13481349    /// Assert unreachability of never patterns.1350    Never,1351}13521353/// Indicates the kind of slice-length constraint imposed by a slice pattern,1354/// or its corresponding test.1355#[derive(Debug, Clone, Copy, PartialEq)]1356enum SliceLenOp {1357    /// The slice pattern can only match a slice with exactly `len` elements.1358    Equal,1359    /// The slice pattern can match a slice with `len` or more elements1360    /// (i.e. it contains a `..` subpattern in the middle).1361    GreaterOrEqual,1362}13631364/// The branch to be taken after a test.1365#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]1366enum TestBranch<'tcx> {1367    /// Success branch, used for tests with two possible outcomes.1368    Success,1369    /// Branch corresponding to this constant. Must be a scalar.1370    Constant(ty::Value<'tcx>),1371    /// Branch corresponding to this variant.1372    Variant(VariantIdx),1373    /// Failure branch for tests with two possible outcomes, and "otherwise" branch for other tests.1374    Failure,1375}13761377impl<'tcx> TestBranch<'tcx> {1378    fn as_constant(&self) -> Option<ty::Value<'tcx>> {1379        if let Self::Constant(v) = self { Some(*v) } else { None }1380    }1381}13821383/// `ArmHasGuard` is a wrapper around a boolean flag. It indicates whether1384/// a match arm has a guard expression attached to it.1385#[derive(Copy, Clone, Debug)]1386pub(crate) struct ArmHasGuard(pub(crate) bool);13871388///////////////////////////////////////////////////////////////////////////1389// Main matching algorithm13901391/// A sub-branch in the output of match lowering. Match lowering has generated MIR code that will1392/// branch to `success_block` when the matched value matches the corresponding pattern. If there is1393/// a guard, its failure must continue to `otherwise_block`, which will resume testing patterns.1394#[derive(Debug, Clone)]1395struct MatchTreeSubBranch<'tcx> {1396    span: Span,1397    /// The block that is branched to if the corresponding subpattern matches.1398    success_block: BasicBlock,1399    /// The block to branch to if this arm had a guard and the guard fails.1400    otherwise_block: BasicBlock,1401    /// The bindings to set up in this sub-branch.1402    bindings: Vec<Binding<'tcx>>,1403    /// The ascriptions to set up in this sub-branch.1404    ascriptions: Vec<Ascription<'tcx>>,1405    /// Whether the sub-branch corresponds to a never pattern.1406    is_never: bool,1407}14081409/// A branch in the output of match lowering.1410#[derive(Debug, Clone)]1411struct MatchTreeBranch<'tcx> {1412    sub_branches: Vec<MatchTreeSubBranch<'tcx>>,1413}14141415/// The result of generating MIR for a pattern-matching expression. Each input branch/arm/pattern1416/// gives rise to an output `MatchTreeBranch`. If one of the patterns matches, we branch to the1417/// corresponding `success_block`. If none of the patterns matches, we branch to `otherwise_block`.1418///1419/// Each branch is made of one of more sub-branches, corresponding to or-patterns. E.g.1420/// ```ignore(illustrative)1421/// match foo {1422///     (x, false) | (false, x) => {}1423///     (true, true) => {}1424/// }1425/// ```1426/// Here the first arm gives the first `MatchTreeBranch`, which has two sub-branches, one for each1427/// alternative of the or-pattern. They are kept separate because each needs to bind `x` to a1428/// different place.1429#[derive(Debug, Clone)]1430pub(crate) struct BuiltMatchTree<'tcx> {1431    branches: Vec<MatchTreeBranch<'tcx>>,1432    otherwise_block: BasicBlock,1433    /// If any of the branches had a guard, we collect here the places and locals to fakely borrow1434    /// to ensure match guards can't modify the values as we match them. For more details, see1435    /// [`util::collect_fake_borrows`].1436    fake_borrow_temps: Vec<(Place<'tcx>, Local, FakeBorrowKind)>,1437}14381439impl<'tcx> MatchTreeSubBranch<'tcx> {1440    fn from_sub_candidate(1441        candidate: Candidate<'tcx>,1442        parent_data: &Vec<PatternExtraData<'tcx>>,1443    ) -> Self {1444        debug_assert!(candidate.match_pairs.is_empty());1445        MatchTreeSubBranch {1446            span: candidate.extra_data.span,1447            success_block: candidate.pre_binding_block.unwrap(),1448            otherwise_block: candidate.otherwise_block.unwrap(),1449            bindings: sub_branch_bindings(parent_data, &candidate.extra_data.bindings),1450            ascriptions: parent_data1451                .iter()1452                .flat_map(|d| &d.ascriptions)1453                .cloned()1454                .chain(candidate.extra_data.ascriptions)1455                .collect(),1456            is_never: candidate.extra_data.is_never,1457        }1458    }1459}14601461impl<'tcx> MatchTreeBranch<'tcx> {1462    fn from_candidate(candidate: Candidate<'tcx>) -> Self {1463        let mut sub_branches = Vec::new();1464        traverse_candidate(1465            candidate,1466            &mut Vec::new(),1467            &mut |candidate: Candidate<'_>, parent_data: &mut Vec<PatternExtraData<'_>>| {1468                sub_branches.push(MatchTreeSubBranch::from_sub_candidate(candidate, parent_data));1469            },1470            |inner_candidate, parent_data| {1471                parent_data.push(inner_candidate.extra_data);1472                inner_candidate.subcandidates.into_iter()1473            },1474            |parent_data| {1475                parent_data.pop();1476            },1477        );1478        MatchTreeBranch { sub_branches }1479    }1480}14811482/// Collects the bindings for a [`MatchTreeSubBranch`], preserving the order they appear in the1483/// pattern, as though the or-alternatives chosen in this sub-branch were inlined.1484fn sub_branch_bindings<'tcx>(1485    parents: &[PatternExtraData<'tcx>],1486    leaf_bindings: &[SubpatternBindings<'tcx>],1487) -> Vec<Binding<'tcx>> {1488    // In the common case, all bindings will be in leaves. Allocate to fit the leaf's bindings.1489    let mut all_bindings = Vec::with_capacity(leaf_bindings.len());1490    let mut remainder = parents1491        .iter()1492        .map(|parent| parent.bindings.as_slice())1493        .chain([leaf_bindings])1494        // Skip over unsimplified or-patterns without bindings.1495        .filter(|bindings| !bindings.is_empty());1496    if let Some(candidate_bindings) = remainder.next() {1497        push_sub_branch_bindings(&mut all_bindings, candidate_bindings, &mut remainder);1498    }1499    // Make sure we've included all bindings. For ill-formed patterns like `(x, _ | y)`, we may not1500    // have collected all bindings yet, since we only check the first alternative when determining1501    // whether to inline subcandidates' bindings.1502    // FIXME(@dianne): prevent ill-formed patterns from getting here1503    while let Some(candidate_bindings) = remainder.next() {1504        ty::tls::with(|tcx| {1505            tcx.dcx().delayed_bug("mismatched or-pattern bindings but no error emitted")1506        });1507        // To recover, we collect the rest in an arbitrary order.1508        push_sub_branch_bindings(&mut all_bindings, candidate_bindings, &mut remainder);1509    }1510    all_bindings1511}15121513/// Helper for [`sub_branch_bindings`]. Collects bindings from `candidate_bindings` into1514/// `flattened`. Bindings in or-patterns are collected recursively from `remainder`.1515fn push_sub_branch_bindings<'c, 'tcx: 'c>(1516    flattened: &mut Vec<Binding<'tcx>>,1517    candidate_bindings: &'c [SubpatternBindings<'tcx>],1518    remainder: &mut impl Iterator<Item = &'c [SubpatternBindings<'tcx>]>,1519) {1520    for subpat_bindings in candidate_bindings {1521        match subpat_bindings {1522            SubpatternBindings::One(binding) => flattened.push(*binding),1523            SubpatternBindings::FromOrPattern => {1524                // Inline bindings from an or-pattern. By construction, this always1525                // corresponds to a subcandidate and its closest descendants (i.e. those1526                // from nested or-patterns, but not adjacent or-patterns). To handle1527                // adjacent or-patterns, e.g. `(x | x, y | y)`, we update the `remainder` to1528                // point to the first descendant candidate from outside this or-pattern.1529                if let Some(subcandidate_bindings) = remainder.next() {1530                    push_sub_branch_bindings(flattened, subcandidate_bindings, remainder);1531                } else {1532                    // For ill-formed patterns like `x | _`, we may not have any subcandidates left1533                    // to inline bindings from.1534                    // FIXME(@dianne): prevent ill-formed patterns from getting here1535                    ty::tls::with(|tcx| {1536                        tcx.dcx().delayed_bug("mismatched or-pattern bindings but no error emitted")1537                    });1538                };1539            }1540        }1541    }1542}15431544#[derive(Debug, Clone, Copy, PartialEq, Eq)]1545pub(crate) enum HasMatchGuard {1546    Yes,1547    No,1548}15491550#[derive(Debug, Clone, Copy, PartialEq, Eq)]1551pub(crate) enum Exhaustive {1552    /// `let` and `match` are exhaustive.1553    Yes,1554    /// `if let` and `let else` are not exhaustive.1555    No,1556}15571558impl<'a, 'tcx> Builder<'a, 'tcx> {1559    /// The entrypoint of the matching algorithm. Create the decision tree for the match expression,1560    /// starting from `block`.1561    ///1562    /// `patterns` is a list of patterns, one for each arm. The associated boolean indicates whether1563    /// the arm has a guard.1564    ///1565    /// `exhaustive` indicates whether the candidate list is exhaustive (for `if let` and `let else`)1566    /// or not (for `let` and `match`). In the non-exhaustive case we return the block to which we1567    /// branch on failure.1568    pub(crate) fn lower_match_tree(1569        &mut self,1570        block: BasicBlock,1571        scrutinee_span: Span,1572        scrutinee_place_builder: &PlaceBuilder<'tcx>,1573        match_start_span: Span,1574        patterns: Vec<(&Pat<'tcx>, HasMatchGuard)>,1575        exhaustive: Exhaustive,1576    ) -> BuiltMatchTree<'tcx> {1577        // Assemble the initial list of candidates. These top-level candidates are 1:1 with the1578        // input patterns, but other parts of match lowering also introduce subcandidates (for1579        // sub-or-patterns). So inside the algorithm, the candidates list may not correspond to1580        // match arms directly.1581        let mut candidates: Vec<Candidate<'_>> = patterns1582            .into_iter()1583            .map(|(pat, has_guard)| {1584                Candidate::new(scrutinee_place_builder.clone(), pat, has_guard, self)1585            })1586            .collect();15871588        let fake_borrow_temps = util::collect_fake_borrows(1589            self,1590            &candidates,1591            scrutinee_span,1592            scrutinee_place_builder.base(),1593        );15941595        // This will generate code to test scrutinee_place and branch to the appropriate arm block.1596        // If none of the arms match, we branch to `otherwise_block`. When lowering a `match`1597        // expression, exhaustiveness checking ensures that this block is unreachable.1598        let mut candidate_refs = candidates.iter_mut().collect::<Vec<_>>();1599        let otherwise_block =1600            self.match_candidates(match_start_span, scrutinee_span, block, &mut candidate_refs);16011602        // Set up false edges so that the borrow-checker cannot make use of the specific CFG we1603        // generated. We falsely branch from each candidate to the one below it to make it as if we1604        // were testing match branches one by one in order. In the non-exhaustive case we also want a1605        // false edge to the final failure block.1606        let mut next_candidate_start_block = match exhaustive {1607            Exhaustive::Yes => None,1608            Exhaustive::No => Some(otherwise_block),1609        };1610        for candidate in candidates.iter_mut().rev() {1611            let has_guard = candidate.has_guard;1612            candidate.visit_leaves_rev(|leaf_candidate| {1613                if let Some(next_candidate_start_block) = next_candidate_start_block {1614                    let source_info = self.source_info(leaf_candidate.extra_data.span);1615                    // Falsely branch to `next_candidate_start_block` before reaching pre_binding.1616                    let old_pre_binding = leaf_candidate.pre_binding_block.unwrap();1617                    let new_pre_binding = self.cfg.start_new_block();1618                    self.false_edges(1619                        old_pre_binding,1620                        new_pre_binding,1621                        next_candidate_start_block,1622                        source_info,1623                    );1624                    leaf_candidate.pre_binding_block = Some(new_pre_binding);1625                    if has_guard {1626                        // Falsely branch to `next_candidate_start_block` also if the guard fails.1627                        let new_otherwise = self.cfg.start_new_block();1628                        let old_otherwise = leaf_candidate.otherwise_block.unwrap();1629                        self.false_edges(1630                            new_otherwise,1631                            old_otherwise,1632                            next_candidate_start_block,1633                            source_info,1634                        );1635                        leaf_candidate.otherwise_block = Some(new_otherwise);1636                    }1637                }1638                assert!(leaf_candidate.false_edge_start_block.is_some());1639                next_candidate_start_block = leaf_candidate.false_edge_start_block;1640            });1641        }16421643        if exhaustive == Exhaustive::Yes {1644            // Match checking ensures `otherwise_block` is actually unreachable in exhaustive1645            // cases.1646            let source_info = self.source_info(scrutinee_span);16471648            // Matching on a scrutinee place of an uninhabited type doesn't generate any memory1649            // reads by itself, and so if the place is uninitialized we wouldn't know. In order to1650            // disallow the following:1651            // ```rust1652            // let x: !;1653            // match x {}1654            // ```1655            // we add a dummy read on the place.1656            //1657            // NOTE: If we require never patterns for empty matches, those will check that the place1658            // is initialized, and so this read would no longer be needed.1659            let cause_matched_place = FakeReadCause::ForMatchedPlace(None);16601661            if let Some(scrutinee_place) = scrutinee_place_builder.try_to_place(self) {1662                self.cfg.push_fake_read(1663                    otherwise_block,1664                    source_info,1665                    cause_matched_place,1666                    scrutinee_place,1667                );1668            }16691670            self.cfg.terminate(otherwise_block, source_info, TerminatorKind::Unreachable);1671        }16721673        BuiltMatchTree {1674            branches: candidates.into_iter().map(MatchTreeBranch::from_candidate).collect(),1675            otherwise_block,1676            fake_borrow_temps,1677        }1678    }16791680    /// The main match algorithm. It begins with a set of candidates `candidates` and has the job of1681    /// generating code that branches to an appropriate block if the scrutinee matches one of these1682    /// candidates. The1683    /// candidates are ordered such that the first item in the list1684    /// has the highest priority. When a candidate is found to match1685    /// the value, we will set and generate a branch to the appropriate1686    /// pre-binding block.1687    ///1688    /// If none of the candidates apply, we continue to the returned `otherwise_block`.1689    ///1690    /// Note that while `match` expressions in the Rust language are exhaustive,1691    /// candidate lists passed to this method are often _non-exhaustive_.1692    /// For example, the match lowering process will frequently divide up the1693    /// list of candidates, and recursively call this method with a non-exhaustive1694    /// subset of candidates.1695    /// See [`Builder::test_candidates`] for more details on this1696    /// "backtracking automata" approach.1697    ///1698    /// For an example of how we use `otherwise_block`, consider:1699    /// ```1700    /// # fn foo((x, y): (bool, bool)) -> u32 {1701    /// match (x, y) {1702    ///     (true, true) => 1,1703    ///     (_, false) => 2,1704    ///     (false, true) => 3,1705    /// }1706    /// # }1707    /// ```1708    /// For this match, we generate something like:1709    /// ```1710    /// # fn foo((x, y): (bool, bool)) -> u32 {1711    /// if x {1712    ///     if y {1713    ///         return 11714    ///     } else {1715    ///         // continue1716    ///     }1717    /// } else {1718    ///     // continue1719    /// }1720    /// if y {1721    ///     if x {1722    ///         // This is actually unreachable because the `(true, true)` case was handled above,1723    ///         // but we don't know that from within the lowering algorithm.1724    ///         // continue1725    ///     } else {1726    ///         return 31727    ///     }1728    /// } else {1729    ///     return 21730    /// }1731    /// // this is the final `otherwise_block`, which is unreachable because the match was exhaustive.1732    /// unreachable!()1733    /// # }1734    /// ```1735    ///1736    /// Every `continue` is an instance of branching to some `otherwise_block` somewhere deep within1737    /// the algorithm. For more details on why we lower like this, see [`Builder::test_candidates`].1738    ///1739    /// Note how we test `x` twice. This is the tradeoff of backtracking automata: we prefer smaller1740    /// code size so we accept non-optimal code paths.1741    #[instrument(skip(self), level = "debug")]1742    fn match_candidates(1743        &mut self,1744        span: Span,1745        scrutinee_span: Span,1746        start_block: BasicBlock,1747        candidates: &mut [&mut Candidate<'tcx>],1748    ) -> BasicBlock {1749        ensure_sufficient_stack(|| {1750            self.match_candidates_inner(span, scrutinee_span, start_block, candidates)1751        })1752    }17531754    /// Construct the decision tree for `candidates`. Don't call this, call `match_candidates`1755    /// instead to reserve sufficient stack space.1756    fn match_candidates_inner(1757        &mut self,1758        span: Span,1759        scrutinee_span: Span,1760        mut start_block: BasicBlock,1761        candidates: &mut [&mut Candidate<'tcx>],1762    ) -> BasicBlock {1763        if let [first, ..] = candidates {1764            if first.false_edge_start_block.is_none() {1765                first.false_edge_start_block = Some(start_block);1766            }1767        }17681769        // Process a prefix of the candidates.1770        let rest = match candidates {1771            [] => {1772                // If there are no candidates that still need testing, we're done.1773                return start_block;1774            }1775            [first, remaining @ ..] if first.match_pairs.is_empty() => {1776                // The first candidate has satisfied all its match pairs.1777                // We record the blocks that will be needed by match arm lowering,1778                // and then continue with the remaining candidates.1779                let remainder_start = self.select_matched_candidate(first, start_block);1780                remainder_start.and(remaining)1781            }1782            candidates if candidates.iter().any(|candidate| candidate.starts_with_or_pattern()) => {1783                // If any candidate starts with an or-pattern, we want to expand or-patterns1784                // before we do any more tests.1785                //1786                // The only candidate we strictly _need_ to expand here is the first one.1787                // But by expanding other candidates as early as possible, we unlock more1788                // opportunities to include them in test outcomes, making the match tree1789                // smaller and simpler.1790                self.expand_and_match_or_candidates(span, scrutinee_span, start_block, candidates)1791            }1792            candidates => {1793                // The first candidate has some unsatisfied match pairs; we proceed to do more tests.1794                self.test_candidates(span, scrutinee_span, candidates, start_block)1795            }1796        };17971798        // Process any candidates that remain.1799        let remaining_candidates = unpack!(start_block = rest);1800        self.match_candidates(span, scrutinee_span, start_block, remaining_candidates)1801    }18021803    /// Link up matched candidates.1804    ///1805    /// For example, if we have something like this:1806    ///1807    /// ```ignore (illustrative)1808    /// ...1809    /// Some(x) if cond1 => ...1810    /// Some(x) => ...1811    /// Some(x) if cond2 => ...1812    /// ...1813    /// ```1814    ///1815    /// We generate real edges from:1816    ///1817    /// * `start_block` to the [pre-binding block] of the first pattern,1818    /// * the [otherwise block] of the first pattern to the second pattern,1819    /// * the [otherwise block] of the third pattern to a block with an1820    ///   [`Unreachable` terminator](TerminatorKind::Unreachable).1821    ///1822    /// In addition, we later add fake edges from the otherwise blocks to the1823    /// pre-binding block of the next candidate in the original set of1824    /// candidates.1825    ///1826    /// [pre-binding block]: Candidate::pre_binding_block1827    /// [otherwise block]: Candidate::otherwise_block1828    fn select_matched_candidate(1829        &mut self,1830        candidate: &mut Candidate<'tcx>,1831        start_block: BasicBlock,1832    ) -> BasicBlock {1833        assert!(candidate.otherwise_block.is_none());1834        assert!(candidate.pre_binding_block.is_none());1835        assert!(candidate.subcandidates.is_empty());18361837        candidate.pre_binding_block = Some(start_block);1838        let otherwise_block = self.cfg.start_new_block();1839        // Create the otherwise block for this candidate, which is the1840        // pre-binding block for the next candidate.1841        candidate.otherwise_block = Some(otherwise_block);1842        otherwise_block1843    }18441845    /// Takes a list of candidates such that some of the candidates' first match pairs are1846    /// or-patterns. This expands as many or-patterns as possible and processes the resulting1847    /// candidates. Returns the unprocessed candidates if any.1848    fn expand_and_match_or_candidates<'b, 'c>(1849        &mut self,1850        span: Span,1851        scrutinee_span: Span,1852        start_block: BasicBlock,1853        candidates: &'b mut [&'c mut Candidate<'tcx>],1854    ) -> BlockAnd<&'b mut [&'c mut Candidate<'tcx>]> {1855        // We can't expand or-patterns freely. The rule is:1856        // - If a candidate doesn't start with an or-pattern, we include it in1857        //   the expansion list as-is (i.e. it "expands" to itself).1858        // - If a candidate has an or-pattern as its only remaining match pair,1859        //   we can expand it.1860        // - If it starts with an or-pattern but also has other match pairs,1861        //   we can expand it, but we can't process more candidates after it.1862        //1863        // If we didn't stop, the `otherwise` cases could get mixed up. E.g. in the1864        // following, or-pattern simplification (in `merge_trivial_subcandidates`) makes it1865        // so the `1` and `2` cases branch to a same block (which then tests `false`). If we1866        // took `(2, _)` in the same set of candidates, when we reach the block that tests1867        // `false` we don't know whether we came from `1` or `2`, hence we can't know where1868        // to branch on failure.1869        //1870        // ```ignore(illustrative)1871        // match (1, true) {1872        //     (1 | 2, false) => {},1873        //     (2, _) => {},1874        //     _ => {}1875        // }1876        // ```1877        //1878        // We therefore split the `candidates` slice in two, expand or-patterns in the first part,1879        // and process the rest separately.1880        let expand_until = candidates1881            .iter()1882            .position(|candidate| {1883                // If a candidate starts with an or-pattern and has more match pairs,1884                // we can expand it, but we must stop expanding _after_ it.1885                candidate.match_pairs.len() > 1 && candidate.starts_with_or_pattern()1886            })1887            .map(|pos| pos + 1) // Stop _after_ the found candidate1888            .unwrap_or(candidates.len()); // Otherwise, include all candidates1889        let (candidates_to_expand, remaining_candidates) = candidates.split_at_mut(expand_until);18901891        // Expand one level of or-patterns for each candidate in `candidates_to_expand`.1892        // We take care to preserve the relative ordering of candidates, so that1893        // or-patterns are expanded in their parent's relative position.1894        let mut expanded_candidates = Vec::new();1895        for candidate in candidates_to_expand.iter_mut() {1896            if candidate.starts_with_or_pattern() {1897                let or_match_pair = candidate.match_pairs.remove(0);1898                // Expand the or-pattern into subcandidates.1899                self.create_or_subcandidates(candidate, or_match_pair);1900                // Collect the newly created subcandidates.1901                for subcandidate in candidate.subcandidates.iter_mut() {1902                    expanded_candidates.push(subcandidate);1903                }1904                // Note that the subcandidates have been added to `expanded_candidates`,1905                // but `candidate` itself has not. If the last candidate has more match pairs,1906                // they are handled separately by `test_remaining_match_pairs_after_or`.1907            } else {1908                // A candidate that doesn't start with an or-pattern has nothing to1909                // expand, so it is included in the post-expansion list as-is.1910                expanded_candidates.push(candidate);1911            }1912        }19131914        // Recursively lower the part of the match tree represented by the1915        // expanded candidates. This is where subcandidates actually get lowered!1916        let remainder_start = self.match_candidates(1917            span,1918            scrutinee_span,1919            start_block,1920            expanded_candidates.as_mut_slice(),1921        );19221923        // Postprocess subcandidates, and process any leftover match pairs.1924        // (Only the last candidate can possibly have more match pairs.)1925        debug_assert!({1926            let mut all_except_last = candidates_to_expand.iter().rev().skip(1);1927            all_except_last.all(|candidate| candidate.match_pairs.is_empty())1928        });1929        for candidate in candidates_to_expand.iter_mut() {1930            if !candidate.subcandidates.is_empty() {1931                self.merge_trivial_subcandidates(candidate);1932                self.remove_never_subcandidates(candidate);1933            }1934        }1935        // It's important to perform the above simplifications _before_ dealing1936        // with remaining match pairs, to avoid exponential blowup if possible1937        // (for trivial or-patterns), and avoid useless work (for never patterns).1938        if let Some(last_candidate) = candidates_to_expand.last_mut() {1939            self.test_remaining_match_pairs_after_or(span, scrutinee_span, last_candidate);1940        }19411942        remainder_start.and(remaining_candidates)1943    }19441945    /// Given a match-pair that corresponds to an or-pattern, expand each subpattern into a new1946    /// subcandidate. Any candidate that has been expanded this way should also be postprocessed1947    /// at the end of [`Self::expand_and_match_or_candidates`].1948    fn create_or_subcandidates(1949        &mut self,1950        candidate: &mut Candidate<'tcx>,1951        match_pair: MatchPairTree<'tcx>,1952    ) {1953        let TestableCase::Or { pats } = match_pair.testable_case else { bug!() };1954        debug!("expanding or-pattern: candidate={:#?}\npats={:#?}", candidate, pats);1955        candidate.or_span = Some(match_pair.pattern_span);1956        candidate.subcandidates = pats1957            .into_iter()1958            .map(|flat_pat| Candidate::from_flat_pat(flat_pat, candidate.has_guard))1959            .collect();1960        candidate.subcandidates[0].false_edge_start_block = candidate.false_edge_start_block;1961    }19621963    /// Try to merge all of the subcandidates of the given candidate into one. This avoids1964    /// exponentially large CFGs in cases like `(1 | 2, 3 | 4, ...)`. The candidate should have been1965    /// expanded with `create_or_subcandidates`.1966    ///1967    /// Given a pattern `(P | Q, R | S)` we (in principle) generate a CFG like1968    /// so:1969    ///1970    /// ```text1971    /// [ start ]1972    ///      |1973    /// [ match P, Q ]1974    ///      |1975    ///      +----------------------------------------+------------------------------------+1976    ///      |                                        |                                    |1977    ///      V                                        V                                    V1978    /// [ P matches ]                           [ Q matches ]                        [ otherwise ]1979    ///      |                                        |                                    |1980    ///      V                                        V                                    |1981    /// [ match R, S ]                          [ match R, S ]                             |1982    ///      |                                        |                                    |1983    ///      +--------------+------------+            +--------------+------------+        |1984    ///      |              |            |            |              |            |        |1985    ///      V              V            V            V              V            V        |1986    /// [ R matches ] [ S matches ] [otherwise ] [ R matches ] [ S matches ] [otherwise ]  |1987    ///      |              |            |            |              |            |        |1988    ///      +--------------+------------|------------+--------------+            |        |1989    ///      |                           |                                        |        |1990    ///      |                           +----------------------------------------+--------+1991    ///      |                           |1992    ///      V                           V1993    /// [ Success ]                 [ Failure ]1994    /// ```1995    ///1996    /// In practice there are some complications:1997    ///1998    /// * If there's a guard, then the otherwise branch of the first match on1999    ///   `R | S` goes to a test for whether `Q` matches, and the control flow2000    ///   doesn't merge into a single success block until after the guard is

Findings

✓ No findings reported for this file.

Get this view in your editor

Same data, no extra tab — call code_get_file + code_get_findings over MCP from Claude/Cursor/Copilot.