Change:
<!-- Thank you for finding an Internal Compiler Error! If possible, try to provide a minimal verifiable example. You can read "Rust Bug Minimization Patterns" for how to create smaller examples. --There's only so much that I can share. The code that seems to be erroring is similar to <!-- If you're using the stable version of the compiler, you should also check if the bug also exists in the beta or nightly versions. --: <!-- Include a backtrace in the code block by setting in your environment. E.g. . --<details<summary<strongBacktrace</strong</summary<p</p</details
I've discovered that destructuring the enum variant outside of the async block fixes the issue
Minimal repro:
amazing that you did reduce your testcase like that. I removed the external dependecy to tokio and silenced the unused warning: Regressed in rollup probably in searched nightlies: from nightly-2021-12-01 to nightly-2022-04-24 regressed nightly: nightly-2021-12-06 searched commits: from to regressed commit: <details<summarybisected with <a href=''cargo-bisect-rustc</av0.6.0</summaryHost triple: x86_64-unknown-linux-gnu Reproduce with: </details
Reduced a bit more (requires an edition with precise captures, I think):
Looks like a duplicate of and
These started ICEing in (), with looking very likely.
If no one is yet investigating this, I'd like to pick it up
So far, I've found 2 issues that cause this behaviour. The first is that it's having trouble in this context to get the field type of the single variant enum: Fix is easy, The second issue is that the MIR is being badly formed. Looking at the traces, I see Which hints to me that the code is not being read as but instead
Yeah, it looks like constructed MIR is incorrect. One issue seems to be in , towards the end it has to rebase projections on top of a capture. First it has to remove the captured prefix, and the implementation makes the assumption that the number of projections in HIR and MIR will coincide. In the HIR downcasting is part of field projection, in the MIR those are two separate elements. Thus we are left with an extra incorrect projection. There seems to be one more issue when constructing the capture - the downcasting operation is completely missing. While the documentation for MIR claims that I think that is an outdated information.
I also just noticed the Downcast issue. In my traces, I do see the variant projection using this Downcast for just a single variant, and the suspect PR changes does seem to ignore all Downcast projections (there's a little bit of discussion taking place on zulip https://rust-)
Should the fix be Downcast and truncation the capture correctly the single variant capture not use Downcast
or might be in a better position to give advice here. I think we should keep and / or add downcast where they are currently missing (e.g., when constructing the closure), and fix how projections corresponding to captured prefix are removed. As far the latter aspect is concerned, I think the issue is in the following lines ( are HIR projections which combine field and downcast into one operation, while are MIR projection elements where those two operations are separate):
I vaguely recall we relied on this to detect if we had a multi variant enum, in which case we would completely capture the root variable. Edit: Ignore that, scrolling into the code bit more, there is comment that Downcast can be expected for single-variant enums
are you still planning to work on this issue?
Not currently, I spent a few full days looking but I don't want to risk burning out debugging something that I don't completely understand . I hope I at least narrowed it down a bit

Discussion:
lhs: ExprId, rhs: ExprId, }, <del> /// Access to a struct or tuple field. </del> <ins> /// Access to a field of a struct, a tuple, an union, or an enum. </ins> Field { lhs: ExprId, <ins> /// Variant containing the field. variant_index: VariantIdx, </ins> /// This can be a named (`.foo`) or unnamed (`.0`) field. name: Field, },

visitor.visit_expr(&visitor.thir()[lhs]); visitor.visit_expr(&visitor.thir()[rhs]); } <del> Field { lhs, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), </del> <ins> Field { lhs, variant_index: _, name: _ } => visitor.visit_expr(&visitor.thir()[lhs]), </ins> Index { lhs, index } => { visitor.visit_expr(&visitor.thir()[lhs]); visitor.visit_expr(&visitor.thir()[index]);

use crate::build::{BlockAnd, BlockAndExtension, Builder}; use rustc_hir::def_id::DefId; use rustc_hir::HirId; <ins> use rustc_middle::hir::place::Projection as HirProjection; </ins> use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; use rustc_middle::middle::region; use rustc_middle::mir::AssertKind::BoundsCheck;

ty::UpvarCapture::ByValue => upvar_resolved_place_builder, }; <del> let next_projection = capture.place.projections.len(); let mut curr_projections = from_builder.projection; </del> // We used some of the projections to build the capture itself, // now we apply the remaining to the upvar resolved place. <del> upvar_resolved_place_builder .projection .extend(curr_projections.drain(next_projection..)); </del> <ins> let remaining_projections = strip_prefix( capture.place.base_ty, from_builder.projection, &capture.place.projections, ); upvar_resolved_place_builder.projection.extend(remaining_projections); </ins> Ok(upvar_resolved_place_builder) } } } <ins> /// Returns projections remaining after stripping an initial prefix of HIR /// projections. /// /// Supports only HIR projection kinds that represent a path that might be /// captured by a closure or a generator, i.e., an `Index` or a `Subslice` /// projection kinds are unsupported. fn strip_prefix<'tcx>( mut base_ty: Ty<'tcx>, projections: Vec<PlaceElem<'tcx>>, prefix_projections: &[HirProjection<'tcx>], ) -> impl Iterator<Item = PlaceElem<'tcx>> { let mut iter = projections.into_iter(); for projection in prefix_projections { match projection.kind { HirProjectionKind::Deref => { assert!(matches!(iter.next(), Some(ProjectionElem::Deref))); } HirProjectionKind::Field(..) => { if base_ty.is_enum() { assert!(matches!(iter.next(), Some(ProjectionElem::Downcast(..)))); } assert!(matches!(iter.next(), Some(ProjectionElem::Field(..)))); } HirProjectionKind::Index | HirProjectionKind::Subslice => { bug!("unexpected projection kind: {:?}", projection); } } base_ty = projection.ty; } iter } </ins> impl<'tcx> PlaceBuilder<'tcx> { pub(crate) fn into_place<'a>( self,

this.expr_as_place(block, &this.thir[value], mutability, fake_borrow_temps) }) } <del> ExprKind::Field { lhs, name } => { let place_builder = unpack!( block = this.expr_as_place(block, &this.thir[lhs], mutability, fake_borrow_temps,) ); </del> <ins> ExprKind::Field { lhs, variant_index, name } => { let lhs = &this.thir[lhs]; let mut place_builder = unpack!(block = this.expr_as_place(block, lhs, mutability, fake_borrow_temps,)); if let ty::Adt(adt_def, _) = lhs.ty.kind() { if adt_def.is_enum() { place_builder = place_builder.downcast(*adt_def, variant_index); } } </ins> block.and(place_builder.field(name, expr.ty)) } ExprKind::Deref { arg } => {

} hir::ExprKind::Field(ref source, ..) => ExprKind::Field { lhs: self.mirror_expr(source), <ins> variant_index: VariantIdx::new(0), </ins> name: Field::new(tcx.field_index(expr.hir_id, self.typeck_results)), }, hir::ExprKind::Cast(ref source, ref cast_ty) => {

HirProjectionKind::Deref => { ExprKind::Deref { arg: self.thir.exprs.push(captured_place_expr) } } <del> HirProjectionKind::Field(field, ..) => { // Variant index will always be 0, because for multi-variant // enums, we capture the enum entirely. ExprKind::Field { lhs: self.thir.exprs.push(captured_place_expr), name: Field::new(field as usize), } } </del> <ins> HirProjectionKind::Field(field, variant_index) => ExprKind::Field { lhs: self.thir.exprs.push(captured_place_expr), variant_index, name: Field::new(field as usize), }, </ins> HirProjectionKind::Index | HirProjectionKind::Subslice => { // We don't capture these projections, so we can ignore them here continue;

<ins> // edition:2021 // run-pass #[derive(Debug, PartialEq, Eq)] pub enum Color { RGB(u8, u8, u8), } fn main() { let mut color = Color::RGB(0, 0, 0); let mut red = |v| { let Color::RGB(ref mut r, _, _) = color; *r = v; }; let mut green = |v| { let Color::RGB(_, ref mut g, _) = color; *g = v; }; let mut blue = |v| { let Color::RGB(_, _, ref mut b) = color; *b = v; }; red(1); green(2); blue(3); assert_eq!(Color::RGB(1, 2, 3), color); } </ins>