From ac31d52324f3a0c41b5daabd842e36448fd95aae Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 2 Nov 2022 13:37:37 +0100 Subject: [PATCH 01/12] implement PlaceBuilder::try_ty --- Cargo.lock | 52 ++++++----------- .../src/build/expr/as_place.rs | 58 +++++++++++++++++++ 2 files changed, 75 insertions(+), 35 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index c987bf44ec00d..12e075a08c251 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,7 +285,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.68.0" +version = "0.67.0" dependencies = [ "anyhow", "atty", @@ -307,7 +307,6 @@ dependencies = [ "glob", "hex 0.4.2", "home", - "http-auth", "humantime 2.0.1", "ignore", "im-rc", @@ -350,11 +349,11 @@ dependencies = [ [[package]] name = "cargo-credential" -version = "0.2.0" +version = "0.1.0" [[package]] name = "cargo-credential-1password" -version = "0.2.0" +version = "0.1.0" dependencies = [ "cargo-credential", "serde", @@ -363,7 +362,7 @@ dependencies = [ [[package]] name = "cargo-credential-macos-keychain" -version = "0.2.0" +version = "0.1.0" dependencies = [ "cargo-credential", "security-framework", @@ -371,7 +370,7 @@ dependencies = [ [[package]] name = "cargo-credential-wincred" -version = "0.2.0" +version = "0.1.0" dependencies = [ "cargo-credential", "winapi", @@ -425,6 +424,7 @@ dependencies = [ "glob", "itertools", "lazy_static", + "remove_dir_all", "serde_json", "snapbox", "tar", @@ -436,7 +436,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.2.3" +version = "0.2.2" dependencies = [ "anyhow", "core-foundation", @@ -446,7 +446,7 @@ dependencies = [ "jobserver", "libc", "log", - "miow 0.5.0", + "miow", "same-file", "shell-escape", "tempfile", @@ -808,7 +808,7 @@ dependencies = [ "lazy_static", "lazycell", "libc", - "miow 0.3.7", + "miow", "miropt-test-tools", "regex", "rustfix", @@ -833,7 +833,7 @@ dependencies = [ "lazy_static", "libc", "log", - "miow 0.3.7", + "miow", "regex", "rustfix", "serde", @@ -846,9 +846,9 @@ dependencies = [ [[package]] name = "concolor" -version = "0.0.9" +version = "0.0.8" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b90f9dcd9490a97db91a85ccd79e38a87e14323f0bb824659ee3274e9143ba37" +checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af" dependencies = [ "atty", "bitflags", @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "concolor-query" -version = "0.1.0" +version = "0.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317" +checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449" [[package]] name = "content_inspector" @@ -909,7 +909,7 @@ dependencies = [ [[package]] name = "crates-io" -version = "0.35.0" +version = "0.34.0" dependencies = [ "anyhow", "curl", @@ -1698,15 +1698,6 @@ dependencies = [ "syn", ] -[[package]] -name = "http-auth" -version = "0.1.6" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c0b40b39d66c28829a0cf4d09f7e139ff8201f7500a5083732848ed3b4b4d850" -dependencies = [ - "memchr", -] - [[package]] name = "humantime" version = "1.3.0" @@ -2309,15 +2300,6 @@ dependencies = [ "winapi", ] -[[package]] -name = "miow" -version = "0.5.0" -source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" -dependencies = [ - "windows-sys", -] - [[package]] name = "miri" version = "0.1.0" @@ -4711,9 +4693,9 @@ checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" [[package]] name = "snapbox" -version = "0.4.1" +version = "0.3.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "827c00e91b15e2674d8a5270bae91f898693cbf9561cbb58d8eaa31974597293" +checksum = "44d199ccf8f606592df2d145db26f2aa45344e23c64b074cc5a4047f1d99b0f7" dependencies = [ "concolor", "content_inspector", diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index edd527286264a..b6f2e3de66827 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -323,6 +323,64 @@ impl<'tcx> PlaceBuilder<'tcx> { projection: Vec::from_iter(self.projection.iter().copied().chain([elem])), } } + + pub fn try_ty(&self, local_decls: &D, cx: &Builder<'_, 'tcx>) -> Option> + where + D: HasLocalDecls<'tcx>, + { + let tcx = cx.tcx; + + let project_ty = |ty: Ty<'tcx>, elem: &PlaceElem<'tcx>| -> Ty<'tcx> { + match elem { + ProjectionElem::Deref => { + ty.builtin_deref(true) + .unwrap_or_else(|| { + bug!("deref projection of non-dereferenceable ty {:?}", ty) + }) + .ty + } + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { + ty.builtin_index().unwrap() + } + ProjectionElem::Subslice { from, to, from_end } => match ty.kind() { + ty::Slice(..) => ty, + ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), + ty::Array(inner, size) if *from_end => { + let size = size.eval_usize(tcx, ty::ParamEnv::empty()); + let len = size - (*from as u64) - (*to as u64); + tcx.mk_array(*inner, len) + } + _ => bug!("cannot subslice non-array type: `{:?}`", ty), + }, + ProjectionElem::Downcast(..) => ty, + ProjectionElem::Field(_, ty) | ProjectionElem::OpaqueCast(ty) => *ty, + } + }; + + match self.base { + PlaceBase::Local(local) => { + let base_ty = local_decls.local_decls()[local].ty; + Some(self.projection.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem))) + } + PlaceBase::Upvar { .. } => { + match to_upvars_resolved_place_builder(self.clone(), cx) { + Ok(resolved_place_builder) => { + // `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok + resolved_place_builder.try_ty(local_decls, cx) + } + Err(place_builder) => { + match &place_builder.projection[..] { + &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => Some( + projections.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)), + ), + + _ => None, // would need a base `Ty` for these + } + } + } + } + } + } } impl<'tcx> From for PlaceBuilder<'tcx> { From 4d3a91b12b8c9e1b89a19c3663f430e58c16acd3 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 2 Nov 2022 13:39:47 +0100 Subject: [PATCH 02/12] use non-ascribed type as field type in mir --- .../src/build/matches/simplify.rs | 4 +- .../rustc_mir_build/src/build/matches/util.rs | 45 +++++++++++++++++++ 2 files changed, 48 insertions(+), 1 deletion(-) diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index f6b1955fdec4d..fb9f19b7b9066 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -294,7 +294,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Leaf { ref subpatterns } => { // tuple struct, match subpats (if any) - candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns)); + candidate + .match_pairs + .extend(self.field_match_pairs_tuple_struct(match_pair.place, subpatterns)); Ok(()) } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index bd435f9ab0095..6a07b07ee1278 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -25,6 +25,51 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .collect() } + #[instrument(skip(self), level = "debug")] + pub(crate) fn field_match_pairs_tuple_struct<'pat>( + &mut self, + place_builder: PlaceBuilder<'tcx>, + subpatterns: &'pat [FieldPat<'tcx>], + ) -> Vec> { + let place_ty = place_builder + .try_ty(&self.local_decls, self) + .map(|ty| self.tcx.normalize_erasing_regions(self.param_env, ty)); + debug!(?place_ty); + + subpatterns + .iter() + .map(|fieldpat| { + // NOTE: With type ascriptions it can happen that we get errors + // during borrow-checking on higher-ranked types if we use the + // ascribed type as the field type, so we try to get the actual field + // type from the `Place`, if possible, see issue #96514 + let field_ty = if let Some(place_ty) = place_ty { + let field_idx = fieldpat.field.as_usize(); + let field_ty = match place_ty.kind() { + ty::Adt(adt_def, substs) => { + adt_def.all_fields().collect::>()[field_idx].ty(self.tcx, substs) + } + ty::Tuple(elems) => elems.to_vec()[field_idx], + _ => bug!( + "no field available, place_ty: {:#?}, kind: {:?}", + place_ty, + place_ty.kind() + ), + }; + + self.tcx.normalize_erasing_regions(self.param_env, field_ty) + } else { + fieldpat.pattern.ty + }; + + let place = place_builder.clone().field(fieldpat.field, field_ty); + debug!(?place, ?field_ty); + + MatchPair::new(place, &fieldpat.pattern, self) + }) + .collect() + } + pub(crate) fn prefix_slice_suffix<'pat>( &mut self, match_pairs: &mut SmallVec<[MatchPair<'pat, 'tcx>; 1]>, From 906c52743aa60002abadae2a9f19673bdad3cf80 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 2 Nov 2022 13:49:42 +0100 Subject: [PATCH 03/12] add tests --- src/test/ui/mir/field-ty-ascription.rs | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) create mode 100644 src/test/ui/mir/field-ty-ascription.rs diff --git a/src/test/ui/mir/field-ty-ascription.rs b/src/test/ui/mir/field-ty-ascription.rs new file mode 100644 index 0000000000000..4147f05776a38 --- /dev/null +++ b/src/test/ui/mir/field-ty-ascription.rs @@ -0,0 +1,21 @@ +// build-pass + +struct Foo(T); // `T` is covariant. + +fn foo<'b>(x: Foo fn(&'a ())>) { + let Foo(y): Foo = x; +} + +fn foo_nested<'b>(x: Foo fn(&'a ())>>) { + let Foo(Foo(y)): Foo> = x; +} + +fn tuple<'b>(x: (u32, for<'a> fn(&'a ()))) { + let (_, y): (u32, fn(&'b ())) = x; +} + +fn tuple_nested<'b>(x: (u32, (u32, for<'a> fn(&'a ())))) { + let (_, (_, y)): (u32, (u32, fn(&'b ()))) = x; +} + +fn main() {} From f015842ed2094340ac1cce2cc4b559eca98e3371 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 2 Nov 2022 22:02:39 +0100 Subject: [PATCH 04/12] properly handle enum field projections --- .../src/build/expr/as_place.rs | 56 ++++++------------- .../src/build/matches/simplify.rs | 10 ++-- .../rustc_mir_build/src/build/matches/util.rs | 18 ++++-- 3 files changed, 35 insertions(+), 49 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index b6f2e3de66827..b682b0c3bd470 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -7,6 +7,7 @@ use rustc_hir::def_id::LocalDefId; use rustc_middle::hir::place::Projection as HirProjection; use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; +use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::AssertKind::BoundsCheck; use rustc_middle::mir::*; use rustc_middle::thir::*; @@ -324,56 +325,35 @@ impl<'tcx> PlaceBuilder<'tcx> { } } - pub fn try_ty(&self, local_decls: &D, cx: &Builder<'_, 'tcx>) -> Option> + pub fn try_compute_ty( + &self, + local_decls: &D, + cx: &Builder<'_, 'tcx>, + ) -> Option> where D: HasLocalDecls<'tcx>, { - let tcx = cx.tcx; - - let project_ty = |ty: Ty<'tcx>, elem: &PlaceElem<'tcx>| -> Ty<'tcx> { - match elem { - ProjectionElem::Deref => { - ty.builtin_deref(true) - .unwrap_or_else(|| { - bug!("deref projection of non-dereferenceable ty {:?}", ty) - }) - .ty - } - ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { - ty.builtin_index().unwrap() - } - ProjectionElem::Subslice { from, to, from_end } => match ty.kind() { - ty::Slice(..) => ty, - ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), - ty::Array(inner, size) if *from_end => { - let size = size.eval_usize(tcx, ty::ParamEnv::empty()); - let len = size - (*from as u64) - (*to as u64); - tcx.mk_array(*inner, len) - } - _ => bug!("cannot subslice non-array type: `{:?}`", ty), - }, - ProjectionElem::Downcast(..) => ty, - ProjectionElem::Field(_, ty) | ProjectionElem::OpaqueCast(ty) => *ty, - } - }; - match self.base { - PlaceBase::Local(local) => { - let base_ty = local_decls.local_decls()[local].ty; - Some(self.projection.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem))) - } + PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)), PlaceBase::Upvar { .. } => { match to_upvars_resolved_place_builder(self.clone(), cx) { Ok(resolved_place_builder) => { // `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok - resolved_place_builder.try_ty(local_decls, cx) + resolved_place_builder.try_compute_ty(local_decls, cx) } Err(place_builder) => { match &place_builder.projection[..] { - &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => Some( - projections.iter().fold(base_ty, |ty, &elem| project_ty(ty, &elem)), - ), + &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => { + let place_ty = projections + .iter() + .fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| { + place_ty.projection_ty(cx.tcx, elem) + }); + + debug!(?place_ty); + Some(place_ty) + } _ => None, // would need a base `Ty` for these } } diff --git a/compiler/rustc_mir_build/src/build/matches/simplify.rs b/compiler/rustc_mir_build/src/build/matches/simplify.rs index fb9f19b7b9066..36aa7693e827f 100644 --- a/compiler/rustc_mir_build/src/build/matches/simplify.rs +++ b/compiler/rustc_mir_build/src/build/matches/simplify.rs @@ -272,9 +272,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { || !adt_def.is_variant_list_non_exhaustive()); if irrefutable { let place_builder = match_pair.place.downcast(adt_def, variant_index); - candidate - .match_pairs - .extend(self.field_match_pairs(place_builder, subpatterns)); + let field_match_pairs = + self.field_match_pairs(place_builder.clone(), subpatterns); + candidate.match_pairs.extend(field_match_pairs); Ok(()) } else { Err(match_pair) @@ -294,9 +294,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { PatKind::Leaf { ref subpatterns } => { // tuple struct, match subpats (if any) - candidate - .match_pairs - .extend(self.field_match_pairs_tuple_struct(match_pair.place, subpatterns)); + candidate.match_pairs.extend(self.field_match_pairs(match_pair.place, subpatterns)); Ok(()) } diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 6a07b07ee1278..7423b5e1ae3ec 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -31,10 +31,14 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place_builder: PlaceBuilder<'tcx>, subpatterns: &'pat [FieldPat<'tcx>], ) -> Vec> { - let place_ty = place_builder - .try_ty(&self.local_decls, self) - .map(|ty| self.tcx.normalize_erasing_regions(self.param_env, ty)); - debug!(?place_ty); + let place_ty_and_variant_idx = + place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| { + ( + self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty), + place_ty.variant_index, + ) + }); + debug!(?place_ty_and_variant_idx); subpatterns .iter() @@ -43,9 +47,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // during borrow-checking on higher-ranked types if we use the // ascribed type as the field type, so we try to get the actual field // type from the `Place`, if possible, see issue #96514 - let field_ty = if let Some(place_ty) = place_ty { + let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx { let field_idx = fieldpat.field.as_usize(); let field_ty = match place_ty.kind() { + ty::Adt(adt_def, substs) if adt_def.is_enum() => { + let variant_idx = opt_variant_idx.unwrap(); + adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs) + } ty::Adt(adt_def, substs) => { adt_def.all_fields().collect::>()[field_idx].ty(self.tcx, substs) } From 2ef8308687f57335e117fdfa7d92002cf6f53eda Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 2 Nov 2022 22:05:19 +0100 Subject: [PATCH 05/12] add more tests --- src/test/ui/mir/field-ty-ascription-enums.rs | 15 +++++++++++++++ src/test/ui/mir/field-ty-ascription.rs | 16 ++++++++++++++++ 2 files changed, 31 insertions(+) create mode 100644 src/test/ui/mir/field-ty-ascription-enums.rs diff --git a/src/test/ui/mir/field-ty-ascription-enums.rs b/src/test/ui/mir/field-ty-ascription-enums.rs new file mode 100644 index 0000000000000..179af61709063 --- /dev/null +++ b/src/test/ui/mir/field-ty-ascription-enums.rs @@ -0,0 +1,15 @@ +// build-pass + +enum Foo { + Var(T), +} // `T` is covariant. + +fn foo<'b>(x: Foo fn(&'a ())>) { + let Foo::Var(x): Foo = x; +} + +fn foo_nested<'b>(x: Foo fn(&'a ())>>) { + let Foo::Var(Foo::Var(x)): Foo> = x; +} + +fn main() {} diff --git a/src/test/ui/mir/field-ty-ascription.rs b/src/test/ui/mir/field-ty-ascription.rs index 4147f05776a38..178c7916bc59f 100644 --- a/src/test/ui/mir/field-ty-ascription.rs +++ b/src/test/ui/mir/field-ty-ascription.rs @@ -2,6 +2,22 @@ struct Foo(T); // `T` is covariant. +struct Bar { + x: T, +} // `T` is covariant. + +fn bar<'b>(x: Bar fn(&'a ())>) { + let Bar { x }: Bar = x; +} + +fn bar_nested<'b>(x: Bar fn(&'a ())>>) { + let Bar { x: Bar { x } }: Bar> = x; +} + +fn bar_foo_nested<'b>(x: Bar fn(&'a ())>>) { + let Bar { x: Foo ( x ) }: Bar> = x; +} + fn foo<'b>(x: Foo fn(&'a ())>) { let Foo(y): Foo = x; } From fd6fed3027be425c27a5a8c825575bdd7a1e63dd Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 2 Nov 2022 22:20:17 +0100 Subject: [PATCH 06/12] address review --- .../rustc_mir_build/src/build/expr/as_place.rs | 7 +++++++ .../rustc_mir_build/src/build/matches/util.rs | 18 ++++++++++++++---- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index b682b0c3bd470..36f08a7a48fd2 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -325,6 +325,13 @@ impl<'tcx> PlaceBuilder<'tcx> { } } + /// Similar to `Place::ty` but needed during mir building. + /// + /// Applies the projections in the `PlaceBuilder` to the base + /// type. + /// + /// Fallible as the root of this place may be an upvar for + /// which no base type can be determined. pub fn try_compute_ty( &self, local_decls: &D, diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 7423b5e1ae3ec..fb2a5be28a2eb 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -54,10 +54,20 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let variant_idx = opt_variant_idx.unwrap(); adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs) } - ty::Adt(adt_def, substs) => { - adt_def.all_fields().collect::>()[field_idx].ty(self.tcx, substs) - } - ty::Tuple(elems) => elems.to_vec()[field_idx], + ty::Adt(adt_def, substs) => adt_def + .all_fields() + .nth(field_idx) + .unwrap_or_else(|| { + bug!( + "expected to take field idx {:?} of fields of {:?}", + field_idx, + adt_def + ) + }) + .ty(self.tcx, substs), + ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| { + bug!("expected to take field idx {:?} of {:?}", field_idx, elems) + }), _ => bug!( "no field available, place_ty: {:#?}, kind: {:?}", place_ty, From 4040734e44d72697dbeb35c4c1be1a70cb7b0b37 Mon Sep 17 00:00:00 2001 From: b-naber Date: Mon, 21 Nov 2022 20:56:27 +0100 Subject: [PATCH 07/12] get field ty during projecting --- Cargo.lock | 52 ++-- .../src/build/expr/as_place.rs | 264 ++++++++++++------ .../src/build/expr/as_rvalue.rs | 9 +- .../rustc_mir_build/src/build/expr/into.rs | 6 +- .../rustc_mir_build/src/build/matches/test.rs | 3 +- .../rustc_mir_build/src/build/matches/util.rs | 73 +---- 6 files changed, 222 insertions(+), 185 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 12e075a08c251..c987bf44ec00d 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -285,7 +285,7 @@ dependencies = [ [[package]] name = "cargo" -version = "0.67.0" +version = "0.68.0" dependencies = [ "anyhow", "atty", @@ -307,6 +307,7 @@ dependencies = [ "glob", "hex 0.4.2", "home", + "http-auth", "humantime 2.0.1", "ignore", "im-rc", @@ -349,11 +350,11 @@ dependencies = [ [[package]] name = "cargo-credential" -version = "0.1.0" +version = "0.2.0" [[package]] name = "cargo-credential-1password" -version = "0.1.0" +version = "0.2.0" dependencies = [ "cargo-credential", "serde", @@ -362,7 +363,7 @@ dependencies = [ [[package]] name = "cargo-credential-macos-keychain" -version = "0.1.0" +version = "0.2.0" dependencies = [ "cargo-credential", "security-framework", @@ -370,7 +371,7 @@ dependencies = [ [[package]] name = "cargo-credential-wincred" -version = "0.1.0" +version = "0.2.0" dependencies = [ "cargo-credential", "winapi", @@ -424,7 +425,6 @@ dependencies = [ "glob", "itertools", "lazy_static", - "remove_dir_all", "serde_json", "snapbox", "tar", @@ -436,7 +436,7 @@ dependencies = [ [[package]] name = "cargo-util" -version = "0.2.2" +version = "0.2.3" dependencies = [ "anyhow", "core-foundation", @@ -446,7 +446,7 @@ dependencies = [ "jobserver", "libc", "log", - "miow", + "miow 0.5.0", "same-file", "shell-escape", "tempfile", @@ -808,7 +808,7 @@ dependencies = [ "lazy_static", "lazycell", "libc", - "miow", + "miow 0.3.7", "miropt-test-tools", "regex", "rustfix", @@ -833,7 +833,7 @@ dependencies = [ "lazy_static", "libc", "log", - "miow", + "miow 0.3.7", "regex", "rustfix", "serde", @@ -846,9 +846,9 @@ dependencies = [ [[package]] name = "concolor" -version = "0.0.8" +version = "0.0.9" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "015267563b1df20adccdd00cb05257b1dfbea70a04928e9cf88ffb850c1a40af" +checksum = "b90f9dcd9490a97db91a85ccd79e38a87e14323f0bb824659ee3274e9143ba37" dependencies = [ "atty", "bitflags", @@ -857,9 +857,9 @@ dependencies = [ [[package]] name = "concolor-query" -version = "0.0.5" +version = "0.1.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6417fe6fc03a8b533fd2177742eeb39a90c7233eedec7bac96d4d6b69a09449" +checksum = "82a90734b3d5dcf656e7624cca6bce9c3a90ee11f900e80141a7427ccfb3d317" [[package]] name = "content_inspector" @@ -909,7 +909,7 @@ dependencies = [ [[package]] name = "crates-io" -version = "0.34.0" +version = "0.35.0" dependencies = [ "anyhow", "curl", @@ -1698,6 +1698,15 @@ dependencies = [ "syn", ] +[[package]] +name = "http-auth" +version = "0.1.6" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "c0b40b39d66c28829a0cf4d09f7e139ff8201f7500a5083732848ed3b4b4d850" +dependencies = [ + "memchr", +] + [[package]] name = "humantime" version = "1.3.0" @@ -2300,6 +2309,15 @@ dependencies = [ "winapi", ] +[[package]] +name = "miow" +version = "0.5.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "52ffbca2f655e33c08be35d87278e5b18b89550a37dbd598c20db92f6a471123" +dependencies = [ + "windows-sys", +] + [[package]] name = "miri" version = "0.1.0" @@ -4693,9 +4711,9 @@ checksum = "da73c8f77aebc0e40c300b93f0a5f1bece7a248a36eee287d4e095f35c7b7d6e" [[package]] name = "snapbox" -version = "0.3.3" +version = "0.4.1" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "44d199ccf8f606592df2d145db26f2aa45344e23c64b074cc5a4047f1d99b0f7" +checksum = "827c00e91b15e2674d8a5270bae91f898693cbf9561cbb58d8eaa31974597293" dependencies = [ "concolor", "content_inspector", diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 36f08a7a48fd2..5c9459c97f403 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -21,21 +21,28 @@ use rustc_index::vec::Idx; use std::assert_matches::assert_matches; use std::iter; -/// The "outermost" place that holds this value. -#[derive(Copy, Clone, Debug, PartialEq)] -pub(crate) enum PlaceBase { +/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a +/// place by pushing more and more projections onto the end, and then convert the final set into a +/// place using the `into_place` method. +/// +/// This is used internally when building a place for an expression like `a.b.c`. The fields `b` +/// and `c` can be progressively pushed onto the place builder that is created when converting `a`. +#[derive(Clone, Debug, PartialEq)] +pub(in crate::build) enum PlaceBuilder<'tcx> { /// Denotes the start of a `Place`. - Local(Local), + /// + /// We use `PlaceElem` since this has all `Field` types available. + Local(Local, Vec>), /// When building place for an expression within a closure, the place might start off a /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture /// index (within the desugared closure) of the captured path until most of the projections - /// are applied. We use `PlaceBase::Upvar` to keep track of the root variable off of which the + /// are applied. We use `PlaceBuilder::Upvar` to keep track of the root variable off of which the /// captured path starts, the closure the capture belongs to and the trait the closure /// implements. /// - /// Once we have figured out the capture index, we can convert the place builder to start from - /// `PlaceBase::Local`. + /// Once we have figured out the capture index, we can convert the place builder to + /// `PlaceBuilder::Local`. /// /// Consider the following example /// ```rust @@ -56,24 +63,16 @@ pub(crate) enum PlaceBase { /// /// When `capture_disjoint_fields` is enabled, `t.0.0.0` is captured and we won't be able to /// figure out that it is captured until all the `Field` projections are applied. - Upvar { - /// HirId of the upvar - var_hir_id: LocalVarId, - /// DefId of the closure - closure_def_id: LocalDefId, - }, + /// + /// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types + /// and will only do so once converting to `PlaceBuilder::Local`. + UpVar(UpVar, Vec>), } -/// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a -/// place by pushing more and more projections onto the end, and then convert the final set into a -/// place using the `to_place` method. -/// -/// This is used internally when building a place for an expression like `a.b.c`. The fields `b` -/// and `c` can be progressively pushed onto the place builder that is created when converting `a`. -#[derive(Clone, Debug, PartialEq)] -pub(in crate::build) struct PlaceBuilder<'tcx> { - base: PlaceBase, - projection: Vec>, +#[derive(Copy, Clone, Debug, PartialEq)] +pub(crate) struct UpVar { + var_hir_id: LocalVarId, + closure_def_id: LocalDefId, } /// Given a list of MIR projections, convert them to list of HIR ProjectionKind. @@ -175,7 +174,7 @@ fn to_upvars_resolved_place_builder<'tcx>( cx: &Builder<'_, 'tcx>, var_hir_id: LocalVarId, closure_def_id: LocalDefId, - projection: &[PlaceElem<'tcx>], + projection: &[UpvarProjectionElem<'tcx>], ) -> Option> { let Some((capture_index, capture)) = find_capture_matching_projections( @@ -197,23 +196,31 @@ fn to_upvars_resolved_place_builder<'tcx>( var_hir_id, projection, ); } + return None; }; // Access the capture by accessing the field within the Closure struct. let capture_info = &cx.upvars[capture_index]; - let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place); + let Place { local: upvar_resolved_local, projection: local_projection } = + capture_info.use_place; // We used some of the projections to build the capture itself, // now we apply the remaining to the upvar resolved place. - trace!(?capture.captured_place, ?projection); - let remaining_projections = strip_prefix( + let upvar_projection = strip_prefix( capture.captured_place.place.base_ty, projection, &capture.captured_place.place.projections, + ) + .collect::>(); + + let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder( + cx, + upvar_resolved_local, + local_projection.to_vec(), + upvar_projection, ); - upvar_resolved_place_builder.projection.extend(remaining_projections); Some(upvar_resolved_place_builder) } @@ -235,6 +242,8 @@ fn strip_prefix<'a, 'tcx>( // Filter out opaque casts, they are unnecessary in the prefix. .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))); for projection in prefix_projections { + debug!(?projection, ?projection.ty); + match projection.kind { HirProjectionKind::Deref => { assert_matches!(iter.next(), Some(ProjectionElem::Deref)); @@ -249,6 +258,7 @@ fn strip_prefix<'a, 'tcx>( bug!("unexpected projection kind: {:?}", projection); } } + base_ty = projection.ty; } iter @@ -263,9 +273,9 @@ impl<'tcx> PlaceBuilder<'tcx> { pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option> { let resolved = self.resolve_upvar(cx); let builder = resolved.as_ref().unwrap_or(self); - let PlaceBase::Local(local) = builder.base else { return None }; - let projection = cx.tcx.intern_place_elems(&builder.projection); - Some(Place { local, projection }) + let PlaceBuilder::Local(local, projection) = builder else { return None }; + let projection = cx.tcx.intern_place_elems(&projection); + Some(Place { local: *local, projection }) } /// Attempts to resolve the `PlaceBuilder`. @@ -282,22 +292,39 @@ impl<'tcx> PlaceBuilder<'tcx> { &self, cx: &Builder<'_, 'tcx>, ) -> Option> { - let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else { + let PlaceBuilder::Upvar( Upvar {var_hir_id, closure_def_id }, projection) = self else { return None; }; - to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection) - } - pub(crate) fn base(&self) -> PlaceBase { - self.base + to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &projection) } - pub(crate) fn projection(&self) -> &[PlaceElem<'tcx>] { - &self.projection + pub(crate) fn get_local_projection(&self) -> &[PlaceElem<'tcx>] { + match self { + Self::Local(_, projection) => projection, + Self::UpVar(..) => { + bug!("get_local_projection_mut can only be called on PlaceBuilder::Local") + } + } } - pub(crate) fn field(self, f: Field, ty: Ty<'tcx>) -> Self { - self.project(PlaceElem::Field(f, ty)) + #[instrument(skip(cx), level = "debug")] + pub(crate) fn field( + self, + cx: &Builder<'_, 'tcx>, + f: Field, + default_field_ty: Ty<'tcx>, + ) -> Self { + let field_ty = match self { + PlaceBuilder::Local(..) => { + let base_place = self.clone(); + PlaceBuilder::try_compute_field_ty(cx, f, base_place) + .unwrap_or_else(|| default_field_ty) + } + PlaceBuilder::UpVar(..) => default_field_ty, + }; + + self.project(ProjectionElem::Field(f, field_ty)) } pub(crate) fn deref(self) -> Self { @@ -312,16 +339,34 @@ impl<'tcx> PlaceBuilder<'tcx> { self.project(PlaceElem::Index(index)) } - pub(crate) fn project(mut self, elem: PlaceElem<'tcx>) -> Self { - self.projection.push(elem); - self + #[instrument(level = "debug")] + pub(crate) fn project(self, elem: PlaceElem<'tcx>) -> Self { + let result = match self { + PlaceBuilder::Local(local, mut proj) => { + proj.push(elem); + PlaceBuilder::Local(local, proj) + } + PlaceBuilder::UpVar(upvar, mut proj) => { + proj.push(elem); + PlaceBuilder::UpVar(upvar, proj) + } + }; + + debug!(?result); + result } /// Same as `.clone().project(..)` but more efficient pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self { - Self { - base: self.base, - projection: Vec::from_iter(self.projection.iter().copied().chain([elem])), + match self { + PlaceBuilder::Local(local, proj) => PlaceBuilder::Local( + *local, + Vec::from_iter(proj.iter().copied().chain([elem.into()])), + ), + PlaceBuilder::Upvar(upvar, proj) => PlaceBuilder::UpVar( + upvar, + Vec::from_iter(proj.iter().copied().chain([elem.into()])), + ), } } @@ -332,59 +377,96 @@ impl<'tcx> PlaceBuilder<'tcx> { /// /// Fallible as the root of this place may be an upvar for /// which no base type can be determined. - pub fn try_compute_ty( - &self, - local_decls: &D, + #[instrument(skip(cx), level = "debug")] + fn try_compute_field_ty( cx: &Builder<'_, 'tcx>, - ) -> Option> - where - D: HasLocalDecls<'tcx>, - { - match self.base { - PlaceBase::Local(_) => Some(self.clone().into_place(cx).ty(local_decls, cx.tcx)), - PlaceBase::Upvar { .. } => { - match to_upvars_resolved_place_builder(self.clone(), cx) { - Ok(resolved_place_builder) => { - // `base` is guaranteed to be `PlaceBase::Local` now, so recursive call is ok - resolved_place_builder.try_compute_ty(local_decls, cx) - } - Err(place_builder) => { - match &place_builder.projection[..] { - &[ProjectionElem::OpaqueCast(base_ty), ref projections @ ..] => { - let place_ty = projections - .iter() - .fold(PlaceTy::from_ty(base_ty), |place_ty, &elem| { - place_ty.projection_ty(cx.tcx, elem) - }); - - debug!(?place_ty); - - Some(place_ty) - } - _ => None, // would need a base `Ty` for these - } - } + field: Field, + base_place: PlaceBuilder<'tcx>, + ) -> Option> { + let field_idx = field.as_usize(); + let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx); + let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + debug!(?base_ty); + + let field_ty = match base_ty.kind() { + ty::Adt(adt_def, substs) if adt_def.is_enum() => { + let variant_idx = variant_index.unwrap(); + adt_def.variant(variant_idx).fields[field_idx].ty(cx.tcx, substs) + } + ty::Adt(adt_def, substs) => adt_def + .all_fields() + .nth(field_idx) + .unwrap_or_else(|| { + bug!("expected to take field idx {:?} of fields of {:?}", field_idx, adt_def) + }) + .ty(cx.tcx, substs), + ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| { + bug!("expected to take field idx {:?} of {:?}", field_idx, elems) + }), + _ => return None, + }; + + Some(cx.tcx.normalize_erasing_regions(cx.param_env, field_ty)) + } + + /// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::UpVar` whose upvars + /// are resolved. This function takes two kinds of projections: `local_projection` + /// contains the projections of the captured upvar and `upvar_projection` the + /// projections that are applied to the captured upvar. The main purpose of this + /// function is to figure out the `Ty`s of the field projections in `upvar_projection`. + #[instrument(skip(cx, local))] + fn construct_local_place_builder( + cx: &Builder<'_, 'tcx>, + local: Local, + mut local_projection: Vec>, + upvar_projection: Vec>, + ) -> Self { + // We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use + // the ancestor projections, i.e. those projection elements that come before the field projection, + // to get the `Ty` for the field. + + for proj in upvar_projection.iter() { + debug!("proj: {:?}, local_projection: {:?}", proj, local_projection); + match *proj { + ProjectionElem::Field(field, default_field_ty) => { + let ancestor_proj = local_projection.to_vec(); + let base_place = PlaceBuilder::Local(local, ancestor_proj); + let field_ty = PlaceBuilder::try_compute_field_ty(cx, field, base_place) + .unwrap_or_else(|| default_field_ty); + debug!(?field_ty); + + local_projection.push(ProjectionElem::Field(field, field_ty)); + debug!(?local_projection); + } + ProjectionElem::Deref => local_projection.push(ProjectionElem::Deref), + ProjectionElem::Index(idx) => local_projection.push(ProjectionElem::Index(idx)), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => local_projection + .push(ProjectionElem::ConstantIndex { offset, min_length, from_end }), + ProjectionElem::Subslice { from, to, from_end } => { + local_projection.push(ProjectionElem::Subslice { from, to, from_end }) + } + ProjectionElem::Downcast(sym, variant_idx) => { + local_projection.push(ProjectionElem::Downcast(sym, variant_idx)) + } + ProjectionElem::OpaqueCast(ty) => { + local_projection.push(ProjectionElem::OpaqueCast(ty)) } } } + + PlaceBuilder::Local(local, local_projection) } } impl<'tcx> From for PlaceBuilder<'tcx> { fn from(local: Local) -> Self { - Self { base: PlaceBase::Local(local), projection: Vec::new() } - } -} - -impl<'tcx> From for PlaceBuilder<'tcx> { - fn from(base: PlaceBase) -> Self { - Self { base, projection: Vec::new() } + Self::Local(local, Vec::new()) } } impl<'tcx> From> for PlaceBuilder<'tcx> { fn from(p: Place<'tcx>) -> Self { - Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() } + Self::Local(p.local, p.projection.to_vec()) } } @@ -448,6 +530,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { self.expr_as_place(block, expr, Mutability::Not, None) } + #[instrument(skip(self, fake_borrow_temps), level = "debug")] fn expr_as_place( &mut self, mut block: BasicBlock, @@ -455,8 +538,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { mutability: Mutability, fake_borrow_temps: Option<&mut Vec>, ) -> BlockAnd> { - debug!("expr_as_place(block={:?}, expr={:?}, mutability={:?})", block, expr, mutability); - let this = self; let expr_span = expr.span; let source_info = this.source_info(expr_span); @@ -470,12 +551,13 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let lhs = &this.thir[lhs]; let mut place_builder = unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,)); + debug!(?place_builder); if let ty::Adt(adt_def, _) = lhs.ty.kind() { if adt_def.is_enum() { place_builder = place_builder.downcast(*adt_def, variant_index); } } - block.and(place_builder.field(name, expr.ty)) + block.and(place_builder.field(this, name, expr.ty)) } ExprKind::Deref { arg } => { let place_builder = unpack!( @@ -617,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Lower a captured upvar. Note we might not know the actual capture index, - /// so we create a place starting from `PlaceBase::Upvar`, which will be resolved + /// so we create a place starting from `UpVar`, which will be resolved /// once all projections that allow us to identify a capture have been applied. fn lower_captured_upvar( &mut self, @@ -625,7 +707,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { closure_def_id: LocalDefId, var_hir_id: LocalVarId, ) -> BlockAnd> { - block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id })) + block.and(PlaceBuilder::UpVar(UpVar { var_hir_id, closure_def_id }, vec![])) } /// Lower an index expression @@ -716,8 +798,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { source_info: SourceInfo, ) { let tcx = self.tcx; - let place_ty = base_place.ty(&self.local_decls, tcx); + if let ty::Slice(_) = place_ty.ty.kind() { // We need to create fake borrows to ensure that the bounds // check that we just did stays valid. Since we can't assign to diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 0814793f27790..618aa9e310954 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -4,9 +4,8 @@ use rustc_index::vec::Idx; use rustc_middle::ty::util::IntTypeExt; use rustc_target::abi::{Abi, Primitive}; -use crate::build::expr::as_place::PlaceBase; use crate::build::expr::category::{Category, RvalueFunc}; -use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary}; +use crate::build::{BlockAnd, BlockAndExtension, Builder, NeedsTemporary, PlaceBuilder}; use rustc_hir::lang_items::LangItem; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind; @@ -651,15 +650,15 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let arg_place_builder = unpack!(block = this.as_place_builder(block, arg)); - let mutability = match arg_place_builder.base() { + let mutability = match arg_place_builder { // We are capturing a path that starts off a local variable in the parent. // The mutability of the current capture is same as the mutability // of the local declaration in the parent. - PlaceBase::Local(local) => this.local_decls[local].mutability, + PlaceBuilder::Local(local, _) => this.local_decls[local].mutability, // Parent is a closure and we are capturing a path that is captured // by the parent itself. The mutability of the current capture // is same as that of the capture in the parent closure. - PlaceBase::Upvar { .. } => { + PlaceBuilder::UpVar(..) => { let enclosing_upvars_resolved = arg_place_builder.to_place(this); match enclosing_upvars_resolved.as_ref() { diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 218a26e62797d..12cd0e65a1158 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -358,8 +358,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { .map(|(n, ty)| match fields_map.get(&n) { Some(v) => v.clone(), None => { - let place = place_builder.clone_project(PlaceElem::Field(n, *ty)); - this.consume_by_copy_or_move(place.to_place(this)) + let place_builder = place_builder.clone(); + this.consume_by_copy_or_move( + place_builder.field(this, n, *ty).to_place(this), + ) } }) .collect() diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 58513bde2aa2a..7b932eda74432 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -760,8 +760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter().map(|subpattern| { // e.g., `(x as Variant).0` - let place = downcast_place - .clone_project(PlaceElem::Field(subpattern.field, subpattern.pattern.ty)); + let place = downcast_place.clone().field(self, subpattern.field, subpattern.pattern.ty); // e.g., `(x as Variant).0 @ P1` MatchPair::new(place, &subpattern.pattern, self) }); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index fb2a5be28a2eb..30f4e49d8bae5 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -1,4 +1,3 @@ -use crate::build::expr::as_place::PlaceBase; use crate::build::expr::as_place::PlaceBuilder; use crate::build::matches::MatchPair; use crate::build::Builder; @@ -18,70 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { subpatterns .iter() .map(|fieldpat| { - let place = - place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPair::new(place, &fieldpat.pattern, self) - }) - .collect() - } - - #[instrument(skip(self), level = "debug")] - pub(crate) fn field_match_pairs_tuple_struct<'pat>( - &mut self, - place_builder: PlaceBuilder<'tcx>, - subpatterns: &'pat [FieldPat<'tcx>], - ) -> Vec> { - let place_ty_and_variant_idx = - place_builder.try_compute_ty(&self.local_decls, self).map(|place_ty| { - ( - self.tcx.normalize_erasing_regions(self.param_env, place_ty.ty), - place_ty.variant_index, - ) - }); - debug!(?place_ty_and_variant_idx); - - subpatterns - .iter() - .map(|fieldpat| { - // NOTE: With type ascriptions it can happen that we get errors - // during borrow-checking on higher-ranked types if we use the - // ascribed type as the field type, so we try to get the actual field - // type from the `Place`, if possible, see issue #96514 - let field_ty = if let Some((place_ty, opt_variant_idx)) = place_ty_and_variant_idx { - let field_idx = fieldpat.field.as_usize(); - let field_ty = match place_ty.kind() { - ty::Adt(adt_def, substs) if adt_def.is_enum() => { - let variant_idx = opt_variant_idx.unwrap(); - adt_def.variant(variant_idx).fields[field_idx].ty(self.tcx, substs) - } - ty::Adt(adt_def, substs) => adt_def - .all_fields() - .nth(field_idx) - .unwrap_or_else(|| { - bug!( - "expected to take field idx {:?} of fields of {:?}", - field_idx, - adt_def - ) - }) - .ty(self.tcx, substs), - ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| { - bug!("expected to take field idx {:?} of {:?}", field_idx, elems) - }), - _ => bug!( - "no field available, place_ty: {:#?}, kind: {:?}", - place_ty, - place_ty.kind() - ), - }; - - self.tcx.normalize_erasing_regions(self.param_env, field_ty) - } else { - fieldpat.pattern.ty - }; - - let place = place_builder.clone().field(fieldpat.field, field_ty); - debug!(?place, ?field_ty); + let place = place.clone().field(self, fieldpat.field, fieldpat.pattern.ty); MatchPair::new(place, &fieldpat.pattern, self) }) @@ -171,9 +107,10 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { // Only add the OpaqueCast projection if the given place is an opaque type and the // expected type from the pattern is not. - let may_need_cast = match place.base() { - PlaceBase::Local(local) => { - let ty = Place::ty_from(local, place.projection(), &cx.local_decls, cx.tcx).ty; + let may_need_cast = match place { + PlaceBuilder::Local(local, _) => { + let ty = + Place::ty_from(local, place.get_local_projection(), &cx.local_decls, cx.tcx).ty; ty != pattern.ty && ty.has_opaque_types() } _ => true, From 4d00026edd315a05c4aff27c8d8cb233a6e95d92 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 22 Nov 2022 22:08:09 +0100 Subject: [PATCH 08/12] add invariance test --- src/test/ui/mir/field-projection-invariant.rs | 24 +++++++++++++++++++ 1 file changed, 24 insertions(+) create mode 100644 src/test/ui/mir/field-projection-invariant.rs diff --git a/src/test/ui/mir/field-projection-invariant.rs b/src/test/ui/mir/field-projection-invariant.rs new file mode 100644 index 0000000000000..b5d6add043cb9 --- /dev/null +++ b/src/test/ui/mir/field-projection-invariant.rs @@ -0,0 +1,24 @@ +// build-pass +struct Inv<'a>(&'a mut &'a ()); +enum Foo { + Bar, + Var(T), +} +type Supertype = Foo fn(Inv<'a>, Inv<'a>)>; + +fn foo(x: Foo fn(Inv<'a>, Inv<'b>)>) { + match x { + Supertype::Bar => {} + Supertype::Var(x) => {} + } +} + +fn foo_nested(x: Foo fn(Inv<'a>, Inv<'b>)>>) { + match x { + Foo::Bar => {} + Foo::Var(Supertype::Bar) => {} + Foo::Var(Supertype::Var(x)) => {} + } +} + +fn main() {} From c39de61d2a8fd1f3226e623d67e1e5bac593dac6 Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 23 Nov 2022 17:42:12 +0100 Subject: [PATCH 09/12] include closures and generators in try_compute_field_ty --- .../src/build/expr/as_place.rs | 42 +++++++++++++++++-- 1 file changed, 39 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 5c9459c97f403..bf417dae78511 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -397,13 +397,49 @@ impl<'tcx> PlaceBuilder<'tcx> { .all_fields() .nth(field_idx) .unwrap_or_else(|| { - bug!("expected to take field idx {:?} of fields of {:?}", field_idx, adt_def) + bug!( + "expected to take field with idx {:?} of fields of {:?}", + field_idx, + adt_def + ) }) .ty(cx.tcx, substs), ty::Tuple(elems) => elems.iter().nth(field_idx).unwrap_or_else(|| { - bug!("expected to take field idx {:?} of {:?}", field_idx, elems) + bug!("expected to take field with idx {:?} of {:?}", field_idx, elems) }), - _ => return None, + ty::Closure(_, substs) => { + let substs = substs.as_closure(); + let Some(f_ty) = substs.upvar_tys().nth(field_idx) else { + bug!("expected to take field with idx {:?} of {:?}", field_idx, substs.upvar_tys().collect::>()); + }; + + f_ty + } + &ty::Generator(def_id, substs, _) => { + if let Some(var) = variant_index { + let gen_body = cx.tcx.optimized_mir(def_id); + let Some(layout) = gen_body.generator_layout() else { + bug!("No generator layout for {:?}", base_ty); + }; + + let Some(&local) = layout.variant_fields[var].get(field) else { + bug!("expected to take field {:?} of {:?}", field, layout.variant_fields[var]); + }; + + let Some(&f_ty) = layout.field_tys.get(local) else { + bug!("expected to get element for {:?} in {:?}", local, layout.field_tys); + }; + + f_ty + } else { + let Some(f_ty) = substs.as_generator().prefix_tys().nth(field.index()) else { + bug!("expected to take index {:?} in {:?}", field.index(), substs.as_generator().prefix_tys().collect::>()); + }; + + f_ty + } + } + _ => bug!("couldn't create field type, unexpected base type: {:?}", base_ty), }; Some(cx.tcx.normalize_erasing_regions(cx.param_env, field_ty)) From 9061ffba8ceb6a3a927aff15b570f9bd4247862a Mon Sep 17 00:00:00 2001 From: b-naber Date: Wed, 23 Nov 2022 19:55:24 +0100 Subject: [PATCH 10/12] use no type in ProjectionElem::Field for PlaceBuilder::UpVar --- compiler/rustc_middle/src/mir/mod.rs | 4 +- compiler/rustc_middle/src/mir/syntax.rs | 32 ++++++- compiler/rustc_middle/src/mir/tcx.rs | 15 +-- .../src/build/expr/as_place.rs | 92 ++++++++++++------- .../rustc_mir_build/src/build/expr/into.rs | 4 +- .../rustc_mir_build/src/build/matches/test.rs | 2 +- .../rustc_mir_build/src/build/matches/util.rs | 2 +- .../src/move_paths/abs_domain.rs | 2 +- .../rustc_mir_dataflow/src/value_analysis.rs | 4 +- 9 files changed, 105 insertions(+), 52 deletions(-) diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index 364c1b375ae5d..a646860ed45f1 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1517,7 +1517,7 @@ impl<'tcx> StatementKind<'tcx> { /////////////////////////////////////////////////////////////////////////// // Places -impl ProjectionElem { +impl ProjectionElem { /// Returns `true` if the target of this projection may refer to a different region of memory /// than the base. fn is_indirect(&self) -> bool { @@ -1546,7 +1546,7 @@ impl ProjectionElem { /// Alias for projections as they appear in `UserTypeProjection`, where we /// need neither the `V` parameter for `Index` nor the `T` for `Field`. -pub type ProjectionKind = ProjectionElem<(), ()>; +pub type ProjectionKind = ProjectionElem<(), (), ()>; rustc_index::newtype_index! { /// A [newtype'd][wrapper] index type in the MIR [control-flow graph][CFG] diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index fed943169dfb5..004dd004c723d 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -877,9 +877,9 @@ pub struct Place<'tcx> { #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] -pub enum ProjectionElem { +pub enum ProjectionElem { Deref, - Field(Field, T), + Field(Field, T1), /// Index into a slice/array. /// /// Note that this does not also dereference, and so it does not exactly correspond to slice @@ -935,12 +935,36 @@ pub enum ProjectionElem { /// Like an explicit cast from an opaque type to a concrete type, but without /// requiring an intermediate variable. - OpaqueCast(T), + OpaqueCast(T2), } /// Alias for projections as they appear in places, where the base is a place /// and the index is a local. -pub type PlaceElem<'tcx> = ProjectionElem>; +pub type PlaceElem<'tcx> = ProjectionElem, Ty<'tcx>>; + +/// Alias for projections that appear in `PlaceBuilder::UpVar`, for which +/// we cannot provide any field types. +pub type UpvarProjectionElem<'tcx> = ProjectionElem>; + +impl<'tcx> From> for UpvarProjectionElem<'tcx> { + fn from(elem: PlaceElem<'tcx>) -> Self { + match elem { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Field(field, _) => ProjectionElem::Field(field, ()), + ProjectionElem::Index(v) => ProjectionElem::Index(v), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } + } + ProjectionElem::Downcast(opt_sym, variant_idx) => { + ProjectionElem::Downcast(opt_sym, variant_idx) + } + ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), + } + } +} /////////////////////////////////////////////////////////////////////////// // Operands diff --git a/compiler/rustc_middle/src/mir/tcx.rs b/compiler/rustc_middle/src/mir/tcx.rs index fa3adafd4b85f..e3ca1f41d7ea1 100644 --- a/compiler/rustc_middle/src/mir/tcx.rs +++ b/compiler/rustc_middle/src/mir/tcx.rs @@ -28,8 +28,8 @@ impl<'tcx> PlaceTy<'tcx> { /// `place_ty.field_ty(tcx, f)` computes the type at a given field /// of a record or enum-variant. (Most clients of `PlaceTy` can /// instead just extract the relevant type directly from their - /// `PlaceElem`, but some instances of `ProjectionElem` do - /// not carry a `Ty` for `T`.) + /// `PlaceElem`, but some instances of `ProjectionElem` do + /// not carry a `Ty` for `T1` or `T2`.) /// /// Note that the resulting type has not been normalized. pub fn field_ty(self, tcx: TyCtxt<'tcx>, f: Field) -> Ty<'tcx> { @@ -64,17 +64,18 @@ impl<'tcx> PlaceTy<'tcx> { /// `Ty` or downcast variant corresponding to that projection. /// The `handle_field` callback must map a `Field` to its `Ty`, /// (which should be trivial when `T` = `Ty`). - pub fn projection_ty_core( + pub fn projection_ty_core( self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>, - elem: &ProjectionElem, - mut handle_field: impl FnMut(&Self, Field, T) -> Ty<'tcx>, - mut handle_opaque_cast: impl FnMut(&Self, T) -> Ty<'tcx>, + elem: &ProjectionElem, + mut handle_field: impl FnMut(&Self, Field, T1) -> Ty<'tcx>, + mut handle_opaque_cast: impl FnMut(&Self, T2) -> Ty<'tcx>, ) -> PlaceTy<'tcx> where V: ::std::fmt::Debug, - T: ::std::fmt::Debug + Copy, + T1: ::std::fmt::Debug + Copy, + T2: ::std::fmt::Debug + Copy, { if self.variant_index.is_some() && !matches!(elem, ProjectionElem::Field(..)) { bug!("cannot use non field projection on downcasted place") diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index bf417dae78511..bd27b6c2bebc5 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -19,6 +19,7 @@ use rustc_target::abi::VariantIdx; use rustc_index::vec::Idx; use std::assert_matches::assert_matches; +use std::convert::From; use std::iter; /// `PlaceBuilder` is used to create places during MIR construction. It allows you to "build up" a @@ -66,7 +67,7 @@ pub(in crate::build) enum PlaceBuilder<'tcx> { /// /// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types /// and will only do so once converting to `PlaceBuilder::Local`. - UpVar(UpVar, Vec>), + UpVar(UpVar, Vec>), } #[derive(Copy, Clone, Debug, PartialEq)] @@ -82,7 +83,7 @@ pub(crate) struct UpVar { /// part of a path that is captured by a closure. We stop applying projections once we see the first /// projection that isn't captured by a closure. fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( - mir_projections: &[PlaceElem<'tcx>], + mir_projections: &[UpvarProjectionElem<'tcx>], ) -> Vec { let mut hir_projections = Vec::new(); let mut variant = None; @@ -156,7 +157,7 @@ fn is_ancestor_or_same_capture( fn find_capture_matching_projections<'a, 'tcx>( upvars: &'a CaptureMap<'tcx>, var_hir_id: LocalVarId, - projections: &[PlaceElem<'tcx>], + projections: &[UpvarProjectionElem<'tcx>], ) -> Option<(usize, &'a Capture<'tcx>)> { let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections); @@ -212,8 +213,7 @@ fn to_upvars_resolved_place_builder<'tcx>( capture.captured_place.place.base_ty, projection, &capture.captured_place.place.projections, - ) - .collect::>(); + ); let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder( cx, @@ -222,6 +222,37 @@ fn to_upvars_resolved_place_builder<'tcx>( upvar_projection, ); + debug_assert!({ + let builder = upvar_resolved_place_builder.clone(); + let mut valid_conversion = true; + match builder { + PlaceBuilder::Local(_, projections) => { + for proj in projections.iter() { + match proj { + ProjectionElem::Field(_, field_ty) => { + if matches!(field_ty.kind(), ty::Infer(..)) { + debug!( + "field ty should have been converted for projection {:?} in PlaceBuilder {:?}", + proj, + upvar_resolved_place_builder.clone() + ); + + valid_conversion = false; + break; + } + } + _ => {} + } + } + } + PlaceBuilder::UpVar(..) => { + unreachable!() + } + } + + valid_conversion + }); + Some(upvar_resolved_place_builder) } @@ -233,14 +264,14 @@ fn to_upvars_resolved_place_builder<'tcx>( /// projection kinds are unsupported. fn strip_prefix<'a, 'tcx>( mut base_ty: Ty<'tcx>, - projections: &'a [PlaceElem<'tcx>], + projections: &'a [UpvarProjectionElem<'tcx>], prefix_projections: &[HirProjection<'tcx>], -) -> impl Iterator> + 'a { +) -> Vec> { let mut iter = projections .iter() - .copied() // Filter out opaque casts, they are unnecessary in the prefix. - .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))); + .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))) + .map(|elem| *elem); for projection in prefix_projections { debug!(?projection, ?projection.ty); @@ -261,7 +292,8 @@ fn strip_prefix<'a, 'tcx>( base_ty = projection.ty; } - iter + + iter.collect::>() } impl<'tcx> PlaceBuilder<'tcx> { @@ -292,11 +324,11 @@ impl<'tcx> PlaceBuilder<'tcx> { &self, cx: &Builder<'_, 'tcx>, ) -> Option> { - let PlaceBuilder::Upvar( Upvar {var_hir_id, closure_def_id }, projection) = self else { + let PlaceBuilder::UpVar( UpVar {var_hir_id, closure_def_id }, projection) = self else { return None; }; - to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &projection) + to_upvars_resolved_place_builder(cx, *var_hir_id, *closure_def_id, &projection) } pub(crate) fn get_local_projection(&self) -> &[PlaceElem<'tcx>] { @@ -309,19 +341,16 @@ impl<'tcx> PlaceBuilder<'tcx> { } #[instrument(skip(cx), level = "debug")] - pub(crate) fn field( - self, - cx: &Builder<'_, 'tcx>, - f: Field, - default_field_ty: Ty<'tcx>, - ) -> Self { + pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self { let field_ty = match self { PlaceBuilder::Local(..) => { let base_place = self.clone(); - PlaceBuilder::try_compute_field_ty(cx, f, base_place) - .unwrap_or_else(|| default_field_ty) + PlaceBuilder::compute_field_ty(cx, f, base_place) + } + PlaceBuilder::UpVar(..) => { + let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0)); + dummy_ty } - PlaceBuilder::UpVar(..) => default_field_ty, }; self.project(ProjectionElem::Field(f, field_ty)) @@ -347,7 +376,7 @@ impl<'tcx> PlaceBuilder<'tcx> { PlaceBuilder::Local(local, proj) } PlaceBuilder::UpVar(upvar, mut proj) => { - proj.push(elem); + proj.push(elem.into()); PlaceBuilder::UpVar(upvar, proj) } }; @@ -363,8 +392,8 @@ impl<'tcx> PlaceBuilder<'tcx> { *local, Vec::from_iter(proj.iter().copied().chain([elem.into()])), ), - PlaceBuilder::Upvar(upvar, proj) => PlaceBuilder::UpVar( - upvar, + PlaceBuilder::UpVar(upvar, proj) => PlaceBuilder::UpVar( + *upvar, Vec::from_iter(proj.iter().copied().chain([elem.into()])), ), } @@ -378,11 +407,11 @@ impl<'tcx> PlaceBuilder<'tcx> { /// Fallible as the root of this place may be an upvar for /// which no base type can be determined. #[instrument(skip(cx), level = "debug")] - fn try_compute_field_ty( + fn compute_field_ty( cx: &Builder<'_, 'tcx>, field: Field, base_place: PlaceBuilder<'tcx>, - ) -> Option> { + ) -> Ty<'tcx> { let field_idx = field.as_usize(); let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx); let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); @@ -442,7 +471,7 @@ impl<'tcx> PlaceBuilder<'tcx> { _ => bug!("couldn't create field type, unexpected base type: {:?}", base_ty), }; - Some(cx.tcx.normalize_erasing_regions(cx.param_env, field_ty)) + cx.tcx.normalize_erasing_regions(cx.param_env, field_ty) } /// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::UpVar` whose upvars @@ -455,7 +484,7 @@ impl<'tcx> PlaceBuilder<'tcx> { cx: &Builder<'_, 'tcx>, local: Local, mut local_projection: Vec>, - upvar_projection: Vec>, + upvar_projection: Vec>, ) -> Self { // We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use // the ancestor projections, i.e. those projection elements that come before the field projection, @@ -464,11 +493,10 @@ impl<'tcx> PlaceBuilder<'tcx> { for proj in upvar_projection.iter() { debug!("proj: {:?}, local_projection: {:?}", proj, local_projection); match *proj { - ProjectionElem::Field(field, default_field_ty) => { + ProjectionElem::Field(field, _) => { let ancestor_proj = local_projection.to_vec(); let base_place = PlaceBuilder::Local(local, ancestor_proj); - let field_ty = PlaceBuilder::try_compute_field_ty(cx, field, base_place) - .unwrap_or_else(|| default_field_ty); + let field_ty = PlaceBuilder::compute_field_ty(cx, field, base_place); debug!(?field_ty); local_projection.push(ProjectionElem::Field(field, field_ty)); @@ -593,7 +621,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { place_builder = place_builder.downcast(*adt_def, variant_index); } } - block.and(place_builder.field(this, name, expr.ty)) + block.and(place_builder.field(this, name)) } ExprKind::Deref { arg } => { let place_builder = unpack!( diff --git a/compiler/rustc_mir_build/src/build/expr/into.rs b/compiler/rustc_mir_build/src/build/expr/into.rs index 12cd0e65a1158..e5c2f4f4cbeb0 100644 --- a/compiler/rustc_mir_build/src/build/expr/into.rs +++ b/compiler/rustc_mir_build/src/build/expr/into.rs @@ -355,12 +355,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // base-supplied field, generate an operand that // reads it from the base. iter::zip(field_names, &**field_types) - .map(|(n, ty)| match fields_map.get(&n) { + .map(|(n, _ty)| match fields_map.get(&n) { Some(v) => v.clone(), None => { let place_builder = place_builder.clone(); this.consume_by_copy_or_move( - place_builder.field(this, n, *ty).to_place(this), + place_builder.field(this, n).to_place(this), ) } }) diff --git a/compiler/rustc_mir_build/src/build/matches/test.rs b/compiler/rustc_mir_build/src/build/matches/test.rs index 7b932eda74432..c669016e0ed7f 100644 --- a/compiler/rustc_mir_build/src/build/matches/test.rs +++ b/compiler/rustc_mir_build/src/build/matches/test.rs @@ -760,7 +760,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { let downcast_place = match_pair.place.downcast(adt_def, variant_index); // `(x as Variant)` let consequent_match_pairs = subpatterns.iter().map(|subpattern| { // e.g., `(x as Variant).0` - let place = downcast_place.clone().field(self, subpattern.field, subpattern.pattern.ty); + let place = downcast_place.clone().field(self, subpattern.field); // e.g., `(x as Variant).0 @ P1` MatchPair::new(place, &subpattern.pattern, self) }); diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 30f4e49d8bae5..27a7b03465f67 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -17,7 +17,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { subpatterns .iter() .map(|fieldpat| { - let place = place.clone().field(self, fieldpat.field, fieldpat.pattern.ty); + let place = place.clone().field(self, fieldpat.field); MatchPair::new(place, &fieldpat.pattern, self) }) diff --git a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs index 7806e8f45d3ad..5cfbbb1ac01e7 100644 --- a/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs +++ b/compiler/rustc_mir_dataflow/src/move_paths/abs_domain.rs @@ -18,7 +18,7 @@ use rustc_middle::ty::Ty; pub struct AbstractOperand; #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug)] pub struct AbstractType; -pub type AbstractElem = ProjectionElem; +pub type AbstractElem = ProjectionElem; pub trait Lift { type Abstract; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index cc69a1bb02db1..b09503a309305 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -777,10 +777,10 @@ pub enum TrackElem { Field(Field), } -impl TryFrom> for TrackElem { +impl TryFrom> for TrackElem { type Error = (); - fn try_from(value: ProjectionElem) -> Result { + fn try_from(value: ProjectionElem) -> Result { match value { ProjectionElem::Field(field, _) => Ok(TrackElem::Field(field)), _ => Err(()), From dc93a28e98e6bdcb73441ec699f43aa01d10e4e6 Mon Sep 17 00:00:00 2001 From: b-naber Date: Tue, 29 Nov 2022 13:42:52 +0100 Subject: [PATCH 11/12] reduce allocations --- .../src/build/expr/as_place.rs | 149 +++++++++++++----- 1 file changed, 111 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index bd27b6c2bebc5..3f52334b72472 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -218,7 +218,7 @@ fn to_upvars_resolved_place_builder<'tcx>( let upvar_resolved_place_builder = PlaceBuilder::construct_local_place_builder( cx, upvar_resolved_local, - local_projection.to_vec(), + local_projection.as_slice(), upvar_projection, ); @@ -266,7 +266,7 @@ fn strip_prefix<'a, 'tcx>( mut base_ty: Ty<'tcx>, projections: &'a [UpvarProjectionElem<'tcx>], prefix_projections: &[HirProjection<'tcx>], -) -> Vec> { +) -> impl Iterator> + 'a { let mut iter = projections .iter() // Filter out opaque casts, they are unnecessary in the prefix. @@ -293,7 +293,7 @@ fn strip_prefix<'a, 'tcx>( base_ty = projection.ty; } - iter.collect::>() + iter } impl<'tcx> PlaceBuilder<'tcx> { @@ -342,10 +342,14 @@ impl<'tcx> PlaceBuilder<'tcx> { #[instrument(skip(cx), level = "debug")] pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self { - let field_ty = match self { - PlaceBuilder::Local(..) => { - let base_place = self.clone(); - PlaceBuilder::compute_field_ty(cx, f, base_place) + let field_ty = match self.clone() { + PlaceBuilder::Local(local, projection) => { + let base_place = PlaceBuilder::Local(local, projection); + let PlaceTy { ty, variant_index } = + base_place.to_place(cx).ty(&cx.local_decls, cx.tcx); + let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); + + PlaceBuilder::compute_field_ty(cx, f, base_ty, variant_index) } PlaceBuilder::UpVar(..) => { let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0)); @@ -410,13 +414,10 @@ impl<'tcx> PlaceBuilder<'tcx> { fn compute_field_ty( cx: &Builder<'_, 'tcx>, field: Field, - base_place: PlaceBuilder<'tcx>, + base_ty: Ty<'tcx>, + variant_index: Option, ) -> Ty<'tcx> { let field_idx = field.as_usize(); - let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx); - let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - debug!(?base_ty); - let field_ty = match base_ty.kind() { ty::Adt(adt_def, substs) if adt_def.is_enum() => { let variant_idx = variant_index.unwrap(); @@ -479,41 +480,38 @@ impl<'tcx> PlaceBuilder<'tcx> { /// contains the projections of the captured upvar and `upvar_projection` the /// projections that are applied to the captured upvar. The main purpose of this /// function is to figure out the `Ty`s of the field projections in `upvar_projection`. - #[instrument(skip(cx, local))] + #[instrument(skip(cx, local, upvar_projection))] fn construct_local_place_builder( cx: &Builder<'_, 'tcx>, local: Local, - mut local_projection: Vec>, - upvar_projection: Vec>, + local_projection: &[PlaceElem<'tcx>], + upvar_projection: impl Iterator>, ) -> Self { - // We iterate through `upvar_projection` and whenever we find a `ProjectionElem::Field` we use - // the ancestor projections, i.e. those projection elements that come before the field projection, - // to get the `Ty` for the field. - - for proj in upvar_projection.iter() { - debug!("proj: {:?}, local_projection: {:?}", proj, local_projection); - match *proj { + // We maintain a `Ty` to which we apply a projection in each iteration over `upvar_projection`. + // This `ancestor_ty` let's us infer the field type whenever we encounter a + // `ProjectionElem::Field`. + let (mut ancestor_ty, mut opt_variant_idx) = + local_projections_to_ty(cx, local, local_projection); + + // We add all projection elements we encounter to this `Vec`. + let mut local_projection = local_projection.to_vec(); + + for (i, proj) in upvar_projection.enumerate() { + debug!("i: {:?}, proj: {:?}, local_projection: {:?}", i, proj, local_projection); + match proj { ProjectionElem::Field(field, _) => { - let ancestor_proj = local_projection.to_vec(); - let base_place = PlaceBuilder::Local(local, ancestor_proj); - let field_ty = PlaceBuilder::compute_field_ty(cx, field, base_place); + let field_ty = + PlaceBuilder::compute_field_ty(cx, field, ancestor_ty, opt_variant_idx); debug!(?field_ty); local_projection.push(ProjectionElem::Field(field, field_ty)); - debug!(?local_projection); - } - ProjectionElem::Deref => local_projection.push(ProjectionElem::Deref), - ProjectionElem::Index(idx) => local_projection.push(ProjectionElem::Index(idx)), - ProjectionElem::ConstantIndex { offset, min_length, from_end } => local_projection - .push(ProjectionElem::ConstantIndex { offset, min_length, from_end }), - ProjectionElem::Subslice { from, to, from_end } => { - local_projection.push(ProjectionElem::Subslice { from, to, from_end }) + ancestor_ty = field_ty; + opt_variant_idx = None; } - ProjectionElem::Downcast(sym, variant_idx) => { - local_projection.push(ProjectionElem::Downcast(sym, variant_idx)) - } - ProjectionElem::OpaqueCast(ty) => { - local_projection.push(ProjectionElem::OpaqueCast(ty)) + _ => { + let proj = upvar_proj_to_place_elem_no_field_proj(proj); + (ancestor_ty, opt_variant_idx) = project_ty(cx.tcx, ancestor_ty, proj); + local_projection.push(proj); } } } @@ -534,6 +532,81 @@ impl<'tcx> From> for PlaceBuilder<'tcx> { } } +fn project_ty<'tcx>( + tcx: TyCtxt<'tcx>, + ty: Ty<'tcx>, + elem: PlaceElem<'tcx>, +) -> (Ty<'tcx>, Option) { + match elem { + ProjectionElem::Deref => { + let updated_ty = ty + .builtin_deref(true) + .unwrap_or_else(|| bug!("deref projection of non-dereferenceable ty {:?}", ty)) + .ty; + + (updated_ty, None) + } + ProjectionElem::Index(_) | ProjectionElem::ConstantIndex { .. } => { + (ty.builtin_index().unwrap(), None) + } + ProjectionElem::Subslice { from, to, from_end } => { + let ty = match ty.kind() { + ty::Slice(..) => ty, + ty::Array(inner, _) if !from_end => tcx.mk_array(*inner, (to - from) as u64), + ty::Array(inner, size) if from_end => { + let size = size.eval_usize(tcx, ty::ParamEnv::empty()); + let len = size - (from as u64) - (to as u64); + tcx.mk_array(*inner, len) + } + _ => bug!("cannot subslice non-array type: `{:?}`", ty), + }; + + (ty, None) + } + ProjectionElem::Downcast(_, variant_idx) => (ty, Some(variant_idx)), + ProjectionElem::Field(_, ty) => { + if matches!(ty.kind(), ty::Infer(..)) { + bug!("Field ty should have been resolved"); + } + + (ty, None) + } + ProjectionElem::OpaqueCast(..) => bug!("didn't expect OpaqueCast"), + } +} + +fn local_projections_to_ty<'a, 'tcx>( + cx: &'a Builder<'a, 'tcx>, + local: Local, + projection: &'a [PlaceElem<'tcx>], +) -> (Ty<'tcx>, Option) { + let local_ty = cx.local_decls.local_decls()[local].ty; + projection.iter().fold((local_ty, None), |ty_variant_idx, elem| { + let ty = ty_variant_idx.0; + project_ty(cx.tcx, ty, *elem) + }) +} + +// Converts an `UpvarProjectionElem` to `PlaceElem`, ICE'ing when being passed a +// field projection. +fn upvar_proj_to_place_elem_no_field_proj<'tcx>( + upvar_proj: UpvarProjectionElem<'tcx>, +) -> PlaceElem<'tcx> { + match upvar_proj { + ProjectionElem::Deref => ProjectionElem::Deref, + ProjectionElem::Index(i) => ProjectionElem::Index(i), + ProjectionElem::ConstantIndex { offset, min_length, from_end } => { + ProjectionElem::ConstantIndex { offset, min_length, from_end } + } + ProjectionElem::Subslice { from, to, from_end } => { + ProjectionElem::Subslice { from, to, from_end } + } + ProjectionElem::Downcast(ty, variant_idx) => ProjectionElem::Downcast(ty, variant_idx), + ProjectionElem::OpaqueCast(ty) => ProjectionElem::OpaqueCast(ty), + ProjectionElem::Field(..) => bug!("should not be called with `ProjectionElem::Field`"), + } +} + impl<'a, 'tcx> Builder<'a, 'tcx> { /// Compile `expr`, yielding a place that we can move from etc. /// From ff41359e6535ca7dc1261f282b1601136fedee21 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 9 Dec 2022 18:08:56 +0100 Subject: [PATCH 12/12] address review --- compiler/rustc_middle/src/mir/syntax.rs | 9 +- .../src/build/expr/as_place.rs | 133 +++++++----------- .../src/build/expr/as_rvalue.rs | 4 +- .../rustc_mir_build/src/build/matches/util.rs | 5 +- 4 files changed, 60 insertions(+), 91 deletions(-) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 004dd004c723d..b7a5f9c8757ba 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -875,6 +875,13 @@ pub struct Place<'tcx> { pub projection: &'tcx List>, } +/// The different kinds of projections that can be used in the projection of a `Place`. +/// +/// `T1` is the generic type for a field projection. For an actual projection on a `Place` +/// this parameter will always be `Ty`, but the field type can be unavailable when +/// building (by using `PlaceBuilder`) places that correspond to upvars. +/// `T2` is the generic type for an `OpaqueCast` (is generic since it's abstracted over +/// in dataflow analysis, see `AbstractElem`). #[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash)] #[derive(TyEncodable, TyDecodable, HashStable, TypeFoldable, TypeVisitable)] pub enum ProjectionElem { @@ -942,7 +949,7 @@ pub enum ProjectionElem { /// and the index is a local. pub type PlaceElem<'tcx> = ProjectionElem, Ty<'tcx>>; -/// Alias for projections that appear in `PlaceBuilder::UpVar`, for which +/// Alias for projections that appear in `PlaceBuilder::Upvar`, for which /// we cannot provide any field types. pub type UpvarProjectionElem<'tcx> = ProjectionElem>; diff --git a/compiler/rustc_mir_build/src/build/expr/as_place.rs b/compiler/rustc_mir_build/src/build/expr/as_place.rs index 3f52334b72472..8a35478dd8b34 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_place.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_place.rs @@ -33,7 +33,7 @@ pub(in crate::build) enum PlaceBuilder<'tcx> { /// Denotes the start of a `Place`. /// /// We use `PlaceElem` since this has all `Field` types available. - Local(Local, Vec>), + Local { local: Local, projection: Vec> }, /// When building place for an expression within a closure, the place might start off a /// captured path. When `capture_disjoint_fields` is enabled, we might not know the capture @@ -67,11 +67,11 @@ pub(in crate::build) enum PlaceBuilder<'tcx> { /// /// Note: in contrast to `PlaceBuilder::Local` we have not yet determined all `Field` types /// and will only do so once converting to `PlaceBuilder::Local`. - UpVar(UpVar, Vec>), + Upvar { upvar: Upvar, projection: Vec> }, } #[derive(Copy, Clone, Debug, PartialEq)] -pub(crate) struct UpVar { +pub(crate) struct Upvar { var_hir_id: LocalVarId, closure_def_id: LocalDefId, } @@ -222,36 +222,7 @@ fn to_upvars_resolved_place_builder<'tcx>( upvar_projection, ); - debug_assert!({ - let builder = upvar_resolved_place_builder.clone(); - let mut valid_conversion = true; - match builder { - PlaceBuilder::Local(_, projections) => { - for proj in projections.iter() { - match proj { - ProjectionElem::Field(_, field_ty) => { - if matches!(field_ty.kind(), ty::Infer(..)) { - debug!( - "field ty should have been converted for projection {:?} in PlaceBuilder {:?}", - proj, - upvar_resolved_place_builder.clone() - ); - - valid_conversion = false; - break; - } - } - _ => {} - } - } - } - PlaceBuilder::UpVar(..) => { - unreachable!() - } - } - - valid_conversion - }); + assert!(matches!(upvar_resolved_place_builder, PlaceBuilder::Local { .. })); Some(upvar_resolved_place_builder) } @@ -269,9 +240,9 @@ fn strip_prefix<'a, 'tcx>( ) -> impl Iterator> + 'a { let mut iter = projections .iter() + .copied() // Filter out opaque casts, they are unnecessary in the prefix. - .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))) - .map(|elem| *elem); + .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))); for projection in prefix_projections { debug!(?projection, ?projection.ty); @@ -305,8 +276,8 @@ impl<'tcx> PlaceBuilder<'tcx> { pub(in crate::build) fn try_to_place(&self, cx: &Builder<'_, 'tcx>) -> Option> { let resolved = self.resolve_upvar(cx); let builder = resolved.as_ref().unwrap_or(self); - let PlaceBuilder::Local(local, projection) = builder else { return None }; - let projection = cx.tcx.intern_place_elems(&projection); + let PlaceBuilder::Local{local, ref projection} = builder else { return None }; + let projection = cx.tcx.intern_place_elems(projection); Some(Place { local: *local, projection }) } @@ -324,40 +295,31 @@ impl<'tcx> PlaceBuilder<'tcx> { &self, cx: &Builder<'_, 'tcx>, ) -> Option> { - let PlaceBuilder::UpVar( UpVar {var_hir_id, closure_def_id }, projection) = self else { + let PlaceBuilder::Upvar{ upvar: Upvar {var_hir_id, closure_def_id }, projection} = self else { return None; }; to_upvars_resolved_place_builder(cx, *var_hir_id, *closure_def_id, &projection) } - pub(crate) fn get_local_projection(&self) -> &[PlaceElem<'tcx>] { - match self { - Self::Local(_, projection) => projection, - Self::UpVar(..) => { - bug!("get_local_projection_mut can only be called on PlaceBuilder::Local") - } - } - } - #[instrument(skip(cx), level = "debug")] pub(crate) fn field(self, cx: &Builder<'_, 'tcx>, f: Field) -> Self { - let field_ty = match self.clone() { - PlaceBuilder::Local(local, projection) => { - let base_place = PlaceBuilder::Local(local, projection); + match self.clone() { + PlaceBuilder::Local { local, projection } => { + let base_place = PlaceBuilder::Local { local, projection }; let PlaceTy { ty, variant_index } = base_place.to_place(cx).ty(&cx.local_decls, cx.tcx); let base_ty = cx.tcx.normalize_erasing_regions(cx.param_env, ty); - PlaceBuilder::compute_field_ty(cx, f, base_ty, variant_index) + let field_ty = PlaceBuilder::compute_field_ty(cx, f, base_ty, variant_index); + + self.project(ProjectionElem::Field(f, field_ty)) } - PlaceBuilder::UpVar(..) => { - let dummy_ty = cx.tcx.mk_ty_infer(ty::FreshTy(0)); - dummy_ty + PlaceBuilder::Upvar { upvar, mut projection } => { + projection.push(ProjectionElem::Field(f, ())); + PlaceBuilder::Upvar { upvar, projection } } - }; - - self.project(ProjectionElem::Field(f, field_ty)) + } } pub(crate) fn deref(self) -> Self { @@ -375,13 +337,13 @@ impl<'tcx> PlaceBuilder<'tcx> { #[instrument(level = "debug")] pub(crate) fn project(self, elem: PlaceElem<'tcx>) -> Self { let result = match self { - PlaceBuilder::Local(local, mut proj) => { - proj.push(elem); - PlaceBuilder::Local(local, proj) + PlaceBuilder::Local { local, mut projection } => { + projection.push(elem); + PlaceBuilder::Local { local, projection } } - PlaceBuilder::UpVar(upvar, mut proj) => { - proj.push(elem.into()); - PlaceBuilder::UpVar(upvar, proj) + PlaceBuilder::Upvar { upvar, mut projection } => { + projection.push(elem.into()); + PlaceBuilder::Upvar { upvar, projection } } }; @@ -392,14 +354,14 @@ impl<'tcx> PlaceBuilder<'tcx> { /// Same as `.clone().project(..)` but more efficient pub(crate) fn clone_project(&self, elem: PlaceElem<'tcx>) -> Self { match self { - PlaceBuilder::Local(local, proj) => PlaceBuilder::Local( - *local, - Vec::from_iter(proj.iter().copied().chain([elem.into()])), - ), - PlaceBuilder::UpVar(upvar, proj) => PlaceBuilder::UpVar( - *upvar, - Vec::from_iter(proj.iter().copied().chain([elem.into()])), - ), + PlaceBuilder::Local { local, projection } => PlaceBuilder::Local { + local: *local, + projection: Vec::from_iter(projection.iter().copied().chain([elem.into()])), + }, + PlaceBuilder::Upvar { upvar, projection } => PlaceBuilder::Upvar { + upvar: *upvar, + projection: Vec::from_iter(projection.iter().copied().chain([elem.into()])), + }, } } @@ -463,7 +425,11 @@ impl<'tcx> PlaceBuilder<'tcx> { f_ty } else { let Some(f_ty) = substs.as_generator().prefix_tys().nth(field.index()) else { - bug!("expected to take index {:?} in {:?}", field.index(), substs.as_generator().prefix_tys().collect::>()); + bug!( + "expected to take index {:?} in {:?}", + field.index(), + substs.as_generator().prefix_tys().collect::>() + ); }; f_ty @@ -475,7 +441,7 @@ impl<'tcx> PlaceBuilder<'tcx> { cx.tcx.normalize_erasing_regions(cx.param_env, field_ty) } - /// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::UpVar` whose upvars + /// Creates a `PlaceBuilder::Local` from a `PlaceBuilder::Upvar` whose upvars /// are resolved. This function takes two kinds of projections: `local_projection` /// contains the projections of the captured upvar and `upvar_projection` the /// projections that are applied to the captured upvar. The main purpose of this @@ -516,19 +482,19 @@ impl<'tcx> PlaceBuilder<'tcx> { } } - PlaceBuilder::Local(local, local_projection) + PlaceBuilder::Local { local, projection: local_projection } } } impl<'tcx> From for PlaceBuilder<'tcx> { fn from(local: Local) -> Self { - Self::Local(local, Vec::new()) + Self::Local { local, projection: Vec::new() } } } impl<'tcx> From> for PlaceBuilder<'tcx> { fn from(p: Place<'tcx>) -> Self { - Self::Local(p.local, p.projection.to_vec()) + Self::Local { local: p.local, projection: p.projection.to_vec() } } } @@ -564,13 +530,7 @@ fn project_ty<'tcx>( (ty, None) } ProjectionElem::Downcast(_, variant_idx) => (ty, Some(variant_idx)), - ProjectionElem::Field(_, ty) => { - if matches!(ty.kind(), ty::Infer(..)) { - bug!("Field ty should have been resolved"); - } - - (ty, None) - } + ProjectionElem::Field(_, ty) => (ty, None), ProjectionElem::OpaqueCast(..) => bug!("didn't expect OpaqueCast"), } } @@ -836,7 +796,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { } /// Lower a captured upvar. Note we might not know the actual capture index, - /// so we create a place starting from `UpVar`, which will be resolved + /// so we create a place starting from `Upvar`, which will be resolved /// once all projections that allow us to identify a capture have been applied. fn lower_captured_upvar( &mut self, @@ -844,7 +804,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { closure_def_id: LocalDefId, var_hir_id: LocalVarId, ) -> BlockAnd> { - block.and(PlaceBuilder::UpVar(UpVar { var_hir_id, closure_def_id }, vec![])) + block.and(PlaceBuilder::Upvar { + upvar: Upvar { var_hir_id, closure_def_id }, + projection: vec![], + }) } /// Lower an index expression diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index 618aa9e310954..b3fd054a00a5c 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -654,11 +654,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { // We are capturing a path that starts off a local variable in the parent. // The mutability of the current capture is same as the mutability // of the local declaration in the parent. - PlaceBuilder::Local(local, _) => this.local_decls[local].mutability, + PlaceBuilder::Local { local, .. } => this.local_decls[local].mutability, // Parent is a closure and we are capturing a path that is captured // by the parent itself. The mutability of the current capture // is same as that of the capture in the parent closure. - PlaceBuilder::UpVar(..) => { + PlaceBuilder::Upvar { .. } => { let enclosing_upvars_resolved = arg_place_builder.to_place(this); match enclosing_upvars_resolved.as_ref() { diff --git a/compiler/rustc_mir_build/src/build/matches/util.rs b/compiler/rustc_mir_build/src/build/matches/util.rs index 27a7b03465f67..e48c6b2457be3 100644 --- a/compiler/rustc_mir_build/src/build/matches/util.rs +++ b/compiler/rustc_mir_build/src/build/matches/util.rs @@ -108,9 +108,8 @@ impl<'pat, 'tcx> MatchPair<'pat, 'tcx> { // Only add the OpaqueCast projection if the given place is an opaque type and the // expected type from the pattern is not. let may_need_cast = match place { - PlaceBuilder::Local(local, _) => { - let ty = - Place::ty_from(local, place.get_local_projection(), &cx.local_decls, cx.tcx).ty; + PlaceBuilder::Local { local, ref projection } => { + let ty = Place::ty_from(local, projection, &cx.local_decls, cx.tcx).ty; ty != pattern.ty && ty.has_opaque_types() } _ => true,