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