Auto merge of #151820 - petrochenkov:packhyg3, r=nnethercote

resolve: Use `IdentKey` in `resolve_ident_in_scope_set`

Follow up to https://github.com/rust-lang/rust/pull/151550, implements https://github.com/rust-lang/rust/pull/151550#issuecomment-3792971456.

r? @nnethercote
This commit is contained in:
bors 2026-02-02 08:25:12 +00:00
commit f60a0f1bcc
5 changed files with 101 additions and 83 deletions

View file

@ -32,7 +32,7 @@ use rustc_span::edit_distance::find_best_match_for_name;
use rustc_span::edition::Edition;
use rustc_span::hygiene::MacroKind;
use rustc_span::source_map::{SourceMap, Spanned};
use rustc_span::{BytePos, DUMMY_SP, Ident, Span, Symbol, SyntaxContext, kw, sym};
use rustc_span::{BytePos, Ident, Span, Symbol, SyntaxContext, kw, sym};
use thin_vec::{ThinVec, thin_vec};
use tracing::{debug, instrument};
@ -41,6 +41,7 @@ use crate::errors::{
ExplicitUnsafeTraits, MacroDefinedLater, MacroRulesNot, MacroSuggMovePosition,
MaybeMissingMacroRulesName,
};
use crate::hygiene::Macros20NormalizedSyntaxContext;
use crate::imports::{Import, ImportKind};
use crate::late::{DiagMetadata, PatternSource, Rib};
use crate::{
@ -1163,11 +1164,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
suggestions: &mut Vec<TypoSuggestion>,
scope_set: ScopeSet<'ra>,
ps: &ParentScope<'ra>,
ctxt: SyntaxContext,
sp: Span,
filter_fn: &impl Fn(Res) -> bool,
) {
let ctxt = DUMMY_SP.with_ctxt(ctxt);
self.cm().visit_scopes(scope_set, ps, ctxt, None, |this, scope, use_prelude, _| {
let ctxt = Macros20NormalizedSyntaxContext::new(sp.ctxt());
self.cm().visit_scopes(scope_set, ps, ctxt, sp, None, |this, scope, use_prelude, _| {
match scope {
Scope::DeriveHelpers(expn_id) => {
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
@ -1269,8 +1270,13 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
filter_fn: &impl Fn(Res) -> bool,
) -> Option<TypoSuggestion> {
let mut suggestions = Vec::new();
let ctxt = ident.span.ctxt();
self.add_scope_set_candidates(&mut suggestions, scope_set, parent_scope, ctxt, filter_fn);
self.add_scope_set_candidates(
&mut suggestions,
scope_set,
parent_scope,
ident.span,
filter_fn,
);
// Make sure error reporting is deterministic.
suggestions.sort_by(|a, b| a.candidate.as_str().cmp(b.candidate.as_str()));

View file

@ -54,9 +54,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
mut self: CmResolver<'r, 'ra, 'tcx>,
scope_set: ScopeSet<'ra>,
parent_scope: &ParentScope<'ra>,
// Location of the span is not significant, but pass a `Span` instead of `SyntaxContext`
// to avoid extracting and re-packaging the syntax context unnecessarily.
orig_ctxt: Span,
mut ctxt: Macros20NormalizedSyntaxContext,
orig_ident_span: Span,
derive_fallback_lint_id: Option<NodeId>,
mut visitor: impl FnMut(
CmResolver<'_, 'ra, 'tcx>,
@ -128,7 +127,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None),
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
};
let mut ctxt = Macros20NormalizedSyntaxContext::new(orig_ctxt.ctxt());
let mut use_prelude = !module.no_implicit_prelude;
loop {
@ -153,7 +151,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
true
}
Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..) => true,
Scope::MacroUsePrelude => use_prelude || orig_ctxt.edition().is_rust_2015(),
Scope::MacroUsePrelude => use_prelude || orig_ident_span.is_rust_2015(),
Scope::BuiltinAttrs => true,
Scope::ExternPreludeItems | Scope::ExternPreludeFlags => {
use_prelude || module_and_extern_prelude || extern_prelude
@ -396,9 +394,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
finalize: Option<Finalize>,
ignore_decl: Option<Decl<'ra>>,
ignore_import: Option<Import<'ra>>,
) -> Result<Decl<'ra>, Determinacy> {
self.resolve_ident_in_scope_set_inner(
IdentKey::new(orig_ident),
orig_ident.span,
scope_set,
parent_scope,
finalize,
ignore_decl,
ignore_import,
)
}
fn resolve_ident_in_scope_set_inner<'r>(
self: CmResolver<'r, 'ra, 'tcx>,
ident: IdentKey,
orig_ident_span: Span,
scope_set: ScopeSet<'ra>,
parent_scope: &ParentScope<'ra>,
finalize: Option<Finalize>,
ignore_decl: Option<Decl<'ra>>,
ignore_import: Option<Import<'ra>>,
) -> Result<Decl<'ra>, Determinacy> {
// Make sure `self`, `super` etc produce an error when passed to here.
if !matches!(scope_set, ScopeSet::Module(..)) && orig_ident.is_path_segment_keyword() {
if !matches!(scope_set, ScopeSet::Module(..)) && ident.name.is_path_segment_keyword() {
return Err(Determinacy::Determined);
}
@ -432,13 +451,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
let break_result = self.visit_scopes(
scope_set,
parent_scope,
orig_ident.span,
ident.ctxt,
orig_ident_span,
derive_fallback_lint_id,
|mut this, scope, use_prelude, ctxt| {
let ident = IdentKey { name: orig_ident.name, ctxt };
let ident = IdentKey { name: ident.name, ctxt };
let res = match this.reborrow().resolve_ident_in_scope(
ident,
orig_ident.span,
orig_ident_span,
ns,
scope,
use_prelude,
@ -472,7 +492,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if let Some(&(innermost_decl, _)) = innermost_results.first() {
// Found another solution, if the first one was "weak", report an error.
if this.get_mut().maybe_push_ambiguity(
orig_ident,
ident,
orig_ident_span,
ns,
scope_set,
parent_scope,
@ -695,8 +716,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Scope::StdLibPrelude => {
let mut result = Err(Determinacy::Determined);
if let Some(prelude) = self.prelude
&& let Ok(decl) = self.reborrow().resolve_ident_in_scope_set(
ident.orig(orig_ident_span.with_ctxt(*ident.ctxt)),
&& let Ok(decl) = self.reborrow().resolve_ident_in_scope_set_inner(
ident,
orig_ident_span,
ScopeSet::Module(ns, prelude),
parent_scope,
None,
@ -749,7 +771,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
fn maybe_push_ambiguity(
&mut self,
orig_ident: Ident,
ident: IdentKey,
orig_ident_span: Span,
ns: Namespace,
scope_set: ScopeSet<'ra>,
parent_scope: &ParentScope<'ra>,
@ -775,7 +798,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} else if innermost_res == derive_helper_compat {
Some(AmbiguityKind::DeriveHelper)
} else if res == derive_helper_compat && innermost_res != derive_helper {
span_bug!(orig_ident.span, "impossible inner resolution kind")
span_bug!(orig_ident_span, "impossible inner resolution kind")
} else if matches!(innermost_scope, Scope::MacroRules(_))
&& matches!(scope, Scope::ModuleNonGlobs(..) | Scope::ModuleGlobs(..))
&& !self.disambiguate_macro_rules_vs_modularized(innermost_decl, decl)
@ -790,7 +813,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// we visit all macro_rules scopes (e.g. textual scope macros)
// before we visit any modules (e.g. path-based scope macros)
span_bug!(
orig_ident.span,
orig_ident_span,
"ambiguous scoped macro resolutions with path-based \
scope resolution as first candidate"
)
@ -839,8 +862,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
} else {
// Turn ambiguity errors for core vs std panic into warnings.
// FIXME: Remove with lang team approval.
let is_issue_147319_hack = orig_ident.span.edition() <= Edition::Edition2024
&& matches!(orig_ident.name, sym::panic)
let is_issue_147319_hack = orig_ident_span.edition() <= Edition::Edition2024
&& matches!(ident.name, sym::panic)
&& matches!(scope, Scope::StdLibPrelude)
&& matches!(innermost_scope, Scope::ModuleGlobs(_, _))
&& ((self.is_specific_builtin_macro(res, sym::std_panic)
@ -852,7 +875,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
self.ambiguity_errors.push(AmbiguityError {
kind,
ident: orig_ident,
ident: ident.orig(orig_ident_span),
b1: innermost_decl,
b2: decl,
scope1: innermost_scope,
@ -880,46 +903,6 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
#[instrument(level = "debug", skip(self))]
pub(crate) fn resolve_ident_in_module<'r>(
self: CmResolver<'r, 'ra, 'tcx>,
module: ModuleOrUniformRoot<'ra>,
mut ident: Ident,
ns: Namespace,
parent_scope: &ParentScope<'ra>,
finalize: Option<Finalize>,
ignore_decl: Option<Decl<'ra>>,
ignore_import: Option<Import<'ra>>,
) -> Result<Decl<'ra>, Determinacy> {
let tmp_parent_scope;
let mut adjusted_parent_scope = parent_scope;
match module {
ModuleOrUniformRoot::Module(m) => {
if let Some(def) = ident.span.normalize_to_macros_2_0_and_adjust(m.expansion) {
tmp_parent_scope =
ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
adjusted_parent_scope = &tmp_parent_scope;
}
}
ModuleOrUniformRoot::ExternPrelude => {
ident.span.normalize_to_macros_2_0_and_adjust(ExpnId::root());
}
ModuleOrUniformRoot::ModuleAndExternPrelude(..) | ModuleOrUniformRoot::CurrentScope => {
// No adjustments
}
}
self.resolve_ident_in_virt_module_unadjusted(
module,
ident,
ns,
adjusted_parent_scope,
finalize,
ignore_decl,
ignore_import,
)
}
/// Attempts to resolve `ident` in namespace `ns` of `module`.
#[instrument(level = "debug", skip(self))]
fn resolve_ident_in_virt_module_unadjusted<'r>(
self: CmResolver<'r, 'ra, 'tcx>,
module: ModuleOrUniformRoot<'ra>,
ident: Ident,
@ -930,14 +913,22 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
ignore_import: Option<Import<'ra>>,
) -> Result<Decl<'ra>, Determinacy> {
match module {
ModuleOrUniformRoot::Module(module) => self.resolve_ident_in_scope_set(
ident,
ScopeSet::Module(ns, module),
parent_scope,
finalize,
ignore_decl,
ignore_import,
),
ModuleOrUniformRoot::Module(module) => {
let (ident_key, def) = IdentKey::new_adjusted(ident, module.expansion);
let adjusted_parent_scope = match def {
Some(def) => ParentScope { module: self.expn_def_scope(def), ..*parent_scope },
None => *parent_scope,
};
self.resolve_ident_in_scope_set_inner(
ident_key,
ident.span,
ScopeSet::Module(ns, module),
&adjusted_parent_scope,
finalize,
ignore_decl,
ignore_import,
)
}
ModuleOrUniformRoot::ModuleAndExternPrelude(module) => self.resolve_ident_in_scope_set(
ident,
ScopeSet::ModuleAndExternPrelude(ns, module),
@ -950,8 +941,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
if ns != TypeNS {
Err(Determined)
} else {
self.resolve_ident_in_scope_set(
ident,
self.resolve_ident_in_scope_set_inner(
IdentKey::new_adjusted(ident, ExpnId::root()).0,
ident.span,
ScopeSet::ExternPrelude,
parent_scope,
finalize,
@ -1145,8 +1137,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
None => return Err(ControlFlow::Continue(Undetermined)),
};
let tmp_parent_scope;
let (mut adjusted_parent_scope, mut ctxt) = (parent_scope, *ident.ctxt);
match ctxt.glob_adjust(module.expansion, glob_import.span) {
let (mut adjusted_parent_scope, mut adjusted_ident) = (parent_scope, ident);
match adjusted_ident
.ctxt
.update_unchecked(|ctxt| ctxt.glob_adjust(module.expansion, glob_import.span))
{
Some(Some(def)) => {
tmp_parent_scope =
ParentScope { module: self.expn_def_scope(def), ..*parent_scope };
@ -1155,8 +1150,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
Some(None) => {}
None => continue,
};
let result = self.reborrow().resolve_ident_in_scope_set(
ident.orig(orig_ident_span.with_ctxt(ctxt)),
let result = self.reborrow().resolve_ident_in_scope_set_inner(
adjusted_ident,
orig_ident_span,
ScopeSet::Module(ns, module),
adjusted_parent_scope,
None,

View file

@ -2677,7 +2677,7 @@ impl<'ast, 'ra, 'tcx> LateResolutionVisitor<'_, 'ast, 'ra, 'tcx> {
&mut names,
ScopeSet::All(ns),
parent_scope,
ctxt,
segment.ident.span.with_ctxt(ctxt),
filter_fn,
);
break;

View file

@ -575,6 +575,12 @@ impl IdentKey {
IdentKey { name: ident.name, ctxt: Macros20NormalizedSyntaxContext::new(ident.span.ctxt()) }
}
#[inline]
fn new_adjusted(ident: Ident, expn_id: ExpnId) -> (IdentKey, Option<ExpnId>) {
let (ctxt, def) = Macros20NormalizedSyntaxContext::new_adjusted(ident.span.ctxt(), expn_id);
(IdentKey { name: ident.name, ctxt }, def)
}
#[inline]
fn with_root_ctxt(name: Symbol) -> Self {
let ctxt = Macros20NormalizedSyntaxContext::new_unchecked(SyntaxContext::root());
@ -1923,7 +1929,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&mut self,
current_trait: Option<Module<'ra>>,
parent_scope: &ParentScope<'ra>,
ctxt: Span,
sp: Span,
assoc_item: Option<(Symbol, Namespace)>,
) -> Vec<TraitCandidate> {
let mut found_traits = Vec::new();
@ -1940,7 +1946,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
let scope_set = ScopeSet::All(TypeNS);
self.cm().visit_scopes(scope_set, parent_scope, ctxt, None, |mut this, scope, _, _| {
let ctxt = Macros20NormalizedSyntaxContext::new(sp.ctxt());
self.cm().visit_scopes(scope_set, parent_scope, ctxt, sp, None, |mut this, scope, _, _| {
match scope {
Scope::ModuleNonGlobs(module, _) => {
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
@ -2723,7 +2730,7 @@ mod ref_mut {
}
mod hygiene {
use rustc_span::SyntaxContext;
use rustc_span::{ExpnId, SyntaxContext};
/// A newtype around `SyntaxContext` that can only keep contexts produced by
/// [SyntaxContext::normalize_to_macros_2_0].
@ -2736,6 +2743,15 @@ mod hygiene {
Macros20NormalizedSyntaxContext(ctxt.normalize_to_macros_2_0())
}
#[inline]
pub(crate) fn new_adjusted(
mut ctxt: SyntaxContext,
expn_id: ExpnId,
) -> (Macros20NormalizedSyntaxContext, Option<ExpnId>) {
let def = ctxt.normalize_to_macros_2_0_and_adjust(expn_id);
(Macros20NormalizedSyntaxContext(ctxt), def)
}
#[inline]
pub(crate) fn new_unchecked(ctxt: SyntaxContext) -> Macros20NormalizedSyntaxContext {
debug_assert_eq!(ctxt, ctxt.normalize_to_macros_2_0());

View file

@ -804,7 +804,7 @@ impl SyntaxContext {
/// Like `SyntaxContext::adjust`, but also normalizes `self` to macros 2.0.
#[inline]
pub(crate) fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
pub fn normalize_to_macros_2_0_and_adjust(&mut self, expn_id: ExpnId) -> Option<ExpnId> {
HygieneData::with(|data| {
*self = data.normalize_to_macros_2_0(*self);
data.adjust(self, expn_id)