Skip to content

Commit 2e44c17

Browse files
committed
Auto merge of #100968 - cjgillot:mir-upvar-vec, r=wesleywiser
Only compute captures once when building MIR.
2 parents 5197c96 + bcbd183 commit 2e44c17

File tree

8 files changed

+83
-152
lines changed

8 files changed

+83
-152
lines changed

compiler/rustc_mir_build/src/build/expr/as_place.rs

+34-102
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
33
use crate::build::expr::category::Category;
44
use crate::build::ForGuard::{OutsideGuard, RefWithinGuard};
5-
use crate::build::{BlockAnd, BlockAndExtension, Builder};
5+
use crate::build::{BlockAnd, BlockAndExtension, Builder, Capture, CaptureMap};
66
use rustc_hir::def_id::LocalDefId;
77
use rustc_middle::hir::place::Projection as HirProjection;
88
use rustc_middle::hir::place::ProjectionKind as HirProjectionKind;
@@ -59,8 +59,6 @@ pub(crate) enum PlaceBase {
5959
var_hir_id: LocalVarId,
6060
/// DefId of the closure
6161
closure_def_id: LocalDefId,
62-
/// The trait closure implements, `Fn`, `FnMut`, `FnOnce`
63-
closure_kind: ty::ClosureKind,
6462
},
6563
}
6664

@@ -145,27 +143,6 @@ fn is_ancestor_or_same_capture(
145143
iter::zip(proj_possible_ancestor, proj_capture).all(|(a, b)| a == b)
146144
}
147145

