Skip to content

Commit 9221079

Browse files
committed
resolve: Collapse macro_rules scope chains on the fly
1 parent a601302 commit 9221079

File tree

6 files changed

+70
-30
lines changed

6 files changed

+70
-30
lines changed

compiler/rustc_resolve/src/build_reduced_graph.rs

+16-11
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
88
use crate::def_collector::collect_definitions;
99
use crate::imports::{Import, ImportKind};
10-
use crate::macros::{MacroRulesBinding, MacroRulesScope};
10+
use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
1111
use crate::Namespace::{self, MacroNS, TypeNS, ValueNS};
1212
use crate::{CrateLint, Determinacy, PathResult, ResolutionError, VisResolutionError};
1313
use crate::{
@@ -209,7 +209,7 @@ impl<'a> Resolver<'a> {
209209
&mut self,
210210
fragment: &AstFragment,
211211
parent_scope: ParentScope<'a>,
212-
) -> MacroRulesScope<'a> {
212+
) -> MacroRulesScopeRef<'a> {
213213
collect_definitions(self, fragment, parent_scope.expansion);
214214
let mut visitor = BuildReducedGraphVisitor { r: self, parent_scope };
215215
fragment.visit_with(&mut visitor);
@@ -220,7 +220,8 @@ impl<'a> Resolver<'a> {
220220
let def_id = module.def_id().expect("unpopulated module without a def-id");
221221
for child in self.cstore().item_children_untracked(def_id, self.session) {
222222
let child = child.map_id(|_| panic!("unexpected id"));
223-
BuildReducedGraphVisitor { r: self, parent_scope: ParentScope::module(module) }
223+
let parent_scope = ParentScope::module(module, self);
224+
BuildReducedGraphVisitor { r: self, parent_scope }
224225
.build_reduced_graph_for_external_crate_res(child);
225226
}
226227
}
@@ -1154,15 +1155,17 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
11541155
false
11551156
}
11561157

1157-
fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScope<'a> {
1158+
fn visit_invoc(&mut self, id: NodeId) -> MacroRulesScopeRef<'a> {
11581159
let invoc_id = id.placeholder_to_expn_id();
11591160

11601161
self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
11611162

11621163
let old_parent_scope = self.r.invocation_parent_scopes.insert(invoc_id, self.parent_scope);
11631164
assert!(old_parent_scope.is_none(), "invocation data is reset for an invocation");
11641165

1165-
MacroRulesScope::Invocation(invoc_id)
1166+
let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id));
1167+
self.r.invocation_macro_rules_scopes.entry(invoc_id).or_default().insert(scope);
1168+
scope
11661169
}
11671170

11681171
fn proc_macro_stub(&self, item: &ast::Item) -> Option<(MacroKind, Ident, Span)> {
@@ -1196,7 +1199,7 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
11961199
}
11971200
}
11981201

