From 68b76a48358e611e31de8e96c56b9e50862a960e Mon Sep 17 00:00:00 2001 From: Nadrieril 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 @@ pub fn inhibit_union_abi_opt(&self) -> bool { } 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 @@ fn list_variant_nonhidden_fields<'a>( 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 @@ fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { 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::Projection); + +fn foo1(item: Next) { + match item { + Next(true) => {} + Next(false) => {} + } +} + +fn foo2(x: ::Projection) { + match x { + true => {} + false => {} + } +} + +fn foo3(x: Next) { + let Next((_, _)) = x; + match x { + Next((_, _)) => {} + } +} + +fn foo4(x: ::Projection) { + let (_, _) = x; + match x { + (_, _) => {} + } +} + +fn foo5(x: ::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::Projection); - -fn f(item: Next<()>) { - match item { - Next(true) => {} - Next(false) => {} - } -} - -fn main() {}