148-
/// Computes the index of a capture within the desugared closure provided the closure's
149-
/// `closure_min_captures` and the capture's index of the capture in the
150-
/// `ty::MinCaptureList` of the root variable `var_hir_id`.
151-
fn compute_capture_idx<'tcx>(
152-
closure_min_captures: &ty::RootVariableMinCaptureList<'tcx>,
153-
var_hir_id: LocalVarId,
154-
root_var_idx: usize,
155-
) -> usize {
156-
let mut res = 0;
157-
for (var_id, capture_list) in closure_min_captures {
158-
if *var_id == var_hir_id.0 {
159-
res += root_var_idx;
160-
break;
161-
} else {
162-
res += capture_list.len();
163-
}
164-
}
165-
166-
res
167-
}
168-
169146
/// Given a closure, returns the index of a capture within the desugared closure struct and the
170147
/// `ty::CapturedPlace` which is the ancestor of the Place represented using the `var_hir_id`
171148
/// and `projection`.
@@ -174,27 +151,17 @@ fn compute_capture_idx<'tcx>(
174151
///
175152
/// Returns None, when the ancestor is not found.
176153
fn find_capture_matching_projections<'a, 'tcx>(
177-
typeck_results: &'a ty::TypeckResults<'tcx>,
154+
upvars: &'a CaptureMap<'tcx>,
178155
var_hir_id: LocalVarId,
179-
closure_def_id: LocalDefId,
180156
projections: &[PlaceElem<'tcx>],
181-
) -> Option<(usize, &'a ty::CapturedPlace<'tcx>)> {
182-
let closure_min_captures = typeck_results.closure_min_captures.get(&closure_def_id)?;
183-
let root_variable_min_captures = closure_min_captures.get(&var_hir_id.0)?;
184-
157+
) -> Option<(usize, &'a Capture<'tcx>)> {
185158
let hir_projections = convert_to_hir_projections_and_truncate_for_capture(projections);
186159

187-
// If an ancestor is found, `idx` is the index within the list of captured places
188-
// for root variable `var_hir_id` and `capture` is the `ty::CapturedPlace` itself.
189-
let (idx, capture) = root_variable_min_captures.iter().enumerate().find(|(_, capture)| {
160+
upvars.get_by_key_enumerated(var_hir_id.0).find(|(_, capture)| {
190161
let possible_ancestor_proj_kinds: Vec<_> =
191-
capture.place.projections.iter().map(|proj| proj.kind).collect();
162+
capture.captured_place.place.projections.iter().map(|proj| proj.kind).collect();
192163
is_ancestor_or_same_capture(&possible_ancestor_proj_kinds, &hir_projections)
193-
})?;
194-
195-
// Convert index to be from the perspective of the entire closure_min_captures map
196-
// instead of just the root variable capture list
197-
Some((compute_capture_idx(closure_min_captures, var_hir_id, idx), capture))
164+
})
198165
}
199166

200167
/// Takes a PlaceBuilder and resolves the upvar (if any) within it, so that the
@@ -204,24 +171,15 @@ fn find_capture_matching_projections<'a, 'tcx>(
204171
fn to_upvars_resolved_place_builder<'a, 'tcx>(
205172
from_builder: PlaceBuilder<'tcx>,
206173
tcx: TyCtxt<'tcx>,
207-
typeck_results: &'a ty::TypeckResults<'tcx>,
174+
upvars: &'a CaptureMap<'tcx>,
208175
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
209176
match from_builder.base {
210177
PlaceBase::Local(_) => Ok(from_builder),
211-
PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind } => {
212-
let mut upvar_resolved_place_builder = PlaceBuilder::from(ty::CAPTURE_STRUCT_LOCAL);
213-
match closure_kind {
214-
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
215-
upvar_resolved_place_builder = upvar_resolved_place_builder.deref();
216-
}
217-
ty::ClosureKind::FnOnce => {}
218-
}
219-
178+
PlaceBase::Upvar { var_hir_id, closure_def_id } => {
220179
let Some((capture_index, capture)) =
221180
find_capture_matching_projections(
222-
typeck_results,
181+
upvars,
223182
var_hir_id,
224-
closure_def_id,
225183
&from_builder.projection,
226184
) else {
227185
let closure_span = tcx.def_span(closure_def_id);
@@ -241,39 +199,17 @@ fn to_upvars_resolved_place_builder<'a, 'tcx>(
241199
return Err(from_builder);
242200
};
243201

244-
// We won't be building MIR if the closure wasn't local
245-
let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id);
246-
let closure_ty = typeck_results.node_type(closure_hir_id);
247-
248-
let substs = match closure_ty.kind() {
249-
ty::Closure(_, substs) => ty::UpvarSubsts::Closure(substs),
250-
ty::Generator(_, substs, _) => ty::UpvarSubsts::Generator(substs),
251-
_ => bug!("Lowering capture for non-closure type {:?}", closure_ty),
252-
};
253-
254202
// Access the capture by accessing the field within the Closure struct.
255-
//
256-
// We must have inferred the capture types since we are building MIR, therefore
257-
// it's safe to call `tuple_element_ty` and we can unwrap here because
258-
// we know that the capture exists and is the `capture_index`-th capture.
259-
let var_ty = substs.tupled_upvars_ty().tuple_fields()[capture_index];
260-
261-
upvar_resolved_place_builder =
262-
upvar_resolved_place_builder.field(Field::new(capture_index), var_ty);
263-
264-
// If the variable is captured via ByRef(Immutable/Mutable) Borrow,
265-
// we need to deref it
266-
upvar_resolved_place_builder = match capture.info.capture_kind {
267-
ty::UpvarCapture::ByRef(_) => upvar_resolved_place_builder.deref(),
268-
ty::UpvarCapture::ByValue => upvar_resolved_place_builder,
269-
};
203+
let capture_info = &upvars[capture_index];
204+
205+
let mut upvar_resolved_place_builder = PlaceBuilder::from(capture_info.use_place);
270206

271207
// We used some of the projections to build the capture itself,
272208
// now we apply the remaining to the upvar resolved place.
273209
let remaining_projections = strip_prefix(
274-
capture.place.base_ty,
210+
capture.captured_place.place.base_ty,
275211
from_builder.projection,
276-
&capture.place.projections,
212+
&capture.captured_place.place.projections,
277213
);
278214
upvar_resolved_place_builder.projection.extend(remaining_projections);
279215

@@ -315,24 +251,24 @@ fn strip_prefix<'tcx>(
315251
}
316252

317253
impl<'tcx> PlaceBuilder<'tcx> {
318-
pub(crate) fn into_place<'a>(
254+
pub(in crate::build) fn into_place<'a>(
319255
self,
320256
tcx: TyCtxt<'tcx>,
321-
typeck_results: &'a ty::TypeckResults<'tcx>,
257+
upvars: &'a CaptureMap<'tcx>,
322258
) -> Place<'tcx> {
323259
if let PlaceBase::Local(local) = self.base {
324260
Place { local, projection: tcx.intern_place_elems(&self.projection) }
325261
} else {
326-
self.expect_upvars_resolved(tcx, typeck_results).into_place(tcx, typeck_results)
262+
self.expect_upvars_resolved(tcx, upvars).into_place(tcx, upvars)
327263
}
328264
}
329265

330266
fn expect_upvars_resolved<'a>(
331267
self,
332268
tcx: TyCtxt<'tcx>,
333-
typeck_results: &'a ty::TypeckResults<'tcx>,
269+
upvars: &'a CaptureMap<'tcx>,
334270
) -> PlaceBuilder<'tcx> {
335-
to_upvars_resolved_place_builder(self, tcx, typeck_results).unwrap()
271+
to_upvars_resolved_place_builder(self, tcx, upvars).unwrap()
336272
}
337273

