-
Notifications
You must be signed in to change notification settings - Fork 13.6k
RFC-2229: Implement Precise Capture Analysis #78801
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from 1 commit
127a6ed
88310cc
58e8f8f
1453120
8f0c0d6
b16815b
825e9e4
fa38160
be77402
abc4004
43423f6
deeb025
d0fac05
c50e57f
bb8c5e5
40dfe1e
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
Co-authored-by: Jenny Wills <wills.jenniferg@gmail.com> Co-authored-by: Aman Arora <me@aman-arora.com>
- Loading branch information
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -46,22 +46,6 @@ use rustc_span::{Span, Symbol}; | |
|
||
use std::env; | ||
|
||
macro_rules! log_capture_analysis { | ||
($fcx:expr, $closure_def_id:expr, $fmt:literal) => { | ||
if $fcx.should_log_capture_analysis($closure_def_id) { | ||
print!("For closure={:?}: ", $closure_def_id); | ||
println!($fmt); | ||
} | ||
}; | ||
|
||
($fcx:expr, $closure_def_id:expr, $fmt:literal, $($args:expr),*) => { | ||
if $fcx.should_log_capture_analysis($closure_def_id) { | ||
print!("For closure={:?}: ", $closure_def_id); | ||
println!($fmt, $($args),*); | ||
} | ||
}; | ||
} | ||
|
||
/// Describe the relationship between the paths of two places | ||
/// eg: | ||
/// - foo is ancestor of foo.bar.baz | ||
|
@@ -144,9 +128,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
|
||
let mut capture_information = FxIndexMap::<Place<'tcx>, ty::CaptureInfo<'tcx>>::default(); | ||
if self.tcx.features().capture_disjoint_fields || matches!(env::var("SG_NEW"), Ok(_)) { | ||
log_capture_analysis!(self, closure_def_id, "Using new-style capture analysis"); | ||
} else { | ||
log_capture_analysis!(self, closure_def_id, "Using old-style capture analysis"); | ||
if let Some(upvars) = self.tcx.upvars_mentioned(closure_def_id) { | ||
for (&var_hir_id, _) in upvars.iter() { | ||
let place = self.place_for_root_variable(local_def_id, var_hir_id); | ||
|
@@ -182,12 +164,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
) | ||
.consume_body(body); | ||
|
||
log_capture_analysis!( | ||
self, | ||
closure_def_id, | ||
"capture information: {:#?}", | ||
delegate.capture_information | ||
debug!( | ||
"For closure={:?}, capture_information={:#?}", | ||
closure_def_id, delegate.capture_information | ||
); | ||
self.log_closure_capture_info(closure_def_id, &delegate.capture_information, span); | ||
|
||
if let Some(closure_substs) = infer_kind { | ||
// Unify the (as yet unbound) type variable in the closure | ||
|
@@ -206,6 +187,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
} | ||
|
||
self.compute_min_captures(closure_def_id, delegate); | ||
self.log_closure_min_capture_info(closure_def_id, span); | ||
|
||
self.set_closure_captures(closure_def_id); | ||
|
||
// Now that we've analyzed the closure, we know how each | ||
|
@@ -333,10 +316,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
} | ||
} | ||
} | ||
debug!( | ||
"For closure_def_id={:?}, set_closure_captures={:#?}", | ||
closure_def_id, closure_captures | ||
); | ||
debug!("For closure_def_id={:?}, closure_captures={:#?}", closure_def_id, closure_captures); | ||
debug!( | ||
"For closure_def_id={:?}, upvar_capture_map={:#?}", | ||
closure_def_id, upvar_capture_map | ||
|
@@ -478,12 +458,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
} | ||
} | ||
|
||
log_capture_analysis!( | ||
self, | ||
closure_def_id, | ||
"min_captures={:#?}", | ||
root_var_min_capture_list | ||
); | ||
debug!("For closure={:?}, min_captures={:#?}", closure_def_id, root_var_min_capture_list); | ||
|
||
if !root_var_min_capture_list.is_empty() { | ||
self.typeck_results | ||
|
@@ -581,6 +556,46 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { | |
} | ||
} | ||
} | ||
|
||
fn log_closure_capture_info( | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. so this is logging every capture... There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Renamed the function to express the intent more clearly |
||
&self, | ||
closure_def_id: rustc_hir::def_id::DefId, | ||
capture_information: &FxIndexMap<Place<'tcx>, ty::CaptureInfo<'tcx>>, | ||
closure_span: Span, | ||
) { | ||
if self.should_log_capture_analysis(closure_def_id) { | ||
for (place, capture_info) in capture_information { | ||
let capture_str = construct_capture_info_string(self.tcx, place, capture_info); | ||
let output_str = format!("Capturing {}", capture_str); | ||
|
||
let span = capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e)); | ||
self.tcx.sess.span_err(span, &output_str); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. One thought I have for how to make this clearer is to add a "note" that indicates which closure this is captured by. Something like: let mut diag = self.tcx.sess.struct_span_err(span, &output);
diag.span_note(closure_span, "captured by this closure");
diag.emit(); |
||
} | ||
} | ||
} | ||
|
||
fn log_closure_min_capture_info(&self, closure_def_id: DefId, closure_span: Span) { | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. ....and this is logging the minimum captures ...? |
||
if self.should_log_capture_analysis(closure_def_id) { | ||
if let Some(min_captures) = | ||
self.typeck_results.borrow().closure_min_captures.get(&closure_def_id) | ||
{ | ||
for (_, min_captures_for_var) in min_captures { | ||
for capture in min_captures_for_var { | ||
let place = &capture.place; | ||
let capture_info = &capture.info; | ||
|
||
let capture_str = | ||
construct_capture_info_string(self.tcx, place, capture_info); | ||
let output_str = format!("Min Capture {}", capture_str); | ||
|
||
let span = | ||
capture_info.expr_id.map_or(closure_span, |e| self.tcx.hir().span(e)); | ||
self.tcx.sess.span_err(span, &output_str); | ||
} | ||
} | ||
} | ||
} | ||
} | ||
} | ||
|
||
struct InferBorrowKind<'a, 'tcx> { | ||
|
@@ -917,6 +932,37 @@ impl<'a, 'tcx> euv::Delegate<'tcx> for InferBorrowKind<'a, 'tcx> { | |
} | ||
} | ||
|
||
fn construct_capture_info_string( | ||
tcx: TyCtxt<'_>, | ||
place: &Place<'tcx>, | ||
capture_info: &ty::CaptureInfo<'tcx>, | ||
) -> String { | ||
let variable_name = match place.base { | ||
PlaceBase::Upvar(upvar_id) => var_name(tcx, upvar_id.var_path.hir_id).to_string(), | ||
_ => bug!("Capture_information should only contain upvars"), | ||
}; | ||
|
||
let mut projections_str = String::new(); | ||
for (i, item) in place.projections.iter().enumerate() { | ||
let proj = match item.kind { | ||
ProjectionKind::Field(a, b) => format!("({:?}, {:?})", a, b), | ||
ProjectionKind::Deref => String::from("Deref"), | ||
ProjectionKind::Index => String::from("Index"), | ||
ProjectionKind::Subslice => String::from("Subslice"), | ||
}; | ||
if i != 0 { | ||
projections_str.push_str(","); | ||
} | ||
projections_str.push_str(proj.as_str()); | ||
} | ||
|
||
let capture_kind_str = match capture_info.capture_kind { | ||
ty::UpvarCapture::ByValue(_) => "ByValue".into(), | ||
ty::UpvarCapture::ByRef(borrow) => format!("{:?}", borrow.kind), | ||
}; | ||
format!("{}[{}] -> {}", variable_name, projections_str, capture_kind_str) | ||
} | ||
|
||
fn var_name(tcx: TyCtxt<'_>, var_hir_id: hir::HirId) -> Symbol { | ||
tcx.hir().name(var_hir_id) | ||
} | ||
|
This file was deleted.
This file was deleted.
Uh oh!
There was an error while loading. Please reload this page.