Auto merge of #78801 - sexxi-goose:min_capture, r=nikomatsakis
RFC-2229: Implement Precise Capture Analysis ### This PR introduces - Feature gate for RFC-2229 (incomplete) `capture_disjoint_field` - Rustc Attribute to print out the capture analysis `rustc_capture_analysis` - Precise capture analysis ### Description of the analysis 1. If the feature gate is not set then all variables that are not local to the closure will be added to the list of captures. (This is for backcompat) 2. The rest of the analysis is based entirely on how the captured `Place`s are used within the closure. Precise information (i.e. projections) about the `Place` is maintained throughout. 3. To reduce the amount of information we need to keep track of, we do a minimization step. In this step, we determine a list such that no Place within this list represents an ancestor path to another entry in the list. Check rust-lang/project-rfc-2229#9 for more detailed examples. 4. To keep the compiler functional as before we implement a Bridge between the results of this new analysis to existing data structures used for closure captures. Note the new capture analysis results are only part of MaybeTypeckTables that is the information is only available during typeck-ing. ### Known issues - Statements like `let _ = x` will make the compiler ICE when used within a closure with the feature enabled. More generally speaking the issue is caused by `let` statements that create no bindings and are init'ed using a Place expression. ### Testing We removed the code that would handle the case where the feature gate is not set, to enable the feature as default and did a bors try and perf run. More information here: #78762 ### Thanks This has been slowly in the works for a while now. I want to call out `@Azhng` `@ChrisPardy` `@null-sleep` `@jenniferwills` `@logmosier` `@roxelo` for working on this and the previous PRs that led up to this, `@nikomatsakis` for guiding us. Closes rust-lang/project-rfc-2229#7 Closes rust-lang/project-rfc-2229#9 Closes rust-lang/project-rfc-2229#6 Closes rust-lang/project-rfc-2229#19 r? `@nikomatsakis`
This commit is contained in:
commit
b5c37e86ff
37 changed files with 2484 additions and 177 deletions
|
@ -6,6 +6,7 @@ pub use self::IntVarValue::*;
|
|||
pub use self::Variance::*;
|
||||
|
||||
use crate::hir::exports::ExportMap;
|
||||
use crate::hir::place::Place as HirPlace;
|
||||
use crate::ich::StableHashingContext;
|
||||
use crate::middle::cstore::CrateStoreDyn;
|
||||
use crate::middle::resolve_lifetime::ObjectLifetimeDefault;
|
||||
|
@ -685,6 +686,12 @@ pub struct UpvarId {
|
|||
pub closure_expr_id: LocalDefId,
|
||||
}
|
||||
|
||||
impl UpvarId {
|
||||
pub fn new(var_hir_id: hir::HirId, closure_def_id: LocalDefId) -> UpvarId {
|
||||
UpvarId { var_path: UpvarPath { hir_id: var_hir_id }, closure_expr_id: closure_def_id }
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, PartialEq, Debug, TyEncodable, TyDecodable, Copy, HashStable)]
|
||||
pub enum BorrowKind {
|
||||
/// Data must be immutable and is aliasable.
|
||||
|
@ -767,6 +774,56 @@ pub struct UpvarBorrow<'tcx> {
|
|||
pub region: ty::Region<'tcx>,
|
||||
}
|
||||
|
||||
/// Given the closure DefId this map provides a map of root variables to minimum
|
||||
/// set of `CapturedPlace`s that need to be tracked to support all captures of that closure.
|
||||
pub type MinCaptureInformationMap<'tcx> = FxHashMap<DefId, RootVariableMinCaptureList<'tcx>>;
|
||||
|
||||
/// Part of `MinCaptureInformationMap`; Maps a root variable to the list of `CapturedPlace`.
|
||||
/// Used to track the minimum set of `Place`s that need to be captured to support all
|
||||
/// Places captured by the closure starting at a given root variable.
|
||||
///
|
||||
/// This provides a convenient and quick way of checking if a variable being used within
|
||||
/// a closure is a capture of a local variable.
|
||||
pub type RootVariableMinCaptureList<'tcx> = FxIndexMap<hir::HirId, MinCaptureList<'tcx>>;
|
||||
|
||||
/// Part of `MinCaptureInformationMap`; List of `CapturePlace`s.
|
||||
pub type MinCaptureList<'tcx> = Vec<CapturedPlace<'tcx>>;
|
||||
|
||||
/// A `Place` and the corresponding `CaptureInfo`.
|
||||
#[derive(PartialEq, Clone, Debug, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct CapturedPlace<'tcx> {
|
||||
pub place: HirPlace<'tcx>,
|
||||
pub info: CaptureInfo<'tcx>,
|
||||
}
|
||||
|
||||
/// Part of `MinCaptureInformationMap`; describes the capture kind (&, &mut, move)
|
||||
/// for a particular capture as well as identifying the part of the source code
|
||||
/// that triggered this capture to occur.
|
||||
#[derive(PartialEq, Clone, Debug, Copy, TyEncodable, TyDecodable, HashStable)]
|
||||
pub struct CaptureInfo<'tcx> {
|
||||
/// Expr Id pointing to use that resulted in selecting the current capture kind
|
||||
///
|
||||
/// If the user doesn't enable feature `capture_disjoint_fields` (RFC 2229) then, it is
|
||||
/// possible that we don't see the use of a particular place resulting in expr_id being
|
||||
/// None. In such case we fallback on uvpars_mentioned for span.
|
||||
///
|
||||
/// Eg:
|
||||
/// ```rust,no_run
|
||||
/// let x = 5;
|
||||
///
|
||||
/// let c = || {
|
||||
/// let _ = x
|
||||
/// };
|
||||
/// ```
|
||||
///
|
||||
/// In this example, if `capture_disjoint_fields` is **not** set, then x will be captured,
|
||||
/// but we won't see it being used during capture analysis, since it's essentially a discard.
|
||||
pub expr_id: Option<hir::HirId>,
|
||||
|
||||
/// Capture mode that was selected
|
||||
pub capture_kind: UpvarCapture<'tcx>,
|
||||
}
|
||||
|
||||
pub type UpvarListMap = FxHashMap<DefId, FxIndexMap<hir::HirId, UpvarId>>;
|
||||
pub type UpvarCaptureMap<'tcx> = FxHashMap<UpvarId, UpvarCapture<'tcx>>;
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue