From 360bdf653b91f5232a5584c7f4b13960caa48dda Mon Sep 17 00:00:00 2001 From: Josh Mcguigan Date: Tue, 14 Apr 2020 16:06:57 -0700 Subject: fix false positive for enum with no variants --- crates/ra_hir_ty/src/_match.rs | 42 ++++++++++++++++++++++++++++++++++++++++-- crates/ra_hir_ty/src/expr.rs | 2 +- crates/ra_hir_ty/src/lib.rs | 10 ++++++++++ 3 files changed, 51 insertions(+), 3 deletions(-) (limited to 'crates/ra_hir_ty') diff --git a/crates/ra_hir_ty/src/_match.rs b/crates/ra_hir_ty/src/_match.rs index a64be9848..688026a04 100644 --- a/crates/ra_hir_ty/src/_match.rs +++ b/crates/ra_hir_ty/src/_match.rs @@ -194,9 +194,10 @@ use smallvec::{smallvec, SmallVec}; use crate::{ db::HirDatabase, expr::{Body, Expr, Literal, Pat, PatId}, - InferenceResult, + ApplicationTy, InferenceResult, Ty, TypeCtor, }; -use hir_def::{adt::VariantData, EnumVariantId, VariantId}; +use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId}; +use ra_arena::Idx; #[derive(Debug, Clone, Copy)] /// Either a pattern from the source code being analyzed, represented as @@ -512,6 +513,7 @@ pub enum Usefulness { } pub struct MatchCheckCtx<'a> { + pub match_expr: Idx, pub body: Arc, pub infer: Arc, pub db: &'a dyn HirDatabase, @@ -530,6 +532,16 @@ pub(crate) fn is_useful( matrix: &Matrix, v: &PatStack, ) -> MatchCheckResult { + // Handle the special case of enums with no variants. In that case, no match + // arm is useful. + if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) = + cx.infer[cx.match_expr].strip_references() + { + if cx.db.enum_data(*enum_id).variants.is_empty() { + return Ok(Usefulness::NotUseful); + } + } + if v.is_empty() { let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; @@ -1618,6 +1630,32 @@ mod tests { check_no_diagnostic(content); } + + #[test] + fn enum_never() { + let content = r" + enum Never {} + + fn test_fn(never: Never) { + match never {} + } + "; + + check_no_diagnostic(content); + } + + #[test] + fn enum_never_ref() { + let content = r" + enum Never {} + + fn test_fn(never: &Never) { + match never {} + } + "; + + check_no_diagnostic(content); + } } #[cfg(test)] diff --git a/crates/ra_hir_ty/src/expr.rs b/crates/ra_hir_ty/src/expr.rs index 21abbcf1e..fd59f4320 100644 --- a/crates/ra_hir_ty/src/expr.rs +++ b/crates/ra_hir_ty/src/expr.rs @@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> { None => return, }; - let cx = MatchCheckCtx { body, infer: infer.clone(), db }; + let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db }; let pats = arms.iter().map(|arm| arm.pat); let mut seen = Matrix::empty(); diff --git a/crates/ra_hir_ty/src/lib.rs b/crates/ra_hir_ty/src/lib.rs index 18f74d3b1..2677f3af2 100644 --- a/crates/ra_hir_ty/src/lib.rs +++ b/crates/ra_hir_ty/src/lib.rs @@ -680,6 +680,16 @@ impl Ty { } } + pub fn strip_references(&self) -> &Ty { + let mut t: &Ty = self; + + while let Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(_mutability), parameters }) = t { + t = parameters.as_single(); + } + + t + } + pub fn as_adt(&self) -> Option<(AdtId, &Substs)> { match self { Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => { -- cgit v1.2.3