From 3088ca0a53540e0d7ae14f0d18efcad16cad0735 Mon Sep 17 00:00:00 2001
From: Dawer <7803845+iDawer@users.noreply.github.com>
Date: Wed, 19 May 2021 18:08:13 +0500
Subject: [PATCH] Take substitutions into account.

---
 crates/hir_ty/src/diagnostics/match_check.rs  | 20 +++++++++++++--
 .../match_check/deconstruct_pat.rs            | 25 +++++++++++--------
 .../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 5fb98ff35c6..992bb868222 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 {
 }
 
 impl Pat {
-    pub(crate) fn wildcard_from_ty(ty: &Ty) -> Self {
-        Pat { ty: ty.clone(), kind: Box::new(PatKind::Wild) }
+    pub(crate) fn wildcard_from_ty(ty: Ty) -> Self {
+        Pat { ty, kind: Box::new(PatKind::Wild) }
     }
 }
 
@@ -1145,6 +1145,22 @@ fn main() {
         );
     }
 
+    #[test]
+    fn pattern_type_is_of_substitution() {
+        cov_mark::check!(match_check_wildcard_expanded_to_substitutions);
+        check_diagnostics(
+            r#"
+struct Foo<T>(T);
+struct Bar;
+fn main() {
+    match Foo(Bar) {
+        _ | Foo(Bar) => {}
+    }
+}
+"#,
+        );
+    }
+
     mod false_negatives {
         //! The implementation of match checking here is a work in progress. As we roll this out, we
         //! 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 15ec5cf4501..a470826174c 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 {
     }
 
     /// Convenience; internal use.
-    fn wildcards_from_tys<'a>(
-        cx: &MatchCheckCtx<'_>,
-        tys: impl IntoIterator<Item = &'a Ty>,
-    ) -> Self {
+    fn wildcards_from_tys(cx: &MatchCheckCtx<'_>, tys: impl IntoIterator<Item = Ty>) -> Self {
         let wilds = tys.into_iter().map(Pat::wildcard_from_ty);
         let pats = wilds.map(|pat| cx.alloc_pat(pat)).collect();
         Fields::Vec(pats)
@@ -645,13 +642,13 @@ impl Fields {
     pub(crate) fn wildcards(pcx: PatCtxt<'_>, constructor: &Constructor) -> Self {
         let ty = pcx.ty;
         let cx = pcx.cx;
-        let wildcard_from_ty = |ty| cx.alloc_pat(Pat::wildcard_from_ty(ty));
+        let wildcard_from_ty = |ty: &Ty| cx.alloc_pat(Pat::wildcard_from_ty(ty.clone()));
 
         let ret = match constructor {
             Single | Variant(_) => match ty.kind(&Interner) {
                 TyKind::Tuple(_, substs) => {
                     let tys = substs.iter(&Interner).map(|ty| ty.assert_ty_ref(&Interner));
-                    Fields::wildcards_from_tys(cx, tys)
+                    Fields::wildcards_from_tys(cx, tys.cloned())
                 }
                 TyKind::Ref(.., rty) => Fields::from_single_pattern(wildcard_from_ty(rty)),
                 &TyKind::Adt(AdtId(adt), ref substs) => {
@@ -666,14 +663,20 @@ impl Fields {
                         // Whether we must not match the fields of this variant exhaustively.
                         let is_non_exhaustive =
                             is_field_list_non_exhaustive(variant_id, cx) && !adt_is_local;
-                        let field_ty_arena = cx.db.field_types(variant_id);
-                        let field_tys =
-                            || field_ty_arena.iter().map(|(_, binders)| binders.skip_binders());
+
+                        cov_mark::hit!(match_check_wildcard_expanded_to_substitutions);
+                        let field_ty_data = cx.db.field_types(variant_id);
+                        let field_tys = || {
+                            field_ty_data
+                                .iter()
+                                .map(|(_, binders)| binders.clone().substitute(&Interner, substs))
+                        };
+
                         // In the following cases, we don't need to filter out any fields. This is
                         // the vast majority of real cases, since uninhabited fields are uncommon.
                         let has_no_hidden_fields = (matches!(adt, hir_def::AdtId::EnumId(_))
                             && !is_non_exhaustive)
-                            || !field_tys().any(|ty| cx.is_uninhabited(ty));
+                            || !field_tys().any(|ty| cx.is_uninhabited(&ty));
 
                         if has_no_hidden_fields {
                             Fields::wildcards_from_tys(cx, field_tys())
@@ -759,7 +762,7 @@ impl Fields {
             FloatRange(..) => UNHANDLED,
             Constructor::IntRange(_) => UNHANDLED,
             NonExhaustive => PatKind::Wild,
-            Wildcard => return Pat::wildcard_from_ty(pcx.ty),
+            Wildcard => return Pat::wildcard_from_ty(pcx.ty.clone()),
             Opaque => pcx.cx.bug("we should not try to apply an opaque constructor"),
             Missing => pcx.cx.bug(
                 "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 cb322a3de36..61fba41bf8d 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(
         .collect();
 
     let wild_pattern =
-        cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(&cx.infer[cx.match_expr]));
+        cx.pattern_arena.borrow_mut().alloc(Pat::wildcard_from_ty(cx.infer[cx.match_expr].clone()));
     let v = PatStack::from_pattern(wild_pattern);
     let usefulness = is_useful(cx, &matrix, &v, ConstructWitness, false, true);
     let non_exhaustiveness_witnesses = match usefulness {