aboutsummaryrefslogtreecommitdiff
path: root/crates
diff options
context:
space:
mode:
Diffstat (limited to 'crates')
-rw-r--r--crates/ra_hir_ty/src/diagnostics/match_check.rs168
1 files changed, 83 insertions, 85 deletions
diff --git a/crates/ra_hir_ty/src/diagnostics/match_check.rs b/crates/ra_hir_ty/src/diagnostics/match_check.rs
index 722c0e9ee..899025a87 100644
--- a/crates/ra_hir_ty/src/diagnostics/match_check.rs
+++ b/crates/ra_hir_ty/src/diagnostics/match_check.rs
@@ -272,7 +272,7 @@ impl From<&PatId> for PatIdOrWild {
272} 272}
273 273
274#[derive(Debug, Clone, Copy, PartialEq)] 274#[derive(Debug, Clone, Copy, PartialEq)]
275pub enum MatchCheckErr { 275pub(super) enum MatchCheckErr {
276 NotImplemented, 276 NotImplemented,
277 MalformedMatchArm, 277 MalformedMatchArm,
278 /// Used when type inference cannot resolve the type of 278 /// Used when type inference cannot resolve the type of
@@ -287,21 +287,21 @@ pub enum MatchCheckErr {
287/// 287///
288/// The `std::result::Result` type is used here rather than a custom enum 288/// The `std::result::Result` type is used here rather than a custom enum
289/// to allow the use of `?`. 289/// to allow the use of `?`.
290pub type MatchCheckResult<T> = Result<T, MatchCheckErr>; 290pub(super) type MatchCheckResult<T> = Result<T, MatchCheckErr>;
291 291
292#[derive(Debug)] 292#[derive(Debug)]
293/// A row in a Matrix. 293/// A row in a Matrix.
294/// 294///
295/// This type is modeled from the struct of the same name in `rustc`. 295/// This type is modeled from the struct of the same name in `rustc`.
296pub(crate) struct PatStack(PatStackInner); 296pub(super) struct PatStack(PatStackInner);
297type PatStackInner = SmallVec<[PatIdOrWild; 2]>; 297type PatStackInner = SmallVec<[PatIdOrWild; 2]>;
298 298
299impl PatStack { 299impl PatStack {
300 pub(crate) fn from_pattern(pat_id: PatId) -> PatStack { 300 pub(super) fn from_pattern(pat_id: PatId) -> PatStack {
301 Self(smallvec!(pat_id.into())) 301 Self(smallvec!(pat_id.into()))
302 } 302 }
303 303
304 pub(crate) fn from_wild() -> PatStack { 304 pub(super) fn from_wild() -> PatStack {
305 Self(smallvec!(PatIdOrWild::Wild)) 305 Self(smallvec!(PatIdOrWild::Wild))
306 } 306 }
307 307
@@ -510,14 +510,14 @@ impl PatStack {
510/// A collection of PatStack. 510/// A collection of PatStack.
511/// 511///
512/// This type is modeled from the struct of the same name in `rustc`. 512/// This type is modeled from the struct of the same name in `rustc`.
513pub(crate) struct Matrix(Vec<PatStack>); 513pub(super) struct Matrix(Vec<PatStack>);
514 514
515impl Matrix { 515impl Matrix {
516 pub(crate) fn empty() -> Self { 516 pub(super) fn empty() -> Self {
517 Self(vec![]) 517 Self(vec![])
518 } 518 }
519 519
520 pub(crate) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) { 520 pub(super) fn push(&mut self, cx: &MatchCheckCtx, row: PatStack) {
521 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) { 521 if let Some(Pat::Or(pat_ids)) = row.get_head().map(|pat_id| pat_id.as_pat(cx)) {
522 // Or patterns are expanded here 522 // Or patterns are expanded here
523 for pat_id in pat_ids { 523 for pat_id in pat_ids {
@@ -579,16 +579,16 @@ impl Matrix {
579/// not matched by an prior match arms. 579/// not matched by an prior match arms.
580/// 580///
581/// We may eventually need an `Unknown` variant here. 581/// We may eventually need an `Unknown` variant here.
582pub enum Usefulness { 582pub(super) enum Usefulness {
583 Useful, 583 Useful,
584 NotUseful, 584 NotUseful,
585} 585}
586 586
587pub struct MatchCheckCtx<'a> { 587pub(super) struct MatchCheckCtx<'a> {
588 pub match_expr: Idx<Expr>, 588 pub(super) match_expr: Idx<Expr>,
589 pub body: Arc<Body>, 589 pub(super) body: Arc<Body>,
590 pub infer: Arc<InferenceResult>, 590 pub(super) infer: Arc<InferenceResult>,
591 pub db: &'a dyn HirDatabase, 591 pub(super) db: &'a dyn HirDatabase,
592} 592}
593 593
594/// Given a set of patterns `matrix`, and pattern to consider `v`, determines 594/// Given a set of patterns `matrix`, and pattern to consider `v`, determines
@@ -599,7 +599,7 @@ pub struct MatchCheckCtx<'a> {
599/// expected that you have already type checked the match arms. All patterns in 599/// expected that you have already type checked the match arms. All patterns in
600/// matrix should be the same type as v, as well as they should all be the same 600/// matrix should be the same type as v, as well as they should all be the same
601/// type as the match expression. 601/// type as the match expression.
602pub(crate) fn is_useful( 602pub(super) fn is_useful(
603 cx: &MatchCheckCtx, 603 cx: &MatchCheckCtx,
604 matrix: &Matrix, 604 matrix: &Matrix,
605 v: &PatStack, 605 v: &PatStack,
@@ -837,23 +837,23 @@ fn enum_variant_matches(cx: &MatchCheckCtx, pat_id: PatId, enum_variant_id: Enum
837 837
838#[cfg(test)] 838#[cfg(test)]
839mod tests { 839mod tests {
840 pub(super) use insta::assert_snapshot; 840 use insta::assert_snapshot;
841 pub(super) use ra_db::fixture::WithFixture; 841 use ra_db::fixture::WithFixture;
842 842
843 pub(super) use crate::{diagnostics::MissingMatchArms, test_db::TestDB}; 843 use crate::{diagnostics::MissingMatchArms, test_db::TestDB};
844 844
845 pub(super) fn check_diagnostic_message(ra_fixture: &str) -> String { 845 fn check_diagnostic_message(ra_fixture: &str) -> String {
846 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0 846 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().0
847 } 847 }
848 848
849 pub(super) fn check_diagnostic(ra_fixture: &str) { 849 fn check_diagnostic(ra_fixture: &str) {
850 let diagnostic_count = 850 let diagnostic_count =
851 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1; 851 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>().1;
852 852
853 assert_eq!(1, diagnostic_count, "no diagnostic reported"); 853 assert_eq!(1, diagnostic_count, "no diagnostic reported");
854 } 854 }
855 855
856 pub(super) fn check_no_diagnostic(ra_fixture: &str) { 856 fn check_no_diagnostic(ra_fixture: &str) {
857 let (s, diagnostic_count) = 857 let (s, diagnostic_count) =
858 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>(); 858 TestDB::with_single_file(ra_fixture).0.diagnostic::<MissingMatchArms>();
859 859
@@ -2036,28 +2036,25 @@ mod tests {
2036 ", 2036 ",
2037 ); 2037 );
2038 } 2038 }
2039}
2040 2039
2041#[cfg(test)] 2040 mod false_negatives {
2042mod false_negatives { 2041 //! The implementation of match checking here is a work in progress. As we roll this out, we
2043 //! The implementation of match checking here is a work in progress. As we roll this out, we 2042 //! prefer false negatives to false positives (ideally there would be no false positives). This
2044 //! prefer false negatives to false positives (ideally there would be no false positives). This 2043 //! test module should document known false negatives. Eventually we will have a complete
2045 //! test module should document known false negatives. Eventually we will have a complete 2044 //! implementation of match checking and this module will be empty.
2046 //! implementation of match checking and this module will be empty. 2045 //!
2047 //! 2046 //! The reasons for documenting known false negatives:
2048 //! The reasons for documenting known false negatives: 2047 //!
2049 //! 2048 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system.
2050 //! 1. It acts as a backlog of work that can be done to improve the behavior of the system. 2049 //! 2. It ensures the code doesn't panic when handling these cases.
2051 //! 2. It ensures the code doesn't panic when handling these cases. 2050 use super::*;
2052 2051
2053 use super::tests::*; 2052 #[test]
2054 2053 fn integers() {
2055 #[test] 2054 // This is a false negative.
2056 fn integers() { 2055 // We don't currently check integer exhaustiveness.
2057 // This is a false negative. 2056 check_no_diagnostic(
2058 // We don't currently check integer exhaustiveness. 2057 r"
2059 check_no_diagnostic(
2060 r"
2061 fn test_fn() { 2058 fn test_fn() {
2062 match 5 { 2059 match 5 {
2063 10 => (), 2060 10 => (),
@@ -2065,15 +2062,15 @@ mod false_negatives {
2065 } 2062 }
2066 } 2063 }
2067 ", 2064 ",
2068 ); 2065 );
2069 } 2066 }
2070 2067
2071 #[test] 2068 #[test]
2072 fn internal_or() { 2069 fn internal_or() {
2073 // This is a false negative. 2070 // This is a false negative.
2074 // We do not currently handle patterns with internal `or`s. 2071 // We do not currently handle patterns with internal `or`s.
2075 check_no_diagnostic( 2072 check_no_diagnostic(
2076 r" 2073 r"
2077 fn test_fn() { 2074 fn test_fn() {
2078 enum Either { 2075 enum Either {
2079 A(bool), 2076 A(bool),
@@ -2084,17 +2081,17 @@ mod false_negatives {
2084 } 2081 }
2085 } 2082 }
2086 ", 2083 ",
2087 ); 2084 );
2088 } 2085 }
2089 2086
2090 #[test] 2087 #[test]
2091 fn expr_loop_missing_arm() { 2088 fn expr_loop_missing_arm() {
2092 // This is a false negative. 2089 // This is a false negative.
2093 // We currently infer the type of `loop { break Foo::A }` to `!`, which 2090 // We currently infer the type of `loop { break Foo::A }` to `!`, which
2094 // causes us to skip the diagnostic since `Either::A` doesn't type check 2091 // causes us to skip the diagnostic since `Either::A` doesn't type check
2095 // with `!`. 2092 // with `!`.
2096 check_diagnostic( 2093 check_diagnostic(
2097 r" 2094 r"
2098 enum Either { 2095 enum Either {
2099 A, 2096 A,
2100 B, 2097 B,
@@ -2105,45 +2102,45 @@ mod false_negatives {
2105 } 2102 }
2106 } 2103 }
2107 ", 2104 ",
2108 ); 2105 );
2109 } 2106 }
2110 2107
2111 #[test] 2108 #[test]
2112 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() { 2109 fn tuple_of_bools_with_ellipsis_at_end_missing_arm() {
2113 // This is a false negative. 2110 // This is a false negative.
2114 // We don't currently handle tuple patterns with ellipsis. 2111 // We don't currently handle tuple patterns with ellipsis.
2115 check_no_diagnostic( 2112 check_no_diagnostic(
2116 r" 2113 r"
2117 fn test_fn() { 2114 fn test_fn() {
2118 match (false, true, false) { 2115 match (false, true, false) {
2119 (false, ..) => {}, 2116 (false, ..) => {},
2120 } 2117 }
2121 } 2118 }
2122 ", 2119 ",
2123 ); 2120 );
2124 } 2121 }
2125 2122
2126 #[test] 2123 #[test]
2127 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() { 2124 fn tuple_of_bools_with_ellipsis_at_beginning_missing_arm() {
2128 // This is a false negative. 2125 // This is a false negative.
2129 // We don't currently handle tuple patterns with ellipsis. 2126 // We don't currently handle tuple patterns with ellipsis.
2130 check_no_diagnostic( 2127 check_no_diagnostic(
2131 r" 2128 r"
2132 fn test_fn() { 2129 fn test_fn() {
2133 match (false, true, false) { 2130 match (false, true, false) {
2134 (.., false) => {}, 2131 (.., false) => {},
2135 } 2132 }
2136 } 2133 }
2137 ", 2134 ",
2138 ); 2135 );
2139 } 2136 }
2140 2137
2141 #[test] 2138 #[test]
2142 fn struct_missing_arm() { 2139 fn struct_missing_arm() {
2143 // This is a false negative. 2140 // This is a false negative.
2144 // We don't currently handle structs. 2141 // We don't currently handle structs.
2145 check_no_diagnostic( 2142 check_no_diagnostic(
2146 r" 2143 r"
2147 struct Foo { 2144 struct Foo {
2148 a: bool, 2145 a: bool,
2149 } 2146 }
@@ -2153,6 +2150,7 @@ mod false_negatives {
2153 } 2150 }
2154 } 2151 }
2155 ", 2152 ",
2156 ); 2153 );
2154 }
2157 } 2155 }
2158} 2156}