aboutsummaryrefslogtreecommitdiff
path: root/crates/hir_ty/src/diagnostics
diff options
context:
space:
mode:
authorDawer <[email protected]>2021-05-12 07:04:56 +0100
committerDawer <[email protected]>2021-05-31 20:49:44 +0100
commit4cce7a6407821f456741a8d512ae31da3128c84f (patch)
treee7baddfdf72bcef8477fe20de090590b34932a3c /crates/hir_ty/src/diagnostics
parentf46a42f73aa92ab66800c70d525ddc7e6529edd6 (diff)
Box field detection; test #[non-exhaustive] attribute
Diffstat (limited to 'crates/hir_ty/src/diagnostics')
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs36
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs22
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs4
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]
1099pub enum E { A, B }
1100fn _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
1112use lib::E;
1113fn 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
894fn 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