1
Fork 0

Introduce PlaceBuilder::resolve_upvar by ref

This commit is contained in:
Cameron Steffen 2022-11-02 15:16:08 -05:00
parent 83356b78c4
commit 1c819792a7

View file

@ -167,23 +167,20 @@ fn find_capture_matching_projections<'a, 'tcx>(
}) })
} }
/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the /// Takes an upvar place and tries to resolve it into a `PlaceBuilder`
/// `PlaceBuilder` now starts from `PlaceBase::Local`. /// with `PlaceBase::Local`
///
/// Returns a Result with the error being the PlaceBuilder (`from_builder`) that was not found.
#[instrument(level = "trace", skip(cx), ret)] #[instrument(level = "trace", skip(cx), ret)]
fn to_upvars_resolved_place_builder<'tcx>( fn to_upvars_resolved_place_builder<'tcx>(
from_builder: PlaceBuilder<'tcx>,
cx: &Builder<'_, 'tcx>, cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { var_hir_id: LocalVarId,
match from_builder.base { closure_def_id: LocalDefId,
PlaceBase::Local(_) => Ok(from_builder), projection: &[PlaceElem<'tcx>],
PlaceBase::Upvar { var_hir_id, closure_def_id } => { ) -> Option<PlaceBuilder<'tcx>> {
let Some((capture_index, capture)) = let Some((capture_index, capture)) =
find_capture_matching_projections( find_capture_matching_projections(
&cx.upvars, &cx.upvars,
var_hir_id, var_hir_id,
&from_builder.projection, &projection,
) else { ) else {
let closure_span = cx.tcx.def_span(closure_def_id); let closure_span = cx.tcx.def_span(closure_def_id);
if !enable_precise_capture(cx.tcx, closure_span) { if !enable_precise_capture(cx.tcx, closure_span) {
@ -191,15 +188,15 @@ fn to_upvars_resolved_place_builder<'tcx>(
"No associated capture found for {:?}[{:#?}] even though \ "No associated capture found for {:?}[{:#?}] even though \
capture_disjoint_fields isn't enabled", capture_disjoint_fields isn't enabled",
var_hir_id, var_hir_id,
from_builder.projection projection
) )
} else { } else {
debug!( debug!(
"No associated capture found for {:?}[{:#?}]", "No associated capture found for {:?}[{:#?}]",
var_hir_id, from_builder.projection, var_hir_id, projection,
); );
} }
return Err(from_builder); return None;
}; };
// Access the capture by accessing the field within the Closure struct. // Access the capture by accessing the field within the Closure struct.
@ -209,17 +206,15 @@ fn to_upvars_resolved_place_builder<'tcx>(
// We used some of the projections to build the capture itself, // We used some of the projections to build the capture itself,
// now we apply the remaining to the upvar resolved place. // now we apply the remaining to the upvar resolved place.
trace!(?capture.captured_place, ?from_builder.projection); trace!(?capture.captured_place, ?projection);
let remaining_projections = strip_prefix( let remaining_projections = strip_prefix(
capture.captured_place.place.base_ty, capture.captured_place.place.base_ty,
from_builder.projection, projection,
&capture.captured_place.place.projections, &capture.captured_place.place.projections,
); );
upvar_resolved_place_builder.projection.extend(remaining_projections); upvar_resolved_place_builder.projection.extend(remaining_projections);
Ok(upvar_resolved_place_builder) Some(upvar_resolved_place_builder)
}
}
} }
/// Returns projections remaining after stripping an initial prefix of HIR /// Returns projections remaining after stripping an initial prefix of HIR
@ -228,13 +223,14 @@ fn to_upvars_resolved_place_builder<'tcx>(
/// Supports only HIR projection kinds that represent a path that might be /// 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` /// captured by a closure or a generator, i.e., an `Index` or a `Subslice`
/// projection kinds are unsupported. /// projection kinds are unsupported.
fn strip_prefix<'tcx>( fn strip_prefix<'a, 'tcx>(
mut base_ty: Ty<'tcx>, mut base_ty: Ty<'tcx>,
projections: Vec<PlaceElem<'tcx>>, projections: &'a [PlaceElem<'tcx>],
prefix_projections: &[HirProjection<'tcx>], prefix_projections: &[HirProjection<'tcx>],
) -> impl Iterator<Item = PlaceElem<'tcx>> { ) -> impl Iterator<Item = PlaceElem<'tcx>> + 'a {
let mut iter = projections let mut iter = projections
.into_iter() .iter()
.copied()
// Filter out opaque casts, they are unnecessary in the prefix. // Filter out opaque casts, they are unnecessary in the prefix.
.filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..))); .filter(|elem| !matches!(elem, ProjectionElem::OpaqueCast(..)));
for projection in prefix_projections { for projection in prefix_projections {
@ -258,21 +254,31 @@ fn strip_prefix<'tcx>(
} }
impl<'tcx> PlaceBuilder<'tcx> { impl<'tcx> PlaceBuilder<'tcx> {
pub(in crate::build) fn into_place(self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> { pub(in crate::build) fn into_place(mut self, cx: &Builder<'_, 'tcx>) -> Place<'tcx> {
if let PlaceBase::Local(local) = self.base { self = self.resolve_upvar(cx).unwrap_or(self);
let PlaceBase::Local(local) = self.base else { panic!("expected local") };
Place { local, projection: cx.tcx.intern_place_elems(&self.projection) } Place { local, projection: cx.tcx.intern_place_elems(&self.projection) }
} else {
self.expect_upvars_resolved(cx).into_place(cx)
}
} }
fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> { fn expect_upvars_resolved(self, cx: &Builder<'_, 'tcx>) -> PlaceBuilder<'tcx> {
to_upvars_resolved_place_builder(self, cx).unwrap() match self.base {
PlaceBase::Local(_) => self,
PlaceBase::Upvar {..} => self.resolve_upvar(cx).unwrap(),
}
}
pub(in crate::build) fn try_upvars_resolved(
self,
cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
match self.base {
PlaceBase::Local(_) => Ok(self),
PlaceBase::Upvar { .. } => self.resolve_upvar(cx).ok_or(self),
}
} }
/// Attempts to resolve the `PlaceBuilder`. /// Attempts to resolve the `PlaceBuilder`.
/// On success, it will return the resolved `PlaceBuilder`. /// Returns `None` if this is not an upvar.
/// On failure, it will return itself.
/// ///
/// Upvars resolve may fail for a `PlaceBuilder` when attempting to /// Upvars resolve may fail for a `PlaceBuilder` when attempting to
/// resolve a disjoint field whose root variable is not captured /// resolve a disjoint field whose root variable is not captured
@ -281,11 +287,14 @@ impl<'tcx> PlaceBuilder<'tcx> {
/// not captured. This can happen because the final mir that will be /// not captured. This can happen because the final mir that will be
/// generated doesn't require a read for this place. Failures will only /// generated doesn't require a read for this place. Failures will only
/// happen inside closures. /// happen inside closures.
pub(in crate::build) fn try_upvars_resolved( pub(in crate::build) fn resolve_upvar(
self, &self,
cx: &Builder<'_, 'tcx>, cx: &Builder<'_, 'tcx>,
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> { ) -> Option<PlaceBuilder<'tcx>> {
to_upvars_resolved_place_builder(self, cx) let PlaceBase::Upvar { var_hir_id, closure_def_id } = self.base else {
return None;
};
to_upvars_resolved_place_builder(cx, var_hir_id, closure_def_id, &self.projection)
} }
pub(crate) fn base(&self) -> PlaceBase { pub(crate) fn base(&self) -> PlaceBase {