Skip to content

Commit a38f8fb

Browse files
committed
Auto merge of #78826 - petrochenkov:mrscopes2, r=eddyb
resolve: Collapse `macro_rules` scope chains on the fly Otherwise they grow too long and you have to endlessly walk through them when resolving macros or imports. Addresses https://rust-lang.zulipchat.com/#narrow/stream/247081-t-compiler.2Fperformance/topic/Slow.20Builtin.20Derives/near/215750815
2 parents f036a8f + 9221079 commit a38f8fb

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
@@ -675,7 +675,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
675675
// During late resolution we only track the module component of the parent scope,
676676
// although it may be useful to track other components as well for diagnostics.
677677
let graph_root = resolver.graph_root;
678-
let parent_scope = ParentScope::module(graph_root);
678+
let parent_scope = ParentScope::module(graph_root, resolver);
679679
let start_rib_kind = ModuleRibKind(graph_root);
680680
LateResolutionVisitor {
681681
r: resolver,

compiler/rustc_resolve/src/lib.rs

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

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

@@ -101,7 +101,7 @@ impl Determinacy {
101101
enum Scope<'a> {
102102
DeriveHelpers(ExpnId),
103103
DeriveHelpersCompat,
104-
MacroRules(MacroRulesScope<'a>),
104+
MacroRules(MacroRulesScopeRef<'a>),
105105
CrateRoot,
106106
Module(Module<'a>),
107107
RegisteredAttrs,
@@ -134,18 +134,18 @@ enum ScopeSet {
134134
pub struct ParentScope<'a> {
135135
module: Module<'a>,
136136
expansion: ExpnId,
137-
macro_rules: MacroRulesScope<'a>,
137+
macro_rules: MacroRulesScopeRef<'a>,
138138
derives: &'a [ast::Path],
139139
}
140140

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

@@ -1044,6 +1047,9 @@ impl<'a> ResolverArenas<'a> {
10441047
fn alloc_name_resolution(&'a self) -> &'a RefCell<NameResolution<'a>> {
10451048
self.name_resolutions.alloc(Default::default())
10461049
}
1050+
fn alloc_macro_rules_scope(&'a self, scope: MacroRulesScope<'a>) -> MacroRulesScopeRef<'a> {
1051+
PtrKey(self.dropless.alloc(Cell::new(scope)))
1052+
}
10471053
fn alloc_macro_rules_binding(
10481054
&'a self,
10491055
binding: MacroRulesBinding<'a>,
@@ -1231,14 +1237,11 @@ impl<'a> Resolver<'a> {
12311237
let (registered_attrs, registered_tools) =
12321238
macros::registered_attrs_and_tools(session, &krate.attrs);
12331239

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

1241-
Resolver {
1244+
let mut resolver = Resolver {
12421245
session,
12431246

12441247
definitions,
@@ -1305,8 +1308,9 @@ impl<'a> Resolver<'a> {
13051308
dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(session.edition())),
13061309
dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(session.edition())),
13071310
non_macro_attrs: [non_macro_attr(false), non_macro_attr(true)],
1308-
invocation_parent_scopes,
1311+
invocation_parent_scopes: Default::default(),
13091312
output_macro_rules_scopes: Default::default(),
1313+
invocation_macro_rules_scopes: Default::default(),
13101314
helper_attrs: Default::default(),
13111315
local_macro_def_scopes: FxHashMap::default(),
13121316
name_already_seen: FxHashMap::default(),
@@ -1333,7 +1337,12 @@ impl<'a> Resolver<'a> {
13331337
invocation_parents,
13341338
next_disambiguator: Default::default(),
13351339
trait_impl_items: Default::default(),
1336-
}
1340+
};
1341+
1342+
let root_parent_scope = ParentScope::module(graph_root, &resolver);
1343+
resolver.invocation_parent_scopes.insert(ExpnId::root(), root_parent_scope);
1344+
1345+
resolver
13371346
}
13381347

13391348
pub fn next_node_id(&mut self) -> NodeId {
@@ -1703,7 +1712,7 @@ impl<'a> Resolver<'a> {
17031712
}
17041713
Scope::DeriveHelpers(..) => Scope::DeriveHelpersCompat,
17051714
Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules),
1706-
Scope::MacroRules(macro_rules_scope) => match macro_rules_scope {
1715+
Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() {
17071716
MacroRulesScope::Binding(binding) => {
17081717
Scope::MacroRules(binding.parent_macro_rules_scope)
17091718
}
@@ -3200,7 +3209,7 @@ impl<'a> Resolver<'a> {
32003209
}
32013210
};
32023211
let module = self.get_module(module_id);
3203-
let parent_scope = &ParentScope::module(module);
3212+
let parent_scope = &ParentScope::module(module, self);
32043213
let res = self.resolve_ast_path(&path, ns, parent_scope).map_err(|_| ())?;
32053214
Ok((path, res))
32063215
}

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
@@ -352,7 +352,7 @@ impl<'a, 'tcx> LinkCollector<'a, 'tcx> {
352352
if let Ok((Some(ext), res)) = resolver.resolve_macro_path(
353353
&path,
354354
None,
355-
&ParentScope::module(resolver.graph_root()),
355+
&ParentScope::module(resolver.graph_root(), resolver),
356356
false,
357357
false,
358358
) {

0 commit comments

Comments
 (0)