Change:
I was messing around with the crate and an ICE was raised when I tried to pattern match an enum in the function parameter. I narrowed it down to trying to pattern match a variable that exists outside the scope from within a closure. Playground link: Present in all three channels, beta, nightly and stable. Only present on 2021 edition. : <details<summary<strongBacktrace</strong</summary<p</p</details
I'm willing to work on it if it turns out to be a simple fix, hints are appreciated!
Does this still crash on nightly? I was not able to repro with
It does here, same code as above. But the backtrace has changed. <details<summaryBacktrace</summary</details
Ah I missed the :upsidedownface: :+1:

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>