Skip to content

Commit f7a4c9d

Browse files
committed
rustc: collect upvars from HIR, instead of during name resolution.
1 parent 648b4d8 commit f7a4c9d

File tree

12 files changed

+143
-97
lines changed

12 files changed

+143
-97
lines changed

src/librustc/arena.rs

+1
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ macro_rules! arena_types {
109109
>,
110110
[few] crate_variances: rustc::ty::CrateVariancesMap<'tcx>,
111111
[few] inferred_outlives_crate: rustc::ty::CratePredicatesMap<'tcx>,
112+
[] upvars: rustc_data_structures::fx::FxIndexMap<rustc::hir::HirId, rustc::hir::Upvar>,
112113
], $tcx);
113114
)
114115
}

src/librustc/hir/map/mod.rs

+10-8
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ use crate::util::common::time;
2626

2727
use std::io;
2828
use std::result::Result::Err;
29-
use crate::ty::TyCtxt;
29+
use crate::ty::query::Providers;
3030

3131
pub mod blocks;
3232
mod collector;
@@ -1450,11 +1450,13 @@ fn hir_id_to_string(map: &Map<'_>, id: HirId, include_id: bool) -> String {
14501450
}
14511451
}
14521452

1453-
pub fn def_kind(tcx: TyCtxt<'_, '_, '_>, def_id: DefId) -> Option<DefKind> {
1454-
if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
1455-
tcx.hir().def_kind(node_id)
1456-
} else {
1457-
bug!("Calling local def_kind query provider for upstream DefId: {:?}",
1458-
def_id)
1459-
}
1453+
pub fn provide(providers: &mut Providers<'_>) {
1454+
providers.def_kind = |tcx, def_id| {
1455+
if let Some(node_id) = tcx.hir().as_local_node_id(def_id) {
1456+
tcx.hir().def_kind(node_id)
1457+
} else {
1458+
bug!("Calling local def_kind query provider for upstream DefId: {:?}",
1459+
def_id)
1460+
}
1461+
};
14601462
}

src/librustc/hir/mod.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -30,7 +30,6 @@ use syntax::util::parser::ExprPrecedence;
3030
use crate::ty::AdtKind;
3131
use crate::ty::query::Providers;
3232

33-
use rustc_data_structures::fx::FxIndexMap;
3433
use rustc_data_structures::sync::{par_for_each_in, Send, Sync};
3534
use rustc_data_structures::thin_vec::ThinVec;
3635
use rustc_macros::HashStable;
@@ -64,6 +63,7 @@ pub mod lowering;
6463
pub mod map;
6564
pub mod pat_util;
6665
pub mod print;
66+
pub mod upvars;
6767

6868
/// Uniquely identifies a node in the HIR of the current crate. It is
6969
/// composed of the `owner`, which is the `DefIndex` of the directly enclosing
@@ -2498,8 +2498,6 @@ pub struct Upvar {
24982498
pub span: Span
24992499
}
25002500

2501-
pub type UpvarMap = NodeMap<FxIndexMap<ast::NodeId, Upvar>>;
2502-
25032501
pub type CaptureModeMap = NodeMap<CaptureClause>;
25042502

25052503
// The TraitCandidate's import_ids is empty if the trait is defined in the same module, and
@@ -2518,10 +2516,10 @@ pub type TraitMap = NodeMap<Vec<TraitCandidate>>;
25182516
// imported.
25192517
pub type GlobMap = NodeMap<FxHashSet<Name>>;
25202518

2521-
25222519
pub fn provide(providers: &mut Providers<'_>) {
25232520
check_attr::provide(providers);
2524-
providers.def_kind = map::def_kind;
2521+
map::provide(providers);
2522+
upvars::provide(providers);
25252523
}
25262524

25272525
#[derive(Clone, RustcEncodable, RustcDecodable, HashStable)]

src/librustc/hir/upvars.rs

+104
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,104 @@
1+
//! Upvar (closure capture) collection from cross-body HIR uses of `Res::Local`s.
2+
3+
use crate::hir::{self, HirId};
4+
use crate::hir::def::Res;
5+
use crate::hir::intravisit::{self, Visitor, NestedVisitorMap};
6+
use crate::ty::TyCtxt;
7+
use crate::ty::query::Providers;
8+
use syntax_pos::Span;
9+
use rustc_data_structures::fx::{FxIndexMap, FxHashSet};
10+
11+
pub fn provide(providers: &mut Providers<'_>) {
12+
providers.upvars = |tcx, def_id| {
13+
if !tcx.is_closure(def_id) {
14+
return None;
15+
}
16+
17+
let node_id = tcx.hir().as_local_node_id(def_id).unwrap();
18+
let body = tcx.hir().body(tcx.hir().maybe_body_owned_by(node_id)?);
19+
20+
let mut local_collector = LocalCollector::default();
21+
local_collector.visit_body(body);
22+
23+
let mut capture_collector = CaptureCollector {
24+
tcx,
25+
locals: &local_collector.locals,
26+
upvars: FxIndexMap::default(),
27+
};
28+
capture_collector.visit_body(body);
29+
30+
if !capture_collector.upvars.is_empty() {
31+
Some(tcx.arena.alloc(capture_collector.upvars))
32+
} else {
33+
None
34+
}
35+
};
36+
}
37+
38+
#[derive(Default)]
39+
struct LocalCollector {
40+
// FIXME(eddyb) perhaps use `ItemLocalId` instead?
41+
locals: FxHashSet<HirId>,
42+
}
43+
44+
impl Visitor<'tcx> for LocalCollector {
45+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
46+
NestedVisitorMap::None
47+
}
48+
49+
fn visit_pat(&mut self, pat: &'tcx hir::Pat) {
50+
if let hir::PatKind::Binding(_, hir_id, ..) = pat.node {
51+
self.locals.insert(hir_id);
52+
}
53+
intravisit::walk_pat(self, pat);
54+
}
55+
}
56+
57+
struct CaptureCollector<'a, 'tcx> {
58+
tcx: TyCtxt<'a, 'tcx, 'tcx>,
59+
locals: &'a FxHashSet<HirId>,
60+
upvars: FxIndexMap<HirId, hir::Upvar>,
61+
}
62+
63+
impl CaptureCollector<'_, '_> {
64+
fn visit_local_use(&mut self, var_id: HirId, span: Span) {
65+
if !self.locals.contains(&var_id) {
66+
self.upvars.entry(var_id).or_insert(hir::Upvar { span });
67+
}
68+
}
69+
}
70+
71+
impl Visitor<'tcx> for CaptureCollector<'a, 'tcx> {
72+
fn nested_visit_map<'this>(&'this mut self) -> NestedVisitorMap<'this, 'tcx> {
73+
NestedVisitorMap::None
74+
}
75+
76+
fn visit_path(&mut self, path: &'tcx hir::Path, _: hir::HirId) {
77+
if let Res::Local(var_id) = path.res {
78+
self.visit_local_use(var_id, path.span);
79+
}
80+
81+
intravisit::walk_path(self, path);
82+
}
83+
84+
fn visit_expr(&mut self, expr: &'tcx hir::Expr) {
85+
if let hir::ExprKind::Closure(..) = expr.node {
86+
let closure_def_id = self.tcx.hir().local_def_id_from_hir_id(expr.hir_id);
87+
if let Some(upvars) = self.tcx.upvars(closure_def_id) {
88+
// Every capture of a closure expression is a local in scope,
89+
// that is moved/copied/borrowed into the closure value, and
90+
// for this analysis they are like any other access to a local.
91+
//
92+
// E.g. in `|b| |c| (a, b, c)`, the upvars of the inner closure
93+
// are `a` and `b`, and while `a` is not directly used in the
94+
// outer closure, it needs to be an upvar there too, so that
95+
// the inner closure can take it (from the outer closure's env).
96+
for (&var_id, upvar) in upvars {
97+
self.visit_local_use(var_id, upvar.span);
98+
}
99+
}
100+
}
101+
102+
intravisit::walk_expr(self, expr);
103+
}
104+
}

src/librustc/ty/context.rs

