Skip to content

Commit 6534637

Browse files
committed
Auto merge of rust-lang#95563 - dingxiangfei2009:dxf-rfc66-refactor, r=nikomatsakis
Move the extended lifetime resolution into typeck context Related to rust-lang#15023 This PR is based on the [idea](rust-lang#15023 (comment)) of rust-lang#15023 by `@nikomatsakis.` This PR specifically proposes to - Delay the resolution of scopes of rvalues to a later stage, so that enough type information is available to refine those scopes based on relationships of lifetimes. - Highlight relevant parts that would help future reviews on the next installments of works to fully implement a solution to RFC 66.
2 parents acfd327 + 6044fbe commit 6534637

File tree

25 files changed

+363
-192
lines changed

25 files changed

+363
-192
lines changed

compiler/rustc_hir/src/hir.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1370,7 +1370,7 @@ pub enum UnsafeSource {
13701370
UserProvided,
13711371
}
13721372

1373-
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Hash, Debug)]
1373+
#[derive(Copy, Clone, PartialEq, Eq, Encodable, Decodable, Hash, Debug)]
13741374
pub struct BodyId {
13751375
pub hir_id: HirId,
13761376
}

compiler/rustc_middle/src/arena.rs

-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,6 @@ macro_rules! arena_types {
3333
[] const_allocs: rustc_middle::mir::interpret::Allocation,
3434
// Required for the incremental on-disk cache
3535
[] mir_keys: rustc_hir::def_id::DefIdSet,
36-
[] region_scope_tree: rustc_middle::middle::region::ScopeTree,
3736
[] dropck_outlives:
3837
rustc_middle::infer::canonical::Canonical<'tcx,
3938
rustc_middle::infer::canonical::QueryResponse<'tcx,

compiler/rustc_middle/src/middle/region.rs

+33-45
Original file line numberDiff line numberDiff line change
@@ -203,7 +203,7 @@ impl Scope {
203203
pub type ScopeDepth = u32;
204204

205205
/// The region scope tree encodes information about region relationships.
206-
#[derive(Default, Debug)]
206+
#[derive(TyEncodable, TyDecodable, Default, Debug)]
207207
pub struct ScopeTree {
208208
/// If not empty, this body is the root of this region hierarchy.
209209
pub root_body: Option<hir::HirId>,
@@ -223,15 +223,12 @@ pub struct ScopeTree {
223223
/// Maps from a `NodeId` to the associated destruction scope (if any).
224224
destruction_scopes: FxIndexMap<hir::ItemLocalId, Scope>,
225225

226-
/// `rvalue_scopes` includes entries for those expressions whose
227-
/// cleanup scope is larger than the default. The map goes from the
228-
/// expression ID to the cleanup scope id. For rvalues not present in
229-
/// this table, the appropriate cleanup scope is the innermost
230-
/// enclosing statement, conditional expression, or repeating
231-
/// block (see `terminating_scopes`).
232-
/// In constants, None is used to indicate that certain expressions
233-
/// escape into 'static and should have no local cleanup scope.
234-
rvalue_scopes: FxHashMap<hir::ItemLocalId, Option<Scope>>,
226+
/// Identifies expressions which, if captured into a temporary, ought to
227+
/// have a temporary whose lifetime extends to the end of the enclosing *block*,
228+
/// and not the enclosing *statement*. Expressions that are not present in this
229+
/// table are not rvalue candidates. The set of rvalue candidates is computed
230+
/// during type check based on a traversal of the AST.
231+
pub rvalue_candidates: FxHashMap<hir::HirId, RvalueCandidateType>,
235232

236233
/// If there are any `yield` nested within a scope, this map
237234
/// stores the `Span` of the last one and its index in the
@@ -315,6 +312,17 @@ pub struct ScopeTree {
315312
pub body_expr_count: FxHashMap<hir::BodyId, usize>,
316313
}
317314

315+
/// Identifies the reason that a given expression is an rvalue candidate
316+
/// (see the `rvalue_candidates` field for more information what rvalue
317+
/// candidates in general). In constants, the `lifetime` field is None
318+
/// to indicate that certain expressions escape into 'static and
319+
/// should have no local cleanup scope.
320+
#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
321+
pub enum RvalueCandidateType {
322+
Borrow { target: hir::ItemLocalId, lifetime: Option<Scope> },
323+
Pattern { target: hir::ItemLocalId, lifetime: Option<Scope> },
324+
}
325+
318326
#[derive(Debug, Copy, Clone, TyEncodable, TyDecodable, HashStable)]
319327
pub struct YieldData {
320328
/// The `Span` of the yield.
@@ -349,12 +357,20 @@ impl ScopeTree {
349357
self.var_map.insert(var, lifetime);
350358
}
351359

352-
pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
353-
debug!("record_rvalue_scope(sub={:?}, sup={:?})", var, lifetime);
354-
if let Some(lifetime) = lifetime {
355-
assert!(var != lifetime.item_local_id());
360+
pub fn record_rvalue_candidate(
361+
&mut self,
362+
var: hir::HirId,
363+
candidate_type: RvalueCandidateType,
364+
) {
365+
debug!("record_rvalue_candidate(var={var:?}, type={candidate_type:?})");
366+
match &candidate_type {
367+
RvalueCandidateType::Borrow { lifetime: Some(lifetime), .. }
368+
| RvalueCandidateType::Pattern { lifetime: Some(lifetime), .. } => {
369+
assert!(var.local_id != lifetime.item_local_id())
370+
}
371+
_ => {}
356372
}
357-
self.rvalue_scopes.insert(var, lifetime);
373+
self.rvalue_candidates.insert(var, candidate_type);
358374
}
359375

360376
/// Returns the narrowest scope that encloses `id`, if any.
@@ -367,34 +383,6 @@ impl ScopeTree {
367383
self.var_map.get(&var_id).cloned()
368384
}
369385

370-
/// Returns the scope when the temp created by `expr_id` will be cleaned up.
371-
pub fn temporary_scope(&self, expr_id: hir::ItemLocalId) -> Option<Scope> {
372-
// Check for a designated rvalue scope.
373-
if let Some(&s) = self.rvalue_scopes.get(&expr_id) {
374-
debug!("temporary_scope({:?}) = {:?} [custom]", expr_id, s);
375-
return s;
376-
}
377-
378-
// Otherwise, locate the innermost terminating scope
379-
// if there's one. Static items, for instance, won't
380-
// have an enclosing scope, hence no scope will be
381-
// returned.
382-
let mut id = Scope { id: expr_id, data: ScopeData::Node };
383-
384-
while let Some(&(p, _)) = self.parent_map.get(&id) {
385-
match p.data {
386-
ScopeData::Destruction => {
387-
debug!("temporary_scope({:?}) = {:?} [enclosing]", expr_id, id);
388-
return Some(id);
389-
}
390-
_ => id = p,
391-
}
392-
}
393-
394-
debug!("temporary_scope({:?}) = None", expr_id);
395-
None
396-
}
397-
398386
/// Returns `true` if `subscope` is equal to or is lexically nested inside `superscope`, and
399387
/// `false` otherwise.
400388
///
@@ -439,7 +427,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
439427
ref parent_map,
440428
ref var_map,
441429
ref destruction_scopes,
442-
ref rvalue_scopes,
430+
ref rvalue_candidates,
443431
ref yield_in_scope,
444432
} = *self;
445433

@@ -448,7 +436,7 @@ impl<'a> HashStable<StableHashingContext<'a>> for ScopeTree {
448436
parent_map.hash_stable(hcx, hasher);
449437
var_map.hash_stable(hcx, hasher);
450438
destruction_scopes.hash_stable(hcx, hasher);
451-
rvalue_scopes.hash_stable(hcx, hasher);
439+
rvalue_candidates.hash_stable(hcx, hasher);
452440
yield_in_scope.hash_stable(hcx, hasher);
453441
}
454442
}

compiler/rustc_middle/src/query/mod.rs

-6
Original file line numberDiff line numberDiff line change
@@ -1048,12 +1048,6 @@ rustc_queries! {
10481048
desc { "reachability" }
10491049
}
10501050

1051-
/// Per-body `region::ScopeTree`. The `DefId` should be the owner `DefId` for the body;
1052-
/// in the case of closures, this will be redirected to the enclosing function.
1053-
query region_scope_tree(def_id: DefId) -> &'tcx region::ScopeTree {
1054-
desc { |tcx| "computing drop scopes for `{}`", tcx.def_path_str(def_id) }
1055-
}
1056-
10571051
/// Generates a MIR body for the shim.
10581052
query mir_shims(key: ty::InstanceDef<'tcx>) -> mir::Body<'tcx> {
10591053
storage(ArenaCacheSelector<'tcx>)

compiler/rustc_middle/src/ty/context.rs

+16
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ use crate::hir::place::Place as HirPlace;
66
use crate::infer::canonical::{Canonical, CanonicalVarInfo, CanonicalVarInfos};
77
use crate::lint::{struct_lint_level, LintDiagnosticBuilder, LintLevelSource};
88
use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
9+
use crate::middle::region::ScopeTree;
910
use crate::middle::resolve_lifetime::{self, LifetimeScopeForPath};
1011
use crate::middle::stability;
1112
use crate::mir::interpret::{self, Allocation, ConstAllocation, ConstValue, Scalar};
@@ -74,6 +75,8 @@ use std::mem;
7475
use std::ops::{Bound, Deref};
7576
use std::sync::Arc;
7677

78+
use super::RvalueScopes;
79+
7780
pub trait OnDiskCache<'tcx>: rustc_data_structures::sync::Sync {
7881
/// Creates a new `OnDiskCache` instance from the serialized data in `data`.
7982
fn new(sess: &'tcx Session, data: Mmap, start_pos: usize) -> Self
@@ -535,6 +538,17 @@ pub struct TypeckResults<'tcx> {
535538
/// issue by fake reading `t`.
536539
pub closure_fake_reads: FxHashMap<DefId, Vec<(HirPlace<'tcx>, FakeReadCause, hir::HirId)>>,
537540

541+
/// Tracks critical information about regions in a body.
542+
/// This includes containment relationship between regions,
543+
/// liveness relationship between variables and regions and
544+
/// information about yield points.
545+
pub region_scope_tree: ScopeTree,
546+
547+
/// Tracks the rvalue scoping rules which defines finer scoping for rvalue expressions
548+
/// by applying extended parameter rules.
549+
/// Details may be find in `rustc_typeck::check::rvalue_scopes`.
550+
pub rvalue_scopes: RvalueScopes,
551+
538552
/// Stores the type, expression, span and optional scope span of all types
539553
/// that are live across the yield of this generator (if a generator).
540554
pub generator_interior_types: ty::Binder<'tcx, Vec<GeneratorInteriorTypeCause<'tcx>>>,
@@ -572,6 +586,8 @@ impl<'tcx> TypeckResults<'tcx> {
572586
concrete_opaque_types: Default::default(),
573587
closure_min_captures: Default::default(),
574588
closure_fake_reads: Default::default(),
589+
region_scope_tree: Default::default(),
590+
rvalue_scopes: Default::default(),
575591
generator_interior_types: ty::Binder::dummy(Default::default()),
576592
treat_byte_string_as_slice: Default::default(),
577593
closure_size_eval: Default::default(),

compiler/rustc_middle/src/ty/mod.rs

+2
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,7 @@ pub use self::context::{
7272
};
7373
pub use self::instance::{Instance, InstanceDef};
7474
pub use self::list::List;
75+
pub use self::rvalue_scopes::RvalueScopes;
7576
pub use self::sty::BoundRegionKind::*;
7677
pub use self::sty::RegionKind::*;
7778
pub use self::sty::TyKind::*;
@@ -118,6 +119,7 @@ mod generics;
118119
mod impls_ty;
119120
mod instance;
120121
mod list;
122+
mod rvalue_scopes;
121123
mod structural_impls;
122124
mod sty;
123125

compiler/rustc_middle/src/ty/query.rs

-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,6 @@ use crate::middle::codegen_fn_attrs::CodegenFnAttrs;
66
use crate::middle::exported_symbols::{ExportedSymbol, SymbolExportInfo};
77
use crate::middle::lib_features::LibFeatures;
88
use crate::middle::privacy::AccessLevels;
9-
use crate::middle::region;
109
use crate::middle::resolve_lifetime::{
1110
LifetimeScopeForPath, ObjectLifetimeDefault, Region, ResolveLifetimes,
1211
};
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
use crate::middle::region::{Scope, ScopeData, ScopeTree};
2+
use rustc_data_structures::fx::FxHashMap;
3+
use rustc_hir as hir;
4+
5+
/// `RvalueScopes` is a mapping from sub-expressions to _extended_ lifetime as determined by
6+
/// rules laid out in `rustc_typeck::check::rvalue_scopes`.
7+
#[derive(TyEncodable, TyDecodable, Clone, Debug, Default, Eq, PartialEq, HashStable)]
8+
pub struct RvalueScopes {
9+
map: FxHashMap<hir::ItemLocalId, Option<Scope>>,
10+
}
11+
12+
impl RvalueScopes {
13+
pub fn new() -> Self {
14+
Self { map: <_>::default() }
15+
}
16+
17+
/// Returns the scope when the temp created by `expr_id` will be cleaned up.
18+
pub fn temporary_scope(
19+
&self,
20+
region_scope_tree: &ScopeTree,
21+
expr_id: hir::ItemLocalId,
22+
) -> Option<Scope> {
23+
// Check for a designated rvalue scope.
24+
if let Some(&s) = self.map.get(&expr_id) {
25+
debug!("temporary_scope({expr_id:?}) = {s:?} [custom]");
26+
return s;
27+
}
28+
29+
// Otherwise, locate the innermost terminating scope
30+
// if there's one. Static items, for instance, won't
31+
// have an enclosing scope, hence no scope will be
32+
// returned.
33+
let mut id = Scope { id: expr_id, data: ScopeData::Node };
34+
35+
while let Some(&(p, _)) = region_scope_tree.parent_map.get(&id) {
36+
match p.data {
37+
ScopeData::Destruction => {
38+
debug!("temporary_scope({expr_id:?}) = {id:?} [enclosing]");
39+
return Some(id);
40+
}
41+
_ => id = p,
42+
}
43+
}
44+
45+
debug!("temporary_scope({expr_id:?}) = None");
46+
None
47+
}
48+
49+
/// Make an association between a sub-expression and an extended lifetime
50+
pub fn record_rvalue_scope(&mut self, var: hir::ItemLocalId, lifetime: Option<Scope>) {
51+
debug!("record_rvalue_scope(var={var:?}, lifetime={lifetime:?})");
52+
if let Some(lifetime) = lifetime {
53+
assert!(var != lifetime.item_local_id());
54+
}
55+
self.map.insert(var, lifetime);
56+
}
57+
}

compiler/rustc_mir_build/src/build/block.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -108,7 +108,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
108108
let_scope_stack.push(remainder_scope);
109109

110110
// Declare the bindings, which may create a source scope.
111-
let remainder_span = remainder_scope.span(this.tcx, this.region_scope_tree);
111+
let remainder_span =
112+
remainder_scope.span(this.tcx, &this.typeck_results.region_scope_tree);
112113

113114
let visibility_scope =
114115
Some(this.new_source_scope(remainder_span, LintLevel::Inherited, None));

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

+2-2
Original file line numberDiff line numberDiff line change
@@ -699,7 +699,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
699699
self.cfg.push(block, Statement { source_info, kind: StatementKind::StorageLive(local_id) });
700700
// Altough there is almost always scope for given variable in corner cases
701701
// like #92893 we might get variable with no scope.
702-
if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) && schedule_drop{
702+
if let Some(region_scope) = self.typeck_results.region_scope_tree.var_scope(var.local_id) && schedule_drop{
703703
self.schedule_drop(span, region_scope, local_id, DropKind::Storage);
704704
}
705705
Place::from(local_id)
@@ -712,7 +712,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
712712
for_guard: ForGuard,
713713
) {
714714
let local_id = self.var_local_id(var, for_guard);
715-
if let Some(region_scope) = self.region_scope_tree.var_scope(var.local_id) {
715+
if let Some(region_scope) = self.typeck_results.region_scope_tree.var_scope(var.local_id) {
716716
self.schedule_drop(span, region_scope, local_id, DropKind::Value);
717717
}
718718
}

compiler/rustc_mir_build/src/build/mod.rs

-2
Original file line numberDiff line numberDiff line change
@@ -398,7 +398,6 @@ struct Builder<'a, 'tcx> {
398398
tcx: TyCtxt<'tcx>,
399399
infcx: &'a InferCtxt<'a, 'tcx>,
400400
typeck_results: &'tcx TypeckResults<'tcx>,
401-
region_scope_tree: &'tcx region::ScopeTree,
402401
param_env: ty::ParamEnv<'tcx>,
403402

404403
thir: &'a Thir<'tcx>,
@@ -881,7 +880,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
881880
tcx,
882881
infcx,
883882
typeck_results: tcx.typeck_opt_const_arg(def),
884-
region_scope_tree: tcx.region_scope_tree(def.did),
885883
param_env,
886884
def_id: def.did.to_def_id(),
887885
hir_id,

compiler/rustc_mir_build/src/build/scope.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -916,7 +916,8 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
916916
}
917917

918918
if scope.region_scope == region_scope {
919-
let region_scope_span = region_scope.span(self.tcx, &self.region_scope_tree);
919+
let region_scope_span =
920+
region_scope.span(self.tcx, &self.typeck_results.region_scope_tree);
920921
// Attribute scope exit drops to scope's closing brace.
921922
let scope_end = self.tcx.sess.source_map().end_point(region_scope_span);
922923

0 commit comments

Comments
 (0)