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}