From 68b76a48358e611e31de8e96c56b9e50862a960e Mon Sep 17 00:00:00 2001
From: Nadrieril <nadrieril+git@gmail.com>
Date: Fri, 1 Oct 2021 19:09:43 +0100
Subject: [PATCH] Normalize after substituting via `field.ty()`

---
 compiler/rustc_middle/src/ty/mod.rs           |  4 +-
 .../src/thir/pattern/deconstruct_pat.rs       |  4 +-
 .../src/thir/pattern/usefulness.rs            |  3 +-
 .../issue-72476-and-89393-associated-type.rs  | 56 +++++++++++++++++++
 .../usefulness/issue-72476-associated-type.rs | 22 --------
 5 files changed, 62 insertions(+), 27 deletions(-)
 create mode 100644 src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs
 delete mode 100644 src/test/ui/pattern/usefulness/issue-72476-associated-type.rs

diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs
index 777c6035be8..02c3b391a97 100644
--- a/compiler/rustc_middle/src/ty/mod.rs
+++ b/compiler/rustc_middle/src/ty/mod.rs
@@ -1627,8 +1627,8 @@ impl ReprOptions {
 }
 
 impl<'tcx> FieldDef {
-    /// Returns the type of this field. The `subst` is typically obtained
-    /// via the second field of `TyKind::AdtDef`.
+    /// Returns the type of this field. The resulting type is not normalized. The `subst` is
+    /// typically obtained via the second field of `TyKind::AdtDef`.
     pub fn ty(&self, tcx: TyCtxt<'tcx>, subst: SubstsRef<'tcx>) -> Ty<'tcx> {
         tcx.type_of(self.did).subst(tcx, subst)
     }
diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
index 69a7d44ff39..dfcbd0da3a6 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs
@@ -1154,6 +1154,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> {
 
         variant.fields.iter().enumerate().filter_map(move |(i, field)| {
             let ty = field.ty(cx.tcx, substs);
+            // `field.ty()` doesn't normalize after substituting.
+            let ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty);
             let is_visible = adt.is_enum() || field.vis.is_accessible_from(cx.module, cx.tcx);
             let is_uninhabited = cx.is_uninhabited(ty);
 
@@ -1671,7 +1673,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> {
                 write!(f, "{}", hi)
             }
             IntRange(range) => write!(f, "{:?}", range), // Best-effort, will render e.g. `false` as `0..=0`
-            Wildcard | Missing { .. } | NonExhaustive => write!(f, "_"),
+            Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty),
             Or => {
                 for pat in self.iter_fields() {
                     write!(f, "{}{:?}", start_or_continue(" | "), pat)?;
diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
index 650a87b2d88..43adef3d03b 100644
--- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
+++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs
@@ -781,8 +781,7 @@ fn is_useful<'p, 'tcx>(
 
     assert!(rows.iter().all(|r| r.len() == v.len()));
 
-    // FIXME(Nadrieril): Hack to work around type normalization issues (see #72476).
-    let ty = matrix.heads().next().map_or(v.head().ty(), |r| r.ty());
+    let ty = v.head().ty();
     let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty);
     let pcx = PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive };
 
diff --git a/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs
new file mode 100644
index 00000000000..058f4196798
--- /dev/null
+++ b/src/test/ui/pattern/usefulness/issue-72476-and-89393-associated-type.rs
@@ -0,0 +1,56 @@
+// check-pass
+
+// From https://github.com/rust-lang/rust/issues/72476
+// and https://github.com/rust-lang/rust/issues/89393
+
+trait Trait {
+    type Projection;
+}
+
+struct A;
+impl Trait for A {
+    type Projection = bool;
+}
+
+struct B;
+impl Trait for B {
+    type Projection = (u32, u32);
+}
+
+struct Next<T: Trait>(T::Projection);
+
+fn foo1(item: Next<A>) {
+    match item {
+        Next(true) => {}
+        Next(false) => {}
+    }
+}
+
+fn foo2(x: <A as Trait>::Projection) {
+    match x {
+        true => {}
+        false => {}
+    }
+}
+
+fn foo3(x: Next<B>) {
+    let Next((_, _)) = x;
+    match x {
+        Next((_, _)) => {}
+    }
+}
+
+fn foo4(x: <B as Trait>::Projection) {
+    let (_, _) = x;
+    match x {
+        (_, _) => {}
+    }
+}
+
+fn foo5<T: Trait>(x: <T as Trait>::Projection) {
+    match x {
+        _ => {}
+    }
+}
+
+fn main() {}
diff --git a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs b/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs
deleted file mode 100644
index 1e1d21433b7..00000000000
--- a/src/test/ui/pattern/usefulness/issue-72476-associated-type.rs
+++ /dev/null
@@ -1,22 +0,0 @@
-// check-pass
-
-// From https://github.com/rust-lang/rust/issues/72476
-
-trait A {
-    type Projection;
-}
-
-impl A for () {
-    type Projection = bool;
-}
-
-struct Next<T: A>(T::Projection);
-
-fn f(item: Next<()>) {
-    match item {
-        Next(true) => {}
-        Next(false) => {}
-    }
-}
-
-fn main() {}