338274
/// Attempts to resolve the `PlaceBuilder`.
@@ -346,12 +282,12 @@ impl<'tcx> PlaceBuilder<'tcx> {
346282
/// not captured. This can happen because the final mir that will be
347283
/// generated doesn't require a read for this place. Failures will only
348284
/// happen inside closures.
349-
pub(crate) fn try_upvars_resolved<'a>(
285+
pub(in crate::build) fn try_upvars_resolved<'a>(
350286
self,
351287
tcx: TyCtxt<'tcx>,
352-
typeck_results: &'a ty::TypeckResults<'tcx>,
288+
upvars: &'a CaptureMap<'tcx>,
353289
) -> Result<PlaceBuilder<'tcx>, PlaceBuilder<'tcx>> {
354-
to_upvars_resolved_place_builder(self, tcx, typeck_results)
290+
to_upvars_resolved_place_builder(self, tcx, upvars)
355291
}
356292

357293
pub(crate) fn base(&self) -> PlaceBase {
@@ -392,6 +328,12 @@ impl<'tcx> From<PlaceBase> for PlaceBuilder<'tcx> {
392328
}
393329
}
394330

331+
impl<'tcx> From<Place<'tcx>> for PlaceBuilder<'tcx> {
332+
fn from(p: Place<'tcx>) -> Self {
333+
Self { base: PlaceBase::Local(p.local), projection: p.projection.to_vec() }
334+
}
335+
}
336+
395337
impl<'a, 'tcx> Builder<'a, 'tcx> {
396338
/// Compile `expr`, yielding a place that we can move from etc.
397339
///
@@ -411,7 +353,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
411353
expr: &Expr<'tcx>,
412354
) -> BlockAnd<Place<'tcx>> {
413355
let place_builder = unpack!(block = self.as_place_builder(block, expr));
414-
block.and(place_builder.into_place(self.tcx, self.typeck_results))
356+
block.and(place_builder.into_place(self.tcx, &self.upvars))
415357
}
416358

417359
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -435,7 +377,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
435377
expr: &Expr<'tcx>,
436378
) -> BlockAnd<Place<'tcx>> {
437379
let place_builder = unpack!(block = self.as_read_only_place_builder(block, expr));
438-
block.and(place_builder.into_place(self.tcx, self.typeck_results))
380+
block.and(place_builder.into_place(self.tcx, &self.upvars))
439381
}
440382

441383
/// This is used when constructing a compound `Place`, so that we can avoid creating
@@ -530,7 +472,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
530472
inferred_ty: expr.ty,
531473
});
532474

