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