-13
Original file line numberDiff line numberDiff line change
@@ -54,7 +54,6 @@ use rustc_data_structures::stable_hasher::{HashStable, hash_stable_hashmap,
5454
StableHasher, StableHasherResult,
5555
StableVec};
5656
use arena::SyncDroplessArena;
57-
use rustc_data_structures::fx::FxIndexMap;
5857
use rustc_data_structures::indexed_vec::{Idx, IndexVec};
5958
use rustc_data_structures::sync::{Lrc, Lock, WorkerLocal};
6059
use std::any::Any;
@@ -1063,11 +1062,6 @@ pub struct GlobalCtxt<'tcx> {
10631062

10641063
pub queries: query::Queries<'tcx>,
10651064

1066-
// Records the captured variables referenced by every closure
1067-
// expression. Do not track deps for this, just recompute it from
1068-
// scratch every time.
1069-
upvars: FxHashMap<DefId, FxIndexMap<hir::HirId, hir::Upvar>>,
1070-
10711065
maybe_unused_trait_imports: FxHashSet<DefId>,
10721066
maybe_unused_extern_crates: Vec<(DefId, Span)>,
10731067
/// A map of glob use to a set of names it actually imports. Currently only
@@ -1298,12 +1292,6 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
12981292
}).collect();
12991293
(k, exports)
13001294
}).collect(),
1301-
upvars: resolutions.upvars.into_iter().map(|(k, upvars)| {
1302-
let upvars: FxIndexMap<_, _> = upvars.into_iter().map(|(var_id, upvar)| {
1303-
(hir.node_to_hir_id(var_id), upvar)
1304-
}).collect();
1305-
(hir.local_def_id(k), upvars)
1306-
}).collect(),
13071295
maybe_unused_trait_imports:
13081296
resolutions.maybe_unused_trait_imports
13091297
.into_iter()
@@ -3024,7 +3012,6 @@ pub fn provide(providers: &mut ty::query::Providers<'_>) {
30243012
assert_eq!(id, LOCAL_CRATE);
30253013
tcx.arena.alloc(middle::lang_items::collect(tcx))
30263014
};
3027-
providers.upvars = |tcx, id| tcx.gcx.upvars.get(&id);
30283015
providers.maybe_unused_trait_import = |tcx, id| {
30293016
tcx.maybe_unused_trait_imports.contains(&id)
30303017
};

src/librustc/ty/mod.rs

+1-2
Original file line numberDiff line numberDiff line change
@@ -8,7 +8,7 @@ pub use self::BorrowKind::*;
88
pub use self::IntVarValue::*;
99
pub use self::fold::TypeFoldable;
1010

11-
use crate::hir::{map as hir_map, UpvarMap, GlobMap, TraitMap};
11+
use crate::hir::{map as hir_map, GlobMap, TraitMap};
1212
use crate::hir::Node;
1313
use crate::hir::def::{Res, DefKind, CtorOf, CtorKind, ExportMap};
1414
use crate::hir::def_id::{CrateNum, DefId, LocalDefId, CRATE_DEF_INDEX, LOCAL_CRATE};
@@ -123,7 +123,6 @@ mod sty;
123123

124124
#[derive(Clone)]
125125
pub struct Resolutions {
126-
pub upvars: UpvarMap,
127126
pub trait_map: TraitMap,
128127
pub maybe_unused_trait_imports: NodeSet,
129128
pub maybe_unused_extern_crates: Vec<(NodeId, Span)>,

src/librustc_interface/passes.rs

-2
Original file line numberDiff line numberDiff line change
@@ -178,7 +178,6 @@ impl ExpansionResult {
178178
ExpansionResult {
179179
defs: Steal::new(resolver.definitions),
180180
resolutions: Steal::new(Resolutions {
181-
upvars: resolver.upvars,
182181
export_map: resolver.export_map,
183182
trait_map: resolver.trait_map,
184183
glob_map: resolver.glob_map,
@@ -197,7 +196,6 @@ impl ExpansionResult {
197196
ExpansionResult {
198197
defs: Steal::new(resolver.definitions.clone()),
199198
resolutions: Steal::new(Resolutions {
200-
upvars: resolver.upvars.clone(),
201199
export_map: resolver.export_map.clone(),
202200
trait_map: resolver.trait_map.clone(),
203201
glob_map: resolver.glob_map.clone(),

0 commit comments

Comments
 (0)