Introduce and use CmCell during import resolution.

This commit is contained in:
LorrensP-2158466
2025-09-05 08:34:00 +02:00
parent 0d6a806909
commit 0374df1b50
4 changed files with 135 additions and 40 deletions

View File

@@ -5,7 +5,6 @@
//! unexpanded macros in the fragment are visited and registered.
//! Imports are also considered items and placed into modules here, but not resolved yet.
use std::cell::Cell;
use std::sync::Arc;
use rustc_ast::visit::{self, AssocCtxt, Visitor, WalkItemKind};
@@ -35,6 +34,7 @@ use crate::Namespace::{MacroNS, TypeNS, ValueNS};
use crate::def_collector::collect_definitions;
use crate::imports::{ImportData, ImportKind};
use crate::macros::{MacroRulesBinding, MacroRulesScope, MacroRulesScopeRef};
use crate::ref_mut::CmCell;
use crate::{
BindingKey, ExternPreludeEntry, Finalize, MacroData, Module, ModuleKind, ModuleOrUniformRoot,
NameBinding, ParentScope, PathResult, ResolutionError, Resolver, Segment, Used,
@@ -87,7 +87,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// because they can be fetched by glob imports from those modules, and bring traits
// into scope both directly and through glob imports.
let key = BindingKey::new_disambiguated(ident, ns, || {
parent.underscore_disambiguator.update(|d| d + 1);
// FIXME(batched): Will be fixed in batched resolution.
parent.underscore_disambiguator.update_unchecked(|d| d + 1);
parent.underscore_disambiguator.get()
});
if self
@@ -477,7 +478,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
kind,
parent_scope: self.parent_scope,
module_path,
imported_module: Cell::new(None),
imported_module: CmCell::new(None),
span,
use_span: item.span,
use_span_with_attributes: item.span_with_attributes(),
@@ -505,7 +506,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
});
}
}
ImportKind::Glob { .. } => current_module.globs.borrow_mut().push(import),
ImportKind::Glob { .. } => current_module.globs.borrow_mut(self.r).push(import),
_ => unreachable!(),
}
}
@@ -668,7 +669,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
}
ast::UseTreeKind::Glob => {
if !ast::attr::contains_name(&item.attrs, sym::prelude_import) {
let kind = ImportKind::Glob { max_vis: Cell::new(None), id };
let kind = ImportKind::Glob { max_vis: CmCell::new(None), id };
self.add_import(prefix, kind, use_tree.span, item, root_span, item.id, vis);
} else {
// Resolve the prelude import early.
@@ -971,7 +972,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
kind: ImportKind::ExternCrate { source: orig_name, target: ident, id: item.id },
root_id: item.id,
parent_scope: self.parent_scope,
imported_module: Cell::new(module),
imported_module: CmCell::new(module),
has_attributes: !item.attrs.is_empty(),
use_span_with_attributes: item.span_with_attributes(),
use_span: item.span,
@@ -1103,7 +1104,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
kind: ImportKind::MacroUse { warn_private },
root_id: item.id,
parent_scope: this.parent_scope,
imported_module: Cell::new(Some(ModuleOrUniformRoot::Module(module))),
imported_module: CmCell::new(Some(ModuleOrUniformRoot::Module(module))),
use_span_with_attributes: item.span_with_attributes(),
has_attributes: !item.attrs.is_empty(),
use_span: item.span,
@@ -1196,7 +1197,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
/// directly into its parent scope's module.
fn visit_invoc_in_module(&mut self, id: NodeId) -> MacroRulesScopeRef<'ra> {
let invoc_id = self.visit_invoc(id);
self.parent_scope.module.unexpanded_invocations.borrow_mut().insert(invoc_id);
self.parent_scope.module.unexpanded_invocations.borrow_mut(self.r).insert(invoc_id);
self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Invocation(invoc_id))
}
@@ -1274,7 +1275,7 @@ impl<'a, 'ra, 'tcx> BuildReducedGraphVisitor<'a, 'ra, 'tcx> {
kind: ImportKind::MacroExport,
root_id: item.id,
parent_scope: self.parent_scope,
imported_module: Cell::new(None),
imported_module: CmCell::new(None),
has_attributes: false,
use_span_with_attributes: span,
use_span: span,

View File

@@ -1,6 +1,5 @@
//! A bunch of methods and structures more or less related to resolving imports.
use std::cell::Cell;
use std::mem;
use rustc_ast::NodeId;
@@ -32,6 +31,7 @@ use crate::errors::{
CannotBeReexportedPrivateNS, CannotDetermineImportResolution, CannotGlobImportAllCrates,
ConsiderAddingMacroExport, ConsiderMarkingAsPub, ConsiderMarkingAsPubCrate,
};
use crate::ref_mut::CmCell;
use crate::{
AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion,
Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope,
@@ -68,7 +68,7 @@ pub(crate) enum ImportKind<'ra> {
/// It will directly use `source` when the format is `use prefix::source`.
target: Ident,
/// Bindings introduced by the import.
bindings: PerNS<Cell<PendingBinding<'ra>>>,
bindings: PerNS<CmCell<PendingBinding<'ra>>>,
/// `true` for `...::{self [as target]}` imports, `false` otherwise.
type_ns_only: bool,
/// Did this import result from a nested import? ie. `use foo::{bar, baz};`
@@ -89,7 +89,7 @@ pub(crate) enum ImportKind<'ra> {
Glob {
// The visibility of the greatest re-export.
// n.b. `max_vis` is only used in `finalize_import` to check for re-export errors.
max_vis: Cell<Option<Visibility>>,
max_vis: CmCell<Option<Visibility>>,
id: NodeId,
},
ExternCrate {
@@ -182,7 +182,7 @@ pub(crate) struct ImportData<'ra> {
/// |`use ::foo` | `ModuleOrUniformRoot::ExternPrelude` | 2018+ editions |
/// |`use ::foo` | `ModuleOrUniformRoot::ModuleAndExternPrelude` | a special case in 2015 edition |
/// |`use foo` | `ModuleOrUniformRoot::CurrentScope` | - |
pub imported_module: Cell<Option<ModuleOrUniformRoot<'ra>>>,
pub imported_module: CmCell<Option<ModuleOrUniformRoot<'ra>>>,
pub vis: Visibility,
/// Span of the visibility.
@@ -320,7 +320,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&& (vis == import_vis
|| max_vis.get().is_none_or(|max_vis| vis.is_at_least(max_vis, self.tcx)))
{
max_vis.set(Some(vis.expect_local()))
// FIXME(batched): Will be fixed in batched import resolution.
max_vis.set_unchecked(Some(vis.expect_local()))
}
self.arenas.alloc_name_binding(NameBindingData {
@@ -349,7 +350,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// because they can be fetched by glob imports from those modules, and bring traits
// into scope both directly and through glob imports.
let key = BindingKey::new_disambiguated(ident, ns, || {
module.underscore_disambiguator.update(|d| d + 1);
// FIXME(batched): Will be fixed in batched resolution.
module.underscore_disambiguator.update_unchecked(|d| d + 1);
module.underscore_disambiguator.get()
});
self.update_local_resolution(module, key, warn_ambiguity, |this, resolution| {
@@ -482,7 +484,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
};
let Ok(glob_importers) = module.glob_importers.try_borrow_mut() else {
let Ok(glob_importers) = module.glob_importers.try_borrow_mut_unchecked() else {
return t;
};
@@ -862,7 +864,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
};
import.imported_module.set(Some(module));
// FIXME(batched): Will be fixed in batched import resolution.
import.imported_module.set_unchecked(Some(module));
let (source, target, bindings, type_ns_only) = match import.kind {
ImportKind::Single { source, target, ref bindings, type_ns_only, .. } => {
(source, target, bindings, type_ns_only)
@@ -937,7 +940,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
PendingBinding::Pending
}
};
bindings[ns].set(binding);
// FIXME(batched): Will be fixed in batched import resolution.
bindings[ns].set_unchecked(binding);
}
});
@@ -1508,7 +1512,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
// Add to module's glob_importers
module.glob_importers.borrow_mut().push(import);
module.glob_importers.borrow_mut_unchecked().push(import);
// Ensure that `resolutions` isn't borrowed during `try_define`,
// since it might get updated via a glob cycle.
@@ -1550,7 +1554,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// reporting conflicts, and reporting unresolved imports.
fn finalize_resolutions_in(&mut self, module: Module<'ra>) {
// Since import resolution is finished, globs will not define any more names.
*module.globs.borrow_mut() = Vec::new();
*module.globs.borrow_mut(self) = Vec::new();
let Some(def_id) = module.opt_def_id() else { return };

View File

@@ -19,6 +19,7 @@
#![feature(default_field_values)]
#![feature(if_let_guard)]
#![feature(iter_intersperse)]
#![feature(ptr_as_ref_unchecked)]
#![feature(rustc_attrs)]
#![feature(rustdoc_internals)]
#![recursion_limit = "256"]
@@ -26,7 +27,7 @@
use std::cell::{Cell, Ref, RefCell};
use std::collections::BTreeSet;
use std::fmt;
use std::fmt::{self};
use std::sync::Arc;
use diagnostics::{ImportSuggestion, LabelSuggestion, Suggestion};
@@ -95,6 +96,8 @@ pub mod rustdoc;
pub use macros::registered_tools_ast;
use crate::ref_mut::{CmCell, CmRefCell};
rustc_fluent_macro::fluent_messages! { "../messages.ftl" }
#[derive(Debug)]
@@ -592,22 +595,22 @@ struct ModuleData<'ra> {
/// Resolutions in modules from other crates are not populated until accessed.
lazy_resolutions: Resolutions<'ra>,
/// True if this is a module from other crate that needs to be populated on access.
populate_on_access: Cell<bool>,
populate_on_access: Cell<bool>, // FIXME(parallel): Use an atomic in parallel import resolution
/// Used to disambiguate underscore items (`const _: T = ...`) in the module.
underscore_disambiguator: Cell<u32>,
underscore_disambiguator: CmCell<u32>,
/// Macro invocations that can expand into items in this module.
unexpanded_invocations: RefCell<FxHashSet<LocalExpnId>>,
unexpanded_invocations: CmRefCell<FxHashSet<LocalExpnId>>,
/// Whether `#[no_implicit_prelude]` is active.
no_implicit_prelude: bool,
glob_importers: RefCell<Vec<Import<'ra>>>,
globs: RefCell<Vec<Import<'ra>>>,
glob_importers: CmRefCell<Vec<Import<'ra>>>,
globs: CmRefCell<Vec<Import<'ra>>>,
/// Used to memoize the traits in this module for faster searches through all traits in scope.
traits:
RefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
CmRefCell<Option<Box<[(Macros20NormalizedIdent, NameBinding<'ra>, Option<Module<'ra>>)]>>>,
/// Span of the module itself. Used for error reporting.
span: Span,
@@ -656,12 +659,12 @@ impl<'ra> ModuleData<'ra> {
kind,
lazy_resolutions: Default::default(),
populate_on_access: Cell::new(is_foreign),
underscore_disambiguator: Cell::new(0),
underscore_disambiguator: CmCell::new(0),
unexpanded_invocations: Default::default(),
no_implicit_prelude,
glob_importers: RefCell::new(Vec::new()),
globs: RefCell::new(Vec::new()),
traits: RefCell::new(None),
glob_importers: CmRefCell::new(Vec::new()),
globs: CmRefCell::new(Vec::new()),
traits: CmRefCell::new(None),
span,
expansion,
self_binding,
@@ -696,7 +699,7 @@ impl<'ra> Module<'ra> {
/// This modifies `self` in place. The traits will be stored in `self.traits`.
fn ensure_traits<'tcx>(self, resolver: &impl AsRef<Resolver<'ra, 'tcx>>) {
let mut traits = self.traits.borrow_mut();
let mut traits = self.traits.borrow_mut(resolver.as_ref());
if traits.is_none() {
let mut collected_traits = Vec::new();
self.for_each_child(resolver, |r, name, ns, binding| {
@@ -1974,6 +1977,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
fn resolutions(&self, module: Module<'ra>) -> &'ra Resolutions<'ra> {
if module.populate_on_access.get() {
// FIXME(batched): Will be fixed in batched import resolution.
module.populate_on_access.set(false);
self.build_reduced_graph_external(module);
}
@@ -2502,9 +2506,20 @@ pub fn provide(providers: &mut Providers) {
providers.registered_tools = macros::registered_tools;
}
/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions.
///
/// `Cm` stands for "conditionally mutable".
///
/// Prefer constructing it through [`Resolver::cm`] to ensure correctness.
type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>;
mod ref_mut {
use std::cell::{BorrowMutError, Cell, Ref, RefCell, RefMut};
use std::fmt;
use std::ops::Deref;
use crate::Resolver;
/// A wrapper around a mutable reference that conditionally allows mutable access.
pub(crate) struct RefOrMut<'a, T> {
p: &'a mut T,
@@ -2553,11 +2568,86 @@ mod ref_mut {
self.p
}
}
}
/// A wrapper around `&mut Resolver` that may be mutable or immutable, depending on a conditions.
///
/// `Cm` stands for "conditionally mutable".
///
/// Prefer constructing it through [`Resolver::cm`] to ensure correctness.
type CmResolver<'r, 'ra, 'tcx> = ref_mut::RefOrMut<'r, Resolver<'ra, 'tcx>>;
/// A wrapper around a [`Cell`] that only allows mutation based on a condition in the resolver.
#[derive(Default)]
pub(crate) struct CmCell<T>(Cell<T>);
impl<T: Copy + fmt::Debug> fmt::Debug for CmCell<T> {
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
f.debug_tuple("CmCell").field(&self.get()).finish()
}
}
impl<T: Copy> Clone for CmCell<T> {
#[inline]
fn clone(&self) -> CmCell<T> {
CmCell::new(self.get())
}
}
impl<T: Copy> CmCell<T> {
pub(crate) const fn get(&self) -> T {
self.0.get()
}
pub(crate) fn update_unchecked(&self, f: impl FnOnce(T) -> T)
where
T: Copy,
{
let old = self.get();
self.set_unchecked(f(old));
}
}
impl<T> CmCell<T> {
pub(crate) const fn new(value: T) -> CmCell<T> {
CmCell(Cell::new(value))
}
pub(crate) fn set_unchecked(&self, val: T) {
self.0.set(val);
}
pub(crate) fn into_inner(self) -> T {
self.0.into_inner()
}
}
/// A wrapper around a [`RefCell`] that only allows mutable borrows based on a condition in the resolver.
#[derive(Default)]
pub(crate) struct CmRefCell<T>(RefCell<T>);
impl<T> CmRefCell<T> {
pub(crate) const fn new(value: T) -> CmRefCell<T> {
CmRefCell(RefCell::new(value))
}
#[inline]
#[track_caller]
pub(crate) fn borrow_mut_unchecked(&self) -> RefMut<'_, T> {
self.0.borrow_mut()
}
#[inline]
#[track_caller]
pub(crate) fn borrow_mut<'ra, 'tcx>(&self, r: &Resolver<'ra, 'tcx>) -> RefMut<'_, T> {
if r.assert_speculative {
panic!("Not allowed to mutably borrow a CmRefCell during speculative resolution");
}
self.borrow_mut_unchecked()
}
#[inline]
#[track_caller]
pub(crate) fn try_borrow_mut_unchecked(&self) -> Result<RefMut<'_, T>, BorrowMutError> {
self.0.try_borrow_mut()
}
#[inline]
#[track_caller]
pub(crate) fn borrow(&self) -> Ref<'_, T> {
self.0.borrow()
}
}
}

View File

@@ -189,7 +189,7 @@ impl<'ra, 'tcx> ResolverExpand for Resolver<'ra, 'tcx> {
let output_macro_rules_scope = self.build_reduced_graph(fragment, parent_scope);
self.output_macro_rules_scopes.insert(expansion, output_macro_rules_scope);
parent_scope.module.unexpanded_invocations.borrow_mut().remove(&expansion);
parent_scope.module.unexpanded_invocations.borrow_mut(self).remove(&expansion);
if let Some(unexpanded_invocations) =
self.impl_unexpanded_invocations.get_mut(&self.invocation_parent(expansion))
{