aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics
diff options
context:
space:
mode:
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r--crates/hir_ty/src/diagnostics/expr.rs2
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs68
2 files changed, 69 insertions, 1 deletions
diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs
index c6015d236..0a7e6ee52 100644
--- a/crates/hir_ty/src/diagnostics/expr.rs
+++ b/crates/hir_ty/src/diagnostics/expr.rs
@@ -346,6 +346,8 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
346 // fit the match expression, we skip this diagnostic. Skipping the entire 346 // fit the match expression, we skip this diagnostic. Skipping the entire
347 // diagnostic rather than just not including this match arm is preferred 347 // diagnostic rather than just not including this match arm is preferred
348 // to avoid the chance of false positives. 348 // to avoid the chance of false positives.
349 #[cfg(test)]
350 match_check::tests::report_bail_out(db, self.owner, arm.pat, self.sink);
349 return; 351 return;
350 } 352 }
351 353
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index aebadd391..5f0cc4145 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -339,9 +339,60 @@ impl PatternFoldable for PatKind {
339} 339}
340 340
341#[cfg(test)] 341#[cfg(test)]
342mod tests { 342pub(super) mod tests {
343 mod report {
344 use std::any::Any;
345
346 use hir_def::{expr::PatId, DefWithBodyId};
347 use hir_expand::{HirFileId, InFile};
348 use syntax::SyntaxNodePtr;
349
350 use crate::{
351 db::HirDatabase,
352 diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink},
353 };
354
355 /// In tests, match check bails out loudly.
356 /// This helps to catch incorrect tests that pass due to false negatives.
357 pub(crate) fn report_bail_out(
358 db: &dyn HirDatabase,
359 def: DefWithBodyId,
360 pat: PatId,
361 sink: &mut DiagnosticSink,
362 ) {
363 let (_, source_map) = db.body_with_source_map(def);
364 if let Ok(source_ptr) = source_map.pat_syntax(pat) {
365 let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into);
366 sink.push(BailedOut { file: source_ptr.file_id, pat_syntax_ptr });
367 }
368 }
369
370 #[derive(Debug)]
371 struct BailedOut {
372 file: HirFileId,
373 pat_syntax_ptr: SyntaxNodePtr,
374 }
375
376 impl Diagnostic for BailedOut {
377 fn code(&self) -> DiagnosticCode {
378 DiagnosticCode("internal:match-check-bailed-out")
379 }
380 fn message(&self) -> String {
381 format!("Internal: match check bailed out")
382 }
383 fn display_source(&self) -> InFile<SyntaxNodePtr> {
384 InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() }
385 }
386 fn as_any(&self) -> &(dyn Any + Send + 'static) {
387 self
388 }
389 }
390 }
391
343 use crate::diagnostics::tests::check_diagnostics; 392 use crate::diagnostics::tests::check_diagnostics;
344 393
394 pub(crate) use self::report::report_bail_out;
395
345 #[test] 396 #[test]
346 fn empty_tuple() { 397 fn empty_tuple() {
347 check_diagnostics( 398 check_diagnostics(
@@ -589,14 +640,18 @@ enum Either2 { C, D }
589fn main() { 640fn main() {
590 match Either::A { 641 match Either::A {
591 Either2::C => (), 642 Either2::C => (),
643 // ^^^^^^^^^^ Internal: match check bailed out
592 Either2::D => (), 644 Either2::D => (),
593 } 645 }
594 match (true, false) { 646 match (true, false) {
595 (true, false, true) => (), 647 (true, false, true) => (),
648 // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out
596 (true) => (), 649 (true) => (),
597 } 650 }
598 match (true, false) { (true,) => {} } 651 match (true, false) { (true,) => {} }
652 // ^^^^^^^ Internal: match check bailed out
599 match (0) { () => () } 653 match (0) { () => () }
654 // ^^ Internal: match check bailed out
600 match Unresolved::Bar { Unresolved::Baz => () } 655 match Unresolved::Bar { Unresolved::Baz => () }
601} 656}
602 "#, 657 "#,
@@ -609,7 +664,9 @@ fn main() {
609 r#" 664 r#"
610fn main() { 665fn main() {
611 match false { true | () => {} } 666 match false { true | () => {} }
667 // ^^^^^^^^^ Internal: match check bailed out
612 match (false,) { (true | (),) => {} } 668 match (false,) { (true | (),) => {} }
669 // ^^^^^^^^^^^^ Internal: match check bailed out
613} 670}
614"#, 671"#,
615 ); 672 );
@@ -642,10 +699,12 @@ enum Either { A, B }
642fn main() { 699fn main() {
643 match loop {} { 700 match loop {} {
644 Either::A => (), 701 Either::A => (),
702 // ^^^^^^^^^ Internal: match check bailed out
645 Either::B => (), 703 Either::B => (),
646 } 704 }
647 match loop {} { 705 match loop {} {
648 Either::A => (), 706 Either::A => (),
707 // ^^^^^^^^^ Internal: match check bailed out
649 } 708 }
650 match loop { break Foo::A } { 709 match loop { break Foo::A } {
651 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm 710 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
@@ -853,6 +912,11 @@ fn main() {
853 match Option::<Never>::None { 912 match Option::<Never>::None {
854 None => (), 913 None => (),
855 Some(never) => match never {}, 914 Some(never) => match never {},
915 // ^^^^^^^^^^^ Internal: match check bailed out
916 }
917 match Option::<Never>::None {
918 //^^^^^^^^^^^^^^^^^^^^^ Missing match arm
919 Option::Some(_never) => {},
856 } 920 }
857} 921}
858"#, 922"#,
@@ -1000,6 +1064,7 @@ fn main(v: S) {
1000 match v { S{ a } => {} } 1064 match v { S{ a } => {} }
1001 match v { S{ a: _x } => {} } 1065 match v { S{ a: _x } => {} }
1002 match v { S{ a: 'a' } => {} } 1066 match v { S{ a: 'a' } => {} }
1067 //^^^^^^^^^^^ Internal: match check bailed out
1003 match v { S{..} => {} } 1068 match v { S{..} => {} }
1004 match v { _ => {} } 1069 match v { _ => {} }
1005 match v { } 1070 match v { }
@@ -1045,6 +1110,7 @@ fn main() {
1045fn main() { 1110fn main() {
1046 match 5 { 1111 match 5 {
1047 10 => (), 1112 10 => (),
1113 // ^^ Internal: match check bailed out
1048 11..20 => (), 1114 11..20 => (),
1049 } 1115 }
1050} 1116}