Skip to content

Commit 3ef79c4

Browse files
Add helper function for Capture Esclations and expressions
Co-authored-by: Dhruv Jauhar <[email protected]>
1 parent 3aaf6e9 commit 3ef79c4

File tree

3 files changed

+110
-67
lines changed

3 files changed

+110
-67
lines changed

compiler/rustc_middle/src/ty/mod.rs

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -765,7 +765,23 @@ pub struct UpvarBorrow<'tcx> {
765765

766766
#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
767767
pub struct CaptureInfo<'tcx> {
768-
/// Expr Id pointing to use that resulting in selecting the current capture kind
768+
/// Expr Id pointing to use that resulted in selecting the current capture kind
769+
///
770+
/// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
771+
/// possible that we don't see the use of a particular place resulting in expr_id being
772+
/// None. In such case we fallback on uvpars_mentioned for span.
773+
///
774+
/// Eg:
775+
/// ```rust
776+
/// let x = ...;
777+
///
778+
/// let c = || {
779+
/// let _ = x
780+
/// }
781+
/// ```
782+
///
783+
/// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
784+
/// but we won't see it being used during capture analysis, since it's essentially a discard.
769785
pub expr_id: Option<hir::HirId>,
770786

771787
/// Capture mode that was selected

compiler/rustc_typeck/src/check/upvar.rs

Lines changed: 84 additions & 64 deletions
Original file line numberDiff line numberDiff line change
@@ -284,30 +284,17 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
284284
let var_hir_id = upvar_id.var_path.hir_id;
285285
closure_captures.insert(var_hir_id, upvar_id);
286286

287-
let mut new_capture_kind = capture_info.capture_kind;
288-
if let Some(existing_capture_kind) =
287+
let new_capture_kind = if let Some(capture_kind) =
289288
self.typeck_results.borrow_mut().upvar_capture_map.get(&upvar_id)
290289
{
291-
// FIXME(@azhng): refactor this later
292-
new_capture_kind = match (existing_capture_kind, new_capture_kind) {
293-
(ty::UpvarCapture::ByValue(Some(_)), _) => *existing_capture_kind,
294-
(_, ty::UpvarCapture::ByValue(Some(_))) => new_capture_kind,
295-
(ty::UpvarCapture::ByValue(_), _) | (_, ty::UpvarCapture::ByValue(_)) => {
296-
ty::UpvarCapture::ByValue(None)
297-
}
298-
(ty::UpvarCapture::ByRef(existing_ref), ty::UpvarCapture::ByRef(new_ref)) => {
299-
match (existing_ref.kind, new_ref.kind) {
300-
// Take RHS:
301-
(ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
302-
| (ty::UniqueImmBorrow, ty::MutBorrow) => new_capture_kind,
303-
// Take LHS:
304-
(ty::ImmBorrow, ty::ImmBorrow)
305-
| (ty::UniqueImmBorrow, ty::ImmBorrow | ty::UniqueImmBorrow)
306-
| (ty::MutBorrow, _) => *existing_capture_kind,
307-
}
308-
}
309-
};
310-
}
290+
// upvar_capture_map only stores the UpvarCapture (CaptureKind),
291+
// so we create a fake capture info with no expression.
292+
let fake_capture_info =
293+
ty::CaptureInfo { expr_id: None, capture_kind: capture_kind.clone() };
294+
self.determine_capture_info(fake_capture_info, capture_info.clone()).capture_kind
295+
} else {
296+
capture_info.capture_kind
297+
};
311298
self.typeck_results.borrow_mut().upvar_capture_map.insert(upvar_id, new_capture_kind);
312299
}
313300

@@ -353,6 +340,60 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
353340
fn should_log_capture_analysis(&self, closure_def_id: DefId) -> bool {
354341
self.tcx.has_attr(closure_def_id, sym::rustc_capture_analysis)
355342
}
343+
344+
/// Helper function to determine if we need to escalate CaptureKind from
345+
/// CaptureInfo A to B and returns the escalated CaptureInfo.
346+
/// (Note: CaptureInfo contains CaptureKind and an expression that led to capture it in that way)
347+
///
348+
/// If both `CaptureKind`s are considered equivalent, then the CaptureInfo is selected based
349+
/// on the `CaptureInfo` containing an associated expression id.
350+
///
351+
/// If both the CaptureKind and Expression are considered to be equivalent,
352+
/// then `CaptureInfo` A is preferred.
353+
fn determine_capture_info(
354+
&self,
355+
capture_info_a: ty::CaptureInfo<'tcx>,
356+
capture_info_b: ty::CaptureInfo<'tcx>,
357+
) -> ty::CaptureInfo<'tcx> {
358+
// If the capture kind is equivalent then, we don't need to escalate and can compare the
359+
// expressions.
360+
let eq_capture_kind = match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
361+
(ty::UpvarCapture::ByValue(_), ty::UpvarCapture::ByValue(_)) => true,
362+
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
363+
ref_a.kind == ref_b.kind
364+
}
365+
_ => false,
366+
};
367+
368+
if eq_capture_kind {
369+
match (capture_info_a.expr_id, capture_info_b.expr_id) {
370+
(Some(_), _) | (None, None) => capture_info_a,
371+
(None, Some(_)) => capture_info_b,
372+
}
373+
} else {
374+
match (capture_info_a.capture_kind, capture_info_b.capture_kind) {
375+
(ty::UpvarCapture::ByValue(_), _) => capture_info_a,
376+
(_, ty::UpvarCapture::ByValue(_)) => capture_info_b,
377+
(ty::UpvarCapture::ByRef(ref_a), ty::UpvarCapture::ByRef(ref_b)) => {
378+
match (ref_a.kind, ref_b.kind) {
379+
// Take LHS:
380+
(ty::UniqueImmBorrow | ty::MutBorrow, ty::ImmBorrow)
381+
| (ty::MutBorrow, ty::UniqueImmBorrow) => capture_info_a,
382+
383+
// Take RHS:
384+
(ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
385+
| (ty::UniqueImmBorrow, ty::MutBorrow) => capture_info_b,
386+
387+
(ty::ImmBorrow, ty::ImmBorrow)
388+
| (ty::UniqueImmBorrow, ty::UniqueImmBorrow)
389+
| (ty::MutBorrow, ty::MutBorrow) => {
390+
bug!("Expected unequal capture kinds");
391+
}
392+
}
393+
}
394+
}
395+
}
396+
}
356397
}
357398

