diff options
Diffstat (limited to 'crates/ra_hir_ty/src')
-rw-r--r-- | crates/ra_hir_ty/src/_match.rs | 857 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/db.rs | 15 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/diagnostics.rs | 12 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/expr.rs | 81 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/infer/path.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 63 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lower.rs | 25 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/method_resolution.rs | 69 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/regression.rs | 151 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/tests/traits.rs | 223 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits.rs | 43 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/builtin.rs | 20 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/traits/chalk.rs | 28 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/utils.rs | 14 |
14 files changed, 1090 insertions, 513 deletions
diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs index fff257193..5495ce284 100644 --- a/crates/ra_hir_ty/src/_match.rs +++ b/crates/ra_hir_ty/src/_match.rs | |||
@@ -312,20 +312,16 @@ impl PatStack { | |||
312 | Self(v) | 312 | Self(v) |
313 | } | 313 | } |
314 | 314 | ||
315 | fn is_empty(&self) -> bool { | ||
316 | self.0.is_empty() | ||
317 | } | ||
318 | |||
319 | fn head(&self) -> PatIdOrWild { | ||
320 | self.0[0] | ||
321 | } | ||
322 | |||
323 | fn get_head(&self) -> Option<PatIdOrWild> { | 315 | fn get_head(&self) -> Option<PatIdOrWild> { |
324 | self.0.first().copied() | 316 | self.0.first().copied() |
325 | } | 317 | } |
326 | 318 | ||
319 | fn tail(&self) -> &[PatIdOrWild] { | ||
320 | self.0.get(1..).unwrap_or(&[]) | ||
321 | } | ||
322 | |||
327 | fn to_tail(&self) -> PatStack { | 323 | fn to_tail(&self) -> PatStack { |
328 | Self::from_slice(&self.0[1..]) | 324 | Self::from_slice(self.tail()) |
329 | } | 325 | } |
330 | 326 | ||
331 | fn replace_head_with<I, T>(&self, pats: I) -> PatStack | 327 | fn replace_head_with<I, T>(&self, pats: I) -> PatStack |
@@ -347,7 +343,7 @@ impl PatStack { | |||
347 | /// | 343 | /// |
348 | /// See the module docs and the associated documentation in rustc for details. | 344 | /// See the module docs and the associated documentation in rustc for details. |
349 | fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> { | 345 | fn specialize_wildcard(&self, cx: &MatchCheckCtx) -> Option<PatStack> { |
350 | if matches!(self.head().as_pat(cx), Pat::Wild) { | 346 | if matches!(self.get_head()?.as_pat(cx), Pat::Wild) { |
351 | Some(self.to_tail()) | 347 | Some(self.to_tail()) |
352 | } else { | 348 | } else { |
353 | None | 349 | None |
@@ -362,7 +358,13 @@ impl PatStack { | |||
362 | cx: &MatchCheckCtx, | 358 | cx: &MatchCheckCtx, |
363 | constructor: &Constructor, | 359 | constructor: &Constructor, |
364 | ) -> MatchCheckResult<Option<PatStack>> { | 360 | ) -> MatchCheckResult<Option<PatStack>> { |
365 | let result = match (self.head().as_pat(cx), constructor) { | 361 | let head = match self.get_head() { |
362 | Some(head) => head, | ||
363 | None => return Ok(None), | ||
364 | }; | ||
365 | |||
366 | let head_pat = head.as_pat(cx); | ||
367 | let result = match (head_pat, constructor) { | ||
366 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { | 368 | (Pat::Tuple { args: ref pat_ids, ellipsis }, Constructor::Tuple { arity: _ }) => { |
367 | if ellipsis.is_some() { | 369 | if ellipsis.is_some() { |
368 | // If there are ellipsis here, we should add the correct number of | 370 | // If there are ellipsis here, we should add the correct number of |
@@ -389,7 +391,7 @@ impl PatStack { | |||
389 | (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?), | 391 | (Pat::Wild, constructor) => Some(self.expand_wildcard(cx, constructor)?), |
390 | (Pat::Path(_), Constructor::Enum(constructor)) => { | 392 | (Pat::Path(_), Constructor::Enum(constructor)) => { |
391 | // unit enum variants become `Pat::Path` | 393 | // unit enum variants become `Pat::Path` |
392 | let pat_id = self.head().as_id().expect("we know this isn't a wild"); | 394 | let pat_id = head.as_id().expect("we know this isn't a wild"); |
393 | if !enum_variant_matches(cx, pat_id, *constructor) { | 395 | if !enum_variant_matches(cx, pat_id, *constructor) { |
394 | None | 396 | None |
395 | } else { | 397 | } else { |
@@ -400,7 +402,7 @@ impl PatStack { | |||
400 | Pat::TupleStruct { args: ref pat_ids, ellipsis, .. }, | 402 | Pat::TupleStruct { args: ref pat_ids, ellipsis, .. }, |
401 | Constructor::Enum(enum_constructor), | 403 | Constructor::Enum(enum_constructor), |
402 | ) => { | 404 | ) => { |
403 | let pat_id = self.head().as_id().expect("we know this isn't a wild"); | 405 | let pat_id = head.as_id().expect("we know this isn't a wild"); |
404 | if !enum_variant_matches(cx, pat_id, *enum_constructor) { | 406 | if !enum_variant_matches(cx, pat_id, *enum_constructor) { |
405 | None | 407 | None |
406 | } else { | 408 | } else { |
@@ -440,7 +442,7 @@ impl PatStack { | |||
440 | } | 442 | } |
441 | } | 443 | } |
442 | (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => { | 444 | (Pat::Record { args: ref arg_patterns, .. }, Constructor::Enum(e)) => { |
443 | let pat_id = self.head().as_id().expect("we know this isn't a wild"); | 445 | let pat_id = head.as_id().expect("we know this isn't a wild"); |
444 | if !enum_variant_matches(cx, pat_id, *e) { | 446 | if !enum_variant_matches(cx, pat_id, *e) { |
445 | None | 447 | None |
446 | } else { | 448 | } else { |
@@ -486,7 +488,7 @@ impl PatStack { | |||
486 | ) -> MatchCheckResult<PatStack> { | 488 | ) -> MatchCheckResult<PatStack> { |
487 | assert_eq!( | 489 | assert_eq!( |
488 | Pat::Wild, | 490 | Pat::Wild, |
489 | self.head().as_pat(cx), | 491 | self.get_head().expect("expand_wildcard called on empty PatStack").as_pat(cx), |
490 | "expand_wildcard must only be called on PatStack with wild at head", | 492 | "expand_wildcard must only be called on PatStack with wild at head", |
491 | ); | 493 | ); |
492 | 494 | ||
@@ -504,7 +506,6 @@ impl PatStack { | |||
504 | } | 506 | } |
505 | } | 507 | } |
506 | 508 | ||
507 | #[derive(Debug)] | ||
508 | /// A collection of PatStack. | 509 | /// A collection of PatStack. |
509 | /// | 510 | /// |
510 | /// This type is modeled from the struct of the same name in `rustc`. | 511 | /// This type is modeled from the struct of the same name in `rustc`. |
@@ -531,7 +532,7 @@ impl Matrix { | |||
531 | } | 532 | } |
532 | 533 | ||
533 | fn heads(&self) -> Vec<PatIdOrWild> { | 534 | fn heads(&self) -> Vec<PatIdOrWild> { |
534 | self.0.iter().map(|p| p.head()).collect() | 535 | self.0.iter().flat_map(|p| p.get_head()).collect() |
535 | } | 536 | } |
536 | 537 | ||
537 | /// Computes `D(self)` for each contained PatStack. | 538 | /// Computes `D(self)` for each contained PatStack. |
@@ -618,13 +619,16 @@ pub(crate) fn is_useful( | |||
618 | _ => (), | 619 | _ => (), |
619 | } | 620 | } |
620 | 621 | ||
621 | if v.is_empty() { | 622 | let head = match v.get_head() { |
622 | let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; | 623 | Some(head) => head, |
624 | None => { | ||
625 | let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; | ||
623 | 626 | ||
624 | return Ok(result); | 627 | return Ok(result); |
625 | } | 628 | } |
629 | }; | ||
626 | 630 | ||
627 | if let Pat::Or(pat_ids) = v.head().as_pat(cx) { | 631 | if let Pat::Or(pat_ids) = head.as_pat(cx) { |
628 | let mut found_unimplemented = false; | 632 | let mut found_unimplemented = false; |
629 | let any_useful = pat_ids.iter().any(|&pat_id| { | 633 | let any_useful = pat_ids.iter().any(|&pat_id| { |
630 | let v = PatStack::from_pattern(pat_id); | 634 | let v = PatStack::from_pattern(pat_id); |
@@ -648,7 +652,7 @@ pub(crate) fn is_useful( | |||
648 | }; | 652 | }; |
649 | } | 653 | } |
650 | 654 | ||
651 | if let Some(constructor) = pat_constructor(cx, v.head())? { | 655 | if let Some(constructor) = pat_constructor(cx, head)? { |
652 | let matrix = matrix.specialize_constructor(&cx, &constructor)?; | 656 | let matrix = matrix.specialize_constructor(&cx, &constructor)?; |
653 | let v = v | 657 | let v = v |
654 | .specialize_constructor(&cx, &constructor)? | 658 | .specialize_constructor(&cx, &constructor)? |
@@ -837,194 +841,193 @@ mod tests { | |||
837 | 841 | ||
838 | pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; | 842 | pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; |
839 | 843 | ||
840 | pub(super) fn check_diagnostic_message(content: &str) -> String { | 844 | pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String { |
841 | TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().0 | 845 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0 |
842 | } | 846 | } |
843 | 847 | ||
844 | pub(super) fn check_diagnostic(content: &str) { | 848 | pub(super) fn check_diagnostic(ra_fixture: &str) { |
845 | let diagnostic_count = | 849 | let diagnostic_count = |
846 | TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; | 850 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1; |
847 | 851 | ||
848 | assert_eq!(1, diagnostic_count, "no diagnostic reported"); | 852 | assert_eq!(1, diagnostic_count, "no diagnostic reported"); |
849 | } | 853 | } |
850 | 854 | ||
851 | pub(super) fn check_no_diagnostic(content: &str) { | 855 | pub(super) fn check_no_diagnostic(ra_fixture: &str) { |
852 | let diagnostic_count = | 856 | let (s, diagnostic_count) = |
853 | TestDB::with_single_file(content).0.diagnostic::<MissingMatchArms>().1; | 857 | TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>(); |
854 | 858 | ||
855 | assert_eq!(0, diagnostic_count, "expected no diagnostic, found one"); | 859 | assert_eq!(0, diagnostic_count, "expected no diagnostic, found one: {}", s); |
856 | } | 860 | } |
857 | 861 | ||
858 | #[test] | 862 | #[test] |
859 | fn empty_tuple_no_arms_diagnostic_message() { | 863 | fn empty_tuple_no_arms_diagnostic_message() { |
860 | let content = r" | ||
861 | fn test_fn() { | ||
862 | match () { | ||
863 | } | ||
864 | } | ||
865 | "; | ||
866 | |||
867 | assert_snapshot!( | 864 | assert_snapshot!( |
868 | check_diagnostic_message(content), | 865 | check_diagnostic_message(r" |
866 | fn test_fn() { | ||
867 | match () { | ||
868 | } | ||
869 | } | ||
870 | "), | ||
869 | @"\"()\": Missing match arm\n" | 871 | @"\"()\": Missing match arm\n" |
870 | ); | 872 | ); |
871 | } | 873 | } |
872 | 874 | ||
873 | #[test] | 875 | #[test] |
874 | fn empty_tuple_no_arms() { | 876 | fn empty_tuple_no_arms() { |
875 | let content = r" | 877 | check_diagnostic( |
878 | r" | ||
876 | fn test_fn() { | 879 | fn test_fn() { |
877 | match () { | 880 | match () { |
878 | } | 881 | } |
879 | } | 882 | } |
880 | "; | 883 | ", |
881 | 884 | ); | |
882 | check_diagnostic(content); | ||
883 | } | 885 | } |
884 | 886 | ||
885 | #[test] | 887 | #[test] |
886 | fn empty_tuple_wild() { | 888 | fn empty_tuple_wild() { |
887 | let content = r" | 889 | check_no_diagnostic( |
890 | r" | ||
888 | fn test_fn() { | 891 | fn test_fn() { |
889 | match () { | 892 | match () { |
890 | _ => {} | 893 | _ => {} |
891 | } | 894 | } |
892 | } | 895 | } |
893 | "; | 896 | ", |
894 | 897 | ); | |
895 | check_no_diagnostic(content); | ||
896 | } | 898 | } |
897 | 899 | ||
898 | #[test] | 900 | #[test] |
899 | fn empty_tuple_no_diagnostic() { | 901 | fn empty_tuple_no_diagnostic() { |
900 | let content = r" | 902 | check_no_diagnostic( |
903 | r" | ||
901 | fn test_fn() { | 904 | fn test_fn() { |
902 | match () { | 905 | match () { |
903 | () => {} | 906 | () => {} |
904 | } | 907 | } |
905 | } | 908 | } |
906 | "; | 909 | ", |
907 | 910 | ); | |
908 | check_no_diagnostic(content); | ||
909 | } | 911 | } |
910 | 912 | ||
911 | #[test] | 913 | #[test] |
912 | fn tuple_of_empty_tuple_no_arms() { | 914 | fn tuple_of_empty_tuple_no_arms() { |
913 | let content = r" | 915 | check_diagnostic( |
916 | r" | ||
914 | fn test_fn() { | 917 | fn test_fn() { |
915 | match (()) { | 918 | match (()) { |
916 | } | 919 | } |
917 | } | 920 | } |
918 | "; | 921 | ", |
919 | 922 | ); | |
920 | check_diagnostic(content); | ||
921 | } | 923 | } |
922 | 924 | ||
923 | #[test] | 925 | #[test] |
924 | fn tuple_of_empty_tuple_no_diagnostic() { | 926 | fn tuple_of_empty_tuple_no_diagnostic() { |
925 | let content = r" | 927 | check_no_diagnostic( |
928 | r" | ||
926 | fn test_fn() { | 929 | fn test_fn() { |
927 | match (()) { | 930 | match (()) { |
928 | (()) => {} | 931 | (()) => {} |
929 | } | 932 | } |
930 | } | 933 | } |
931 | "; | 934 | ", |
932 | 935 | ); | |
933 | check_no_diagnostic(content); | ||
934 | } | 936 | } |
935 | 937 | ||
936 | #[test] | 938 | #[test] |
937 | fn tuple_of_two_empty_tuple_no_arms() { | 939 | fn tuple_of_two_empty_tuple_no_arms() { |
938 | let content = r" | 940 | check_diagnostic( |
941 | r" | ||
939 | fn test_fn() { | 942 | fn test_fn() { |
940 | match ((), ()) { | 943 | match ((), ()) { |
941 | } | 944 | } |
942 | } | 945 | } |
943 | "; | 946 | ", |
944 | 947 | ); | |
945 | check_diagnostic(content); | ||
946 | } | 948 | } |
947 | 949 | ||
948 | #[test] | 950 | #[test] |
949 | fn tuple_of_two_empty_tuple_no_diagnostic() { | 951 | fn tuple_of_two_empty_tuple_no_diagnostic() { |
950 | let content = r" | 952 | check_no_diagnostic( |
953 | r" | ||
951 | fn test_fn() { | 954 | fn test_fn() { |
952 | match ((), ()) { | 955 | match ((), ()) { |
953 | ((), ()) => {} | 956 | ((), ()) => {} |
954 | } | 957 | } |
955 | } | 958 | } |
956 | "; | 959 | ", |
957 | 960 | ); | |
958 | check_no_diagnostic(content); | ||
959 | } | 961 | } |
960 | 962 | ||
961 | #[test] | 963 | #[test] |
962 | fn bool_no_arms() { | 964 | fn bool_no_arms() { |
963 | let content = r" | 965 | check_diagnostic( |
966 | r" | ||
964 | fn test_fn() { | 967 | fn test_fn() { |
965 | match false { | 968 | match false { |
966 | } | 969 | } |
967 | } | 970 | } |
968 | "; | 971 | ", |
969 | 972 | ); | |
970 | check_diagnostic(content); | ||
971 | } | 973 | } |
972 | 974 | ||
973 | #[test] | 975 | #[test] |
974 | fn bool_missing_arm() { | 976 | fn bool_missing_arm() { |
975 | let content = r" | 977 | check_diagnostic( |
978 | r" | ||
976 | fn test_fn() { | 979 | fn test_fn() { |
977 | match false { | 980 | match false { |
978 | true => {} | 981 | true => {} |
979 | } | 982 | } |
980 | } | 983 | } |
981 | "; | 984 | ", |
982 | 985 | ); | |
983 | check_diagnostic(content); | ||
984 | } | 986 | } |
985 | 987 | ||
986 | #[test] | 988 | #[test] |
987 | fn bool_no_diagnostic() { | 989 | fn bool_no_diagnostic() { |
988 | let content = r" | 990 | check_no_diagnostic( |
991 | r" | ||
989 | fn test_fn() { | 992 | fn test_fn() { |
990 | match false { | 993 | match false { |
991 | true => {} | 994 | true => {} |
992 | false => {} | 995 | false => {} |
993 | } | 996 | } |
994 | } | 997 | } |
995 | "; | 998 | ", |
996 | 999 | ); | |
997 | check_no_diagnostic(content); | ||
998 | } | 1000 | } |
999 | 1001 | ||
1000 | #[test] | 1002 | #[test] |
1001 | fn tuple_of_bools_no_arms() { | 1003 | fn tuple_of_bools_no_arms() { |
1002 | let content = r" | 1004 | check_diagnostic( |
1005 | r" | ||
1003 | fn test_fn() { | 1006 | fn test_fn() { |
1004 | match (false, true) { | 1007 | match (false, true) { |
1005 | } | 1008 | } |
1006 | } | 1009 | } |
1007 | "; | 1010 | ", |
1008 | 1011 | ); | |
1009 | check_diagnostic(content); | ||
1010 | } | 1012 | } |
1011 | 1013 | ||
1012 | #[test] | 1014 | #[test] |
1013 | fn tuple_of_bools_missing_arms() { | 1015 | fn tuple_of_bools_missing_arms() { |
1014 | let content = r" | 1016 | check_diagnostic( |
1017 | r" | ||
1015 | fn test_fn() { | 1018 | fn test_fn() { |
1016 | match (false, true) { | 1019 | match (false, true) { |
1017 | (true, true) => {}, | 1020 | (true, true) => {}, |
1018 | } | 1021 | } |
1019 | } | 1022 | } |
1020 | "; | 1023 | ", |
1021 | 1024 | ); | |
1022 | check_diagnostic(content); | ||
1023 | } | 1025 | } |
1024 | 1026 | ||
1025 | #[test] | 1027 | #[test] |
1026 | fn tuple_of_bools_missing_arm() { | 1028 | fn tuple_of_bools_missing_arm() { |
1027 | let content = r" | 1029 | check_diagnostic( |
1030 | r" | ||
1028 | fn test_fn() { | 1031 | fn test_fn() { |
1029 | match (false, true) { | 1032 | match (false, true) { |
1030 | (false, true) => {}, | 1033 | (false, true) => {}, |
@@ -1032,14 +1035,14 @@ mod tests { | |||
1032 | (true, false) => {}, | 1035 | (true, false) => {}, |
1033 | } | 1036 | } |
1034 | } | 1037 | } |
1035 | "; | 1038 | ", |
1036 | 1039 | ); | |
1037 | check_diagnostic(content); | ||
1038 | } | 1040 | } |
1039 | 1041 | ||
1040 | #[test] | 1042 | #[test] |
1041 | fn tuple_of_bools_with_wilds() { | 1043 | fn tuple_of_bools_with_wilds() { |
1042 | let content = r" | 1044 | check_no_diagnostic( |
1045 | r" | ||
1043 | fn test_fn() { | 1046 | fn test_fn() { |
1044 | match (false, true) { | 1047 | match (false, true) { |
1045 | (false, _) => {}, | 1048 | (false, _) => {}, |
@@ -1047,14 +1050,14 @@ mod tests { | |||
1047 | (_, true) => {}, | 1050 | (_, true) => {}, |
1048 | } | 1051 | } |
1049 | } | 1052 | } |
1050 | "; | 1053 | ", |
1051 | 1054 | ); | |
1052 | check_no_diagnostic(content); | ||
1053 | } | 1055 | } |
1054 | 1056 | ||
1055 | #[test] | 1057 | #[test] |
1056 | fn tuple_of_bools_no_diagnostic() { | 1058 | fn tuple_of_bools_no_diagnostic() { |
1057 | let content = r" | 1059 | check_no_diagnostic( |
1060 | r" | ||
1058 | fn test_fn() { | 1061 | fn test_fn() { |
1059 | match (false, true) { | 1062 | match (false, true) { |
1060 | (true, true) => {}, | 1063 | (true, true) => {}, |
@@ -1063,27 +1066,27 @@ mod tests { | |||
1063 | (false, false) => {}, | 1066 | (false, false) => {}, |
1064 | } | 1067 | } |
1065 | } | 1068 | } |
1066 | "; | 1069 | ", |
1067 | 1070 | ); | |
1068 | check_no_diagnostic(content); | ||
1069 | } | 1071 | } |
1070 | 1072 | ||
1071 | #[test] | 1073 | #[test] |
1072 | fn tuple_of_bools_binding_missing_arms() { | 1074 | fn tuple_of_bools_binding_missing_arms() { |
1073 | let content = r" | 1075 | check_diagnostic( |
1076 | r" | ||
1074 | fn test_fn() { | 1077 | fn test_fn() { |
1075 | match (false, true) { | 1078 | match (false, true) { |
1076 | (true, _x) => {}, | 1079 | (true, _x) => {}, |
1077 | } | 1080 | } |
1078 | } | 1081 | } |
1079 | "; | 1082 | ", |
1080 | 1083 | ); | |
1081 | check_diagnostic(content); | ||
1082 | } | 1084 | } |
1083 | 1085 | ||
1084 | #[test] | 1086 | #[test] |
1085 | fn tuple_of_bools_binding_no_diagnostic() { | 1087 | fn tuple_of_bools_binding_no_diagnostic() { |
1086 | let content = r" | 1088 | check_no_diagnostic( |
1089 | r" | ||
1087 | fn test_fn() { | 1090 | fn test_fn() { |
1088 | match (false, true) { | 1091 | match (false, true) { |
1089 | (true, _x) => {}, | 1092 | (true, _x) => {}, |
@@ -1091,80 +1094,80 @@ mod tests { | |||
1091 | (false, false) => {}, | 1094 | (false, false) => {}, |
1092 | } | 1095 | } |
1093 | } | 1096 | } |
1094 | "; | 1097 | ", |
1095 | 1098 | ); | |
1096 | check_no_diagnostic(content); | ||
1097 | } | 1099 | } |
1098 | 1100 | ||
1099 | #[test] | 1101 | #[test] |
1100 | fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { | 1102 | fn tuple_of_bools_with_ellipsis_at_end_no_diagnostic() { |
1101 | let content = r" | 1103 | check_no_diagnostic( |
1104 | r" | ||
1102 | fn test_fn() { | 1105 | fn test_fn() { |
1103 | match (false, true, false) { | 1106 | match (false, true, false) { |
1104 | (false, ..) => {}, | 1107 | (false, ..) => {}, |
1105 | (true, ..) => {}, | 1108 | (true, ..) => {}, |
1106 | } | 1109 | } |
1107 | } | 1110 | } |
1108 | "; | 1111 | ", |
1109 | 1112 | ); | |
1110 | check_no_diagnostic(content); | ||
1111 | } | 1113 | } |
1112 | 1114 | ||
1113 | #[test] | 1115 | #[test] |
1114 | fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { | 1116 | fn tuple_of_bools_with_ellipsis_at_beginning_no_diagnostic() { |
1115 | let content = r" | 1117 | check_no_diagnostic( |
1118 | r" | ||
1116 | fn test_fn() { | 1119 | fn test_fn() { |
1117 | match (false, true, false) { | 1120 | match (false, true, false) { |
1118 | (.., false) => {}, | 1121 | (.., false) => {}, |
1119 | (.., true) => {}, | 1122 | (.., true) => {}, |
1120 | } | 1123 | } |
1121 | } | 1124 | } |
1122 | "; | 1125 | ", |
1123 | 1126 | ); | |
1124 | check_no_diagnostic(content); | ||
1125 | } | 1127 | } |
1126 | 1128 | ||
1127 | #[test] | 1129 | #[test] |
1128 | fn tuple_of_bools_with_ellipsis_no_diagnostic() { | 1130 | fn tuple_of_bools_with_ellipsis_no_diagnostic() { |
1129 | let content = r" | 1131 | check_no_diagnostic( |
1132 | r" | ||
1130 | fn test_fn() { | 1133 | fn test_fn() { |
1131 | match (false, true, false) { | 1134 | match (false, true, false) { |
1132 | (..) => {}, | 1135 | (..) => {}, |
1133 | } | 1136 | } |
1134 | } | 1137 | } |
1135 | "; | 1138 | ", |
1136 | 1139 | ); | |
1137 | check_no_diagnostic(content); | ||
1138 | } | 1140 | } |
1139 | 1141 | ||
1140 | #[test] | 1142 | #[test] |
1141 | fn tuple_of_tuple_and_bools_no_arms() { | 1143 | fn tuple_of_tuple_and_bools_no_arms() { |
1142 | let content = r" | 1144 | check_diagnostic( |
1145 | r" | ||
1143 | fn test_fn() { | 1146 | fn test_fn() { |
1144 | match (false, ((), false)) { | 1147 | match (false, ((), false)) { |
1145 | } | 1148 | } |
1146 | } | 1149 | } |
1147 | "; | 1150 | ", |
1148 | 1151 | ); | |
1149 | check_diagnostic(content); | ||
1150 | } | 1152 | } |
1151 | 1153 | ||
1152 | #[test] | 1154 | #[test] |
1153 | fn tuple_of_tuple_and_bools_missing_arms() { | 1155 | fn tuple_of_tuple_and_bools_missing_arms() { |
1154 | let content = r" | 1156 | check_diagnostic( |
1157 | r" | ||
1155 | fn test_fn() { | 1158 | fn test_fn() { |
1156 | match (false, ((), false)) { | 1159 | match (false, ((), false)) { |
1157 | (true, ((), true)) => {}, | 1160 | (true, ((), true)) => {}, |
1158 | } | 1161 | } |
1159 | } | 1162 | } |
1160 | "; | 1163 | ", |
1161 | 1164 | ); | |
1162 | check_diagnostic(content); | ||
1163 | } | 1165 | } |
1164 | 1166 | ||
1165 | #[test] | 1167 | #[test] |
1166 | fn tuple_of_tuple_and_bools_no_diagnostic() { | 1168 | fn tuple_of_tuple_and_bools_no_diagnostic() { |
1167 | let content = r" | 1169 | check_no_diagnostic( |
1170 | r" | ||
1168 | fn test_fn() { | 1171 | fn test_fn() { |
1169 | match (false, ((), false)) { | 1172 | match (false, ((), false)) { |
1170 | (true, ((), true)) => {}, | 1173 | (true, ((), true)) => {}, |
@@ -1173,27 +1176,27 @@ mod tests { | |||
1173 | (false, ((), false)) => {}, | 1176 | (false, ((), false)) => {}, |
1174 | } | 1177 | } |
1175 | } | 1178 | } |
1176 | "; | 1179 | ", |
1177 | 1180 | ); | |
1178 | check_no_diagnostic(content); | ||
1179 | } | 1181 | } |
1180 | 1182 | ||
1181 | #[test] | 1183 | #[test] |
1182 | fn tuple_of_tuple_and_bools_wildcard_missing_arms() { | 1184 | fn tuple_of_tuple_and_bools_wildcard_missing_arms() { |
1183 | let content = r" | 1185 | check_diagnostic( |
1186 | r" | ||
1184 | fn test_fn() { | 1187 | fn test_fn() { |
1185 | match (false, ((), false)) { | 1188 | match (false, ((), false)) { |
1186 | (true, _) => {}, | 1189 | (true, _) => {}, |
1187 | } | 1190 | } |
1188 | } | 1191 | } |
1189 | "; | 1192 | ", |
1190 | 1193 | ); | |
1191 | check_diagnostic(content); | ||
1192 | } | 1194 | } |
1193 | 1195 | ||
1194 | #[test] | 1196 | #[test] |
1195 | fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { | 1197 | fn tuple_of_tuple_and_bools_wildcard_no_diagnostic() { |
1196 | let content = r" | 1198 | check_no_diagnostic( |
1199 | r" | ||
1197 | fn test_fn() { | 1200 | fn test_fn() { |
1198 | match (false, ((), false)) { | 1201 | match (false, ((), false)) { |
1199 | (true, ((), true)) => {}, | 1202 | (true, ((), true)) => {}, |
@@ -1201,14 +1204,14 @@ mod tests { | |||
1201 | (false, _) => {}, | 1204 | (false, _) => {}, |
1202 | } | 1205 | } |
1203 | } | 1206 | } |
1204 | "; | 1207 | ", |
1205 | 1208 | ); | |
1206 | check_no_diagnostic(content); | ||
1207 | } | 1209 | } |
1208 | 1210 | ||
1209 | #[test] | 1211 | #[test] |
1210 | fn enum_no_arms() { | 1212 | fn enum_no_arms() { |
1211 | let content = r" | 1213 | check_diagnostic( |
1214 | r" | ||
1212 | enum Either { | 1215 | enum Either { |
1213 | A, | 1216 | A, |
1214 | B, | 1217 | B, |
@@ -1217,14 +1220,14 @@ mod tests { | |||
1217 | match Either::A { | 1220 | match Either::A { |
1218 | } | 1221 | } |
1219 | } | 1222 | } |
1220 | "; | 1223 | ", |
1221 | 1224 | ); | |
1222 | check_diagnostic(content); | ||
1223 | } | 1225 | } |
1224 | 1226 | ||
1225 | #[test] | 1227 | #[test] |
1226 | fn enum_missing_arms() { | 1228 | fn enum_missing_arms() { |
1227 | let content = r" | 1229 | check_diagnostic( |
1230 | r" | ||
1228 | enum Either { | 1231 | enum Either { |
1229 | A, | 1232 | A, |
1230 | B, | 1233 | B, |
@@ -1234,14 +1237,14 @@ mod tests { | |||
1234 | Either::A => {}, | 1237 | Either::A => {}, |
1235 | } | 1238 | } |
1236 | } | 1239 | } |
1237 | "; | 1240 | ", |
1238 | 1241 | ); | |
1239 | check_diagnostic(content); | ||
1240 | } | 1242 | } |
1241 | 1243 | ||
1242 | #[test] | 1244 | #[test] |
1243 | fn enum_no_diagnostic() { | 1245 | fn enum_no_diagnostic() { |
1244 | let content = r" | 1246 | check_no_diagnostic( |
1247 | r" | ||
1245 | enum Either { | 1248 | enum Either { |
1246 | A, | 1249 | A, |
1247 | B, | 1250 | B, |
@@ -1252,14 +1255,14 @@ mod tests { | |||
1252 | Either::B => {}, | 1255 | Either::B => {}, |
1253 | } | 1256 | } |
1254 | } | 1257 | } |
1255 | "; | 1258 | ", |
1256 | 1259 | ); | |
1257 | check_no_diagnostic(content); | ||
1258 | } | 1260 | } |
1259 | 1261 | ||
1260 | #[test] | 1262 | #[test] |
1261 | fn enum_ref_missing_arms() { | 1263 | fn enum_ref_missing_arms() { |
1262 | let content = r" | 1264 | check_diagnostic( |
1265 | r" | ||
1263 | enum Either { | 1266 | enum Either { |
1264 | A, | 1267 | A, |
1265 | B, | 1268 | B, |
@@ -1269,14 +1272,14 @@ mod tests { | |||
1269 | Either::A => {}, | 1272 | Either::A => {}, |
1270 | } | 1273 | } |
1271 | } | 1274 | } |
1272 | "; | 1275 | ", |
1273 | 1276 | ); | |
1274 | check_diagnostic(content); | ||
1275 | } | 1277 | } |
1276 | 1278 | ||
1277 | #[test] | 1279 | #[test] |
1278 | fn enum_ref_no_diagnostic() { | 1280 | fn enum_ref_no_diagnostic() { |
1279 | let content = r" | 1281 | check_no_diagnostic( |
1282 | r" | ||
1280 | enum Either { | 1283 | enum Either { |
1281 | A, | 1284 | A, |
1282 | B, | 1285 | B, |
@@ -1287,14 +1290,14 @@ mod tests { | |||
1287 | Either::B => {}, | 1290 | Either::B => {}, |
1288 | } | 1291 | } |
1289 | } | 1292 | } |
1290 | "; | 1293 | ", |
1291 | 1294 | ); | |
1292 | check_no_diagnostic(content); | ||
1293 | } | 1295 | } |
1294 | 1296 | ||
1295 | #[test] | 1297 | #[test] |
1296 | fn enum_containing_bool_no_arms() { | 1298 | fn enum_containing_bool_no_arms() { |
1297 | let content = r" | 1299 | check_diagnostic( |
1300 | r" | ||
1298 | enum Either { | 1301 | enum Either { |
1299 | A(bool), | 1302 | A(bool), |
1300 | B, | 1303 | B, |
@@ -1303,14 +1306,14 @@ mod tests { | |||
1303 | match Either::B { | 1306 | match Either::B { |
1304 | } | 1307 | } |
1305 | } | 1308 | } |
1306 | "; | 1309 | ", |
1307 | 1310 | ); | |
1308 | check_diagnostic(content); | ||
1309 | } | 1311 | } |
1310 | 1312 | ||
1311 | #[test] | 1313 | #[test] |
1312 | fn enum_containing_bool_missing_arms() { | 1314 | fn enum_containing_bool_missing_arms() { |
1313 | let content = r" | 1315 | check_diagnostic( |
1316 | r" | ||
1314 | enum Either { | 1317 | enum Either { |
1315 | A(bool), | 1318 | A(bool), |
1316 | B, | 1319 | B, |
@@ -1321,14 +1324,14 @@ mod tests { | |||
1321 | Either::B => (), | 1324 | Either::B => (), |
1322 | } | 1325 | } |
1323 | } | 1326 | } |
1324 | "; | 1327 | ", |
1325 | 1328 | ); | |
1326 | check_diagnostic(content); | ||
1327 | } | 1329 | } |
1328 | 1330 | ||
1329 | #[test] | 1331 | #[test] |
1330 | fn enum_containing_bool_no_diagnostic() { | 1332 | fn enum_containing_bool_no_diagnostic() { |
1331 | let content = r" | 1333 | check_no_diagnostic( |
1334 | r" | ||
1332 | enum Either { | 1335 | enum Either { |
1333 | A(bool), | 1336 | A(bool), |
1334 | B, | 1337 | B, |
@@ -1340,14 +1343,14 @@ mod tests { | |||
1340 | Either::B => (), | 1343 | Either::B => (), |
1341 | } | 1344 | } |
1342 | } | 1345 | } |
1343 | "; | 1346 | ", |
1344 | 1347 | ); | |
1345 | check_no_diagnostic(content); | ||
1346 | } | 1348 | } |
1347 | 1349 | ||
1348 | #[test] | 1350 | #[test] |
1349 | fn enum_containing_bool_with_wild_no_diagnostic() { | 1351 | fn enum_containing_bool_with_wild_no_diagnostic() { |
1350 | let content = r" | 1352 | check_no_diagnostic( |
1353 | r" | ||
1351 | enum Either { | 1354 | enum Either { |
1352 | A(bool), | 1355 | A(bool), |
1353 | B, | 1356 | B, |
@@ -1358,14 +1361,14 @@ mod tests { | |||
1358 | _ => (), | 1361 | _ => (), |
1359 | } | 1362 | } |
1360 | } | 1363 | } |
1361 | "; | 1364 | ", |
1362 | 1365 | ); | |
1363 | check_no_diagnostic(content); | ||
1364 | } | 1366 | } |
1365 | 1367 | ||
1366 | #[test] | 1368 | #[test] |
1367 | fn enum_containing_bool_with_wild_2_no_diagnostic() { | 1369 | fn enum_containing_bool_with_wild_2_no_diagnostic() { |
1368 | let content = r" | 1370 | check_no_diagnostic( |
1371 | r" | ||
1369 | enum Either { | 1372 | enum Either { |
1370 | A(bool), | 1373 | A(bool), |
1371 | B, | 1374 | B, |
@@ -1376,14 +1379,14 @@ mod tests { | |||
1376 | Either::B => (), | 1379 | Either::B => (), |
1377 | } | 1380 | } |
1378 | } | 1381 | } |
1379 | "; | 1382 | ", |
1380 | 1383 | ); | |
1381 | check_no_diagnostic(content); | ||
1382 | } | 1384 | } |
1383 | 1385 | ||
1384 | #[test] | 1386 | #[test] |
1385 | fn enum_different_sizes_missing_arms() { | 1387 | fn enum_different_sizes_missing_arms() { |
1386 | let content = r" | 1388 | check_diagnostic( |
1389 | r" | ||
1387 | enum Either { | 1390 | enum Either { |
1388 | A(bool), | 1391 | A(bool), |
1389 | B(bool, bool), | 1392 | B(bool, bool), |
@@ -1394,14 +1397,14 @@ mod tests { | |||
1394 | Either::B(false, _) => (), | 1397 | Either::B(false, _) => (), |
1395 | } | 1398 | } |
1396 | } | 1399 | } |
1397 | "; | 1400 | ", |
1398 | 1401 | ); | |
1399 | check_diagnostic(content); | ||
1400 | } | 1402 | } |
1401 | 1403 | ||
1402 | #[test] | 1404 | #[test] |
1403 | fn enum_different_sizes_no_diagnostic() { | 1405 | fn enum_different_sizes_no_diagnostic() { |
1404 | let content = r" | 1406 | check_no_diagnostic( |
1407 | r" | ||
1405 | enum Either { | 1408 | enum Either { |
1406 | A(bool), | 1409 | A(bool), |
1407 | B(bool, bool), | 1410 | B(bool, bool), |
@@ -1413,14 +1416,14 @@ mod tests { | |||
1413 | Either::B(false, _) => (), | 1416 | Either::B(false, _) => (), |
1414 | } | 1417 | } |
1415 | } | 1418 | } |
1416 | "; | 1419 | ", |
1417 | 1420 | ); | |
1418 | check_no_diagnostic(content); | ||
1419 | } | 1421 | } |
1420 | 1422 | ||
1421 | #[test] | 1423 | #[test] |
1422 | fn or_no_diagnostic() { | 1424 | fn or_no_diagnostic() { |
1423 | let content = r" | 1425 | check_no_diagnostic( |
1426 | r" | ||
1424 | enum Either { | 1427 | enum Either { |
1425 | A(bool), | 1428 | A(bool), |
1426 | B(bool, bool), | 1429 | B(bool, bool), |
@@ -1432,14 +1435,14 @@ mod tests { | |||
1432 | Either::B(false, _) => (), | 1435 | Either::B(false, _) => (), |
1433 | } | 1436 | } |
1434 | } | 1437 | } |
1435 | "; | 1438 | ", |
1436 | 1439 | ); | |
1437 | check_no_diagnostic(content); | ||
1438 | } | 1440 | } |
1439 | 1441 | ||
1440 | #[test] | 1442 | #[test] |
1441 | fn tuple_of_enum_no_diagnostic() { | 1443 | fn tuple_of_enum_no_diagnostic() { |
1442 | let content = r" | 1444 | check_no_diagnostic( |
1445 | r" | ||
1443 | enum Either { | 1446 | enum Either { |
1444 | A(bool), | 1447 | A(bool), |
1445 | B(bool, bool), | 1448 | B(bool, bool), |
@@ -1456,14 +1459,16 @@ mod tests { | |||
1456 | (Either::B(_, _), Either2::D) => (), | 1459 | (Either::B(_, _), Either2::D) => (), |
1457 | } | 1460 | } |
1458 | } | 1461 | } |
1459 | "; | 1462 | ", |
1460 | 1463 | ); | |
1461 | check_no_diagnostic(content); | ||
1462 | } | 1464 | } |
1463 | 1465 | ||
1464 | #[test] | 1466 | #[test] |
1465 | fn mismatched_types() { | 1467 | fn mismatched_types() { |
1466 | let content = r" | 1468 | // Match statements with arms that don't match the |
1469 | // expression pattern do not fire this diagnostic. | ||
1470 | check_no_diagnostic( | ||
1471 | r" | ||
1467 | enum Either { | 1472 | enum Either { |
1468 | A, | 1473 | A, |
1469 | B, | 1474 | B, |
@@ -1478,47 +1483,47 @@ mod tests { | |||
1478 | Either2::D => (), | 1483 | Either2::D => (), |
1479 | } | 1484 | } |
1480 | } | 1485 | } |
1481 | "; | 1486 | ", |
1482 | 1487 | ); | |
1483 | // Match statements with arms that don't match the | ||
1484 | // expression pattern do not fire this diagnostic. | ||
1485 | check_no_diagnostic(content); | ||
1486 | } | 1488 | } |
1487 | 1489 | ||
1488 | #[test] | 1490 | #[test] |
1489 | fn mismatched_types_with_different_arity() { | 1491 | fn mismatched_types_with_different_arity() { |
1490 | let content = r" | 1492 | // Match statements with arms that don't match the |
1493 | // expression pattern do not fire this diagnostic. | ||
1494 | check_no_diagnostic( | ||
1495 | r" | ||
1491 | fn test_fn() { | 1496 | fn test_fn() { |
1492 | match (true, false) { | 1497 | match (true, false) { |
1493 | (true, false, true) => (), | 1498 | (true, false, true) => (), |
1494 | (true) => (), | 1499 | (true) => (), |
1495 | } | 1500 | } |
1496 | } | 1501 | } |
1497 | "; | 1502 | ", |
1498 | 1503 | ); | |
1499 | // Match statements with arms that don't match the | ||
1500 | // expression pattern do not fire this diagnostic. | ||
1501 | check_no_diagnostic(content); | ||
1502 | } | 1504 | } |
1503 | 1505 | ||
1504 | #[test] | 1506 | #[test] |
1505 | fn malformed_match_arm_tuple_missing_pattern() { | 1507 | fn malformed_match_arm_tuple_missing_pattern() { |
1506 | let content = r" | 1508 | // Match statements with arms that don't match the |
1509 | // expression pattern do not fire this diagnostic. | ||
1510 | check_no_diagnostic( | ||
1511 | r" | ||
1507 | fn test_fn() { | 1512 | fn test_fn() { |
1508 | match (0) { | 1513 | match (0) { |
1509 | () => (), | 1514 | () => (), |
1510 | } | 1515 | } |
1511 | } | 1516 | } |
1512 | "; | 1517 | ", |
1513 | 1518 | ); | |
1514 | // Match statements with arms that don't match the | ||
1515 | // expression pattern do not fire this diagnostic. | ||
1516 | check_no_diagnostic(content); | ||
1517 | } | 1519 | } |
1518 | 1520 | ||
1519 | #[test] | 1521 | #[test] |
1520 | fn malformed_match_arm_tuple_enum_missing_pattern() { | 1522 | fn malformed_match_arm_tuple_enum_missing_pattern() { |
1521 | let content = r" | 1523 | // We are testing to be sure we don't panic here when the match |
1524 | // arm `Either::B` is missing its pattern. | ||
1525 | check_no_diagnostic( | ||
1526 | r" | ||
1522 | enum Either { | 1527 | enum Either { |
1523 | A, | 1528 | A, |
1524 | B(u32), | 1529 | B(u32), |
@@ -1529,32 +1534,30 @@ mod tests { | |||
1529 | Either::B() => (), | 1534 | Either::B() => (), |
1530 | } | 1535 | } |
1531 | } | 1536 | } |
1532 | "; | 1537 | ", |
1533 | 1538 | ); | |
1534 | // We are testing to be sure we don't panic here when the match | ||
1535 | // arm `Either::B` is missing its pattern. | ||
1536 | check_no_diagnostic(content); | ||
1537 | } | 1539 | } |
1538 | 1540 | ||
1539 | #[test] | 1541 | #[test] |
1540 | fn enum_not_in_scope() { | 1542 | fn enum_not_in_scope() { |
1541 | let content = r" | 1543 | // The enum is not in scope so we don't perform exhaustiveness |
1544 | // checking, but we want to be sure we don't panic here (and | ||
1545 | // we don't create a diagnostic). | ||
1546 | check_no_diagnostic( | ||
1547 | r" | ||
1542 | fn test_fn() { | 1548 | fn test_fn() { |
1543 | match Foo::Bar { | 1549 | match Foo::Bar { |
1544 | Foo::Baz => (), | 1550 | Foo::Baz => (), |
1545 | } | 1551 | } |
1546 | } | 1552 | } |
1547 | "; | 1553 | ", |
1548 | 1554 | ); | |
1549 | // The enum is not in scope so we don't perform exhaustiveness | ||
1550 | // checking, but we want to be sure we don't panic here (and | ||
1551 | // we don't create a diagnostic). | ||
1552 | check_no_diagnostic(content); | ||
1553 | } | 1555 | } |
1554 | 1556 | ||
1555 | #[test] | 1557 | #[test] |
1556 | fn expr_diverges() { | 1558 | fn expr_diverges() { |
1557 | let content = r" | 1559 | check_no_diagnostic( |
1560 | r" | ||
1558 | enum Either { | 1561 | enum Either { |
1559 | A, | 1562 | A, |
1560 | B, | 1563 | B, |
@@ -1565,14 +1568,14 @@ mod tests { | |||
1565 | Either::B => (), | 1568 | Either::B => (), |
1566 | } | 1569 | } |
1567 | } | 1570 | } |
1568 | "; | 1571 | ", |
1569 | 1572 | ); | |
1570 | check_no_diagnostic(content); | ||
1571 | } | 1573 | } |
1572 | 1574 | ||
1573 | #[test] | 1575 | #[test] |
1574 | fn expr_loop_with_break() { | 1576 | fn expr_loop_with_break() { |
1575 | let content = r" | 1577 | check_no_diagnostic( |
1578 | r" | ||
1576 | enum Either { | 1579 | enum Either { |
1577 | A, | 1580 | A, |
1578 | B, | 1581 | B, |
@@ -1583,14 +1586,14 @@ mod tests { | |||
1583 | Either::B => (), | 1586 | Either::B => (), |
1584 | } | 1587 | } |
1585 | } | 1588 | } |
1586 | "; | 1589 | ", |
1587 | 1590 | ); | |
1588 | check_no_diagnostic(content); | ||
1589 | } | 1591 | } |
1590 | 1592 | ||
1591 | #[test] | 1593 | #[test] |
1592 | fn expr_partially_diverges() { | 1594 | fn expr_partially_diverges() { |
1593 | let content = r" | 1595 | check_no_diagnostic( |
1596 | r" | ||
1594 | enum Either<T> { | 1597 | enum Either<T> { |
1595 | A(T), | 1598 | A(T), |
1596 | B, | 1599 | B, |
@@ -1604,14 +1607,14 @@ mod tests { | |||
1604 | Either::B => 0, | 1607 | Either::B => 0, |
1605 | } | 1608 | } |
1606 | } | 1609 | } |
1607 | "; | 1610 | ", |
1608 | 1611 | ); | |
1609 | check_no_diagnostic(content); | ||
1610 | } | 1612 | } |
1611 | 1613 | ||
1612 | #[test] | 1614 | #[test] |
1613 | fn enum_record_no_arms() { | 1615 | fn enum_record_no_arms() { |
1614 | let content = r" | 1616 | check_diagnostic( |
1617 | r" | ||
1615 | enum Either { | 1618 | enum Either { |
1616 | A { foo: bool }, | 1619 | A { foo: bool }, |
1617 | B, | 1620 | B, |
@@ -1621,14 +1624,14 @@ mod tests { | |||
1621 | match a { | 1624 | match a { |
1622 | } | 1625 | } |
1623 | } | 1626 | } |
1624 | "; | 1627 | ", |
1625 | 1628 | ); | |
1626 | check_diagnostic(content); | ||
1627 | } | 1629 | } |
1628 | 1630 | ||
1629 | #[test] | 1631 | #[test] |
1630 | fn enum_record_missing_arms() { | 1632 | fn enum_record_missing_arms() { |
1631 | let content = r" | 1633 | check_diagnostic( |
1634 | r" | ||
1632 | enum Either { | 1635 | enum Either { |
1633 | A { foo: bool }, | 1636 | A { foo: bool }, |
1634 | B, | 1637 | B, |
@@ -1639,14 +1642,14 @@ mod tests { | |||
1639 | Either::A { foo: true } => (), | 1642 | Either::A { foo: true } => (), |
1640 | } | 1643 | } |
1641 | } | 1644 | } |
1642 | "; | 1645 | ", |
1643 | 1646 | ); | |
1644 | check_diagnostic(content); | ||
1645 | } | 1647 | } |
1646 | 1648 | ||
1647 | #[test] | 1649 | #[test] |
1648 | fn enum_record_no_diagnostic() { | 1650 | fn enum_record_no_diagnostic() { |
1649 | let content = r" | 1651 | check_no_diagnostic( |
1652 | r" | ||
1650 | enum Either { | 1653 | enum Either { |
1651 | A { foo: bool }, | 1654 | A { foo: bool }, |
1652 | B, | 1655 | B, |
@@ -1659,14 +1662,17 @@ mod tests { | |||
1659 | Either::B => (), | 1662 | Either::B => (), |
1660 | } | 1663 | } |
1661 | } | 1664 | } |
1662 | "; | 1665 | ", |
1663 | 1666 | ); | |
1664 | check_no_diagnostic(content); | ||
1665 | } | 1667 | } |
1666 | 1668 | ||
1667 | #[test] | 1669 | #[test] |
1668 | fn enum_record_missing_field_no_diagnostic() { | 1670 | fn enum_record_missing_field_no_diagnostic() { |
1669 | let content = r" | 1671 | // When `Either::A` is missing a struct member, we don't want |
1672 | // to fire the missing match arm diagnostic. This should fire | ||
1673 | // some other diagnostic. | ||
1674 | check_no_diagnostic( | ||
1675 | r" | ||
1670 | enum Either { | 1676 | enum Either { |
1671 | A { foo: bool }, | 1677 | A { foo: bool }, |
1672 | B, | 1678 | B, |
@@ -1678,17 +1684,16 @@ mod tests { | |||
1678 | Either::B => (), | 1684 | Either::B => (), |
1679 | } | 1685 | } |
1680 | } | 1686 | } |
1681 | "; | 1687 | ", |
1682 | 1688 | ); | |
1683 | // When `Either::A` is missing a struct member, we don't want | ||
1684 | // to fire the missing match arm diagnostic. This should fire | ||
1685 | // some other diagnostic. | ||
1686 | check_no_diagnostic(content); | ||
1687 | } | 1689 | } |
1688 | 1690 | ||
1689 | #[test] | 1691 | #[test] |
1690 | fn enum_record_missing_field_missing_match_arm() { | 1692 | fn enum_record_missing_field_missing_match_arm() { |
1691 | let content = r" | 1693 | // Even though `Either::A` is missing fields, we still want to fire |
1694 | // the missing arm diagnostic here, since we know `Either::B` is missing. | ||
1695 | check_diagnostic( | ||
1696 | r" | ||
1692 | enum Either { | 1697 | enum Either { |
1693 | A { foo: bool }, | 1698 | A { foo: bool }, |
1694 | B, | 1699 | B, |
@@ -1699,16 +1704,14 @@ mod tests { | |||
1699 | Either::A { } => (), | 1704 | Either::A { } => (), |
1700 | } | 1705 | } |
1701 | } | 1706 | } |
1702 | "; | 1707 | ", |
1703 | 1708 | ); | |
1704 | // Even though `Either::A` is missing fields, we still want to fire | ||
1705 | // the missing arm diagnostic here, since we know `Either::B` is missing. | ||
1706 | check_diagnostic(content); | ||
1707 | } | 1709 | } |
1708 | 1710 | ||
1709 | #[test] | 1711 | #[test] |
1710 | fn enum_record_no_diagnostic_wild() { | 1712 | fn enum_record_no_diagnostic_wild() { |
1711 | let content = r" | 1713 | check_no_diagnostic( |
1714 | r" | ||
1712 | enum Either { | 1715 | enum Either { |
1713 | A { foo: bool }, | 1716 | A { foo: bool }, |
1714 | B, | 1717 | B, |
@@ -1720,14 +1723,14 @@ mod tests { | |||
1720 | Either::B => (), | 1723 | Either::B => (), |
1721 | } | 1724 | } |
1722 | } | 1725 | } |
1723 | "; | 1726 | ", |
1724 | 1727 | ); | |
1725 | check_no_diagnostic(content); | ||
1726 | } | 1728 | } |
1727 | 1729 | ||
1728 | #[test] | 1730 | #[test] |
1729 | fn enum_record_fields_out_of_order_missing_arm() { | 1731 | fn enum_record_fields_out_of_order_missing_arm() { |
1730 | let content = r" | 1732 | check_diagnostic( |
1733 | r" | ||
1731 | enum Either { | 1734 | enum Either { |
1732 | A { foo: bool, bar: () }, | 1735 | A { foo: bool, bar: () }, |
1733 | B, | 1736 | B, |
@@ -1739,14 +1742,14 @@ mod tests { | |||
1739 | Either::A { foo: true, bar: () } => (), | 1742 | Either::A { foo: true, bar: () } => (), |
1740 | } | 1743 | } |
1741 | } | 1744 | } |
1742 | "; | 1745 | ", |
1743 | 1746 | ); | |
1744 | check_diagnostic(content); | ||
1745 | } | 1747 | } |
1746 | 1748 | ||
1747 | #[test] | 1749 | #[test] |
1748 | fn enum_record_fields_out_of_order_no_diagnostic() { | 1750 | fn enum_record_fields_out_of_order_no_diagnostic() { |
1749 | let content = r" | 1751 | check_no_diagnostic( |
1752 | r" | ||
1750 | enum Either { | 1753 | enum Either { |
1751 | A { foo: bool, bar: () }, | 1754 | A { foo: bool, bar: () }, |
1752 | B, | 1755 | B, |
@@ -1759,89 +1762,89 @@ mod tests { | |||
1759 | Either::B => (), | 1762 | Either::B => (), |
1760 | } | 1763 | } |
1761 | } | 1764 | } |
1762 | "; | 1765 | ", |
1763 | 1766 | ); | |
1764 | check_no_diagnostic(content); | ||
1765 | } | 1767 | } |
1766 | 1768 | ||
1767 | #[test] | 1769 | #[test] |
1768 | fn enum_record_ellipsis_missing_arm() { | 1770 | fn enum_record_ellipsis_missing_arm() { |
1769 | let content = r" | 1771 | check_diagnostic( |
1770 | enum Either { | 1772 | r" |
1771 | A { foo: bool, bar: bool }, | 1773 | enum Either { |
1772 | B, | 1774 | A { foo: bool, bar: bool }, |
1773 | } | 1775 | B, |
1774 | fn test_fn() { | 1776 | } |
1775 | match Either::B { | 1777 | fn test_fn() { |
1776 | Either::A { foo: true, .. } => (), | 1778 | match Either::B { |
1777 | Either::B => (), | 1779 | Either::A { foo: true, .. } => (), |
1778 | } | 1780 | Either::B => (), |
1779 | } | 1781 | } |
1780 | "; | 1782 | } |
1781 | 1783 | ", | |
1782 | check_diagnostic(content); | 1784 | ); |
1783 | } | 1785 | } |
1784 | 1786 | ||
1785 | #[test] | 1787 | #[test] |
1786 | fn enum_record_ellipsis_no_diagnostic() { | 1788 | fn enum_record_ellipsis_no_diagnostic() { |
1787 | let content = r" | 1789 | check_no_diagnostic( |
1788 | enum Either { | 1790 | r" |
1789 | A { foo: bool, bar: bool }, | 1791 | enum Either { |
1790 | B, | 1792 | A { foo: bool, bar: bool }, |
1791 | } | 1793 | B, |
1792 | fn test_fn() { | 1794 | } |
1793 | let a = Either::A { foo: true }; | 1795 | fn test_fn() { |
1794 | match a { | 1796 | let a = Either::A { foo: true }; |
1795 | Either::A { foo: true, .. } => (), | 1797 | match a { |
1796 | Either::A { foo: false, .. } => (), | 1798 | Either::A { foo: true, .. } => (), |
1797 | Either::B => (), | 1799 | Either::A { foo: false, .. } => (), |
1798 | } | 1800 | Either::B => (), |
1799 | } | 1801 | } |
1800 | "; | 1802 | } |
1801 | 1803 | ", | |
1802 | check_no_diagnostic(content); | 1804 | ); |
1803 | } | 1805 | } |
1804 | 1806 | ||
1805 | #[test] | 1807 | #[test] |
1806 | fn enum_record_ellipsis_all_fields_missing_arm() { | 1808 | fn enum_record_ellipsis_all_fields_missing_arm() { |
1807 | let content = r" | 1809 | check_diagnostic( |
1808 | enum Either { | 1810 | r" |
1809 | A { foo: bool, bar: bool }, | 1811 | enum Either { |
1810 | B, | 1812 | A { foo: bool, bar: bool }, |
1811 | } | 1813 | B, |
1812 | fn test_fn() { | 1814 | } |
1813 | let a = Either::B; | 1815 | fn test_fn() { |
1814 | match a { | 1816 | let a = Either::B; |
1815 | Either::A { .. } => (), | 1817 | match a { |
1816 | } | 1818 | Either::A { .. } => (), |
1817 | } | 1819 | } |
1818 | "; | 1820 | } |
1819 | 1821 | ", | |
1820 | check_diagnostic(content); | 1822 | ); |
1821 | } | 1823 | } |
1822 | 1824 | ||
1823 | #[test] | 1825 | #[test] |
1824 | fn enum_record_ellipsis_all_fields_no_diagnostic() { | 1826 | fn enum_record_ellipsis_all_fields_no_diagnostic() { |
1825 | let content = r" | 1827 | check_no_diagnostic( |
1826 | enum Either { | 1828 | r" |
1827 | A { foo: bool, bar: bool }, | 1829 | enum Either { |
1828 | B, | 1830 | A { foo: bool, bar: bool }, |
1829 | } | 1831 | B, |
1830 | fn test_fn() { | 1832 | } |
1831 | let a = Either::B; | 1833 | fn test_fn() { |
1832 | match a { | 1834 | let a = Either::B; |
1833 | Either::A { .. } => (), | 1835 | match a { |
1834 | Either::B => (), | 1836 | Either::A { .. } => (), |
1835 | } | 1837 | Either::B => (), |
1836 | } | 1838 | } |
1837 | "; | 1839 | } |
1838 | 1840 | ", | |
1839 | check_no_diagnostic(content); | 1841 | ); |
1840 | } | 1842 | } |
1841 | 1843 | ||
1842 | #[test] | 1844 | #[test] |
1843 | fn enum_tuple_partial_ellipsis_no_diagnostic() { | 1845 | fn enum_tuple_partial_ellipsis_no_diagnostic() { |
1844 | let content = r" | 1846 | check_no_diagnostic( |
1847 | r" | ||
1845 | enum Either { | 1848 | enum Either { |
1846 | A(bool, bool, bool, bool), | 1849 | A(bool, bool, bool, bool), |
1847 | B, | 1850 | B, |
@@ -1855,14 +1858,14 @@ mod tests { | |||
1855 | Either::B => {}, | 1858 | Either::B => {}, |
1856 | } | 1859 | } |
1857 | } | 1860 | } |
1858 | "; | 1861 | ", |
1859 | 1862 | ); | |
1860 | check_no_diagnostic(content); | ||
1861 | } | 1863 | } |
1862 | 1864 | ||
1863 | #[test] | 1865 | #[test] |
1864 | fn enum_tuple_partial_ellipsis_2_no_diagnostic() { | 1866 | fn enum_tuple_partial_ellipsis_2_no_diagnostic() { |
1865 | let content = r" | 1867 | check_no_diagnostic( |
1868 | r" | ||
1866 | enum Either { | 1869 | enum Either { |
1867 | A(bool, bool, bool, bool), | 1870 | A(bool, bool, bool, bool), |
1868 | B, | 1871 | B, |
@@ -1876,14 +1879,14 @@ mod tests { | |||
1876 | Either::B => {}, | 1879 | Either::B => {}, |
1877 | } | 1880 | } |
1878 | } | 1881 | } |
1879 | "; | 1882 | ", |
1880 | 1883 | ); | |
1881 | check_no_diagnostic(content); | ||
1882 | } | 1884 | } |
1883 | 1885 | ||
1884 | #[test] | 1886 | #[test] |
1885 | fn enum_tuple_partial_ellipsis_missing_arm() { | 1887 | fn enum_tuple_partial_ellipsis_missing_arm() { |
1886 | let content = r" | 1888 | check_diagnostic( |
1889 | r" | ||
1887 | enum Either { | 1890 | enum Either { |
1888 | A(bool, bool, bool, bool), | 1891 | A(bool, bool, bool, bool), |
1889 | B, | 1892 | B, |
@@ -1896,14 +1899,14 @@ mod tests { | |||
1896 | Either::B => {}, | 1899 | Either::B => {}, |
1897 | } | 1900 | } |
1898 | } | 1901 | } |
1899 | "; | 1902 | ", |
1900 | 1903 | ); | |
1901 | check_diagnostic(content); | ||
1902 | } | 1904 | } |
1903 | 1905 | ||
1904 | #[test] | 1906 | #[test] |
1905 | fn enum_tuple_partial_ellipsis_2_missing_arm() { | 1907 | fn enum_tuple_partial_ellipsis_2_missing_arm() { |
1906 | let content = r" | 1908 | check_diagnostic( |
1909 | r" | ||
1907 | enum Either { | 1910 | enum Either { |
1908 | A(bool, bool, bool, bool), | 1911 | A(bool, bool, bool, bool), |
1909 | B, | 1912 | B, |
@@ -1916,14 +1919,14 @@ mod tests { | |||
1916 | Either::B => {}, | 1919 | Either::B => {}, |
1917 | } | 1920 | } |
1918 | } | 1921 | } |
1919 | "; | 1922 | ", |
1920 | 1923 | ); | |
1921 | check_diagnostic(content); | ||
1922 | } | 1924 | } |
1923 | 1925 | ||
1924 | #[test] | 1926 | #[test] |
1925 | fn enum_tuple_ellipsis_no_diagnostic() { | 1927 | fn enum_tuple_ellipsis_no_diagnostic() { |
1926 | let content = r" | 1928 | check_no_diagnostic( |
1929 | r" | ||
1927 | enum Either { | 1930 | enum Either { |
1928 | A(bool, bool, bool, bool), | 1931 | A(bool, bool, bool, bool), |
1929 | B, | 1932 | B, |
@@ -1934,51 +1937,51 @@ mod tests { | |||
1934 | Either::B => {}, | 1937 | Either::B => {}, |
1935 | } | 1938 | } |
1936 | } | 1939 | } |
1937 | "; | 1940 | ", |
1938 | 1941 | ); | |
1939 | check_no_diagnostic(content); | ||
1940 | } | 1942 | } |
1941 | 1943 | ||
1942 | #[test] | 1944 | #[test] |
1943 | fn enum_never() { | 1945 | fn enum_never() { |
1944 | let content = r" | 1946 | check_no_diagnostic( |
1947 | r" | ||
1945 | enum Never {} | 1948 | enum Never {} |
1946 | 1949 | ||
1947 | fn test_fn(never: Never) { | 1950 | fn test_fn(never: Never) { |
1948 | match never {} | 1951 | match never {} |
1949 | } | 1952 | } |
1950 | "; | 1953 | ", |
1951 | 1954 | ); | |
1952 | check_no_diagnostic(content); | ||
1953 | } | 1955 | } |
1954 | 1956 | ||
1955 | #[test] | 1957 | #[test] |
1956 | fn type_never() { | 1958 | fn type_never() { |
1957 | let content = r" | 1959 | check_no_diagnostic( |
1960 | r" | ||
1958 | fn test_fn(never: !) { | 1961 | fn test_fn(never: !) { |
1959 | match never {} | 1962 | match never {} |
1960 | } | 1963 | } |
1961 | "; | 1964 | ", |
1962 | 1965 | ); | |
1963 | check_no_diagnostic(content); | ||
1964 | } | 1966 | } |
1965 | 1967 | ||
1966 | #[test] | 1968 | #[test] |
1967 | fn enum_never_ref() { | 1969 | fn enum_never_ref() { |
1968 | let content = r" | 1970 | check_no_diagnostic( |
1971 | r" | ||
1969 | enum Never {} | 1972 | enum Never {} |
1970 | 1973 | ||
1971 | fn test_fn(never: &Never) { | 1974 | fn test_fn(never: &Never) { |
1972 | match never {} | 1975 | match never {} |
1973 | } | 1976 | } |
1974 | "; | 1977 | ", |
1975 | 1978 | ); | |
1976 | check_no_diagnostic(content); | ||
1977 | } | 1979 | } |
1978 | 1980 | ||
1979 | #[test] | 1981 | #[test] |
1980 | fn expr_diverges_missing_arm() { | 1982 | fn expr_diverges_missing_arm() { |
1981 | let content = r" | 1983 | check_no_diagnostic( |
1984 | r" | ||
1982 | enum Either { | 1985 | enum Either { |
1983 | A, | 1986 | A, |
1984 | B, | 1987 | B, |
@@ -1988,9 +1991,49 @@ mod tests { | |||
1988 | Either::A => (), | 1991 | Either::A => (), |
1989 | } | 1992 | } |
1990 | } | 1993 | } |
1991 | "; | 1994 | ", |
1995 | ); | ||
1996 | } | ||
1992 | 1997 | ||
1993 | check_no_diagnostic(content); | 1998 | #[test] |
1999 | fn or_pattern_panic() { | ||
2000 | check_no_diagnostic( | ||
2001 | r" | ||
2002 | pub enum Category { | ||
2003 | Infinity, | ||
2004 | Zero, | ||
2005 | } | ||
2006 | |||
2007 | fn panic(a: Category, b: Category) { | ||
2008 | match (a, b) { | ||
2009 | (Category::Zero | Category::Infinity, _) => {} | ||
2010 | (_, Category::Zero | Category::Infinity) => {} | ||
2011 | } | ||
2012 | } | ||
2013 | ", | ||
2014 | ); | ||
2015 | } | ||
2016 | |||
2017 | #[test] | ||
2018 | fn or_pattern_panic_2() { | ||
2019 | // FIXME: This is a false positive, but the code used to cause a panic in the match checker, | ||
2020 | // so this acts as a regression test for that. | ||
2021 | check_diagnostic( | ||
2022 | r" | ||
2023 | pub enum Category { | ||
2024 | Infinity, | ||
2025 | Zero, | ||
2026 | } | ||
2027 | |||
2028 | fn panic(a: Category, b: Category) { | ||
2029 | match (a, b) { | ||
2030 | (Category::Infinity, Category::Infinity) | (Category::Zero, Category::Zero) => {} | ||
2031 | |||
2032 | (Category::Infinity | Category::Zero, _) => {} | ||
2033 | } | ||
2034 | } | ||
2035 | ", | ||
2036 | ); | ||
1994 | } | 2037 | } |
1995 | } | 2038 | } |
1996 | 2039 | ||
@@ -2010,23 +2053,26 @@ mod false_negatives { | |||
2010 | 2053 | ||
2011 | #[test] | 2054 | #[test] |
2012 | fn integers() { | 2055 | fn integers() { |
2013 | let content = r" | 2056 | // This is a false negative. |
2057 | // We don't currently check integer exhaustiveness. | ||
2058 | check_no_diagnostic( | ||
2059 | r" | ||
2014 | fn test_fn() { | 2060 | fn test_fn() { |
2015 | match 5 { | 2061 | match 5 { |
2016 | 10 => (), | 2062 | 10 => (), |
2017 | 11..20 => (), | 2063 | 11..20 => (), |
2018 | } | 2064 | } |
2019 | } | 2065 | } |
2020 | "; | 2066 | ", |
2021 | 2067 | ); | |
2022 | // This is a false negative. | ||
2023 | // We don't currently check integer exhaustiveness. | ||
2024 | check_no_diagnostic(content); | ||
2025 | } | 2068 | } |
2026 | 2069 | ||
2027 | #[test] | 2070 | #[test] |
2028 | fn internal_or() { | 2071 | fn internal_or() { |
2029 | let content = r" | 2072 | // This is a false negative. |
2073 | // We do not currently handle patterns with internal `or`s. | ||
2074 | check_no_diagnostic( | ||
2075 | r" | ||
2030 | fn test_fn() { | 2076 | fn test_fn() { |
2031 | enum Either { | 2077 | enum Either { |
2032 | A(bool), | 2078 | A(bool), |
@@ -2036,16 +2082,18 @@ mod false_negatives { | |||
2036 | Either::A(true | false) => (), | 2082 | Either::A(true | false) => (), |
2037 | } | 2083 | } |
2038 | } | 2084 | } |
2039 | "; | 2085 | ", |
2040 | 2086 | ); | |
2041 | // This is a false negative. | ||
2042 | // We do not currently handle patterns with internal `or`s. | ||
2043 | check_no_diagnostic(content); | ||
2044 | } | 2087 | } |
2045 | 2088 | ||
2046 | #[test] | 2089 | #[test] |
2047 | fn expr_loop_missing_arm() { | 2090 | fn expr_loop_missing_arm() { |
2048 | let content = r" | 2091 | // This is a false negative. |
2092 | // We currently infer the type of `loop { break Foo::A }` to `!`, which | ||
2093 | // causes us to skip the diagnostic since `Either::A` doesn't type check | ||
2094 | // with `!`. | ||
2095 | check_diagnostic( | ||
2096 | r" | ||
2049 | enum Either { | 2097 | enum Either { |
2050 | A, | 2098 | A, |
2051 | B, | 2099 | B, |
@@ -2055,48 +2103,46 @@ mod false_negatives { | |||
2055 | Either::A => (), | 2103 | Either::A => (), |
2056 | } | 2104 | } |
2057 | } | 2105 | } |
2058 | "; | 2106 | ", |
2059 | 2107 | ); | |
2060 | // This is a false negative. | ||
2061 | // We currently infer the type of `loop { break Foo::A }` to `!`, which | ||
2062 | // causes us to skip the diagnostic since `Either::A` doesn't type check | ||
2063 | // with `!`. | ||
2064 | check_diagnostic(content); | ||
2065 | } | 2108 | } |
2066 | 2109 | ||
2067 | #[test] | 2110 | #[test] |
2068 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { | 2111 | fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { |
2069 | let content = r" | 2112 | // This is a false negative. |
2113 | // We don't currently handle tuple patterns with ellipsis. | ||
2114 | check_no_diagnostic( | ||
2115 | r" | ||
2070 | fn test_fn() { | 2116 | fn test_fn() { |
2071 | match (false, true, false) { | 2117 | match (false, true, false) { |
2072 | (false, ..) => {}, | 2118 | (false, ..) => {}, |
2073 | } | 2119 | } |
2074 | } | 2120 | } |
2075 | "; | 2121 | ", |
2076 | 2122 | ); | |
2077 | // This is a false negative. | ||
2078 | // We don't currently handle tuple patterns with ellipsis. | ||
2079 | check_no_diagnostic(content); | ||
2080 | } | 2123 | } |
2081 | 2124 | ||
2082 | #[test] | 2125 | #[test] |
2083 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { | 2126 | fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { |
2084 | let content = r" | 2127 | // This is a false negative. |
2128 | // We don't currently handle tuple patterns with ellipsis. | ||
2129 | check_no_diagnostic( | ||
2130 | r" | ||
2085 | fn test_fn() { | 2131 | fn test_fn() { |
2086 | match (false, true, false) { | 2132 | match (false, true, false) { |
2087 | (.., false) => {}, | 2133 | (.., false) => {}, |
2088 | } | 2134 | } |
2089 | } | 2135 | } |
2090 | "; | 2136 | ", |
2091 | 2137 | ); | |
2092 | // This is a false negative. | ||
2093 | // We don't currently handle tuple patterns with ellipsis. | ||
2094 | check_no_diagnostic(content); | ||
2095 | } | 2138 | } |
2096 | 2139 | ||
2097 | #[test] | 2140 | #[test] |
2098 | fn struct_missing_arm() { | 2141 | fn struct_missing_arm() { |
2099 | let content = r" | 2142 | // This is a false negative. |
2143 | // We don't currently handle structs. | ||
2144 | check_no_diagnostic( | ||
2145 | r" | ||
2100 | struct Foo { | 2146 | struct Foo { |
2101 | a: bool, | 2147 | a: bool, |
2102 | } | 2148 | } |
@@ -2105,10 +2151,7 @@ mod false_negatives { | |||
2105 | Foo { a: true } => {}, | 2151 | Foo { a: true } => {}, |
2106 | } | 2152 | } |
2107 | } | 2153 | } |
2108 | "; | 2154 | ", |
2109 | 2155 | ); | |
2110 | // This is a false negative. | ||
2111 | // We don't currently handle structs. | ||
2112 | check_no_diagnostic(content); | ||
2113 | } | 2156 | } |
2114 | } | 2157 | } |
diff --git a/crates/ra_hir_ty/src/db.rs b/crates/ra_hir_ty/src/db.rs index bf71d38d6..7889b8d2c 100644 --- a/crates/ra_hir_ty/src/db.rs +++ b/crates/ra_hir_ty/src/db.rs | |||
@@ -3,15 +3,15 @@ | |||
3 | use std::sync::Arc; | 3 | use std::sync::Arc; |
4 | 4 | ||
5 | use hir_def::{ | 5 | use hir_def::{ |
6 | db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TraitId, | 6 | db::DefDatabase, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId, TypeParamId, |
7 | TypeParamId, VariantId, | 7 | VariantId, |
8 | }; | 8 | }; |
9 | use ra_arena::map::ArenaMap; | 9 | use ra_arena::map::ArenaMap; |
10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; | 10 | use ra_db::{impl_intern_key, salsa, CrateId, Upcast}; |
11 | use ra_prof::profile; | 11 | use ra_prof::profile; |
12 | 12 | ||
13 | use crate::{ | 13 | use crate::{ |
14 | method_resolution::{CrateImplDefs, TyFingerprint}, | 14 | method_resolution::CrateImplDefs, |
15 | traits::{chalk, AssocTyValue, Impl}, | 15 | traits::{chalk, AssocTyValue, Impl}, |
16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, | 16 | Binders, CallableDef, GenericPredicate, InferenceResult, OpaqueTyId, PolyFnSig, |
17 | ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, | 17 | ReturnTypeImplTraits, Substs, TraitRef, Ty, TyDefId, TypeCtor, ValueTyDefId, |
@@ -70,13 +70,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> { | |||
70 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] | 70 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_in_crate_query)] |
71 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; | 71 | fn impls_in_crate(&self, krate: CrateId) -> Arc<CrateImplDefs>; |
72 | 72 | ||
73 | #[salsa::invoke(crate::traits::impls_for_trait_query)] | 73 | #[salsa::invoke(crate::method_resolution::CrateImplDefs::impls_from_deps_query)] |
74 | fn impls_for_trait( | 74 | fn impls_from_deps(&self, krate: CrateId) -> Arc<CrateImplDefs>; |
75 | &self, | ||
76 | krate: CrateId, | ||
77 | trait_: TraitId, | ||
78 | self_ty_fp: Option<TyFingerprint>, | ||
79 | ) -> Arc<[ImplId]>; | ||
80 | 75 | ||
81 | // Interned IDs for Chalk integration | 76 | // Interned IDs for Chalk integration |
82 | #[salsa::interned] | 77 | #[salsa::interned] |
diff --git a/crates/ra_hir_ty/src/diagnostics.rs b/crates/ra_hir_ty/src/diagnostics.rs index 2c7298714..ebd9cb08f 100644 --- a/crates/ra_hir_ty/src/diagnostics.rs +++ b/crates/ra_hir_ty/src/diagnostics.rs | |||
@@ -6,7 +6,7 @@ use hir_expand::{db::AstDatabase, name::Name, HirFileId, InFile}; | |||
6 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; | 6 | use ra_syntax::{ast, AstNode, AstPtr, SyntaxNodePtr}; |
7 | use stdx::format_to; | 7 | use stdx::format_to; |
8 | 8 | ||
9 | pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm}; | 9 | pub use hir_def::{diagnostics::UnresolvedModule, expr::MatchArm, path::Path}; |
10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; | 10 | pub use hir_expand::diagnostics::{AstDiagnostic, Diagnostic, DiagnosticSink}; |
11 | 11 | ||
12 | #[derive(Debug)] | 12 | #[derive(Debug)] |
@@ -29,6 +29,16 @@ impl Diagnostic for NoSuchField { | |||
29 | } | 29 | } |
30 | } | 30 | } |
31 | 31 | ||
32 | impl AstDiagnostic for NoSuchField { | ||
33 | type AST = ast::RecordField; | ||
34 | |||
35 | fn ast(&self, db: &impl AstDatabase) -> Self::AST { | ||
36 | let root = db.parse_or_expand(self.source().file_id).unwrap(); | ||
37 | let node = self.source().value.to_node(&root); | ||
38 | ast::RecordField::cast(node).unwrap() | ||
39 | } | ||
40 | } | ||
41 | |||
32 | #[derive(Debug)] | 42 | #[derive(Debug)] |
33 | pub struct MissingFields { | 43 | pub struct MissingFields { |
34 | pub file: HirFileId, | 44 | pub file: HirFileId, |
diff --git a/crates/ra_hir_ty/src/infer/expr.rs b/crates/ra_hir_ty/src/infer/expr.rs index 9fd310f69..a9565a58d 100644 --- a/crates/ra_hir_ty/src/infer/expr.rs +++ b/crates/ra_hir_ty/src/infer/expr.rs | |||
@@ -10,12 +10,12 @@ use hir_def::{ | |||
10 | resolver::resolver_for_expr, | 10 | resolver::resolver_for_expr, |
11 | AdtId, AssocContainerId, FieldId, Lookup, | 11 | AdtId, AssocContainerId, FieldId, Lookup, |
12 | }; | 12 | }; |
13 | use hir_expand::name::Name; | 13 | use hir_expand::name::{name, Name}; |
14 | use ra_syntax::ast::RangeOp; | 14 | use ra_syntax::ast::RangeOp; |
15 | 15 | ||
16 | use crate::{ | 16 | use crate::{ |
17 | autoderef, method_resolution, op, | 17 | autoderef, method_resolution, op, |
18 | traits::InEnvironment, | 18 | traits::{FnTrait, InEnvironment}, |
19 | utils::{generics, variant_data, Generics}, | 19 | utils::{generics, variant_data, Generics}, |
20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, | 20 | ApplicationTy, Binders, CallableDef, InferTy, IntTy, Mutability, Obligation, Rawness, Substs, |
21 | TraitRef, Ty, TypeCtor, | 21 | TraitRef, Ty, TypeCtor, |
@@ -63,6 +63,58 @@ impl<'a> InferenceContext<'a> { | |||
63 | self.resolve_ty_as_possible(ty) | 63 | self.resolve_ty_as_possible(ty) |
64 | } | 64 | } |
65 | 65 | ||
66 | fn callable_sig_from_fn_trait(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
67 | let krate = self.resolver.krate()?; | ||
68 | let fn_once_trait = FnTrait::FnOnce.get_id(self.db, krate)?; | ||
69 | let output_assoc_type = | ||
70 | self.db.trait_data(fn_once_trait).associated_type_by_name(&name![Output])?; | ||
71 | let generic_params = generics(self.db.upcast(), fn_once_trait.into()); | ||
72 | if generic_params.len() != 2 { | ||
73 | return None; | ||
74 | } | ||
75 | |||
76 | let mut param_builder = Substs::builder(num_args); | ||
77 | let mut arg_tys = vec![]; | ||
78 | for _ in 0..num_args { | ||
79 | let arg = self.table.new_type_var(); | ||
80 | param_builder = param_builder.push(arg.clone()); | ||
81 | arg_tys.push(arg); | ||
82 | } | ||
83 | let parameters = param_builder.build(); | ||
84 | let arg_ty = Ty::Apply(ApplicationTy { | ||
85 | ctor: TypeCtor::Tuple { cardinality: num_args as u16 }, | ||
86 | parameters, | ||
87 | }); | ||
88 | let substs = Substs::build_for_generics(&generic_params) | ||
89 | .push(ty.clone()) | ||
90 | .push(arg_ty.clone()) | ||
91 | .build(); | ||
92 | |||
93 | let trait_env = Arc::clone(&self.trait_env); | ||
94 | let implements_fn_trait = | ||
95 | Obligation::Trait(TraitRef { trait_: fn_once_trait, substs: substs.clone() }); | ||
96 | let goal = self.canonicalizer().canonicalize_obligation(InEnvironment { | ||
97 | value: implements_fn_trait.clone(), | ||
98 | environment: trait_env, | ||
99 | }); | ||
100 | if self.db.trait_solve(krate, goal.value).is_some() { | ||
101 | self.obligations.push(implements_fn_trait); | ||
102 | let output_proj_ty = | ||
103 | crate::ProjectionTy { associated_ty: output_assoc_type, parameters: substs }; | ||
104 | let return_ty = self.normalize_projection_ty(output_proj_ty); | ||
105 | Some((arg_tys, return_ty)) | ||
106 | } else { | ||
107 | None | ||
108 | } | ||
109 | } | ||
110 | |||
111 | pub fn callable_sig(&mut self, ty: &Ty, num_args: usize) -> Option<(Vec<Ty>, Ty)> { | ||
112 | match ty.callable_sig(self.db) { | ||
113 | Some(sig) => Some((sig.params().to_vec(), sig.ret().clone())), | ||
114 | None => self.callable_sig_from_fn_trait(ty, num_args), | ||
115 | } | ||
116 | } | ||
117 | |||
66 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { | 118 | fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty { |
67 | let body = Arc::clone(&self.body); // avoid borrow checker problem | 119 | let body = Arc::clone(&self.body); // avoid borrow checker problem |
68 | let ty = match &body[tgt_expr] { | 120 | let ty = match &body[tgt_expr] { |
@@ -198,14 +250,23 @@ impl<'a> InferenceContext<'a> { | |||
198 | } | 250 | } |
199 | Expr::Call { callee, args } => { | 251 | Expr::Call { callee, args } => { |
200 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); | 252 | let callee_ty = self.infer_expr(*callee, &Expectation::none()); |
201 | let (param_tys, ret_ty) = match callee_ty.callable_sig(self.db) { | 253 | let canonicalized = self.canonicalizer().canonicalize_ty(callee_ty.clone()); |
202 | Some(sig) => (sig.params().to_vec(), sig.ret().clone()), | 254 | let mut derefs = autoderef( |
203 | None => { | 255 | self.db, |
204 | // Not callable | 256 | self.resolver.krate(), |
205 | // FIXME: report an error | 257 | InEnvironment { |
206 | (Vec::new(), Ty::Unknown) | 258 | value: canonicalized.value.clone(), |
207 | } | 259 | environment: self.trait_env.clone(), |
208 | }; | 260 | }, |
261 | ); | ||
262 | let (param_tys, ret_ty): (Vec<Ty>, Ty) = derefs | ||
263 | .find_map(|callee_deref_ty| { | ||
264 | self.callable_sig( | ||
265 | &canonicalized.decanonicalize_ty(callee_deref_ty.value), | ||
266 | args.len(), | ||
267 | ) | ||
268 | }) | ||
269 | .unwrap_or((Vec::new(), Ty::Unknown)); | ||
209 | self.register_obligations_for_call(&callee_ty); | 270 | self.register_obligations_for_call(&callee_ty); |
210 | self.check_call_arguments(args, ¶m_tys); | 271 | self.check_call_arguments(args, ¶m_tys); |
211 | self.normalize_associated_types_in(ret_ty) | 272 | self.normalize_associated_types_in(ret_ty) |
diff --git a/crates/ra_hir_ty/src/infer/path.rs b/crates/ra_hir_ty/src/infer/path.rs index 1ad0d8397..80d7ed10e 100644 --- a/crates/ra_hir_ty/src/infer/path.rs +++ b/crates/ra_hir_ty/src/infer/path.rs | |||
@@ -81,7 +81,7 @@ impl<'a> InferenceContext<'a> { | |||
81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); | 81 | let generics = crate::utils::generics(self.db.upcast(), impl_id.into()); |
82 | let substs = Substs::type_params_for_generics(&generics); | 82 | let substs = Substs::type_params_for_generics(&generics); |
83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); | 83 | let ty = self.db.impl_self_ty(impl_id).subst(&substs); |
84 | if let Some((AdtId::StructId(struct_id), _)) = ty.as_adt() { | 84 | if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() { |
85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); | 85 | let ty = self.db.value_ty(struct_id.into()).subst(&substs); |
86 | return Some(ty); | 86 | return Some(ty); |
87 | } else { | 87 | } else { |
diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 2b9372b4b..f22232324 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs | |||
@@ -73,6 +73,7 @@ pub use lower::{ | |||
73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; | 73 | pub use traits::{InEnvironment, Obligation, ProjectionPredicate, TraitEnvironment}; |
74 | 74 | ||
75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; | 75 | pub use chalk_ir::{BoundVar, DebruijnIndex}; |
76 | use itertools::Itertools; | ||
76 | 77 | ||
77 | /// A type constructor or type name: this might be something like the primitive | 78 | /// A type constructor or type name: this might be something like the primitive |
78 | /// type `bool`, a struct like `Vec`, or things like function pointers or | 79 | /// type `bool`, a struct like `Vec`, or things like function pointers or |
@@ -815,6 +816,11 @@ impl Ty { | |||
815 | } | 816 | } |
816 | } | 817 | } |
817 | 818 | ||
819 | /// If this is a `dyn Trait`, returns that trait. | ||
820 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
821 | self.dyn_trait_ref().map(|it| it.trait_) | ||
822 | } | ||
823 | |||
818 | fn builtin_deref(&self) -> Option<Ty> { | 824 | fn builtin_deref(&self) -> Option<Ty> { |
819 | match self { | 825 | match self { |
820 | Ty::Apply(a_ty) => match a_ty.ctor { | 826 | Ty::Apply(a_ty) => match a_ty.ctor { |
@@ -867,13 +873,56 @@ impl Ty { | |||
867 | } | 873 | } |
868 | } | 874 | } |
869 | 875 | ||
870 | /// If this is a `dyn Trait`, returns that trait. | 876 | pub fn impl_trait_bounds(&self, db: &dyn HirDatabase) -> Option<Vec<GenericPredicate>> { |
871 | pub fn dyn_trait(&self) -> Option<TraitId> { | ||
872 | match self { | 877 | match self { |
873 | Ty::Dyn(predicates) => predicates.iter().find_map(|pred| match pred { | 878 | Ty::Opaque(opaque_ty) => { |
874 | GenericPredicate::Implemented(tr) => Some(tr.trait_), | 879 | let predicates = match opaque_ty.opaque_ty_id { |
875 | _ => None, | 880 | OpaqueTyId::ReturnTypeImplTrait(func, idx) => { |
876 | }), | 881 | db.return_type_impl_traits(func).map(|it| { |
882 | let data = (*it) | ||
883 | .as_ref() | ||
884 | .map(|rpit| rpit.impl_traits[idx as usize].bounds.clone()); | ||
885 | data.clone().subst(&opaque_ty.parameters) | ||
886 | }) | ||
887 | } | ||
888 | }; | ||
889 | |||
890 | predicates.map(|it| it.value) | ||
891 | } | ||
892 | Ty::Placeholder(id) => { | ||
893 | let generic_params = db.generic_params(id.parent); | ||
894 | let param_data = &generic_params.types[id.local_id]; | ||
895 | match param_data.provenance { | ||
896 | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => { | ||
897 | let predicates = db | ||
898 | .generic_predicates_for_param(*id) | ||
899 | .into_iter() | ||
900 | .map(|pred| pred.value.clone()) | ||
901 | .collect_vec(); | ||
902 | |||
903 | Some(predicates) | ||
904 | } | ||
905 | _ => None, | ||
906 | } | ||
907 | } | ||
908 | _ => None, | ||
909 | } | ||
910 | } | ||
911 | |||
912 | pub fn associated_type_parent_trait(&self, db: &dyn HirDatabase) -> Option<TraitId> { | ||
913 | match self { | ||
914 | Ty::Apply(ApplicationTy { ctor: TypeCtor::AssociatedType(type_alias_id), .. }) => { | ||
915 | match type_alias_id.lookup(db.upcast()).container { | ||
916 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
917 | _ => None, | ||
918 | } | ||
919 | } | ||
920 | Ty::Projection(projection_ty) => { | ||
921 | match projection_ty.associated_ty.lookup(db.upcast()).container { | ||
922 | AssocContainerId::TraitId(trait_id) => Some(trait_id), | ||
923 | _ => None, | ||
924 | } | ||
925 | } | ||
877 | _ => None, | 926 | _ => None, |
878 | } | 927 | } |
879 | } | 928 | } |
@@ -1057,5 +1106,5 @@ pub struct ReturnTypeImplTraits { | |||
1057 | 1106 | ||
1058 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] | 1107 | #[derive(Clone, PartialEq, Eq, Debug, Hash)] |
1059 | pub(crate) struct ReturnTypeImplTrait { | 1108 | pub(crate) struct ReturnTypeImplTrait { |
1060 | pub(crate) bounds: Binders<Vec<GenericPredicate>>, | 1109 | pub bounds: Binders<Vec<GenericPredicate>>, |
1061 | } | 1110 | } |
diff --git a/crates/ra_hir_ty/src/lower.rs b/crates/ra_hir_ty/src/lower.rs index 42713928f..d5154f436 100644 --- a/crates/ra_hir_ty/src/lower.rs +++ b/crates/ra_hir_ty/src/lower.rs | |||
@@ -337,17 +337,17 @@ impl Ty { | |||
337 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); | 337 | TraitRef::from_resolved_path(ctx, trait_, resolved_segment, self_ty); |
338 | let ty = if remaining_segments.len() == 1 { | 338 | let ty = if remaining_segments.len() == 1 { |
339 | let segment = remaining_segments.first().unwrap(); | 339 | let segment = remaining_segments.first().unwrap(); |
340 | let associated_ty = associated_type_by_name_including_super_traits( | 340 | let found = associated_type_by_name_including_super_traits( |
341 | ctx.db.upcast(), | 341 | ctx.db, |
342 | trait_ref.trait_, | 342 | trait_ref.clone(), |
343 | &segment.name, | 343 | &segment.name, |
344 | ); | 344 | ); |
345 | match associated_ty { | 345 | match found { |
346 | Some(associated_ty) => { | 346 | Some((super_trait_ref, associated_ty)) => { |
347 | // FIXME handle type parameters on the segment | 347 | // FIXME handle type parameters on the segment |
348 | Ty::Projection(ProjectionTy { | 348 | Ty::Projection(ProjectionTy { |
349 | associated_ty, | 349 | associated_ty, |
350 | parameters: trait_ref.substs, | 350 | parameters: super_trait_ref.substs, |
351 | }) | 351 | }) |
352 | } | 352 | } |
353 | None => { | 353 | None => { |
@@ -467,6 +467,9 @@ impl Ty { | |||
467 | } | 467 | } |
468 | TypeParamLoweringMode::Variable => t.substs.clone(), | 468 | TypeParamLoweringMode::Variable => t.substs.clone(), |
469 | }; | 469 | }; |
470 | // We need to shift in the bound vars, since | ||
471 | // associated_type_shorthand_candidates does not do that | ||
472 | let substs = substs.shift_bound_vars(ctx.in_binders); | ||
470 | // FIXME handle type parameters on the segment | 473 | // FIXME handle type parameters on the segment |
471 | return Some(Ty::Projection(ProjectionTy { | 474 | return Some(Ty::Projection(ProjectionTy { |
472 | associated_ty, | 475 | associated_ty, |
@@ -706,17 +709,17 @@ fn assoc_type_bindings_from_type_bound<'a>( | |||
706 | .flat_map(|segment| segment.args_and_bindings.into_iter()) | 709 | .flat_map(|segment| segment.args_and_bindings.into_iter()) |
707 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) | 710 | .flat_map(|args_and_bindings| args_and_bindings.bindings.iter()) |
708 | .flat_map(move |binding| { | 711 | .flat_map(move |binding| { |
709 | let associated_ty = associated_type_by_name_including_super_traits( | 712 | let found = associated_type_by_name_including_super_traits( |
710 | ctx.db.upcast(), | 713 | ctx.db, |
711 | trait_ref.trait_, | 714 | trait_ref.clone(), |
712 | &binding.name, | 715 | &binding.name, |
713 | ); | 716 | ); |
714 | let associated_ty = match associated_ty { | 717 | let (super_trait_ref, associated_ty) = match found { |
715 | None => return SmallVec::<[GenericPredicate; 1]>::new(), | 718 | None => return SmallVec::<[GenericPredicate; 1]>::new(), |
716 | Some(t) => t, | 719 | Some(t) => t, |
717 | }; | 720 | }; |
718 | let projection_ty = | 721 | let projection_ty = |
719 | ProjectionTy { associated_ty, parameters: trait_ref.substs.clone() }; | 722 | ProjectionTy { associated_ty, parameters: super_trait_ref.substs.clone() }; |
720 | let mut preds = SmallVec::with_capacity( | 723 | let mut preds = SmallVec::with_capacity( |
721 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), | 724 | binding.type_ref.as_ref().map_or(0, |_| 1) + binding.bounds.len(), |
722 | ); | 725 | ); |
diff --git a/crates/ra_hir_ty/src/method_resolution.rs b/crates/ra_hir_ty/src/method_resolution.rs index e83b39456..ed638c195 100644 --- a/crates/ra_hir_ty/src/method_resolution.rs +++ b/crates/ra_hir_ty/src/method_resolution.rs | |||
@@ -38,18 +38,53 @@ impl TyFingerprint { | |||
38 | } | 38 | } |
39 | } | 39 | } |
40 | 40 | ||
41 | /// A queryable and mergeable collection of impls. | ||
41 | #[derive(Debug, PartialEq, Eq)] | 42 | #[derive(Debug, PartialEq, Eq)] |
42 | pub struct CrateImplDefs { | 43 | pub struct CrateImplDefs { |
43 | impls: FxHashMap<TyFingerprint, Vec<ImplId>>, | 44 | inherent_impls: FxHashMap<TyFingerprint, Vec<ImplId>>, |
44 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, | 45 | impls_by_trait: FxHashMap<TraitId, FxHashMap<Option<TyFingerprint>, Vec<ImplId>>>, |
45 | } | 46 | } |
46 | 47 | ||
47 | impl CrateImplDefs { | 48 | impl CrateImplDefs { |
48 | pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { | 49 | pub(crate) fn impls_in_crate_query(db: &dyn HirDatabase, krate: CrateId) -> Arc<CrateImplDefs> { |
49 | let _p = profile("impls_in_crate_query"); | 50 | let _p = profile("impls_in_crate_query"); |
50 | let mut res = | 51 | let mut res = CrateImplDefs { |
51 | CrateImplDefs { impls: FxHashMap::default(), impls_by_trait: FxHashMap::default() }; | 52 | inherent_impls: FxHashMap::default(), |
53 | impls_by_trait: FxHashMap::default(), | ||
54 | }; | ||
55 | res.fill(db, krate); | ||
56 | |||
57 | Arc::new(res) | ||
58 | } | ||
59 | |||
60 | /// Collects all impls from transitive dependencies of `krate` that may be used by `krate`. | ||
61 | /// | ||
62 | /// The full set of impls that can be used by `krate` is the returned map plus all the impls | ||
63 | /// from `krate` itself. | ||
64 | pub(crate) fn impls_from_deps_query( | ||
65 | db: &dyn HirDatabase, | ||
66 | krate: CrateId, | ||
67 | ) -> Arc<CrateImplDefs> { | ||
68 | let _p = profile("impls_from_deps_query"); | ||
69 | let crate_graph = db.crate_graph(); | ||
70 | let mut res = CrateImplDefs { | ||
71 | inherent_impls: FxHashMap::default(), | ||
72 | impls_by_trait: FxHashMap::default(), | ||
73 | }; | ||
52 | 74 | ||
75 | // For each dependency, calculate `impls_from_deps` recursively, then add its own | ||
76 | // `impls_in_crate`. | ||
77 | // As we might visit crates multiple times, `merge` has to deduplicate impls to avoid | ||
78 | // wasting memory. | ||
79 | for dep in &crate_graph[krate].dependencies { | ||
80 | res.merge(&db.impls_from_deps(dep.crate_id)); | ||
81 | res.merge(&db.impls_in_crate(dep.crate_id)); | ||
82 | } | ||
83 | |||
84 | Arc::new(res) | ||
85 | } | ||
86 | |||
87 | fn fill(&mut self, db: &dyn HirDatabase, krate: CrateId) { | ||
53 | let crate_def_map = db.crate_def_map(krate); | 88 | let crate_def_map = db.crate_def_map(krate); |
54 | for (_module_id, module_data) in crate_def_map.modules.iter() { | 89 | for (_module_id, module_data) in crate_def_map.modules.iter() { |
55 | for impl_id in module_data.scope.impls() { | 90 | for impl_id in module_data.scope.impls() { |
@@ -57,7 +92,7 @@ impl CrateImplDefs { | |||
57 | Some(tr) => { | 92 | Some(tr) => { |
58 | let self_ty = db.impl_self_ty(impl_id); | 93 | let self_ty = db.impl_self_ty(impl_id); |
59 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); | 94 | let self_ty_fp = TyFingerprint::for_impl(&self_ty.value); |
60 | res.impls_by_trait | 95 | self.impls_by_trait |
61 | .entry(tr.value.trait_) | 96 | .entry(tr.value.trait_) |
62 | .or_default() | 97 | .or_default() |
63 | .entry(self_ty_fp) | 98 | .entry(self_ty_fp) |
@@ -67,18 +102,36 @@ impl CrateImplDefs { | |||
67 | None => { | 102 | None => { |
68 | let self_ty = db.impl_self_ty(impl_id); | 103 | let self_ty = db.impl_self_ty(impl_id); |
69 | if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { | 104 | if let Some(self_ty_fp) = TyFingerprint::for_impl(&self_ty.value) { |
70 | res.impls.entry(self_ty_fp).or_default().push(impl_id); | 105 | self.inherent_impls.entry(self_ty_fp).or_default().push(impl_id); |
71 | } | 106 | } |
72 | } | 107 | } |
73 | } | 108 | } |
74 | } | 109 | } |
75 | } | 110 | } |
111 | } | ||
76 | 112 | ||
77 | Arc::new(res) | 113 | fn merge(&mut self, other: &Self) { |
114 | for (fp, impls) in &other.inherent_impls { | ||
115 | let vec = self.inherent_impls.entry(*fp).or_default(); | ||
116 | vec.extend(impls); | ||
117 | vec.sort(); | ||
118 | vec.dedup(); | ||
119 | } | ||
120 | |||
121 | for (trait_, other_map) in &other.impls_by_trait { | ||
122 | let map = self.impls_by_trait.entry(*trait_).or_default(); | ||
123 | for (fp, impls) in other_map { | ||
124 | let vec = map.entry(*fp).or_default(); | ||
125 | vec.extend(impls); | ||
126 | vec.sort(); | ||
127 | vec.dedup(); | ||
128 | } | ||
129 | } | ||
78 | } | 130 | } |
131 | |||
79 | pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { | 132 | pub fn lookup_impl_defs(&self, ty: &Ty) -> impl Iterator<Item = ImplId> + '_ { |
80 | let fingerprint = TyFingerprint::for_impl(ty); | 133 | let fingerprint = TyFingerprint::for_impl(ty); |
81 | fingerprint.and_then(|f| self.impls.get(&f)).into_iter().flatten().copied() | 134 | fingerprint.and_then(|f| self.inherent_impls.get(&f)).into_iter().flatten().copied() |
82 | } | 135 | } |
83 | 136 | ||
84 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { | 137 | pub fn lookup_impl_defs_for_trait(&self, tr: TraitId) -> impl Iterator<Item = ImplId> + '_ { |
@@ -110,7 +163,7 @@ impl CrateImplDefs { | |||
110 | } | 163 | } |
111 | 164 | ||
112 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { | 165 | pub fn all_impls<'a>(&'a self) -> impl Iterator<Item = ImplId> + 'a { |
113 | self.impls | 166 | self.inherent_impls |
114 | .values() | 167 | .values() |
115 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) | 168 | .chain(self.impls_by_trait.values().flat_map(|m| m.values())) |
116 | .flatten() | 169 | .flatten() |
diff --git a/crates/ra_hir_ty/src/tests/regression.rs b/crates/ra_hir_ty/src/tests/regression.rs index 1f004bd63..4da2e972b 100644 --- a/crates/ra_hir_ty/src/tests/regression.rs +++ b/crates/ra_hir_ty/src/tests/regression.rs | |||
@@ -633,3 +633,154 @@ where | |||
633 | "### | 633 | "### |
634 | ); | 634 | ); |
635 | } | 635 | } |
636 | |||
637 | #[test] | ||
638 | fn issue_4953() { | ||
639 | assert_snapshot!( | ||
640 | infer(r#" | ||
641 | pub struct Foo(pub i64); | ||
642 | impl Foo { | ||
643 | fn test() -> Self { Self(0i64) } | ||
644 | } | ||
645 | "#), | ||
646 | @r###" | ||
647 | 59..73 '{ Self(0i64) }': Foo | ||
648 | 61..65 'Self': Foo(i64) -> Foo | ||
649 | 61..71 'Self(0i64)': Foo | ||
650 | 66..70 '0i64': i64 | ||
651 | "### | ||
652 | ); | ||
653 | assert_snapshot!( | ||
654 | infer(r#" | ||
655 | pub struct Foo<T>(pub T); | ||
656 | impl Foo<i64> { | ||
657 | fn test() -> Self { Self(0i64) } | ||
658 | } | ||
659 | "#), | ||
660 | @r###" | ||
661 | 65..79 '{ Self(0i64) }': Foo<i64> | ||
662 | 67..71 'Self': Foo<i64>(i64) -> Foo<i64> | ||
663 | 67..77 'Self(0i64)': Foo<i64> | ||
664 | 72..76 '0i64': i64 | ||
665 | "### | ||
666 | ); | ||
667 | } | ||
668 | |||
669 | #[test] | ||
670 | fn issue_4931() { | ||
671 | assert_snapshot!( | ||
672 | infer(r#" | ||
673 | trait Div<T> { | ||
674 | type Output; | ||
675 | } | ||
676 | |||
677 | trait CheckedDiv: Div<()> {} | ||
678 | |||
679 | trait PrimInt: CheckedDiv<Output = ()> { | ||
680 | fn pow(self); | ||
681 | } | ||
682 | |||
683 | fn check<T: PrimInt>(i: T) { | ||
684 | i.pow(); | ||
685 | } | ||
686 | "#), | ||
687 | @r###" | ||
688 | 118..122 'self': Self | ||
689 | 149..150 'i': T | ||
690 | 155..171 '{ ...w(); }': () | ||
691 | 161..162 'i': T | ||
692 | 161..168 'i.pow()': () | ||
693 | "### | ||
694 | ); | ||
695 | } | ||
696 | |||
697 | #[test] | ||
698 | fn issue_4885() { | ||
699 | assert_snapshot!( | ||
700 | infer(r#" | ||
701 | #[lang = "coerce_unsized"] | ||
702 | pub trait CoerceUnsized<T> {} | ||
703 | |||
704 | trait Future { | ||
705 | type Output; | ||
706 | } | ||
707 | trait Foo<R> { | ||
708 | type Bar; | ||
709 | } | ||
710 | fn foo<R, K>(key: &K) -> impl Future<Output = K::Bar> | ||
711 | where | ||
712 | K: Foo<R>, | ||
713 | { | ||
714 | bar(key) | ||
715 | } | ||
716 | fn bar<R, K>(key: &K) -> impl Future<Output = K::Bar> | ||
717 | where | ||
718 | K: Foo<R>, | ||
719 | { | ||
720 | } | ||
721 | "#), | ||
722 | @r###" | ||
723 | 137..140 'key': &K | ||
724 | 199..215 '{ ...key) }': impl Future<Output = <K as Foo<R>>::Bar> | ||
725 | 205..208 'bar': fn bar<R, K>(&K) -> impl Future<Output = <K as Foo<R>>::Bar> | ||
726 | 205..213 'bar(key)': impl Future<Output = <K as Foo<R>>::Bar> | ||
727 | 209..212 'key': &K | ||
728 | 229..232 'key': &K | ||
729 | 291..294 '{ }': () | ||
730 | "### | ||
731 | ); | ||
732 | } | ||
733 | |||
734 | #[test] | ||
735 | fn issue_4800() { | ||
736 | assert_snapshot!( | ||
737 | infer(r#" | ||
738 | trait Debug {} | ||
739 | |||
740 | struct Foo<T>; | ||
741 | |||
742 | type E1<T> = (T, T, T); | ||
743 | type E2<T> = E1<E1<E1<(T, T, T)>>>; | ||
744 | |||
745 | impl Debug for Foo<E2<()>> {} | ||
746 | |||
747 | struct Request; | ||
748 | |||
749 | pub trait Future { | ||
750 | type Output; | ||
751 | } | ||
752 | |||
753 | pub struct PeerSet<D>; | ||
754 | |||
755 | impl<D> Service<Request> for PeerSet<D> | ||
756 | where | ||
757 | D: Discover, | ||
758 | D::Key: Debug, | ||
759 | { | ||
760 | type Error = (); | ||
761 | type Future = dyn Future<Output = Self::Error>; | ||
762 | |||
763 | fn call(&mut self) -> Self::Future { | ||
764 | loop {} | ||
765 | } | ||
766 | } | ||
767 | |||
768 | pub trait Discover { | ||
769 | type Key; | ||
770 | } | ||
771 | |||
772 | pub trait Service<Request> { | ||
773 | type Error; | ||
774 | type Future: Future<Output = Self::Error>; | ||
775 | fn call(&mut self) -> Self::Future; | ||
776 | } | ||
777 | "#), | ||
778 | @r###" | ||
779 | 380..384 'self': &mut PeerSet<D> | ||
780 | 402..425 '{ ... }': dyn Future<Output = ()> | ||
781 | 412..419 'loop {}': ! | ||
782 | 417..419 '{}': () | ||
783 | 576..580 'self': &mut Self | ||
784 | "### | ||
785 | ); | ||
786 | } | ||
diff --git a/crates/ra_hir_ty/src/tests/traits.rs b/crates/ra_hir_ty/src/tests/traits.rs index e81193a3c..961be4abd 100644 --- a/crates/ra_hir_ty/src/tests/traits.rs +++ b/crates/ra_hir_ty/src/tests/traits.rs | |||
@@ -2888,3 +2888,226 @@ impl<A: Step> iter::Iterator for ops::Range<A> { | |||
2888 | ); | 2888 | ); |
2889 | assert_eq!(t, "i32"); | 2889 | assert_eq!(t, "i32"); |
2890 | } | 2890 | } |
2891 | |||
2892 | #[test] | ||
2893 | fn infer_closure_arg() { | ||
2894 | assert_snapshot!( | ||
2895 | infer( | ||
2896 | r#" | ||
2897 | //- /lib.rs | ||
2898 | |||
2899 | enum Option<T> { | ||
2900 | None, | ||
2901 | Some(T) | ||
2902 | } | ||
2903 | |||
2904 | fn foo() { | ||
2905 | let s = Option::None; | ||
2906 | let f = |x: Option<i32>| {}; | ||
2907 | (&f)(s) | ||
2908 | } | ||
2909 | "# | ||
2910 | ), | ||
2911 | @r###" | ||
2912 | 137..259 '{ ... }': () | ||
2913 | 159..160 's': Option<i32> | ||
2914 | 163..175 'Option::None': Option<i32> | ||
2915 | 197..198 'f': |Option<i32>| -> () | ||
2916 | 201..220 '|x: Op...2>| {}': |Option<i32>| -> () | ||
2917 | 202..203 'x': Option<i32> | ||
2918 | 218..220 '{}': () | ||
2919 | 238..245 '(&f)(s)': () | ||
2920 | 239..241 '&f': &|Option<i32>| -> () | ||
2921 | 240..241 'f': |Option<i32>| -> () | ||
2922 | 243..244 's': Option<i32> | ||
2923 | "### | ||
2924 | ); | ||
2925 | } | ||
2926 | |||
2927 | #[test] | ||
2928 | fn infer_fn_trait_arg() { | ||
2929 | assert_snapshot!( | ||
2930 | infer( | ||
2931 | r#" | ||
2932 | //- /lib.rs deps:std | ||
2933 | |||
2934 | #[lang = "fn_once"] | ||
2935 | pub trait FnOnce<Args> { | ||
2936 | type Output; | ||
2937 | |||
2938 | extern "rust-call" fn call_once(&self, args: Args) -> Self::Output; | ||
2939 | } | ||
2940 | |||
2941 | #[lang = "fn"] | ||
2942 | pub trait Fn<Args>:FnOnce<Args> { | ||
2943 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
2944 | } | ||
2945 | |||
2946 | enum Option<T> { | ||
2947 | None, | ||
2948 | Some(T) | ||
2949 | } | ||
2950 | |||
2951 | fn foo<F, T>(f: F) -> T | ||
2952 | where | ||
2953 | F: Fn(Option<i32>) -> T, | ||
2954 | { | ||
2955 | let s = None; | ||
2956 | f(s) | ||
2957 | } | ||
2958 | "# | ||
2959 | ), | ||
2960 | @r###" | ||
2961 | 183..187 'self': &Self | ||
2962 | 189..193 'args': Args | ||
2963 | 350..354 'self': &Self | ||
2964 | 356..360 'args': Args | ||
2965 | 515..516 'f': F | ||
2966 | 597..663 '{ ... }': T | ||
2967 | 619..620 's': Option<i32> | ||
2968 | 623..627 'None': Option<i32> | ||
2969 | 645..646 'f': F | ||
2970 | 645..649 'f(s)': T | ||
2971 | 647..648 's': Option<i32> | ||
2972 | "### | ||
2973 | ); | ||
2974 | } | ||
2975 | |||
2976 | #[test] | ||
2977 | fn infer_box_fn_arg() { | ||
2978 | assert_snapshot!( | ||
2979 | infer( | ||
2980 | r#" | ||
2981 | //- /lib.rs deps:std | ||
2982 | |||
2983 | #[lang = "fn_once"] | ||
2984 | pub trait FnOnce<Args> { | ||
2985 | type Output; | ||
2986 | |||
2987 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
2988 | } | ||
2989 | |||
2990 | #[lang = "deref"] | ||
2991 | pub trait Deref { | ||
2992 | type Target: ?Sized; | ||
2993 | |||
2994 | fn deref(&self) -> &Self::Target; | ||
2995 | } | ||
2996 | |||
2997 | #[lang = "owned_box"] | ||
2998 | pub struct Box<T: ?Sized> { | ||
2999 | inner: *mut T, | ||
3000 | } | ||
3001 | |||
3002 | impl<T: ?Sized> Deref for Box<T> { | ||
3003 | type Target = T; | ||
3004 | |||
3005 | fn deref(&self) -> &T { | ||
3006 | &self.inner | ||
3007 | } | ||
3008 | } | ||
3009 | |||
3010 | enum Option<T> { | ||
3011 | None, | ||
3012 | Some(T) | ||
3013 | } | ||
3014 | |||
3015 | fn foo() { | ||
3016 | let s = Option::None; | ||
3017 | let f: Box<dyn FnOnce(&Option<i32>)> = box (|ps| {}); | ||
3018 | f(&s) | ||
3019 | } | ||
3020 | "# | ||
3021 | ), | ||
3022 | @r###" | ||
3023 | 182..186 'self': Self | ||
3024 | 188..192 'args': Args | ||
3025 | 356..360 'self': &Self | ||
3026 | 622..626 'self': &Box<T> | ||
3027 | 634..685 '{ ... }': &T | ||
3028 | 656..667 '&self.inner': &*mut T | ||
3029 | 657..661 'self': &Box<T> | ||
3030 | 657..667 'self.inner': *mut T | ||
3031 | 812..957 '{ ... }': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | ||
3032 | 834..835 's': Option<i32> | ||
3033 | 838..850 'Option::None': Option<i32> | ||
3034 | 872..873 'f': Box<dyn FnOnce<(&Option<i32>,)>> | ||
3035 | 907..920 'box (|ps| {})': Box<|{unknown}| -> ()> | ||
3036 | 912..919 '|ps| {}': |{unknown}| -> () | ||
3037 | 913..915 'ps': {unknown} | ||
3038 | 917..919 '{}': () | ||
3039 | 938..939 'f': Box<dyn FnOnce<(&Option<i32>,)>> | ||
3040 | 938..943 'f(&s)': FnOnce::Output<dyn FnOnce<(&Option<i32>,)>, (&Option<i32>,)> | ||
3041 | 940..942 '&s': &Option<i32> | ||
3042 | 941..942 's': Option<i32> | ||
3043 | "### | ||
3044 | ); | ||
3045 | } | ||
3046 | |||
3047 | #[test] | ||
3048 | fn infer_dyn_fn_output() { | ||
3049 | assert_snapshot!( | ||
3050 | infer( | ||
3051 | r#" | ||
3052 | //- /lib.rs deps:std | ||
3053 | |||
3054 | #[lang = "fn_once"] | ||
3055 | pub trait FnOnce<Args> { | ||
3056 | type Output; | ||
3057 | |||
3058 | extern "rust-call" fn call_once(self, args: Args) -> Self::Output; | ||
3059 | } | ||
3060 | |||
3061 | #[lang = "fn"] | ||
3062 | pub trait Fn<Args>:FnOnce<Args> { | ||
3063 | extern "rust-call" fn call(&self, args: Args) -> Self::Output; | ||
3064 | } | ||
3065 | |||
3066 | #[lang = "deref"] | ||
3067 | pub trait Deref { | ||
3068 | type Target: ?Sized; | ||
3069 | |||
3070 | fn deref(&self) -> &Self::Target; | ||
3071 | } | ||
3072 | |||
3073 | #[lang = "owned_box"] | ||
3074 | pub struct Box<T: ?Sized> { | ||
3075 | inner: *mut T, | ||
3076 | } | ||
3077 | |||
3078 | impl<T: ?Sized> Deref for Box<T> { | ||
3079 | type Target = T; | ||
3080 | |||
3081 | fn deref(&self) -> &T { | ||
3082 | &self.inner | ||
3083 | } | ||
3084 | } | ||
3085 | |||
3086 | fn foo() { | ||
3087 | let f: Box<dyn Fn() -> i32> = box(|| 5); | ||
3088 | let x = f(); | ||
3089 | } | ||
3090 | "# | ||
3091 | ), | ||
3092 | @r###" | ||
3093 | 182..186 'self': Self | ||
3094 | 188..192 'args': Args | ||
3095 | 349..353 'self': &Self | ||
3096 | 355..359 'args': Args | ||
3097 | 523..527 'self': &Self | ||
3098 | 789..793 'self': &Box<T> | ||
3099 | 801..852 '{ ... }': &T | ||
3100 | 823..834 '&self.inner': &*mut T | ||
3101 | 824..828 'self': &Box<T> | ||
3102 | 824..834 'self.inner': *mut T | ||
3103 | 889..990 '{ ... }': () | ||
3104 | 911..912 'f': Box<dyn Fn<(), Output = i32>> | ||
3105 | 937..946 'box(|| 5)': Box<|| -> i32> | ||
3106 | 941..945 '|| 5': || -> i32 | ||
3107 | 944..945 '5': i32 | ||
3108 | 968..969 'x': FnOnce::Output<dyn Fn<(), Output = i32>, ()> | ||
3109 | 972..973 'f': Box<dyn Fn<(), Output = i32>> | ||
3110 | 972..975 'f()': FnOnce::Output<dyn Fn<(), Output = i32>, ()> | ||
3111 | "### | ||
3112 | ); | ||
3113 | } | ||
diff --git a/crates/ra_hir_ty/src/traits.rs b/crates/ra_hir_ty/src/traits.rs index 6bc6d474c..6f43c3a22 100644 --- a/crates/ra_hir_ty/src/traits.rs +++ b/crates/ra_hir_ty/src/traits.rs | |||
@@ -2,12 +2,13 @@ | |||
2 | use std::{panic, sync::Arc}; | 2 | use std::{panic, sync::Arc}; |
3 | 3 | ||
4 | use chalk_ir::cast::Cast; | 4 | use chalk_ir::cast::Cast; |
5 | use hir_def::{expr::ExprId, DefWithBodyId, ImplId, TraitId, TypeAliasId}; | 5 | use hir_def::{ |
6 | expr::ExprId, lang_item::LangItemTarget, DefWithBodyId, ImplId, TraitId, TypeAliasId, | ||
7 | }; | ||
6 | use ra_db::{impl_intern_key, salsa, CrateId}; | 8 | use ra_db::{impl_intern_key, salsa, CrateId}; |
7 | use ra_prof::profile; | 9 | use ra_prof::profile; |
8 | use rustc_hash::FxHashSet; | ||
9 | 10 | ||
10 | use crate::{db::HirDatabase, method_resolution::TyFingerprint, DebruijnIndex}; | 11 | use crate::{db::HirDatabase, DebruijnIndex}; |
11 | 12 | ||
12 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; | 13 | use super::{Canonical, GenericPredicate, HirDisplay, ProjectionTy, TraitRef, Ty, TypeWalk}; |
13 | 14 | ||
@@ -36,34 +37,6 @@ fn create_chalk_solver() -> chalk_solve::Solver<Interner> { | |||
36 | solver_choice.into_solver() | 37 | solver_choice.into_solver() |
37 | } | 38 | } |
38 | 39 | ||
39 | /// Collects impls for the given trait in the whole dependency tree of `krate`. | ||
40 | pub(crate) fn impls_for_trait_query( | ||
41 | db: &dyn HirDatabase, | ||
42 | krate: CrateId, | ||
43 | trait_: TraitId, | ||
44 | self_ty_fp: Option<TyFingerprint>, | ||
45 | ) -> Arc<[ImplId]> { | ||
46 | // FIXME: We could be a lot smarter here - because of the orphan rules and | ||
47 | // the fact that the trait and the self type need to be in the dependency | ||
48 | // tree of a crate somewhere for an impl to exist, we could skip looking in | ||
49 | // a lot of crates completely | ||
50 | let mut impls = FxHashSet::default(); | ||
51 | // We call the query recursively here. On the one hand, this means we can | ||
52 | // reuse results from queries for different crates; on the other hand, this | ||
53 | // will only ever get called for a few crates near the root of the tree (the | ||
54 | // ones the user is editing), so this may actually be a waste of memory. I'm | ||
55 | // doing it like this mainly for simplicity for now. | ||
56 | for dep in &db.crate_graph()[krate].dependencies { | ||
57 | impls.extend(db.impls_for_trait(dep.crate_id, trait_, self_ty_fp).iter()); | ||
58 | } | ||
59 | let crate_impl_defs = db.impls_in_crate(krate); | ||
60 | match self_ty_fp { | ||
61 | Some(fp) => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp)), | ||
62 | None => impls.extend(crate_impl_defs.lookup_impl_defs_for_trait(trait_)), | ||
63 | } | ||
64 | impls.into_iter().collect() | ||
65 | } | ||
66 | |||
67 | /// A set of clauses that we assume to be true. E.g. if we are inside this function: | 40 | /// A set of clauses that we assume to be true. E.g. if we are inside this function: |
68 | /// ```rust | 41 | /// ```rust |
69 | /// fn foo<T: Default>(t: T) {} | 42 | /// fn foo<T: Default>(t: T) {} |
@@ -298,6 +271,14 @@ impl FnTrait { | |||
298 | FnTrait::Fn => "fn", | 271 | FnTrait::Fn => "fn", |
299 | } | 272 | } |
300 | } | 273 | } |
274 | |||
275 | pub fn get_id(&self, db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { | ||
276 | let target = db.lang_item(krate, self.lang_item_name().into())?; | ||
277 | match target { | ||
278 | LangItemTarget::TraitId(t) => Some(t), | ||
279 | _ => None, | ||
280 | } | ||
281 | } | ||
301 | } | 282 | } |
302 | 283 | ||
303 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] | 284 | #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)] |
diff --git a/crates/ra_hir_ty/src/traits/builtin.rs b/crates/ra_hir_ty/src/traits/builtin.rs index 88a422d2c..6d5f2d46a 100644 --- a/crates/ra_hir_ty/src/traits/builtin.rs +++ b/crates/ra_hir_ty/src/traits/builtin.rs | |||
@@ -40,7 +40,7 @@ pub(super) fn get_builtin_impls( | |||
40 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { | 40 | if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Closure { def, expr }, .. }) = ty { |
41 | for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() | 41 | for &fn_trait in [super::FnTrait::FnOnce, super::FnTrait::FnMut, super::FnTrait::Fn].iter() |
42 | { | 42 | { |
43 | if let Some(actual_trait) = get_fn_trait(db, krate, fn_trait) { | 43 | if let Some(actual_trait) = fn_trait.get_id(db, krate) { |
44 | if trait_ == actual_trait { | 44 | if trait_ == actual_trait { |
45 | let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; | 45 | let impl_ = super::ClosureFnTraitImplData { def: *def, expr: *expr, fn_trait }; |
46 | if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) { | 46 | if check_closure_fn_trait_impl_prerequisites(db, krate, impl_) { |
@@ -128,7 +128,7 @@ fn check_closure_fn_trait_impl_prerequisites( | |||
128 | data: super::ClosureFnTraitImplData, | 128 | data: super::ClosureFnTraitImplData, |
129 | ) -> bool { | 129 | ) -> bool { |
130 | // the respective Fn/FnOnce/FnMut trait needs to exist | 130 | // the respective Fn/FnOnce/FnMut trait needs to exist |
131 | if get_fn_trait(db, krate, data.fn_trait).is_none() { | 131 | if data.fn_trait.get_id(db, krate).is_none() { |
132 | return false; | 132 | return false; |
133 | } | 133 | } |
134 | 134 | ||
@@ -136,7 +136,7 @@ fn check_closure_fn_trait_impl_prerequisites( | |||
136 | // the traits having no type params, FnOnce being a supertrait | 136 | // the traits having no type params, FnOnce being a supertrait |
137 | 137 | ||
138 | // the FnOnce trait needs to exist and have an assoc type named Output | 138 | // the FnOnce trait needs to exist and have an assoc type named Output |
139 | let fn_once_trait = match get_fn_trait(db, krate, super::FnTrait::FnOnce) { | 139 | let fn_once_trait = match (super::FnTrait::FnOnce).get_id(db, krate) { |
140 | Some(t) => t, | 140 | Some(t) => t, |
141 | None => return false, | 141 | None => return false, |
142 | }; | 142 | }; |
@@ -151,7 +151,9 @@ fn closure_fn_trait_impl_datum( | |||
151 | // for some closure |X, Y| -> Z: | 151 | // for some closure |X, Y| -> Z: |
152 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } | 152 | // impl<T, U, V> Fn<(T, U)> for closure<fn(T, U) -> V> { Output = V } |
153 | 153 | ||
154 | let trait_ = get_fn_trait(db, krate, data.fn_trait) // get corresponding fn trait | 154 | let trait_ = data |
155 | .fn_trait | ||
156 | .get_id(db, krate) // get corresponding fn trait | ||
155 | // the existence of the Fn trait has been checked before | 157 | // the existence of the Fn trait has been checked before |
156 | .expect("fn trait for closure impl missing"); | 158 | .expect("fn trait for closure impl missing"); |
157 | 159 | ||
@@ -211,7 +213,7 @@ fn closure_fn_trait_output_assoc_ty_value( | |||
211 | let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into())); | 213 | let output_ty = Ty::Bound(BoundVar::new(DebruijnIndex::INNERMOST, num_args.into())); |
212 | 214 | ||
213 | let fn_once_trait = | 215 | let fn_once_trait = |
214 | get_fn_trait(db, krate, super::FnTrait::FnOnce).expect("assoc ty value should not exist"); | 216 | (super::FnTrait::FnOnce).get_id(db, krate).expect("assoc ty value should not exist"); |
215 | 217 | ||
216 | let output_ty_id = db | 218 | let output_ty_id = db |
217 | .trait_data(fn_once_trait) | 219 | .trait_data(fn_once_trait) |
@@ -360,14 +362,6 @@ fn super_trait_object_unsize_impl_datum( | |||
360 | BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } | 362 | BuiltinImplData { num_vars, trait_ref, where_clauses: Vec::new(), assoc_ty_values: Vec::new() } |
361 | } | 363 | } |
362 | 364 | ||
363 | fn get_fn_trait(db: &dyn HirDatabase, krate: CrateId, fn_trait: super::FnTrait) -> Option<TraitId> { | ||
364 | let target = db.lang_item(krate, fn_trait.lang_item_name().into())?; | ||
365 | match target { | ||
366 | LangItemTarget::TraitId(t) => Some(t), | ||
367 | _ => None, | ||
368 | } | ||
369 | } | ||
370 | |||
371 | fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { | 365 | fn get_unsize_trait(db: &dyn HirDatabase, krate: CrateId) -> Option<TraitId> { |
372 | let target = db.lang_item(krate, "unsize".into())?; | 366 | let target = db.lang_item(krate, "unsize".into())?; |
373 | match target { | 367 | match target { |
diff --git a/crates/ra_hir_ty/src/traits/chalk.rs b/crates/ra_hir_ty/src/traits/chalk.rs index a72a82f5a..2f35d6d49 100644 --- a/crates/ra_hir_ty/src/traits/chalk.rs +++ b/crates/ra_hir_ty/src/traits/chalk.rs | |||
@@ -74,14 +74,26 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> { | |||
74 | // Note: Since we're using impls_for_trait, only impls where the trait | 74 | // Note: Since we're using impls_for_trait, only impls where the trait |
75 | // can be resolved should ever reach Chalk. `impl_datum` relies on that | 75 | // can be resolved should ever reach Chalk. `impl_datum` relies on that |
76 | // and will panic if the trait can't be resolved. | 76 | // and will panic if the trait can't be resolved. |
77 | let mut result: Vec<_> = self | 77 | let in_deps = self.db.impls_from_deps(self.krate); |
78 | .db | 78 | let in_self = self.db.impls_in_crate(self.krate); |
79 | .impls_for_trait(self.krate, trait_, self_ty_fp) | 79 | let impl_maps = [in_deps, in_self]; |
80 | .iter() | 80 | |
81 | .copied() | 81 | let id_to_chalk = |id: hir_def::ImplId| Impl::ImplDef(id).to_chalk(self.db); |
82 | .map(Impl::ImplDef) | 82 | |
83 | .map(|impl_| impl_.to_chalk(self.db)) | 83 | let mut result: Vec<_> = match self_ty_fp { |
84 | .collect(); | 84 | Some(fp) => impl_maps |
85 | .iter() | ||
86 | .flat_map(|crate_impl_defs| { | ||
87 | crate_impl_defs.lookup_impl_defs_for_trait_and_ty(trait_, fp).map(id_to_chalk) | ||
88 | }) | ||
89 | .collect(), | ||
90 | None => impl_maps | ||
91 | .iter() | ||
92 | .flat_map(|crate_impl_defs| { | ||
93 | crate_impl_defs.lookup_impl_defs_for_trait(trait_).map(id_to_chalk) | ||
94 | }) | ||
95 | .collect(), | ||
96 | }; | ||
85 | 97 | ||
86 | let arg: Option<Ty> = | 98 | let arg: Option<Ty> = |
87 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); | 99 | parameters.get(1).map(|p| from_chalk(self.db, p.assert_ty_ref(&Interner).clone())); |
diff --git a/crates/ra_hir_ty/src/utils.rs b/crates/ra_hir_ty/src/utils.rs index f98350bf9..c45820ff0 100644 --- a/crates/ra_hir_ty/src/utils.rs +++ b/crates/ra_hir_ty/src/utils.rs | |||
@@ -143,13 +143,14 @@ pub(super) fn find_super_trait_path( | |||
143 | } | 143 | } |
144 | 144 | ||
145 | pub(super) fn associated_type_by_name_including_super_traits( | 145 | pub(super) fn associated_type_by_name_including_super_traits( |
146 | db: &dyn DefDatabase, | 146 | db: &dyn HirDatabase, |
147 | trait_: TraitId, | 147 | trait_ref: TraitRef, |
148 | name: &Name, | 148 | name: &Name, |
149 | ) -> Option<TypeAliasId> { | 149 | ) -> Option<(TraitRef, TypeAliasId)> { |
150 | all_super_traits(db, trait_) | 150 | all_super_trait_refs(db, trait_ref).into_iter().find_map(|t| { |
151 | .into_iter() | 151 | let assoc_type = db.trait_data(t.trait_).associated_type_by_name(name)?; |
152 | .find_map(|t| db.trait_data(t).associated_type_by_name(name)) | 152 | Some((t, assoc_type)) |
153 | }) | ||
153 | } | 154 | } |
154 | 155 | ||
155 | pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> { | 156 | pub(super) fn variant_data(db: &dyn DefDatabase, var: VariantId) -> Arc<VariantData> { |
@@ -176,6 +177,7 @@ pub(crate) fn generics(db: &dyn DefDatabase, def: GenericDefId) -> Generics { | |||
176 | Generics { def, params: db.generic_params(def), parent_generics } | 177 | Generics { def, params: db.generic_params(def), parent_generics } |
177 | } | 178 | } |
178 | 179 | ||
180 | #[derive(Debug)] | ||
179 | pub(crate) struct Generics { | 181 | pub(crate) struct Generics { |
180 | def: GenericDefId, | 182 | def: GenericDefId, |
181 | pub(crate) params: Arc<GenericParams>, | 183 | pub(crate) params: Arc<GenericParams>, |