diff options
| author | Manish Goregaokar <manishsmail@gmail.com> | 2021-10-01 14:46:52 -0700 |
|---|---|---|
| committer | GitHub <noreply@github.com> | 2021-10-01 14:46:52 -0700 |
| commit | 5ab1245303c26d3ae33b1adaa89fef2b8d9fb9ca (patch) | |
| tree | bbd7a3f43561a8f7c88d76fc9b162c4bf7620069 | |
| parent | b458ecf29dc65e3e62785a4e3fdacbec1f18188b (diff) | |
| parent | 68b76a48358e611e31de8e96c56b9e50862a960e (diff) | |
| download | rust-5ab1245303c26d3ae33b1adaa89fef2b8d9fb9ca.tar.gz rust-5ab1245303c26d3ae33b1adaa89fef2b8d9fb9ca.zip | |
Rollup merge of #89441 - Nadrieril:fix-89393, r=tmandry
Normalize after substituting via `field.ty()` Back in https://github.com/rust-lang/rust/issues/72476 I hadn't understood where the problem was coming from, and only worked around the issue. What happens is that calling `field.ty()` on a field of a generic struct substitutes the appropriate generics but doesn't normalize the resulting type. As a consumer of types I'm surprised that one would substitute without normalizing, feels like a footgun, so I added a comment. Fixes https://github.com/rust-lang/rust/issues/89393.
5 files changed, 62 insertions, 27 deletions
diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index d04d1565fea..82fad07b157 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1640,8 +1640,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() {} |
