Skip to content

Commit 0390d62

Browse files
Merge #3979
3979: fix missing match arm false positive for enum with no variants r=flodiebold a=JoshMcguigan fixes #3974 Co-authored-by: Josh Mcguigan <[email protected]>
2 parents 7d60a44 + 360bdf6 commit 0390d62

File tree

3 files changed

+51
-3
lines changed

3 files changed

+51
-3
lines changed

crates/ra_hir_ty/src/_match.rs

Lines changed: 40 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -194,9 +194,10 @@ use smallvec::{smallvec, SmallVec};
194194
use crate::{
195195
db::HirDatabase,
196196
expr::{Body, Expr, Literal, Pat, PatId},
197-
InferenceResult,
197+
ApplicationTy, InferenceResult, Ty, TypeCtor,
198198
};
199-
use hir_def::{adt::VariantData, EnumVariantId, VariantId};
199+
use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId};
200+
use ra_arena::Idx;
200201

201202
#[derive(Debug, Clone, Copy)]
202203
/// Either a pattern from the source code being analyzed, represented as
@@ -512,6 +513,7 @@ pub enum Usefulness {
512513
}
513514

514515
pub struct MatchCheckCtx<'a> {
516+
pub match_expr: Idx<Expr>,
515517
pub body: Arc<Body>,
516518
pub infer: Arc<InferenceResult>,
517519
pub db: &'a dyn HirDatabase,
@@ -530,6 +532,16 @@ pub(crate) fn is_useful(
530532
matrix: &Matrix,
531533
v: &PatStack,
532534
) -> MatchCheckResult<Usefulness> {
535+
// Handle the special case of enums with no variants. In that case, no match
536+
// arm is useful.
537+
if let Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(AdtId::EnumId(enum_id)), .. }) =
538+
cx.infer[cx.match_expr].strip_references()
539+
{
540+
if cx.db.enum_data(*enum_id).variants.is_empty() {
541+
return Ok(Usefulness::NotUseful);
542+
}
543+
}
544+
533545
if v.is_empty() {
534546
let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful };
535547

@@ -1618,6 +1630,32 @@ mod tests {
16181630

16191631
check_no_diagnostic(content);
16201632
}
1633+
1634+
#[test]
1635+
fn enum_never() {
1636+
let content = r"
1637+
enum Never {}
1638+
1639+
fn test_fn(never: Never) {
1640+
match never {}
1641+
}
1642+
";
1643+
1644+
check_no_diagnostic(content);
1645+
}
1646+
1647+
#[test]
1648+
fn enum_never_ref() {
1649+
let content = r"
1650+
enum Never {}
1651+
1652+
fn test_fn(never: &Never) {
1653+
match never {}
1654+
}
1655+
";
1656+
1657+
check_no_diagnostic(content);
1658+
}
16211659
}
16221660

16231661
#[cfg(test)]

crates/ra_hir_ty/src/expr.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -156,7 +156,7 @@ impl<'a, 'b> ExprValidator<'a, 'b> {
156156
None => return,
157157
};
158158

159-
let cx = MatchCheckCtx { body, infer: infer.clone(), db };
159+
let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db };
160160
let pats = arms.iter().map(|arm| arm.pat);
161161

162162
let mut seen = Matrix::empty();

crates/ra_hir_ty/src/lib.rs

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -680,6 +680,16 @@ impl Ty {
680680
}
681681
}
682682

683+
pub fn strip_references(&self) -> &Ty {
684+
let mut t: &Ty = self;
685+
686+
while let Ty::Apply(ApplicationTy { ctor: TypeCtor::Ref(_mutability), parameters }) = t {
687+
t = parameters.as_single();
688+
}
689+
690+
t
691+
}
692+
683693
pub fn as_adt(&self) -> Option<(AdtId, &Substs)> {
684694
match self {
685695
Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => {

0 commit comments

Comments
 (0)