Introduce PlaceBuilder::resolve_upvar by ref
This commit is contained in:
parent
83356b78c4
commit
1c819792a7
1 changed files with 74 additions and 65 deletions
|
@ -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 {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue