Skip to content

Commit 457c443

Browse files
committed
Perf improvements
1 parent 1bcbe8c commit 457c443

4 files changed

Lines changed: 151 additions & 81 deletions

File tree

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 33 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -400,27 +400,32 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
400400
// Record primary definitions.
401401
let mut define_extern = |ns| {
402402
let orig_ident_span = orig_ident.span;
403-
let edition_redirects = edition_redirects
404-
.iter()
405-
.map(|redirect| crate::EditionRedirectDecl {
406-
before: redirect.before,
407-
// Model this as a one-step reexport under the original
408-
// child's name: the target supplies the resolution, while
409-
// the child supplies its visibility and provenance.
410-
target: self.arenas.alloc_decl(DeclData {
411-
kind: DeclKind::Def(redirect.target.expect_non_local()),
412-
ambiguity: CmCell::new(None),
413-
initial_vis: vis,
414-
ambiguity_vis_max: CmCell::new(None),
415-
ambiguity_vis_min: CmCell::new(None),
416-
span,
417-
expansion,
418-
parent_module: Some(parent.to_module()),
419-
edition_redirects: &[],
420-
}),
421-
})
422-
.collect::<SmallVec<[_; 1]>>();
423-
let edition_redirects = self.arenas.alloc_edition_redirects(&edition_redirects);
403+
let edition_redirects = if edition_redirects.is_empty() {
404+
// Fast path when there are no edition redirects.
405+
&[]
406+
} else {
407+
let edition_redirects = edition_redirects
408+
.iter()
409+
.map(|redirect| crate::EditionRedirectDecl {
410+
before: redirect.before,
411+
// Model this as a one-step reexport under the original
412+
// child's name: the target supplies the resolution, while
413+
// the child supplies its visibility and provenance.
414+
target: self.arenas.alloc_decl(DeclData {
415+
kind: DeclKind::Def(redirect.target.expect_non_local()),
416+
ambiguity: CmCell::new(None),
417+
initial_vis: vis,
418+
ambiguity_vis_max: CmCell::new(None),
419+
ambiguity_vis_min: CmCell::new(None),
420+
span,
421+
expansion,
422+
parent_module: Some(parent.to_module()),
423+
edition_redirects: &[],
424+
}),
425+
})
426+
.collect::<SmallVec<[_; 1]>>();
427+
self.arenas.alloc_edition_redirects(&edition_redirects)
428+
};
424429
let decl = self.arenas.alloc_decl(DeclData {
425430
kind: DeclKind::Def(res),
426431
ambiguity: CmCell::new(ambig),
@@ -1434,12 +1439,13 @@ impl<'a, 'ra, 'tcx> DefCollector<'a, 'ra, 'tcx> {
14341439
// The resolver runs before these attributes are available through HIR.
14351440
// Parse and retain them here, but leave their target paths unresolved
14361441
// until ordinary imports have settled.
1437-
if let Some(Attribute::Parsed(AttributeKind::RustcEditionRedirect(mut redirects))) =
1438-
AttributeParser::parse_limited_sym(
1439-
self.r.tcx.sess,
1440-
&item.attrs,
1441-
&[sym::rustc_edition_redirect],
1442-
)
1442+
if ast::attr::contains_name(&item.attrs, sym::rustc_edition_redirect)
1443+
&& let Some(Attribute::Parsed(AttributeKind::RustcEditionRedirect(mut redirects))) =
1444+
AttributeParser::parse_limited_sym(
1445+
self.r.tcx.sess,
1446+
&item.attrs,
1447+
&[sym::rustc_edition_redirect],
1448+
)
14431449
{
14441450
redirects.sort_by_key(|redirect| redirect.before);
14451451
let edition_redirects = redirects

compiler/rustc_resolve/src/ident.rs

Lines changed: 11 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -713,7 +713,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
713713
}
714714
}
715715
Scope::MacroUsePrelude => match self.macro_use_prelude.get(&ident.name).cloned() {
716-
Some(decl) => Ok(self.edition_adjusted_decl(decl, orig_ident_span.edition())),
716+
Some(decl) => Ok(self.edition_adjusted_decl(decl, orig_ident_span)),
717717
None => Err(Determinacy::determined(!self.graph_root.has_unexpanded_invocations())),
718718
},
719719
Scope::BuiltinAttrs => match self.builtin_attr_decls.get(&ident.name) {
@@ -1114,10 +1114,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
11141114
let resolution =
11151115
&*self.resolution(module.to_module(), key).ok_or(ControlFlow::Continue(Determined))?;
11161116

1117-
let binding = resolution
1118-
.non_glob_decl
1119-
.filter(|b| Some(*b) != ignore_decl)
1120-
.map(|binding| self.edition_adjusted_decl(binding, orig_ident_span.edition()));
1117+
let binding = resolution.non_glob_decl.filter(|b| Some(*b) != ignore_decl).map(|binding| {
1118+
// This check is redundant with the one inside
1119+
// edition_adjusted_decl, but this is a hot path and we want to
1120+
// avoid the call if it isn't necessary.
1121+
if !binding.edition_redirects.is_empty() {
1122+
self.edition_adjusted_decl(binding, orig_ident_span)
1123+
} else {
1124+
binding
1125+
}
1126+
});
11211127

11221128
if let Some(finalize) = finalize {
11231129
return self.get_mut().finalize_module_binding(

compiler/rustc_resolve/src/imports.rs

Lines changed: 100 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -467,7 +467,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
467467
// Without `edition_redirect`, the first import consumes the redirect
468468
// using that import's edition. The resulting binding is fixed for
469469
// downstream users.
470-
decl = self.edition_adjusted_decl(decl, import.span.edition());
470+
decl = self.edition_adjusted_decl(decl, import.span);
471471

472472
let vis = self.import_decl_vis(decl, import.summary());
473473

@@ -483,28 +483,33 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
483483
// each target in this import so a downstream edition adjustment retains
484484
// its visibility and re-export provenance. Other crates consume the
485485
// redirects above and produce re-exports with no redirects.
486-
let edition_redirects = if self.features.edition_redirect() {
487-
decl.edition_redirects
488-
.iter()
489-
.map(|redirect| crate::EditionRedirectDecl {
490-
before: redirect.before,
491-
target: self.arenas.alloc_decl(DeclData {
492-
kind: DeclKind::Import { source_decl: redirect.target, import },
493-
ambiguity: CmCell::new(None),
494-
span: import.span,
495-
initial_vis: vis.to_mod_id(),
496-
ambiguity_vis_max: CmCell::new(None),
497-
ambiguity_vis_min: CmCell::new(None),
498-
expansion: import.parent_scope.expansion,
499-
parent_module: Some(import.parent_scope.module),
500-
edition_redirects: &[],
501-
}),
502-
})
503-
.collect::<SmallVec<[_; 1]>>()
486+
let edition_redirects = if decl.edition_redirects.is_empty() {
487+
// Fast path when there are no edition redirects.
488+
&[]
504489
} else {
505-
SmallVec::new()
490+
let edition_redirects = if self.features.edition_redirect() {
491+
decl.edition_redirects
492+
.iter()
493+
.map(|redirect| crate::EditionRedirectDecl {
494+
before: redirect.before,
495+
target: self.arenas.alloc_decl(DeclData {
496+
kind: DeclKind::Import { source_decl: redirect.target, import },
497+
ambiguity: CmCell::new(None),
498+
span: import.span,
499+
initial_vis: vis.to_mod_id(),
500+
ambiguity_vis_max: CmCell::new(None),
501+
ambiguity_vis_min: CmCell::new(None),
502+
expansion: import.parent_scope.expansion,
503+
parent_module: Some(import.parent_scope.module),
504+
edition_redirects: &[],
505+
}),
506+
})
507+
.collect::<SmallVec<[_; 1]>>()
508+
} else {
509+
SmallVec::new()
510+
};
511+
self.arenas.alloc_edition_redirects(&edition_redirects)
506512
};
507-
let edition_redirects = self.arenas.alloc_edition_redirects(&edition_redirects);
508513

509514
self.arenas.alloc_decl(DeclData {
510515
kind: DeclKind::Import { source_decl: decl, import },
@@ -625,7 +630,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
625630
}
626631
glob_decl
627632
} else if glob_decl.res() != old_glob_decl.res()
628-
|| !Self::same_edition_redirects(old_glob_decl, glob_decl)
633+
|| (!(old_glob_decl.edition_redirects.is_empty()
634+
&& glob_decl.edition_redirects.is_empty())
635+
&& !Self::same_edition_redirects(old_glob_decl, glob_decl))
629636
{
630637
// Redirects are part of a binding's behavior. If two globs resolve
631638
// to the same item but redirect differently, retaining either
@@ -668,6 +675,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
668675
/// considered: they affect only the metadata produced for downstream
669676
/// crates, not local name resolution.
670677
fn same_edition_redirects(decl1: Decl<'ra>, decl2: Decl<'ra>) -> bool {
678+
// Fast path when there are no edition redirects.
679+
if decl1.edition_redirects.is_empty() && decl2.edition_redirects.is_empty() {
680+
return true;
681+
}
682+
671683
decl1.edition_redirects.len() == decl2.edition_redirects.len()
672684
&& decl1.edition_redirects.iter().zip(decl2.edition_redirects).all(
673685
|(redirect1, redirect2)| {
@@ -1860,8 +1872,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18601872
.iter()
18611873
.filter_map(|(key, resolution)| {
18621874
let res = resolution.borrow();
1863-
let decl =
1864-
self.edition_adjusted_decl(res.determined_decl()?, import.span.edition());
1875+
let decl = self.edition_adjusted_decl(res.determined_decl()?, import.span);
18651876
let mut key = *key;
18661877
let scope = match key.ident.ctxt.update_unchecked(|ctxt| {
18671878
ctxt.reverse_glob_adjust(module.expansion, import.span)
@@ -1960,30 +1971,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
19601971
}
19611972
}
19621973

1963-
/// Produces the sorted, metadata-ready edition redirects for `decl` in
1964-
/// `ns`.
1965-
///
1966-
/// Targets declared in the current crate are resolved here, after ordinary
1967-
/// imports have settled and once the namespace exported by the declaration
1968-
/// is known. Redirects on external declarations are already resolved in
1969-
/// crate metadata and are copied through unchanged.
1970-
fn resolved_edition_redirects(
1974+
/// Resolves local redirect targets after ordinary imports have settled and
1975+
/// once the namespace exported by `decl` is known.
1976+
fn resolve_local_edition_redirects(
19711977
&mut self,
19721978
ns: Namespace,
19731979
decl: Decl<'ra>,
1980+
redirects: Vec<crate::LocalEditionRedirect<'ra>>,
19741981
) -> SmallVec<[MetadataEditionRedirect; 1]> {
1975-
let Some(redirects) = self.local_edition_redirects(decl) else {
1976-
// External declarations already carry resolved redirect targets
1977-
// from crate metadata.
1978-
return decl
1979-
.edition_redirects
1980-
.iter()
1981-
.map(|redirect| MetadataEditionRedirect {
1982-
before: redirect.before,
1983-
target: redirect.target.res().expect_non_local(),
1984-
})
1985-
.collect();
1986-
};
19871982
redirects
19881983
.into_iter()
19891984
.filter_map(|redirect| {
@@ -2080,9 +2075,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20802075

20812076
let Some(def_id) = module.opt_def_id() else { return };
20822077

2078+
enum EditionRedirectSlot {
2079+
Child(usize),
2080+
AmbiguousMain(usize),
2081+
AmbiguousSecond(usize),
2082+
}
2083+
20832084
let mut children = Vec::new();
20842085
let mut ambig_children = Vec::new();
2085-
module.to_module().for_each_child_mut(self, |this, ident, orig_ident_span, ns, decl| {
2086+
let mut pending_edition_redirects = Vec::new();
2087+
module.to_module().for_each_child(self, |this, ident, orig_ident_span, ns, decl| {
20862088
let res = decl.res().expect_non_local();
20872089
if res != def::Res::Err {
20882090
let vis = if this.rust_embed_hack(module, decl) {
@@ -2091,34 +2093,84 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20912093
decl.vis()
20922094
};
20932095
let ident = ident.orig(orig_ident_span);
2096+
let mut edition_redirects = |decl, child| {
2097+
// Local redirect targets must be resolved after
2098+
// `for_each_child` releases its borrow. Otherwise copy any
2099+
// already-resolved redirects decoded from external crate
2100+
// metadata.
2101+
if !this.local_edition_redirects.is_empty()
2102+
&& let Some(redirects) = this.local_edition_redirects(decl)
2103+
{
2104+
pending_edition_redirects.push((child, ns, decl, redirects));
2105+
SmallVec::new()
2106+
} else if decl.edition_redirects.is_empty() {
2107+
SmallVec::new()
2108+
} else {
2109+
decl.edition_redirects
2110+
.iter()
2111+
.map(|redirect| MetadataEditionRedirect {
2112+
before: redirect.before,
2113+
target: redirect.target.res().expect_non_local(),
2114+
})
2115+
.collect()
2116+
}
2117+
};
20942118
if let Some((ambig_binding1, ambig_binding2)) = decl.descent_to_ambiguity() {
2119+
let index = ambig_children.len();
20952120
let main = ModChild {
20962121
ident,
20972122
res,
20982123
vis,
20992124
reexport_chain: ambig_binding1.reexport_chain(),
2100-
edition_redirects: this.resolved_edition_redirects(ns, ambig_binding1),
2125+
edition_redirects: edition_redirects(
2126+
ambig_binding1,
2127+
EditionRedirectSlot::AmbiguousMain(index),
2128+
),
21012129
};
21022130
let second = ModChild {
21032131
ident,
21042132
res: ambig_binding2.res().expect_non_local(),
21052133
vis: ambig_binding2.vis(),
21062134
reexport_chain: ambig_binding2.reexport_chain(),
2107-
edition_redirects: this.resolved_edition_redirects(ns, ambig_binding2),
2135+
edition_redirects: edition_redirects(
2136+
ambig_binding2,
2137+
EditionRedirectSlot::AmbiguousSecond(index),
2138+
),
21082139
};
21092140
ambig_children.push(AmbigModChild { main, second })
21102141
} else {
2142+
let index = children.len();
21112143
children.push(ModChild {
21122144
ident,
21132145
res,
21142146
vis,
21152147
reexport_chain: decl.reexport_chain(),
2116-
edition_redirects: this.resolved_edition_redirects(ns, decl),
2148+
edition_redirects: edition_redirects(
2149+
decl,
2150+
EditionRedirectSlot::Child(index),
2151+
),
21172152
});
21182153
}
21192154
}
21202155
});
21212156

2157+
// Resolving a target can record import uses and diagnostics, so wait
2158+
// until `for_each_child` releases its borrow of the module resolutions.
2159+
for (child, ns, decl, redirects) in pending_edition_redirects {
2160+
let redirects = self.resolve_local_edition_redirects(ns, decl, redirects);
2161+
match child {
2162+
EditionRedirectSlot::Child(index) => {
2163+
children[index].edition_redirects = redirects;
2164+
}
2165+
EditionRedirectSlot::AmbiguousMain(index) => {
2166+
ambig_children[index].main.edition_redirects = redirects;
2167+
}
2168+
EditionRedirectSlot::AmbiguousSecond(index) => {
2169+
ambig_children[index].second.edition_redirects = redirects;
2170+
}
2171+
}
2172+
}
2173+
21222174
if !children.is_empty() {
21232175
module_children.insert(def_id.expect_local(), children);
21242176
}

compiler/rustc_resolve/src/lib.rs

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2063,7 +2063,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20632063
f(self, MacroNS);
20642064
}
20652065

2066-
fn edition_adjusted_decl(&self, decl: Decl<'ra>, edition: Edition) -> Decl<'ra> {
2066+
fn edition_adjusted_decl(&self, decl: Decl<'ra>, span: Span) -> Decl<'ra> {
2067+
// Nothing to do if the decl has no redirects.
2068+
if decl.edition_redirects.is_empty() {
2069+
return decl;
2070+
}
2071+
20672072
// Crates with `edition_redirect` resolve canonical bindings so
20682073
// redirects can be preserved through their re-exports. Other crates
20692074
// select using the use-site edition.
@@ -2079,6 +2084,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
20792084
return decl;
20802085
}
20812086

2087+
let edition = span.edition();
20822088
decl.edition_redirects
20832089
.iter()
20842090
.find(|redirect| edition < redirect.before)

0 commit comments

Comments
 (0)