1199-
fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScope<'a> {
1202+
fn define_macro(&mut self, item: &ast::Item) -> MacroRulesScopeRef<'a> {
12001203
let parent_scope = self.parent_scope;
12011204
let expansion = parent_scope.expansion;
12021205
let def_id = self.r.local_def_id(item.id);
@@ -1239,11 +1242,13 @@ impl<'a, 'b> BuildReducedGraphVisitor<'a, 'b> {
12391242
self.insert_unused_macro(ident, def_id, item.id, span);
12401243
}
12411244
self.r.visibilities.insert(def_id, vis);
1242-
MacroRulesScope::Binding(self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding {
1243-
parent_macro_rules_scope: parent_scope.macro_rules,
1244-
binding,
1245-
ident,
1246-
}))
1245+
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding(
1246+
self.r.arenas.alloc_macro_rules_binding(MacroRulesBinding {
1247+
parent_macro_rules_scope: parent_scope.macro_rules,
1248+
binding,
1249+
ident,
1250+
}),
1251+
))
12471252
} else {
12481253
let module = parent_scope.module;
12491254
let vis = match item.kind {

compiler/rustc_resolve/src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -630,7 +630,7 @@ impl<'a> Resolver<'a> {
630630
}
631631
}
632632
Scope::MacroRules(macro_rules_scope) => {
633-
if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope {
633+
if let MacroRulesScope::Binding(macro_rules_binding) = macro_rules_scope.get() {
634634
let res = macro_rules_binding.binding.res();
635635
if filter_fn(res) {
636636
suggestions

compiler/rustc_resolve/src/late.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -677,7 +677,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
677677
// During late resolution we only track the module component of the parent scope,
678678
// although it may be useful to track other components as well for diagnostics.
679679
let graph_root = resolver.graph_root;
680-
let parent_scope = ParentScope::module(graph_root);
680+
let parent_scope = ParentScope::module(graph_root, resolver);
681681
let start_rib_kind = ModuleRibKind(graph_root);
682682
LateResolutionVisitor {
683683
r: resolver,

compiler/rustc_resolve/src/lib.rs

+23-14
Original file line numberDiff line numberDiff line change
@@ -64,7 +64,7 @@ use diagnostics::{extend_span_to_previous_binding, find_span_of_binding_until_ne
6464
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
6565
use imports::{Import, ImportKind, ImportResolver, NameResolution};
6666
use late::{HasGenericParams, PathSource, Rib, RibKind::*};
67-
use macros::{MacroRulesBinding, MacroRulesScope};
67+
use macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
6868

6969
type Res = def::Res<NodeId>;
7070

@@ -100,7 +100,7 @@ impl Determinacy {
100100
enum Scope<'a> {
101101
DeriveHelpers(ExpnId),
102102
DeriveHelpersCompat,
103-
MacroRules(MacroRulesScope<'a>),
103+
MacroRules(MacroRulesScopeRef<'a>),
104104
CrateRoot,
105105
Module(Module<'a>),
106106
RegisteredAttrs,
@@ -133,18 +133,18 @@ enum ScopeSet {
133133
pub struct ParentScope<'a> {
134134
module: Module<'a>,
135135
expansion: ExpnId,
136-
macro_rules: MacroRulesScope<'a>,
136+
macro_rules: MacroRulesScopeRef<'a>,
137137
derives: &'a [ast::Path],
138138
}
139139

140140
impl<'a> ParentScope<'a> {
141141
/// Creates a parent scope with the passed argument used as the module scope component,
142142
/// and other scope components set to default empty values.
143-
pub fn module(module: Module<'a>) -> ParentScope<'a> {
143+
pub fn module(module: Module<'a>, resolver: &Resolver<'a>) -> ParentScope<'a> {
144144
ParentScope {
145145
module,
146146
expansion: ExpnId::root(),
147-
macro_rules: MacroRulesScope::Empty,
147+
macro_rules: resolver.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty),
148148
derives: &[],
149149
}
150150
}
@@ -974,7 +974,10 @@ pub struct Resolver<'a> {
974974
invocation_parent_scopes: FxHashMap<ExpnId, ParentScope<'a>>,
975975
/// `macro_rules` scopes *produced* by expanding the macro invocations,
976976
/// include all the `macro_rules` items and other invocations generated by them.
977-
output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScope<'a>>,
977+
output_macro_rules_scopes: FxHashMap<ExpnId, MacroRulesScopeRef<'a>>,
978+
/// References to all `MacroRulesScope::Invocation(invoc_id)`s, used to update such scopes
979+
/// when their corresponding `invoc_id`s get expanded.
980+
invocation_macro_rules_scopes: FxHashMap<ExpnId, FxHashSet<MacroRulesScopeRef<'a>>>,
978981
/// Helper attributes that are in scope for the given expansion.
979982
helper_attrs: FxHashMap<ExpnId, Vec<Ident>>,
980983

@@ -1043,6 +1046,9 @@ impl<'a> ResolverArenas<'a> {
10431046
fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
10441047
self.name_resolutions.alloc(Default::default())
10451048
}
1049+
fn alloc_macro_rules_scope(&'a self, scope: MacroRulesScope<'a>) -> MacroRulesScopeRef<'a> {
1050+
PtrKey(self.dropless.alloc(Cell::new(scope)))
1051+
}
10461052
fn alloc_macro_rules_binding(
10471053
&'a self,
10481054
binding: MacroRulesBinding<'a>,
@@ -1230,14 +1236,11 @@ impl<'a> Resolver<'a> {
12301236
let (registered_attrs, registered_tools) =
12311237
macros::registered_attrs_and_tools(session, &krate.attrs);
12321238

1233-
let mut invocation_parent_scopes = FxHashMap::default();
1234-
invocation_parent_scopes.insert(ExpnId::root(), ParentScope::module(graph_root));
1235-
12361239
let features = session.features_untracked();
12371240
let non_macro_attr =
12381241
|mark_used| Lrc::new(SyntaxExtension::non_macro_attr(mark_used, session.edition()));
12391242

1240-
Resolver {
1243+
let mut resolver = Resolver {
12411244
session,
12421245

12431246
definitions,
@@ -1304,8 +1307,9 @@ impl<'a> Resolver<'a> {
13041307
dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
13051308
dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
13061309
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
1307-
invocation_parent_scopes,
1310+
invocation_parent_scopes: Default::default(),
13081311
output_macro_rules_scopes: Default::default(),
1312+
invocation_macro_rules_scopes: Default::default(),
13091313
helper_attrs: Default::default(),
13101314
local_macro_def_scopes: FxHashMap::default(),
13111315
name_already_seen: FxHashMap::default(),
@@ -1332,7 +1336,12 @@ impl<'a> Resolver<'a> {
13321336
invocation_parents,
13331337
next_disambiguator: Default::default(),
13341338
trait_impl_items: Default::default(),
1335-
}
1339+
};
1340+
1341+
let root_parent_scope = ParentScope::module(graph_root, &resolver);
1342+
resolver.invocation_parent_scopes.insert(ExpnId::root(), root_parent_scope);
1343+
1344+
resolver
13361345
}
13371346

13381347
pub fn next_node_id(&mut self) -> NodeId {
@@ -1702,7 +1711,7 @@ impl<'a> Resolver<'a> {
17021711
}
17031712
Scope::DeriveHelpers(..) => Scope::DeriveHelpersCompat,
17041713
Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules),
1705-
Scope::MacroRules(macro_rules_scope) => match macro_rules_scope {
1714+
Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
17061715
MacroRulesScope::Binding(binding) => {
17071716
Scope::MacroRules(binding.parent_macro_rules_scope)
17081717
}
@@ -3199,7 +3208,7 @@ impl<'a> Resolver<'a> {
31993208
}
32003209
};
32013210
let module = self.get_module(module_id);
3202-
let parent_scope = &ParentScope::module(module);
3211+
let parent_scope = &ParentScope::module(module, self);
32033212
let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
32043213
Ok((path, res))
32053214
}

compiler/rustc_resolve/src/macros.rs

+28-2
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ use rustc_ast_lowering::ResolverAstLowering;
1111
use rustc_ast_pretty::pprust;
1212
use rustc_attr::StabilityLevel;
1313
use rustc_data_structures::fx::FxHashSet;
14+
use rustc_data_structures::ptr_key::PtrKey;
1415
use rustc_errors::struct_span_err;
1516
use rustc_expand::base::{Indeterminate, InvocationRes, ResolverExpand, SyntaxExtension};
1617
use rustc_expand::compile_declarative_macro;
@@ -29,6 +30,7 @@ use rustc_span::{Span, DUMMY_SP};
2930

3031
use rustc_data_structures::sync::Lrc;
3132
use rustc_span::hygiene::{AstPass, MacroKind};
33+
use std::cell::Cell;
3234
use std::{mem, ptr};
3335

3436
type Res = def::Res<NodeId>;
@@ -39,7 +41,7 @@ type Res = def::Res<NodeId>;
3941
pub struct MacroRulesBinding<'a> {
4042
crate binding: &'a NameBinding<'a>,
4143
/// `macro_rules` scope into which the `macro_rules` item was planted.
42-
crate parent_macro_rules_scope: MacroRulesScope<'a>,
44+
crate parent_macro_rules_scope: MacroRulesScopeRef<'a>,
4345
crate ident: Ident,
4446
}
4547

@@ -59,6 +61,14 @@ pub enum MacroRulesScope<'a> {
5961
Invocation(ExpnId),
6062
}
6163

64+
/// `macro_rules!` scopes are always kept by reference and inside a cell.
65+
/// The reason is that we update all scopes with value `MacroRulesScope::Invocation(invoc_id)`
66+
/// in-place immediately after `invoc_id` gets expanded.
67+
/// This helps to avoid uncontrollable growth of `macro_rules!` scope chains,
68+
/// which usually grow lineraly with the number of macro invocations
69+
/// in a module (including derives) and hurt performance.
70+
pub(crate) type MacroRulesScopeRef<'a> = PtrKey<'a, Cell<MacroRulesScope<'a>>>;
71+
6272
// Macro namespace is separated into two sub-namespaces, one for bang macros and
6373
// one for attribute-like macros (attributes, derives).
6474
// We ignore resolutions from one sub-namespace when searching names in scope for another.
@@ -163,6 +173,22 @@ impl<'a> ResolverExpand for Resolver<'a> {
163173
let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope);
164174
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
165175

176+
// Update all `macro_rules` scopes referring to this invocation. This is an optimization
177+
// used to avoid long scope chains, see the comments on `MacroRulesScopeRef`.
178+
if let Some(invocation_scopes) = self.invocation_macro_rules_scopes.remove(&expansion) {
179+
for invocation_scope in &invocation_scopes {
180+
invocation_scope.set(output_macro_rules_scope.get());
181+
}
182+
// All `macro_rules` scopes that previously referred to `expansion`
183+
// are now rerouted to its output scope, if it's also an invocation.
184+
if let MacroRulesScope::Invocation(invoc_id) = output_macro_rules_scope.get() {
185+
self.invocation_macro_rules_scopes
186+
.entry(invoc_id)
187+
.or_default()
188+
.extend(invocation_scopes);
189+
}
190+
}
191+
166192
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
167193
}
168194

@@ -655,7 +681,7 @@ impl<'a> Resolver<'a> {
655681
}
656682
result
657683
}
658-
Scope::MacroRules(macro_rules_scope) => match macro_rules_scope {
684+
Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
659685
MacroRulesScope::Binding(macro_rules_binding)
660686
if ident == macro_rules_binding.ident =>
661687
{

src/librustdoc/passes/collect_intra_doc_links.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -297,7 +297,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
297297
if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
298298
&path,
299299
None,
300-
&ParentScope::module(resolver.graph_root()),
300+
&ParentScope::module(resolver.graph_root(), resolver),
301301
false,
302302
false,
303303
) {

0 commit comments

Comments
 (0)