3 use crate::{Diagnostic, DiagnosticsContext};
5 // Diagnostic: missing-match-arm
7 // This diagnostic is triggered if `match` block is missing one or more match arms.
8 pub(crate) fn missing_match_arms(
9 ctx: &DiagnosticsContext<'_>,
10 d: &hir::MissingMatchArms,
15 ctx.sema.diagnostics_display_range(InFile::new(d.file, d.match_expr.clone().into())).range,
21 use crate::tests::check_diagnostics;
23 fn check_diagnostics_no_bails(ra_fixture: &str) {
24 cov_mark::check_count!(validate_match_bailed_out, 0);
25 crate::tests::check_diagnostics(ra_fixture)
30 check_diagnostics_no_bails(
34 //^^ error: missing match arm
36 //^^^^ error: missing match arm
39 match () { () => (), }
40 match (()) { (()) => (), }
47 fn tuple_of_two_empty_tuple() {
48 check_diagnostics_no_bails(
52 //^^^^^^^^ error: missing match arm
54 match ((), ()) { ((), ()) => (), }
62 check_diagnostics_no_bails(
66 //^^^^^ error: missing match arm
67 match false { true => (), }
68 //^^^^^ error: missing match arm
69 match (false, true) {}
70 //^^^^^^^^^^^^^ error: missing match arm
71 match (false, true) { (true, true) => (), }
72 //^^^^^^^^^^^^^ error: missing match arm
74 //^^^^^^^^^^^^^ error: missing match arm
79 match (false, true) { (true, _x) => (), }
80 //^^^^^^^^^^^^^ error: missing match arm
82 match false { true => (), false => (), }
99 match (false, true, false) {
103 match (false, true, false) {
107 match (false, true, false) { (..) => (), }
114 fn tuple_of_tuple_and_bools() {
115 check_diagnostics_no_bails(
118 match (false, ((), false)) {}
119 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
120 match (false, ((), false)) { (true, ((), true)) => (), }
121 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
122 match (false, ((), false)) { (true, _) => (), }
123 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
125 match (false, ((), false)) {
126 (true, ((), true)) => (),
127 (true, ((), false)) => (),
128 (false, ((), true)) => (),
129 (false, ((), false)) => (),
131 match (false, ((), false)) {
132 (true, ((), true)) => (),
133 (true, ((), false)) => (),
143 check_diagnostics_no_bails(
145 enum Either { A, B, }
149 //^^^^^^^^^ error: missing match arm
150 match Either::B { Either::A => (), }
151 //^^^^^^^^^ error: missing match arm
154 //^^^^^^^^^^ error: missing match arm
159 Either::A => (), Either::B => (),
162 Either::A => (), Either::B => (),
170 fn enum_containing_bool() {
171 check_diagnostics_no_bails(
173 enum Either { A(bool), B }
177 //^^^^^^^^^ error: missing match arm
179 //^^^^^^^^^ error: missing match arm
180 Either::A(true) => (), Either::B => ()
184 Either::A(true) => (),
185 Either::A(false) => (),
203 fn enum_different_sizes() {
204 check_diagnostics_no_bails(
206 enum Either { A(bool), B(bool, bool) }
209 match Either::A(false) {
210 //^^^^^^^^^^^^^^^^ error: missing match arm
212 Either::B(false, _) => (),
215 match Either::A(false) {
217 Either::B(true, _) => (),
218 Either::B(false, _) => (),
220 match Either::A(false) {
221 Either::A(true) | Either::A(false) => (),
222 Either::B(true, _) => (),
223 Either::B(false, _) => (),
231 fn tuple_of_enum_no_diagnostic() {
232 check_diagnostics_no_bails(
234 enum Either { A(bool), B(bool, bool) }
235 enum Either2 { C, D }
238 match (Either::A(false), Either2::C) {
239 (Either::A(true), _) | (Either::A(false), _) => (),
240 (Either::B(true, _), Either2::C) => (),
241 (Either::B(false, _), Either2::C) => (),
242 (Either::B(_, _), Either2::D) => (),
250 fn or_pattern_no_diagnostic() {
251 check_diagnostics_no_bails(
256 match (Either::A, Either::B) {
257 (Either::A | Either::B, _) => (),
264 fn mismatched_types() {
265 cov_mark::check_count!(validate_match_bailed_out, 4);
266 // Match statements with arms that don't match the
267 // expression pattern do not fire this diagnostic.
271 enum Either2 { C, D }
278 match (true, false) {
279 (true, false, true) => (),
282 match (true, false) { (true,) => {} }
283 match (0) { () => () }
284 match Unresolved::Bar { Unresolved::Baz => () }
291 fn mismatched_types_in_or_patterns() {
292 cov_mark::check_count!(validate_match_bailed_out, 2);
296 match false { true | () => {} }
297 match (false,) { (true | (),) => {} }
304 fn malformed_match_arm_tuple_enum_missing_pattern() {
305 // We are testing to be sure we don't panic here when the match
306 // arm `Either::B` is missing its pattern.
307 check_diagnostics_no_bails(
309 enum Either { A, B(u32) }
322 fn malformed_match_arm_extra_fields() {
323 cov_mark::check_count!(validate_match_bailed_out, 2);
326 enum A { B(isize, isize), C }
341 cov_mark::check_count!(validate_match_bailed_out, 2);
354 match loop { break Foo::A } {
355 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
358 match loop { break Foo::A } {
368 fn expr_partially_diverges() {
369 check_diagnostics_no_bails(
371 enum Either<T> { A(T), B }
373 fn foo() -> Either<!> { Either::B }
376 Either::A(val) => val,
386 check_diagnostics_no_bails(
388 enum Either { A { foo: bool }, B }
391 let a = Either::A { foo: true };
393 //^ error: missing match arm
394 match a { Either::A { foo: true } => () }
395 //^ error: missing match arm
398 //^^^^^^^^^ error: missing structure fields:
403 //^ error: missing match arm
405 } //^^^^^^^^^ error: missing structure fields:
409 Either::A { foo: true } => (),
410 Either::A { foo: false } => (),
414 Either::A { foo: _ } => (),
423 fn enum_record_fields_out_of_order() {
424 check_diagnostics_no_bails(
427 A { foo: bool, bar: () },
432 let a = Either::A { foo: true, bar: () };
434 //^ error: missing match arm
435 Either::A { bar: (), foo: false } => (),
436 Either::A { foo: true, bar: () } => (),
440 Either::A { bar: (), foo: false } => (),
441 Either::A { foo: true, bar: () } => (),
450 fn enum_record_ellipsis() {
451 check_diagnostics_no_bails(
454 A { foo: bool, bar: bool },
461 //^ error: missing match arm
462 Either::A { foo: true, .. } => (),
466 //^ error: missing match arm
467 Either::A { .. } => (),
471 Either::A { foo: true, .. } => (),
472 Either::A { foo: false, .. } => (),
477 Either::A { .. } => (),
486 fn enum_tuple_partial_ellipsis() {
487 check_diagnostics_no_bails(
490 A(bool, bool, bool, bool),
496 //^^^^^^^^^ error: missing match arm
497 Either::A(true, .., true) => (),
498 Either::A(true, .., false) => (),
499 Either::A(false, .., false) => (),
503 //^^^^^^^^^ error: missing match arm
504 Either::A(true, .., true) => (),
505 Either::A(true, .., false) => (),
506 Either::A(.., true) => (),
511 Either::A(true, .., true) => (),
512 Either::A(true, .., false) => (),
513 Either::A(false, .., true) => (),
514 Either::A(false, .., false) => (),
518 Either::A(true, .., true) => (),
519 Either::A(true, .., false) => (),
520 Either::A(.., true) => (),
521 Either::A(.., false) => (),
531 check_diagnostics_no_bails(
535 fn enum_(never: Never) {
538 fn enum_ref(never: &Never) {
540 //^^^^^ error: missing match arm
551 cov_mark::check_count!(validate_match_bailed_out, 1);
555 enum Option<T> { Some(T), None }
558 // `Never` is deliberately not defined so that it's an uninferred type.
559 match Option::<Never>::None {
561 Some(never) => match never {},
563 match Option::<Never>::None {
564 //^^^^^^^^^^^^^^^^^^^^^ error: missing match arm
565 Option::Some(_never) => {},
573 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
574 check_diagnostics_no_bails(
577 match (false, true, false) {
578 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
586 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
587 check_diagnostics_no_bails(
590 match (false, true, false) {
591 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
599 fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() {
600 check_diagnostics_no_bails(
603 match (false, true, false) {
604 //^^^^^^^^^^^^^^^^^^^^ error: missing match arm
605 (true, .., false) => (),
613 check_diagnostics_no_bails(
614 r#"struct Foo { a: bool }
617 //^ error: missing match arm
618 match f { Foo { a: true } => () }
619 //^ error: missing match arm
620 match &f { Foo { a: true } => () }
621 //^^ error: missing match arm
622 match f { Foo { a: _ } => () }
624 Foo { a: true } => (),
625 Foo { a: false } => (),
628 Foo { a: true } => (),
629 Foo { a: false } => (),
638 check_diagnostics_no_bails(
642 //^ error: missing match arm
643 match f { Foo(true) => () }
644 //^ error: missing match arm
656 check_diagnostics_no_bails(
660 //^ error: missing match arm
661 match f { Foo => () }
668 fn record_struct_ellipsis() {
669 check_diagnostics_no_bails(
670 r#"struct Foo { foo: bool, bar: bool }
672 match f { Foo { foo: true, .. } => () }
673 //^ error: missing match arm
675 //^ error: missing match arm
676 Foo { foo: true, .. } => (),
677 Foo { bar: false, .. } => ()
679 match f { Foo { .. } => () }
681 Foo { foo: true, .. } => (),
682 Foo { foo: false, .. } => ()
691 check_diagnostics_no_bails(
694 enum Either { A(bool), B }
696 //^^^^^^^^^ error: missing match arm
697 Either::A(true | false) => (),
705 fn no_panic_at_unimplemented_subpattern_type() {
706 cov_mark::check_count!(validate_match_bailed_out, 1);
712 match v { S{ a } => {} }
713 match v { S{ a: _x } => {} }
714 match v { S{ a: 'a' } => {} }
715 match v { S{..} => {} }
718 //^ error: missing match arm
726 check_diagnostics_no_bails(
733 match true { _x @ true => {} }
734 //^^^^ error: missing match arm
741 fn binding_ref_has_correct_type() {
742 cov_mark::check_count!(validate_match_bailed_out, 1);
744 // Asserts `PatKind::Binding(ref _x): bool`, not &bool.
745 // If that's not true match checking will panic with "incompatible constructors"
746 // FIXME: make facilities to test this directly like `tests::check_infer(..)`
751 // FIXME: this should not bail out but current behavior is such as the old algorithm.
752 // ExprValidator::validate_match(..) checks types of top level patterns incorrecly.
767 fn enum_non_exhaustive() {
768 check_diagnostics_no_bails(
770 //- /lib.rs crate:lib
774 match E::A { _ => {} }
784 //- /main.rs crate:main deps:lib
787 match E::A { _ => {} }
789 //^^^^ error: missing match arm
794 //^^^^ error: missing match arm
804 check_diagnostics_no_bails(
813 //^^^^ error: missing match arm
823 fn pattern_type_is_of_substitution() {
824 check_diagnostics_no_bails(
838 fn record_struct_no_such_field() {
839 cov_mark::check_count!(validate_match_bailed_out, 1);
845 match f { Foo { bar } => () }
852 fn match_ergonomics_issue_9095() {
853 check_diagnostics_no_bails(
857 match &Foo::A(true) {
867 fn normalize_field_ty() {
868 check_diagnostics_no_bails(
870 trait Trait { type Projection; }
873 impl Trait for A { type Projection = E; }
874 struct Next<T: Trait>(T::Projection);
876 let n: Next<A> = Next(E::Foo);
877 match n { Next(E::Foo) => {} }
878 // ^ error: missing match arm
879 match n { Next(E::Foo | E::Bar) => {} }
880 match n { Next(E::Foo | _ ) => {} }
881 match n { Next(_ | E::Bar) => {} }
882 match n { _ | Next(E::Bar) => {} }
883 match &n { Next(E::Foo | E::Bar) => {} }
884 match &n { _ | Next(E::Bar) => {} }
890 fn binding_mode_by_ref() {
891 check_diagnostics_no_bails(
905 check_diagnostics_no_bails(
909 Enum::Type1 | Enum::Type2
921 //^^ error: missing match arm
926 m!() | Enum::Type3 => ()
933 mod false_negatives {
934 //! The implementation of match checking here is a work in progress. As we roll this out, we
935 //! prefer false negatives to false positives (ideally there would be no false positives). This
936 //! test module should document known false negatives. Eventually we will have a complete
937 //! implementation of match checking and this module will be empty.
939 //! The reasons for documenting known false negatives:
941 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
942 //! 2. It ensures the code doesn't panic when handling these cases.
947 cov_mark::check_count!(validate_match_bailed_out, 1);
949 // We don't currently check integer exhaustiveness.
963 fn reference_patterns_at_top_level() {
964 cov_mark::check_count!(validate_match_bailed_out, 1);
978 fn reference_patterns_in_fields() {
979 cov_mark::check_count!(validate_match_bailed_out, 2);