From 865f3025c66c61a6f1798387a42c2ede978f391a Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Mon, 19 Jan 2026 18:54:21 +0300 Subject: [PATCH] [WIP,perf] A structure for keeping conditionally extracted syntax contexts --- compiler/rustc_resolve/src/diagnostics.rs | 4 +- compiler/rustc_resolve/src/ident.rs | 34 ++++++++--------- compiler/rustc_resolve/src/late.rs | 13 +++++-- compiler/rustc_resolve/src/lib.rs | 6 ++- compiler/rustc_span/src/hygiene.rs | 46 +++++++++++++++++++++++ compiler/rustc_span/src/lib.rs | 3 +- 6 files changed, 81 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_resolve/src/diagnostics.rs b/compiler/rustc_resolve/src/diagnostics.rs index 4f371643ed244..737664fd86576 100644 --- a/compiler/rustc_resolve/src/diagnostics.rs +++ b/compiler/rustc_resolve/src/diagnostics.rs @@ -30,7 +30,7 @@ use rustc_session::lint::builtin::{ use rustc_session::utils::was_invoked_from_cargo; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::edition::Edition; -use rustc_span::hygiene::MacroKind; +use rustc_span::hygiene::{MacroKind, PackagedSyntaxContext}; use rustc_span::source_map::{SourceMap, Spanned}; use rustc_span::{ BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, SyntaxContext, kw, sym, @@ -1180,7 +1180,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { ctxt: SyntaxContext, filter_fn: &impl Fn(Res) -> bool, ) { - let ctxt = DUMMY_SP.with_ctxt(ctxt); + let ctxt = PackagedSyntaxContext::new(DUMMY_SP.with_ctxt(ctxt)); self.cm().visit_scopes(scope_set, ps, ctxt, None, |this, scope, use_prelude, _| { match scope { Scope::DeriveHelpers(expn_id) => { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 79d08828ccc4a..b2a035d9ae6b7 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -9,7 +9,9 @@ use rustc_middle::{bug, span_bug}; use rustc_session::lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK; use rustc_session::parse::feature_err; use rustc_span::edition::Edition; -use rustc_span::hygiene::{ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext}; +use rustc_span::hygiene::{ + ExpnId, ExpnKind, LocalExpnId, MacroKind, PackagedSyntaxContext, SyntaxContext, +}; use rustc_span::{Ident, Macros20NormalizedIdent, Span, kw, sym}; use smallvec::SmallVec; use tracing::{debug, instrument}; @@ -53,15 +55,13 @@ 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 orig_ctxt: PackagedSyntaxContext, derive_fallback_lint_id: Option, mut visitor: impl FnMut( &mut CmResolver<'r, 'ra, 'tcx>, Scope<'ra>, UsePrelude, - Span, + PackagedSyntaxContext, ) -> ControlFlow, ) -> Option { // General principles: @@ -127,7 +127,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { TypeNS | ValueNS => Scope::ModuleNonGlobs(module, None), MacroNS => Scope::DeriveHelpers(parent_scope.expansion), }; - let mut ctxt = orig_ctxt.normalize_to_macros_2_0(); + let mut ctxt = orig_ctxt.clone(); + ctxt.mutate_ctxt(|ctxt| *ctxt = ctxt.normalize_to_macros_2_0()); let mut use_prelude = !module.no_implicit_prelude; loop { @@ -152,7 +153,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_ctxt.ctxt().edition().is_rust_2015(), Scope::BuiltinAttrs => true, Scope::ExternPreludeItems | Scope::ExternPreludeFlags => { use_prelude || module_and_extern_prelude || extern_prelude @@ -165,7 +166,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { if visit { let use_prelude = if use_prelude { UsePrelude::Yes } else { UsePrelude::No }; if let ControlFlow::Break(break_result) = - visitor(&mut self, scope, use_prelude, ctxt) + visitor(&mut self, scope, use_prelude, ctxt.clone()) { return Some(break_result); } @@ -198,7 +199,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::ModuleGlobs(..) if module_only => break, Scope::ModuleGlobs(..) if module_and_extern_prelude => match ns { TypeNS => { - ctxt.adjust(ExpnId::root()); + ctxt.mutate_ctxt(|ctxt| ctxt.adjust(ExpnId::root())); Scope::ExternPreludeItems } ValueNS | MacroNS => break, @@ -210,7 +211,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { Scope::ModuleNonGlobs(parent_module, lint_id.or(prev_lint_id)) } None => { - ctxt.adjust(ExpnId::root()); + ctxt.mutate_ctxt(|ctxt| ctxt.adjust(ExpnId::root())); match ns { TypeNS => Scope::ExternPreludeItems, ValueNS => Scope::StdLibPrelude, @@ -240,12 +241,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { fn hygienic_lexical_parent( &self, module: Module<'ra>, - span: &mut Span, + span: &mut PackagedSyntaxContext, derive_fallback_lint_id: Option, ) -> Option<(Module<'ra>, Option)> { - let ctxt = span.ctxt(); - if !module.expansion.outer_expn_is_descendant_of(ctxt) { - return Some((self.expn_def_scope(span.remove_mark()), None)); + if !module.expansion.outer_expn_is_descendant_of(span.ctxt()) { + return Some((self.expn_def_scope(span.mutate_ctxt(|ctxt| ctxt.remove_mark())), None)); } if let ModuleKind::Block = module.kind { @@ -275,7 +275,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let ext = &self.get_macro_by_def_id(def_id).ext; if ext.builtin_name.is_none() && ext.macro_kinds() == MacroKinds::DERIVE - && parent.expansion.outer_expn_is_descendant_of(ctxt) + && parent.expansion.outer_expn_is_descendant_of(span.ctxt()) { return Some((parent, derive_fallback_lint_id)); } @@ -436,10 +436,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { let break_result = self.visit_scopes( scope_set, parent_scope, - orig_ident.span, + PackagedSyntaxContext::new(orig_ident.span), derive_fallback_lint_id, |this, scope, use_prelude, ctxt| { - let ident = Ident::new(orig_ident.name, ctxt); + let ident = Ident::new(orig_ident.name, ctxt.finalize()); // The passed `ctxt` is already normalized, so avoid expensive double normalization. let ident = Macros20NormalizedIdent(ident); let res = match this.reborrow().resolve_ident_in_scope( diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 963bee369f6b8..11aa731c05423 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -37,7 +37,9 @@ use rustc_session::config::{CrateType, ResolveDocLinks}; use rustc_session::lint; use rustc_session::parse::feature_err; use rustc_span::source_map::{Spanned, respan}; -use rustc_span::{BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; +use rustc_span::{ + BytePos, DUMMY_SP, Ident, Macros20NormalizedIdent, PackagedSyntaxContext, Span, Symbol, kw, sym, +}; use smallvec::{SmallVec, smallvec}; use thin_vec::ThinVec; use tracing::{debug, instrument, trace}; @@ -5222,7 +5224,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { self.r.traits_in_scope( self.current_trait_ref.as_ref().map(|(module, _)| *module), &self.parent_scope, - ident.span, + PackagedSyntaxContext::new(ident.span), Some((ident.name, ns)), ) } @@ -5321,7 +5323,12 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { .entry(self.parent_scope.module.nearest_parent_mod().expect_local()) .or_insert_with(|| { self.r - .traits_in_scope(None, &self.parent_scope, DUMMY_SP, None) + .traits_in_scope( + None, + &self.parent_scope, + PackagedSyntaxContext::new(DUMMY_SP), + None, + ) .into_iter() .filter_map(|tr| { if self.is_invalid_proc_macro_item_for_doc(tr.def_id) { diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 52b016b6bdca2..ff41dff33e528 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -74,7 +74,9 @@ use rustc_middle::ty::{ use rustc_query_system::ich::StableHashingContext; use rustc_session::config::CrateType; use rustc_session::lint::builtin::PRIVATE_MACRO_USE; -use rustc_span::hygiene::{ExpnId, LocalExpnId, MacroKind, SyntaxContext, Transparency}; +use rustc_span::hygiene::{ + ExpnId, LocalExpnId, MacroKind, PackagedSyntaxContext, SyntaxContext, Transparency, +}; use rustc_span::{DUMMY_SP, Ident, Macros20NormalizedIdent, Span, Symbol, kw, sym}; use smallvec::{SmallVec, smallvec}; use tracing::debug; @@ -1885,7 +1887,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> { &mut self, current_trait: Option>, parent_scope: &ParentScope<'ra>, - ctxt: Span, + ctxt: PackagedSyntaxContext, assoc_item: Option<(Symbol, Namespace)>, ) -> Vec { let mut found_traits = Vec::new(); diff --git a/compiler/rustc_span/src/hygiene.rs b/compiler/rustc_span/src/hygiene.rs index d94d82835d650..57ba0ea5215b4 100644 --- a/compiler/rustc_span/src/hygiene.rs +++ b/compiler/rustc_span/src/hygiene.rs @@ -51,6 +51,52 @@ use crate::{DUMMY_SP, HashStableContext, Span, SpanDecoder, SpanEncoder, with_se #[derive(Clone, Copy, PartialEq, Eq, Hash)] pub struct SyntaxContext(u32); +#[derive(Clone)] +pub struct PackagedSyntaxContext { + span: Span, + ctxt: Option, +} + +impl PackagedSyntaxContext { + #[inline] + pub fn new(span: Span) -> PackagedSyntaxContext { + PackagedSyntaxContext { span, ctxt: None } + } + + #[inline] + pub fn ctxt(&mut self) -> SyntaxContext { + match self.ctxt { + Some(ctxt) => ctxt, + None => { + let ctxt = self.span.ctxt(); + self.ctxt = Some(ctxt); + ctxt + } + } + } + + #[inline] + pub fn mutate_ctxt(&mut self, f: impl FnOnce(&mut SyntaxContext) -> R) -> R { + match &mut self.ctxt { + Some(ctxt) => f(ctxt), + None => { + let mut ctxt = self.span.ctxt(); + let ret = f(&mut ctxt); + self.ctxt = Some(ctxt); + ret + } + } + } + + #[inline] + pub fn finalize(self) -> Span { + match self.ctxt { + Some(ctxt) => self.span.with_ctxt(ctxt), + None => self.span, + } + } +} + // To ensure correctness of incremental compilation, // `SyntaxContext` must not implement `Ord` or `PartialOrd`. // See https://github.com/rust-lang/rust/issues/90317. diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 747cb2c17eb91..9291549093c6c 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -52,7 +52,8 @@ use edition::Edition; pub mod hygiene; use hygiene::Transparency; pub use hygiene::{ - DesugaringKind, ExpnData, ExpnHash, ExpnId, ExpnKind, LocalExpnId, MacroKind, SyntaxContext, + DesugaringKind, ExpnData, ExpnHash, ExpnId, ExpnKind, LocalExpnId, MacroKind, + PackagedSyntaxContext, SyntaxContext, }; use rustc_data_structures::stable_hasher::HashingControls; pub mod def_id;