From 92ff367be6a4991cdc03b043c5cab3060be8010b Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 4 Aug 2025 17:14:12 +0200 Subject: [PATCH 1/6] introduce, implement and use SmartResolver --- .../rustc_resolve/src/build_reduced_graph.rs | 4 +- compiler/rustc_resolve/src/diagnostics.rs | 222 ++++--- compiler/rustc_resolve/src/ident.rs | 627 ++++++++++++------ compiler/rustc_resolve/src/imports.rs | 41 +- compiler/rustc_resolve/src/late.rs | 22 +- compiler/rustc_resolve/src/lib.rs | 133 ++-- compiler/rustc_resolve/src/macros.rs | 376 +++++------ 7 files changed, 852 insertions(+), 573 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d9671c43b3d8a..193bce13dec12 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -37,7 +37,7 @@ use crate::imports::{ImportData, ImportKind}; use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef}; use crate::{ BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, SmartResolver, Used, VisResolutionError, errors, }; @@ -373,7 +373,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { res, )) }; - match self.r.resolve_path( + match SmartResolver::finalize(self.r, finalize).resolve_path( &segments, None, parent_scope, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index d18554bba1b17..6f91f6683cbb7 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -45,8 +45,8 @@ use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingError, BindingKey, Finalize, ForwardGenericParamBanReason, HasGenericParams, LexicalScopeBinding, MacroRulesScope, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, - PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, UseError, Used, - VisResolutionError, errors as errs, path_names_to_string, + PrivacyError, ResolutionError, Resolver, Scope, ScopeSet, Segment, SmartResolver, UseError, + Used, VisResolutionError, errors as errs, path_names_to_string, }; type Res = def::Res; @@ -465,61 +465,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(errors::RemoveUnnecessaryImport { span }); } - pub(crate) fn lint_if_path_starts_with_module( - &mut self, - finalize: Option, - path: &[Segment], - second_binding: Option>, - ) { - let Some(Finalize { node_id, root_span, .. }) = finalize else { - return; - }; - - let first_name = match path.get(0) { - // In the 2018 edition this lint is a hard error, so nothing to do - Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => { - seg.ident.name - } - _ => return, - }; - - // We're only interested in `use` paths which should start with - // `{{root}}` currently. - if first_name != kw::PathRoot { - return; - } - - match path.get(1) { - // If this import looks like `crate::...` it's already good - Some(Segment { ident, .. }) if ident.name == kw::Crate => return, - // Otherwise go below to see if it's an extern crate - Some(_) => {} - // If the path has length one (and it's `PathRoot` most likely) - // then we don't know whether we're gonna be importing a crate or an - // item in our crate. Defer this lint to elsewhere - None => return, - } - - // If the first element of our path was actually resolved to an - // `ExternCrate` (also used for `crate::...`) then no need to issue a - // warning, this looks all good! - if let Some(binding) = second_binding - && let NameBindingKind::Import { import, .. } = binding.kind - // Careful: we still want to rewrite paths from renamed extern crates. - && let ImportKind::ExternCrate { source: None, .. } = import.kind - { - return; - } - - let diag = BuiltinLintDiag::AbsPathWithModule(root_span); - self.lint_buffer.buffer_lint( - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - node_id, - root_span, - diag, - ); - } - pub(crate) fn add_module_candidates( &self, module: Module<'ra>, @@ -1046,15 +991,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - let Ok((Some(ext), _)) = this.resolve_macro_path( - derive, - Some(MacroKind::Derive), - parent_scope, - false, - false, - None, - None, - ) else { + let Ok((Some(ext), _)) = SmartResolver::Finalize(this) + .resolve_macro_path( + derive, + Some(MacroKind::Derive), + parent_scope, + false, + false, + None, + None, + ) + else { continue; }; suggestions.extend( @@ -1589,15 +1536,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - let Ok(binding) = self.early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ns), - parent_scope, - None, - false, - None, - None, - ) else { + let Ok(binding) = SmartResolver::Speculative(self) + .early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns), + parent_scope, + None, + false, + None, + None, + ) + else { continue; }; @@ -2269,21 +2218,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if ns == TypeNS || ns == ValueNS { let ns_to_try = if ns == TypeNS { ValueNS } else { TypeNS }; let binding = if let Some(module) = module { - self.resolve_ident_in_module( - module, - ident, - ns_to_try, - parent_scope, - None, - ignore_binding, - ignore_import, - ) - .ok() + SmartResolver::Speculative(self) + .resolve_ident_in_module( + module, + ident, + ns_to_try, + parent_scope, + None, + ignore_binding, + ignore_import, + ) + .ok() } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { assert!(ignore_import.is_none()); - match self.resolve_ident_in_lexical_scope( + match SmartResolver::Speculative(self).resolve_ident_in_lexical_scope( ident, ns_to_try, parent_scope, @@ -2296,16 +2246,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, } } else { - self.early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ns_to_try), - parent_scope, - None, - false, - ignore_binding, - ignore_import, - ) - .ok() + SmartResolver::Speculative(self) + .early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns_to_try), + parent_scope, + None, + false, + ignore_binding, + ignore_import, + ) + .ok() }; if let Some(binding) = binding { msg = format!( @@ -2332,7 +2283,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Check whether the name refers to an item in the value namespace. let binding = if let Some(ribs) = ribs { assert!(ignore_import.is_none()); - self.resolve_ident_in_lexical_scope( + SmartResolver::Speculative(self).resolve_ident_in_lexical_scope( ident, ValueNS, parent_scope, @@ -2399,15 +2350,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ) }); - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ValueNS), - parent_scope, - None, - false, - ignore_binding, - ignore_import, - ) { + if let Ok(binding) = SmartResolver::Speculative(self) + .early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ValueNS), + parent_scope, + None, + false, + ignore_binding, + ignore_import, + ) + { let descr = binding.res().descr(); (format!("{descr} `{ident}` is not a crate or module"), suggestion) } else { @@ -3297,6 +3250,63 @@ fn show_candidates( showed } +impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { + pub(crate) fn lint_if_path_starts_with_module( + mut self, + finalize: Option, + path: &[Segment], + second_binding: Option>, + ) { + let Some(Finalize { node_id, root_span, .. }) = finalize else { + return; + }; + + let first_name = match path.get(0) { + // In the 2018 edition this lint is a hard error, so nothing to do + Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => { + seg.ident.name + } + _ => return, + }; + + // We're only interested in `use` paths which should start with + // `{{root}}` currently. + if first_name != kw::PathRoot { + return; + } + + match path.get(1) { + // If this import looks like `crate::...` it's already good + Some(Segment { ident, .. }) if ident.name == kw::Crate => return, + // Otherwise go below to see if it's an extern crate + Some(_) => {} + // If the path has length one (and it's `PathRoot` most likely) + // then we don't know whether we're gonna be importing a crate or an + // item in our crate. Defer this lint to elsewhere + None => return, + } + + // If the first element of our path was actually resolved to an + // `ExternCrate` (also used for `crate::...`) then no need to issue a + // warning, this looks all good! + if let Some(binding) = second_binding + && let NameBindingKind::Import { import, .. } = binding.kind + // Careful: we still want to rewrite paths from renamed extern crates. + && let ImportKind::ExternCrate { source: None, .. } = import.kind + { + return; + } + + let diag = BuiltinLintDiag::AbsPathWithModule(root_span); + self.res_mut().lint_buffer.buffer_lint( + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + node_id, + root_span, + diag, + ); + } +} + #[derive(Debug)] struct UsePlacementFinder { target_module: NodeId, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index f5bc46bf05304..121fd9afd31d8 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -19,7 +19,7 @@ use crate::{ AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError, Resolver, Scope, - ScopeSet, Segment, Used, Weak, errors, + ScopeSet, Segment, SmartResolver, Used, Weak, errors, }; #[derive(Copy, Clone)] @@ -264,6 +264,340 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None } + #[instrument(level = "debug", skip(self))] + pub(crate) fn maybe_resolve_ident_in_module( + &self, + module: ModuleOrUniformRoot<'ra>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'ra>, + ignore_import: Option>, + ) -> Result, Determinacy> { + SmartResolver::Speculative(self) + .resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) + .map_err(|(determinacy, _)| determinacy) + } + + fn finalize_module_binding( + &mut self, + ident: Ident, + binding: Option>, + shadowed_glob: 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)); + } + } + + // Forbid expanded shadowing to avoid time travel. + if let Some(shadowed_glob) = 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); + } + + // 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( + &self, + resolution: &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, bindings, .. } = &single_import.kind else { + unreachable!(); + }; + if source != target { + if bindings.iter().all(|binding| binding.get().binding().is_none()) { + return true; + } else if bindings[ns].get().binding().is_none() && binding.is_some() { + return true; + } + } + + match SmartResolver::Speculative(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 + } + + #[instrument(level = "debug", skip(self))] + pub(crate) fn maybe_resolve_path( + &self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + parent_scope: &ParentScope<'ra>, + ignore_import: Option>, + ) -> PathResult<'ra> { + SmartResolver::Speculative(self).resolve_path_with_ribs( + path, + opt_ns, + parent_scope, + None, + None, + None, + ignore_import, + ) + } +} + +impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { + /// A generic scope visitor. + /// Visits scopes in order to resolve some identifier in them or perform other actions. + /// If the callback returns `Some` result, we stop visiting scopes and return it. + pub(crate) fn visit_scopes( + mut self, + scope_set: ScopeSet<'ra>, + parent_scope: &ParentScope<'ra>, + ctxt: SyntaxContext, + mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option, + ) -> Option { + // General principles: + // 1. Not controlled (user-defined) names should have higher priority than controlled names + // built into the language or standard library. This way we can add new names into the + // language or standard library without breaking user code. + // 2. "Closed set" below means new names cannot appear after the current resolution attempt. + // Places to search (in order of decreasing priority): + // (Type NS) + // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet + // (open set, not controlled). + // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents + // (open, not controlled). + // 3. Extern prelude (open, the open part is from macro expansions, not controlled). + // 4. Tool modules (closed, controlled right now, but not in the future). + // 5. Standard library prelude (de-facto closed, controlled). + // 6. Language prelude (closed, controlled). + // (Value NS) + // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet + // (open set, not controlled). + // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents + // (open, not controlled). + // 3. Standard library prelude (de-facto closed, controlled). + // (Macro NS) + // 1-3. Derive helpers (open, not controlled). All ambiguities with other names + // are currently reported as errors. They should be higher in priority than preludes + // and probably even names in modules according to the "general principles" above. They + // also should be subject to restricted shadowing because are effectively produced by + // derives (you need to resolve the derive first to add helpers into scope), but they + // should be available before the derive is expanded for compatibility. + // It's mess in general, so we are being conservative for now. + // 1-3. `macro_rules` (open, not controlled), loop through `macro_rules` scopes. Have higher + // priority than prelude macros, but create ambiguities with macros in modules. + // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents + // (open, not controlled). Have higher priority than prelude macros, but create + // ambiguities with `macro_rules`. + // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled). + // 4a. User-defined prelude from macro-use + // (open, the open part is from macro expansions, not controlled). + // 4b. "Standard library prelude" part implemented through `macro-use` (closed, controlled). + // 4c. Standard library prelude (de-facto closed, controlled). + // 6. Language prelude: builtin attributes (closed, controlled). + + let rust_2015 = ctxt.edition().is_rust_2015(); + let (ns, macro_kind) = match scope_set { + ScopeSet::All(ns) + | ScopeSet::ModuleAndExternPrelude(ns, _) + | ScopeSet::Late(ns, ..) => (ns, None), + ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), + }; + let module = match scope_set { + // Start with the specified module. + ScopeSet::Late(_, module, _) | ScopeSet::ModuleAndExternPrelude(_, module) => module, + // Jump out of trait or enum modules, they do not act as scopes. + _ => parent_scope.module.nearest_item_scope(), + }; + let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); + let mut scope = match ns { + _ if module_and_extern_prelude => Scope::Module(module, None), + TypeNS | ValueNS => Scope::Module(module, None), + MacroNS => Scope::DeriveHelpers(parent_scope.expansion), + }; + let mut ctxt = ctxt.normalize_to_macros_2_0(); + let mut use_prelude = !module.no_implicit_prelude; + + loop { + let visit = match scope { + // Derive helpers are not in scope when resolving derives in the same container. + Scope::DeriveHelpers(expn_id) => { + !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)) + } + Scope::DeriveHelpersCompat => true, + Scope::MacroRules(macro_rules_scope) => { + // Use "path compression" on `macro_rules` scope chains. This is an optimization + // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. + // As another consequence of this optimization visitors never observe invocation + // scopes for macros that were already expanded. + while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { + if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { + macro_rules_scope.set(next_scope.get()); + } else { + break; + } + } + true + } + Scope::Module(..) => true, + Scope::MacroUsePrelude => use_prelude || rust_2015, + Scope::BuiltinAttrs => true, + Scope::ExternPrelude => use_prelude || module_and_extern_prelude, + Scope::ToolPrelude => use_prelude, + Scope::StdLibPrelude => use_prelude || ns == MacroNS, + Scope::BuiltinTypes => true, + }; + + if visit { + let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; + if let break_result @ Some(..) = visitor(&mut self, scope, use_prelude, ctxt) { + return break_result; + } + } + + scope = match scope { + Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat, + Scope::DeriveHelpers(expn_id) => { + // Derive helpers are not visible to code generated by bang or derive macros. + let expn_data = expn_id.expn_data(); + match expn_data.kind { + ExpnKind::Root + | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { + Scope::DeriveHelpersCompat + } + _ => Scope::DeriveHelpers(expn_data.parent.expect_local()), + } + } + Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), + Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { + MacroRulesScope::Binding(binding) => { + Scope::MacroRules(binding.parent_macro_rules_scope) + } + MacroRulesScope::Invocation(invoc_id) => { + Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) + } + MacroRulesScope::Empty => Scope::Module(module, None), + }, + Scope::Module(..) if module_and_extern_prelude => match ns { + TypeNS => { + ctxt.adjust(ExpnId::root()); + Scope::ExternPrelude + } + ValueNS | MacroNS => break, + }, + Scope::Module(module, prev_lint_id) => { + use_prelude = !module.no_implicit_prelude; + let derive_fallback_lint_id = match scope_set { + ScopeSet::Late(.., lint_id) => lint_id, + _ => None, + }; + match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { + Some((parent_module, lint_id)) => { + Scope::Module(parent_module, lint_id.or(prev_lint_id)) + } + None => { + ctxt.adjust(ExpnId::root()); + match ns { + TypeNS => Scope::ExternPrelude, + ValueNS => Scope::StdLibPrelude, + MacroNS => Scope::MacroUsePrelude, + } + } + } + } + Scope::MacroUsePrelude => Scope::StdLibPrelude, + Scope::BuiltinAttrs => break, // nowhere else to search + Scope::ExternPrelude if module_and_extern_prelude => break, + Scope::ExternPrelude => Scope::ToolPrelude, + Scope::ToolPrelude => Scope::StdLibPrelude, + Scope::StdLibPrelude => match ns { + TypeNS => Scope::BuiltinTypes, + ValueNS => break, // nowhere else to search + MacroNS => Scope::BuiltinAttrs, + }, + Scope::BuiltinTypes => break, // nowhere else to search + }; + } + + None + } + /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. /// More specifically, we proceed up the hierarchy of scopes and return the binding for /// `ident` in the first scope that defines it (or None if no scopes define it). @@ -283,7 +617,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// import resolution. #[instrument(level = "debug", skip(self, ribs))] pub(crate) fn resolve_ident_in_lexical_scope( - &mut self, + mut self, mut ident: Ident, ns: Namespace, parent_scope: &ParentScope<'ra>, @@ -315,7 +649,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let rib_ident = if rib.kind.contains_params() { normalized_ident } else { ident }; if let Some((original_rib_ident_def, res)) = rib.bindings.get_key_value(&rib_ident) { // The ident resolves to a type parameter or local variable. - return Some(LexicalScopeBinding::Res(self.validate_res_from_ribs( + return Some(LexicalScopeBinding::Res(self.reborrow().validate_res_from_ribs( i, rib_ident, *res, @@ -341,7 +675,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => break, } - let item = self.resolve_ident_in_module_unadjusted( + let item = self.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -368,7 +702,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .ok() .map(LexicalScopeBinding::Item) } - /// Resolve an identifier in lexical scope. /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during /// expansion and import resolution (perhaps they can be merged in the future). @@ -376,7 +709,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition. #[instrument(level = "debug", skip(self))] pub(crate) fn early_resolve_ident_in_lexical_scope( - &mut self, + self, orig_ident: Ident, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, @@ -450,7 +783,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut result = Err(Determinacy::Determined); for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - match this.resolve_macro_path( + match this.reborrow().resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, @@ -497,7 +830,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { finalize.map(|f| Finalize { used: Used::Scope, ..f }), ) }; - let binding = this.resolve_ident_in_module_unadjusted( + let binding = this.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -514,7 +847,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { match binding { Ok(binding) => { if let Some(lint_id) = derive_fallback_lint_id { - this.lint_buffer.buffer_lint( + this.res_mut().lint_buffer.buffer_lint( PROC_MACRO_DERIVE_RESOLUTION_FALLBACK, lint_id, orig_ident.span, @@ -556,7 +889,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None => Err(Determinacy::Determined), }, Scope::ExternPrelude => { - match this.extern_prelude_get(ident, finalize.is_some()) { + match this.reborrow().extern_prelude_get(ident, finalize.is_some()) { Some(binding) => Ok((binding, Flags::empty())), None => Err(Determinacy::determined( this.graph_root.unexpanded_invocations.borrow().is_empty(), @@ -570,7 +903,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::StdLibPrelude => { let mut result = Err(Determinacy::Determined); if let Some(prelude) = this.prelude - && let Ok(binding) = this.resolve_ident_in_module_unadjusted( + && let Ok(binding) = this.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(prelude), ident, ns, @@ -687,7 +1020,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { AmbiguityErrorMisc::None } }; - this.ambiguity_errors.push(AmbiguityError { + this.res_mut().ambiguity_errors.push(AmbiguityError { kind, ident: orig_ident, b1: innermost_binding, @@ -723,23 +1056,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_ident_in_module( - &mut self, - module: ModuleOrUniformRoot<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - ignore_import: Option>, - ) -> Result, Determinacy> { - self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) - .map_err(|(determinacy, _)| determinacy) - } - #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_ident_in_module( - &mut self, + self, module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, @@ -776,12 +1095,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ignore_import, ) } - /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. #[instrument(level = "debug", skip(self))] fn resolve_ident_in_module_unadjusted( - &mut self, + mut self, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -812,7 +1130,9 @@ 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()) { + } else if let Some(binding) = + self.reborrow().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. @@ -865,7 +1185,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .find_map(|binding| if binding == ignore_binding { None } else { binding }); if let Some(finalize) = finalize { - return self.finalize_module_binding( + return self.res_mut().finalize_module_binding( ident, binding, if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None }, @@ -875,7 +1195,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ); } - let check_usable = |this: &Self, binding: NameBinding<'ra>| { + let check_usable = |this: Self, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -962,7 +1282,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(None) => {} None => continue, }; - let result = self.resolve_ident_in_module_unadjusted( + let result = self.reborrow().resolve_ident_in_module_unadjusted( ModuleOrUniformRoot::Module(module), ident, ns, @@ -987,133 +1307,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // No resolution and no one else can define the name - determinate error. Err((Determined, Weak::No)) } - - fn finalize_module_binding( - &mut self, - ident: Ident, - binding: Option>, - shadowed_glob: 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)); - } - } - - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = 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); - } - - // 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: &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, bindings, .. } = &single_import.kind else { - unreachable!(); - }; - if source != target { - if bindings.iter().all(|binding| binding.get().binding().is_none()) { - return true; - } else if bindings[ns].get().binding().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( - &mut self, + mut self, rib_index: usize, rib_ident: Ident, mut res: Res, @@ -1133,7 +1330,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else { ResolutionError::ForwardDeclaredGenericParam(rib_ident.name, reason) }; - self.report_error(span, res_error); + self.res_mut().report_error(span, res_error); } assert_eq!(res, Res::Err); return Res::Err; @@ -1209,13 +1406,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ), }; - self.report_error(span, resolution_error); + self.res_mut().report_error(span, resolution_error); } return Res::Err; } RibKind::ConstParamTy => { if let Some(span) = finalize { - self.report_error( + self.res_mut().report_error( span, ParamInTyOfConstParam { name: rib_ident.name }, ); @@ -1224,14 +1421,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } RibKind::InlineAsmSym => { if let Some(span) = finalize { - self.report_error(span, InvalidAsmSym); + self.res_mut().report_error(span, InvalidAsmSym); } return Res::Err; } } } if let Some((span, res_err)) = res_err { - self.report_error(span, res_err); + self.res_mut().report_error(span, res_err); return Res::Err; } } @@ -1252,7 +1449,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::ConstParamTy => { if !self.tcx.features().generic_const_parameter_types() { if let Some(span) = finalize { - self.report_error( + self.res_mut().report_error( span, ResolutionError::ParamInTyOfConstParam { name: rib_ident.name, @@ -1299,7 +1496,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } }; - let _: ErrorGuaranteed = self.report_error(span, error); + let _: ErrorGuaranteed = + self.res_mut().report_error(span, error); } return Res::Err; @@ -1316,7 +1514,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }; if let Some(span) = finalize { - self.report_error( + self.res_mut().report_error( span, ResolutionError::GenericParamsFromOuterItem( res, @@ -1342,7 +1540,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { RibKind::ConstParamTy => { if !self.tcx.features().generic_const_parameter_types() { if let Some(span) = finalize { - self.report_error( + self.res_mut().report_error( span, ResolutionError::ParamInTyOfConstParam { name: rib_ident.name, @@ -1374,7 +1572,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } }; - self.report_error(span, error); + self.res_mut().report_error(span, error); } return Res::Err; @@ -1390,7 +1588,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // This was an attempt to use a const parameter outside its scope. if let Some(span) = finalize { - self.report_error( + self.res_mut().report_error( span, ResolutionError::GenericParamsFromOuterItem( res, @@ -1407,21 +1605,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_path( - &mut self, - path: &[Segment], - opt_ns: Option, // `None` indicates a module path in import - parent_scope: &ParentScope<'ra>, - ignore_import: Option>, - ) -> PathResult<'ra> { - self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import) - } - #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_path( - &mut self, + self, path: &[Segment], opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1441,7 +1627,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } pub(crate) fn resolve_path_with_ribs( - &mut self, + mut self, path: &[Segment], opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1457,18 +1643,23 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); + fn record_segment_res<'r, 'ra, 'tcx>( + mut this: SmartResolver<'r, 'ra, 'tcx>, + finalize: Option, + res: Res, + id: Option, + ) { + if finalize.is_some() + && let Some(id) = id + && !this.partial_res_map.contains_key(&id) + { + assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); + this.res_mut().record_partial_res(id, PartialRes::new(res)); + } + } for (segment_idx, &Segment { ident, id, .. }) in path.iter().enumerate() { debug!("resolve_path ident {} {:?} {:?}", segment_idx, ident, id); - let record_segment_res = |this: &mut Self, res| { - if finalize.is_some() - && let Some(id) = id - && !this.partial_res_map.contains_key(&id) - { - assert!(id != ast::DUMMY_NODE_ID, "Trying to resolve dummy id"); - this.record_partial_res(id, PartialRes::new(res)); - } - }; let is_last = segment_idx + 1 == path.len(); let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS }; @@ -1507,7 +1698,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut ctxt = ident.span.ctxt().normalize_to_macros_2_0(); let self_mod = self.resolve_self(&mut ctxt, parent_scope.module); if let Some(res) = self_mod.res() { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } module = Some(ModuleOrUniformRoot::Module(self_mod)); continue; @@ -1529,7 +1720,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // `::a::b`, `crate::a::b` or `$crate::a::b` let crate_root = self.resolve_crate_root(ident); if let Some(res) = crate_root.res() { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } module = Some(ModuleOrUniformRoot::Module(crate_root)); continue; @@ -1562,21 +1753,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } let binding = if let Some(module) = module { - self.resolve_ident_in_module( - module, - ident, - ns, - parent_scope, - finalize, - ignore_binding, - ignore_import, - ) - .map_err(|(determinacy, _)| determinacy) + self.reborrow() + .resolve_ident_in_module( + module, + ident, + ns, + parent_scope, + finalize, + ignore_binding, + ignore_import, + ) + .map_err(|(determinacy, _)| determinacy) } else if let Some(ribs) = ribs && let Some(TypeNS | ValueNS) = opt_ns { assert!(ignore_import.is_none()); - match self.resolve_ident_in_lexical_scope( + match self.reborrow().resolve_ident_in_lexical_scope( ident, ns, parent_scope, @@ -1588,7 +1780,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Some(LexicalScopeBinding::Item(binding)) => Ok(binding), // we found a local variable or type param Some(LexicalScopeBinding::Res(res)) => { - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - 1, @@ -1597,7 +1789,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => Err(Determinacy::determined(finalize.is_some())), } } else { - self.early_resolve_ident_in_lexical_scope( + self.reborrow().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -1618,8 +1810,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Mark every privacy error in this path with the res to the last element. This allows us // to detect the item the user cares about and either find an alternative import, or tell // the user it is not accessible. - for error in &mut self.privacy_errors[privacy_errors_len..] { - error.outermost_res = Some((res, ident)); + if finalize.is_some() { + for error in + &mut self.reborrow().res_mut().privacy_errors[privacy_errors_len..] + { + error.outermost_res = Some((res, ident)); + } } let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res); @@ -1628,7 +1824,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_had_parse_errors = true; } module = Some(ModuleOrUniformRoot::Module(self.expect_module(def_id))); - record_segment_res(self, res); + record_segment_res(self.reborrow(), finalize, res, id); } else if res == Res::ToolMod && !is_last && opt_ns.is_some() { if binding.is_import() { self.dcx().emit_err(errors::ToolModuleImported { @@ -1641,8 +1837,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } else if res == Res::Err { return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { - self.lint_if_path_starts_with_module(finalize, path, second_binding); - record_segment_res(self, res); + self.reborrow().lint_if_path_starts_with_module( + finalize, + path, + second_binding, + ); + record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, path.len() - segment_idx - 1, @@ -1677,6 +1877,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )); } + let mut this = self.reborrow(); return PathResult::failed( ident, is_last, @@ -1684,7 +1885,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { module_had_parse_errors, module, || { - self.report_path_resolution_error( + this.res_mut().report_path_resolution_error( path, opt_ns, parent_scope, @@ -1701,7 +1902,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.lint_if_path_starts_with_module(finalize, path, second_binding); + self.reborrow().lint_if_path_starts_with_module(finalize, path, second_binding); PathResult::Module(match module { Some(module) => module, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index 156df45147fd7..aa6db1b2bab04 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -35,7 +35,8 @@ use crate::errors::{ use crate::{ AmbiguityError, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, + PerNS, ResolutionError, Resolver, ScopeSet, Segment, SmartResolver, Used, module_to_string, + names_to_string, }; type Res = def::Res; @@ -943,7 +944,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = self.resolve_path( + let path_res = SmartResolver::Finalize(self).resolve_path( &import.module_path, None, &import.parent_scope, @@ -1060,7 +1061,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(Ident::dummy())); - self.lint_if_path_starts_with_module(Some(finalize), &full_path, None); + SmartResolver::Finalize(self).lint_if_path_starts_with_module( + Some(finalize), + &full_path, + None, + ); } if let ModuleOrUniformRoot::Module(module) = module @@ -1103,14 +1108,16 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // importing it if available. let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); - if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.resolve_path( - &path, - None, - &import.parent_scope, - Some(finalize), - ignore_binding, - None, - ) { + if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = + SmartResolver::Finalize(self).resolve_path( + &path, + None, + &import.parent_scope, + Some(finalize), + ignore_binding, + None, + ) + { let res = module.res().map(|r| (r, ident)); for error in &mut self.privacy_errors[privacy_errors_len..] { error.outermost_res = res; @@ -1121,7 +1128,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_err = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = this.resolve_ident_in_module( + let binding = SmartResolver::Finalize(this).resolve_ident_in_module( module, ident, ns, @@ -1184,7 +1191,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_failed = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = this.resolve_ident_in_module( + let binding = SmartResolver::Finalize(this).resolve_ident_in_module( module, ident, ns, @@ -1373,7 +1380,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { - this.lint_if_path_starts_with_module(Some(finalize), &full_path, Some(binding)); + SmartResolver::Finalize(this).lint_if_path_starts_with_module( + Some(finalize), + &full_path, + Some(binding), + ); } }); } @@ -1426,7 +1437,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - match this.early_resolve_ident_in_lexical_scope( + match SmartResolver::Speculative(this).early_resolve_ident_in_lexical_scope( target, ScopeSet::All(ns), &import.parent_scope, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 163e4b5b7a949..dd79fe391d34e 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -41,8 +41,8 @@ use tracing::{debug, instrument, trace}; use crate::{ BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, TyCtxt, UseError, - Used, errors, path_names_to_string, rustdoc, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, SmartResolver, + TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -1451,7 +1451,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident: Ident, ns: Namespace, ) -> Option> { - self.r.resolve_ident_in_lexical_scope( + SmartResolver::Finalize(self.r).resolve_ident_in_lexical_scope( ident, ns, &self.parent_scope, @@ -1468,7 +1468,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { finalize: Option, ignore_binding: Option>, ) -> Option> { - self.r.resolve_ident_in_lexical_scope( + SmartResolver::Finalize(self.r).resolve_ident_in_lexical_scope( ident, ns, &self.parent_scope, @@ -1484,7 +1484,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import finalize: Option, ) -> PathResult<'ra> { - self.r.resolve_path_with_ribs( + SmartResolver::Finalize(self.r).resolve_path_with_ribs( path, opt_ns, &self.parent_scope, @@ -4466,9 +4466,15 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; - if let Ok((_, res)) = - self.r.resolve_macro_path(&path, None, &self.parent_scope, false, false, None, None) - { + if let Ok((_, res)) = SmartResolver::Finalize(self.r).resolve_macro_path( + &path, + None, + &self.parent_scope, + false, + false, + None, + None, + ) { return Ok(Some(PartialRes::new(res))); } } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 6b034c5129f39..85c512dc3426d 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -24,6 +24,7 @@ use std::cell::{Cell, Ref, RefCell}; use std::collections::BTreeSet; use std::fmt; +use std::ops::Deref; use std::sync::Arc; use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion}; @@ -2177,48 +2178,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option> { - 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 { - record_use = Some(binding); - } - 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 { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) - } else { - self.cstore_mut().maybe_process_path_extern(self.tcx, ident.name) - }; - 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(binding) = record_use { - self.record_use(ident, binding, Used::Scope); - } - - binding - } - /// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>` /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, @@ -2423,3 +2382,93 @@ impl Finalize { pub fn provide(providers: &mut Providers) { providers.registered_tools = macros::registered_tools; } + +enum SmartResolver<'r, 'ra, 'tcx> { + Speculative(&'r Resolver<'ra, 'tcx>), + Finalize(&'r mut Resolver<'ra, 'tcx>), +} + +impl<'ra, 'tcx> Deref for SmartResolver<'_, 'ra, 'tcx> { + type Target = Resolver<'ra, 'tcx>; + + fn deref(&self) -> &Self::Target { + match self { + SmartResolver::Speculative(resolver) => resolver, + SmartResolver::Finalize(resolver) => resolver, + } + } +} + +impl<'ra, 'tcx, T> AsRef for SmartResolver<'_, 'ra, 'tcx> +where + T: ?Sized, + ::Target: AsRef, +{ + fn as_ref(&self) -> &T { + self.deref().as_ref() + } +} + +impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { + fn finalize(res: &'r mut Resolver<'ra, 'tcx>, finalize: bool) -> Self { + if finalize { SmartResolver::Finalize(res) } else { SmartResolver::Speculative(res) } + } + + // need manual reborrowing because this is a wrapper on an exclusive ref (can't be `Copy`) + fn reborrow(&mut self) -> SmartResolver<'_, 'ra, 'tcx> { + match self { + SmartResolver::Speculative(r) => SmartResolver::Speculative(&**r), + &mut SmartResolver::Finalize(ref mut r) => SmartResolver::Finalize(&mut **r), + } + } + + // This is the same as implementing `DerefMut`, but this one panics. + /// Panics when this is not a finalize resolver. + #[track_caller] + fn res_mut(&mut self) -> &mut Resolver<'ra, 'tcx> { + match self { + SmartResolver::Speculative(_) => panic!("Can't mutably borrow speculative resolver"), + SmartResolver::Finalize(resolver) => resolver, + } + } + + fn extern_prelude_get(mut self, ident: Ident, finalize: bool) -> Option> { + 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() { + 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.res_mut().record_use(ident, binding, Used::Other); + } + } + binding + } else { + 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 + } else { + 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) + }) + }); + + if let Some(entry) = self.extern_prelude.get(&norm_ident) { + entry.binding.set(binding); + } + + binding + } +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4e3c0cd5bc00e..bf9d5c3d9c2e9 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -43,7 +43,7 @@ use crate::imports::Import; use crate::{ BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError, - Resolver, ScopeSet, Segment, Used, + Resolver, ScopeSet, Segment, SmartResolver, Used, }; type Res = def::Res; @@ -403,7 +403,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { for (i, resolution) in entry.resolutions.iter_mut().enumerate() { if resolution.exts.is_none() { resolution.exts = Some( - match self.resolve_macro_path( + match SmartResolver::Finalize(self).resolve_macro_path( &resolution.path, Some(MacroKind::Derive), &parent_scope, @@ -568,7 +568,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option, suggestion_span: Option, ) -> Result<(Arc, Res), Indeterminate> { - let (ext, res) = match self.resolve_macro_or_delegation_path( + let (ext, res) = match SmartResolver::Finalize(self).resolve_macro_or_delegation_path( path, Some(kind), parent_scope, @@ -713,133 +713,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok((ext, res)) } - pub(crate) fn resolve_macro_path( - &mut self, - path: &ast::Path, - kind: Option, - parent_scope: &ParentScope<'ra>, - trace: bool, - force: bool, - ignore_import: Option>, - suggestion_span: Option, - ) -> Result<(Option>, Res), Determinacy> { - self.resolve_macro_or_delegation_path( - path, - kind, - parent_scope, - trace, - force, - None, - None, - ignore_import, - suggestion_span, - ) - } - - fn resolve_macro_or_delegation_path( - &mut self, - ast_path: &ast::Path, - kind: Option, - parent_scope: &ParentScope<'ra>, - trace: bool, - force: bool, - deleg_impl: Option, - invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - ignore_import: Option>, - suggestion_span: Option, - ) -> Result<(Option>, Res), Determinacy> { - let path_span = ast_path.span; - let mut path = Segment::from_path(ast_path); - - // Possibly apply the macro helper hack - if deleg_impl.is_none() - && kind == Some(MacroKind::Bang) - && let [segment] = path.as_slice() - && segment.ident.span.ctxt().outer_expn_data().local_inner_macros - { - let root = Ident::new(kw::DollarCrate, segment.ident.span); - path.insert(0, Segment::from_ident(root)); - } - - let res = if deleg_impl.is_some() || path.len() > 1 { - let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; - let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { - PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), - PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), - PathResult::NonModule(..) - | PathResult::Indeterminate - | PathResult::Failed { .. } => Err(Determinacy::Determined), - PathResult::Module(ModuleOrUniformRoot::Module(module)) => { - Ok(module.res().unwrap()) - } - PathResult::Module(..) => unreachable!(), - }; - - if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.multi_segment_macro_resolutions.push(( - path, - path_span, - kind, - *parent_scope, - res.ok(), - ns, - )); - } - - self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); - res - } else { - let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); - let binding = self.early_resolve_ident_in_lexical_scope( - path[0].ident, - scope_set, - parent_scope, - None, - force, - None, - None, - ); - if let Err(Determinacy::Undetermined) = binding { - return Err(Determinacy::Undetermined); - } - - if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.single_segment_macro_resolutions.push(( - path[0].ident, - kind, - *parent_scope, - binding.ok(), - suggestion_span, - )); - } - - let res = binding.map(|binding| binding.res()); - self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); - self.report_out_of_scope_macro_calls( - ast_path, - parent_scope, - invoc_in_mod_inert_attr, - binding.ok(), - ); - res - }; - - let res = res?; - let ext = match deleg_impl { - Some(impl_def_id) => match res { - def::Res::Def(DefKind::Trait, def_id) => { - let edition = self.tcx.sess.edition(); - Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) - } - _ => None, - }, - None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), - }; - Ok((ext, res)) - } - pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { let check_consistency = |this: &Self, path: &[Segment], @@ -878,7 +751,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for seg in &mut path { seg.id = None; } - match self.resolve_path( + match SmartResolver::Finalize(self).resolve_path( &path, Some(ns), &parent_scope, @@ -950,7 +823,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match self.early_resolve_ident_in_lexical_scope( + match SmartResolver::Finalize(self).early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1005,7 +878,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = self.early_resolve_ident_in_lexical_scope( + let _ = SmartResolver::Finalize(self).early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1090,60 +963,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn report_out_of_scope_macro_calls( - &mut self, - path: &ast::Path, - parent_scope: &ParentScope<'ra>, - invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option>, - ) { - if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr - && let Some(binding) = binding - // This is a `macro_rules` itself, not some import. - && let NameBindingKind::Res(res) = binding.kind - && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res - // And the `macro_rules` is defined inside the attribute's module, - // so it cannot be in scope unless imported. - && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id()) - { - // Try to resolve our ident ignoring `macro_rules` scopes. - // If such resolution is successful and gives the same result - // (e.g. if the macro is re-imported), then silence the lint. - let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); - let fallback_binding = self.early_resolve_ident_in_lexical_scope( - path.segments[0].ident, - ScopeSet::Macro(MacroKind::Bang), - &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, - None, - false, - None, - None, - ); - if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) { - let location = match parent_scope.module.kind { - ModuleKind::Def(kind, def_id, name) => { - if let Some(name) = name { - format!("{} `{name}`", kind.descr(def_id)) - } else { - "the crate root".to_string() - } - } - ModuleKind::Block => "this scope".to_string(), - }; - self.tcx.sess.psess.buffer_lint( - OUT_OF_SCOPE_MACRO_CALLS, - path.span, - node_id, - BuiltinLintDiag::OutOfScopeMacroCalls { - span: path.span, - path: pprust::path_to_string(path), - location, - }, - ); - } - } - } - pub(crate) fn check_reserved_macro_name(&self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. @@ -1236,3 +1055,186 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok(false) } } + +impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { + pub(crate) fn resolve_macro_path( + self, + path: &ast::Path, + kind: Option, + parent_scope: &ParentScope<'ra>, + trace: bool, + force: bool, + ignore_import: Option>, + suggestion_span: Option, + ) -> Result<(Option>, Res), Determinacy> { + self.resolve_macro_or_delegation_path( + path, + kind, + parent_scope, + trace, + force, + None, + None, + ignore_import, + suggestion_span, + ) + } + + fn resolve_macro_or_delegation_path( + mut self, + ast_path: &ast::Path, + kind: Option, + parent_scope: &ParentScope<'ra>, + trace: bool, + force: bool, + deleg_impl: Option, + invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, + ignore_import: Option>, + suggestion_span: Option, + ) -> Result<(Option>, Res), Determinacy> { + let path_span = ast_path.span; + let mut path = Segment::from_path(ast_path); + + // Possibly apply the macro helper hack + if deleg_impl.is_none() + && kind == Some(MacroKind::Bang) + && let [segment] = path.as_slice() + && segment.ident.span.ctxt().outer_expn_data().local_inner_macros + { + let root = Ident::new(kw::DollarCrate, segment.ident.span); + path.insert(0, Segment::from_ident(root)); + } + + let res = if deleg_impl.is_some() || path.len() > 1 { + let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; + let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { + PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), + PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), + PathResult::NonModule(..) + | PathResult::Indeterminate + | PathResult::Failed { .. } => Err(Determinacy::Determined), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + Ok(module.res().unwrap()) + } + PathResult::Module(..) => unreachable!(), + }; + + if trace { + let kind = kind.expect("macro kind must be specified if tracing is enabled"); + self.res_mut().multi_segment_macro_resolutions.push(( + path, + path_span, + kind, + *parent_scope, + res.ok(), + ns, + )); + } + + self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); + res + } else { + let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); + let binding = self.reborrow().early_resolve_ident_in_lexical_scope( + path[0].ident, + scope_set, + parent_scope, + None, + force, + None, + None, + ); + if let Err(Determinacy::Undetermined) = binding { + return Err(Determinacy::Undetermined); + } + + if trace { + let kind = kind.expect("macro kind must be specified if tracing is enabled"); + self.res_mut().single_segment_macro_resolutions.push(( + path[0].ident, + kind, + *parent_scope, + binding.ok(), + suggestion_span, + )); + } + + let res = binding.map(|binding| binding.res()); + self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); + self.reborrow().report_out_of_scope_macro_calls( + ast_path, + parent_scope, + invoc_in_mod_inert_attr, + binding.ok(), + ); + res + }; + + let res = res?; + let ext = match deleg_impl { + Some(impl_def_id) => match res { + def::Res::Def(DefKind::Trait, def_id) => { + let edition = self.tcx.sess.edition(); + Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) + } + _ => None, + }, + None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), + }; + Ok((ext, res)) + } + + fn report_out_of_scope_macro_calls( + mut self, + path: &ast::Path, + parent_scope: &ParentScope<'ra>, + invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, + binding: Option>, + ) { + if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr + && let Some(binding) = binding + // This is a `macro_rules` itself, not some import. + && let NameBindingKind::Res(res) = binding.kind + && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res + // And the `macro_rules` is defined inside the attribute's module, + // so it cannot be in scope unless imported. + && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id()) + { + // Try to resolve our ident ignoring `macro_rules` scopes. + // If such resolution is successful and gives the same result + // (e.g. if the macro is re-imported), then silence the lint. + let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); + let fallback_binding = self.reborrow().early_resolve_ident_in_lexical_scope( + path.segments[0].ident, + ScopeSet::Macro(MacroKind::Bang), + &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, + None, + false, + None, + None, + ); + if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) { + let location = match parent_scope.module.kind { + ModuleKind::Def(kind, def_id, name) => { + if let Some(name) = name { + format!("{} `{name}`", kind.descr(def_id)) + } else { + "the crate root".to_string() + } + } + ModuleKind::Block => "this scope".to_string(), + }; + self.tcx.sess.psess.buffer_lint( + OUT_OF_SCOPE_MACRO_CALLS, + path.span, + node_id, + BuiltinLintDiag::OutOfScopeMacroCalls { + span: path.span, + path: pprust::path_to_string(path), + location, + }, + ); + } + } + } +} From 3ab8e2f8edf4e5ff703e268baeee38a93b1819e3 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Mon, 4 Aug 2025 17:31:05 +0200 Subject: [PATCH 2/6] Extract `visit_scopes` for `Resolver` and `SmartResolver`. --- compiler/rustc_resolve/src/diagnostics.rs | 1 + compiler/rustc_resolve/src/ident.rs | 209 +++------------------- compiler/rustc_resolve/src/lib.rs | 2 + 3 files changed, 26 insertions(+), 186 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6f91f6683cbb7..6025888f993a1 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -39,6 +39,7 @@ use crate::errors::{ ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition, MaybeMissingMacroRulesName, }; +use crate::ident::ScopeVisitor as _; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::{ diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 121fd9afd31d8..30fcf65a0fd98 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -40,12 +40,15 @@ enum Shadowing { Unrestricted, } -impl<'ra, 'tcx> Resolver<'ra, 'tcx> { +pub(crate) trait ScopeVisitor<'ra, 'tcx> +where + Self: AsRef> + Sized, +{ /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. /// If the callback returns `Some` result, we stop visiting scopes and return it. - pub(crate) fn visit_scopes( - &mut self, + fn visit_scopes( + mut self, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, @@ -127,7 +130,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // As another consequence of this optimization visitors never observe invocation // scopes for macros that were already expanded. while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { - if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { + if let Some(next_scope) = + self.as_ref().output_macro_rules_scopes.get(&invoc_id) + { macro_rules_scope.set(next_scope.get()); } else { break; @@ -146,7 +151,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if visit { let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; - if let break_result @ Some(..) = visitor(self, scope, use_prelude, ctxt) { + if let break_result @ Some(..) = visitor(&mut self, scope, use_prelude, ctxt) { return break_result; } } @@ -169,9 +174,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { MacroRulesScope::Binding(binding) => { Scope::MacroRules(binding.parent_macro_rules_scope) } - MacroRulesScope::Invocation(invoc_id) => { - Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) - } + MacroRulesScope::Invocation(invoc_id) => Scope::MacroRules( + self.as_ref().invocation_parent_scopes[&invoc_id].macro_rules, + ), MacroRulesScope::Empty => Scope::Module(module, None), }, Scope::Module(..) if module_and_extern_prelude => match ns { @@ -187,7 +192,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ScopeSet::Late(.., lint_id) => lint_id, _ => None, }; - match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { + match self.as_ref().hygienic_lexical_parent( + module, + &mut ctxt, + derive_fallback_lint_id, + ) { Some((parent_module, lint_id)) => { Scope::Module(parent_module, lint_id.or(prev_lint_id)) } @@ -217,7 +226,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None } +} + +impl<'ra, 'tcx> ScopeVisitor<'ra, 'tcx> for &mut Resolver<'ra, 'tcx> {} +impl<'r, 'ra, 'tcx> ScopeVisitor<'ra, 'tcx> for SmartResolver<'r, 'ra, 'tcx> {} +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn hygienic_lexical_parent( &self, module: Module<'ra>, @@ -421,183 +435,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { - /// A generic scope visitor. - /// Visits scopes in order to resolve some identifier in them or perform other actions. - /// If the callback returns `Some` result, we stop visiting scopes and return it. - pub(crate) fn visit_scopes( - mut self, - scope_set: ScopeSet<'ra>, - parent_scope: &ParentScope<'ra>, - ctxt: SyntaxContext, - mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option, - ) -> Option { - // General principles: - // 1. Not controlled (user-defined) names should have higher priority than controlled names - // built into the language or standard library. This way we can add new names into the - // language or standard library without breaking user code. - // 2. "Closed set" below means new names cannot appear after the current resolution attempt. - // Places to search (in order of decreasing priority): - // (Type NS) - // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet - // (open set, not controlled). - // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents - // (open, not controlled). - // 3. Extern prelude (open, the open part is from macro expansions, not controlled). - // 4. Tool modules (closed, controlled right now, but not in the future). - // 5. Standard library prelude (de-facto closed, controlled). - // 6. Language prelude (closed, controlled). - // (Value NS) - // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet - // (open set, not controlled). - // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents - // (open, not controlled). - // 3. Standard library prelude (de-facto closed, controlled). - // (Macro NS) - // 1-3. Derive helpers (open, not controlled). All ambiguities with other names - // are currently reported as errors. They should be higher in priority than preludes - // and probably even names in modules according to the "general principles" above. They - // also should be subject to restricted shadowing because are effectively produced by - // derives (you need to resolve the derive first to add helpers into scope), but they - // should be available before the derive is expanded for compatibility. - // It's mess in general, so we are being conservative for now. - // 1-3. `macro_rules` (open, not controlled), loop through `macro_rules` scopes. Have higher - // priority than prelude macros, but create ambiguities with macros in modules. - // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents - // (open, not controlled). Have higher priority than prelude macros, but create - // ambiguities with `macro_rules`. - // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled). - // 4a. User-defined prelude from macro-use - // (open, the open part is from macro expansions, not controlled). - // 4b. "Standard library prelude" part implemented through `macro-use` (closed, controlled). - // 4c. Standard library prelude (de-facto closed, controlled). - // 6. Language prelude: builtin attributes (closed, controlled). - - let rust_2015 = ctxt.edition().is_rust_2015(); - let (ns, macro_kind) = match scope_set { - ScopeSet::All(ns) - | ScopeSet::ModuleAndExternPrelude(ns, _) - | ScopeSet::Late(ns, ..) => (ns, None), - ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind)), - }; - let module = match scope_set { - // Start with the specified module. - ScopeSet::Late(_, module, _) | ScopeSet::ModuleAndExternPrelude(_, module) => module, - // Jump out of trait or enum modules, they do not act as scopes. - _ => parent_scope.module.nearest_item_scope(), - }; - let module_and_extern_prelude = matches!(scope_set, ScopeSet::ModuleAndExternPrelude(..)); - let mut scope = match ns { - _ if module_and_extern_prelude => Scope::Module(module, None), - TypeNS | ValueNS => Scope::Module(module, None), - MacroNS => Scope::DeriveHelpers(parent_scope.expansion), - }; - let mut ctxt = ctxt.normalize_to_macros_2_0(); - let mut use_prelude = !module.no_implicit_prelude; - - loop { - let visit = match scope { - // Derive helpers are not in scope when resolving derives in the same container. - Scope::DeriveHelpers(expn_id) => { - !(expn_id == parent_scope.expansion && macro_kind == Some(MacroKind::Derive)) - } - Scope::DeriveHelpersCompat => true, - Scope::MacroRules(macro_rules_scope) => { - // Use "path compression" on `macro_rules` scope chains. This is an optimization - // used to avoid long scope chains, see the comments on `MacroRulesScopeRef`. - // As another consequence of this optimization visitors never observe invocation - // scopes for macros that were already expanded. - while let MacroRulesScope::Invocation(invoc_id) = macro_rules_scope.get() { - if let Some(next_scope) = self.output_macro_rules_scopes.get(&invoc_id) { - macro_rules_scope.set(next_scope.get()); - } else { - break; - } - } - true - } - Scope::Module(..) => true, - Scope::MacroUsePrelude => use_prelude || rust_2015, - Scope::BuiltinAttrs => true, - Scope::ExternPrelude => use_prelude || module_and_extern_prelude, - Scope::ToolPrelude => use_prelude, - Scope::StdLibPrelude => use_prelude || ns == MacroNS, - Scope::BuiltinTypes => true, - }; - - if visit { - let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; - if let break_result @ Some(..) = visitor(&mut self, scope, use_prelude, ctxt) { - return break_result; - } - } - - scope = match scope { - Scope::DeriveHelpers(LocalExpnId::ROOT) => Scope::DeriveHelpersCompat, - Scope::DeriveHelpers(expn_id) => { - // Derive helpers are not visible to code generated by bang or derive macros. - let expn_data = expn_id.expn_data(); - match expn_data.kind { - ExpnKind::Root - | ExpnKind::Macro(MacroKind::Bang | MacroKind::Derive, _) => { - Scope::DeriveHelpersCompat - } - _ => Scope::DeriveHelpers(expn_data.parent.expect_local()), - } - } - Scope::DeriveHelpersCompat => Scope::MacroRules(parent_scope.macro_rules), - Scope::MacroRules(macro_rules_scope) => match macro_rules_scope.get() { - MacroRulesScope::Binding(binding) => { - Scope::MacroRules(binding.parent_macro_rules_scope) - } - MacroRulesScope::Invocation(invoc_id) => { - Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules) - } - MacroRulesScope::Empty => Scope::Module(module, None), - }, - Scope::Module(..) if module_and_extern_prelude => match ns { - TypeNS => { - ctxt.adjust(ExpnId::root()); - Scope::ExternPrelude - } - ValueNS | MacroNS => break, - }, - Scope::Module(module, prev_lint_id) => { - use_prelude = !module.no_implicit_prelude; - let derive_fallback_lint_id = match scope_set { - ScopeSet::Late(.., lint_id) => lint_id, - _ => None, - }; - match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) { - Some((parent_module, lint_id)) => { - Scope::Module(parent_module, lint_id.or(prev_lint_id)) - } - None => { - ctxt.adjust(ExpnId::root()); - match ns { - TypeNS => Scope::ExternPrelude, - ValueNS => Scope::StdLibPrelude, - MacroNS => Scope::MacroUsePrelude, - } - } - } - } - Scope::MacroUsePrelude => Scope::StdLibPrelude, - Scope::BuiltinAttrs => break, // nowhere else to search - Scope::ExternPrelude if module_and_extern_prelude => break, - Scope::ExternPrelude => Scope::ToolPrelude, - Scope::ToolPrelude => Scope::StdLibPrelude, - Scope::StdLibPrelude => match ns { - TypeNS => Scope::BuiltinTypes, - ValueNS => break, // nowhere else to search - MacroNS => Scope::BuiltinAttrs, - }, - Scope::BuiltinTypes => break, // nowhere else to search - }; - } - - None - } - /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. /// More specifically, we proceed up the hierarchy of scopes and return the binding for /// `ident` in the first scope that defines it (or None if no scopes define it). diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 85c512dc3426d..ebbc7ae61c9b0 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -92,6 +92,8 @@ pub mod rustdoc; pub use macros::registered_tools_ast; +use crate::ident::ScopeVisitor as _; + rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] From 4ce5f4074c6a738af42f4578802b0d6d750c7658 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 5 Aug 2025 18:27:38 +0200 Subject: [PATCH 3/6] address review: dumbify `lint_if_path_starts_with_module` --- compiler/rustc_resolve/src/diagnostics.rs | 110 +++++++++++----------- compiler/rustc_resolve/src/ident.rs | 16 ++-- compiler/rustc_resolve/src/imports.rs | 12 +-- 3 files changed, 65 insertions(+), 73 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 6025888f993a1..3c643b0de96d6 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -466,6 +466,59 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { err.subdiagnostic(errors::RemoveUnnecessaryImport { span }); } + pub(crate) fn lint_if_path_starts_with_module( + &mut self, + finalize: Finalize, + path: &[Segment], + second_binding: Option>, + ) { + let Finalize { node_id, root_span, .. } = finalize; + + let first_name = match path.get(0) { + // In the 2018 edition this lint is a hard error, so nothing to do + Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => { + seg.ident.name + } + _ => return, + }; + + // We're only interested in `use` paths which should start with + // `{{root}}` currently. + if first_name != kw::PathRoot { + return; + } + + match path.get(1) { + // If this import looks like `crate::...` it's already good + Some(Segment { ident, .. }) if ident.name == kw::Crate => return, + // Otherwise go below to see if it's an extern crate + Some(_) => {} + // If the path has length one (and it's `PathRoot` most likely) + // then we don't know whether we're gonna be importing a crate or an + // item in our crate. Defer this lint to elsewhere + None => return, + } + + // If the first element of our path was actually resolved to an + // `ExternCrate` (also used for `crate::...`) then no need to issue a + // warning, this looks all good! + if let Some(binding) = second_binding + && let NameBindingKind::Import { import, .. } = binding.kind + // Careful: we still want to rewrite paths from renamed extern crates. + && let ImportKind::ExternCrate { source: None, .. } = import.kind + { + return; + } + + let diag = BuiltinLintDiag::AbsPathWithModule(root_span); + self.lint_buffer.buffer_lint( + ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, + node_id, + root_span, + diag, + ); + } + pub(crate) fn add_module_candidates( &self, module: Module<'ra>, @@ -3251,63 +3304,6 @@ fn show_candidates( showed } -impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { - pub(crate) fn lint_if_path_starts_with_module( - mut self, - finalize: Option, - path: &[Segment], - second_binding: Option>, - ) { - let Some(Finalize { node_id, root_span, .. }) = finalize else { - return; - }; - - let first_name = match path.get(0) { - // In the 2018 edition this lint is a hard error, so nothing to do - Some(seg) if seg.ident.span.is_rust_2015() && self.tcx.sess.is_rust_2015() => { - seg.ident.name - } - _ => return, - }; - - // We're only interested in `use` paths which should start with - // `{{root}}` currently. - if first_name != kw::PathRoot { - return; - } - - match path.get(1) { - // If this import looks like `crate::...` it's already good - Some(Segment { ident, .. }) if ident.name == kw::Crate => return, - // Otherwise go below to see if it's an extern crate - Some(_) => {} - // If the path has length one (and it's `PathRoot` most likely) - // then we don't know whether we're gonna be importing a crate or an - // item in our crate. Defer this lint to elsewhere - None => return, - } - - // If the first element of our path was actually resolved to an - // `ExternCrate` (also used for `crate::...`) then no need to issue a - // warning, this looks all good! - if let Some(binding) = second_binding - && let NameBindingKind::Import { import, .. } = binding.kind - // Careful: we still want to rewrite paths from renamed extern crates. - && let ImportKind::ExternCrate { source: None, .. } = import.kind - { - return; - } - - let diag = BuiltinLintDiag::AbsPathWithModule(root_span); - self.res_mut().lint_buffer.buffer_lint( - ABSOLUTE_PATHS_NOT_STARTING_WITH_CRATE, - node_id, - root_span, - diag, - ); - } -} - #[derive(Debug)] struct UsePlacementFinder { target_module: NodeId, diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 30fcf65a0fd98..46bfb45c6db25 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -1674,11 +1674,13 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { } else if res == Res::Err { return PathResult::NonModule(PartialRes::new(Res::Err)); } else if opt_ns.is_some() && (is_last || maybe_assoc) { - self.reborrow().lint_if_path_starts_with_module( - finalize, - path, - second_binding, - ); + if let Some(finalize) = finalize { + self.res_mut().lint_if_path_starts_with_module( + finalize, + path, + second_binding, + ); + } record_segment_res(self.reborrow(), finalize, res, id); return PathResult::NonModule(PartialRes::with_unresolved_segments( res, @@ -1739,7 +1741,9 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { } } - self.reborrow().lint_if_path_starts_with_module(finalize, path, second_binding); + if let Some(finalize) = finalize { + self.res_mut().lint_if_path_starts_with_module(finalize, path, second_binding); + } PathResult::Module(match module { Some(module) => module, diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index aa6db1b2bab04..fbcc9955d714d 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -1061,11 +1061,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 2 segments, so the `resolve_path` above won't trigger it. let mut full_path = import.module_path.clone(); full_path.push(Segment::from_ident(Ident::dummy())); - SmartResolver::Finalize(self).lint_if_path_starts_with_module( - Some(finalize), - &full_path, - None, - ); + self.lint_if_path_starts_with_module(finalize, &full_path, None); } if let ModuleOrUniformRoot::Module(module) = module @@ -1380,11 +1376,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { full_path.push(Segment::from_ident(ident)); self.per_ns(|this, ns| { if let Some(binding) = bindings[ns].get().binding().map(|b| b.import_source()) { - SmartResolver::Finalize(this).lint_if_path_starts_with_module( - Some(finalize), - &full_path, - Some(binding), - ); + this.lint_if_path_starts_with_module(finalize, &full_path, Some(binding)); } }); } From 7c54e4709b755fdf1c37b6f52e250329c1f6e741 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 5 Aug 2025 20:00:05 +0200 Subject: [PATCH 4/6] use SmartResolver as self-type in some resolver functions --- compiler/rustc_resolve/src/ident.rs | 345 ++++++++++++------------- compiler/rustc_resolve/src/lib.rs | 85 ++++--- compiler/rustc_resolve/src/macros.rs | 364 +++++++++++++-------------- 3 files changed, 399 insertions(+), 395 deletions(-) diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 46bfb45c6db25..1ed7306c08646 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -278,163 +278,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { None } - #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_ident_in_module( - &self, - module: ModuleOrUniformRoot<'ra>, - ident: Ident, - ns: Namespace, - parent_scope: &ParentScope<'ra>, - ignore_import: Option>, - ) -> Result, Determinacy> { - SmartResolver::Speculative(self) - .resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) - .map_err(|(determinacy, _)| determinacy) - } - - fn finalize_module_binding( - &mut self, - ident: Ident, - binding: Option>, - shadowed_glob: 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)); - } - } - - // Forbid expanded shadowing to avoid time travel. - if let Some(shadowed_glob) = 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); - } - - // 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( - &self, - resolution: &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, bindings, .. } = &single_import.kind else { - unreachable!(); - }; - if source != target { - if bindings.iter().all(|binding| binding.get().binding().is_none()) { - return true; - } else if bindings[ns].get().binding().is_none() && binding.is_some() { - return true; - } - } - - match SmartResolver::Speculative(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 - } - - #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_path( - &self, - path: &[Segment], - opt_ns: Option, // `None` indicates a module path in import - parent_scope: &ParentScope<'ra>, - ignore_import: Option>, - ) -> PathResult<'ra> { - SmartResolver::Speculative(self).resolve_path_with_ribs( - path, - opt_ns, - parent_scope, - None, - None, - None, - ignore_import, - ) - } -} - -impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope. /// More specifically, we proceed up the hierarchy of scopes and return the binding for /// `ident` in the first scope that defines it (or None if no scopes define it). @@ -453,8 +296,8 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { /// Invariant: This must only be called during main resolution, not during /// import resolution. #[instrument(level = "debug", skip(self, ribs))] - pub(crate) fn resolve_ident_in_lexical_scope( - mut self, + pub(crate) fn resolve_ident_in_lexical_scope<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, mut ident: Ident, ns: Namespace, parent_scope: &ParentScope<'ra>, @@ -539,14 +382,15 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { .ok() .map(LexicalScopeBinding::Item) } + /// Resolve an identifier in lexical scope. /// This is a variation of `fn resolve_ident_in_lexical_scope` that can be run during /// expansion and import resolution (perhaps they can be merged in the future). /// The function is used for resolving initial segments of macro paths (e.g., `foo` in /// `foo::bar!();` or `foo!();`) and also for import paths on 2018 edition. #[instrument(level = "debug", skip(self))] - pub(crate) fn early_resolve_ident_in_lexical_scope( - self, + pub(crate) fn early_resolve_ident_in_lexical_scope<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, orig_ident: Ident, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, @@ -893,9 +737,24 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { Err(Determinacy::determined(determinacy == Determinacy::Determined || force)) } + + #[instrument(level = "debug", skip(self))] + pub(crate) fn maybe_resolve_ident_in_module( + &self, + module: ModuleOrUniformRoot<'ra>, + ident: Ident, + ns: Namespace, + parent_scope: &ParentScope<'ra>, + ignore_import: Option>, + ) -> Result, Determinacy> { + SmartResolver::Speculative(self) + .resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) + .map_err(|(determinacy, _)| determinacy) + } + #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_ident_in_module( - self, + pub(crate) fn resolve_ident_in_module<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, @@ -935,8 +794,8 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { /// Attempts to resolve `ident` in namespaces `ns` of `module`. /// Invariant: if `finalize` is `Some`, expansion and import resolution must be complete. #[instrument(level = "debug", skip(self))] - fn resolve_ident_in_module_unadjusted( - mut self, + fn resolve_ident_in_module_unadjusted<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -1032,7 +891,7 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { ); } - let check_usable = |this: Self, binding: NameBinding<'ra>| { + let check_usable = |this: SmartResolver<'r, 'ra, 'tcx>, binding: NameBinding<'ra>| { let usable = this.is_accessible_from(binding.vis, parent_scope.module); if usable { Ok(binding) } else { Err((Determined, Weak::No)) } }; @@ -1144,10 +1003,133 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { // No resolution and no one else can define the name - determinate error. Err((Determined, Weak::No)) } + + fn finalize_module_binding( + &mut self, + ident: Ident, + binding: Option>, + shadowed_glob: 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)); + } + } + + // Forbid expanded shadowing to avoid time travel. + if let Some(shadowed_glob) = 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); + } + + // 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( + &self, + resolution: &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, bindings, .. } = &single_import.kind else { + unreachable!(); + }; + if source != target { + if bindings.iter().all(|binding| binding.get().binding().is_none()) { + return true; + } else if bindings[ns].get().binding().is_none() && binding.is_some() { + return true; + } + } + + match SmartResolver::Speculative(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( - mut self, + fn validate_res_from_ribs<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, rib_index: usize, rib_ident: Ident, mut res: Res, @@ -1442,9 +1424,28 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { res } + #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_path( - self, + pub(crate) fn maybe_resolve_path( + &self, + path: &[Segment], + opt_ns: Option, // `None` indicates a module path in import + parent_scope: &ParentScope<'ra>, + ignore_import: Option>, + ) -> PathResult<'ra> { + SmartResolver::Speculative(self).resolve_path_with_ribs( + path, + opt_ns, + parent_scope, + None, + None, + None, + ignore_import, + ) + } + #[instrument(level = "debug", skip(self))] + pub(crate) fn resolve_path<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, @@ -1463,8 +1464,8 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { ) } - pub(crate) fn resolve_path_with_ribs( - mut self, + pub(crate) fn resolve_path_with_ribs<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index ebbc7ae61c9b0..c037339468376 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -12,6 +12,7 @@ #![allow(rustc::untranslatable_diagnostic)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![doc(rust_logo)] +#![feature(arbitrary_self_types)] #![feature(assert_matches)] #![feature(box_patterns)] #![feature(if_let_guard)] @@ -2180,6 +2181,50 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn extern_prelude_get<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, + ident: Ident, + finalize: bool, + ) -> Option> { + 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() { + 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.res_mut().record_use(ident, binding, Used::Other); + } + } + binding + } else { + 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 + } else { + 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) + }) + }); + + if let Some(entry) = self.extern_prelude.get(&norm_ident) { + entry.binding.set(binding); + } + + binding + } + /// Rustdoc uses this to resolve doc link paths in a recoverable way. `PathResult<'a>` /// isn't something that can be returned because it can't be made to live that long, /// and also it's a private type. Fortunately rustdoc doesn't need to know the error, @@ -2433,44 +2478,4 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { SmartResolver::Finalize(resolver) => resolver, } } - - fn extern_prelude_get(mut self, ident: Ident, finalize: bool) -> Option> { - 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() { - 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.res_mut().record_use(ident, binding, Used::Other); - } - } - binding - } else { - 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 - } else { - 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) - }) - }); - - if let Some(entry) = self.extern_prelude.get(&norm_ident) { - entry.binding.set(binding); - } - - binding - } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index bf9d5c3d9c2e9..46147fc85d891 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -713,6 +713,133 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok((ext, res)) } + pub(crate) fn resolve_macro_path<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, + path: &ast::Path, + kind: Option, + parent_scope: &ParentScope<'ra>, + trace: bool, + force: bool, + ignore_import: Option>, + suggestion_span: Option, + ) -> Result<(Option>, Res), Determinacy> { + self.resolve_macro_or_delegation_path( + path, + kind, + parent_scope, + trace, + force, + None, + None, + ignore_import, + suggestion_span, + ) + } + + fn resolve_macro_or_delegation_path<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, + ast_path: &ast::Path, + kind: Option, + parent_scope: &ParentScope<'ra>, + trace: bool, + force: bool, + deleg_impl: Option, + invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, + ignore_import: Option>, + suggestion_span: Option, + ) -> Result<(Option>, Res), Determinacy> { + let path_span = ast_path.span; + let mut path = Segment::from_path(ast_path); + + // Possibly apply the macro helper hack + if deleg_impl.is_none() + && kind == Some(MacroKind::Bang) + && let [segment] = path.as_slice() + && segment.ident.span.ctxt().outer_expn_data().local_inner_macros + { + let root = Ident::new(kw::DollarCrate, segment.ident.span); + path.insert(0, Segment::from_ident(root)); + } + + let res = if deleg_impl.is_some() || path.len() > 1 { + let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; + let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { + PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), + PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), + PathResult::NonModule(..) + | PathResult::Indeterminate + | PathResult::Failed { .. } => Err(Determinacy::Determined), + PathResult::Module(ModuleOrUniformRoot::Module(module)) => { + Ok(module.res().unwrap()) + } + PathResult::Module(..) => unreachable!(), + }; + + if trace { + let kind = kind.expect("macro kind must be specified if tracing is enabled"); + self.res_mut().multi_segment_macro_resolutions.push(( + path, + path_span, + kind, + *parent_scope, + res.ok(), + ns, + )); + } + + self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); + res + } else { + let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); + let binding = self.reborrow().early_resolve_ident_in_lexical_scope( + path[0].ident, + scope_set, + parent_scope, + None, + force, + None, + None, + ); + if let Err(Determinacy::Undetermined) = binding { + return Err(Determinacy::Undetermined); + } + + if trace { + let kind = kind.expect("macro kind must be specified if tracing is enabled"); + self.res_mut().single_segment_macro_resolutions.push(( + path[0].ident, + kind, + *parent_scope, + binding.ok(), + suggestion_span, + )); + } + + let res = binding.map(|binding| binding.res()); + self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); + self.reborrow().report_out_of_scope_macro_calls( + ast_path, + parent_scope, + invoc_in_mod_inert_attr, + binding.ok(), + ); + res + }; + + let res = res?; + let ext = match deleg_impl { + Some(impl_def_id) => match res { + def::Res::Def(DefKind::Trait, def_id) => { + let edition = self.tcx.sess.edition(); + Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) + } + _ => None, + }, + None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), + }; + Ok((ext, res)) + } + pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { let check_consistency = |this: &Self, path: &[Segment], @@ -963,6 +1090,60 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn report_out_of_scope_macro_calls<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, + path: &ast::Path, + parent_scope: &ParentScope<'ra>, + invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, + binding: Option>, + ) { + if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr + && let Some(binding) = binding + // This is a `macro_rules` itself, not some import. + && let NameBindingKind::Res(res) = binding.kind + && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res + // And the `macro_rules` is defined inside the attribute's module, + // so it cannot be in scope unless imported. + && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id()) + { + // Try to resolve our ident ignoring `macro_rules` scopes. + // If such resolution is successful and gives the same result + // (e.g. if the macro is re-imported), then silence the lint. + let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); + let fallback_binding = self.reborrow().early_resolve_ident_in_lexical_scope( + path.segments[0].ident, + ScopeSet::Macro(MacroKind::Bang), + &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, + None, + false, + None, + None, + ); + if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) { + let location = match parent_scope.module.kind { + ModuleKind::Def(kind, def_id, name) => { + if let Some(name) = name { + format!("{} `{name}`", kind.descr(def_id)) + } else { + "the crate root".to_string() + } + } + ModuleKind::Block => "this scope".to_string(), + }; + self.tcx.sess.psess.buffer_lint( + OUT_OF_SCOPE_MACRO_CALLS, + path.span, + node_id, + BuiltinLintDiag::OutOfScopeMacroCalls { + span: path.span, + path: pprust::path_to_string(path), + location, + }, + ); + } + } + } + pub(crate) fn check_reserved_macro_name(&self, ident: Ident, res: Res) { // Reserve some names that are not quite covered by the general check // performed on `Resolver::builtin_attrs`. @@ -1055,186 +1236,3 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok(false) } } - -impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { - pub(crate) fn resolve_macro_path( - self, - path: &ast::Path, - kind: Option, - parent_scope: &ParentScope<'ra>, - trace: bool, - force: bool, - ignore_import: Option>, - suggestion_span: Option, - ) -> Result<(Option>, Res), Determinacy> { - self.resolve_macro_or_delegation_path( - path, - kind, - parent_scope, - trace, - force, - None, - None, - ignore_import, - suggestion_span, - ) - } - - fn resolve_macro_or_delegation_path( - mut self, - ast_path: &ast::Path, - kind: Option, - parent_scope: &ParentScope<'ra>, - trace: bool, - force: bool, - deleg_impl: Option, - invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - ignore_import: Option>, - suggestion_span: Option, - ) -> Result<(Option>, Res), Determinacy> { - let path_span = ast_path.span; - let mut path = Segment::from_path(ast_path); - - // Possibly apply the macro helper hack - if deleg_impl.is_none() - && kind == Some(MacroKind::Bang) - && let [segment] = path.as_slice() - && segment.ident.span.ctxt().outer_expn_data().local_inner_macros - { - let root = Ident::new(kw::DollarCrate, segment.ident.span); - path.insert(0, Segment::from_ident(root)); - } - - let res = if deleg_impl.is_some() || path.len() > 1 { - let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; - let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { - PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), - PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), - PathResult::NonModule(..) - | PathResult::Indeterminate - | PathResult::Failed { .. } => Err(Determinacy::Determined), - PathResult::Module(ModuleOrUniformRoot::Module(module)) => { - Ok(module.res().unwrap()) - } - PathResult::Module(..) => unreachable!(), - }; - - if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.res_mut().multi_segment_macro_resolutions.push(( - path, - path_span, - kind, - *parent_scope, - res.ok(), - ns, - )); - } - - self.prohibit_imported_non_macro_attrs(None, res.ok(), path_span); - res - } else { - let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); - let binding = self.reborrow().early_resolve_ident_in_lexical_scope( - path[0].ident, - scope_set, - parent_scope, - None, - force, - None, - None, - ); - if let Err(Determinacy::Undetermined) = binding { - return Err(Determinacy::Undetermined); - } - - if trace { - let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.res_mut().single_segment_macro_resolutions.push(( - path[0].ident, - kind, - *parent_scope, - binding.ok(), - suggestion_span, - )); - } - - let res = binding.map(|binding| binding.res()); - self.prohibit_imported_non_macro_attrs(binding.ok(), res.ok(), path_span); - self.reborrow().report_out_of_scope_macro_calls( - ast_path, - parent_scope, - invoc_in_mod_inert_attr, - binding.ok(), - ); - res - }; - - let res = res?; - let ext = match deleg_impl { - Some(impl_def_id) => match res { - def::Res::Def(DefKind::Trait, def_id) => { - let edition = self.tcx.sess.edition(); - Some(Arc::new(SyntaxExtension::glob_delegation(def_id, impl_def_id, edition))) - } - _ => None, - }, - None => self.get_macro(res).map(|macro_data| Arc::clone(¯o_data.ext)), - }; - Ok((ext, res)) - } - - fn report_out_of_scope_macro_calls( - mut self, - path: &ast::Path, - parent_scope: &ParentScope<'ra>, - invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>, - binding: Option>, - ) { - if let Some((mod_def_id, node_id)) = invoc_in_mod_inert_attr - && let Some(binding) = binding - // This is a `macro_rules` itself, not some import. - && let NameBindingKind::Res(res) = binding.kind - && let Res::Def(DefKind::Macro(MacroKind::Bang), def_id) = res - // And the `macro_rules` is defined inside the attribute's module, - // so it cannot be in scope unless imported. - && self.tcx.is_descendant_of(def_id, mod_def_id.to_def_id()) - { - // Try to resolve our ident ignoring `macro_rules` scopes. - // If such resolution is successful and gives the same result - // (e.g. if the macro is re-imported), then silence the lint. - let no_macro_rules = self.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty); - let fallback_binding = self.reborrow().early_resolve_ident_in_lexical_scope( - path.segments[0].ident, - ScopeSet::Macro(MacroKind::Bang), - &ParentScope { macro_rules: no_macro_rules, ..*parent_scope }, - None, - false, - None, - None, - ); - if fallback_binding.ok().and_then(|b| b.res().opt_def_id()) != Some(def_id) { - let location = match parent_scope.module.kind { - ModuleKind::Def(kind, def_id, name) => { - if let Some(name) = name { - format!("{} `{name}`", kind.descr(def_id)) - } else { - "the crate root".to_string() - } - } - ModuleKind::Block => "this scope".to_string(), - }; - self.tcx.sess.psess.buffer_lint( - OUT_OF_SCOPE_MACRO_CALLS, - path.span, - node_id, - BuiltinLintDiag::OutOfScopeMacroCalls { - span: path.span, - path: pprust::path_to_string(path), - location, - }, - ); - } - } - } -} From 6f652d41772fd66ce8b5a9accf47332e8543ec83 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 5 Aug 2025 21:24:14 +0200 Subject: [PATCH 5/6] address review: be smarter about creating/using SmartResolver --- .../rustc_resolve/src/build_reduced_graph.rs | 4 +- compiler/rustc_resolve/src/diagnostics.rs | 70 +++++++++---------- compiler/rustc_resolve/src/ident.rs | 29 +++----- compiler/rustc_resolve/src/imports.rs | 19 ++--- compiler/rustc_resolve/src/late.rs | 14 ++-- .../rustc_resolve/src/late/diagnostics.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 53 +++++++++----- compiler/rustc_resolve/src/macros.rs | 24 ++++--- 8 files changed, 114 insertions(+), 101 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 193bce13dec12..a3709eaea5ecb 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -223,7 +223,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn build_reduced_graph_external(&self, module: Module<'ra>) { for child in self.tcx.module_children(module.def_id()) { - let parent_scope = ParentScope::module(module, self); + let parent_scope = ParentScope::module(module, self.arenas); self.build_reduced_graph_for_external_crate_res(child, parent_scope) } } @@ -1128,7 +1128,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> { }); } else { for ident in single_imports.iter().cloned() { - let result = self.r.maybe_resolve_ident_in_module( + let result = self.r.smart().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, MacroNS, diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 3c643b0de96d6..7db3dbed1a004 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -1045,17 +1045,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - let Ok((Some(ext), _)) = SmartResolver::Finalize(this) - .resolve_macro_path( - derive, - Some(MacroKind::Derive), - parent_scope, - false, - false, - None, - None, - ) - else { + let Ok((Some(ext), _)) = this.smart().resolve_macro_path( + derive, + Some(MacroKind::Derive), + parent_scope, + false, + false, + None, + None, + ) else { continue; }; suggestions.extend( @@ -1590,17 +1588,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }); } for ns in [Namespace::MacroNS, Namespace::TypeNS, Namespace::ValueNS] { - let Ok(binding) = SmartResolver::Speculative(self) - .early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ns), - parent_scope, - None, - false, - None, - None, - ) - else { + let Ok(binding) = self.smart().early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ns), + parent_scope, + None, + false, + None, + None, + ) else { continue; }; @@ -2300,7 +2296,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { _ => None, } } else { - SmartResolver::Speculative(self) + self.smart() .early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns_to_try), @@ -2404,17 +2400,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ) }); - if let Ok(binding) = SmartResolver::Speculative(self) - .early_resolve_ident_in_lexical_scope( - ident, - ScopeSet::All(ValueNS), - parent_scope, - None, - false, - ignore_binding, - ignore_import, - ) - { + if let Ok(binding) = self.smart().early_resolve_ident_in_lexical_scope( + ident, + ScopeSet::All(ValueNS), + parent_scope, + None, + false, + ignore_binding, + ignore_import, + ) { let descr = binding.res().descr(); (format!("{descr} `{ident}` is not a crate or module"), suggestion) } else { @@ -2536,7 +2530,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec, Option)> { // Replace first ident with `self` and check if that is valid. path[0].ident.name = kw::SelfLower; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.smart().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2556,7 +2550,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec, Option)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Crate; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.smart().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some(( @@ -2588,7 +2582,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option<(Vec, Option)> { // Replace first ident with `crate` and check if that is valid. path[0].ident.name = kw::Super; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.smart().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?result); if let PathResult::Module(..) = result { Some((path, None)) } else { None } } @@ -2623,7 +2617,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for name in extern_crate_names.into_iter() { // Replace first ident with a crate name and check if that is valid. path[0].ident.name = name; - let result = self.maybe_resolve_path(&path, None, parent_scope, None); + let result = self.smart().maybe_resolve_path(&path, None, parent_scope, None); debug!(?path, ?name, ?result); if let PathResult::Module(..) = result { return Some((path, None)); diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 1ed7306c08646..c241829ae8144 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -739,16 +739,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_ident_in_module( - &self, + pub(crate) fn maybe_resolve_ident_in_module<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, parent_scope: &ParentScope<'ra>, ignore_import: Option>, ) -> Result, Determinacy> { - SmartResolver::Speculative(self) - .resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) + self.resolve_ident_in_module(module, ident, ns, parent_scope, None, None, ignore_import) .map_err(|(determinacy, _)| determinacy) } @@ -907,7 +906,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 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 self.single_import_can_define_name( + if self.reborrow().single_import_can_define_name( &resolution, binding, ns, @@ -1065,8 +1064,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 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( - &self, + fn single_import_can_define_name<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, resolution: &NameResolution<'ra>, binding: Option>, ns: Namespace, @@ -1102,7 +1101,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - match SmartResolver::Speculative(self).resolve_ident_in_module( + match self.reborrow().resolve_ident_in_module( module, *source, ns, @@ -1426,22 +1425,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_path( - &self, + pub(crate) fn maybe_resolve_path<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, path: &[Segment], opt_ns: Option, // `None` indicates a module path in import parent_scope: &ParentScope<'ra>, ignore_import: Option>, ) -> PathResult<'ra> { - SmartResolver::Speculative(self).resolve_path_with_ribs( - path, - opt_ns, - parent_scope, - None, - None, - None, - ignore_import, - ) + self.resolve_path_with_ribs(path, opt_ns, parent_scope, None, None, None, ignore_import) } #[instrument(level = "debug", skip(self))] pub(crate) fn resolve_path<'r>( diff --git a/compiler/rustc_resolve/src/imports.rs b/compiler/rustc_resolve/src/imports.rs index fbcc9955d714d..4a8cb94657ba2 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -35,8 +35,7 @@ use crate::errors::{ use crate::{ AmbiguityError, AmbiguityKind, BindingKey, Determinacy, Finalize, ImportSuggestion, Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope, PathResult, - PerNS, ResolutionError, Resolver, ScopeSet, Segment, SmartResolver, Used, module_to_string, - names_to_string, + PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string, names_to_string, }; type Res = def::Res; @@ -552,6 +551,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// Resolves all imports for the crate. This method performs the fixed- /// point iteration. pub(crate) fn resolve_imports(&mut self) { + self.speculative = true; let mut prev_indeterminate_count = usize::MAX; let mut indeterminate_count = self.indeterminate_imports.len() * 3; while indeterminate_count < prev_indeterminate_count { @@ -566,6 +566,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + self.speculative = false; } pub(crate) fn finalize_imports(&mut self) { @@ -847,7 +848,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let module = if let Some(module) = import.imported_module.get() { module } else { - let path_res = self.maybe_resolve_path( + let path_res = self.smart_speculative().maybe_resolve_path( &import.module_path, None, &import.parent_scope, @@ -879,7 +880,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if bindings[ns].get() != PendingBinding::Pending { return; }; - let binding_result = this.maybe_resolve_ident_in_module( + let binding_result = this.smart_speculative().maybe_resolve_ident_in_module( module, source, ns, @@ -944,7 +945,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // We'll provide more context to the privacy errors later, up to `len`. let privacy_errors_len = self.privacy_errors.len(); - let path_res = SmartResolver::Finalize(self).resolve_path( + let path_res = self.smart().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1105,7 +1106,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut path = import.module_path.clone(); path.push(Segment::from_ident(ident)); if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = - SmartResolver::Finalize(self).resolve_path( + self.smart().resolve_path( &path, None, &import.parent_scope, @@ -1124,7 +1125,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_err = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = SmartResolver::Finalize(this).resolve_ident_in_module( + let binding = this.smart().resolve_ident_in_module( module, ident, ns, @@ -1187,7 +1188,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut all_ns_failed = true; self.per_ns(|this, ns| { if !type_ns_only || ns == TypeNS { - let binding = SmartResolver::Finalize(this).resolve_ident_in_module( + let binding = this.smart().resolve_ident_in_module( module, ident, ns, @@ -1429,7 +1430,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - match SmartResolver::Speculative(this).early_resolve_ident_in_lexical_scope( + match this.smart().early_resolve_ident_in_lexical_scope( target, ScopeSet::All(ns), &import.parent_scope, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index dd79fe391d34e..44a06f5feb791 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -41,8 +41,8 @@ use tracing::{debug, instrument, trace}; use crate::{ BindingError, BindingKey, Finalize, LexicalScopeBinding, Module, ModuleOrUniformRoot, - NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, SmartResolver, - TyCtxt, UseError, Used, errors, path_names_to_string, rustdoc, + NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, TyCtxt, UseError, + Used, errors, path_names_to_string, rustdoc, }; mod diagnostics; @@ -1424,7 +1424,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { // During late resolution we only track the module component of the parent scope, // although it may be useful to track other components as well for diagnostics. let graph_root = resolver.graph_root; - let parent_scope = ParentScope::module(graph_root, resolver); + let parent_scope = ParentScope::module(graph_root, resolver.arenas); let start_rib_kind = RibKind::Module(graph_root); LateResolutionVisitor { r: resolver, @@ -1451,7 +1451,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { ident: Ident, ns: Namespace, ) -> Option> { - SmartResolver::Finalize(self.r).resolve_ident_in_lexical_scope( + self.r.smart().resolve_ident_in_lexical_scope( ident, ns, &self.parent_scope, @@ -1468,7 +1468,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { finalize: Option, ignore_binding: Option>, ) -> Option> { - SmartResolver::Finalize(self.r).resolve_ident_in_lexical_scope( + self.r.smart().resolve_ident_in_lexical_scope( ident, ns, &self.parent_scope, @@ -1484,7 +1484,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { opt_ns: Option, // `None` indicates a module path in import finalize: Option, ) -> PathResult<'ra> { - SmartResolver::Finalize(self.r).resolve_path_with_ribs( + self.r.smart().resolve_path_with_ribs( path, opt_ns, &self.parent_scope, @@ -4466,7 +4466,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { if qself.is_none() { let path_seg = |seg: &Segment| PathSegment::from_ident(seg.ident); let path = Path { segments: path.iter().map(path_seg).collect(), span, tokens: None }; - if let Ok((_, res)) = SmartResolver::Finalize(self.r).resolve_macro_path( + if let Ok((_, res)) = self.r.smart().resolve_macro_path( &path, None, &self.parent_scope, diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index c8ca57a380fef..e26b3d2ff6e3c 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -2386,7 +2386,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> { // Look for associated items in the current trait. if let Some((module, _)) = self.current_trait_ref - && let Ok(binding) = self.r.maybe_resolve_ident_in_module( + && let Ok(binding) = self.r.smart().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ns, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c037339468376..e056ce59b5903 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -166,11 +166,11 @@ struct ParentScope<'ra> { impl<'ra> ParentScope<'ra> { /// Creates a parent scope with the passed argument used as the module scope component, /// and other scope components set to default empty values. - fn module(module: Module<'ra>, resolver: &Resolver<'ra, '_>) -> ParentScope<'ra> { + fn module(module: Module<'ra>, arenas: &'ra ResolverArenas<'ra>) -> ParentScope<'ra> { ParentScope { module, expansion: LocalExpnId::ROOT, - macro_rules: resolver.arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), + macro_rules: arenas.alloc_macro_rules_scope(MacroRulesScope::Empty), derives: &[], } } @@ -1057,6 +1057,9 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, + /// Are we in speculative or final resolution. + speculative: bool, + prelude: Option>, extern_prelude: FxIndexMap>, @@ -1528,6 +1531,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // The outermost module has def ID 0; this is not reflected in the // AST. graph_root, + speculative: false, // Only set/cleared in Resolver::resolve_imports prelude: None, extern_prelude, @@ -1645,7 +1649,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { impl_trait_names: Default::default(), }; - let root_parent_scope = ParentScope::module(graph_root, &resolver); + let root_parent_scope = ParentScope::module(graph_root, resolver.arenas); resolver.invocation_parent_scopes.insert(LocalExpnId::ROOT, root_parent_scope); resolver.feed_visibility(crate_feed, Visibility::Public); @@ -1793,6 +1797,18 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } + fn smart_speculative(&self) -> SmartResolver<'_, 'ra, 'tcx> { + SmartResolver::Speculative(self) + } + + fn smart(&mut self) -> SmartResolver<'_, 'ra, 'tcx> { + if self.speculative { + SmartResolver::Speculative(self) + } else { + SmartResolver::Finalize(self) + } + } + /// Runs the function on each namespace. fn per_ns(&mut self, mut f: F) { f(self, TypeNS); @@ -2003,14 +2019,17 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // Do not report the lint if the macro name resolves in stdlib prelude // even without the problematic `macro_use` import. let found_in_stdlib_prelude = self.prelude.is_some_and(|prelude| { - self.maybe_resolve_ident_in_module( - ModuleOrUniformRoot::Module(prelude), - ident, - MacroNS, - &ParentScope::module(self.empty_module, self), - None, - ) - .is_ok() + let empty_module = self.empty_module; + let arenas = self.arenas; + self.smart() + .maybe_resolve_ident_in_module( + ModuleOrUniformRoot::Module(prelude), + ident, + MacroNS, + &ParentScope::module(empty_module, arenas), + None, + ) + .is_ok() }); if !found_in_stdlib_prelude { self.lint_buffer().buffer_lint( @@ -2254,7 +2273,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { .collect(); let Ok(segments) = segments else { return None }; - match self.maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { + match self.smart().maybe_resolve_path(&segments, Some(ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(module)) => Some(module.res().unwrap()), PathResult::NonModule(path_res) => { path_res.full_res().filter(|res| !matches!(res, Res::Def(DefKind::Ctor(..), _))) @@ -2333,9 +2352,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn resolve_main(&mut self) { let module = self.graph_root; let ident = Ident::with_dummy_span(sym::main); - let parent_scope = &ParentScope::module(module, self); + let parent_scope = &ParentScope::module(module, self.arenas); - let Ok(name_binding) = self.maybe_resolve_ident_in_module( + let Ok(name_binding) = self.smart().maybe_resolve_ident_in_module( ModuleOrUniformRoot::Module(module), ident, ValueNS, @@ -2465,7 +2484,7 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { fn reborrow(&mut self) -> SmartResolver<'_, 'ra, 'tcx> { match self { SmartResolver::Speculative(r) => SmartResolver::Speculative(&**r), - &mut SmartResolver::Finalize(ref mut r) => SmartResolver::Finalize(&mut **r), + SmartResolver::Finalize(r) => SmartResolver::Finalize(&mut **r), } } @@ -2474,7 +2493,9 @@ impl<'r, 'ra, 'tcx> SmartResolver<'r, 'ra, 'tcx> { #[track_caller] fn res_mut(&mut self) -> &mut Resolver<'ra, 'tcx> { match self { - SmartResolver::Speculative(_) => panic!("Can't mutably borrow speculative resolver"), + SmartResolver::Speculative(_) => { + panic!("Can't mutably borrow speculative resolver, mode: {:?}", self.speculative) + } SmartResolver::Finalize(resolver) => resolver, } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 46147fc85d891..6c9e6be6b0929 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -403,7 +403,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> { for (i, resolution) in entry.resolutions.iter_mut().enumerate() { if resolution.exts.is_none() { resolution.exts = Some( - match SmartResolver::Finalize(self).resolve_macro_path( + match self.smart().resolve_macro_path( &resolution.path, Some(MacroKind::Derive), &parent_scope, @@ -568,7 +568,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { invoc_in_mod_inert_attr: Option, suggestion_span: Option, ) -> Result<(Arc, Res), Indeterminate> { - let (ext, res) = match SmartResolver::Finalize(self).resolve_macro_or_delegation_path( + let (ext, res) = match self.smart().resolve_macro_or_delegation_path( path, Some(kind), parent_scope, @@ -763,7 +763,12 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let res = if deleg_impl.is_some() || path.len() > 1 { let ns = if deleg_impl.is_some() { TypeNS } else { MacroNS }; - let res = match self.maybe_resolve_path(&path, Some(ns), parent_scope, ignore_import) { + let res = match self.reborrow().maybe_resolve_path( + &path, + Some(ns), + parent_scope, + ignore_import, + ) { PathResult::NonModule(path_res) if let Some(res) = path_res.full_res() => Ok(res), PathResult::Indeterminate if !force => return Err(Determinacy::Undetermined), PathResult::NonModule(..) @@ -878,7 +883,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for seg in &mut path { seg.id = None; } - match SmartResolver::Finalize(self).resolve_path( + match self.smart().resolve_path( &path, Some(ns), &parent_scope, @@ -905,8 +910,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { path_res { // try to suggest if it's not a macro, maybe a function - if let PathResult::NonModule(partial_res) = - self.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None) + if let PathResult::NonModule(partial_res) = self + .smart() + .maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None) && partial_res.unresolved_segments() == 0 { let sm = self.tcx.sess.source_map(); @@ -950,7 +956,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions); for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions { - match SmartResolver::Finalize(self).early_resolve_ident_in_lexical_scope( + match self.smart().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(kind), &parent_scope, @@ -1005,7 +1011,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let builtin_attrs = mem::take(&mut self.builtin_attrs); for (ident, parent_scope) in builtin_attrs { - let _ = SmartResolver::Finalize(self).early_resolve_ident_in_lexical_scope( + let _ = self.smart().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1206,7 +1212,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let mut indeterminate = false; for ns in namespaces { - match self.maybe_resolve_path(path, Some(*ns), &parent_scope, None) { + match self.smart().maybe_resolve_path(path, Some(*ns), &parent_scope, None) { PathResult::Module(ModuleOrUniformRoot::Module(_)) => return Ok(true), PathResult::NonModule(partial_res) if partial_res.unresolved_segments() == 0 => { return Ok(true); From 75d597ab5102ded71b0b5326dbf2025b38e6a850 Mon Sep 17 00:00:00 2001 From: LorrensP-2158466 Date: Tue, 5 Aug 2025 22:03:20 +0200 Subject: [PATCH 6/6] address review: fn `visit_scopes` only for SmartResolver --- compiler/rustc_resolve/src/diagnostics.rs | 7 +++-- compiler/rustc_resolve/src/ident.rs | 21 +++++++-------- compiler/rustc_resolve/src/lib.rs | 33 ++++++++++++----------- 3 files changed, 30 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 7db3dbed1a004..41abf3ecc69c4 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -39,7 +39,6 @@ use crate::errors::{ ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition, MaybeMissingMacroRulesName, }; -use crate::ident::ScopeVisitor as _; use crate::imports::{Import, ImportKind}; use crate::late::{PatternSource, Rib}; use crate::{ @@ -1026,7 +1025,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> Option { let mut suggestions = Vec::new(); let ctxt = ident.span.ctxt(); - self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { + self.smart().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper); @@ -1045,7 +1044,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if filter_fn(res) { for derive in parent_scope.derives { let parent_scope = &ParentScope { derives: &[], ..*parent_scope }; - let Ok((Some(ext), _)) = this.smart().resolve_macro_path( + let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, @@ -1479,7 +1478,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) { // Bring imported but unused `derive` macros into `macro_map` so we ensure they can be used // for suggestions. - self.visit_scopes( + self.smart().visit_scopes( ScopeSet::Macro(MacroKind::Derive), &parent_scope, ident.span.ctxt(), diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index c241829ae8144..c6d898e5e557e 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -40,19 +40,21 @@ enum Shadowing { Unrestricted, } -pub(crate) trait ScopeVisitor<'ra, 'tcx> -where - Self: AsRef> + Sized, -{ +impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// A generic scope visitor. /// Visits scopes in order to resolve some identifier in them or perform other actions. /// If the callback returns `Some` result, we stop visiting scopes and return it. - fn visit_scopes( - mut self, + pub(crate) fn visit_scopes<'r, T>( + mut self: SmartResolver<'r, 'ra, 'tcx>, scope_set: ScopeSet<'ra>, parent_scope: &ParentScope<'ra>, ctxt: SyntaxContext, - mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option, + mut visitor: impl FnMut( + &mut SmartResolver<'r, 'ra, 'tcx>, + Scope<'ra>, + UsePrelude, + SyntaxContext, + ) -> Option, ) -> Option { // General principles: // 1. Not controlled (user-defined) names should have higher priority than controlled names @@ -226,12 +228,7 @@ where None } -} -impl<'ra, 'tcx> ScopeVisitor<'ra, 'tcx> for &mut Resolver<'ra, 'tcx> {} -impl<'r, 'ra, 'tcx> ScopeVisitor<'ra, 'tcx> for SmartResolver<'r, 'ra, 'tcx> {} - -impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn hygienic_lexical_parent( &self, module: Module<'ra>, diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index e056ce59b5903..31dca7cc3d5e3 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -93,8 +93,6 @@ pub mod rustdoc; pub use macros::registered_tools_ast; -use crate::ident::ScopeVisitor as _; - rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] @@ -1869,21 +1867,26 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| { - match scope { - Scope::Module(module, _) => { - this.traits_in_module(module, assoc_item, &mut found_traits); - } - Scope::StdLibPrelude => { - if let Some(module) = this.prelude { - this.traits_in_module(module, assoc_item, &mut found_traits); + self.smart().visit_scopes( + ScopeSet::All(TypeNS), + parent_scope, + ctxt, + |this, scope, _, _| { + match scope { + Scope::Module(module, _) => { + this.res_mut().traits_in_module(module, assoc_item, &mut found_traits); + } + Scope::StdLibPrelude => { + if let Some(module) = this.prelude { + this.res_mut().traits_in_module(module, assoc_item, &mut found_traits); + } } + Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {} + _ => unreachable!(), } - Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {} - _ => unreachable!(), - } - None::<()> - }); + None::<()> + }, + ); found_traits }