1use crate::{Diagnostic, DiagnosticCode, DiagnosticsContext};
2
3pub(crate) fn missing_match_arms(
7 ctx: &DiagnosticsContext<'_>,
8 d: &hir::MissingMatchArms,
9) -> Diagnostic {
10 Diagnostic::new_with_syntax_node_ptr(
11 ctx,
12 DiagnosticCode::RustcHardError("E0004"),
13 format!("missing match arm: {}", d.uncovered_patterns),
14 d.scrutinee_expr.map(Into::into),
15 )
16 .stable()
17}
18
19#[cfg(test)]
20mod tests {
21 use crate::{
22 DiagnosticsConfig,
23 tests::{
24 check_diagnostics, check_diagnostics_with_config, check_diagnostics_with_disabled,
25 },
26 };
27 use test_utils::skip_slow_tests;
28
29 #[track_caller]
30 fn check_diagnostics_no_bails(#[rust_analyzer::rust_fixture] ra_fixture: &str) {
31 cov_mark::check_count!(validate_match_bailed_out, 0);
32 crate::tests::check_diagnostics(ra_fixture)
33 }
34
35 #[test]
36 fn empty_body() {
37 let mut config = DiagnosticsConfig::test_sample();
38 config.disabled.insert("syntax-error".to_owned());
39 check_diagnostics_with_config(
40 config,
41 r#"
42fn main() {
43 match 0;
44}
45"#,
46 );
47 }
48
49 #[test]
50 fn empty_tuple() {
51 check_diagnostics_no_bails(
52 r#"
53fn main() {
54 match () { }
55 //^^ error: missing match arm: type `()` is non-empty
56 match (()) { }
57 //^^^^ error: missing match arm: type `()` is non-empty
58
59 match () { _ => (), }
60 match () { () => (), }
61 match (()) { (()) => (), }
62}
63"#,
64 );
65 }
66
67 #[test]
68 fn tuple_of_two_empty_tuple() {
69 check_diagnostics_no_bails(
70 r#"
71fn main() {
72 match ((), ()) { }
73 //^^^^^^^^ error: missing match arm: type `((), ())` is non-empty
74
75 match ((), ()) { ((), ()) => (), }
76}
77"#,
78 );
79 }
80
81 #[test]
82 fn boolean() {
83 check_diagnostics_no_bails(
84 r#"
85fn test_main() {
86 match false { }
87 //^^^^^ error: missing match arm: type `bool` is non-empty
88 match false { true => (), }
89 //^^^^^ error: missing match arm: `false` not covered
90 match (false, true) {}
91 //^^^^^^^^^^^^^ error: missing match arm: type `(bool, bool)` is non-empty
92 match (false, true) { (true, true) => (), }
93 //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
94 match (false, true) {
95 //^^^^^^^^^^^^^ error: missing match arm: `(true, true)` not covered
96 (false, true) => (),
97 (false, false) => (),
98 (true, false) => (),
99 }
100 match (false, true) { (true, _x) => (), }
101 //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
102
103 match false { true => (), false => (), }
104 match (false, true) {
105 (false, _) => (),
106 (true, false) => (),
107 (_, true) => (),
108 }
109 match (false, true) {
110 (true, true) => (),
111 (true, false) => (),
112 (false, true) => (),
113 (false, false) => (),
114 }
115 match (false, true) {
116 (true, _x) => (),
117 (false, true) => (),
118 (false, false) => (),
119 }
120 match (false, true, false) {
121 (false, ..) => (),
122 (true, ..) => (),
123 }
124 match (false, true, false) {
125 (.., false) => (),
126 (.., true) => (),
127 }
128 match (false, true, false) { (..) => (), }
129}
130"#,
131 );
132 }
133
134 #[test]
135 fn tuple_of_tuple_and_bools() {
136 check_diagnostics_no_bails(
137 r#"
138fn main() {
139 match (false, ((), false)) {}
140 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: type `(bool, ((), bool))` is non-empty
141 match (false, ((), false)) { (true, ((), true)) => (), }
142 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
143 match (false, ((), false)) { (true, _) => (), }
144 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
145
146 match (false, ((), false)) {
147 (true, ((), true)) => (),
148 (true, ((), false)) => (),
149 (false, ((), true)) => (),
150 (false, ((), false)) => (),
151 }
152 match (false, ((), false)) {
153 (true, ((), true)) => (),
154 (true, ((), false)) => (),
155 (false, _) => (),
156 }
157}
158"#,
159 );
160 }
161
162 #[test]
163 fn enums() {
164 check_diagnostics_no_bails(
165 r#"
166enum Either { A, B, }
167
168fn main() {
169 match Either::A { }
170 //^^^^^^^^^ error: missing match arm: `A` and `B` not covered
171 match Either::B { Either::A => (), }
172 //^^^^^^^^^ error: missing match arm: `B` not covered
173
174 match &Either::B {
175 //^^^^^^^^^^ error: missing match arm: `&B` not covered
176 Either::A => (),
177 }
178
179 match Either::B {
180 Either::A => (), Either::B => (),
181 }
182 match &Either::B {
183 Either::A => (), Either::B => (),
184 }
185}
186"#,
187 );
188 }
189
190 #[test]
191 fn enum_containing_bool() {
192 check_diagnostics_no_bails(
193 r#"
194enum Either { A(bool), B }
195
196fn main() {
197 match Either::B { }
198 //^^^^^^^^^ error: missing match arm: `A(_)` and `B` not covered
199 match Either::B {
200 //^^^^^^^^^ error: missing match arm: `A(false)` not covered
201 Either::A(true) => (), Either::B => ()
202 }
203
204 match Either::B {
205 Either::A(true) => (),
206 Either::A(false) => (),
207 Either::B => (),
208 }
209 match Either::B {
210 Either::B => (),
211 _ => (),
212 }
213 match Either::B {
214 Either::A(_) => (),
215 Either::B => (),
216 }
217
218}
219 "#,
220 );
221 }
222
223 #[test]
224 fn enum_different_sizes() {
225 check_diagnostics_no_bails(
226 r#"
227enum Either { A(bool), B(bool, bool) }
228
229fn main() {
230 match Either::A(false) {
231 //^^^^^^^^^^^^^^^^ error: missing match arm: `B(true, _)` not covered
232 Either::A(_) => (),
233 Either::B(false, _) => (),
234 }
235
236 match Either::A(false) {
237 Either::A(_) => (),
238 Either::B(true, _) => (),
239 Either::B(false, _) => (),
240 }
241 match Either::A(false) {
242 Either::A(true) | Either::A(false) => (),
243 Either::B(true, _) => (),
244 Either::B(false, _) => (),
245 }
246}
247"#,
248 );
249 }
250
251 #[test]
252 fn tuple_of_enum_no_diagnostic() {
253 check_diagnostics_no_bails(
254 r#"
255enum Either { A(bool), B(bool, bool) }
256enum Either2 { C, D }
257
258fn main() {
259 match (Either::A(false), Either2::C) {
260 (Either::A(true), _) | (Either::A(false), _) => (),
261 (Either::B(true, _), Either2::C) => (),
262 (Either::B(false, _), Either2::C) => (),
263 (Either::B(_, _), Either2::D) => (),
264 }
265}
266"#,
267 );
268 }
269
270 #[test]
271 fn or_pattern_no_diagnostic() {
272 check_diagnostics_no_bails(
273 r#"
274enum Either {A, B}
275
276fn main() {
277 match (Either::A, Either::B) {
278 (Either::A | Either::B, _) => (),
279 }
280}"#,
281 )
282 }
283
284 #[test]
285 fn mismatched_types() {
286 cov_mark::check_count!(validate_match_bailed_out, 4);
287 check_diagnostics_with_disabled(
290 r#"
291enum Either { A, B }
292enum Either2 { C, D }
293
294fn main() {
295 match Either::A {
296 Either2::C => (),
297 //^^^^^^^^^^ error: expected Either, found Either2
298 Either2::D => (),
299 //^^^^^^^^^^ error: expected Either, found Either2
300 }
301 match (true, false) {
302 (true, false, true) => (),
303 //^^^^^^^^^^^^^^^^^^^ error: expected (bool, bool), found (bool, bool, bool)
304 (true) => (),
305 // ^^^^ error: expected (bool, bool), found bool
306 }
307 match (true, false) { (true,) => {} }
308 //^^^^^^^ error: expected (bool, bool), found (bool,)
309 match (0) { () => () }
310 //^^ error: expected i32, found ()
311 match Unresolved::Bar { Unresolved::Baz => () }
312}
313 "#,
314 &["E0425"],
315 );
316 }
317
318 #[test]
319 fn mismatched_types_issue_15883() {
320 cov_mark::check!(validate_match_bailed_out);
322 check_diagnostics(
323 r#"
324//- minicore: option
325fn main() {
326 match Some((true, false)) {
327 Some(true) | Some(false) => {}
328 // ^^^^ error: expected (bool, bool), found bool
329 // ^^^^^ error: expected (bool, bool), found bool
330 None => {}
331 }
332}
333 "#,
334 );
335 }
336
337 #[test]
338 fn mismatched_types_in_or_patterns() {
339 cov_mark::check_count!(validate_match_bailed_out, 2);
340 check_diagnostics(
341 r#"
342fn main() {
343 match false { true | () => {} }
344 //^^ error: expected bool, found ()
345 match (false,) { (true | (),) => {} }
346 //^^ error: expected bool, found ()
347}
348"#,
349 );
350 }
351
352 #[test]
353 fn malformed_match_arm_tuple_enum_missing_pattern() {
354 check_diagnostics_no_bails(
357 r#"
358enum Either { A, B(u32) }
359
360fn main() {
361 match Either::A {
362 Either::A => (),
363 Either::B() => (),
364 // ^^ error: this pattern has 0 fields, but the corresponding tuple struct has 1 field
365 }
366}
367"#,
368 );
369 }
370
371 #[test]
372 fn malformed_match_arm_extra_fields() {
373 cov_mark::check_count!(validate_match_bailed_out, 2);
374 check_diagnostics(
375 r#"
376enum A { B(isize, isize), C }
377fn main() {
378 match A::B(1, 2) {
379 A::B(_, _, _) => (),
380 // ^^ error: this pattern has 3 fields, but the corresponding tuple struct has 2 fields
381 }
382 match A::B(1, 2) {
383 A::C(_) => (),
384 // ^^^ error: this pattern has 1 field, but the corresponding tuple struct has 0 fields
385 }
386}
387"#,
388 );
389 }
390
391 #[test]
392 fn expr_diverges() {
393 check_diagnostics(
394 r#"
395enum Either { A, B }
396
397fn main() {
398 match loop {} {
399 Either::A => (),
400 Either::B => (),
401 }
402 match loop {} {
403 // ^^^^^^^ error: missing match arm: `B` not covered
404 Either::A => (),
405 }
406 match loop { break Either::A } {
407 //^^^^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
408 Either::A => (),
409 }
410 match loop { break Either::A } {
411 Either::A => (),
412 Either::B => (),
413 }
414}
415"#,
416 );
417 }
418
419 #[test]
420 fn expr_partially_diverges() {
421 check_diagnostics_no_bails(
422 r#"
423enum Either<T> { A(T), B }
424
425fn foo() -> Either<!> { Either::B }
426fn main() -> u32 {
427 match foo() {
428 Either::A(val) => val,
429 Either::B => 0,
430 }
431}
432"#,
433 );
434 }
435
436 #[test]
437 fn enum_record() {
438 check_diagnostics_no_bails(
439 r#"
440enum Either { A { foo: bool }, B }
441
442fn main() {
443 let a = Either::A { foo: true };
444 match a { }
445 //^ error: missing match arm: `A { .. }` and `B` not covered
446 match a { Either::A { foo: true } => () }
447 //^ error: missing match arm: `B` not covered
448 match a {
449 Either::A { } => (),
450 //^^^^^^^^^ 💡 error: missing structure fields:
451 // | - foo
452 Either::B => (),
453 }
454 match a {
455 //^ error: missing match arm: `B` not covered
456 Either::A { } => (),
457 } //^^^^^^^^^ 💡 error: missing structure fields:
458 // | - foo
459
460 match a {
461 Either::A { foo: true } => (),
462 Either::A { foo: false } => (),
463 Either::B => (),
464 }
465 match a {
466 Either::A { foo: _ } => (),
467 Either::B => (),
468 }
469}
470"#,
471 );
472 }
473
474 #[test]
475 fn enum_record_fields_out_of_order() {
476 check_diagnostics_no_bails(
477 r#"
478enum Either {
479 A { foo: bool, bar: () },
480 B,
481}
482
483fn main() {
484 let a = Either::A { foo: true, bar: () };
485 match a {
486 //^ error: missing match arm: `B` not covered
487 Either::A { bar: (), foo: false } => (),
488 Either::A { foo: true, bar: () } => (),
489 }
490
491 match a {
492 Either::A { bar: (), foo: false } => (),
493 Either::A { foo: true, bar: () } => (),
494 Either::B => (),
495 }
496}
497"#,
498 );
499 }
500
501 #[test]
502 fn enum_record_ellipsis() {
503 check_diagnostics_no_bails(
504 r#"
505enum Either {
506 A { foo: bool, bar: bool },
507 B,
508}
509
510fn main() {
511 let a = Either::B;
512 match a {
513 //^ error: missing match arm: `A { foo: false, .. }` not covered
514 Either::A { foo: true, .. } => (),
515 Either::B => (),
516 }
517 match a {
518 //^ error: missing match arm: `B` not covered
519 Either::A { .. } => (),
520 }
521
522 match a {
523 Either::A { foo: true, .. } => (),
524 Either::A { foo: false, .. } => (),
525 Either::B => (),
526 }
527
528 match a {
529 Either::A { .. } => (),
530 Either::B => (),
531 }
532}
533"#,
534 );
535 }
536
537 #[test]
538 fn enum_tuple_partial_ellipsis() {
539 check_diagnostics_no_bails(
540 r#"
541enum Either {
542 A(bool, bool, bool, bool),
543 B,
544}
545
546fn main() {
547 match Either::B {
548 //^^^^^^^^^ error: missing match arm: `A(false, _, _, true)` not covered
549 Either::A(true, .., true) => (),
550 Either::A(true, .., false) => (),
551 Either::A(false, .., false) => (),
552 Either::B => (),
553 }
554 match Either::B {
555 //^^^^^^^^^ error: missing match arm: `A(false, _, _, false)` not covered
556 Either::A(true, .., true) => (),
557 Either::A(true, .., false) => (),
558 Either::A(.., true) => (),
559 Either::B => (),
560 }
561
562 match Either::B {
563 Either::A(true, .., true) => (),
564 Either::A(true, .., false) => (),
565 Either::A(false, .., true) => (),
566 Either::A(false, .., false) => (),
567 Either::B => (),
568 }
569 match Either::B {
570 Either::A(true, .., true) => (),
571 Either::A(true, .., false) => (),
572 Either::A(.., true) => (),
573 Either::A(.., false) => (),
574 Either::B => (),
575 }
576}
577"#,
578 );
579 }
580
581 #[test]
582 fn never() {
583 check_diagnostics_no_bails(
584 r#"
585enum Never {}
586
587fn enum_(never: Never) {
588 match never {}
589}
590fn enum_ref(never: &Never) {
591 match never {}
592 //^^^^^ error: missing match arm: type `&Never` is non-empty
593}
594fn bang(never: !) {
595 match never {}
596}
597"#,
598 );
599 }
600
601 #[test]
602 fn unknown_type() {
603 check_diagnostics_no_bails(
604 r#"
605enum Option<T> { Some(T), None }
606
607#[allow(unused)]
608fn main() {
609 // `Never` is deliberately not defined so that it's an uninferred type.
610 // We ignore these to avoid triggering bugs in the analysis.
611 match Option::<Never>::None {
612 Option::None => (),
613 Option::Some(never) => match never {},
614 }
615 match Option::<Never>::None {
616 Option::Some(_never) => {},
617 }
618}
619"#,
620 );
621 }
622
623 #[test]
624 fn arity_mismatch_issue_16746() {
625 check_diagnostics_with_disabled(
626 r#"
627fn main() {
628 let (a, ) = (0, 0);
629}
630"#,
631 &["E0308"],
632 );
633 }
634
635 #[test]
636 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
637 check_diagnostics_no_bails(
638 r#"
639fn main() {
640 match (false, true, false) {
641 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(true, _, _)` not covered
642 (false, ..) => (),
643 }
644}"#,
645 );
646 }
647
648 #[test]
649 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
650 check_diagnostics_no_bails(
651 r#"
652fn main() {
653 match (false, true, false) {
654 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(_, _, true)` not covered
655 (.., false) => (),
656 }
657}"#,
658 );
659 }
660
661 #[test]
662 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
663 check_diagnostics_no_bails(
664 r#"
665fn main() {
666 match (false, true, false) {
667 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _, _)` not covered
668 (true, .., false) => (),
669 }
670}"#,
671 );
672 }
673
674 #[test]
675 fn record_struct() {
676 check_diagnostics_no_bails(
677 r#"struct Foo { a: bool }
678fn main(f: Foo) {
679 match f {}
680 //^ error: missing match arm: type `Foo` is non-empty
681 match f { Foo { a: true } => () }
682 //^ error: missing match arm: `Foo { a: false }` not covered
683 match &f { Foo { a: true } => () }
684 //^^ error: missing match arm: `&Foo { a: false }` not covered
685 match f { Foo { a: _ } => () }
686 match f {
687 Foo { a: true } => (),
688 Foo { a: false } => (),
689 }
690 match &f {
691 Foo { a: true } => (),
692 Foo { a: false } => (),
693 }
694}
695"#,
696 );
697 }
698
699 #[test]
700 fn tuple_struct() {
701 check_diagnostics_no_bails(
702 r#"struct Foo(bool);
703fn main(f: Foo) {
704 match f {}
705 //^ error: missing match arm: type `Foo` is non-empty
706 match f { Foo(true) => () }
707 //^ error: missing match arm: `Foo(false)` not covered
708 match f {
709 Foo(true) => (),
710 Foo(false) => (),
711 }
712}
713"#,
714 );
715 }
716
717 #[test]
718 fn unit_struct() {
719 check_diagnostics_no_bails(
720 r#"struct Foo;
721fn main(f: Foo) {
722 match f {}
723 //^ error: missing match arm: type `Foo` is non-empty
724 match f { Foo => () }
725}
726"#,
727 );
728 }
729
730 #[test]
731 fn record_struct_ellipsis() {
732 check_diagnostics_no_bails(
733 r#"struct Foo { foo: bool, bar: bool }
734fn main(f: Foo) {
735 match f { Foo { foo: true, .. } => () }
736 //^ error: missing match arm: `Foo { foo: false, .. }` not covered
737 match f {
738 //^ error: missing match arm: `Foo { foo: false, bar: true }` not covered
739 Foo { foo: true, .. } => (),
740 Foo { bar: false, .. } => ()
741 }
742 match f { Foo { .. } => () }
743 match f {
744 Foo { foo: true, .. } => (),
745 Foo { foo: false, .. } => ()
746 }
747}
748"#,
749 );
750 }
751
752 #[test]
753 fn internal_or() {
754 check_diagnostics_no_bails(
755 r#"
756fn main() {
757 enum Either { A(bool), B }
758 match Either::B {
759 //^^^^^^^^^ error: missing match arm: `B` not covered
760 Either::A(true | false) => (),
761 }
762}
763"#,
764 );
765 }
766
767 #[test]
768 fn no_panic_at_unimplemented_subpattern_type() {
769 cov_mark::check_count!(validate_match_bailed_out, 1);
770
771 check_diagnostics(
772 r#"
773struct S { a: char}
774fn main(v: S) {
775 match v { S{ a } => { _ = a; } }
776 match v { S{ a: _x } => {} }
777 match v { S{ a: 'a' } => {} }
778 match v { S{..} => {} }
779 match v { _ => {} }
780 match v { }
781 //^ error: missing match arm: type `S` is non-empty
782}
783"#,
784 );
785 }
786
787 #[test]
788 fn binding() {
789 check_diagnostics_no_bails(
790 r#"
791fn main() {
792 match true {
793 _x @ true => {}
794 false => {}
795 }
796 match true { _x @ true => {} }
797 //^^^^ error: missing match arm: `false` not covered
798}
799"#,
800 );
801 }
802
803 #[test]
804 fn binding_ref_has_correct_type() {
805 check_diagnostics_no_bails(
809 r#"
810enum Foo { A }
811fn main() {
812 match Foo::A {
813 ref _x => {}
814 Foo::A => {}
815 }
816 match (true,) {
817 (ref _x,) => {}
818 (true,) => {}
819 }
820}
821"#,
822 );
823 }
824
825 #[test]
826 fn enum_non_exhaustive() {
827 check_diagnostics_no_bails(
828 r#"
829//- /lib.rs crate:lib
830#[non_exhaustive]
831pub enum E { A, B }
832fn _local() {
833 match E::A { _ => {} }
834 match E::A {
835 E::A => {}
836 E::B => {}
837 }
838 match E::A {
839 E::A | E::B => {}
840 }
841}
842
843//- /main.rs crate:main deps:lib
844use lib::E;
845fn main() {
846 match E::A { _ => {} }
847 match E::A {
848 //^^^^ error: missing match arm: `_` not covered
849 E::A => {}
850 E::B => {}
851 }
852 match E::A {
853 //^^^^ error: missing match arm: `_` not covered
854 E::A | E::B => {}
855 }
856}
857"#,
858 );
859 }
860
861 #[test]
862 fn match_guard() {
863 check_diagnostics_no_bails(
864 r#"
865fn main() {
866 match true {
867 true if false => {}
868 true => {}
869 false => {}
870 }
871 match true {
872 //^^^^ error: missing match arm: `true` not covered
873 true if false => {}
874 false => {}
875 }
876}
877"#,
878 );
879 }
880
881 #[test]
882 fn pattern_type_is_of_substitution() {
883 check_diagnostics_no_bails(
884 r#"
885struct Foo<T>(T);
886struct Bar;
887fn main() {
888 match Foo(Bar) {
889 _ | Foo(Bar) => {}
890 }
891}
892"#,
893 );
894 }
895
896 #[test]
897 fn record_struct_no_such_field() {
898 cov_mark::check_count!(validate_match_bailed_out, 1);
899
900 check_diagnostics(
901 r#"
902struct Foo { }
903fn main(f: Foo) {
904 match f { Foo { bar } => () }
905 // ^^^ error: no such field
906}
907"#,
908 );
909 }
910
911 #[test]
912 fn match_ergonomics_issue_9095() {
913 check_diagnostics_no_bails(
914 r#"
915enum Foo<T> { A(T) }
916fn main() {
917 match &Foo::A(true) {
918 _ => {}
919 Foo::A(_) => {}
920 }
921}
922"#,
923 );
924 }
925
926 #[test]
927 fn normalize_field_ty() {
928 check_diagnostics_no_bails(
929 r"
930trait Trait { type Projection; }
931enum E {Foo, Bar}
932struct A;
933impl Trait for A { type Projection = E; }
934struct Next<T: Trait>(T::Projection);
935static __: () = {
936 let n: Next<A> = Next(E::Foo);
937 match n { Next(E::Foo) => {} }
938 // ^ error: missing match arm: `Next(Bar)` not covered
939 match n { Next(E::Foo | E::Bar) => {} }
940 match n { Next(E::Foo | _ ) => {} }
941 match n { Next(_ | E::Bar) => {} }
942 match n { _ | Next(E::Bar) => {} }
943 match &n { Next(E::Foo | E::Bar) => {} }
944 match &n { _ | Next(E::Bar) => {} }
945};",
946 );
947 }
948
949 #[test]
950 fn binding_mode_by_ref() {
951 check_diagnostics_no_bails(
952 r"
953enum E{ A, B }
954fn foo() {
955 match &E::A {
956 E::A => {}
957 _x => {}
958 }
959}",
960 );
961 }
962
963 #[test]
964 fn macro_or_pat() {
965 check_diagnostics_no_bails(
966 r#"
967macro_rules! m {
968 () => {
969 Enum::Type1 | Enum::Type2
970 };
971}
972
973enum Enum {
974 Type1,
975 Type2,
976 Type3,
977}
978
979fn f(ty: Enum) {
980 match ty {
981 //^^ error: missing match arm: `Type3` not covered
982 m!() => (),
983 }
984
985 match ty {
986 m!() | Enum::Type3 => ()
987 }
988}
989"#,
990 );
991 }
992
993 #[test]
994 fn unexpected_ty_fndef() {
995 cov_mark::check!(validate_match_bailed_out);
996 check_diagnostics_with_disabled(
997 r"
998enum Exp {
999 Tuple(()),
1000}
1001fn f() {
1002 match __unknown {
1003 Exp::Tuple => {}
1004 }
1005}",
1006 &["E0425"],
1007 );
1008 }
1009
1010 #[test]
1011 fn exponential_match() {
1012 if skip_slow_tests() {
1013 return;
1014 }
1015 use std::fmt::Write;
1017 let struct_arity = 50;
1018 let mut code = String::new();
1019 write!(code, "struct BigStruct {{").unwrap();
1020 for i in 0..struct_arity {
1021 write!(code, " field{i}: bool,").unwrap();
1022 }
1023 write!(code, "}}").unwrap();
1024 write!(code, "fn big_match(s: BigStruct) {{").unwrap();
1025 write!(code, " match s {{").unwrap();
1026 for i in 0..struct_arity {
1027 write!(code, " BigStruct {{ field{i}: true, ..}} => {{}},").unwrap();
1028 write!(code, " BigStruct {{ field{i}: false, ..}} => {{}},").unwrap();
1029 }
1030 write!(code, " _ => {{}},").unwrap();
1031 write!(code, " }}").unwrap();
1032 write!(code, "}}").unwrap();
1033 check_diagnostics_no_bails(&code);
1034 }
1035
1036 #[test]
1037 fn min_exhaustive() {
1038 check_diagnostics(
1039 r#"
1040//- minicore: result
1041fn test(x: Result<i32, !>) {
1042 match x {
1043 Ok(_y) => {}
1044 }
1045}
1046"#,
1047 );
1048 check_diagnostics(
1049 r#"
1050//- minicore: result
1051fn test(ptr: *const Result<i32, !>) {
1052 unsafe {
1053 match *ptr {
1054 //^^^^ error: missing match arm: `Err(!)` not covered
1055 Ok(_x) => {}
1056 }
1057 }
1058}
1059"#,
1060 );
1061 check_diagnostics(
1062 r#"
1063//- minicore: result
1064fn test(x: Result<i32, &'static !>) {
1065 match x {
1066 //^ error: missing match arm: `Err(_)` not covered
1067 Ok(_y) => {}
1068 }
1069}
1070"#,
1071 );
1072 }
1073
1074 mod rust_unstable {
1075 use super::*;
1076
1077 #[test]
1078 fn rfc_1872_exhaustive_patterns() {
1079 check_diagnostics_no_bails(
1080 r"
1081//- minicore: option, result
1082#![feature(exhaustive_patterns)]
1083enum Void {}
1084fn test() {
1085 match None::<!> { None => () }
1086 match Result::<u8, !>::Ok(2) { Ok(_) => () }
1087 match Result::<u8, Void>::Ok(2) { Ok(_) => () }
1088 match (2, loop {}) {}
1089 match Result::<!, !>::Ok(loop {}) {}
1090 match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919
1091 // ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty
1092}",
1093 );
1094 }
1095
1096 #[test]
1097 fn rfc_1872_private_uninhabitedness() {
1098 check_diagnostics_no_bails(
1099 r"
1100//- minicore: option
1101//- /lib.rs crate:lib
1102#![feature(exhaustive_patterns)]
1103pub struct PrivatelyUninhabited { private_field: Void }
1104enum Void {}
1105fn test_local(x: Option<PrivatelyUninhabited>) {
1106 match x {}
1107} // ^ error: missing match arm: `None` not covered
1108//- /main.rs crate:main deps:lib
1109#![feature(exhaustive_patterns)]
1110fn test(x: Option<lib::PrivatelyUninhabited>) {
1111 match x {}
1112 // ^ error: missing match arm: `None` and `Some(_)` not covered
1113}",
1114 );
1115 }
1116 }
1117
1118 #[test]
1119 fn non_exhaustive_may_be_empty() {
1120 check_diagnostics_no_bails(
1121 r"
1122//- /main.rs crate:main deps:dep
1123// In a different crate
1124fn empty_match_on_empty_struct<T>(x: dep::UninhabitedStruct) -> T {
1125 match x {}
1126}
1127//- /dep.rs crate:dep
1128#[non_exhaustive]
1129pub struct UninhabitedStruct {
1130 pub never: !,
1131 // other fields
1132}
1133",
1134 );
1135 }
1136
1137 mod false_negatives {
1138 use super::*;
1148
1149 #[test]
1150 fn integers() {
1151 cov_mark::check_count!(validate_match_bailed_out, 1);
1152
1153 check_diagnostics(
1155 r#"
1156fn main() {
1157 match 5 {
1158 10 => (),
1159 11..20 => (),
1160 }
1161}
1162"#,
1163 );
1164 }
1165
1166 #[test]
1167 fn reference_patterns_at_top_level() {
1168 cov_mark::check_count!(validate_match_bailed_out, 1);
1169
1170 check_diagnostics(
1171 r#"
1172//- minicore: copy
1173fn main() {
1174 match &false {
1175 &true => {}
1176 }
1177}
1178 "#,
1179 );
1180 }
1181
1182 #[test]
1183 fn reference_patterns_in_fields() {
1184 cov_mark::check_count!(validate_match_bailed_out, 1);
1185 check_diagnostics(
1186 r#"
1187//- minicore: copy
1188fn main() {
1189 match (&false,) {
1190 //^^^^^^^^^ error: missing match arm: `(&false,)` not covered
1191 (true,) => {}
1192 }
1193 match (&false,) {
1194 (&true,) => {}
1195 }
1196}
1197 "#,
1198 );
1199 }
1200 }
1201}