From f46a42f73aa92ab66800c70d525ddc7e6529edd6 Mon Sep 17 00:00:00 2001 From: Dawer <7803845+iDawer@users.noreply.github.com> Date: Tue, 11 May 2021 18:24:39 +0500 Subject: [PATCH] Better tests: check if match checking bails out. --- crates/hir_ty/src/diagnostics/expr.rs | 2 + crates/hir_ty/src/diagnostics/match_check.rs | 68 +++++++++++++++++++- 2 files changed, 69 insertions(+), 1 deletion(-) diff --git a/crates/hir_ty/src/diagnostics/expr.rs b/crates/hir_ty/src/diagnostics/expr.rs index c6015d23651..0a7e6ee52d8 100644 --- a/crates/hir_ty/src/diagnostics/expr.rs +++ b/crates/hir_ty/src/diagnostics/expr.rs @@ -346,6 +346,8 @@ fn validate_match( // fit the match expression, we skip this diagnostic. Skipping the entire // diagnostic rather than just not including this match arm is preferred // to avoid the chance of false positives. + #[cfg(test)] + match_check::tests::report_bail_out(db, self.owner, arm.pat, self.sink); return; } diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index aebadd39170..5f0cc4145c6 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs @@ -339,9 +339,60 @@ fn super_fold_with(&self, folder: &mut F) -> Self { } #[cfg(test)] -mod tests { +pub(super) mod tests { + mod report { + use std::any::Any; + + use hir_def::{expr::PatId, DefWithBodyId}; + use hir_expand::{HirFileId, InFile}; + use syntax::SyntaxNodePtr; + + use crate::{ + db::HirDatabase, + diagnostics_sink::{Diagnostic, DiagnosticCode, DiagnosticSink}, + }; + + /// In tests, match check bails out loudly. + /// This helps to catch incorrect tests that pass due to false negatives. + pub(crate) fn report_bail_out( + db: &dyn HirDatabase, + def: DefWithBodyId, + pat: PatId, + sink: &mut DiagnosticSink, + ) { + let (_, source_map) = db.body_with_source_map(def); + if let Ok(source_ptr) = source_map.pat_syntax(pat) { + let pat_syntax_ptr = source_ptr.value.either(Into::into, Into::into); + sink.push(BailedOut { file: source_ptr.file_id, pat_syntax_ptr }); + } + } + + #[derive(Debug)] + struct BailedOut { + file: HirFileId, + pat_syntax_ptr: SyntaxNodePtr, + } + + impl Diagnostic for BailedOut { + fn code(&self) -> DiagnosticCode { + DiagnosticCode("internal:match-check-bailed-out") + } + fn message(&self) -> String { + format!("Internal: match check bailed out") + } + fn display_source(&self) -> InFile { + InFile { file_id: self.file, value: self.pat_syntax_ptr.clone() } + } + fn as_any(&self) -> &(dyn Any + Send + 'static) { + self + } + } + } + use crate::diagnostics::tests::check_diagnostics; + pub(crate) use self::report::report_bail_out; + #[test] fn empty_tuple() { check_diagnostics( @@ -589,14 +640,18 @@ enum Either2 { C, D } fn main() { match Either::A { Either2::C => (), + // ^^^^^^^^^^ Internal: match check bailed out Either2::D => (), } match (true, false) { (true, false, true) => (), + // ^^^^^^^^^^^^^^^^^^^ Internal: match check bailed out (true) => (), } match (true, false) { (true,) => {} } + // ^^^^^^^ Internal: match check bailed out match (0) { () => () } + // ^^ Internal: match check bailed out match Unresolved::Bar { Unresolved::Baz => () } } "#, @@ -609,7 +664,9 @@ fn mismatched_types_in_or_patterns() { r#" fn main() { match false { true | () => {} } + // ^^^^^^^^^ Internal: match check bailed out match (false,) { (true | (),) => {} } + // ^^^^^^^^^^^^ Internal: match check bailed out } "#, ); @@ -642,10 +699,12 @@ enum Either { A, B } fn main() { match loop {} { Either::A => (), + // ^^^^^^^^^ Internal: match check bailed out Either::B => (), } match loop {} { Either::A => (), + // ^^^^^^^^^ Internal: match check bailed out } match loop { break Foo::A } { //^^^^^^^^^^^^^^^^^^^^^ Missing match arm @@ -853,6 +912,11 @@ fn main() { match Option::::None { None => (), Some(never) => match never {}, + // ^^^^^^^^^^^ Internal: match check bailed out + } + match Option::::None { + //^^^^^^^^^^^^^^^^^^^^^ Missing match arm + Option::Some(_never) => {}, } } "#, @@ -1000,6 +1064,7 @@ fn main(v: S) { match v { S{ a } => {} } match v { S{ a: _x } => {} } match v { S{ a: 'a' } => {} } + //^^^^^^^^^^^ Internal: match check bailed out match v { S{..} => {} } match v { _ => {} } match v { } @@ -1045,6 +1110,7 @@ fn integers() { fn main() { match 5 { 10 => (), + // ^^ Internal: match check bailed out 11..20 => (), } }