diff options
author | Josh Mcguigan <[email protected]> | 2020-04-15 00:06:57 +0100 |
---|---|---|
committer | Josh Mcguigan <[email protected]> | 2020-04-16 13:37:49 +0100 |
commit | 360bdf653b91f5232a5584c7f4b13960caa48dda (patch) | |
tree | db24ae367e16cb316ffa7bccdac34afbde32ea2a | |
parent | c82e7696e6f86cc0843c5aab9f09b5d6dd0d4bac (diff) |
fix false positive for enum with no variants
-rw-r--r-- | crates/ra_hir_ty/src/_match.rs | 42 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/expr.rs | 2 | ||||
-rw-r--r-- | crates/ra_hir_ty/src/lib.rs | 10 |
3 files changed, 51 insertions, 3 deletions
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}; | |||
194 | use crate::{ | 194 | use crate::{ |
195 | db::HirDatabase, | 195 | db::HirDatabase, |
196 | expr::{Body, Expr, Literal, Pat, PatId}, | 196 | expr::{Body, Expr, Literal, Pat, PatId}, |
197 | InferenceResult, | 197 | ApplicationTy, InferenceResult, Ty, TypeCtor, |
198 | }; | 198 | }; |
199 | use hir_def::{adt::VariantData, EnumVariantId, VariantId}; | 199 | use hir_def::{adt::VariantData, AdtId, EnumVariantId, VariantId}; |
200 | use ra_arena::Idx; | ||
200 | 201 | ||
201 | #[derive(Debug, Clone, Copy)] | 202 | #[derive(Debug, Clone, Copy)] |
202 | /// Either a pattern from the source code being analyzed, represented as | 203 | /// Either a pattern from the source code being analyzed, represented as |
@@ -512,6 +513,7 @@ pub enum Usefulness { | |||
512 | } | 513 | } |
513 | 514 | ||
514 | pub struct MatchCheckCtx<'a> { | 515 | pub struct MatchCheckCtx<'a> { |
516 | pub match_expr: Idx<Expr>, | ||
515 | pub body: Arc<Body>, | 517 | pub body: Arc<Body>, |
516 | pub infer: Arc<InferenceResult>, | 518 | pub infer: Arc<InferenceResult>, |
517 | pub db: &'a dyn HirDatabase, | 519 | pub db: &'a dyn HirDatabase, |
@@ -530,6 +532,16 @@ pub(crate) fn is_useful( | |||
530 | matrix: &Matrix, | 532 | matrix: &Matrix, |
531 | v: &PatStack, | 533 | v: &PatStack, |
532 | ) -> MatchCheckResult<Usefulness> { | 534 | ) -> 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 | |||
533 | if v.is_empty() { | 545 | if v.is_empty() { |
534 | let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; | 546 | let result = if matrix.is_empty() { Usefulness::Useful } else { Usefulness::NotUseful }; |
535 | 547 | ||
@@ -1618,6 +1630,32 @@ mod tests { | |||
1618 | 1630 | ||
1619 | check_no_diagnostic(content); | 1631 | check_no_diagnostic(content); |
1620 | } | 1632 | } |
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 | } | ||
1621 | } | 1659 | } |
1622 | 1660 | ||
1623 | #[cfg(test)] | 1661 | #[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> { | |||
156 | None => return, | 156 | None => return, |
157 | }; | 157 | }; |
158 | 158 | ||
159 | let cx = MatchCheckCtx { body, infer: infer.clone(), db }; | 159 | let cx = MatchCheckCtx { match_expr, body, infer: infer.clone(), db }; |
160 | let pats = arms.iter().map(|arm| arm.pat); | 160 | let pats = arms.iter().map(|arm| arm.pat); |
161 | 161 | ||
162 | let mut seen = Matrix::empty(); | 162 | 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 { | |||
680 | } | 680 | } |
681 | } | 681 | } |
682 | 682 | ||
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 | |||
683 | pub fn as_adt(&self) -> Option<(AdtId, &Substs)> { | 693 | pub fn as_adt(&self) -> Option<(AdtId, &Substs)> { |
684 | match self { | 694 | match self { |
685 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => { | 695 | Ty::Apply(ApplicationTy { ctor: TypeCtor::Adt(adt_def), parameters }) => { |