diff options
Diffstat (limited to 'crates/ide/src/diagnostics.rs')
-rw-r--r-- | crates/ide/src/diagnostics.rs | 909 |
1 files changed, 2 insertions, 907 deletions
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs index 7978c1fc2..01b68232e 100644 --- a/crates/ide/src/diagnostics.rs +++ b/crates/ide/src/diagnostics.rs | |||
@@ -10,6 +10,7 @@ mod incorrect_case; | |||
10 | mod macro_error; | 10 | mod macro_error; |
11 | mod mismatched_arg_count; | 11 | mod mismatched_arg_count; |
12 | mod missing_fields; | 12 | mod missing_fields; |
13 | mod missing_match_arms; | ||
13 | mod missing_ok_or_some_in_tail_expr; | 14 | mod missing_ok_or_some_in_tail_expr; |
14 | mod missing_unsafe; | 15 | mod missing_unsafe; |
15 | mod no_such_field; | 16 | mod no_such_field; |
@@ -205,6 +206,7 @@ pub(crate) fn diagnostics( | |||
205 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), | 206 | AnyDiagnostic::MacroError(d) => macro_error::macro_error(&ctx, &d), |
206 | AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), | 207 | AnyDiagnostic::MismatchedArgCount(d) => mismatched_arg_count::mismatched_arg_count(&ctx, &d), |
207 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), | 208 | AnyDiagnostic::MissingFields(d) => missing_fields::missing_fields(&ctx, &d), |
209 | AnyDiagnostic::MissingMatchArms(d) => missing_match_arms::missing_match_arms(&ctx, &d), | ||
208 | AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d), | 210 | AnyDiagnostic::MissingOkOrSomeInTailExpr(d) => missing_ok_or_some_in_tail_expr::missing_ok_or_some_in_tail_expr(&ctx, &d), |
209 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), | 211 | AnyDiagnostic::MissingUnsafe(d) => missing_unsafe::missing_unsafe(&ctx, &d), |
210 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), | 212 | AnyDiagnostic::NoSuchField(d) => no_such_field::no_such_field(&ctx, &d), |
@@ -545,910 +547,3 @@ pub struct Claims { | |||
545 | ); | 547 | ); |
546 | } | 548 | } |
547 | } | 549 | } |
548 | |||
549 | #[cfg(test)] | ||
550 | pub(super) mod match_check_tests { | ||
551 | use crate::diagnostics::tests::check_diagnostics; | ||
552 | |||
553 | #[test] | ||
554 | fn empty_tuple() { | ||
555 | check_diagnostics( | ||
556 | r#" | ||
557 | fn main() { | ||
558 | match () { } | ||
559 | //^^ Missing match arm | ||
560 | match (()) { } | ||
561 | //^^^^ Missing match arm | ||
562 | |||
563 | match () { _ => (), } | ||
564 | match () { () => (), } | ||
565 | match (()) { (()) => (), } | ||
566 | } | ||
567 | "#, | ||
568 | ); | ||
569 | } | ||
570 | |||
571 | #[test] | ||
572 | fn tuple_of_two_empty_tuple() { | ||
573 | check_diagnostics( | ||
574 | r#" | ||
575 | fn main() { | ||
576 | match ((), ()) { } | ||
577 | //^^^^^^^^ Missing match arm | ||
578 | |||
579 | match ((), ()) { ((), ()) => (), } | ||
580 | } | ||
581 | "#, | ||
582 | ); | ||
583 | } | ||
584 | |||
585 | #[test] | ||
586 | fn boolean() { | ||
587 | check_diagnostics( | ||
588 | r#" | ||
589 | fn test_main() { | ||
590 | match false { } | ||
591 | //^^^^^ Missing match arm | ||
592 | match false { true => (), } | ||
593 | //^^^^^ Missing match arm | ||
594 | match (false, true) {} | ||
595 | //^^^^^^^^^^^^^ Missing match arm | ||
596 | match (false, true) { (true, true) => (), } | ||
597 | //^^^^^^^^^^^^^ Missing match arm | ||
598 | match (false, true) { | ||
599 | //^^^^^^^^^^^^^ Missing match arm | ||
600 | (false, true) => (), | ||
601 | (false, false) => (), | ||
602 | (true, false) => (), | ||
603 | } | ||
604 | match (false, true) { (true, _x) => (), } | ||
605 | //^^^^^^^^^^^^^ Missing match arm | ||
606 | |||
607 | match false { true => (), false => (), } | ||
608 | match (false, true) { | ||
609 | (false, _) => (), | ||
610 | (true, false) => (), | ||
611 | (_, true) => (), | ||
612 | } | ||
613 | match (false, true) { | ||
614 | (true, true) => (), | ||
615 | (true, false) => (), | ||
616 | (false, true) => (), | ||
617 | (false, false) => (), | ||
618 | } | ||
619 | match (false, true) { | ||
620 | (true, _x) => (), | ||
621 | (false, true) => (), | ||
622 | (false, false) => (), | ||
623 | } | ||
624 | match (false, true, false) { | ||
625 | (false, ..) => (), | ||
626 | (true, ..) => (), | ||
627 | } | ||
628 | match (false, true, false) { | ||
629 | (.., false) => (), | ||
630 | (.., true) => (), | ||
631 | } | ||
632 | match (false, true, false) { (..) => (), } | ||
633 | } | ||
634 | "#, | ||
635 | ); | ||
636 | } | ||
637 | |||
638 | #[test] | ||
639 | fn tuple_of_tuple_and_bools() { | ||
640 | check_diagnostics( | ||
641 | r#" | ||
642 | fn main() { | ||
643 | match (false, ((), false)) {} | ||
644 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
645 | match (false, ((), false)) { (true, ((), true)) => (), } | ||
646 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
647 | match (false, ((), false)) { (true, _) => (), } | ||
648 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
649 | |||
650 | match (false, ((), false)) { | ||
651 | (true, ((), true)) => (), | ||
652 | (true, ((), false)) => (), | ||
653 | (false, ((), true)) => (), | ||
654 | (false, ((), false)) => (), | ||
655 | } | ||
656 | match (false, ((), false)) { | ||
657 | (true, ((), true)) => (), | ||
658 | (true, ((), false)) => (), | ||
659 | (false, _) => (), | ||
660 | } | ||
661 | } | ||
662 | "#, | ||
663 | ); | ||
664 | } | ||
665 | |||
666 | #[test] | ||
667 | fn enums() { | ||
668 | check_diagnostics( | ||
669 | r#" | ||
670 | enum Either { A, B, } | ||
671 | |||
672 | fn main() { | ||
673 | match Either::A { } | ||
674 | //^^^^^^^^^ Missing match arm | ||
675 | match Either::B { Either::A => (), } | ||
676 | //^^^^^^^^^ Missing match arm | ||
677 | |||
678 | match &Either::B { | ||
679 | //^^^^^^^^^^ Missing match arm | ||
680 | Either::A => (), | ||
681 | } | ||
682 | |||
683 | match Either::B { | ||
684 | Either::A => (), Either::B => (), | ||
685 | } | ||
686 | match &Either::B { | ||
687 | Either::A => (), Either::B => (), | ||
688 | } | ||
689 | } | ||
690 | "#, | ||
691 | ); | ||
692 | } | ||
693 | |||
694 | #[test] | ||
695 | fn enum_containing_bool() { | ||
696 | check_diagnostics( | ||
697 | r#" | ||
698 | enum Either { A(bool), B } | ||
699 | |||
700 | fn main() { | ||
701 | match Either::B { } | ||
702 | //^^^^^^^^^ Missing match arm | ||
703 | match Either::B { | ||
704 | //^^^^^^^^^ Missing match arm | ||
705 | Either::A(true) => (), Either::B => () | ||
706 | } | ||
707 | |||
708 | match Either::B { | ||
709 | Either::A(true) => (), | ||
710 | Either::A(false) => (), | ||
711 | Either::B => (), | ||
712 | } | ||
713 | match Either::B { | ||
714 | Either::B => (), | ||
715 | _ => (), | ||
716 | } | ||
717 | match Either::B { | ||
718 | Either::A(_) => (), | ||
719 | Either::B => (), | ||
720 | } | ||
721 | |||
722 | } | ||
723 | "#, | ||
724 | ); | ||
725 | } | ||
726 | |||
727 | #[test] | ||
728 | fn enum_different_sizes() { | ||
729 | check_diagnostics( | ||
730 | r#" | ||
731 | enum Either { A(bool), B(bool, bool) } | ||
732 | |||
733 | fn main() { | ||
734 | match Either::A(false) { | ||
735 | //^^^^^^^^^^^^^^^^ Missing match arm | ||
736 | Either::A(_) => (), | ||
737 | Either::B(false, _) => (), | ||
738 | } | ||
739 | |||
740 | match Either::A(false) { | ||
741 | Either::A(_) => (), | ||
742 | Either::B(true, _) => (), | ||
743 | Either::B(false, _) => (), | ||
744 | } | ||
745 | match Either::A(false) { | ||
746 | Either::A(true) | Either::A(false) => (), | ||
747 | Either::B(true, _) => (), | ||
748 | Either::B(false, _) => (), | ||
749 | } | ||
750 | } | ||
751 | "#, | ||
752 | ); | ||
753 | } | ||
754 | |||
755 | #[test] | ||
756 | fn tuple_of_enum_no_diagnostic() { | ||
757 | check_diagnostics( | ||
758 | r#" | ||
759 | enum Either { A(bool), B(bool, bool) } | ||
760 | enum Either2 { C, D } | ||
761 | |||
762 | fn main() { | ||
763 | match (Either::A(false), Either2::C) { | ||
764 | (Either::A(true), _) | (Either::A(false), _) => (), | ||
765 | (Either::B(true, _), Either2::C) => (), | ||
766 | (Either::B(false, _), Either2::C) => (), | ||
767 | (Either::B(_, _), Either2::D) => (), | ||
768 | } | ||
769 | } | ||
770 | "#, | ||
771 | ); | ||
772 | } | ||
773 | |||
774 | #[test] | ||
775 | fn or_pattern_no_diagnostic() { | ||
776 | check_diagnostics( | ||
777 | r#" | ||
778 | enum Either {A, B} | ||
779 | |||
780 | fn main() { | ||
781 | match (Either::A, Either::B) { | ||
782 | (Either::A | Either::B, _) => (), | ||
783 | } | ||
784 | }"#, | ||
785 | ) | ||
786 | } | ||
787 | |||
788 | #[test] | ||
789 | fn mismatched_types() { | ||
790 | // Match statements with arms that don't match the | ||
791 | // expression pattern do not fire this diagnostic. | ||
792 | check_diagnostics( | ||
793 | r#" | ||
794 | enum Either { A, B } | ||
795 | enum Either2 { C, D } | ||
796 | |||
797 | fn main() { | ||
798 | match Either::A { | ||
799 | Either2::C => (), | ||
800 | // ^^^^^^^^^^ Internal: match check bailed out | ||
801 | Either2::D => (), | ||
802 | } | ||
803 | match (true, false) { | ||
804 | (true, false, true) => (), | ||
805 | // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out | ||
806 | (true) => (), | ||
807 | } | ||
808 | match (true, false) { (true,) => {} } | ||
809 | // ^^^^^^^ Internal: match check bailed out | ||
810 | match (0) { () => () } | ||
811 | // ^^ Internal: match check bailed out | ||
812 | match Unresolved::Bar { Unresolved::Baz => () } | ||
813 | } | ||
814 | "#, | ||
815 | ); | ||
816 | } | ||
817 | |||
818 | #[test] | ||
819 | fn mismatched_types_in_or_patterns() { | ||
820 | check_diagnostics( | ||
821 | r#" | ||
822 | fn main() { | ||
823 | match false { true | () => {} } | ||
824 | // ^^^^^^^^^ Internal: match check bailed out | ||
825 | match (false,) { (true | (),) => {} } | ||
826 | // ^^^^^^^^^^^^ Internal: match check bailed out | ||
827 | } | ||
828 | "#, | ||
829 | ); | ||
830 | } | ||
831 | |||
832 | #[test] | ||
833 | fn malformed_match_arm_tuple_enum_missing_pattern() { | ||
834 | // We are testing to be sure we don't panic here when the match | ||
835 | // arm `Either::B` is missing its pattern. | ||
836 | check_diagnostics( | ||
837 | r#" | ||
838 | enum Either { A, B(u32) } | ||
839 | |||
840 | fn main() { | ||
841 | match Either::A { | ||
842 | Either::A => (), | ||
843 | Either::B() => (), | ||
844 | } | ||
845 | } | ||
846 | "#, | ||
847 | ); | ||
848 | } | ||
849 | |||
850 | #[test] | ||
851 | fn malformed_match_arm_extra_fields() { | ||
852 | check_diagnostics( | ||
853 | r#" | ||
854 | enum A { B(isize, isize), C } | ||
855 | fn main() { | ||
856 | match A::B(1, 2) { | ||
857 | A::B(_, _, _) => (), | ||
858 | // ^^^^^^^^^^^^^ Internal: match check bailed out | ||
859 | } | ||
860 | match A::B(1, 2) { | ||
861 | A::C(_) => (), | ||
862 | // ^^^^^^^ Internal: match check bailed out | ||
863 | } | ||
864 | } | ||
865 | "#, | ||
866 | ); | ||
867 | } | ||
868 | |||
869 | #[test] | ||
870 | fn expr_diverges() { | ||
871 | check_diagnostics( | ||
872 | r#" | ||
873 | enum Either { A, B } | ||
874 | |||
875 | fn main() { | ||
876 | match loop {} { | ||
877 | Either::A => (), | ||
878 | // ^^^^^^^^^ Internal: match check bailed out | ||
879 | Either::B => (), | ||
880 | } | ||
881 | match loop {} { | ||
882 | Either::A => (), | ||
883 | // ^^^^^^^^^ Internal: match check bailed out | ||
884 | } | ||
885 | match loop { break Foo::A } { | ||
886 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
887 | Either::A => (), | ||
888 | } | ||
889 | match loop { break Foo::A } { | ||
890 | Either::A => (), | ||
891 | Either::B => (), | ||
892 | } | ||
893 | } | ||
894 | "#, | ||
895 | ); | ||
896 | } | ||
897 | |||
898 | #[test] | ||
899 | fn expr_partially_diverges() { | ||
900 | check_diagnostics( | ||
901 | r#" | ||
902 | enum Either<T> { A(T), B } | ||
903 | |||
904 | fn foo() -> Either<!> { Either::B } | ||
905 | fn main() -> u32 { | ||
906 | match foo() { | ||
907 | Either::A(val) => val, | ||
908 | Either::B => 0, | ||
909 | } | ||
910 | } | ||
911 | "#, | ||
912 | ); | ||
913 | } | ||
914 | |||
915 | #[test] | ||
916 | fn enum_record() { | ||
917 | check_diagnostics( | ||
918 | r#" | ||
919 | enum Either { A { foo: bool }, B } | ||
920 | |||
921 | fn main() { | ||
922 | let a = Either::A { foo: true }; | ||
923 | match a { } | ||
924 | //^ Missing match arm | ||
925 | match a { Either::A { foo: true } => () } | ||
926 | //^ Missing match arm | ||
927 | match a { | ||
928 | Either::A { } => (), | ||
929 | //^^^^^^^^^ Missing structure fields: | ||
930 | // | - foo | ||
931 | Either::B => (), | ||
932 | } | ||
933 | match a { | ||
934 | //^ Missing match arm | ||
935 | Either::A { } => (), | ||
936 | } //^^^^^^^^^ Missing structure fields: | ||
937 | // | - foo | ||
938 | |||
939 | match a { | ||
940 | Either::A { foo: true } => (), | ||
941 | Either::A { foo: false } => (), | ||
942 | Either::B => (), | ||
943 | } | ||
944 | match a { | ||
945 | Either::A { foo: _ } => (), | ||
946 | Either::B => (), | ||
947 | } | ||
948 | } | ||
949 | "#, | ||
950 | ); | ||
951 | } | ||
952 | |||
953 | #[test] | ||
954 | fn enum_record_fields_out_of_order() { | ||
955 | check_diagnostics( | ||
956 | r#" | ||
957 | enum Either { | ||
958 | A { foo: bool, bar: () }, | ||
959 | B, | ||
960 | } | ||
961 | |||
962 | fn main() { | ||
963 | let a = Either::A { foo: true, bar: () }; | ||
964 | match a { | ||
965 | //^ Missing match arm | ||
966 | Either::A { bar: (), foo: false } => (), | ||
967 | Either::A { foo: true, bar: () } => (), | ||
968 | } | ||
969 | |||
970 | match a { | ||
971 | Either::A { bar: (), foo: false } => (), | ||
972 | Either::A { foo: true, bar: () } => (), | ||
973 | Either::B => (), | ||
974 | } | ||
975 | } | ||
976 | "#, | ||
977 | ); | ||
978 | } | ||
979 | |||
980 | #[test] | ||
981 | fn enum_record_ellipsis() { | ||
982 | check_diagnostics( | ||
983 | r#" | ||
984 | enum Either { | ||
985 | A { foo: bool, bar: bool }, | ||
986 | B, | ||
987 | } | ||
988 | |||
989 | fn main() { | ||
990 | let a = Either::B; | ||
991 | match a { | ||
992 | //^ Missing match arm | ||
993 | Either::A { foo: true, .. } => (), | ||
994 | Either::B => (), | ||
995 | } | ||
996 | match a { | ||
997 | //^ Missing match arm | ||
998 | Either::A { .. } => (), | ||
999 | } | ||
1000 | |||
1001 | match a { | ||
1002 | Either::A { foo: true, .. } => (), | ||
1003 | Either::A { foo: false, .. } => (), | ||
1004 | Either::B => (), | ||
1005 | } | ||
1006 | |||
1007 | match a { | ||
1008 | Either::A { .. } => (), | ||
1009 | Either::B => (), | ||
1010 | } | ||
1011 | } | ||
1012 | "#, | ||
1013 | ); | ||
1014 | } | ||
1015 | |||
1016 | #[test] | ||
1017 | fn enum_tuple_partial_ellipsis() { | ||
1018 | check_diagnostics( | ||
1019 | r#" | ||
1020 | enum Either { | ||
1021 | A(bool, bool, bool, bool), | ||
1022 | B, | ||
1023 | } | ||
1024 | |||
1025 | fn main() { | ||
1026 | match Either::B { | ||
1027 | //^^^^^^^^^ Missing match arm | ||
1028 | Either::A(true, .., true) => (), | ||
1029 | Either::A(true, .., false) => (), | ||
1030 | Either::A(false, .., false) => (), | ||
1031 | Either::B => (), | ||
1032 | } | ||
1033 | match Either::B { | ||
1034 | //^^^^^^^^^ Missing match arm | ||
1035 | Either::A(true, .., true) => (), | ||
1036 | Either::A(true, .., false) => (), | ||
1037 | Either::A(.., true) => (), | ||
1038 | Either::B => (), | ||
1039 | } | ||
1040 | |||
1041 | match Either::B { | ||
1042 | Either::A(true, .., true) => (), | ||
1043 | Either::A(true, .., false) => (), | ||
1044 | Either::A(false, .., true) => (), | ||
1045 | Either::A(false, .., false) => (), | ||
1046 | Either::B => (), | ||
1047 | } | ||
1048 | match Either::B { | ||
1049 | Either::A(true, .., true) => (), | ||
1050 | Either::A(true, .., false) => (), | ||
1051 | Either::A(.., true) => (), | ||
1052 | Either::A(.., false) => (), | ||
1053 | Either::B => (), | ||
1054 | } | ||
1055 | } | ||
1056 | "#, | ||
1057 | ); | ||
1058 | } | ||
1059 | |||
1060 | #[test] | ||
1061 | fn never() { | ||
1062 | check_diagnostics( | ||
1063 | r#" | ||
1064 | enum Never {} | ||
1065 | |||
1066 | fn enum_(never: Never) { | ||
1067 | match never {} | ||
1068 | } | ||
1069 | fn enum_ref(never: &Never) { | ||
1070 | match never {} | ||
1071 | //^^^^^ Missing match arm | ||
1072 | } | ||
1073 | fn bang(never: !) { | ||
1074 | match never {} | ||
1075 | } | ||
1076 | "#, | ||
1077 | ); | ||
1078 | } | ||
1079 | |||
1080 | #[test] | ||
1081 | fn unknown_type() { | ||
1082 | check_diagnostics( | ||
1083 | r#" | ||
1084 | enum Option<T> { Some(T), None } | ||
1085 | |||
1086 | fn main() { | ||
1087 | // `Never` is deliberately not defined so that it's an uninferred type. | ||
1088 | match Option::<Never>::None { | ||
1089 | None => (), | ||
1090 | Some(never) => match never {}, | ||
1091 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
1092 | } | ||
1093 | match Option::<Never>::None { | ||
1094 | //^^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1095 | Option::Some(_never) => {}, | ||
1096 | } | ||
1097 | } | ||
1098 | "#, | ||
1099 | ); | ||
1100 | } | ||
1101 | |||
1102 | #[test] | ||
1103 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | ||
1104 | check_diagnostics( | ||
1105 | r#" | ||
1106 | fn main() { | ||
1107 | match (false, true, false) { | ||
1108 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1109 | (false, ..) => (), | ||
1110 | } | ||
1111 | }"#, | ||
1112 | ); | ||
1113 | } | ||
1114 | |||
1115 | #[test] | ||
1116 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | ||
1117 | check_diagnostics( | ||
1118 | r#" | ||
1119 | fn main() { | ||
1120 | match (false, true, false) { | ||
1121 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1122 | (.., false) => (), | ||
1123 | } | ||
1124 | }"#, | ||
1125 | ); | ||
1126 | } | ||
1127 | |||
1128 | #[test] | ||
1129 | fn tuple_of_bools_with_ellipsis_in_middle_missing_arm() { | ||
1130 | check_diagnostics( | ||
1131 | r#" | ||
1132 | fn main() { | ||
1133 | match (false, true, false) { | ||
1134 | //^^^^^^^^^^^^^^^^^^^^ Missing match arm | ||
1135 | (true, .., false) => (), | ||
1136 | } | ||
1137 | }"#, | ||
1138 | ); | ||
1139 | } | ||
1140 | |||
1141 | #[test] | ||
1142 | fn record_struct() { | ||
1143 | check_diagnostics( | ||
1144 | r#"struct Foo { a: bool } | ||
1145 | fn main(f: Foo) { | ||
1146 | match f {} | ||
1147 | //^ Missing match arm | ||
1148 | match f { Foo { a: true } => () } | ||
1149 | //^ Missing match arm | ||
1150 | match &f { Foo { a: true } => () } | ||
1151 | //^^ Missing match arm | ||
1152 | match f { Foo { a: _ } => () } | ||
1153 | match f { | ||
1154 | Foo { a: true } => (), | ||
1155 | Foo { a: false } => (), | ||
1156 | } | ||
1157 | match &f { | ||
1158 | Foo { a: true } => (), | ||
1159 | Foo { a: false } => (), | ||
1160 | } | ||
1161 | } | ||
1162 | "#, | ||
1163 | ); | ||
1164 | } | ||
1165 | |||
1166 | #[test] | ||
1167 | fn tuple_struct() { | ||
1168 | check_diagnostics( | ||
1169 | r#"struct Foo(bool); | ||
1170 | fn main(f: Foo) { | ||
1171 | match f {} | ||
1172 | //^ Missing match arm | ||
1173 | match f { Foo(true) => () } | ||
1174 | //^ Missing match arm | ||
1175 | match f { | ||
1176 | Foo(true) => (), | ||
1177 | Foo(false) => (), | ||
1178 | } | ||
1179 | } | ||
1180 | "#, | ||
1181 | ); | ||
1182 | } | ||
1183 | |||
1184 | #[test] | ||
1185 | fn unit_struct() { | ||
1186 | check_diagnostics( | ||
1187 | r#"struct Foo; | ||
1188 | fn main(f: Foo) { | ||
1189 | match f {} | ||
1190 | //^ Missing match arm | ||
1191 | match f { Foo => () } | ||
1192 | } | ||
1193 | "#, | ||
1194 | ); | ||
1195 | } | ||
1196 | |||
1197 | #[test] | ||
1198 | fn record_struct_ellipsis() { | ||
1199 | check_diagnostics( | ||
1200 | r#"struct Foo { foo: bool, bar: bool } | ||
1201 | fn main(f: Foo) { | ||
1202 | match f { Foo { foo: true, .. } => () } | ||
1203 | //^ Missing match arm | ||
1204 | match f { | ||
1205 | //^ Missing match arm | ||
1206 | Foo { foo: true, .. } => (), | ||
1207 | Foo { bar: false, .. } => () | ||
1208 | } | ||
1209 | match f { Foo { .. } => () } | ||
1210 | match f { | ||
1211 | Foo { foo: true, .. } => (), | ||
1212 | Foo { foo: false, .. } => () | ||
1213 | } | ||
1214 | } | ||
1215 | "#, | ||
1216 | ); | ||
1217 | } | ||
1218 | |||
1219 | #[test] | ||
1220 | fn internal_or() { | ||
1221 | check_diagnostics( | ||
1222 | r#" | ||
1223 | fn main() { | ||
1224 | enum Either { A(bool), B } | ||
1225 | match Either::B { | ||
1226 | //^^^^^^^^^ Missing match arm | ||
1227 | Either::A(true | false) => (), | ||
1228 | } | ||
1229 | } | ||
1230 | "#, | ||
1231 | ); | ||
1232 | } | ||
1233 | |||
1234 | #[test] | ||
1235 | fn no_panic_at_unimplemented_subpattern_type() { | ||
1236 | check_diagnostics( | ||
1237 | r#" | ||
1238 | struct S { a: char} | ||
1239 | fn main(v: S) { | ||
1240 | match v { S{ a } => {} } | ||
1241 | match v { S{ a: _x } => {} } | ||
1242 | match v { S{ a: 'a' } => {} } | ||
1243 | //^^^^^^^^^^^ Internal: match check bailed out | ||
1244 | match v { S{..} => {} } | ||
1245 | match v { _ => {} } | ||
1246 | match v { } | ||
1247 | //^ Missing match arm | ||
1248 | } | ||
1249 | "#, | ||
1250 | ); | ||
1251 | } | ||
1252 | |||
1253 | #[test] | ||
1254 | fn binding() { | ||
1255 | check_diagnostics( | ||
1256 | r#" | ||
1257 | fn main() { | ||
1258 | match true { | ||
1259 | _x @ true => {} | ||
1260 | false => {} | ||
1261 | } | ||
1262 | match true { _x @ true => {} } | ||
1263 | //^^^^ Missing match arm | ||
1264 | } | ||
1265 | "#, | ||
1266 | ); | ||
1267 | } | ||
1268 | |||
1269 | #[test] | ||
1270 | fn binding_ref_has_correct_type() { | ||
1271 | // Asserts `PatKind::Binding(ref _x): bool`, not &bool. | ||
1272 | // If that's not true match checking will panic with "incompatible constructors" | ||
1273 | // FIXME: make facilities to test this directly like `tests::check_infer(..)` | ||
1274 | check_diagnostics( | ||
1275 | r#" | ||
1276 | enum Foo { A } | ||
1277 | fn main() { | ||
1278 | // FIXME: this should not bail out but current behavior is such as the old algorithm. | ||
1279 | // ExprValidator::validate_match(..) checks types of top level patterns incorrecly. | ||
1280 | match Foo::A { | ||
1281 | ref _x => {} | ||
1282 | // ^^^^^^ Internal: match check bailed out | ||
1283 | Foo::A => {} | ||
1284 | } | ||
1285 | match (true,) { | ||
1286 | (ref _x,) => {} | ||
1287 | (true,) => {} | ||
1288 | } | ||
1289 | } | ||
1290 | "#, | ||
1291 | ); | ||
1292 | } | ||
1293 | |||
1294 | #[test] | ||
1295 | fn enum_non_exhaustive() { | ||
1296 | check_diagnostics( | ||
1297 | r#" | ||
1298 | //- /lib.rs crate:lib | ||
1299 | #[non_exhaustive] | ||
1300 | pub enum E { A, B } | ||
1301 | fn _local() { | ||
1302 | match E::A { _ => {} } | ||
1303 | match E::A { | ||
1304 | E::A => {} | ||
1305 | E::B => {} | ||
1306 | } | ||
1307 | match E::A { | ||
1308 | E::A | E::B => {} | ||
1309 | } | ||
1310 | } | ||
1311 | |||
1312 | //- /main.rs crate:main deps:lib | ||
1313 | use lib::E; | ||
1314 | fn main() { | ||
1315 | match E::A { _ => {} } | ||
1316 | match E::A { | ||
1317 | //^^^^ Missing match arm | ||
1318 | E::A => {} | ||
1319 | E::B => {} | ||
1320 | } | ||
1321 | match E::A { | ||
1322 | //^^^^ Missing match arm | ||
1323 | E::A | E::B => {} | ||
1324 | } | ||
1325 | } | ||
1326 | "#, | ||
1327 | ); | ||
1328 | } | ||
1329 | |||
1330 | #[test] | ||
1331 | fn match_guard() { | ||
1332 | check_diagnostics( | ||
1333 | r#" | ||
1334 | fn main() { | ||
1335 | match true { | ||
1336 | true if false => {} | ||
1337 | true => {} | ||
1338 | false => {} | ||
1339 | } | ||
1340 | match true { | ||
1341 | //^^^^ Missing match arm | ||
1342 | true if false => {} | ||
1343 | false => {} | ||
1344 | } | ||
1345 | } | ||
1346 | "#, | ||
1347 | ); | ||
1348 | } | ||
1349 | |||
1350 | #[test] | ||
1351 | fn pattern_type_is_of_substitution() { | ||
1352 | cov_mark::check!(match_check_wildcard_expanded_to_substitutions); | ||
1353 | check_diagnostics( | ||
1354 | r#" | ||
1355 | struct Foo<T>(T); | ||
1356 | struct Bar; | ||
1357 | fn main() { | ||
1358 | match Foo(Bar) { | ||
1359 | _ | Foo(Bar) => {} | ||
1360 | } | ||
1361 | } | ||
1362 | "#, | ||
1363 | ); | ||
1364 | } | ||
1365 | |||
1366 | #[test] | ||
1367 | fn record_struct_no_such_field() { | ||
1368 | check_diagnostics( | ||
1369 | r#" | ||
1370 | struct Foo { } | ||
1371 | fn main(f: Foo) { | ||
1372 | match f { Foo { bar } => () } | ||
1373 | // ^^^^^^^^^^^ Internal: match check bailed out | ||
1374 | } | ||
1375 | "#, | ||
1376 | ); | ||
1377 | } | ||
1378 | |||
1379 | #[test] | ||
1380 | fn match_ergonomics_issue_9095() { | ||
1381 | check_diagnostics( | ||
1382 | r#" | ||
1383 | enum Foo<T> { A(T) } | ||
1384 | fn main() { | ||
1385 | match &Foo::A(true) { | ||
1386 | _ => {} | ||
1387 | Foo::A(_) => {} | ||
1388 | } | ||
1389 | } | ||
1390 | "#, | ||
1391 | ); | ||
1392 | } | ||
1393 | |||
1394 | mod false_negatives { | ||
1395 | //! The implementation of match checking here is a work in progress. As we roll this out, we | ||
1396 | //! prefer false negatives to false positives (ideally there would be no false positives). This | ||
1397 | //! test module should document known false negatives. Eventually we will have a complete | ||
1398 | //! implementation of match checking and this module will be empty. | ||
1399 | //! | ||
1400 | //! The reasons for documenting known false negatives: | ||
1401 | //! | ||
1402 | //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. | ||
1403 | //! 2. It ensures the code doesn't panic when handling these cases. | ||
1404 | use super::*; | ||
1405 | |||
1406 | #[test] | ||
1407 | fn integers() { | ||
1408 | // We don't currently check integer exhaustiveness. | ||
1409 | check_diagnostics( | ||
1410 | r#" | ||
1411 | fn main() { | ||
1412 | match 5 { | ||
1413 | 10 => (), | ||
1414 | // ^^ Internal: match check bailed out | ||
1415 | 11..20 => (), | ||
1416 | } | ||
1417 | } | ||
1418 | "#, | ||
1419 | ); | ||
1420 | } | ||
1421 | |||
1422 | #[test] | ||
1423 | fn reference_patterns_at_top_level() { | ||
1424 | check_diagnostics( | ||
1425 | r#" | ||
1426 | fn main() { | ||
1427 | match &false { | ||
1428 | &true => {} | ||
1429 | // ^^^^^ Internal: match check bailed out | ||
1430 | } | ||
1431 | } | ||
1432 | "#, | ||
1433 | ); | ||
1434 | } | ||
1435 | |||
1436 | #[test] | ||
1437 | fn reference_patterns_in_fields() { | ||
1438 | check_diagnostics( | ||
1439 | r#" | ||
1440 | fn main() { | ||
1441 | match (&false,) { | ||
1442 | (true,) => {} | ||
1443 | // ^^^^^^^ Internal: match check bailed out | ||
1444 | } | ||
1445 | match (&false,) { | ||
1446 | (&true,) => {} | ||
1447 | // ^^^^^^^^ Internal: match check bailed out | ||
1448 | } | ||
1449 | } | ||
1450 | "#, | ||
1451 | ); | ||
1452 | } | ||
1453 | } | ||
1454 | } | ||