diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 2e870c47f8eb7..1ab4abd9b3a02 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -511,7 +511,7 @@ impl Resolver<'_, '_> { for (_key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); - if let Some(binding) = resolution.binding + if let Some(binding) = resolution.late_binding() && let NameBindingKind::Import { import, .. } = binding.kind && let ImportKind::Single { id, .. } = import.kind { diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 9149974a61774..3634bbf870e7d 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1442,7 +1442,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { |(key, name_resolution)| { if key.ns == TypeNS && key.ident == ident - && let Some(binding) = name_resolution.borrow().binding + && let Some(binding) = name_resolution.borrow().late_binding() { match binding.res() { // No disambiguation needed if the identically named item we @@ -1496,7 +1496,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; }; for (_, resolution) in this.resolutions(m).borrow().iter() { - let Some(binding) = resolution.borrow().binding else { + let Some(binding) = resolution.borrow().late_binding() else { continue; }; let Res::Def(DefKind::Macro(MacroKind::Derive | MacroKind::Attr), def_id) = diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 68fbe48ebcb08..32ba4cbafa4a7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1,3 +1,5 @@ +use std::cell::RefMut; + use Determinacy::*; use Namespace::*; use rustc_ast::{self as ast, NodeId}; @@ -18,9 +20,9 @@ use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib use crate::macros::{MacroRulesScope, sub_namespace_match}; use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, - ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, - NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, ToNameBinding, Used, Weak, errors, + ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, ModuleScope, + NameBinding, NameBindingKind, NameResolution, ParentScope, PathResult, PrivacyError, Res, + ResolutionError, Resolver, Scope, ScopeSet, Segment, ToNameBinding, Used, Weak, errors, }; type Visibility = ty::Visibility; @@ -37,7 +39,7 @@ impl From for bool { } } -#[derive(Debug, PartialEq)] +#[derive(Debug, PartialEq, Clone, Copy)] enum Shadowing { Restricted, Unrestricted, @@ -221,6 +223,27 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None } + #[instrument(skip(self, visitor), level = "debug")] + fn visit_module_scopes( + &mut self, + ns: Namespace, + mut visitor: impl FnMut(&mut Self, ModuleScope) -> Option, + ) -> Option { + let mut scope = ModuleScope::NonGlobal; + loop { + if let break_result @ Some(..) = visitor(self, scope) { + return break_result; + } + + scope = match scope { + ModuleScope::NonGlobal => ModuleScope::Globs, + ModuleScope::Globs => break, // nowhere else to search + }; + } + + None + } + fn hygienic_lexical_parent( &mut self, module: Module<'ra>, @@ -871,168 +894,93 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let resolution = self.resolution(module, key).try_borrow_mut().map_err(|_| (Determined, Weak::No))?; // This happens when there is a cycle of imports. - // If the primary binding is unusable, search further and return the shadowed glob - // binding if it exists. What we really want here is having two separate scopes in - // a module - one for non-globs and one for globs, but until that's done use this - // hack to avoid inconsistent resolution ICEs during import validation. - let binding = [resolution.binding, resolution.shadowed_glob] - .into_iter() - .find_map(|binding| if binding == ignore_binding { None } else { binding }); - - if let Some(Finalize { path_span, report_private, used, root_span, .. }) = finalize { - let Some(binding) = binding else { - return Err((Determined, Weak::No)); - }; - - if !self.is_accessible_from(binding.vis, parent_scope.module) { - if report_private { - self.privacy_errors.push(PrivacyError { - ident, - binding, - dedup_span: path_span, - outermost_res: None, - parent_scope: *parent_scope, - single_nested: path_span != root_span, - }); - } else { - return Err((Determined, Weak::No)); - } - } - - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = resolution.shadowed_glob - && shadowing == Shadowing::Restricted - && binding.expansion != LocalExpnId::ROOT - && binding.res() != shadowed_glob.res() - { - self.ambiguity_errors.push(AmbiguityError { - kind: AmbiguityKind::GlobVsExpanded, - ident, - b1: binding, - b2: shadowed_glob, - warning: false, - misc1: AmbiguityErrorMisc::None, - misc2: AmbiguityErrorMisc::None, - }); - } - - if shadowing == Shadowing::Unrestricted - && binding.expansion != LocalExpnId::ROOT - && let NameBindingKind::Import { import, .. } = binding.kind - && matches!(import.kind, ImportKind::MacroExport) - { - self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); - } - - self.record_use(ident, binding, used); - return Ok(binding); - } - let check_usable = |this: &mut Self, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; - // Items and single imports are not shadowable, if we have one, then it's determined. - if let Some(binding) = binding - && !binding.is_glob_import() - { - return check_usable(self, binding); - } - - // --- From now on we either have a glob resolution or no resolution. --- + let break_result = self.visit_module_scopes(ns, |this, scope| match scope { + ModuleScope::NonGlobal => { + // Non-glob bindings are "strong" and can be resolved immediately. + if let Some(binding) = resolution.non_glob_binding + && ignore_binding.map_or(true, |b| binding != b) + { + if let Some(finalize) = finalize { + return Some(this.finalize_non_glob_module_binding( + ident, + binding, + resolution.glob_binding, + parent_scope, + finalize, + shadowing, + )); + } else { + return Some(check_usable(this, binding)); + } + } - // Check if one of single imports can still define the name, - // if it can then our result is not determined and can be invalidated. - for single_import in &resolution.single_imports { - if ignore_import == Some(*single_import) { - // This branch handles a cycle in single imports. - // - // For example: - // ``` - // use a::b; - // use b as a; - // ``` - // 1. Record `use a::b` as the `ignore_import` and attempt to locate `a` in the - // current module. - // 2. Encounter the import `use b as a`, which is a `single_import` for `a`, - // and try to find `b` in the current module. - // 3. Re-encounter the `use a::b` import since it's a `single_import` of `b`. - // This leads to entering this branch. - continue; - } - if !self.is_accessible_from(single_import.vis, parent_scope.module) { - continue; - } - if let Some(ignored) = ignore_binding - && let NameBindingKind::Import { import, .. } = ignored.kind - && import == *single_import - { - // Ignore not just the binding itself, but if it has a shadowed_glob, - // ignore that, too, because this loop is supposed to only process - // named imports. - continue; + None // Continue to global scope } + ModuleScope::Globs => { + // If we are here, any primary `resolution.binding` is either a glob, None, + // or should be ignored. + let binding = resolution.glob_binding; + + if let Some(binding) = binding { + if !binding.is_glob_import() { + panic!("binding should be glob import {:?}", binding) + } + } - let Some(module) = single_import.imported_module.get() else { - return Err((Undetermined, Weak::No)); - }; - let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind - else { - unreachable!(); - }; - if source != target { - // This branch allows the binding to be defined or updated later if the target name - // can hide the source. - if target_bindings.iter().all(|binding| binding.get().is_none()) { - // None of the target bindings are available, so we can't determine - // if this binding is correct or not. - // See more details in #124840 - return Err((Undetermined, Weak::No)); - } else if target_bindings[ns].get().is_none() && binding.is_some() { - // `binding.is_some()` avoids the condition where the binding - // truly doesn't exist in this namespace and should return `Err(Determined)`. - return Err((Undetermined, Weak::No)); + if let Some(finalize) = finalize { + return Some(this.finalize_glob_module_binding( + ident, + binding, + parent_scope, + finalize, + shadowing, + )); } - } - match self.resolve_ident_in_module( - module, - *source, - ns, - &single_import.parent_scope, - None, - ignore_binding, - ignore_import, - ) { - Err((Determined, _)) => continue, - Ok(binding) - if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => - { - continue; + // Check if one of single imports can still define the name, + // if it can then our result is not determined and can be invalidated. + if this.single_import_can_define_name( + &resolution, + binding, + ns, + ignore_import, + ignore_binding, + parent_scope, + ) { + return Some(Err((Undetermined, Weak::No))); } - Ok(_) | Err((Undetermined, _)) => return Err((Undetermined, Weak::No)), - } - } - // So we have a resolution that's from a glob import. This resolution is determined - // if it cannot be shadowed by some new item/import expanded from a macro. - // This happens either if there are no unexpanded macros, or expanded names cannot - // shadow globs (that happens in macro namespace or with restricted shadowing). - // - // Additionally, any macro in any module can plant names in the root module if it creates - // `macro_export` macros, so the root module effectively has unresolved invocations if any - // module has unresolved invocations. - // However, it causes resolution/expansion to stuck too often (#53144), so, to make - // progress, we have to ignore those potential unresolved invocations from other modules - // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted - // shadowing is enabled, see `macro_expanded_macro_export_errors`). - if let Some(binding) = binding { - if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted { - return check_usable(self, binding); - } else { - return Err((Undetermined, Weak::No)); + // So we have a resolution that's from a glob import. This resolution is determined + // if it cannot be shadowed by some new item/import expanded from a macro. + // This happens either if there are no unexpanded macros, or expanded names cannot + // shadow globs (that happens in macro namespace or with restricted shadowing). + // + // Additionally, any macro in any module can plant names in the root module if it creates + // `macro_export` macros, so the root module effectively has unresolved invocations if any + // module has unresolved invocations. + // However, it causes resolution/expansion to stuck too often (#53144), so, to make + // progress, we have to ignore those potential unresolved invocations from other modules + // and prohibit access to macro-expanded `macro_export` macros instead (unless restricted + // shadowing is enabled, see `macro_expanded_macro_export_errors`). + if let Some(binding) = binding { + if binding.determined() || ns == MacroNS || shadowing == Shadowing::Restricted { + return Some(check_usable(this, binding)); + } else { + return Some(Err((Undetermined, Weak::No))); + } + } + + None } + }); + + if let Some(result) = break_result { + return result; } // --- From now on we have no resolution. --- @@ -1101,6 +1049,166 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err((Determined, Weak::No)) } + fn finalize_non_glob_module_binding( + &mut self, + ident: Ident, + binding: NameBinding<'ra>, + glob_binding: Option>, + parent_scope: &ParentScope<'ra>, + finalize: Finalize, + shadowing: Shadowing, + ) -> Result, (Determinacy, Weak)> { + let Finalize { path_span, report_private, used, root_span, .. } = finalize; + + if !self.is_accessible_from(binding.vis, parent_scope.module) { + if report_private { + self.privacy_errors.push(PrivacyError { + ident, + binding, + dedup_span: path_span, + outermost_res: None, + parent_scope: *parent_scope, + single_nested: path_span != root_span, + }); + } else { + return Err((Determined, Weak::No)); + } + } + + // Forbid expanded shadowing to avoid time travel. + if let Some(shadowed_glob) = glob_binding + && shadowing == Shadowing::Restricted + && binding.expansion != LocalExpnId::ROOT + && binding.res() != shadowed_glob.res() + { + self.ambiguity_errors.push(AmbiguityError { + kind: AmbiguityKind::GlobVsExpanded, + ident, + b1: binding, + b2: shadowed_glob, + warning: false, + misc1: AmbiguityErrorMisc::None, + misc2: AmbiguityErrorMisc::None, + }); + } + + if shadowing == Shadowing::Unrestricted + && binding.expansion != LocalExpnId::ROOT + && let NameBindingKind::Import { import, .. } = binding.kind + && matches!(import.kind, ImportKind::MacroExport) + { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + } + + self.record_use(ident, binding, used); + return Ok(binding); + } + + fn finalize_glob_module_binding( + &mut self, + ident: Ident, + binding: Option>, + parent_scope: &ParentScope<'ra>, + finalize: Finalize, + shadowing: Shadowing, + ) -> Result, (Determinacy, Weak)> { + let Finalize { path_span, report_private, used, root_span, .. } = finalize; + + let Some(binding) = binding else { + return Err((Determined, Weak::No)); + }; + + if !self.is_accessible_from(binding.vis, parent_scope.module) { + if report_private { + self.privacy_errors.push(PrivacyError { + ident, + binding, + dedup_span: path_span, + outermost_res: None, + parent_scope: *parent_scope, + single_nested: path_span != root_span, + }); + } else { + return Err((Determined, Weak::No)); + } + } + + if shadowing == Shadowing::Unrestricted + && binding.expansion != LocalExpnId::ROOT + && let NameBindingKind::Import { import, .. } = binding.kind + && matches!(import.kind, ImportKind::MacroExport) + { + self.macro_expanded_macro_export_errors.insert((path_span, binding.span)); + } + + self.record_use(ident, binding, used); + return Ok(binding); + } + + // Checks if a single import can define the `Ident` corresponding to `binding`. + // This is used to check whether we can definitively accept a glob as a resolution. + fn single_import_can_define_name( + &mut self, + resolution: &RefMut<'_, NameResolution<'ra>>, + binding: Option>, + ns: Namespace, + ignore_import: Option>, + ignore_binding: Option>, + parent_scope: &ParentScope<'ra>, + ) -> bool { + for single_import in &resolution.single_imports { + if ignore_import == Some(*single_import) { + continue; + } + if !self.is_accessible_from(single_import.vis, parent_scope.module) { + continue; + } + if let Some(ignored) = ignore_binding + && let NameBindingKind::Import { import, .. } = ignored.kind + && import == *single_import + { + continue; + } + + let Some(module) = single_import.imported_module.get() else { + return true; + }; + let ImportKind::Single { source, target, target_bindings, .. } = &single_import.kind + else { + unreachable!(); + }; + if source != target { + if target_bindings.iter().all(|binding| binding.get().is_none()) { + return true; + } else if target_bindings[ns].get().is_none() && binding.is_some() { + return true; + } + } + + match self.resolve_ident_in_module( + module, + *source, + ns, + &single_import.parent_scope, + None, + ignore_binding, + ignore_import, + ) { + Err((Determined, _)) => continue, + Ok(binding) + if !self.is_accessible_from(binding.vis, single_import.parent_scope.module) => + { + continue; + } + Ok(_) | Err((Undetermined, _)) => { + return true; + } + } + } + + false + } + /// Validate a local resolution (from ribs). #[instrument(level = "debug", skip(self, all_ribs))] fn validate_res_from_ribs( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index e989209e177a3..5e3dc463f89af 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -22,7 +22,7 @@ use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::hygiene::LocalExpnId; use rustc_span::{Ident, Span, Symbol, kw, sym}; use smallvec::SmallVec; -use tracing::debug; +use tracing::{debug, instrument}; use crate::Determinacy::{self, *}; use crate::Namespace::*; @@ -235,21 +235,20 @@ pub(crate) struct NameResolution<'ra> { /// Single imports that may define the name in the namespace. /// Imports are arena-allocated, so it's ok to use pointers as keys. pub single_imports: FxIndexSet>, - /// The least shadowable known binding for this name, or None if there are no known bindings. - pub binding: Option>, - pub shadowed_glob: Option>, + /// The least shadowable known non-glob binding for this name, or None if there are no known bindings. + pub non_glob_binding: Option>, + pub glob_binding: Option>, } impl<'ra> NameResolution<'ra> { /// Returns the binding for the name if it is known or None if it not known. pub(crate) fn binding(&self) -> Option> { - self.binding.and_then(|binding| { - if !binding.is_glob_import() || self.single_imports.is_empty() { - Some(binding) - } else { - None - } - }) + self.non_glob_binding + .or_else(|| if self.single_imports.is_empty() { self.glob_binding } else { None }) + } + + pub(crate) fn late_binding(&self) -> Option> { + self.non_glob_binding.or_else(|| self.glob_binding) } } @@ -331,77 +330,79 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.check_reserved_macro_name(key.ident, res); self.set_binding_parent_module(binding, module); self.update_resolution(module, key, warn_ambiguity, |this, resolution| { - if let Some(old_binding) = resolution.binding { - if res == Res::Err && old_binding.res() != Res::Err { + if let Some(old_non_glob_binding) = resolution.non_glob_binding { + if res == Res::Err && old_non_glob_binding.res() != Res::Err { // Do not override real bindings with `Res::Err`s from error recovery. return Ok(()); } - match (old_binding.is_glob_import(), binding.is_glob_import()) { - (true, true) => { - // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. - if !binding.is_ambiguity_recursive() - && let NameBindingKind::Import { import: old_import, .. } = - old_binding.kind - && let NameBindingKind::Import { import, .. } = binding.kind - && old_import == import - { - // We should replace the `old_binding` with `binding` regardless - // of whether they has same resolution or not when they are - // imported from the same glob-import statement. - resolution.binding = Some(binding); - } else if res != old_binding.res() { - resolution.binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsGlob, - old_binding, - binding, - warn_ambiguity, - )); - } else if !old_binding.vis.is_at_least(binding.vis, this.tcx) { - // We are glob-importing the same item but with greater visibility. - resolution.binding = Some(binding); - } else if binding.is_ambiguity_recursive() { - resolution.binding = Some(this.new_warn_ambiguity_binding(binding)); - } + + if binding.is_glob_import() { + let (glob_binding, nonglob_binding) = (binding, old_non_glob_binding); + + if key.ns == MacroNS + && nonglob_binding.expansion != LocalExpnId::ROOT + && glob_binding.res() != nonglob_binding.res() + { + resolution.non_glob_binding = Some(this.new_ambiguity_binding( + AmbiguityKind::GlobVsExpanded, + nonglob_binding, + glob_binding, + false, + )); } - (old_glob @ true, false) | (old_glob @ false, true) => { - let (glob_binding, nonglob_binding) = - if old_glob { (old_binding, binding) } else { (binding, old_binding) }; - if key.ns == MacroNS - && nonglob_binding.expansion != LocalExpnId::ROOT - && glob_binding.res() != nonglob_binding.res() - { - resolution.binding = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsExpanded, - nonglob_binding, + + if let Some(old_glob) = resolution.glob_binding { + if glob_binding.res() != old_glob.res() { + resolution.glob_binding = Some(this.new_ambiguity_binding( + AmbiguityKind::GlobVsGlob, + old_glob, glob_binding, - false, + warn_ambiguity, )); - } else { - resolution.binding = Some(nonglob_binding); - } - - if let Some(old_shadowed_glob) = resolution.shadowed_glob { - assert!(old_shadowed_glob.is_glob_import()); - if glob_binding.res() != old_shadowed_glob.res() { - resolution.shadowed_glob = Some(this.new_ambiguity_binding( - AmbiguityKind::GlobVsGlob, - old_shadowed_glob, - glob_binding, - false, - )); - } else if !old_shadowed_glob.vis.is_at_least(binding.vis, this.tcx) { - resolution.shadowed_glob = Some(glob_binding); - } - } else { - resolution.shadowed_glob = Some(glob_binding); + } else if !old_glob.vis.is_at_least(glob_binding.vis, this.tcx) { + resolution.glob_binding = Some(glob_binding); } + } else { + resolution.glob_binding = Some(glob_binding); } - (false, false) => { - return Err(old_binding); + } else { + return Err(old_non_glob_binding); + } + } else if let Some(old_glob_binding) = resolution.glob_binding { + if binding.is_glob_import() { + // FIXME: remove `!binding.is_ambiguity_recursive()` after delete the warning ambiguity. + if !binding.is_ambiguity_recursive() + && let NameBindingKind::Import { import: old_import, .. } = + old_glob_binding.kind + && let NameBindingKind::Import { import, .. } = binding.kind + && old_import == import + { + // We should replace the `old_binding` with `binding` regardless + // of whether they has same resolution or not when they are + // imported from the same glob-import statement. + resolution.glob_binding = Some(binding); + } else if res != old_glob_binding.res() { + resolution.glob_binding = Some(this.new_ambiguity_binding( + AmbiguityKind::GlobVsGlob, + old_glob_binding, + binding, + warn_ambiguity, + )); + } else if !old_glob_binding.vis.is_at_least(binding.vis, this.tcx) { + // We are glob-importing the same item but with greater visibility. + resolution.glob_binding = Some(binding); + } else if binding.is_ambiguity_recursive() { + resolution.glob_binding = Some(this.new_warn_ambiguity_binding(binding)); } + } else { + resolution.non_glob_binding = Some(binding); } } else { - resolution.binding = Some(binding); + if binding.is_glob_import() { + resolution.glob_binding = Some(binding); + } else { + resolution.non_glob_binding = Some(binding); + } } Ok(()) @@ -611,6 +612,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { self.throw_unresolved_import_error(errors, glob_error); } + #[instrument(skip(self), level = "debug")] pub(crate) fn check_hidden_glob_reexports( &mut self, exported_ambiguities: FxHashSet>, @@ -618,8 +620,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for module in self.arenas.local_modules().iter() { for (key, resolution) in self.resolutions(*module).borrow().iter() { let resolution = resolution.borrow(); + debug!(?resolution); - let Some(binding) = resolution.binding else { continue }; + let Some(binding) = resolution.late_binding() else { continue }; if let NameBindingKind::Import { import, .. } = binding.kind && let Some((amb_binding, _)) = binding.ambiguity @@ -639,7 +642,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - if let Some(glob_binding) = resolution.shadowed_glob { + if let Some(glob_binding) = resolution.glob_binding { if binding.res() != Res::Err && glob_binding.res() != Res::Err && let NameBindingKind::Import { import: glob_import, .. } = @@ -1162,7 +1165,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return None; } // Never suggest the same name match *resolution.borrow() { - NameResolution { binding: Some(name_binding), .. } => { + NameResolution { non_glob_binding: Some(name_binding), .. } => { match name_binding.kind { NameBindingKind::Import { binding, .. } => { match binding.kind { diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index ac7bdda41954e..b5bd88c1059f6 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3441,7 +3441,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { }; ident.span.normalize_to_macros_2_0_and_adjust(module.expansion); let key = BindingKey::new(ident, ns); - let mut binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); + let mut binding = + self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.late_binding()); debug!(?binding); if binding.is_none() { // We could not find the trait item in the correct namespace. @@ -3452,7 +3453,8 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { _ => ns, }; let key = BindingKey::new(ident, ns); - binding = self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.binding); + binding = + self.r.resolution(module, key).try_borrow().ok().and_then(|r| r.late_binding()); debug!(?binding); } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index d5dd3bdb6cd8e..2bdb5df82c7c9 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -881,8 +881,10 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { fn lookup_doc_alias_name(&mut self, path: &[Segment], ns: Namespace) -> Option<(DefId, Ident)> { let find_doc_alias_name = |r: &mut Resolver<'ra, '_>, m: Module<'ra>, item_name: Symbol| { for resolution in r.resolutions(m).borrow().values() { - let Some(did) = - resolution.borrow().binding.and_then(|binding| binding.res().opt_def_id()) + let Some(did) = resolution + .borrow() + .late_binding() + .and_then(|binding| binding.res().opt_def_id()) else { continue; }; @@ -1457,15 +1459,16 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { self.resolve_path(mod_path, None, None) { let resolutions = self.r.resolutions(module).borrow(); - let targets: Vec<_> = - resolutions - .iter() - .filter_map(|(key, resolution)| { - resolution.borrow().binding.map(|binding| binding.res()).and_then( - |res| if filter_fn(res) { Some((key, res)) } else { None }, - ) - }) - .collect(); + let targets: Vec<_> = resolutions + .iter() + .filter_map(|(key, resolution)| { + resolution + .borrow() + .late_binding() + .map(|binding| binding.res()) + .and_then(|res| if filter_fn(res) { Some((key, res)) } else { None }) + }) + .collect(); if let [target] = targets.as_slice() { return Some(TypoSuggestion::single_item_from_ident(target.0.ident, target.1)); } @@ -2298,7 +2301,9 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { let targets = resolutions .borrow() .iter() - .filter_map(|(key, res)| res.borrow().binding.map(|binding| (key, binding.res()))) + .filter_map(|(key, res)| { + res.borrow().late_binding().map(|binding| (key, binding.res())) + }) .filter(|(_, res)| match (kind, res) { (AssocItemKind::Const(..), Res::Def(DefKind::AssocConst, _)) => true, (AssocItemKind::Fn(_), Res::Def(DefKind::AssocFn, _)) => true, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index f0540725416cb..d1510a29b2d87 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -130,6 +130,13 @@ enum Scope<'ra> { BuiltinTypes, } +/// Scopes used for resolving an `Ident` in a `Module`. +#[derive(Debug, Copy, Clone, PartialEq)] +enum ModuleScope { + NonGlobal, + Globs, +} + /// Names from different contexts may want to visit different subsets of all specific scopes /// with different restrictions when looking up the resolution. /// This enum is currently used only for early resolution (imports and macros), @@ -640,7 +647,8 @@ impl<'ra> Module<'ra> { F: FnMut(&mut R, Ident, Namespace, NameBinding<'ra>), { for (key, name_resolution) in resolver.as_mut().resolutions(self).borrow().iter() { - if let Some(binding) = name_resolution.borrow().binding { + let resolution = name_resolution.borrow(); + if let Some(binding) = resolution.non_glob_binding.or_else(|| resolution.glob_binding) { f(resolver, key.ident, key.ns, binding); } } diff --git a/tests/ui/imports/ambiguous-17.rs b/tests/ui/imports/ambiguous-17.rs index 28c9c1cc86486..5bca615527795 100644 --- a/tests/ui/imports/ambiguous-17.rs +++ b/tests/ui/imports/ambiguous-17.rs @@ -1,7 +1,8 @@ //@ check-pass // https://github.com/rust-lang/rust/pull/113099#issuecomment-1638206152 -pub use evp::*; //~ WARNING ambiguous glob re-exports +pub use evp::*; +//~^ WARNING ambiguous glob re-exports pub use handwritten::*; macro_rules! m { diff --git a/tests/ui/imports/ambiguous-17.stderr b/tests/ui/imports/ambiguous-17.stderr index 55bc01095c7b0..8117ece56cf36 100644 --- a/tests/ui/imports/ambiguous-17.stderr +++ b/tests/ui/imports/ambiguous-17.stderr @@ -3,13 +3,14 @@ warning: ambiguous glob re-exports | LL | pub use evp::*; | ^^^^^^ the name `id` in the value namespace is first re-exported here +LL | LL | pub use handwritten::*; | -------------- but the name `id` in the value namespace is also re-exported here | = note: `#[warn(ambiguous_glob_reexports)]` on by default warning: `id` is ambiguous - --> $DIR/ambiguous-17.rs:26:5 + --> $DIR/ambiguous-17.rs:27:5 | LL | id(); | ^^ ambiguous name @@ -24,7 +25,7 @@ LL | pub use evp::*; | ^^^^^^ = help: consider adding an explicit import of `id` to disambiguate note: `id` could also refer to the function imported here - --> $DIR/ambiguous-17.rs:5:9 + --> $DIR/ambiguous-17.rs:6:9 | LL | pub use handwritten::*; | ^^^^^^^^^^^^^^ diff --git a/tests/ui/imports/ambiguous-4-extern.rs b/tests/ui/imports/ambiguous-4-extern.rs index a045ab3d8a597..a275c2bcf2423 100644 --- a/tests/ui/imports/ambiguous-4-extern.rs +++ b/tests/ui/imports/ambiguous-4-extern.rs @@ -3,11 +3,12 @@ macro_rules! m { () => { - pub fn id() {} + pub fn id() {} }; } -pub use evp::*; //~ WARNING ambiguous glob re-exports +pub use evp::*; +//~^ WARNING ambiguous glob re-exports pub use handwritten::*; mod evp { diff --git a/tests/ui/imports/ambiguous-4-extern.stderr b/tests/ui/imports/ambiguous-4-extern.stderr index 0011973212bc6..20348bd88473f 100644 --- a/tests/ui/imports/ambiguous-4-extern.stderr +++ b/tests/ui/imports/ambiguous-4-extern.stderr @@ -3,13 +3,14 @@ warning: ambiguous glob re-exports | LL | pub use evp::*; | ^^^^^^ the name `id` in the value namespace is first re-exported here +LL | LL | pub use handwritten::*; | -------------- but the name `id` in the value namespace is also re-exported here | = note: `#[warn(ambiguous_glob_reexports)]` on by default warning: `id` is ambiguous - --> $DIR/ambiguous-4-extern.rs:23:5 + --> $DIR/ambiguous-4-extern.rs:24:5 | LL | id(); | ^^ ambiguous name @@ -24,7 +25,7 @@ LL | pub use evp::*; | ^^^^^^ = help: consider adding an explicit import of `id` to disambiguate note: `id` could also refer to the function imported here - --> $DIR/ambiguous-4-extern.rs:11:9 + --> $DIR/ambiguous-4-extern.rs:12:9 | LL | pub use handwritten::*; | ^^^^^^^^^^^^^^ diff --git a/tests/ui/imports/ambiguous-9.rs b/tests/ui/imports/ambiguous-9.rs index 97321512df0ea..0931b62a3a410 100644 --- a/tests/ui/imports/ambiguous-9.rs +++ b/tests/ui/imports/ambiguous-9.rs @@ -5,7 +5,8 @@ pub mod dsl { mod range { pub fn date_range() {} } - pub use self::range::*; //~ WARNING ambiguous glob re-exports + pub use self::range::*; + //~^ WARNING ambiguous glob re-exports use super::prelude::*; } @@ -13,7 +14,8 @@ pub mod prelude { mod t { pub fn date_range() {} } - pub use self::t::*; //~ WARNING ambiguous glob re-exports + pub use self::t::*; + //~^ WARNING ambiguous glob re-exports pub use super::dsl::*; } diff --git a/tests/ui/imports/ambiguous-9.stderr b/tests/ui/imports/ambiguous-9.stderr index 6c7d79174daf6..64e1ec37bc376 100644 --- a/tests/ui/imports/ambiguous-9.stderr +++ b/tests/ui/imports/ambiguous-9.stderr @@ -3,13 +3,14 @@ warning: ambiguous glob re-exports | LL | pub use self::range::*; | ^^^^^^^^^^^^^^ the name `date_range` in the value namespace is first re-exported here +LL | LL | use super::prelude::*; | ----------------- but the name `date_range` in the value namespace is also re-exported here | = note: `#[warn(ambiguous_glob_reexports)]` on by default warning: `date_range` is ambiguous - --> $DIR/ambiguous-9.rs:24:5 + --> $DIR/ambiguous-9.rs:26:5 | LL | date_range(); | ^^^^^^^^^^ ambiguous name @@ -24,7 +25,7 @@ LL | pub use self::range::*; | ^^^^^^^^^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate note: `date_range` could also refer to the function imported here - --> $DIR/ambiguous-9.rs:9:9 + --> $DIR/ambiguous-9.rs:10:9 | LL | use super::prelude::*; | ^^^^^^^^^^^^^^^^^ @@ -32,15 +33,16 @@ LL | use super::prelude::*; = note: `#[warn(ambiguous_glob_imports)]` on by default warning: ambiguous glob re-exports - --> $DIR/ambiguous-9.rs:16:13 + --> $DIR/ambiguous-9.rs:17:13 | LL | pub use self::t::*; | ^^^^^^^^^^ the name `date_range` in the value namespace is first re-exported here +LL | LL | pub use super::dsl::*; | ------------- but the name `date_range` in the value namespace is also re-exported here warning: `date_range` is ambiguous - --> $DIR/ambiguous-9.rs:24:5 + --> $DIR/ambiguous-9.rs:26:5 | LL | date_range(); | ^^^^^^^^^^ ambiguous name @@ -49,13 +51,13 @@ LL | date_range(); = note: for more information, see issue #114095 = note: ambiguous because of multiple glob imports of a name in the same module note: `date_range` could refer to the function imported here - --> $DIR/ambiguous-9.rs:20:5 + --> $DIR/ambiguous-9.rs:22:5 | LL | use dsl::*; | ^^^^^^ = help: consider adding an explicit import of `date_range` to disambiguate note: `date_range` could also refer to the function imported here - --> $DIR/ambiguous-9.rs:21:5 + --> $DIR/ambiguous-9.rs:23:5 | LL | use prelude::*; | ^^^^^^^^^^ diff --git a/tests/ui/imports/issue-56125.rs b/tests/ui/imports/issue-56125.rs index 4e7e7ac67c572..a30ac36473bdd 100644 --- a/tests/ui/imports/issue-56125.rs +++ b/tests/ui/imports/issue-56125.rs @@ -15,7 +15,7 @@ mod m2 { mod m3 { mod empty {} use empty::issue_56125; //~ ERROR unresolved import `empty::issue_56125` - use issue_56125::*; //~ ERROR `issue_56125` is ambiguous + use issue_56125::*; } fn main() {} diff --git a/tests/ui/imports/issue-56125.stderr b/tests/ui/imports/issue-56125.stderr index 81336d51df4c6..8c4b11c904480 100644 --- a/tests/ui/imports/issue-56125.stderr +++ b/tests/ui/imports/issue-56125.stderr @@ -54,24 +54,7 @@ LL | use issue_56125::non_last_segment::non_last_segment::*; = help: consider adding an explicit import of `issue_56125` to disambiguate = help: or use `self::issue_56125` to refer to this module unambiguously -error[E0659]: `issue_56125` is ambiguous - --> $DIR/issue-56125.rs:18:9 - | -LL | use issue_56125::*; - | ^^^^^^^^^^^ ambiguous name - | - = note: ambiguous because of a conflict between a name from a glob import and an outer scope during import or macro resolution - = note: `issue_56125` could refer to a crate passed with `--extern` - = help: use `::issue_56125` to refer to this crate unambiguously -note: `issue_56125` could also refer to the module imported here - --> $DIR/issue-56125.rs:18:9 - | -LL | use issue_56125::*; - | ^^^^^^^^^^^^^^ - = help: consider adding an explicit import of `issue_56125` to disambiguate - = help: or use `self::issue_56125` to refer to this module unambiguously - -error: aborting due to 4 previous errors +error: aborting due to 3 previous errors Some errors have detailed explanations: E0432, E0659. For more information about an error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.rs b/tests/ui/imports/shadow-glob-module-resolution-2.rs index 36bd72658ae84..ce859f7254638 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-2.rs +++ b/tests/ui/imports/shadow-glob-module-resolution-2.rs @@ -13,7 +13,5 @@ use a::*; use e as b; //~^ ERROR: unresolved import `e` use b::c::D as e; -//~^ ERROR: cannot determine resolution for the import -//~| ERROR: cannot determine resolution for the import fn main() { } diff --git a/tests/ui/imports/shadow-glob-module-resolution-2.stderr b/tests/ui/imports/shadow-glob-module-resolution-2.stderr index 644fcb8416289..22d89eeb8a298 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-2.stderr +++ b/tests/ui/imports/shadow-glob-module-resolution-2.stderr @@ -1,17 +1,3 @@ -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-2.rs:15:5 - | -LL | use b::c::D as e; - | ^^^^^^^^^^^^ - -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-2.rs:15:5 - | -LL | use b::c::D as e; - | ^^^^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0432]: unresolved import `e` --> $DIR/shadow-glob-module-resolution-2.rs:13:5 | @@ -21,6 +7,6 @@ LL | use e as b; | no `e` in the root | help: a similar name exists in the module: `a` -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.rs b/tests/ui/imports/shadow-glob-module-resolution-4.rs index 581cdc185d3f3..38fe7d17a367f 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-4.rs +++ b/tests/ui/imports/shadow-glob-module-resolution-4.rs @@ -12,8 +12,6 @@ use e as b; use b::C as e; //~^ ERROR: unresolved import `b::C` -//~| ERROR: cannot determine resolution for the import -//~| ERROR: cannot determine resolution for the import fn e() {} diff --git a/tests/ui/imports/shadow-glob-module-resolution-4.stderr b/tests/ui/imports/shadow-glob-module-resolution-4.stderr index 063beb612b132..d94a59347a5b8 100644 --- a/tests/ui/imports/shadow-glob-module-resolution-4.stderr +++ b/tests/ui/imports/shadow-glob-module-resolution-4.stderr @@ -1,23 +1,9 @@ -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-4.rs:13:5 - | -LL | use b::C as e; - | ^^^^^^^^^ - -error: cannot determine resolution for the import - --> $DIR/shadow-glob-module-resolution-4.rs:13:5 - | -LL | use b::C as e; - | ^^^^^^^^^ - | - = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` - error[E0432]: unresolved import `b::C` --> $DIR/shadow-glob-module-resolution-4.rs:13:5 | LL | use b::C as e; | ^^^^^^^^^ -error: aborting due to 3 previous errors +error: aborting due to 1 previous error For more information about this error, try `rustc --explain E0432`. diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs index 431213e25e462..5e36c2244ebf3 100644 --- a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs +++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.rs @@ -14,8 +14,12 @@ pub use foo::*; pub use bar::*; mod ambiguous { - mod m1 { pub type A = u8; } - mod m2 { pub type A = u8; } + mod m1 { + pub type A = u8; + } + mod m2 { + pub type A = u8; + } pub use self::m1::*; //~^ ERROR ambiguous glob re-exports pub use self::m2::*; diff --git a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr index 07e61dd8643d4..76f17a6c84a1e 100644 --- a/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr +++ b/tests/ui/resolve/issue-107563-ambiguous-glob-reexports.stderr @@ -1,18 +1,18 @@ error[E0659]: `A` is ambiguous - --> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:24 + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:29:24 | LL | pub use ambiguous::A; | ^ ambiguous name | = note: ambiguous because of multiple glob imports of a name in the same module note: `A` could refer to the type alias imported here - --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13 + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:23:13 | LL | pub use self::m1::*; | ^^^^^^^^^^^ = help: consider adding an explicit import of `A` to disambiguate note: `A` could also refer to the type alias imported here - --> $DIR/issue-107563-ambiguous-glob-reexports.rs:21:13 + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:25:13 | LL | pub use self::m2::*; | ^^^^^^^^^^^ @@ -34,7 +34,7 @@ LL | #![deny(ambiguous_glob_reexports)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: ambiguous glob re-exports - --> $DIR/issue-107563-ambiguous-glob-reexports.rs:19:13 + --> $DIR/issue-107563-ambiguous-glob-reexports.rs:23:13 | LL | pub use self::m1::*; | ^^^^^^^^^^^ the name `A` in the type namespace is first re-exported here