Skip to content

Commit f392f71

Browse files
committed
refactor(resolve): splitting glob and non-glob name bindings
1 parent 114fb86 commit f392f71

File tree

8 files changed

+125
-123
lines changed

8 files changed

+125
-123
lines changed

compiler/rustc_resolve/src/build_reduced_graph.rs

+2-1
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@ use rustc_ast::visit::{self, AssocCtxt, Visitor};
1818
use rustc_ast::{self as ast, AssocItem, AssocItemKind, MetaItemKind, StmtKind};
1919
use rustc_ast::{Block, Fn, ForeignItem, ForeignItemKind, Impl, Item, ItemKind, NodeId};
2020
use rustc_attr as attr;
21+
use rustc_data_structures::intern::Interned;
2122
use rustc_data_structures::sync::Lrc;
2223
use rustc_errors::{struct_span_err, Applicability};
2324
use rustc_expand::expand::AstFragment;
@@ -378,7 +379,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> {
378379
if !type_ns_only || ns == TypeNS {
379380
let key = BindingKey::new(target, ns);
380381
let mut resolution = this.resolution(current_module, key).borrow_mut();
381-
resolution.add_single_import(import);
382+
resolution.single_imports.insert(Interned::new_unchecked(import));
382383
}
383384
});
384385
}

