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}