rustc_mir_build/builder/matches/
test.rs

1// Testing candidates
2//
3// After candidates have been simplified, the only match pairs that
4// remain are those that require some sort of test. The functions here
5// identify what tests are needed, perform the tests, and then filter
6// the candidates based on the result.
7
8use std::cmp::Ordering;
9use std::sync::Arc;
10
11use rustc_data_structures::fx::FxIndexMap;
12use rustc_hir::{LangItem, RangeEnd};
13use rustc_middle::mir::*;
14use rustc_middle::ty::adjustment::PointerCoercion;
15use rustc_middle::ty::util::IntTypeExt;
16use rustc_middle::ty::{self, GenericArg, Ty, TyCtxt};
17use rustc_middle::{bug, span_bug};
18use rustc_span::def_id::DefId;
19use rustc_span::source_map::Spanned;
20use rustc_span::{DUMMY_SP, Span, Symbol, sym};
21use tracing::{debug, instrument};
22
23use crate::builder::Builder;
24use crate::builder::matches::{Candidate, MatchPairTree, Test, TestBranch, TestCase, TestKind};
25
26impl<'a, 'tcx> Builder<'a, 'tcx> {
27    /// Identifies what test is needed to decide if `match_pair` is applicable.
28    ///
29    /// It is a bug to call this with a not-fully-simplified pattern.
30    pub(super) fn pick_test_for_match_pair(
31        &mut self,
32        match_pair: &MatchPairTree<'tcx>,
33    ) -> Test<'tcx> {
34        let kind = match match_pair.test_case {
35            TestCase::Variant { adt_def, variant_index: _ } => TestKind::Switch { adt_def },
36
37            TestCase::Constant { .. } if match_pair.pattern_ty.is_bool() => TestKind::If,
38            TestCase::Constant { .. } if is_switch_ty(match_pair.pattern_ty) => TestKind::SwitchInt,
39            TestCase::Constant { value } => TestKind::Eq { value, ty: match_pair.pattern_ty },
40
41            TestCase::Range(ref range) => {
42                assert_eq!(range.ty, match_pair.pattern_ty);
43                TestKind::Range(Arc::clone(range))
44            }
45
46            TestCase::Slice { len, variable_length } => {
47                let op = if variable_length { BinOp::Ge } else { BinOp::Eq };
48                TestKind::Len { len: len as u64, op }
49            }
50
51            TestCase::Deref { temp, mutability } => TestKind::Deref { temp, mutability },
52
53            TestCase::Never => TestKind::Never,
54
55            // Or-patterns are not tested directly; instead they are expanded into subcandidates,
56            // which are then distinguished by testing whatever non-or patterns they contain.
57            TestCase::Or { .. } => bug!("or-patterns should have already been handled"),
58
59            TestCase::Irrefutable { .. } => span_bug!(
60                match_pair.pattern_span,
61                "simplifiable pattern found: {:?}",
62                match_pair.pattern_span
63            ),
64        };
65
66        Test { span: match_pair.pattern_span, kind }
67    }
68
69    #[instrument(skip(self, target_blocks, place), level = "debug")]
70    pub(super) fn perform_test(
71        &mut self,
72        match_start_span: Span,
73        scrutinee_span: Span,
74        block: BasicBlock,
75        otherwise_block: BasicBlock,
76        place: Place<'tcx>,
77        test: &Test<'tcx>,
78        target_blocks: FxIndexMap<TestBranch<'tcx>, BasicBlock>,
79    ) {
80        let place_ty = place.ty(&self.local_decls, self.tcx);
81        debug!(?place, ?place_ty);
82        let target_block = |branch| target_blocks.get(&branch).copied().unwrap_or(otherwise_block);
83
84        let source_info = self.source_info(test.span);
85        match test.kind {
86            TestKind::Switch { adt_def } => {
87                let otherwise_block = target_block(TestBranch::Failure);
88                let switch_targets = SwitchTargets::new(
89                    adt_def.discriminants(self.tcx).filter_map(|(idx, discr)| {
90                        if let Some(&block) = target_blocks.get(&TestBranch::Variant(idx)) {
91                            Some((discr.val, block))
92                        } else {
93                            None
94                        }
95                    }),
96                    otherwise_block,
97                );
98                debug!("num_enum_variants: {}", adt_def.variants().len());
99                let discr_ty = adt_def.repr().discr_type().to_ty(self.tcx);
100                let discr = self.temp(discr_ty, test.span);
101                self.cfg.push_assign(
102                    block,
103                    self.source_info(scrutinee_span),
104                    discr,
105                    Rvalue::Discriminant(place),
106                );
107                self.cfg.terminate(
108                    block,
109                    self.source_info(match_start_span),
110                    TerminatorKind::SwitchInt {
111                        discr: Operand::Move(discr),
112                        targets: switch_targets,
113                    },
114                );
115            }
116
117            TestKind::SwitchInt => {
118                // The switch may be inexhaustive so we have a catch-all block
119                let otherwise_block = target_block(TestBranch::Failure);
120                let switch_targets = SwitchTargets::new(
121                    target_blocks.iter().filter_map(|(&branch, &block)| {
122                        if let TestBranch::Constant(_, bits) = branch {
123                            Some((bits, block))
124                        } else {
125                            None
126                        }
127                    }),
128                    otherwise_block,
129                );
130                let terminator = TerminatorKind::SwitchInt {
131                    discr: Operand::Copy(place),
132                    targets: switch_targets,
133                };
134                self.cfg.terminate(block, self.source_info(match_start_span), terminator);
135            }
136
137            TestKind::If => {
138                let success_block = target_block(TestBranch::Success);
139                let fail_block = target_block(TestBranch::Failure);
140                let terminator =
141                    TerminatorKind::if_(Operand::Copy(place), success_block, fail_block);
142                self.cfg.terminate(block, self.source_info(match_start_span), terminator);
143            }
144
145            TestKind::Eq { value, mut ty } => {
146                let tcx = self.tcx;
147                let success_block = target_block(TestBranch::Success);
148                let fail_block = target_block(TestBranch::Failure);
149
150                let expect_ty = value.ty();
151                let expect = self.literal_operand(test.span, value);
152
153                let mut place = place;
154                let mut block = block;
155                match ty.kind() {
156                    ty::Adt(def, _) if tcx.is_lang_item(def.did(), LangItem::String) => {
157                        if !tcx.features().string_deref_patterns() {
158                            span_bug!(
159                                test.span,
160                                "matching on `String` went through without enabling string_deref_patterns"
161                            );
162                        }
163                        let re_erased = tcx.lifetimes.re_erased;
164                        let ref_str_ty = Ty::new_imm_ref(tcx, re_erased, tcx.types.str_);
165                        let ref_str = self.temp(ref_str_ty, test.span);
166                        let eq_block = self.cfg.start_new_block();
167                        // `let ref_str: &str = <String as Deref>::deref(&place);`
168                        self.call_deref(
169                            block,
170                            eq_block,
171                            place,
172                            Mutability::Not,
173                            ty,
174                            ref_str,
175                            test.span,
176                        );
177                        // Since we generated a `ref_str = <String as Deref>::deref(&place) -> eq_block` terminator,
178                        // we need to add all further statements to `eq_block`.
179                        // Similarly, the normal test code should be generated for the `&str`, instead of the `String`.
180                        block = eq_block;
181                        place = ref_str;
182                        ty = ref_str_ty;
183                    }
184                    _ => {}
185                }
186
187                if !ty.is_scalar() {
188                    // Use `PartialEq::eq` instead of `BinOp::Eq`
189                    // (the binop can only handle primitives)
190                    self.non_scalar_compare(
191                        block,
192                        success_block,
193                        fail_block,
194                        source_info,
195                        expect,
196                        expect_ty,
197                        Operand::Copy(place),
198                        ty,
199                    );
200                } else {
201                    assert_eq!(expect_ty, ty);
202                    self.compare(
203                        block,
204                        success_block,
205                        fail_block,
206                        source_info,
207                        BinOp::Eq,
208                        expect,
209                        Operand::Copy(place),
210                    );
211                }
212            }
213
214            TestKind::Range(ref range) => {
215                let success = target_block(TestBranch::Success);
216                let fail = target_block(TestBranch::Failure);
217                // Test `val` by computing `lo <= val && val <= hi`, using primitive comparisons.
218                let val = Operand::Copy(place);
219
220                let intermediate_block = if !range.lo.is_finite() {
221                    block
222                } else if !range.hi.is_finite() {
223                    success
224                } else {
225                    self.cfg.start_new_block()
226                };
227
228                if let Some(lo) = range.lo.as_finite() {
229                    let lo = self.literal_operand(test.span, lo);
230                    self.compare(
231                        block,
232                        intermediate_block,
233                        fail,
234                        source_info,
235                        BinOp::Le,
236                        lo,
237                        val.clone(),
238                    );
239                };
240
241                if let Some(hi) = range.hi.as_finite() {
242                    let hi = self.literal_operand(test.span, hi);
243                    let op = match range.end {
244                        RangeEnd::Included => BinOp::Le,
245                        RangeEnd::Excluded => BinOp::Lt,
246                    };
247                    self.compare(intermediate_block, success, fail, source_info, op, val, hi);
248                }
249            }
250
251            TestKind::Len { len, op } => {
252                let usize_ty = self.tcx.types.usize;
253                let actual = self.temp(usize_ty, test.span);
254
255                // actual = len(place)
256                self.cfg.push_assign(block, source_info, actual, Rvalue::Len(place));
257
258                // expected = <N>
259                let expected = self.push_usize(block, source_info, len);
260
261                let success_block = target_block(TestBranch::Success);
262                let fail_block = target_block(TestBranch::Failure);
263                // result = actual == expected OR result = actual < expected
264                // branch based on result
265                self.compare(
266                    block,
267                    success_block,
268                    fail_block,
269                    source_info,
270                    op,
271                    Operand::Move(actual),
272                    Operand::Move(expected),
273                );
274            }
275
276            TestKind::Deref { temp, mutability } => {
277                let ty = place_ty.ty;
278                let target = target_block(TestBranch::Success);
279                self.call_deref(block, target, place, mutability, ty, temp, test.span);
280            }
281
282            TestKind::Never => {
283                // Check that the place is initialized.
284                // FIXME(never_patterns): Also assert validity of the data at `place`.
285                self.cfg.push_fake_read(
286                    block,
287                    source_info,
288                    FakeReadCause::ForMatchedPlace(None),
289                    place,
290                );
291                // A never pattern is only allowed on an uninhabited type, so validity of the data
292                // implies unreachability.
293                self.cfg.terminate(block, source_info, TerminatorKind::Unreachable);
294            }
295        }
296    }
297
298    /// Perform `let temp = <ty as Deref>::deref(&place)`.
299    /// or `let temp = <ty as DerefMut>::deref_mut(&mut place)`.
300    pub(super) fn call_deref(
301        &mut self,
302        block: BasicBlock,
303        target_block: BasicBlock,
304        place: Place<'tcx>,
305        mutability: Mutability,
306        ty: Ty<'tcx>,
307        temp: Place<'tcx>,
308        span: Span,
309    ) {
310        let (trait_item, method) = match mutability {
311            Mutability::Not => (LangItem::Deref, sym::deref),
312            Mutability::Mut => (LangItem::DerefMut, sym::deref_mut),
313        };
314        let borrow_kind = super::util::ref_pat_borrow_kind(mutability);
315        let source_info = self.source_info(span);
316        let re_erased = self.tcx.lifetimes.re_erased;
317        let trait_item = self.tcx.require_lang_item(trait_item, None);
318        let method = trait_method(self.tcx, trait_item, method, [ty]);
319        let ref_src = self.temp(Ty::new_ref(self.tcx, re_erased, ty, mutability), span);
320        // `let ref_src = &src_place;`
321        // or `let ref_src = &mut src_place;`
322        self.cfg.push_assign(
323            block,
324            source_info,
325            ref_src,
326            Rvalue::Ref(re_erased, borrow_kind, place),
327        );
328        // `let temp = <Ty as Deref>::deref(ref_src);`
329        // or `let temp = <Ty as DerefMut>::deref_mut(ref_src);`
330        self.cfg.terminate(
331            block,
332            source_info,
333            TerminatorKind::Call {
334                func: Operand::Constant(Box::new(ConstOperand {
335                    span,
336                    user_ty: None,
337                    const_: method,
338                })),
339                args: [Spanned { node: Operand::Move(ref_src), span }].into(),
340                destination: temp,
341                target: Some(target_block),
342                unwind: UnwindAction::Continue,
343                call_source: CallSource::Misc,
344                fn_span: source_info.span,
345            },
346        );
347    }
348
349    /// Compare using the provided built-in comparison operator
350    fn compare(
351        &mut self,
352        block: BasicBlock,
353        success_block: BasicBlock,
354        fail_block: BasicBlock,
355        source_info: SourceInfo,
356        op: BinOp,
357        left: Operand<'tcx>,
358        right: Operand<'tcx>,
359    ) {
360        let bool_ty = self.tcx.types.bool;
361        let result = self.temp(bool_ty, source_info.span);
362
363        // result = op(left, right)
364        self.cfg.push_assign(
365            block,
366            source_info,
367            result,
368            Rvalue::BinaryOp(op, Box::new((left, right))),
369        );
370
371        // branch based on result
372        self.cfg.terminate(
373            block,
374            source_info,
375            TerminatorKind::if_(Operand::Move(result), success_block, fail_block),
376        );
377    }
378
379    /// Compare two values using `<T as std::compare::PartialEq>::eq`.
380    /// If the values are already references, just call it directly, otherwise
381    /// take a reference to the values first and then call it.
382    fn non_scalar_compare(
383        &mut self,
384        block: BasicBlock,
385        success_block: BasicBlock,
386        fail_block: BasicBlock,
387        source_info: SourceInfo,
388        mut expect: Operand<'tcx>,
389        expect_ty: Ty<'tcx>,
390        mut val: Operand<'tcx>,
391        mut ty: Ty<'tcx>,
392    ) {
393        // If we're using `b"..."` as a pattern, we need to insert an
394        // unsizing coercion, as the byte string has the type `&[u8; N]`.
395        //
396        // We want to do this even when the scrutinee is a reference to an
397        // array, so we can call `<[u8]>::eq` rather than having to find an
398        // `<[u8; N]>::eq`.
399        let unsize = |ty: Ty<'tcx>| match ty.kind() {
400            ty::Ref(region, rty, _) => match rty.kind() {
401                ty::Array(inner_ty, n) => Some((region, inner_ty, n)),
402                _ => None,
403            },
404            _ => None,
405        };
406        let opt_ref_ty = unsize(ty);
407        let opt_ref_test_ty = unsize(expect_ty);
408        match (opt_ref_ty, opt_ref_test_ty) {
409            // nothing to do, neither is an array
410            (None, None) => {}
411            (Some((region, elem_ty, _)), _) | (None, Some((region, elem_ty, _))) => {
412                let tcx = self.tcx;
413                // make both a slice
414                ty = Ty::new_imm_ref(tcx, *region, Ty::new_slice(tcx, *elem_ty));
415                if opt_ref_ty.is_some() {
416                    let temp = self.temp(ty, source_info.span);
417                    self.cfg.push_assign(
418                        block,
419                        source_info,
420                        temp,
421                        Rvalue::Cast(
422                            CastKind::PointerCoercion(
423                                PointerCoercion::Unsize,
424                                CoercionSource::Implicit,
425                            ),
426                            val,
427                            ty,
428                        ),
429                    );
430                    val = Operand::Copy(temp);
431                }
432                if opt_ref_test_ty.is_some() {
433                    let slice = self.temp(ty, source_info.span);
434                    self.cfg.push_assign(
435                        block,
436                        source_info,
437                        slice,
438                        Rvalue::Cast(
439                            CastKind::PointerCoercion(
440                                PointerCoercion::Unsize,
441                                CoercionSource::Implicit,
442                            ),
443                            expect,
444                            ty,
445                        ),
446                    );
447                    expect = Operand::Move(slice);
448                }
449            }
450        }
451
452        // Figure out the type on which we are calling `PartialEq`. This involves an extra wrapping
453        // reference: we can only compare two `&T`, and then compare_ty will be `T`.
454        // Make sure that we do *not* call any user-defined code here.
455        // The only types that can end up here are string and byte literals,
456        // which have their comparison defined in `core`.
457        // (Interestingly this means that exhaustiveness analysis relies, for soundness,
458        // on the `PartialEq` impls for `str` and `[u8]` to b correct!)
459        let compare_ty = match *ty.kind() {
460            ty::Ref(_, deref_ty, _)
461                if deref_ty == self.tcx.types.str_ || deref_ty != self.tcx.types.u8 =>
462            {
463                deref_ty
464            }
465            _ => span_bug!(source_info.span, "invalid type for non-scalar compare: {}", ty),
466        };
467
468        let eq_def_id = self.tcx.require_lang_item(LangItem::PartialEq, Some(source_info.span));
469        let method = trait_method(self.tcx, eq_def_id, sym::eq, [compare_ty, compare_ty]);
470
471        let bool_ty = self.tcx.types.bool;
472        let eq_result = self.temp(bool_ty, source_info.span);
473        let eq_block = self.cfg.start_new_block();
474        self.cfg.terminate(
475            block,
476            source_info,
477            TerminatorKind::Call {
478                func: Operand::Constant(Box::new(ConstOperand {
479                    span: source_info.span,
480
481                    // FIXME(#54571): This constant comes from user input (a
482                    // constant in a pattern). Are there forms where users can add
483                    // type annotations here?  For example, an associated constant?
484                    // Need to experiment.
485                    user_ty: None,
486
487                    const_: method,
488                })),
489                args: [
490                    Spanned { node: val, span: DUMMY_SP },
491                    Spanned { node: expect, span: DUMMY_SP },
492                ]
493                .into(),
494                destination: eq_result,
495                target: Some(eq_block),
496                unwind: UnwindAction::Continue,
497                call_source: CallSource::MatchCmp,
498                fn_span: source_info.span,
499            },
500        );
501        self.diverge_from(block);
502
503        // check the result
504        self.cfg.terminate(
505            eq_block,
506            source_info,
507            TerminatorKind::if_(Operand::Move(eq_result), success_block, fail_block),
508        );
509    }
510
511    /// Given that we are performing `test` against `test_place`, this job
512    /// sorts out what the status of `candidate` will be after the test. See
513    /// `test_candidates` for the usage of this function. The candidate may
514    /// be modified to update its `match_pairs`.
515    ///
516    /// So, for example, if this candidate is `x @ Some(P0)` and the `Test` is
517    /// a variant test, then we would modify the candidate to be `(x as
518    /// Option).0 @ P0` and return the index corresponding to the variant
519    /// `Some`.
520    ///
521    /// However, in some cases, the test may just not be relevant to candidate.
522    /// For example, suppose we are testing whether `foo.x == 22`, but in one
523    /// match arm we have `Foo { x: _, ... }`... in that case, the test for
524    /// the value of `x` has no particular relevance to this candidate. In
525    /// such cases, this function just returns None without doing anything.
526    /// This is used by the overall `match_candidates` algorithm to structure
527    /// the match as a whole. See `match_candidates` for more details.
528    ///
529    /// FIXME(#29623). In some cases, we have some tricky choices to make. for
530    /// example, if we are testing that `x == 22`, but the candidate is `x @
531    /// 13..55`, what should we do? In the event that the test is true, we know
532    /// that the candidate applies, but in the event of false, we don't know
533    /// that it *doesn't* apply. For now, we return false, indicate that the
534    /// test does not apply to this candidate, but it might be we can get
535    /// tighter match code if we do something a bit different.
536    pub(super) fn sort_candidate(
537        &mut self,
538        test_place: Place<'tcx>,
539        test: &Test<'tcx>,
540        candidate: &mut Candidate<'tcx>,
541        sorted_candidates: &FxIndexMap<TestBranch<'tcx>, Vec<&mut Candidate<'tcx>>>,
542    ) -> Option<TestBranch<'tcx>> {
543        // Find the match_pair for this place (if any). At present,
544        // afaik, there can be at most one. (In the future, if we
545        // adopted a more general `@` operator, there might be more
546        // than one, but it'd be very unusual to have two sides that
547        // both require tests; you'd expect one side to be simplified
548        // away.)
549        let (match_pair_index, match_pair) = candidate
550            .match_pairs
551            .iter()
552            .enumerate()
553            .find(|&(_, mp)| mp.place == Some(test_place))?;
554
555        // If true, the match pair is completely entailed by its corresponding test
556        // branch, so it can be removed. If false, the match pair is _compatible_
557        // with its test branch, but still needs a more specific test.
558        let fully_matched;
559        let ret = match (&test.kind, &match_pair.test_case) {
560            // If we are performing a variant switch, then this
561            // informs variant patterns, but nothing else.
562            (
563                &TestKind::Switch { adt_def: tested_adt_def },
564                &TestCase::Variant { adt_def, variant_index },
565            ) => {
566                assert_eq!(adt_def, tested_adt_def);
567                fully_matched = true;
568                Some(TestBranch::Variant(variant_index))
569            }
570
571            // If we are performing a switch over integers, then this informs integer
572            // equality, but nothing else.
573            //
574            // FIXME(#29623) we could use PatKind::Range to rule
575            // things out here, in some cases.
576            (TestKind::SwitchInt, &TestCase::Constant { value })
577                if is_switch_ty(match_pair.pattern_ty) =>
578            {
579                // An important invariant of candidate sorting is that a candidate
580                // must not match in multiple branches. For `SwitchInt` tests, adding
581                // a new value might invalidate that property for range patterns that
582                // have already been sorted into the failure arm, so we must take care
583                // not to add such values here.
584                let is_covering_range = |test_case: &TestCase<'tcx>| {
585                    test_case.as_range().is_some_and(|range| {
586                        matches!(
587                            range.contains(value, self.tcx, self.typing_env()),
588                            None | Some(true)
589                        )
590                    })
591                };
592                let is_conflicting_candidate = |candidate: &&mut Candidate<'tcx>| {
593                    candidate
594                        .match_pairs
595                        .iter()
596                        .any(|mp| mp.place == Some(test_place) && is_covering_range(&mp.test_case))
597                };
598                if sorted_candidates
599                    .get(&TestBranch::Failure)
600                    .is_some_and(|candidates| candidates.iter().any(is_conflicting_candidate))
601                {
602                    fully_matched = false;
603                    None
604                } else {
605                    fully_matched = true;
606                    let bits = value.eval_bits(self.tcx, self.typing_env());
607                    Some(TestBranch::Constant(value, bits))
608                }
609            }
610            (TestKind::SwitchInt, TestCase::Range(range)) => {
611                // When performing a `SwitchInt` test, a range pattern can be
612                // sorted into the failure arm if it doesn't contain _any_ of
613                // the values being tested. (This restricts what values can be
614                // added to the test by subsequent candidates.)
615                fully_matched = false;
616                let not_contained =
617                    sorted_candidates.keys().filter_map(|br| br.as_constant()).copied().all(
618                        |val| {
619                            matches!(range.contains(val, self.tcx, self.typing_env()), Some(false))
620                        },
621                    );
622
623                not_contained.then(|| {
624                    // No switch values are contained in the pattern range,
625                    // so the pattern can be matched only if this test fails.
626                    TestBranch::Failure
627                })
628            }
629
630            (TestKind::If, TestCase::Constant { value }) => {
631                fully_matched = true;
632                let value = value.try_eval_bool(self.tcx, self.typing_env()).unwrap_or_else(|| {
633                    span_bug!(test.span, "expected boolean value but got {value:?}")
634                });
635                Some(if value { TestBranch::Success } else { TestBranch::Failure })
636            }
637
638            (
639                &TestKind::Len { len: test_len, op: BinOp::Eq },
640                &TestCase::Slice { len, variable_length },
641            ) => {
642                match (test_len.cmp(&(len as u64)), variable_length) {
643                    (Ordering::Equal, false) => {
644                        // on true, min_len = len = $actual_length,
645                        // on false, len != $actual_length
646                        fully_matched = true;
647                        Some(TestBranch::Success)
648                    }
649                    (Ordering::Less, _) => {
650                        // test_len < pat_len. If $actual_len = test_len,
651                        // then $actual_len < pat_len and we don't have
652                        // enough elements.
653                        fully_matched = false;
654                        Some(TestBranch::Failure)
655                    }
656                    (Ordering::Equal | Ordering::Greater, true) => {
657                        // This can match both if $actual_len = test_len >= pat_len,
658                        // and if $actual_len > test_len. We can't advance.
659                        fully_matched = false;
660                        None
661                    }
662                    (Ordering::Greater, false) => {
663                        // test_len != pat_len, so if $actual_len = test_len, then
664                        // $actual_len != pat_len.
665                        fully_matched = false;
666                        Some(TestBranch::Failure)
667                    }
668                }
669            }
670            (
671                &TestKind::Len { len: test_len, op: BinOp::Ge },
672                &TestCase::Slice { len, variable_length },
673            ) => {
674                // the test is `$actual_len >= test_len`
675                match (test_len.cmp(&(len as u64)), variable_length) {
676                    (Ordering::Equal, true) => {
677                        // $actual_len >= test_len = pat_len,
678                        // so we can match.
679                        fully_matched = true;
680                        Some(TestBranch::Success)
681                    }
682                    (Ordering::Less, _) | (Ordering::Equal, false) => {
683                        // test_len <= pat_len. If $actual_len < test_len,
684                        // then it is also < pat_len, so the test passing is
685                        // necessary (but insufficient).
686                        fully_matched = false;
687                        Some(TestBranch::Success)
688                    }
689                    (Ordering::Greater, false) => {
690                        // test_len > pat_len. If $actual_len >= test_len > pat_len,
691                        // then we know we won't have a match.
692                        fully_matched = false;
693                        Some(TestBranch::Failure)
694                    }
695                    (Ordering::Greater, true) => {
696                        // test_len < pat_len, and is therefore less
697                        // strict. This can still go both ways.
698                        fully_matched = false;
699                        None
700                    }
701                }
702            }
703
704            (TestKind::Range(test), TestCase::Range(pat)) => {
705                if test == pat {
706                    fully_matched = true;
707                    Some(TestBranch::Success)
708                } else {
709                    fully_matched = false;
710                    // If the testing range does not overlap with pattern range,
711                    // the pattern can be matched only if this test fails.
712                    if !test.overlaps(pat, self.tcx, self.typing_env())? {
713                        Some(TestBranch::Failure)
714                    } else {
715                        None
716                    }
717                }
718            }
719            (TestKind::Range(range), &TestCase::Constant { value }) => {
720                fully_matched = false;
721                if !range.contains(value, self.tcx, self.typing_env())? {
722                    // `value` is not contained in the testing range,
723                    // so `value` can be matched only if this test fails.
724                    Some(TestBranch::Failure)
725                } else {
726                    None
727                }
728            }
729
730            (TestKind::Eq { value: test_val, .. }, TestCase::Constant { value: case_val }) => {
731                if test_val == case_val {
732                    fully_matched = true;
733                    Some(TestBranch::Success)
734                } else {
735                    fully_matched = false;
736                    Some(TestBranch::Failure)
737                }
738            }
739
740            (TestKind::Deref { temp: test_temp, .. }, TestCase::Deref { temp, .. })
741                if test_temp == temp =>
742            {
743                fully_matched = true;
744                Some(TestBranch::Success)
745            }
746
747            (TestKind::Never, _) => {
748                fully_matched = true;
749                Some(TestBranch::Success)
750            }
751
752            (
753                TestKind::Switch { .. }
754                | TestKind::SwitchInt { .. }
755                | TestKind::If
756                | TestKind::Len { .. }
757                | TestKind::Range { .. }
758                | TestKind::Eq { .. }
759                | TestKind::Deref { .. },
760                _,
761            ) => {
762                fully_matched = false;
763                None
764            }
765        };
766
767        if fully_matched {
768            // Replace the match pair by its sub-pairs.
769            let match_pair = candidate.match_pairs.remove(match_pair_index);
770            candidate.match_pairs.extend(match_pair.subpairs);
771            // Move or-patterns to the end.
772            candidate.match_pairs.sort_by_key(|pair| matches!(pair.test_case, TestCase::Or { .. }));
773        }
774
775        ret
776    }
777}
778
779fn is_switch_ty(ty: Ty<'_>) -> bool {
780    ty.is_integral() || ty.is_char()
781}
782
783fn trait_method<'tcx>(
784    tcx: TyCtxt<'tcx>,
785    trait_def_id: DefId,
786    method_name: Symbol,
787    args: impl IntoIterator<Item: Into<GenericArg<'tcx>>>,
788) -> Const<'tcx> {
789    // The unhygienic comparison here is acceptable because this is only
790    // used on known traits.
791    let item = tcx
792        .associated_items(trait_def_id)
793        .filter_by_name_unhygienic(method_name)
794        .find(|item| item.kind == ty::AssocKind::Fn)
795        .expect("trait method not found");
796
797    let method_ty = Ty::new_fn_def(tcx, item.def_id, args);
798
799    Const::zero_sized(method_ty)
800}