Skip to content

resolve: Split extern prelude into two scopes #144793

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 6 commits into
base: master
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions Cargo.lock
Original file line number Diff line number Diff line change
Expand Up @@ -4519,6 +4519,7 @@ name = "rustc_resolve"
version = "0.0.0"
dependencies = [
"bitflags",
"indexmap",
"itertools",
"pulldown-cmark",
"rustc_arena",
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_resolve/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -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" }
Expand Down
49 changes: 25 additions & 24 deletions compiler/rustc_resolve/src/build_reduced_graph.rs
Original file line number Diff line number Diff line change
Expand Up @@ -968,39 +968,40 @@ 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();
// FIXME: this error is technically unnecessary now when extern prelude is split into
// two scopes, remove it with lang team approval.
if let Some(entry) = self.r.extern_prelude.get(&ident)
&& expansion != LocalExpnId::ROOT
&& orig_name.is_some()
&& !entry.is_import()
&& entry.item_binding.is_none()
{
self.r.dcx().emit_err(
errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span },
);
// `return` is intended to discard this binding because it's an
// unregistered ambiguity error which would result in a panic
// caused by inconsistency `path_res`
// 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 entry.item_binding.is_some() {
let msg = format!("extern crate `{ident}` already in extern prelude");
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
} else {
entry.item_binding = Some(imported_binding);
entry.introduced_by_item = orig_name.is_some();
}
entry
}
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
item_binding: Some(imported_binding),
flag_binding: Cell::new(None),
only_item: true,
introduced_by_item: true,
}),
};
}
self.r.define_binding_local(parent, ident, TypeNS, imported_binding);
}
Expand Down
13 changes: 9 additions & 4 deletions compiler/rustc_resolve/src/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1095,12 +1095,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
);
}
}
Scope::ExternPrelude => {
suggestions.extend(this.extern_prelude.iter().filter_map(|(ident, _)| {
Scope::ExternPreludeItems => {
// Add idents from both item and flag scopes.
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))
}));
}
Scope::ExternPreludeFlags => {}
Scope::ToolPrelude => {
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
suggestions.extend(
Expand Down Expand Up @@ -1407,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
Expand Down Expand Up @@ -1884,7 +1886,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
"consider adding an explicit import of `{ident}` to disambiguate"
))
}
if b.is_extern_crate() && ident.span.at_least_rust_2018() {
if kind != AmbiguityKind::ExternPrelude
&& b.is_extern_crate()
&& ident.span.at_least_rust_2018()
{
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
}
match misc {
Expand Down
60 changes: 42 additions & 18 deletions compiler/rustc_resolve/src/ident.rs
Original file line number Diff line number Diff line change
Expand Up @@ -97,6 +97,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ScopeSet::All(ns)
| ScopeSet::ModuleAndExternPrelude(ns, _)
| ScopeSet::Late(ns, ..) => (ns, None),
ScopeSet::ExternPrelude => (TypeNS, None),
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
};
let module = match scope_set {
Expand All @@ -106,8 +107,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
_ => parent_scope.module.nearest_item_scope(),
};
let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..));
let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude);
let mut scope = match ns {
_ if module_and_extern_prelude => Scope::Module(module, None),
_ if extern_prelude => Scope::ExternPreludeItems,
TypeNS | ValueNS => Scope::Module(module, None),
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
};
Expand Down Expand Up @@ -138,7 +141,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Scope::Module(..) => true,
Scope::MacroUsePrelude => use_prelude || rust_2015,
Scope::BuiltinAttrs => true,
Scope::ExternPrelude => use_prelude || module_and_extern_prelude,
Scope::ExternPreludeItems | Scope::ExternPreludeFlags => {
use_prelude || module_and_extern_prelude || extern_prelude
}
Scope::ToolPrelude => use_prelude,
Scope::StdLibPrelude => use_prelude || ns == MacroNS,
Scope::BuiltinTypes => true,
Expand Down Expand Up @@ -177,7 +182,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Scope::Module(..) if module_and_extern_prelude => match ns {
TypeNS => {
ctxt.adjust(ExpnId::root());
Scope::ExternPrelude
Scope::ExternPreludeItems
}
ValueNS | MacroNS => break,
},
Expand All @@ -194,7 +199,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None => {
ctxt.adjust(ExpnId::root());
match ns {
TypeNS => Scope::ExternPrelude,
TypeNS => Scope::ExternPreludeItems,
ValueNS => Scope::StdLibPrelude,
MacroNS => Scope::MacroUsePrelude,
}
Expand All @@ -203,8 +208,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
Scope::MacroUsePrelude => Scope::StdLibPrelude,
Scope::BuiltinAttrs => break, // nowhere else to search
Scope::ExternPrelude if module_and_extern_prelude => break,
Scope::ExternPrelude => Scope::ToolPrelude,
Scope::ExternPreludeItems => Scope::ExternPreludeFlags,
Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break,
Scope::ExternPreludeFlags => Scope::ToolPrelude,
Scope::ToolPrelude => Scope::StdLibPrelude,
Scope::StdLibPrelude => match ns {
TypeNS => Scope::BuiltinTypes,
Expand Down Expand Up @@ -390,9 +396,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
struct Flags: u8 {
const MACRO_RULES = 1 << 0;
const MODULE = 1 << 1;
const MISC_SUGGEST_CRATE = 1 << 2;
const MISC_SUGGEST_SELF = 1 << 3;
const MISC_FROM_PRELUDE = 1 << 4;
const EXTERN_PRELUDE = 1 << 2;
const MISC_SUGGEST_CRATE = 1 << 3;
const MISC_SUGGEST_SELF = 1 << 4;
const MISC_FROM_PRELUDE = 1 << 5;
}
}

Expand All @@ -407,6 +414,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ScopeSet::All(ns)
| ScopeSet::ModuleAndExternPrelude(ns, _)
| ScopeSet::Late(ns, ..) => (ns, None),
ScopeSet::ExternPrelude => (TypeNS, None),
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
};

