diff options
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 36 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs | 22 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check/usefulness.rs | 4 |
3 files changed, 52 insertions, 10 deletions
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs index 5f0cc4145..061ef754d 100644 --- a/crates/hir_ty/src/diagnostics/match_check.rs +++ b/crates/hir_ty/src/diagnostics/match_check.rs | |||
@@ -1090,6 +1090,42 @@ fn main() { | |||
1090 | ); | 1090 | ); |
1091 | } | 1091 | } |
1092 | 1092 | ||
1093 | #[test] | ||
1094 | fn enum_non_exhaustive() { | ||
1095 | check_diagnostics( | ||
1096 | r#" | ||
1097 | //- /lib.rs crate:lib | ||
1098 | #[non_exhaustive] | ||
1099 | pub enum E { A, B } | ||
1100 | fn _local() { | ||
1101 | match E::A { _ => {} } | ||
1102 | match E::A { | ||
1103 | E::A => {} | ||
1104 | E::B => {} | ||
1105 | } | ||
1106 | match E::A { | ||
1107 | E::A | E::B => {} | ||
1108 | } | ||
1109 | } | ||
1110 | |||
1111 | //- /main.rs crate:main deps:lib | ||
1112 | use lib::E; | ||
1113 | fn main() { | ||
1114 | match E::A { _ => {} } | ||
1115 | match E::A { | ||
1116 | //^^^^ Missing match arm | ||
1117 | E::A => {} | ||
1118 | E::B => {} | ||
1119 | } | ||
1120 | match E::A { | ||
1121 | //^^^^ Missing match arm | ||
1122 | E::A | E::B => {} | ||
1123 | } | ||
1124 | } | ||
1125 | "#, | ||
1126 | ); | ||
1127 | } | ||
1128 | |||
1093 | mod false_negatives { | 1129 | mod false_negatives { |
1094 | //! The implementation of match checking here is a work in progress. As we roll this out, we | 1130 | //! The implementation of match checking here is a work in progress. As we roll this out, we |
1095 | //! prefer false negatives to false positives (ideally there would be no false positives). This | 1131 | //! prefer false negatives to false positives (ideally there would be no false positives). This |
diff --git a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs index 9fa82a952..6711fbb4a 100644 --- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs +++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs | |||
@@ -513,9 +513,7 @@ impl SplitWildcard { | |||
513 | if is_secretly_empty || is_declared_nonexhaustive { | 513 | if is_secretly_empty || is_declared_nonexhaustive { |
514 | smallvec![NonExhaustive] | 514 | smallvec![NonExhaustive] |
515 | } else if cx.feature_exhaustive_patterns() { | 515 | } else if cx.feature_exhaustive_patterns() { |
516 | // If `exhaustive_patterns` is enabled, we exclude variants known to be | 516 | unimplemented!() // see MatchCheckCtx.feature_exhaustive_patterns() |
517 | // uninhabited. | ||
518 | unhandled() | ||
519 | } else { | 517 | } else { |
520 | enum_data | 518 | enum_data |
521 | .variants | 519 | .variants |
@@ -643,6 +641,7 @@ impl Fields { | |||
643 | Fields::Vec(pats) | 641 | Fields::Vec(pats) |
644 | } | 642 | } |
645 | 643 | ||
644 | /// Creates a new list of wildcard fields for a given constructor. | ||
646 | pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self { | 645 | pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self { |
647 | let ty = pcx.ty; | 646 | let ty = pcx.ty; |
648 | let cx = pcx.cx; | 647 | let cx = pcx.cx; |
@@ -655,14 +654,13 @@ impl Fields { | |||
655 | Fields::wildcards_from_tys(cx, tys) | 654 | Fields::wildcards_from_tys(cx, tys) |
656 | } | 655 | } |
657 | TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)), | 656 | TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)), |
658 | TyKind::Adt(AdtId(adt), substs) => { | 657 | &TyKind::Adt(AdtId(adt), ref substs) => { |
659 | let adt_is_box = false; // TODO(iDawer): implement this | 658 | if adt_is_box(adt, cx) { |
660 | if adt_is_box { | ||
661 | // Use T as the sub pattern type of Box<T>. | 659 | // Use T as the sub pattern type of Box<T>. |
662 | let subst_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner); | 660 | let subst_ty = substs.at(&Interner, 0).assert_ty_ref(&Interner); |
663 | Fields::from_single_pattern(wildcard_from_ty(subst_ty)) | 661 | Fields::from_single_pattern(wildcard_from_ty(subst_ty)) |
664 | } else { | 662 | } else { |
665 | let variant_id = constructor.variant_id_for_adt(*adt); | 663 | let variant_id = constructor.variant_id_for_adt(adt); |
666 | let adt_is_local = | 664 | let adt_is_local = |
667 | variant_id.module(cx.db.upcast()).krate() == cx.module.krate(); | 665 | variant_id.module(cx.db.upcast()).krate() == cx.module.krate(); |
668 | // Whether we must not match the fields of this variant exhaustively. | 666 | // Whether we must not match the fields of this variant exhaustively. |
@@ -680,7 +678,7 @@ impl Fields { | |||
680 | if has_no_hidden_fields { | 678 | if has_no_hidden_fields { |
681 | Fields::wildcards_from_tys(cx, field_tys()) | 679 | Fields::wildcards_from_tys(cx, field_tys()) |
682 | } else { | 680 | } else { |
683 | //FIXME(iDawer): see MatchCheckCtx::is_uninhabited | 681 | //FIXME(iDawer): see MatchCheckCtx::is_uninhabited, has_no_hidden_fields is always true |
684 | unimplemented!("exhaustive_patterns feature") | 682 | unimplemented!("exhaustive_patterns feature") |
685 | } | 683 | } |
686 | } | 684 | } |
@@ -892,3 +890,11 @@ fn is_field_list_non_exhaustive(variant_id: VariantId, cx: &MatchCheckCtx<'_>) - | |||
892 | }; | 890 | }; |
893 | cx.db.attrs(attr_def_id).by_key("non_exhaustive").exists() | 891 | cx.db.attrs(attr_def_id).by_key("non_exhaustive").exists() |
894 | } | 892 | } |
893 | |||
894 | fn adt_is_box(adt: hir_def::AdtId, cx: &MatchCheckCtx<'_>) -> bool { | ||
895 | use hir_def::lang_item::LangItemTarget; | ||
896 | match cx.db.lang_item(cx.module.krate(), "owned_box".into()) { | ||
897 | Some(LangItemTarget::StructId(box_id)) => adt == box_id.into(), | ||
898 | _ => false, | ||
899 | } | ||
900 | } | ||
diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs index b01e3557c..44e08b6e9 100644 --- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs +++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs | |||
@@ -293,7 +293,7 @@ pub(crate) struct MatchCheckCtx<'a> { | |||
293 | pub(crate) match_expr: ExprId, | 293 | pub(crate) match_expr: ExprId, |
294 | pub(crate) infer: &'a InferenceResult, | 294 | pub(crate) infer: &'a InferenceResult, |
295 | pub(crate) db: &'a dyn HirDatabase, | 295 | pub(crate) db: &'a dyn HirDatabase, |
296 | /// Lowered patterns from self.body.pats plus generated by the check. | 296 | /// Lowered patterns from arms plus generated by the check. |
297 | pub(crate) pattern_arena: &'a RefCell<PatternArena>, | 297 | pub(crate) pattern_arena: &'a RefCell<PatternArena>, |
298 | } | 298 | } |
299 | 299 | ||
@@ -315,7 +315,7 @@ impl<'a> MatchCheckCtx<'a> { | |||
315 | 315 | ||
316 | // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." | 316 | // Rust feature described as "Allows exhaustive pattern matching on types that contain uninhabited types." |
317 | pub(super) fn feature_exhaustive_patterns(&self) -> bool { | 317 | pub(super) fn feature_exhaustive_patterns(&self) -> bool { |
318 | // TODO | 318 | // FIXME see MatchCheckCtx::is_uninhabited |
319 | false | 319 | false |
320 | } | 320 | } |
321 | 321 | ||