Rollup merge of #144746 - petrochenkov:extpreltidy, r=b-naber

resolve: Cleanups and micro-optimizations to extern prelude

This is what can be done without changing the structure of `ExternPreludeEntry`, like in https://github.com/rust-lang/rust/pull/144737.

See individual commits for details.
This commit is contained in:
Stuart Cook 2025-08-04 11:24:39 +10:00 committed by GitHub
commit 2105044784
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 74 additions and 63 deletions

View File

@ -4519,6 +4519,7 @@ name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"bitflags",
"indexmap",
"itertools",
"pulldown-cmark",
"rustc_arena",

View File

@ -6,6 +6,7 @@ edition = "2024"
[dependencies]
# tidy-alphabetical-start
bitflags = "2.4.1"
indexmap = "2.4.0"
itertools = "0.12"
pulldown-cmark = { version = "0.11", features = ["html"], default-features = false }
rustc_arena = { path = "../rustc_arena" }

View File

@ -968,7 +968,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
self.r.potentially_unused_imports.push(import);
let imported_binding = self.r.import(binding, import);
if parent == self.r.graph_root {
if ident.name != kw::Underscore && parent == self.r.graph_root {
let ident = ident.normalize_to_macros_2_0();
if let Some(entry) = self.r.extern_prelude.get(&ident)
&& expansion != LocalExpnId::ROOT
@ -984,23 +984,29 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
// more details: https://github.com/rust-lang/rust/pull/111761
return;
}
let entry = self.r.extern_prelude.entry(ident).or_insert(ExternPreludeEntry {
binding: Cell::new(None),
introduced_by_item: true,
});
if orig_name.is_some() {
entry.introduced_by_item = true;
}
// Binding from `extern crate` item in source code can replace
// a binding from `--extern` on command line here.
if !entry.is_import() {
entry.binding.set(Some(imported_binding));
} else if ident.name != kw::Underscore {
self.r.dcx().span_delayed_bug(
item.span,
format!("it had been define the external module '{ident}' multiple times"),
);
}
use indexmap::map::Entry;
match self.r.extern_prelude.entry(ident) {
Entry::Occupied(mut occupied) => {
let entry = occupied.get_mut();
if let Some(old_binding) = entry.binding.get()
&& old_binding.is_import()
{
let msg = format!("extern crate `{ident}` already in extern prelude");
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
} else {
// Binding from `extern crate` item in source code can replace
// a binding from `--extern` on command line here.
entry.binding.set(Some(imported_binding));
entry.introduced_by_item = orig_name.is_some();
}
entry
}
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
binding: Cell::new(Some(imported_binding)),
introduced_by_item: true,
}),
};
}
self.r.define_binding_local(parent, ident, TypeNS, imported_binding);
}

View File

@ -1098,7 +1098,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(*ident, res))
}));
@ -1409,7 +1409,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
);
if lookup_ident.span.at_least_rust_2018() {
for ident in self.extern_prelude.clone().into_keys() {
for &ident in self.extern_prelude.keys() {
if ident.span.from_expansion() {
// Idents are adjusted to the root context before being
// resolved in the extern prelude, so reporting this to the

View File

@ -2476,19 +2476,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
} else {
// Items from the prelude
if !module.no_implicit_prelude {
let extern_prelude = self.r.extern_prelude.clone();
names.extend(extern_prelude.iter().flat_map(|(ident, _)| {
self.r
.cstore_mut()
.maybe_process_path_extern(self.r.tcx, ident.name)
.and_then(|crate_id| {
let crate_mod =
Res::Def(DefKind::Mod, crate_id.as_def_id());
filter_fn(crate_mod).then(|| {
TypoSuggestion::typo_from_ident(*ident, crate_mod)
})
})
names.extend(self.r.extern_prelude.keys().flat_map(|ident| {
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
filter_fn(res)
.then_some(TypoSuggestion::typo_from_ident(*ident, res))
}));
if let Some(prelude) = self.r.prelude {

View File

@ -1487,13 +1487,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let mut invocation_parents = FxHashMap::default();
invocation_parents.insert(LocalExpnId::ROOT, InvocationParent::ROOT);
let mut extern_prelude: FxIndexMap<Ident, ExternPreludeEntry<'_>> = tcx
let mut extern_prelude: FxIndexMap<_, _> = tcx
.sess
.opts
.externs
.iter()
.filter(|(_, entry)| entry.add_prelude)
.map(|(name, _)| (Ident::from_str(name), Default::default()))
.filter_map(|(name, entry)| {
// Make sure `self`, `super`, `_` etc do not get into extern prelude.
// FIXME: reject `--extern self` and similar in option parsing instead.
if entry.add_prelude
&& let name = Symbol::intern(name)
&& name.can_be_raw()
{
Some((Ident::with_dummy_span(name), Default::default()))
} else {
None
}
})
.collect();
if !attr::contains_name(attrs, sym::no_core) {
@ -2168,40 +2178,42 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
if ident.is_path_segment_keyword() {
// Make sure `self`, `super` etc produce an error when passed to here.
return None;
}
let norm_ident = ident.normalize_to_macros_2_0();
let binding = self.extern_prelude.get(&norm_ident).cloned().and_then(|entry| {
Some(if let Some(binding) = entry.binding.get() {
let mut record_use = None;
let entry = self.extern_prelude.get(&ident.normalize_to_macros_2_0());
let binding = entry.and_then(|entry| match entry.binding.get() {
Some(binding) if binding.is_import() => {
if finalize {
if !entry.is_import() {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
} else if entry.introduced_by_item {
self.record_use(ident, binding, Used::Other);
}
record_use = Some(binding);
}
binding
} else {
Some(binding)
}
Some(binding) => {
if finalize {
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span);
}
Some(binding)
}
None => {
let crate_id = if finalize {
let Some(crate_id) =
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
else {
return Some(self.dummy_binding);
};
crate_id
self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span)
} else {
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)?
self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name)
};
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT)
})
match crate_id {
Some(crate_id) => {
let res = Res::Def(DefKind::Mod, crate_id.as_def_id());
let binding =
self.arenas.new_pub_res_binding(res, DUMMY_SP, LocalExpnId::ROOT);
entry.binding.set(Some(binding));
Some(binding)
}
None => finalize.then_some(self.dummy_binding),
}
}
});
if let Some(entry) = self.extern_prelude.get(&norm_ident) {
entry.binding.set(binding);
if let Some(binding) = record_use {
self.record_use(ident, binding, Used::Scope);
}
binding