Skip to content

Commit c84cea9

Browse files
committed
Flatten InferredCaptureInformation
Min capture computation can already handle the same place appearing twice, and previous commits made CaptureInfo construction very cheap, so just delegate all work to min capture and let InferBorrowKind and process_collected_capture_information handle everything linearly.
1 parent 52db6b9 commit c84cea9

File tree

11 files changed

+168
-108
lines changed

11 files changed

+168
-108
lines changed

compiler/rustc_typeck/src/check/upvar.rs

+67-80
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@
3333
use super::FnCtxt;
3434

3535
use crate::expr_use_visitor as euv;
36-
use rustc_data_structures::fx::FxIndexMap;
3736
use rustc_errors::Applicability;
3837
use rustc_hir as hir;
3938
use rustc_hir::def_id::DefId;
@@ -72,7 +71,7 @@ enum PlaceAncestryRelation {
7271
/// Intermediate format to store a captured `Place` and associated `ty::CaptureInfo`
7372
/// during capture analysis. Information in this map feeds into the minimum capture
7473
/// analysis pass.
75-
type InferredCaptureInformation<'tcx> = FxIndexMap<Place<'tcx>, ty::CaptureInfo>;
74+
type InferredCaptureInformation<'tcx> = Vec<(Place<'tcx>, ty::CaptureInfo)>;
7675

7776
impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
7877
pub fn closure_analyze(&self, body: &'tcx hir::Body<'tcx>) {
@@ -258,7 +257,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
258257
capture_kind,
259258
};
260259

261-
capture_information.insert(place, fake_info);
260+
capture_information.push((place, fake_info));
262261
}
263262
}
264263