358399
struct InferBorrowKind<'a, 'tcx> {
@@ -426,16 +467,10 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
426467
capture_kind: ty::UpvarCapture::ByValue(Some(usage_span)),
427468
};
428469

429-
let curr_info = self.capture_information.get(&place_with_id.place);
430-
let updated_info = match curr_info {
431-
Some(info) => match info.capture_kind {
432-
ty::UpvarCapture::ByRef(_) | ty::UpvarCapture::ByValue(None) => capture_info,
433-
_ => *info,
434-
},
435-
None => capture_info,
436-
};
470+
let curr_info = self.capture_information[&place_with_id.place];
471+
let updated_info = self.fcx.determine_capture_info(curr_info, capture_info);
437472

438-
self.capture_information.insert(place_with_id.place.clone(), updated_info);
473+
self.capture_information[&place_with_id.place] = updated_info;
439474
}
440475

441476
/// Indicates that `place_with_id` is being directly mutated (e.g., assigned
@@ -532,42 +567,28 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
532567
diag_expr_id: hir::HirId,
533568
kind: ty::BorrowKind,
534569
) {
535-
let capture_info = self
536-
.capture_information
537-
.get(&place_with_id.place)
538-
.unwrap_or_else(|| bug!("Upar capture info missing"));
539-
// We init capture_information for each element
570+
let curr_capture_info = self.capture_information[&place_with_id.place];
540571

541572
debug!(
542-
"adjust_upvar_borrow_kind(place={:?}, , diag_expr_id={:?}, capture_info={:?}, kind={:?})",
543-
place_with_id, diag_expr_id, capture_info, kind
573+
"adjust_upvar_borrow_kind(place={:?}, diag_expr_id={:?}, capture_info={:?}, kind={:?})",
574+
place_with_id, diag_expr_id, curr_capture_info, kind
544575
);
545576

546-
match capture_info.capture_kind {
547-
ty::UpvarCapture::ByValue(_) => {
548-
// Upvar is already by-value, the strongest criteria.
549-
}
550-
ty::UpvarCapture::ByRef(upvar_borrow) => {
551-
match (upvar_borrow.kind, kind) {
552-
// Take RHS:
553-
(ty::ImmBorrow, ty::UniqueImmBorrow | ty::MutBorrow)
554-
| (ty::UniqueImmBorrow, ty::MutBorrow) => {
555-
if let Some(ty::CaptureInfo { expr_id, capture_kind }) =
556-
self.capture_information.get_mut(&place_with_id.place)
557-
{
558-
*expr_id = Some(diag_expr_id);
559-
if let ty::UpvarCapture::ByRef(borrow_kind) = capture_kind {
560-
borrow_kind.kind = kind;
561-
}
562-
}
563-
}
564-
// Take LHS:
565-
(ty::ImmBorrow, ty::ImmBorrow)
566-
| (ty::UniqueImmBorrow, ty::ImmBorrow | ty::UniqueImmBorrow)
567-
| (ty::MutBorrow, _) => {}
568-
}
569-
}
570-
}
577+
if let ty::UpvarCapture::ByValue(_) = curr_capture_info.capture_kind {
578+
// It's already captured by value, we don't need to do anything here
579+
return;
580+
} else if let ty::UpvarCapture::ByRef(curr_upvar_borrow) = curr_capture_info.capture_kind {
581+
// Use the same region as the current capture information
582+
// Doesn't matter since only one of the UpvarBorrow will be used.
583+
let new_upvar_borrow = ty::UpvarBorrow { kind, region: curr_upvar_borrow.region };
584+
585+
let capture_info = ty::CaptureInfo {
586+
expr_id: Some(diag_expr_id),
587+
capture_kind: ty::UpvarCapture::ByRef(new_upvar_borrow),
588+
};
589+
let updated_info = self.fcx.determine_capture_info(curr_capture_info, capture_info);
590+
self.capture_information[&place_with_id.place] = updated_info;
591+
};
571592
}
572593

573594
fn adjust_closure_kind(
@@ -622,7 +643,6 @@ impl<'a, 'tcx> InferBorrowKind<'a, 'tcx> {
622643

623644
debug!("Capturing new place {:?}", place_with_id);
624645

625-
let tcx = self.fcx.tcx;
626646
let capture_kind =
627647
self.fcx.init_capture_kind(self.capture_clause, upvar_id, self.closure_span);
628648

src/test/ui/closures/2229_closure_analysis/slice-pat.stdout

Lines changed: 9 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,9 +12,16 @@ For closure=DefId(0:5 ~ slice_pat[317d]::main::{closure#0}): capture information
1212
},
1313
],
1414
}: CaptureInfo {
15-
expr_id: None,
15+
expr_id: Some(
16+
HirId {
17+
owner: DefId(0:3 ~ slice_pat[317d]::main),
18+
local_id: 179,
19+
},
20+
),
1621
capture_kind: ByValue(
17-
None,
22+
Some(
23+
$DIR/slice-pat.rs:21:33: 21:36 (#0),
24+
),
1825
),
1926
},
2027
}

0 commit comments

Comments
 (0)