diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index d9671c43b3d8a..a3709eaea5ecb 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, }; @@ -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) } } @@ -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, @@ -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 d18554bba1b17..41abf3ecc69c4 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; @@ -467,13 +467,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { pub(crate) fn lint_if_path_starts_with_module( &mut self, - finalize: Option, + finalize: Finalize, path: &[Segment], second_binding: Option>, ) { - let Some(Finalize { node_id, root_span, .. }) = finalize else { - return; - }; + 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 @@ -1027,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); @@ -1046,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.resolve_macro_path( + let Ok((Some(ext), _)) = this.reborrow().resolve_macro_path( derive, Some(MacroKind::Derive), parent_scope, @@ -1480,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(), @@ -1589,7 +1587,7 @@ 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( + let Ok(binding) = self.smart().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ns), parent_scope, @@ -2269,21 +2267,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 +2295,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() + self.smart() + .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 +2332,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,7 +2399,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { }, ) }); - if let Ok(binding) = self.early_resolve_ident_in_lexical_scope( + if let Ok(binding) = self.smart().early_resolve_ident_in_lexical_scope( ident, ScopeSet::All(ValueNS), parent_scope, @@ -2529,7 +2529,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 } } @@ -2549,7 +2549,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(( @@ -2581,7 +2581,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 } } @@ -2616,7 +2616,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 f5bc46bf05304..c6d898e5e557e 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)] @@ -44,12 +44,17 @@ 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. - pub(crate) 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 @@ -127,7 +132,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 +153,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 +176,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 +194,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)) } @@ -282,8 +293,8 @@ impl<'ra, 'tcx> Resolver<'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>, @@ -315,7 +326,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 +352,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, @@ -375,8 +386,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// 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( - &mut 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>, @@ -450,7 +461,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 +508,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 +525,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 +567,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 +581,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 +698,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, @@ -725,8 +736,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_ident_in_module( - &mut self, + pub(crate) fn maybe_resolve_ident_in_module<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -738,8 +749,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn resolve_ident_in_module( - &mut self, + pub(crate) fn resolve_ident_in_module<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, mut ident: Ident, ns: Namespace, @@ -776,12 +787,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, + fn resolve_ident_in_module_unadjusted<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, module: ModuleOrUniformRoot<'ra>, ident: Ident, ns: Namespace, @@ -812,7 +822,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 +877,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 +887,7 @@ impl<'ra, 'tcx> Resolver<'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)) } }; @@ -891,7 +903,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, @@ -962,7 +974,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, @@ -1049,8 +1061,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( - &mut self, + fn single_import_can_define_name<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, resolution: &NameResolution<'ra>, binding: Option>, ns: Namespace, @@ -1086,7 +1098,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - match self.resolve_ident_in_module( + match self.reborrow().resolve_ident_in_module( module, *source, ns, @@ -1112,8 +1124,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { /// 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, @@ -1133,7 +1145,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 +1221,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 +1236,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 +1264,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 +1311,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 +1329,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 +1355,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 +1387,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } }; - self.report_error(span, error); + self.res_mut().report_error(span, error); } return Res::Err; @@ -1390,7 +1403,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, @@ -1409,8 +1422,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } #[instrument(level = "debug", skip(self))] - pub(crate) fn maybe_resolve_path( - &mut 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>, @@ -1418,10 +1431,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) -> 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, + 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>, @@ -1440,8 +1452,8 @@ impl<'ra, 'tcx> Resolver<'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>, @@ -1457,18 +1469,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 +1524,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 +1546,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 +1579,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 +1606,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 +1615,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 +1636,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 +1650,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 +1663,14 @@ 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); + 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, path.len() - segment_idx - 1, @@ -1677,6 +1705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { )); } + let mut this = self.reborrow(); return PathResult::failed( ident, is_last, @@ -1684,7 +1713,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 +1730,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - self.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 156df45147fd7..4a8cb94657ba2 100644 --- a/compiler/rustc_resolve/src/imports.rs +++ b/compiler/rustc_resolve/src/imports.rs @@ -551,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 { @@ -565,6 +566,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } } + self.speculative = false; } pub(crate) fn finalize_imports(&mut self) { @@ -846,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, @@ -878,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, @@ -943,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 = self.resolve_path( + let path_res = self.smart().resolve_path( &import.module_path, None, &import.parent_scope, @@ -1060,7 +1062,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())); - 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 @@ -1103,14 +1105,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)) = + self.smart().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 +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 = this.resolve_ident_in_module( + let binding = this.smart().resolve_ident_in_module( module, ident, ns, @@ -1184,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 = this.resolve_ident_in_module( + let binding = this.smart().resolve_ident_in_module( module, ident, ns, @@ -1373,7 +1377,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()) { - 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)); } }); } @@ -1426,7 +1430,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { return; } - match 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 163e4b5b7a949..44a06f5feb791 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -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> { - 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> { - 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> { - self.r.resolve_path_with_ribs( + self.r.smart().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)) = self.r.smart().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/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 6b034c5129f39..31dca7cc3d5e3 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)] @@ -24,6 +25,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}; @@ -162,11 +164,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: &[], } } @@ -1053,6 +1055,9 @@ pub struct Resolver<'ra, 'tcx> { graph_root: Module<'ra>, + /// Are we in speculative or final resolution. + speculative: bool, + prelude: Option>, extern_prelude: FxIndexMap>, @@ -1524,6 +1529,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, @@ -1641,7 +1647,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); @@ -1789,6 +1795,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); @@ -1849,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 } @@ -1999,14 +2022,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( @@ -2177,43 +2203,45 @@ 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) => { + 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 { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span); + 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); + } } - Some(binding) - } - None => { + binding + } else { let crate_id = if finalize { - self.cstore_mut().process_path_extern(self.tcx, ident.name, ident.span) + 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) + 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), - } - } + 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(binding) = record_use { - self.record_use(ident, binding, Used::Scope); + if let Some(entry) = self.extern_prelude.get(&norm_ident) { + entry.binding.set(binding); } binding @@ -2248,7 +2276,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(..), _))) @@ -2327,9 +2355,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, @@ -2423,3 +2451,55 @@ 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), + SmartResolver::Finalize(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, mode: {:?}", self.speculative) + } + SmartResolver::Finalize(resolver) => resolver, + } + } +} diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 4e3c0cd5bc00e..6c9e6be6b0929 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 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 self.resolve_macro_or_delegation_path( + let (ext, res) = match self.smart().resolve_macro_or_delegation_path( path, Some(kind), parent_scope, @@ -713,8 +713,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Ok((ext, res)) } - pub(crate) fn resolve_macro_path( - &mut self, + pub(crate) fn resolve_macro_path<'r>( + self: SmartResolver<'r, 'ra, 'tcx>, path: &ast::Path, kind: Option, parent_scope: &ParentScope<'ra>, @@ -736,8 +736,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ) } - fn resolve_macro_or_delegation_path( - &mut self, + fn resolve_macro_or_delegation_path<'r>( + mut self: SmartResolver<'r, 'ra, 'tcx>, ast_path: &ast::Path, kind: Option, parent_scope: &ParentScope<'ra>, @@ -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(..) @@ -777,7 +782,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if trace { let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.multi_segment_macro_resolutions.push(( + self.res_mut().multi_segment_macro_resolutions.push(( path, path_span, kind, @@ -791,7 +796,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { res } else { let scope_set = kind.map_or(ScopeSet::All(MacroNS), ScopeSet::Macro); - let binding = self.early_resolve_ident_in_lexical_scope( + let binding = self.reborrow().early_resolve_ident_in_lexical_scope( path[0].ident, scope_set, parent_scope, @@ -806,7 +811,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if trace { let kind = kind.expect("macro kind must be specified if tracing is enabled"); - self.single_segment_macro_resolutions.push(( + self.res_mut().single_segment_macro_resolutions.push(( path[0].ident, kind, *parent_scope, @@ -817,7 +822,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { 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( + self.reborrow().report_out_of_scope_macro_calls( ast_path, parent_scope, invoc_in_mod_inert_attr, @@ -878,7 +883,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { for seg in &mut path { seg.id = None; } - match 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 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 _ = self.early_resolve_ident_in_lexical_scope( + let _ = self.smart().early_resolve_ident_in_lexical_scope( ident, ScopeSet::Macro(MacroKind::Attr), &parent_scope, @@ -1090,8 +1096,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { } } - fn report_out_of_scope_macro_calls( - &mut self, + 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)>, @@ -1110,7 +1116,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { // 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( + 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 }, @@ -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);