-
Notifications
You must be signed in to change notification settings - Fork 13.8k
2229: Handle patterns within closures correctly when capture_disjoint_fields
is enabled
#82536
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
ec10b71
d4f8729
b6cf070
685a4c6
74fc643
fb3b77a
22eaffe
189d206
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -10,14 +10,15 @@ use rustc_middle::hir::place::ProjectionKind as HirProjectionKind; | |
use rustc_middle::middle::region; | ||
use rustc_middle::mir::AssertKind::BoundsCheck; | ||
use rustc_middle::mir::*; | ||
use rustc_middle::ty::AdtDef; | ||
use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, Variance}; | ||
use rustc_span::Span; | ||
use rustc_target::abi::VariantIdx; | ||
|
||
use rustc_index::vec::Idx; | ||
|
||
/// The "outermost" place that holds this value. | ||
#[derive(Copy, Clone)] | ||
#[derive(Copy, Clone, Debug, PartialEq)] | ||
crate enum PlaceBase { | ||
/// Denotes the start of a `Place`. | ||
Local(Local), | ||
|
@@ -67,7 +68,7 @@ crate enum PlaceBase { | |
/// | ||
/// 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)] | ||
#[derive(Clone, Debug, PartialEq)] | ||
crate struct PlaceBuilder<'tcx> { | ||
base: PlaceBase, | ||
projection: Vec<PlaceElem<'tcx>>, | ||
|
@@ -83,20 +84,23 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( | |
mir_projections: &[PlaceElem<'tcx>], | ||
) -> Vec<HirProjectionKind> { | ||
let mut hir_projections = Vec::new(); | ||
let mut variant = None; | ||
|
||
for mir_projection in mir_projections { | ||
let hir_projection = match mir_projection { | ||
ProjectionElem::Deref => HirProjectionKind::Deref, | ||
ProjectionElem::Field(field, _) => { | ||
// We will never encouter this for multivariant enums, | ||
// read the comment for `Downcast`. | ||
HirProjectionKind::Field(field.index() as u32, VariantIdx::new(0)) | ||
let variant = variant.unwrap_or(VariantIdx::new(0)); | ||
HirProjectionKind::Field(field.index() as u32, variant) | ||
} | ||
ProjectionElem::Downcast(..) => { | ||
// This projections exist only for enums that have | ||
// multiple variants. Since such enums that are captured | ||
// completely, we can stop here. | ||
break; | ||
ProjectionElem::Downcast(.., idx) => { | ||
// We don't expect to see multi-variant enums here, as earlier | ||
// phases will have truncated them already. However, there can | ||
// still be downcasts, thanks to single-variant enums. | ||
// We keep track of VariantIdx so we can use this information | ||
// if the next ProjectionElem is a Field. | ||
variant = Some(*idx); | ||
|
||
continue; | ||
} | ||
ProjectionElem::Index(..) | ||
| ProjectionElem::ConstantIndex { .. } | ||
|
@@ -106,7 +110,7 @@ fn convert_to_hir_projections_and_truncate_for_capture<'tcx>( | |
break; | ||
} | ||
}; | ||
|
||
variant = None; | ||
hir_projections.push(hir_projection); | ||
} | ||
|
||
|
@@ -194,12 +198,12 @@ fn find_capture_matching_projections<'a, 'tcx>( | |
/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the | ||
/// `PlaceBuilder` now starts from `PlaceBase::Local`. | ||
/// | ||
/// Returns a Result with the error being the HirId of the Upvar that was not found. | ||
/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found. | ||
fn to_upvars_resolved_place_builder<'a, 'tcx>( | ||
from_builder: PlaceBuilder<'tcx>, | ||
tcx: TyCtxt<'tcx>, | ||
typeck_results: &'a ty::TypeckResults<'tcx>, | ||
) -> Result<PlaceBuilder<'tcx>, HirId> { | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { | ||
roxelo marked this conversation as resolved.
Outdated
Show resolved
Hide resolved
|
||
match from_builder.base { | ||
PlaceBase::Local(_) => Ok(from_builder), | ||
PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => { | ||
|
@@ -230,13 +234,12 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>( | |
from_builder.projection | ||
) | ||
} else { | ||
// FIXME(project-rfc-2229#24): Handle this case properly | ||
debug!( | ||
"No associated capture found for {:?}[{:#?}]", | ||
var_hir_id, from_builder.projection, | ||
); | ||
} | ||
return Err(var_hir_id); | ||
return Err(from_builder); | ||
}; | ||
|
||
let closure_ty = typeck_results | ||
|
@@ -300,6 +303,25 @@ impl<'tcx> PlaceBuilder<'tcx> { | |
to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap() | ||
} | ||
|
||
/// Attempts to resolve the `PlaceBuilder`. | ||
/// On success, it will return the resolved `PlaceBuilder`. | ||
/// On failure, it will return itself. | ||
/// | ||
/// Upvars resolve may fail for a `PlaceBuilder` when attempting to | ||
/// resolve a disjoint field whose root variable is not captured | ||
/// (destructured assignments) or when attempting to resolve a root | ||
/// variable (discriminant matching with only wildcard arm) that is | ||
/// not captured. This can happen because the final mir that will be | ||
/// generated doesn't require a read for this place. Failures will only | ||
/// happen inside closures. | ||
crate fn try_upvars_resolved<'a>( | ||
self, | ||
tcx: TyCtxt<'tcx>, | ||
typeck_results: &'a ty::TypeckResults<'tcx>, | ||
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { | ||
to_upvars_resolved_place_builder(self, tcx, typeck_results) | ||
} | ||
|
||
crate fn base(&self) -> PlaceBase { | ||
self.base | ||
} | ||
|
@@ -308,15 +330,22 @@ impl<'tcx> PlaceBuilder<'tcx> { | |
self.project(PlaceElem::Field(f, ty)) | ||
} | ||
|
||
fn deref(self) -> Self { | ||
crate fn deref(self) -> Self { | ||
self.project(PlaceElem::Deref) | ||
} | ||
|
||
crate fn downcast(self, adt_def: &'tcx AdtDef, variant_index: VariantIdx) -> Self { | ||
self.project(PlaceElem::Downcast( | ||
Some(adt_def.variants[variant_index].ident.name), | ||
variant_index, | ||
)) | ||
} | ||
|
||
fn index(self, index: Local) -> Self { | ||
self.project(PlaceElem::Index(index)) | ||
} | ||
|
||
fn project(mut self, elem: PlaceElem<'tcx>) -> Self { | ||
crate fn project(mut self, elem: PlaceElem<'tcx>) -> Self { | ||
self.projection.push(elem); | ||
self | ||
} | ||
|
@@ -602,13 +631,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
// The "retagging" transformation (for Stacked Borrows) relies on this. | ||
let idx = unpack!(block = self.as_temp(block, temp_lifetime, index, Mutability::Not,)); | ||
|
||
block = self.bounds_check( | ||
block, | ||
base_place.clone().into_place(self.tcx, self.typeck_results), | ||
idx, | ||
expr_span, | ||
source_info, | ||
); | ||
block = self.bounds_check(block, base_place.clone(), idx, expr_span, source_info); | ||
|
||
if is_outermost_index { | ||
self.read_fake_borrows(block, fake_borrow_temps, source_info) | ||
|
@@ -629,7 +652,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
fn bounds_check( | ||
&mut self, | ||
block: BasicBlock, | ||
slice: Place<'tcx>, | ||
slice: PlaceBuilder<'tcx>, | ||
index: Local, | ||
expr_span: Span, | ||
source_info: SourceInfo, | ||
|
@@ -641,7 +664,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> { | |
let lt = self.temp(bool_ty, expr_span); | ||
|
||
// len = len(slice) | ||
self.cfg.push_assign(block, source_info, len, Rvalue::Len(slice)); | ||
self.cfg.push_assign( | ||
block, | ||
source_info, | ||
len, | ||
Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)), | ||
); | ||
// lt = idx < len | ||
self.cfg.push_assign( | ||
block, | ||
|
Uh oh!
There was an error while loading. Please reload this page.