]> git.proxmox.com Git - rustc.git/blame - src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_match_arms.rs
New upstream version 1.70.0+dfsg1
[rustc.git] / src / tools / rust-analyzer / crates / ide-diagnostics / src / handlers / missing_match_arms.rs
CommitLineData
064997fb
FG
1use crate::{Diagnostic, DiagnosticsContext};
2
3// Diagnostic: missing-match-arm
4//
5// This diagnostic is triggered if `match` block is missing one or more match arms.
6pub(crate) fn missing_match_arms(
7 ctx: &DiagnosticsContext<'_>,
8 d: &hir::MissingMatchArms,
9) -> Diagnostic {
10 Diagnostic::new(
11 "missing-match-arm",
12 format!("missing match arm: {}", d.uncovered_patterns),
353b0b11 13 ctx.sema.diagnostics_display_range(d.scrutinee_expr.clone().map(Into::into)).range,
064997fb
FG
14 )
15}
16
17#[cfg(test)]
18mod tests {
19 use crate::tests::check_diagnostics;
20
21 fn check_diagnostics_no_bails(ra_fixture: &str) {
22 cov_mark::check_count!(validate_match_bailed_out, 0);
23 crate::tests::check_diagnostics(ra_fixture)
24 }
25
26 #[test]
27 fn empty_tuple() {
28 check_diagnostics_no_bails(
29 r#"
30fn main() {
31 match () { }
32 //^^ error: missing match arm: type `()` is non-empty
33 match (()) { }
34 //^^^^ error: missing match arm: type `()` is non-empty
35
36 match () { _ => (), }
37 match () { () => (), }
38 match (()) { (()) => (), }
39}
40"#,
41 );
42 }
43
44 #[test]
45 fn tuple_of_two_empty_tuple() {
46 check_diagnostics_no_bails(
47 r#"
48fn main() {
49 match ((), ()) { }
50 //^^^^^^^^ error: missing match arm: type `((), ())` is non-empty
51
52 match ((), ()) { ((), ()) => (), }
53}
54"#,
55 );
56 }
57
58 #[test]
59 fn boolean() {
60 check_diagnostics_no_bails(
61 r#"
62fn test_main() {
63 match false { }
64 //^^^^^ error: missing match arm: type `bool` is non-empty
65 match false { true => (), }
66 //^^^^^ error: missing match arm: `false` not covered
67 match (false, true) {}
68 //^^^^^^^^^^^^^ error: missing match arm: type `(bool, bool)` is non-empty
69 match (false, true) { (true, true) => (), }
70 //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
71 match (false, true) {
72 //^^^^^^^^^^^^^ error: missing match arm: `(true, true)` not covered
73 (false, true) => (),
74 (false, false) => (),
75 (true, false) => (),
76 }
77 match (false, true) { (true, _x) => (), }
78 //^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
79
80 match false { true => (), false => (), }
81 match (false, true) {
82 (false, _) => (),
83 (true, false) => (),
84 (_, true) => (),
85 }
86 match (false, true) {
87 (true, true) => (),
88 (true, false) => (),
89 (false, true) => (),
90 (false, false) => (),
91 }
92 match (false, true) {
93 (true, _x) => (),
94 (false, true) => (),
95 (false, false) => (),
96 }
97 match (false, true, false) {
98 (false, ..) => (),
99 (true, ..) => (),
100 }
101 match (false, true, false) {
102 (.., false) => (),
103 (.., true) => (),
104 }
105 match (false, true, false) { (..) => (), }
106}
107"#,
108 );
109 }
110
111 #[test]
112 fn tuple_of_tuple_and_bools() {
113 check_diagnostics_no_bails(
114 r#"
115fn main() {
116 match (false, ((), false)) {}
117 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: type `(bool, ((), bool))` is non-empty
118 match (false, ((), false)) { (true, ((), true)) => (), }
119 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
120 match (false, ((), false)) { (true, _) => (), }
121 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _)` not covered
122
123 match (false, ((), false)) {
124 (true, ((), true)) => (),
125 (true, ((), false)) => (),
126 (false, ((), true)) => (),
127 (false, ((), false)) => (),
128 }
129 match (false, ((), false)) {
130 (true, ((), true)) => (),
131 (true, ((), false)) => (),
132 (false, _) => (),
133 }
134}
135"#,
136 );
137 }
138
139 #[test]
140 fn enums() {
141 check_diagnostics_no_bails(
142 r#"
143enum Either { A, B, }
144
145fn main() {
146 match Either::A { }
147 //^^^^^^^^^ error: missing match arm: `A` and `B` not covered
148 match Either::B { Either::A => (), }
149 //^^^^^^^^^ error: missing match arm: `B` not covered
150
151 match &Either::B {
152 //^^^^^^^^^^ error: missing match arm: `&B` not covered
153 Either::A => (),
154 }
155
156 match Either::B {
157 Either::A => (), Either::B => (),
158 }
159 match &Either::B {
160 Either::A => (), Either::B => (),
161 }
162}
163"#,
164 );
165 }
166
167 #[test]
168 fn enum_containing_bool() {
169 check_diagnostics_no_bails(
170 r#"
171enum Either { A(bool), B }
172
173fn main() {
174 match Either::B { }
175 //^^^^^^^^^ error: missing match arm: `A(_)` and `B` not covered
176 match Either::B {
177 //^^^^^^^^^ error: missing match arm: `A(false)` not covered
178 Either::A(true) => (), Either::B => ()
179 }
180
181 match Either::B {
182 Either::A(true) => (),
183 Either::A(false) => (),
184 Either::B => (),
185 }
186 match Either::B {
187 Either::B => (),
188 _ => (),
189 }
190 match Either::B {
191 Either::A(_) => (),
192 Either::B => (),
193 }
194
195}
196 "#,
197 );
198 }
199
200 #[test]
201 fn enum_different_sizes() {
202 check_diagnostics_no_bails(
203 r#"
204enum Either { A(bool), B(bool, bool) }
205
206fn main() {
207 match Either::A(false) {
208 //^^^^^^^^^^^^^^^^ error: missing match arm: `B(true, _)` not covered
209 Either::A(_) => (),
210 Either::B(false, _) => (),
211 }
212
213 match Either::A(false) {
214 Either::A(_) => (),
215 Either::B(true, _) => (),
216 Either::B(false, _) => (),
217 }
218 match Either::A(false) {
219 Either::A(true) | Either::A(false) => (),
220 Either::B(true, _) => (),
221 Either::B(false, _) => (),
222 }
223}
224"#,
225 );
226 }
227
228 #[test]
229 fn tuple_of_enum_no_diagnostic() {
230 check_diagnostics_no_bails(
231 r#"
232enum Either { A(bool), B(bool, bool) }
233enum Either2 { C, D }
234
235fn main() {
236 match (Either::A(false), Either2::C) {
237 (Either::A(true), _) | (Either::A(false), _) => (),
238 (Either::B(true, _), Either2::C) => (),
239 (Either::B(false, _), Either2::C) => (),
240 (Either::B(_, _), Either2::D) => (),
241 }
242}
243"#,
244 );
245 }
246
247 #[test]
248 fn or_pattern_no_diagnostic() {
249 check_diagnostics_no_bails(
250 r#"
251enum Either {A, B}
252
253fn main() {
254 match (Either::A, Either::B) {
255 (Either::A | Either::B, _) => (),
256 }
257}"#,
258 )
259 }
260
261 #[test]
262 fn mismatched_types() {
263 cov_mark::check_count!(validate_match_bailed_out, 4);
264 // Match statements with arms that don't match the
265 // expression pattern do not fire this diagnostic.
266 check_diagnostics(
267 r#"
268enum Either { A, B }
269enum Either2 { C, D }
270
271fn main() {
272 match Either::A {
273 Either2::C => (),
274 Either2::D => (),
275 }
276 match (true, false) {
277 (true, false, true) => (),
278 (true) => (),
279 // ^^^^ error: expected (bool, bool), found bool
280 }
281 match (true, false) { (true,) => {} }
282 match (0) { () => () }
283 match Unresolved::Bar { Unresolved::Baz => () }
284}
285 "#,
286 );
287 }
288
289 #[test]
290 fn mismatched_types_in_or_patterns() {
291 cov_mark::check_count!(validate_match_bailed_out, 2);
292 check_diagnostics(
293 r#"
294fn main() {
295 match false { true | () => {} }
296 match (false,) { (true | (),) => {} }
297}
298"#,
299 );
300 }
301
302 #[test]
303 fn malformed_match_arm_tuple_enum_missing_pattern() {
304 // We are testing to be sure we don't panic here when the match
305 // arm `Either::B` is missing its pattern.
306 check_diagnostics_no_bails(
307 r#"
308enum Either { A, B(u32) }
309
310fn main() {
311 match Either::A {
312 Either::A => (),
313 Either::B() => (),
314 }
315}
316"#,
317 );
318 }
319
320 #[test]
321 fn malformed_match_arm_extra_fields() {
322 cov_mark::check_count!(validate_match_bailed_out, 2);
323 check_diagnostics(
324 r#"
325enum A { B(isize, isize), C }
326fn main() {
327 match A::B(1, 2) {
328 A::B(_, _, _) => (),
329 }
330 match A::B(1, 2) {
331 A::C(_) => (),
332 }
333}
334"#,
335 );
336 }
337
338 #[test]
339 fn expr_diverges() {
340 cov_mark::check_count!(validate_match_bailed_out, 2);
341 check_diagnostics(
342 r#"
343enum Either { A, B }
344
345fn main() {
346 match loop {} {
347 Either::A => (),
348 Either::B => (),
349 }
350 match loop {} {
351 Either::A => (),
352 }
353 match loop { break Foo::A } {
354 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `B` not covered
355 Either::A => (),
356 }
357 match loop { break Foo::A } {
358 Either::A => (),
359 Either::B => (),
360 }
361}
362"#,
363 );
364 }
365
366 #[test]
367 fn expr_partially_diverges() {
368 check_diagnostics_no_bails(
369 r#"
370enum Either<T> { A(T), B }
371
372fn foo() -> Either<!> { Either::B }
373fn main() -> u32 {
374 match foo() {
375 Either::A(val) => val,
376 Either::B => 0,
377 }
378}
379"#,
380 );
381 }
382
383 #[test]
384 fn enum_record() {
385 check_diagnostics_no_bails(
386 r#"
387enum Either { A { foo: bool }, B }
388
389fn main() {
390 let a = Either::A { foo: true };
391 match a { }
392 //^ error: missing match arm: `A { .. }` and `B` not covered
393 match a { Either::A { foo: true } => () }
394 //^ error: missing match arm: `B` not covered
395 match a {
396 Either::A { } => (),
397 //^^^^^^^^^ 💡 error: missing structure fields:
398 // | - foo
399 Either::B => (),
400 }
401 match a {
402 //^ error: missing match arm: `B` not covered
403 Either::A { } => (),
404 } //^^^^^^^^^ 💡 error: missing structure fields:
405 // | - foo
406
407 match a {
408 Either::A { foo: true } => (),
409 Either::A { foo: false } => (),
410 Either::B => (),
411 }
412 match a {
413 Either::A { foo: _ } => (),
414 Either::B => (),
415 }
416}
417"#,
418 );
419 }
420
421 #[test]
422 fn enum_record_fields_out_of_order() {
423 check_diagnostics_no_bails(
424 r#"
425enum Either {
426 A { foo: bool, bar: () },
427 B,
428}
429
430fn main() {
431 let a = Either::A { foo: true, bar: () };
432 match a {
433 //^ error: missing match arm: `B` not covered
434 Either::A { bar: (), foo: false } => (),
435 Either::A { foo: true, bar: () } => (),
436 }
437
438 match a {
439 Either::A { bar: (), foo: false } => (),
440 Either::A { foo: true, bar: () } => (),
441 Either::B => (),
442 }
443}
444"#,
445 );
446 }
447
448 #[test]
449 fn enum_record_ellipsis() {
450 check_diagnostics_no_bails(
451 r#"
452enum Either {
453 A { foo: bool, bar: bool },
454 B,
455}
456
457fn main() {
458 let a = Either::B;
459 match a {
460 //^ error: missing match arm: `A { foo: false, .. }` not covered
461 Either::A { foo: true, .. } => (),
462 Either::B => (),
463 }
464 match a {
465 //^ error: missing match arm: `B` not covered
466 Either::A { .. } => (),
467 }
468
469 match a {
470 Either::A { foo: true, .. } => (),
471 Either::A { foo: false, .. } => (),
472 Either::B => (),
473 }
474
475 match a {
476 Either::A { .. } => (),
477 Either::B => (),
478 }
479}
480"#,
481 );
482 }
483
484 #[test]
485 fn enum_tuple_partial_ellipsis() {
486 check_diagnostics_no_bails(
487 r#"
488enum Either {
489 A(bool, bool, bool, bool),
490 B,
491}
492
493fn main() {
494 match Either::B {
495 //^^^^^^^^^ error: missing match arm: `A(false, _, _, true)` not covered
496 Either::A(true, .., true) => (),
497 Either::A(true, .., false) => (),
498 Either::A(false, .., false) => (),
499 Either::B => (),
500 }
501 match Either::B {
502 //^^^^^^^^^ error: missing match arm: `A(false, _, _, false)` not covered
503 Either::A(true, .., true) => (),
504 Either::A(true, .., false) => (),
505 Either::A(.., true) => (),
506 Either::B => (),
507 }
508
509 match Either::B {
510 Either::A(true, .., true) => (),
511 Either::A(true, .., false) => (),
512 Either::A(false, .., true) => (),
513 Either::A(false, .., false) => (),
514 Either::B => (),
515 }
516 match Either::B {
517 Either::A(true, .., true) => (),
518 Either::A(true, .., false) => (),
519 Either::A(.., true) => (),
520 Either::A(.., false) => (),
521 Either::B => (),
522 }
523}
524"#,
525 );
526 }
527
528 #[test]
529 fn never() {
530 check_diagnostics_no_bails(
531 r#"
532enum Never {}
533
534fn enum_(never: Never) {
535 match never {}
536}
537fn enum_ref(never: &Never) {
538 match never {}
539 //^^^^^ error: missing match arm: type `&Never` is non-empty
540}
541fn bang(never: !) {
542 match never {}
543}
544"#,
545 );
546 }
547
548 #[test]
549 fn unknown_type() {
550 cov_mark::check_count!(validate_match_bailed_out, 1);
551
552 check_diagnostics(
553 r#"
554enum Option<T> { Some(T), None }
555
556fn main() {
557 // `Never` is deliberately not defined so that it's an uninferred type.
558 match Option::<Never>::None {
559 None => (),
560 Some(never) => match never {},
561 }
562 match Option::<Never>::None {
563 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `None` not covered
564 Option::Some(_never) => {},
565 }
566}
567"#,
568 );
569 }
570
571 #[test]
572 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
573 check_diagnostics_no_bails(
574 r#"
575fn main() {
576 match (false, true, false) {
577 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(true, _, _)` not covered
578 (false, ..) => (),
579 }
580}"#,
581 );
582 }
583
584 #[test]
585 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
586 check_diagnostics_no_bails(
587 r#"
588fn main() {
589 match (false, true, false) {
590 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(_, _, true)` not covered
591 (.., false) => (),
592 }
593}"#,
594 );
595 }
596
597 #[test]
598 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
599 check_diagnostics_no_bails(
600 r#"
601fn main() {
602 match (false, true, false) {
603 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm: `(false, _, _)` not covered
604 (true, .., false) => (),
605 }
606}"#,
607 );
608 }
609
610 #[test]
611 fn record_struct() {
612 check_diagnostics_no_bails(
613 r#"struct Foo { a: bool }
614fn main(f: Foo) {
615 match f {}
616 //^ error: missing match arm: type `Foo` is non-empty
617 match f { Foo { a: true } => () }
618 //^ error: missing match arm: `Foo { a: false }` not covered
619 match &f { Foo { a: true } => () }
620 //^^ error: missing match arm: `&Foo { a: false }` not covered
621 match f { Foo { a: _ } => () }
622 match f {
623 Foo { a: true } => (),
624 Foo { a: false } => (),
625 }
626 match &f {
627 Foo { a: true } => (),
628 Foo { a: false } => (),
629 }
630}
631"#,
632 );
633 }
634
635 #[test]
636 fn tuple_struct() {
637 check_diagnostics_no_bails(
638 r#"struct Foo(bool);
639fn main(f: Foo) {
640 match f {}
641 //^ error: missing match arm: type `Foo` is non-empty
642 match f { Foo(true) => () }
643 //^ error: missing match arm: `Foo(false)` not covered
644 match f {
645 Foo(true) => (),
646 Foo(false) => (),
647 }
648}
649"#,
650 );
651 }
652
653 #[test]
654 fn unit_struct() {
655 check_diagnostics_no_bails(
656 r#"struct Foo;
657fn main(f: Foo) {
658 match f {}
659 //^ error: missing match arm: type `Foo` is non-empty
660 match f { Foo => () }
661}
662"#,
663 );
664 }
665
666 #[test]
667 fn record_struct_ellipsis() {
668 check_diagnostics_no_bails(
669 r#"struct Foo { foo: bool, bar: bool }
670fn main(f: Foo) {
671 match f { Foo { foo: true, .. } => () }
672 //^ error: missing match arm: `Foo { foo: false, .. }` not covered
673 match f {
674 //^ error: missing match arm: `Foo { foo: false, bar: true }` not covered
675 Foo { foo: true, .. } => (),
676 Foo { bar: false, .. } => ()
677 }
678 match f { Foo { .. } => () }
679 match f {
680 Foo { foo: true, .. } => (),
681 Foo { foo: false, .. } => ()
682 }
683}
684"#,
685 );
686 }
687
688 #[test]
689 fn internal_or() {
690 check_diagnostics_no_bails(
691 r#"
692fn main() {
693 enum Either { A(bool), B }
694 match Either::B {
695 //^^^^^^^^^ error: missing match arm: `B` not covered
696 Either::A(true | false) => (),
697 }
698}
699"#,
700 );
701 }
702
703 #[test]
704 fn no_panic_at_unimplemented_subpattern_type() {
705 cov_mark::check_count!(validate_match_bailed_out, 1);
706
707 check_diagnostics(
708 r#"
709struct S { a: char}
710fn main(v: S) {
711 match v { S{ a } => {} }
712 match v { S{ a: _x } => {} }
713 match v { S{ a: 'a' } => {} }
714 match v { S{..} => {} }
715 match v { _ => {} }
716 match v { }
717 //^ error: missing match arm: type `S` is non-empty
718}
719"#,
720 );
721 }
722
723 #[test]
724 fn binding() {
725 check_diagnostics_no_bails(
726 r#"
727fn main() {
728 match true {
729 _x @ true => {}
730 false => {}
731 }
732 match true { _x @ true => {} }
733 //^^^^ error: missing match arm: `false` not covered
734}
735"#,
736 );
737 }
738
739 #[test]
740 fn binding_ref_has_correct_type() {
741 cov_mark::check_count!(validate_match_bailed_out, 1);
742
743 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
744 // If that's not true match checking will panic with "incompatible constructors"
745 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
746 check_diagnostics(
747 r#"
748enum Foo { A }
749fn main() {
750 // FIXME: this should not bail out but current behavior is such as the old algorithm.
f2b60f7d 751 // ExprValidator::validate_match(..) checks types of top level patterns incorrectly.
064997fb
FG
752 match Foo::A {
753 ref _x => {}
754 Foo::A => {}
755 }
756 match (true,) {
757 (ref _x,) => {}
758 (true,) => {}
759 }
760}
761"#,
762 );
763 }
764
765 #[test]
766 fn enum_non_exhaustive() {
767 check_diagnostics_no_bails(
768 r#"
769//- /lib.rs crate:lib
770#[non_exhaustive]
771pub enum E { A, B }
772fn _local() {
773 match E::A { _ => {} }
774 match E::A {
775 E::A => {}
776 E::B => {}
777 }
778 match E::A {
779 E::A | E::B => {}
780 }
781}
782
783//- /main.rs crate:main deps:lib
784use lib::E;
785fn main() {
786 match E::A { _ => {} }
787 match E::A {
788 //^^^^ error: missing match arm: `_` not covered
789 E::A => {}
790 E::B => {}
791 }
792 match E::A {
793 //^^^^ error: missing match arm: `_` not covered
794 E::A | E::B => {}
795 }
796}
797"#,
798 );
799 }
800
801 #[test]
802 fn match_guard() {
803 check_diagnostics_no_bails(
804 r#"
805fn main() {
806 match true {
807 true if false => {}
808 true => {}
809 false => {}
810 }
811 match true {
812 //^^^^ error: missing match arm: `true` not covered
813 true if false => {}
814 false => {}
815 }
816}
817"#,
818 );
819 }
820
821 #[test]
822 fn pattern_type_is_of_substitution() {
823 check_diagnostics_no_bails(
824 r#"
825struct Foo<T>(T);
826struct Bar;
827fn main() {
828 match Foo(Bar) {
829 _ | Foo(Bar) => {}
830 }
831}
832"#,
833 );
834 }
835
836 #[test]
837 fn record_struct_no_such_field() {
838 cov_mark::check_count!(validate_match_bailed_out, 1);
839
840 check_diagnostics(
841 r#"
842struct Foo { }
843fn main(f: Foo) {
844 match f { Foo { bar } => () }
845}
846"#,
847 );
848 }
849
850 #[test]
851 fn match_ergonomics_issue_9095() {
852 check_diagnostics_no_bails(
853 r#"
854enum Foo<T> { A(T) }
855fn main() {
856 match &Foo::A(true) {
857 _ => {}
858 Foo::A(_) => {}
859 }
860}
861"#,
862 );
863 }
864
865 #[test]
866 fn normalize_field_ty() {
867 check_diagnostics_no_bails(
868 r"
869trait Trait { type Projection; }
870enum E {Foo, Bar}
871struct A;
872impl Trait for A { type Projection = E; }
873struct Next<T: Trait>(T::Projection);
874static __: () = {
875 let n: Next<A> = Next(E::Foo);
876 match n { Next(E::Foo) => {} }
877 // ^ error: missing match arm: `Next(Bar)` not covered
878 match n { Next(E::Foo | E::Bar) => {} }
879 match n { Next(E::Foo | _ ) => {} }
880 match n { Next(_ | E::Bar) => {} }
881 match n { _ | Next(E::Bar) => {} }
882 match &n { Next(E::Foo | E::Bar) => {} }
883 match &n { _ | Next(E::Bar) => {} }
884};",
885 );
886 }
887
888 #[test]
889 fn binding_mode_by_ref() {
890 check_diagnostics_no_bails(
891 r"
892enum E{ A, B }
893fn foo() {
894 match &E::A {
895 E::A => {}
896 x => {}
897 }
898}",
899 );
900 }
901
902 #[test]
903 fn macro_or_pat() {
904 check_diagnostics_no_bails(
905 r#"
906macro_rules! m {
907 () => {
908 Enum::Type1 | Enum::Type2
909 };
910}
911
912enum Enum {
913 Type1,
914 Type2,
915 Type3,
916}
917
918fn f(ty: Enum) {
919 match ty {
920 //^^ error: missing match arm: `Type3` not covered
921 m!() => (),
922 }
923
924 match ty {
925 m!() | Enum::Type3 => ()
926 }
927}
928"#,
929 );
930 }
931
932 #[test]
933 fn unexpected_ty_fndef() {
934 cov_mark::check!(validate_match_bailed_out);
935 check_diagnostics(
936 r"
937enum Exp {
938 Tuple(()),
939}
940fn f() {
941 match __unknown {
942 Exp::Tuple => {}
943 }
944}",
945 );
946 }
947
f2b60f7d
FG
948 mod rust_unstable {
949 use super::*;
950
951 #[test]
952 fn rfc_1872_exhaustive_patterns() {
953 check_diagnostics_no_bails(
954 r"
955//- minicore: option, result
956#![feature(exhaustive_patterns)]
957enum Void {}
958fn test() {
959 match None::<!> { None => () }
960 match Result::<u8, !>::Ok(2) { Ok(_) => () }
961 match Result::<u8, Void>::Ok(2) { Ok(_) => () }
962 match (2, loop {}) {}
963 match Result::<!, !>::Ok(loop {}) {}
964 match (&loop {}) {} // https://github.com/rust-lang/rust/issues/50642#issuecomment-388234919
965 // ^^^^^^^^^^ error: missing match arm: type `&!` is non-empty
966}",
967 );
968 }
969
970 #[test]
971 fn rfc_1872_private_uninhabitedness() {
972 check_diagnostics_no_bails(
973 r"
974//- minicore: option
975//- /lib.rs crate:lib
976#![feature(exhaustive_patterns)]
977pub struct PrivatelyUninhabited { private_field: Void }
978enum Void {}
979fn test_local(x: Option<PrivatelyUninhabited>) {
980 match x {}
981} // ^ error: missing match arm: `None` not covered
982//- /main.rs crate:main deps:lib
983#![feature(exhaustive_patterns)]
984fn test(x: Option<lib::PrivatelyUninhabited>) {
985 match x {}
986 // ^ error: missing match arm: `None` and `Some(_)` not covered
987}",
988 );
989 }
990 }
991
064997fb
FG
992 mod false_negatives {
993 //! The implementation of match checking here is a work in progress. As we roll this out, we
994 //! prefer false negatives to false positives (ideally there would be no false positives). This
995 //! test module should document known false negatives. Eventually we will have a complete
996 //! implementation of match checking and this module will be empty.
997 //!
998 //! The reasons for documenting known false negatives:
999 //!
1000 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
1001 //! 2. It ensures the code doesn't panic when handling these cases.
1002 use super::*;
1003
1004 #[test]
1005 fn integers() {
1006 cov_mark::check_count!(validate_match_bailed_out, 1);
1007
1008 // We don't currently check integer exhaustiveness.
1009 check_diagnostics(
1010 r#"
1011fn main() {
1012 match 5 {
1013 10 => (),
1014 11..20 => (),
1015 }
1016}
1017"#,
1018 );
1019 }
1020
1021 #[test]
1022 fn reference_patterns_at_top_level() {
1023 cov_mark::check_count!(validate_match_bailed_out, 1);
1024
1025 check_diagnostics(
1026 r#"
1027fn main() {
1028 match &false {
1029 &true => {}
1030 }
1031}
1032 "#,
1033 );
1034 }
1035
1036 #[test]
1037 fn reference_patterns_in_fields() {
1038 cov_mark::check_count!(validate_match_bailed_out, 2);
064997fb
FG
1039 check_diagnostics(
1040 r#"
1041fn main() {
1042 match (&false,) {
1043 (true,) => {}
1044 }
1045 match (&false,) {
1046 (&true,) => {}
1047 }
1048}
1049 "#,
1050 );
1051 }
1052 }
1053}