compiler/rustc_resolve/src/diagnostics.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -518,7 +518,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
518518
ctxt: Option<SyntaxContext>,
519519
) {
520520
for (key, resolution) in self.resolutions(module).borrow().iter() {
521-
if let Some(binding) = resolution.borrow().binding {
521+
if let Some(binding) = resolution.borrow().available_binding() {
522522
let res = binding.res();
523523
if filter_fn(res) && ctxt.map_or(true, |ctxt| ctxt == key.ident.span.ctxt()) {
524524
names.push(TypoSuggestion::typo_from_ident(key.ident, res));

compiler/rustc_resolve/src/ident.rs

+6-11
Original file line numberDiff line numberDiff line change
@@ -870,16 +870,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
870870
let resolution =
871871
self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports.
872872

873-
// If the primary binding is unusable, search further and return the shadowed glob
874-
// binding if it exists. What we really want here is having two separate scopes in
875-
// a module - one for non-globs and one for globs, but until that's done use this
876-
// hack to avoid inconsistent resolution ICEs during import validation.
877-
let binding =
878-
[resolution.binding, resolution.shadowed_glob].into_iter().find_map(|binding| {
879-
match (binding, ignore_binding) {
880-
(Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
881-
_ => binding,
882-
}
873+
let binding = [resolution.non_glob_binding(), resolution.glob_binding()]
874+
.into_iter()
875+
.find_map(|binding| match (binding, ignore_binding) {
876+
(Some(binding), Some(ignored)) if ptr::eq(binding, ignored) => None,
877+
_ => binding,
883878
});
884879

885880
if let Some(Finalize { path_span, report_private, .. }) = finalize {
@@ -900,7 +895,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
900895
}
901896

902897
// Forbid expanded shadowing to avoid time travel.
903-
if let Some(shadowed_glob) = resolution.shadowed_glob
898+
if let Some(shadowed_glob) = resolution.glob_binding()
904899
&& restricted_shadowing
905900
&& binding.expansion != LocalExpnId::ROOT
906901
&& binding.res() != shadowed_glob.res()

compiler/rustc_resolve/src/imports.rs

+73-97
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ use crate::{
99
Resolver, Segment,
1010
};
1111
use crate::{Finalize, Module, ModuleOrUniformRoot, ParentScope, PerNS, ScopeSet};
12-
use crate::{NameBinding, NameBindingKind, PathResult};
12+
use crate::{NameBinding, NameBindingKind, PathResult, Res};
1313

1414
use rustc_ast::NodeId;
1515
use rustc_data_structures::fx::FxHashSet;
@@ -34,8 +34,6 @@ use smallvec::SmallVec;
3434
use std::cell::Cell;
3535
use std::{mem, ptr};
3636

37-
type Res = def::Res<NodeId>;
38-
3937
/// Contains data for specific kinds of imports.
4038
#[derive(Clone)]
4139
pub(crate) enum ImportKind<'a> {
@@ -212,25 +210,32 @@ pub(crate) struct NameResolution<'a> {
212210
/// Single imports that may define the name in the namespace.
213211
/// Imports are arena-allocated, so it's ok to use pointers as keys.
214212
pub single_imports: FxHashSet<Interned<'a, Import<'a>>>,
215-
/// The least shadowable known binding for this name, or None if there are no known bindings.
216-
pub binding: Option<&'a NameBinding<'a>>,
217-
pub shadowed_glob: Option<&'a NameBinding<'a>>,
213+
non_glob_binding: Option<&'a NameBinding<'a>>,
214+
glob_binding: Option<&'a NameBinding<'a>>,
218215
}
219216

220217
impl<'a> NameResolution<'a> {
221-
/// Returns the binding for the name if it is known or None if it not known.
222218
pub(crate) fn binding(&self) -> Option<&'a NameBinding<'a>> {
223-
self.binding.and_then(|binding| {
224-
if !binding.is_glob_import() || self.single_imports.is_empty() {
225-
Some(binding)
226-
} else {
227-
None
228-
}
219+
self.non_glob_binding()
220+
.or_else(|| if self.single_imports.is_empty() { self.glob_binding() } else { None })
221+
}
222+
223+
pub(crate) fn non_glob_binding(&self) -> Option<&'a NameBinding<'a>> {
224+
self.non_glob_binding.and_then(|binding| {
225+
assert!(!binding.is_glob_import());
226+
Some(binding)
227+
})
228+
}
229+
230+
pub(crate) fn glob_binding(&self) -> Option<&'a NameBinding<'a>> {
231+
self.glob_binding.and_then(|binding| {
232+
assert!(binding.is_glob_import());
233+
Some(binding)
229234
})
230235
}
231236

232-
pub(crate) fn add_single_import(&mut self, import: &'a Import<'a>) {
233-
self.single_imports.insert(Interned::new_unchecked(import));
237+
pub(crate) fn available_binding(&self) -> Option<&'a NameBinding<'a>> {
238+
self.non_glob_binding().or(self.glob_binding())
234239
}
235240
}
236241

@@ -305,65 +310,41 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
305310
self.check_reserved_macro_name(key.ident, res);
306311
self.set_binding_parent_module(binding, module);
307312
self.update_resolution(module, key, |this, resolution| {
308-
if let Some(old_binding) = resolution.binding {
309-
if res == Res::Err && old_binding.res() != Res::Err {
310-
// Do not override real bindings with `Res::Err`s from error recovery.
311-
return Ok(());
312-
}
313-
match (old_binding.is_glob_import(), binding.is_glob_import()) {
314-
(true, true) => {
315-
if res != old_binding.res() {
316-
resolution.binding = Some(this.ambiguity(
317-
AmbiguityKind::GlobVsGlob,
318-
old_binding,
319-
binding,
320-
));
321-
} else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
322-
// We are glob-importing the same item but with greater visibility.
323-
resolution.binding = Some(binding);
324-
}
325-
}
326-
(old_glob @ true, false) | (old_glob @ false, true) => {
327-
let (glob_binding, nonglob_binding) =
328-
if old_glob { (old_binding, binding) } else { (binding, old_binding) };
329-
if glob_binding.res() != nonglob_binding.res()
330-
&& key.ns == MacroNS
331-
&& nonglob_binding.expansion != LocalExpnId::ROOT
332-
{
333-
resolution.binding = Some(this.ambiguity(
334-
AmbiguityKind::GlobVsExpanded,
335-
nonglob_binding,
336-
glob_binding,
337-
));
338-
} else {
339-
resolution.binding = Some(nonglob_binding);
340-
}
341-
342-
if let Some(old_binding) = resolution.shadowed_glob {
343-
assert!(old_binding.is_glob_import());
344-
if glob_binding.res() != old_binding.res() {
345-
resolution.shadowed_glob = Some(this.ambiguity(
346-
AmbiguityKind::GlobVsGlob,
347-
old_binding,
348-
glob_binding,
349-
));
350-
} else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
351-
resolution.shadowed_glob = Some(glob_binding);
352-
}
353-
} else {
354-
resolution.shadowed_glob = Some(glob_binding);
355-
}
356-
}
357-
(false, false) => {
358-
return Err(old_binding);
359-
}
313+
if let Some(old_binding) = resolution.available_binding() && res == Res::Err && old_binding.res() != Res::Err {
314+
// Do not override real bindings with `Res::Err`s from error recovery.
315+
Ok(())
316+
} else if binding.is_glob_import() {
317+
if let Some(old_binding) = resolution.glob_binding() {
318+
if binding.res() != old_binding.res() {
319+
resolution.glob_binding = Some(this.ambiguity(
320+
AmbiguityKind::GlobVsGlob,
321+
old_binding,
322+
binding,
323+
));
324+
} else if !old_binding.vis.is_at_least(binding.vis, this.tcx) {
325+
resolution.glob_binding = Some(binding);
360326
}
361327
} else {
362-
resolution.binding = Some(binding);
328+
resolution.glob_binding = Some(binding);
363329
}
364330

331+
if let Some(old_binding) = resolution.non_glob_binding() {
332+
if binding.res() != old_binding.res() && key.ns == MacroNS && old_binding.expansion != LocalExpnId::ROOT {
333+
resolution.non_glob_binding = Some(this.ambiguity(
334+
AmbiguityKind::GlobVsExpanded,
335+
old_binding,
336+
binding,
337+
));
338+
}
339+
}
365340
Ok(())
366-
})
341+
} else if let Some(old_binding) = resolution.non_glob_binding() {
342+
Err(old_binding)
343+
} else {
344+
resolution.non_glob_binding = Some(binding);
345+
Ok(())
346+
}
347+
})
367348
}
368349

369350
fn ambiguity(
@@ -549,11 +530,11 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
549530
for (key, resolution) in self.resolutions(module).borrow().iter() {
550531
let resolution = resolution.borrow();
551532

552-
if let Some(binding) = resolution.binding {
553-
if let NameBindingKind::Import { import, .. } = binding.kind
554-
&& let Some((amb_binding, _)) = binding.ambiguity
555-
&& binding.res() != Res::Err
556-
&& exported_ambiguities.contains(&Interned::new_unchecked(binding))
533+
if let Some(glob_binding) = resolution.glob_binding() {
534+
if let NameBindingKind::Import { import, .. } = glob_binding.kind
535+
&& let Some((amb_binding, _)) = glob_binding.ambiguity
536+
&& glob_binding.res() != Res::Err
537+
&& exported_ambiguities.contains(&Interned::new_unchecked(glob_binding))
557538
{
558539
self.lint_buffer.buffer_lint_with_diagnostic(
559540
AMBIGUOUS_GLOB_REEXPORTS,
@@ -569,7 +550,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
569550
);
570551
}
571552

572-
if let Some(glob_binding) = resolution.shadowed_glob {
553+
if let Some(binding) = resolution.non_glob_binding() {
573554
let binding_id = match binding.kind {
574555
NameBindingKind::Res(res) => {
575556
Some(self.def_id_to_node_id[res.def_id().expect_local()])
@@ -769,9 +750,8 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
769750
.emit();
770751
}
771752
let key = BindingKey::new(target, ns);
772-
this.update_resolution(parent, key, |_, resolution| {
773-
resolution.single_imports.remove(&Interned::new_unchecked(import));
774-
});
753+
let mut resolution = this.resolution(parent, key).borrow_mut();
754+
resolution.single_imports.remove(&Interned::new_unchecked(import));
775755
}
776756
}
777757
}
@@ -1025,29 +1005,25 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> {
10251005
let resolutions = resolutions.as_ref().into_iter().flat_map(|r| r.iter());
10261006
let names = resolutions
10271007
.filter_map(|(BindingKey { ident: i, .. }, resolution)| {
1008+
let resolution = resolution.borrow();
10281009
if i.name == ident.name {
1029-
return None;
1030-
} // Never suggest the same name
1031-
match *resolution.borrow() {
1032-
NameResolution { binding: Some(name_binding), .. } => {
1033-
match name_binding.kind {
1034-
NameBindingKind::Import { binding, .. } => {
1035-
match binding.kind {
1036-
// Never suggest the name that has binding error
1037-
// i.e., the name that cannot be previously resolved
1038-
NameBindingKind::Res(Res::Err) => None,
1039-
_ => Some(i.name),
1040-
}
1010+
None
1011+
} else if let Some(name_binding) = resolution.available_binding() {
1012+
match name_binding.kind {
1013+
NameBindingKind::Import { binding, .. } => {
1014+
match binding.kind {
1015+
// Never suggest the name that has binding error
1016+
// i.e., the name that cannot be previously resolved
1017+
NameBindingKind::Res(Res::Err) => None,
1018+
_ => Some(i.name),
10411019
}
1042-
_ => Some(i.name),
10431020
}
1021+
_ => Some(i.name),
10441022
}
1045-
NameResolution { ref single_imports, .. }
1046-
if single_imports.is_empty() =>
1047-
{
1048-
None
1049-
}
1050-
_ => Some(i.name),
1023+
} else if resolution.single_imports.is_empty() {
1024+
None
1025+
} else {
1026+
Some(i.name)
10511027
}
10521028
})
10531029
.collect::<Vec<Symbol>>();

compiler/rustc_resolve/src/late.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -2969,7 +2969,8 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
29692969
let Some((module, _)) = &self.current_trait_ref else { return; };
29702970
ident.span.normalize_to_macros_2_0_and_adjust(module.expansion);
29712971
let key = BindingKey::new(ident, ns);
2972-
let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
2972+
let mut binding =
2973+
self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.available_binding());
29732974
debug!(?binding);
29742975
if binding.is_none() {
29752976
// We could not find the trait item in the correct namespace.
@@ -2980,7 +2981,12 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
29802981
_ => ns,
29812982
};
29822983
let key = BindingKey::new(ident, ns);
2983-
binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding);
2984+
binding = self
2985+
.r
2986+
.resolution(module, key)
2987+
.try_borrow()
2988+
.ok()
2989+
.and_then(|r| r.available_binding());
29842990
debug!(?binding);
29852991
}
29862992
let Some(binding) = binding else {

compiler/rustc_resolve/src/late/diagnostics.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -1012,15 +1012,16 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
10121012
self.resolve_path(mod_path, None, None)
10131013
{
10141014
let resolutions = self.r.resolutions(module).borrow();
1015-
let targets: Vec<_> =
1016-
resolutions
1017-
.iter()
1018-
.filter_map(|(key, resolution)| {
1019-
resolution.borrow().binding.map(|binding| binding.res()).and_then(
1020-
|res| if filter_fn(res) { Some((key, res)) } else { None },
1021-
)
1022-
})
1023-
.collect();
1015+
let targets: Vec<_> = resolutions
1016+
.iter()
1017+
.filter_map(|(key, resolution)| {
1018+
resolution
1019+
.borrow()
1020+
.available_binding()
1021+
.map(|binding| binding.res())
1022+
.and_then(|res| if filter_fn(res) { Some((key, res)) } else { None })
1023+
})
1024+
.collect();
10241025
if targets.len() == 1 {
10251026
let target = targets[0];
10261027
return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1));
@@ -1543,7 +1544,9 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> {
15431544
let targets = resolutions
15441545
.borrow()
15451546
.iter()
1546-
.filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res())))
1547+
.filter_map(|(key, res)| {
1548+
res.borrow().available_binding().map(|binding| (key, binding.res()))
1549+
})
15471550
.filter(|(_, res)| match (kind, res) {
15481551
(AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true,
15491552
(AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true,

compiler/rustc_resolve/src/lib.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -565,7 +565,7 @@ impl<'a> ModuleData<'a> {
565565
F: FnMut(&mut R, Ident, Namespace, &'a NameBinding<'a>),
566566
{
567567
for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() {
568-
if let Some(binding) = name_resolution.borrow().binding {
568+
if let Some(binding) = name_resolution.borrow().available_binding() {
569569
f(resolver, key.ident, key.ns, binding);
570570
}
571571
}

tests/ui/resolve/non-glob-first.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
// check-pass
2+
3+
mod a {
4+
pub trait P {}
5+
}
6+
pub use a::*;
7+
8+
mod b {
9+
#[derive(Clone)]
10+
pub enum P {
11+
A
12+
}
13+
}
14+
pub use b::P;
15+
16+
mod c {
17+
use crate::*;
18+
pub struct _S(Vec<P>);
19+
}
20+
21+
fn main() {}

0 commit comments

Comments
 (0)