533-
let place = place_builder.clone().into_place(this.tcx, this.typeck_results);
475+
let place = place_builder.clone().into_place(this.tcx, &this.upvars);
534476
this.cfg.push(
535477
block,
536478
Statement {
@@ -629,17 +571,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
629571
closure_def_id: LocalDefId,
630572
var_hir_id: LocalVarId,
631573
) -> BlockAnd<PlaceBuilder<'tcx>> {
632-
let closure_ty =
633-
self.typeck_results.node_type(self.tcx.hir().local_def_id_to_hir_id(closure_def_id));
634-
635-
let closure_kind = if let ty::Closure(_, closure_substs) = closure_ty.kind() {
636-
self.infcx.closure_kind(closure_substs).unwrap()
637-
} else {
638-
// Generators are considered FnOnce.
639-
ty::ClosureKind::FnOnce
640-
};
641-
642-
block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id, closure_kind }))
574+
block.and(PlaceBuilder::from(PlaceBase::Upvar { var_hir_id, closure_def_id }))
643575
}
644576

645577
/// Lower an index expression
@@ -678,7 +610,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
678610
if is_outermost_index {
679611
self.read_fake_borrows(block, fake_borrow_temps, source_info)
680612
} else {
681-
base_place = base_place.expect_upvars_resolved(self.tcx, self.typeck_results);
613+
base_place = base_place.expect_upvars_resolved(self.tcx, &self.upvars);
682614
self.add_fake_borrows_of_base(
683615
&base_place,
684616
block,
@@ -710,7 +642,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
710642
block,
711643
source_info,
712644
len,
713-
Rvalue::Len(slice.into_place(self.tcx, self.typeck_results)),
645+
Rvalue::Len(slice.into_place(self.tcx, &self.upvars)),
714646
);
715647
// lt = idx < len
716648
self.cfg.push_assign(

compiler/rustc_mir_build/src/build/expr/as_rvalue.rs

+8-9
Original file line numberDiff line numberDiff line change
@@ -328,10 +328,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
328328
unpack!(block = this.as_place_builder(block, &this.thir[*thir_place]));
329329

330330
if let Ok(place_builder_resolved) =
331-
place_builder.try_upvars_resolved(this.tcx, this.typeck_results)
331+
place_builder.try_upvars_resolved(this.tcx, &this.upvars)
332332
{
333-
let mir_place =
334-
place_builder_resolved.into_place(this.tcx, this.typeck_results);
333+
let mir_place = place_builder_resolved.into_place(this.tcx, &this.upvars);
335334
this.cfg.push_fake_read(
336335
block,
337336
this.source_info(this.tcx.hir().span(*hir_id)),
@@ -623,7 +622,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
623622
// is same as that of the capture in the parent closure.
624623
PlaceBase::Upvar { .. } => {
625624
let enclosing_upvars_resolved =
626-
arg_place_builder.clone().into_place(this.tcx, this.typeck_results);
625+
arg_place_builder.clone().into_place(this.tcx, &this.upvars);
627626

628627
match enclosing_upvars_resolved.as_ref() {
629628
PlaceRef {
@@ -643,12 +642,12 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
643642
);
644643
// Not in a closure
645644
debug_assert!(
646-
this.upvar_mutbls.len() > upvar_index.index(),
647-
"Unexpected capture place, upvar_mutbls={:#?}, upvar_index={:?}",
648-
this.upvar_mutbls,
645+
this.upvars.len() > upvar_index.index(),
646+
"Unexpected capture place, upvars={:#?}, upvar_index={:?}",
647+
this.upvars,
649648
upvar_index
650649
);
651-
this.upvar_mutbls[upvar_index.index()]
650+
this.upvars[upvar_index.index()].mutability
652651
}
653652
_ => bug!("Unexpected capture place"),
654653
}
@@ -660,7 +659,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
660659
Mutability::Mut => BorrowKind::Mut { allow_two_phase_borrow: false },
661660
};
662661

663-
let arg_place = arg_place_builder.into_place(this.tcx, this.typeck_results);
662+
let arg_place = arg_place_builder.into_place(this.tcx, &this.upvars);
664663

665664
this.cfg.push_assign(
666665
block,

compiler/rustc_mir_build/src/build/expr/into.rs

+1-3
Original file line numberDiff line numberDiff line change
@@ -366,9 +366,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
366366
None => {
367367
let place_builder = place_builder.clone();
368368
this.consume_by_copy_or_move(
369-
place_builder
370-
.field(n, *ty)
371-
.into_place(this.tcx, this.typeck_results),
369+
place_builder.field(n, *ty).into_place(this.tcx, &this.upvars),
372370
)
373371
}
374372
})

compiler/rustc_mir_build/src/build/matches/mod.rs

+11-15
Original file line numberDiff line numberDiff line change
@@ -221,9 +221,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
221221
let source_info = self.source_info(scrutinee_span);
222222

223223
if let Ok(scrutinee_builder) =
224-
scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, self.typeck_results)
224+
scrutinee_place_builder.clone().try_upvars_resolved(self.tcx, &self.upvars)
225225
{
226-
let scrutinee_place = scrutinee_builder.into_place(self.tcx, self.typeck_results);
226+
let scrutinee_place = scrutinee_builder.into_place(self.tcx, &self.upvars);
227227
self.cfg.push_fake_read(block, source_info, cause_matched_place, scrutinee_place);
228228
}
229229

@@ -348,12 +348,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
348348
// ```
349349
let mut opt_scrutinee_place: Option<(Option<&Place<'tcx>>, Span)> = None;
350350
let scrutinee_place: Place<'tcx>;
351-
if let Ok(scrutinee_builder) = scrutinee_place_builder
352-
.clone()
353-
.try_upvars_resolved(this.tcx, this.typeck_results)
351+
if let Ok(scrutinee_builder) =
352+
scrutinee_place_builder.clone().try_upvars_resolved(this.tcx, &this.upvars)
354353
{
355-
scrutinee_place =
356-
scrutinee_builder.into_place(this.tcx, this.typeck_results);
354+
scrutinee_place = scrutinee_builder.into_place(this.tcx, &this.upvars);
357355
opt_scrutinee_place = Some((Some(&scrutinee_place), scrutinee_span));
358356
}
359357
let scope = this.declare_bindings(
@@ -620,9 +618,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
620618
// };
621619
// ```
622620
if let Ok(match_pair_resolved) =
623-
initializer.clone().try_upvars_resolved(self.tcx, self.typeck_results)
621+
initializer.clone().try_upvars_resolved(self.tcx, &self.upvars)
624622
{
625-
let place = match_pair_resolved.into_place(self.tcx, self.typeck_results);
623+
let place = match_pair_resolved.into_place(self.tcx, &self.upvars);
626624
*match_place = Some(place);
627625
}
628626
}
@@ -1602,9 +1600,9 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
16021600

16031601
// Insert a Shallow borrow of any places that is switched on.
16041602
if let Some(fb) = fake_borrows && let Ok(match_place_resolved) =
1605-
match_place.clone().try_upvars_resolved(self.tcx, self.typeck_results)
1603+
match_place.clone().try_upvars_resolved(self.tcx, &self.upvars)
16061604
{
1607-
let resolved_place = match_place_resolved.into_place(self.tcx, self.typeck_results);
1605+
let resolved_place = match_place_resolved.into_place(self.tcx, &self.upvars);
16081606
fb.insert(resolved_place);
16091607
}
16101608

@@ -1791,10 +1789,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
17911789
);
17921790
let mut opt_expr_place: Option<(Option<&Place<'tcx>>, Span)> = None;
17931791
let expr_place: Place<'tcx>;
1794-
if let Ok(expr_builder) =
1795-
expr_place_builder.try_upvars_resolved(self.tcx, self.typeck_results)
1796-
{
1797-
expr_place = expr_builder.into_place(self.tcx, self.typeck_results);
1792+
if let Ok(expr_builder) = expr_place_builder.try_upvars_resolved(self.tcx, &self.upvars) {
1793+
expr_place = expr_builder.into_place(self.tcx, &self.upvars);
17981794
opt_expr_place = Some((Some(&expr_place), expr_span));
17991795
}
18001796
let otherwise_post_guard_block = otherwise_candidate.pre_binding_block.unwrap();

0 commit comments

Comments
 (0)