aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorDawer <[email protected]>2021-05-19 14:08:13 +0100
committerDawer <[email protected]>2021-05-31 20:49:44 +0100
commit3088ca0a53540e0d7ae14f0d18efcad16cad0735 (patch)
treed4adc50c7bddda2470c64dff00a080f522a5ecac
parente16f413582ea45d6b318337ea2c7838fdc3b82a4 (diff)
Take substitutions into account.
-rw-r--r--crates/hir_ty/src/diagnostics/match_check.rs20
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs25
-rw-r--r--crates/hir_ty/src/diagnostics/match_check/usefulness.rs2
3 files changed, 33 insertions, 14 deletions
diff --git a/crates/hir_ty/src/diagnostics/match_check.rs b/crates/hir_ty/src/diagnostics/match_check.rs
index 5fb98ff35..992bb8682 100644
--- a/crates/hir_ty/src/diagnostics/match_check.rs
+++ b/crates/hir_ty/src/diagnostics/match_check.rs
@@ -39,8 +39,8 @@ pub(crate) struct Pat {
39} 39}
40 40
41impl Pat { 41impl Pat {
42 pub(crate) fn wildcard_from_ty(ty: &Ty) -> Self { 42 pub(crate) fn wildcard_from_ty(ty: Ty) -> Self {
43 Pat { ty: ty.clone(), kind: Box::new(PatKind::Wild) } 43 Pat { ty, kind: Box::new(PatKind::Wild) }
44 } 44 }
45} 45}
46 46
@@ -1145,6 +1145,22 @@ fn main() {
1145 ); 1145 );
1146 } 1146 }
1147 1147
1148 #[test]
1149 fn pattern_type_is_of_substitution() {
1150 cov_mark::check!(match_check_wildcard_expanded_to_substitutions);
1151 check_diagnostics(
1152 r#"
1153struct Foo<T>(T);
1154struct Bar;
1155fn main() {
1156 match Foo(Bar) {
1157 _ | Foo(Bar) => {}
1158 }
1159}
1160"#,
1161 );
1162 }
1163
1148 mod false_negatives { 1164 mod false_negatives {
1149 //! The implementation of match checking here is a work in progress. As we roll this out, we 1165 //! The implementation of match checking here is a work in progress. As we roll this out, we
1150 //! prefer false negatives to false positives (ideally there would be no false positives). This 1166 //! 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 15ec5cf45..a47082617 100644
--- a/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs
@@ -632,10 +632,7 @@ impl Fields {
632 } 632 }
633 633
634 /// Convenience; internal use. 634 /// Convenience; internal use.
635 fn wildcards_from_tys<'a>( 635 fn wildcards_from_tys(cx: &MatchCheckCtx<'_>, tys: impl IntoIterator<Item = Ty>) -> Self {
636 cx: &MatchCheckCtx<'_>,
637 tys: impl IntoIterator<Item = &'a Ty>,
638 ) -> Self {
639 let wilds = tys.into_iter().map(Pat::wildcard_from_ty); 636 let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
640 let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect(); 637 let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect();
641 Fields::Vec(pats) 638 Fields::Vec(pats)
@@ -645,13 +642,13 @@ impl Fields {
645 pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self { 642 pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self {
646 let ty = pcx.ty; 643 let ty = pcx.ty;
647 let cx = pcx.cx; 644 let cx = pcx.cx;
648 let wildcard_from_ty = |ty| cx.alloc_pat(Pat::wildcard_from_ty(ty)); 645 let wildcard_from_ty = |ty: &Ty| cx.alloc_pat(Pat::wildcard_from_ty(ty.clone()));
649 646
650 let ret = match constructor { 647 let ret = match constructor {
651 Single | Variant(_) => match ty.kind(&Interner) { 648 Single | Variant(_) => match ty.kind(&Interner) {
652 TyKind::Tuple(_, substs) => { 649 TyKind::Tuple(_, substs) => {
653 let tys = substs.iter(&Interner).map(|ty| ty.assert_ty_ref(&Interner)); 650 let tys = substs.iter(&Interner).map(|ty| ty.assert_ty_ref(&Interner));
654 Fields::wildcards_from_tys(cx, tys) 651 Fields::wildcards_from_tys(cx, tys.cloned())
655 } 652 }
656 TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)), 653 TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)),
657 &TyKind::Adt(AdtId(adt), ref substs) => { 654 &TyKind::Adt(AdtId(adt), ref substs) => {
@@ -666,14 +663,20 @@ impl Fields {
666 // Whether we must not match the fields of this variant exhaustively. 663 // Whether we must not match the fields of this variant exhaustively.
667 let is_non_exhaustive = 664 let is_non_exhaustive =
668 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local; 665 is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local;
669 let field_ty_arena = cx.db.field_types(variant_id); 666
670 let field_tys = 667 cov_mark::hit!(match_check_wildcard_expanded_to_substitutions);
671 || field_ty_arena.iter().map(|(_, binders)| binders.skip_binders()); 668 let field_ty_data = cx.db.field_types(variant_id);
669 let field_tys = || {
670 field_ty_data
671 .iter()
672 .map(|(_, binders)| binders.clone().substitute(&Interner, substs))
673 };
674
672 // In the following cases, we don't need to filter out any fields. This is 675 // In the following cases, we don't need to filter out any fields. This is
673 // the vast majority of real cases, since uninhabited fields are uncommon. 676 // the vast majority of real cases, since uninhabited fields are uncommon.
674 let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_)) 677 let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_))
675 && !is_non_exhaustive) 678 && !is_non_exhaustive)
676 || !field_tys().any(|ty| cx.is_uninhabited(ty)); 679 || !field_tys().any(|ty| cx.is_uninhabited(&ty));
677 680
678 if has_no_hidden_fields { 681 if has_no_hidden_fields {
679 Fields::wildcards_from_tys(cx, field_tys()) 682 Fields::wildcards_from_tys(cx, field_tys())
@@ -759,7 +762,7 @@ impl Fields {
759 FloatRange(..) => UNHANDLED, 762 FloatRange(..) => UNHANDLED,
760 Constructor::IntRange(_) => UNHANDLED, 763 Constructor::IntRange(_) => UNHANDLED,
761 NonExhaustive => PatKind::Wild, 764 NonExhaustive => PatKind::Wild,
762 Wildcard => return Pat::wildcard_from_ty(pcx.ty), 765 Wildcard => return Pat::wildcard_from_ty(pcx.ty.clone()),
763 Opaque => pcx.cx.bug("we should not try to apply an opaque constructor"), 766 Opaque => pcx.cx.bug("we should not try to apply an opaque constructor"),
764 Missing => pcx.cx.bug( 767 Missing => pcx.cx.bug(
765 "trying to apply the `Missing` constructor;\ 768 "trying to apply the `Missing` constructor;\
diff --git a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
index cb322a3de..61fba41bf 100644
--- a/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
+++ b/crates/hir_ty/src/diagnostics/match_check/usefulness.rs
@@ -1152,7 +1152,7 @@ pub(crate) fn compute_match_usefulness(
1152 .collect(); 1152 .collect();
1153 1153
1154 let wild_pattern = 1154 let wild_pattern =
1155 cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(&cx.infer[cx.match_expr])); 1155 cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(cx.infer[cx.match_expr].clone()));
1156 let v = PatStack::from_pattern(wild_pattern); 1156 let v = PatStack::from_pattern(wild_pattern);
1157 let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true); 1157 let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true);
1158 let non_exhaustiveness_witnesses = match usefulness { 1158 let non_exhaustiveness_witnesses = match usefulness {