3979: fix missing match arm false positive for enum with no variants r=flodiebold a=JoshMcguigan

fixes #3974

Co-authored-by: Josh Mcguigan <joshmcg88@gmail.com>
This commit is contained in:
bors[bot] 2020-04-16 12:57:31 +00:00 committed by GitHub
commit 0390d62168
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
3 changed files with 51 additions and 3 deletions

View file

@ -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<Expr>,
pub body: Arc<Body>,
pub infer: Arc<InferenceResult>,
pub db: &'a dyn HirDatabase,
@ -530,6 +532,16 @@ pub(crate) fn is_useful(
matrix: &Matrix,
v: &PatStack,
) -> MatchCheckResult<Usefulness> {
// 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)]

View file

@ -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();

View file

@ -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 }) => {