Skip to content

Commit 8e77954

Browse files
committed
Auto merge of #144793 - petrochenkov:extprel3, r=davidtwco
resolve: Split extern prelude into two scopes One scope for `extern crate` items and another for `--extern` options, with the former shadowing the latter. If in a single scope some things can overwrite other things, especially with ad hoc restrictions like `MacroExpandedExternCrateCannotShadowExternArguments`, then it's not really a single scope. So this PR splits `Scope::ExternPrelude` into two cleaner scopes. This is similar to how #144131 splits module scope into two scopes for globs and non-globs, but simpler.
2 parents 3672a55 + 9aa6cb5 commit 8e77954

File tree

16 files changed

+235
-90
lines changed

16 files changed

+235
-90
lines changed

compiler/rustc_error_codes/src/error_codes/E0578.md

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1+
#### Note: this error code is no longer emitted by the compiler.
2+
13
A module cannot be found and therefore, the visibility cannot be determined.
24

35
Erroneous code example:
46

5-
```compile_fail,E0578,edition2018
7+
```ignore (no longer emitted)
68
foo!();
79
810
pub (in ::Sea) struct Shark; // error!

compiler/rustc_resolve/src/build_reduced_graph.rs

Lines changed: 8 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -971,40 +971,35 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
971971
let imported_binding = self.r.import(binding, import);
972972
if ident.name != kw::Underscore && parent == self.r.graph_root {
973973
let norm_ident = Macros20NormalizedIdent::new(ident);
974+
// FIXME: this error is technically unnecessary now when extern prelude is split into
975+
// two scopes, remove it with lang team approval.
974976
if let Some(entry) = self.r.extern_prelude.get(&norm_ident)
975977
&& expansion != LocalExpnId::ROOT
976978
&& orig_name.is_some()
977-
&& !entry.is_import()
979+
&& entry.item_binding.is_none()
978980
{
979981
self.r.dcx().emit_err(
980982
errors::MacroExpandedExternCrateCannotShadowExternArguments { span: item.span },
981983
);
982-
// `return` is intended to discard this binding because it's an
983-
// unregistered ambiguity error which would result in a panic
984-
// caused by inconsistency `path_res`
985-
// more details: https://github.com/rust-lang/rust/pull/111761
986-
return;
987984
}
988985

989986
use indexmap::map::Entry;
990987
match self.r.extern_prelude.entry(norm_ident) {
991988
Entry::Occupied(mut occupied) => {
992989
let entry = occupied.get_mut();
993-
if let Some(old_binding) = entry.binding.get()
994-
&& old_binding.is_import()
995-
{
990+
if entry.item_binding.is_some() {
996991
let msg = format!("extern crate `{ident}` already in extern prelude");
997992
self.r.tcx.dcx().span_delayed_bug(item.span, msg);
998993
} else {
999-
// Binding from `extern crate` item in source code can replace
1000-
// a binding from `--extern` on command line here.
1001-
entry.binding.set(Some(imported_binding));
994+
entry.item_binding = Some(imported_binding);
1002995
entry.introduced_by_item = orig_name.is_some();
1003996
}
1004997
entry
1005998
}
1006999
Entry::Vacant(vacant) => vacant.insert(ExternPreludeEntry {
1007-
binding: Cell::new(Some(imported_binding)),
1000+
item_binding: Some(imported_binding),
1001+
flag_binding: Cell::new(None),
1002+
only_item: true,
10081003
introduced_by_item: true,
10091004
}),
10101005
};

compiler/rustc_resolve/src/diagnostics.rs

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1096,12 +1096,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
10961096
);
10971097
}
10981098
}
1099-
Scope::ExternPrelude => {
1099+
Scope::ExternPreludeItems => {
1100+
// Add idents from both item and flag scopes.
11001101
suggestions.extend(this.extern_prelude.keys().filter_map(|ident| {
11011102
let res = Res::Def(DefKind::Mod, CRATE_DEF_ID.to_def_id());
11021103
filter_fn(res).then_some(TypoSuggestion::typo_from_ident(ident.0, res))
11031104
}));
11041105
}
1106+
Scope::ExternPreludeFlags => {}
11051107
Scope::ToolPrelude => {
11061108
let res = Res::NonMacroAttr(NonMacroAttrKind::Tool);
11071109
suggestions.extend(
@@ -1873,14 +1875,20 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18731875
}
18741876
}
18751877

1876-
fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'_>) -> AmbiguityErrorDiag {
1878+
fn ambiguity_diagnostics(&self, ambiguity_error: &AmbiguityError<'ra>) -> AmbiguityErrorDiag {
18771879
let AmbiguityError { kind, ident, b1, b2, misc1, misc2, .. } = *ambiguity_error;
1880+
let extern_prelude_ambiguity = || {
1881+
self.extern_prelude.get(&Macros20NormalizedIdent::new(ident)).is_some_and(|entry| {
1882+
entry.item_binding == Some(b1) && entry.flag_binding.get() == Some(b2)
1883+
})
1884+
};
18781885
let (b1, b2, misc1, misc2, swapped) = if b2.span.is_dummy() && !b1.span.is_dummy() {
18791886
// We have to print the span-less alternative first, otherwise formatting looks bad.
18801887
(b2, b1, misc2, misc1, true)
18811888
} else {
18821889
(b1, b2, misc1, misc2, false)
18831890
};
1891+
18841892
let could_refer_to = |b: NameBinding<'_>, misc: AmbiguityErrorMisc, also: &str| {
18851893
let what = self.binding_description(b, ident, misc == AmbiguityErrorMisc::FromPrelude);
18861894
let note_msg = format!("`{ident}` could{also} refer to {what}");
@@ -1896,7 +1904,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
18961904
"consider adding an explicit import of `{ident}` to disambiguate"
18971905
))
18981906
}
1899-
if b.is_extern_crate() && ident.span.at_least_rust_2018() {
1907+
if b.is_extern_crate() && ident.span.at_least_rust_2018() && !extern_prelude_ambiguity()
1908+
{
19001909
help_msgs.push(format!("use `::{ident}` to refer to this {thing} unambiguously"))
19011910
}
19021911
match misc {

compiler/rustc_resolve/src/ident.rs

Lines changed: 40 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -102,6 +102,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
102102
ScopeSet::All(ns)
103103
| ScopeSet::ModuleAndExternPrelude(ns, _)
104104
| ScopeSet::Late(ns, ..) => (ns, None),
105+
ScopeSet::ExternPrelude => (TypeNS, None),
105106
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
106107
};
107108
let module = match scope_set {
@@ -111,8 +112,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
111112
_ => parent_scope.module.nearest_item_scope(),
112113
};
113114
let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..));
115+
let extern_prelude = matches!(scope_set, ScopeSet::ExternPrelude);
114116
let mut scope = match ns {
115117
_ if module_and_extern_prelude => Scope::Module(module, None),
118+
_ if extern_prelude => Scope::ExternPreludeItems,
116119
TypeNS | ValueNS => Scope::Module(module, None),
117120
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
118121
};
@@ -143,7 +146,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
143146
Scope::Module(..) => true,
144147
Scope::MacroUsePrelude => use_prelude || rust_2015,
145148
Scope::BuiltinAttrs => true,
146-
Scope::ExternPrelude => use_prelude || module_and_extern_prelude,
149+
Scope::ExternPreludeItems | Scope::ExternPreludeFlags => {
150+
use_prelude || module_and_extern_prelude || extern_prelude
151+
}
147152
Scope::ToolPrelude => use_prelude,
148153
Scope::StdLibPrelude => use_prelude || ns == MacroNS,
149154
Scope::BuiltinTypes => true,
@@ -182,7 +187,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
182187
Scope::Module(..) if module_and_extern_prelude => match ns {
183188
TypeNS => {
184189
ctxt.adjust(ExpnId::root());
185-
Scope::ExternPrelude
190+
Scope::ExternPreludeItems
186191
}
187192
ValueNS | MacroNS => break,
188193
},
@@ -199,7 +204,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
199204
None => {
200205
ctxt.adjust(ExpnId::root());
201206
match ns {
202-
TypeNS => Scope::ExternPrelude,
207+
TypeNS => Scope::ExternPreludeItems,
203208
ValueNS => Scope::StdLibPrelude,
204209
MacroNS => Scope::MacroUsePrelude,
205210
}
@@ -208,8 +213,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
208213
}
209214
Scope::MacroUsePrelude => Scope::StdLibPrelude,
210215
Scope::BuiltinAttrs => break, // nowhere else to search
211-
Scope::ExternPrelude if module_and_extern_prelude => break,
212-
Scope::ExternPrelude => Scope::ToolPrelude,
216+
Scope::ExternPreludeItems => Scope::ExternPreludeFlags,
217+
Scope::ExternPreludeFlags if module_and_extern_prelude || extern_prelude => break,
218+
Scope::ExternPreludeFlags => Scope::ToolPrelude,
213219
Scope::ToolPrelude => Scope::StdLibPrelude,
214220
Scope::StdLibPrelude => match ns {
215221
TypeNS => Scope::BuiltinTypes,
@@ -413,6 +419,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
413419
ScopeSet::All(ns)
414420
| ScopeSet::ModuleAndExternPrelude(ns, _)
415421
| ScopeSet::Late(ns, ..) => (ns, None),
422+
ScopeSet::ExternPrelude => (TypeNS, None),
416423
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)),
417424
};
418425

