diff options
author | Dawer <[email protected]> | 2021-05-19 14:08:13 +0100 |
---|---|---|
committer | Dawer <[email protected]> | 2021-05-31 20:49:44 +0100 |
commit | 3088ca0a53540e0d7ae14f0d18efcad16cad0735 (patch) | |
tree | d4adc50c7bddda2470c64dff00a080f522a5ecac | |
parent | e16f413582ea45d6b318337ea2c7838fdc3b82a4 (diff) |
Take substitutions into account.
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check.rs | 20 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check/deconstruct_pat.rs | 25 | ||||
-rw-r--r-- | crates/hir_ty/src/diagnostics/match_check/usefulness.rs | 2 |
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 | ||
41 | impl Pat { | 41 | impl 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#" | ||
1153 | struct Foo<T>(T); | ||
1154 | struct Bar; | ||
1155 | fn 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 { |