@@ -384,76 +383,68 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
384383
capture_clause: hir::CaptureBy,
385384
capture_information: InferredCaptureInformation<'tcx>,
386385
) -> (InferredCaptureInformation<'tcx>, ty::ClosureKind, Option<(Span, Place<'tcx>)>) {
387-
let mut processed: InferredCaptureInformation<'tcx> = Default::default();
388-
389386
let mut closure_kind = ty::ClosureKind::LATTICE_BOTTOM;
390387
let mut origin: Option<(Span, Place<'tcx>)> = None;
391388

392-
for (place, mut capture_info) in capture_information {
393-
// Apply rules for safety before inferring closure kind
394-
let (place, capture_kind) =
395-
restrict_capture_precision(place, capture_info.capture_kind);
396-
capture_info.capture_kind = capture_kind;
389+
let processed = capture_information
390+
.into_iter()
391+
.map(|(place, mut capture_info)| {
392+
// Apply rules for safety before inferring closure kind
393+
let (place, capture_kind) =
394+
restrict_capture_precision(place, capture_info.capture_kind);
397395

398-
let (place, capture_kind) =
399-
truncate_capture_for_optimization(place, capture_info.capture_kind);
400-
capture_info.capture_kind = capture_kind;
396+
let (place, capture_kind) = truncate_capture_for_optimization(place, capture_kind);
401397

402-
let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
403-
self.tcx.hir().span(usage_expr)
404-
} else {
405-
unreachable!()
406-
};
398+
let usage_span = if let Some(usage_expr) = capture_info.path_expr_id {
399+
self.tcx.hir().span(usage_expr)
400+
} else {
401+
unreachable!()
402+
};
407403

408-
let updated = match capture_info.capture_kind {
409-
ty::UpvarCapture::ByValue => match closure_kind {
410-
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
411-
(ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
412-
}
413-
// If closure is already FnOnce, don't update
414-
ty::ClosureKind::FnOnce => (closure_kind, origin),
415-
},
404+
let updated = match capture_kind {
405+
ty::UpvarCapture::ByValue => match closure_kind {
406+
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => {
407+
(ty::ClosureKind::FnOnce, Some((usage_span, place.clone())))
408+
}
409+
// If closure is already FnOnce, don't update
410+
ty::ClosureKind::FnOnce => (closure_kind, origin.take()),
411+
},
416412

417-
ty::UpvarCapture::ByRef(
418-
ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
419-
) => {
420-
match closure_kind {
421-
ty::ClosureKind::Fn => {
422-
(ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
413+
ty::UpvarCapture::ByRef(
414+
ty::BorrowKind::MutBorrow | ty::BorrowKind::UniqueImmBorrow,
415+
) => {
416+
match closure_kind {
417+
ty::ClosureKind::Fn => {
418+
(ty::ClosureKind::FnMut, Some((usage_span, place.clone())))
419+
}
420+
// Don't update the origin
421+
ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => {
422+
(closure_kind, origin.take())
423+
}
423424
}
424-
// Don't update the origin
425-
ty::ClosureKind::FnMut | ty::ClosureKind::FnOnce => (closure_kind, origin),
426425
}
427-
}
428-
429-
_ => (closure_kind, origin),
430-
};
431426

432-
closure_kind = updated.0;
433-
origin = updated.1;
427+
_ => (closure_kind, origin.take()),
428+
};
434429

435-
let (place, capture_kind) = match capture_clause {
436-
hir::CaptureBy::Value => adjust_for_move_closure(place, capture_info.capture_kind),
437-
hir::CaptureBy::Ref => {
438-
adjust_for_non_move_closure(place, capture_info.capture_kind)
439-
}
440-
};
430+
closure_kind = updated.0;
431+
origin = updated.1;
441432

442-
// This restriction needs to be applied after we have handled adjustments for `move`
443-
// closures. We want to make sure any adjustment that might make us move the place into
444-
// the closure gets handled.
445-
let (place, capture_kind) =
446-
restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
433+
let (place, capture_kind) = match capture_clause {
434+
hir::CaptureBy::Value => adjust_for_move_closure(place, capture_kind),
435+
hir::CaptureBy::Ref => adjust_for_non_move_closure(place, capture_kind),
436+
};
447437

448-
capture_info.capture_kind = capture_kind;
438+
// This restriction needs to be applied after we have handled adjustments for `move`
439+
// closures. We want to make sure any adjustment that might make us move the place into
440+
// the closure gets handled.
441+
let (place, capture_kind) =
442+
restrict_precision_for_drop_types(self, place, capture_kind, usage_span);
449443

450-
let capture_info = if let Some(existing) = processed.get(&place) {
451-
determine_capture_info(*existing, capture_info)
452-
} else {
453-
capture_info
454-
};
455-
processed.insert(place, capture_info);
456-
}
444+
capture_info.capture_kind = capture_kind;
445+
(place, capture_info)
446+
})
447+
.collect();
457448

458449
(processed, closure_kind, origin)
459450
}
@@ -609,8 +600,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
609600
if !descendant_found {
610601
for possible_ancestor in min_cap_list.iter_mut() {
611602
match determine_place_ancestry_relation(&place, &possible_ancestor.place) {
603+
PlaceAncestryRelation::SamePlace => {
604+
ancestor_found = true;
605+
possible_ancestor.info = determine_capture_info(
606+
possible_ancestor.info,
607+
updated_capture_info,
608+
);
609+
610+
// Only one related place will be in the list.
611+
break;
612+
}
612613
// current place is descendant of possible_ancestor
613-
PlaceAncestryRelation::Descendant | PlaceAncestryRelation::SamePlace => {
614+
PlaceAncestryRelation::Descendant => {
614615
ancestor_found = true;
615616
let backup_path_expr_id = possible_ancestor.info.path_expr_id;
616617

@@ -630,7 +631,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
630631
// we need to keep the ancestor's `path_expr_id`
631632
possible_ancestor.info.path_expr_id = backup_path_expr_id;
632633

633-
// Only one ancestor of the current place will be in the list.
634+
// Only one related place will be in the list.
634635
break;
635636
}
636637
_ => {}
@@ -1532,7 +1533,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
15321533
fn log_capture_analysis_first_pass(
15331534
&self,
15341535
closure_def_id: rustc_hir::def_id::DefId,
1535-
capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo>,
1536+
capture_information: &InferredCaptureInformation<'tcx>,
15361537
closure_span: Span,
15371538
) {
15381539
if self.should_log_capture_analysis(closure_def_id) {
@@ -1759,20 +1760,6 @@ struct InferBorrowKind<'a, 'tcx> {
17591760
fake_reads: Vec<(Place<'tcx>, FakeReadCause, hir::HirId)>,
17601761
}
17611762

1762-
impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
1763-
fn adjust_capture_info(&mut self, place: Place<'tcx>, capture_info: ty::CaptureInfo) {
1764-
match self.capture_information.get_mut(&place) {
1765-
Some(curr_info) => {
1766-
*curr_info = determine_capture_info(*curr_info, capture_info);
1767-
}
1768-
None => {
1769-
debug!("Capturing new place {:?}, capture_info={:?}", place, capture_info);
1770-
self.capture_information.insert(place, capture_info);
1771-
}
1772-
}
1773-
}
1774-
}
1775-
17761763
impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
17771764
fn fake_read(&mut self, place: Place<'tcx>, cause: FakeReadCause, diag_expr_id: hir::HirId) {
17781765
let PlaceBase::Upvar(_) = place.base else { return };
@@ -1797,14 +1784,14 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
17971784
let PlaceBase::Upvar(upvar_id) = place_with_id.place.base else { return };
17981785
assert_eq!(self.closure_def_id, upvar_id.closure_expr_id);
17991786

1800-
self.adjust_capture_info(
1787+
self.capture_information.push((
18011788
place_with_id.place.clone(),
18021789
ty::CaptureInfo {
18031790
capture_kind_expr_id: Some(diag_expr_id),
18041791
path_expr_id: Some(diag_expr_id),
18051792
capture_kind: ty::UpvarCapture::ByValue,
18061793
},
1807-
);
1794+
));
18081795
}
18091796

18101797
#[instrument(skip(self), level = "debug")]
@@ -1835,14 +1822,14 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> {
18351822
capture_kind = ty::UpvarCapture::ByRef(ty::BorrowKind::ImmBorrow);
18361823
}
18371824

1838-
self.adjust_capture_info(
1825+
self.capture_information.push((
18391826
place,
18401827
ty::CaptureInfo {
18411828
capture_kind_expr_id: Some(diag_expr_id),
18421829
path_expr_id: Some(diag_expr_id),
18431830
capture_kind,
18441831
},
1845-
);
1832+
));
18461833
}
18471834

18481835
#[instrument(skip(self), level = "debug")]

src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.rs

+1
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,7 @@ fn main() {
1515
//~^ NOTE: Capturing m[] -> MutBorrow
1616
//~| NOTE: Min Capture m[] -> MutBorrow
1717
m[1] += 40;
18+
//~^ NOTE: Capturing m[] -> MutBorrow
1819
};
1920

2021
c();

src/test/ui/closures/2229_closure_analysis/arrays-completely-captured.stderr

+7-2
Original file line numberDiff line numberDiff line change
@@ -15,7 +15,7 @@ LL | |
1515
LL | |
1616
LL | | m[0] += 10;
1717
... |
18-
LL | | m[1] += 40;
18+
LL | |
1919
LL | | };
2020
| |_____^
2121
|
@@ -24,6 +24,11 @@ note: Capturing m[] -> MutBorrow
2424
|
2525
LL | m[0] += 10;
2626
| ^
27+
note: Capturing m[] -> MutBorrow
28+
--> $DIR/arrays-completely-captured.rs:17:9
29+
|
30+
LL | m[1] += 40;
31+
| ^
2732

2833
error: Min Capture analysis includes:
2934
--> $DIR/arrays-completely-captured.rs:11:5
@@ -33,7 +38,7 @@ LL | |
3338
LL | |
3439
LL | | m[0] += 10;
3540
... |
36-
LL | | m[1] += 40;
41+
LL | |
3742
LL | | };
3843
| |_____^
3944
|

src/test/ui/closures/2229_closure_analysis/destructure_patterns.rs

+2
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,8 @@ fn arrays() {
1515
//~| ERROR: Min Capture analysis includes:
1616
let [a, b, .., e] = arr;
1717
//~^ NOTE: Capturing arr[Index] -> ByValue
18+
//~| NOTE: Capturing arr[Index] -> ByValue
19+
//~| NOTE: Capturing arr[Index] -> ByValue
1820
//~| NOTE: Min Capture arr[] -> ByValue
1921
assert_eq!(a, "A");
2022
assert_eq!(b, "B");

0 commit comments

Comments
 (0)