@@ -429,6 +436,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
429436
// to detect potential ambiguities.
430437
let mut innermost_result: Option<(NameBinding<'_>, Flags)> = None;
431438
let mut determinacy = Determinacy::Determined;
439+
// Shadowed bindings don't need to be marked as used or non-speculatively loaded.
440+
macro finalize_scope() {
441+
if innermost_result.is_none() { finalize } else { None }
442+
}
432443

433444
// Go through all the scopes and try to resolve the name.
434445
let break_result = self.visit_scopes(
@@ -494,7 +505,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
494505
_ => Err(Determinacy::Determined),
495506
},
496507
Scope::Module(module, derive_fallback_lint_id) => {
497-
let (adjusted_parent_scope, finalize) =
508+
// FIXME: use `finalize_scope` here.
509+
let (adjusted_parent_scope, adjusted_finalize) =
498510
if matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)) {
499511
(parent_scope, finalize)
500512
} else {
@@ -513,7 +525,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
513525
} else {
514526
Shadowing::Restricted
515527
},
516-
finalize,
528+
adjusted_finalize,
517529
ignore_binding,
518530
ignore_import,
519531
);
@@ -561,14 +573,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
561573
Some(binding) => Ok((*binding, Flags::empty())),
562574
None => Err(Determinacy::Determined),
563575
},
564-
Scope::ExternPrelude => {
565-
match this.reborrow().extern_prelude_get(ident, finalize.is_some()) {
576+
Scope::ExternPreludeItems => {
577+
// FIXME: use `finalize_scope` here.
578+
match this.reborrow().extern_prelude_get_item(ident, finalize.is_some()) {
566579
Some(binding) => Ok((binding, Flags::empty())),
567580
None => Err(Determinacy::determined(
568581
this.graph_root.unexpanded_invocations.borrow().is_empty(),
569582
)),
570583
}
571584
}
585+
Scope::ExternPreludeFlags => {
586+
match this.extern_prelude_get_flag(ident, finalize_scope!().is_some()) {
587+
Some(binding) => Ok((binding, Flags::empty())),
588+
None => Err(Determinacy::Determined),
589+
}
590+
}
572591
Scope::ToolPrelude => match this.registered_tool_bindings.get(&ident) {
573592
Some(binding) => Ok((*binding, Flags::empty())),
574593
None => Err(Determinacy::Determined),
@@ -599,8 +618,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
599618
if matches!(ident.name, sym::f16)
600619
&& !this.tcx.features().f16()
601620
&& !ident.span.allows_unstable(sym::f16)
602-
&& finalize.is_some()
603-
&& innermost_result.is_none()
621+
&& finalize_scope!().is_some()
604622
{
605623
feature_err(
606624
this.tcx.sess,
@@ -613,8 +631,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
613631
if matches!(ident.name, sym::f128)
614632
&& !this.tcx.features().f128()
615633
&& !ident.span.allows_unstable(sym::f128)
616-
&& finalize.is_some()
617-
&& innermost_result.is_none()
634+
&& finalize_scope!().is_some()
618635
{
619636
feature_err(
620637
this.tcx.sess,
@@ -819,15 +836,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
819836
assert_eq!(shadowing, Shadowing::Unrestricted);
820837
return if ns != TypeNS {
821838
Err((Determined, Weak::No))
822-
} else if let Some(binding) =
823-
self.reborrow().extern_prelude_get(ident, finalize.is_some())
824-
{
825-
Ok(binding)
826-
} else if !self.graph_root.unexpanded_invocations.borrow().is_empty() {
827-
// Macro-expanded `extern crate` items can add names to extern prelude.
828-
Err((Undetermined, Weak::No))
829839
} else {
830-
Err((Determined, Weak::No))
840+
let binding = self.early_resolve_ident_in_lexical_scope(
841+
ident,
842+
ScopeSet::ExternPrelude,
843+
parent_scope,
844+
finalize,
845+
finalize.is_some(),
846+
ignore_binding,
847+
ignore_import,
848+
);
849+
return binding.map_err(|determinacy| (determinacy, Weak::No));
831850
};
832851
}
833852
ModuleOrUniformRoot::CurrentScope => {

0 commit comments

Comments
 (0)