Expand Down Expand Up @@ -555,14 +563,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Some(binding) => Ok((*binding, Flags::empty())),
None => Err(Determinacy::Determined),
},
Scope::ExternPrelude => {
match this.extern_prelude_get(ident, finalize.is_some()) {
Some(binding) => Ok((binding, Flags::empty())),
Scope::ExternPreludeItems => {
match this.extern_prelude_get_item(ident, finalize.is_some()) {
Some(binding) => Ok((binding, Flags::EXTERN_PRELUDE)),
None => Err(Determinacy::determined(
this.graph_root.unexpanded_invocations.borrow().is_empty(),
)),
}
}
Scope::ExternPreludeFlags => {
match this.extern_prelude_get_flag(ident, finalize.is_some()) {
Some(binding) => Ok((binding, Flags::EXTERN_PRELUDE)),
None => Err(Determinacy::Determined),
}
}
Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) {
Some(binding) => Ok((*binding, Flags::empty())),
None => Err(Determinacy::Determined),
Expand Down Expand Up @@ -671,7 +685,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} else if innermost_binding
.may_appear_after(parent_scope.expansion, binding)
{
Some(AmbiguityKind::MoreExpandedVsOuter)
if flags.contains(Flags::EXTERN_PRELUDE)
&& innermost_flags.contains(Flags::EXTERN_PRELUDE)
{
Some(AmbiguityKind::ExternPrelude)
} else {
Some(AmbiguityKind::MoreExpandedVsOuter)
}
} else {
None
};
Expand Down Expand Up @@ -812,13 +832,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
assert_eq!(shadowing, Shadowing::Unrestricted);
return if ns != TypeNS {
Err((Determined, Weak::No))
} else if let Some(binding) = self.extern_prelude_get(ident, finalize.is_some()) {
Ok(binding)
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
// Macro-expanded `extern crate` items can add names to extern prelude.
Err((Undetermined, Weak::No))
} else {
Err((Determined, Weak::No))
let binding = self.early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::ExternPrelude,
parent_scope,
finalize,
finalize.is_some(),
ignore_binding,
ignore_import,
);
return binding.map_err(|determinacy| (determinacy, Weak::No));
};
}
ModuleOrUniformRoot::CurrentScope => {
Expand Down
17 changes: 4 additions & 13 deletions compiler/rustc_resolve/src/late/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2477,19 +2477,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 {
Expand Down
Loading
Loading