Rollup merge of #144912 - LorrensP-2158466:smart-resolver, r=petrochenkov

Resolver: introduce a conditionally mutable Resolver for (non-)speculative resolution.

This pr introduces a `CmResolver`, a wrapper around the main resolver which gives out mutable access given a condition.

`CmResolver` only allows mutation when we’re not in speculative import resolution. This ensures we can’t accidentally mutate the resolver during this process, which is important as we move towards a batched resolution algorithm.

This also changes functions that are used during speculative import resolution to take a `CmResolver` instead of a `&mut Resolver`.

Also introduces a new kind of "smart pointer" which has the behaviour described above:
```rust
/// A wrapper around a mutable reference that conditionally allows mutable access.
pub(crate) struct RefOrMut<'a, T> {
    p: &'a mut T,
    mutable: bool,
}

type CmResolver<'r, 'ra, 'tcx> = RefOrMut<'r, Resolver<'ra, 'tcx>>;
```
r? petrochenkov
This commit is contained in:
Stuart Cook
2025-08-08 12:52:52 +10:00
committed by GitHub
8 changed files with 337 additions and 189 deletions

View File

@@ -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 self.r.cm().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.cm().maybe_resolve_ident_in_module(
ModuleOrUniformRoot::Module(module),
ident,
MacroNS,

View File

@@ -469,13 +469,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
pub(crate) fn lint_if_path_starts_with_module(
&mut self,
finalize: Option<Finalize>,
finalize: Finalize,
path: &[Segment],
second_binding: Option<NameBinding<'_>>,
) {
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
@@ -1029,7 +1027,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Option<TypoSuggestion> {
let mut suggestions = Vec::new();
let ctxt = ident.span.ctxt();
self.visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
self.cm().visit_scopes(scope_set, parent_scope, ctxt, |this, scope, use_prelude, _| {
match scope {
Scope::DeriveHelpers(expn_id) => {
let res = Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper);
@@ -1048,7 +1046,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,
@@ -1482,7 +1480,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.cm().visit_scopes(
ScopeSet::Macro(MacroKind::Derive),
&parent_scope,
ident.span.ctxt(),
@@ -1591,7 +1589,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.cm().early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::All(ns),
parent_scope,
@@ -2271,7 +2269,8 @@ 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(
self.cm()
.resolve_ident_in_module(
module,
ident,
ns_to_try,
@@ -2298,7 +2297,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
_ => None,
}
} else {
self.early_resolve_ident_in_lexical_scope(
self.cm()
.early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::All(ns_to_try),
parent_scope,
@@ -2401,7 +2401,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
},
)
});
if let Ok(binding) = self.early_resolve_ident_in_lexical_scope(
if let Ok(binding) = self.cm().early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::All(ValueNS),
parent_scope,
@@ -2531,7 +2531,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Option<(Vec<Segment>, Option<String>)> {
// 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.cm().maybe_resolve_path(&path, None, parent_scope, None);
debug!(?path, ?result);
if let PathResult::Module(..) = result { Some((path, None)) } else { None }
}
@@ -2551,7 +2551,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Option<(Vec<Segment>, Option<String>)> {
// 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.cm().maybe_resolve_path(&path, None, parent_scope, None);
debug!(?path, ?result);
if let PathResult::Module(..) = result {
Some((
@@ -2583,7 +2583,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
) -> Option<(Vec<Segment>, Option<String>)> {
// 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.cm().maybe_resolve_path(&path, None, parent_scope, None);
debug!(?path, ?result);
if let PathResult::Module(..) = result { Some((path, None)) } else { None }
}
@@ -2618,7 +2618,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.cm().maybe_resolve_path(&path, None, parent_scope, None);
debug!(?path, ?name, ?result);
if let PathResult::Module(..) = result {
return Some((path, None));

View File

@@ -16,10 +16,10 @@ use crate::imports::{Import, NameResolution};
use crate::late::{ConstantHasGenerics, NoConstantGenericsReason, PathSource, Rib, RibKind};
use crate::macros::{MacroRulesScope, sub_namespace_match};
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,
AmbiguityError, AmbiguityErrorMisc, AmbiguityKind, BindingKey, CmResolver, Determinacy,
Finalize, ImportKind, LexicalScopeBinding, Module, ModuleKind, ModuleOrUniformRoot,
NameBinding, NameBindingKind, ParentScope, PathResult, PrivacyError, Res, ResolutionError,
Resolver, Scope, ScopeSet, Segment, 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<T>(
&mut self,
pub(crate) fn visit_scopes<'r, T>(
mut self: CmResolver<'r, 'ra, 'tcx>,
scope_set: ScopeSet<'ra>,
parent_scope: &ParentScope<'ra>,
ctxt: SyntaxContext,
mut visitor: impl FnMut(&mut Self, Scope<'ra>, UsePrelude, SyntaxContext) -> Option<T>,
mut visitor: impl FnMut(
&mut CmResolver<'r, 'ra, 'tcx>,
Scope<'ra>,
UsePrelude,
SyntaxContext,
) -> Option<T>,
) -> Option<T> {
// General principles:
// 1. Not controlled (user-defined) names should have higher priority than controlled names
@@ -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;
}
}
@@ -341,7 +346,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
_ => break,
}
let item = self.resolve_ident_in_module_unadjusted(
let item = self.cm().resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
@@ -356,7 +361,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
return Some(LexicalScopeBinding::Item(binding));
}
}
self.early_resolve_ident_in_lexical_scope(
self.cm()
.early_resolve_ident_in_lexical_scope(
orig_ident,
ScopeSet::Late(ns, module, finalize.map(|finalize| finalize.node_id)),
parent_scope,
@@ -375,8 +381,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: CmResolver<'r, 'ra, 'tcx>,
orig_ident: Ident,
scope_set: ScopeSet<'ra>,
parent_scope: &ParentScope<'ra>,
@@ -450,7 +456,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 +503,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 +520,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.get_mut().lint_buffer.buffer_lint(
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
lint_id,
orig_ident.span,
@@ -556,7 +562,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 +576,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 +693,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
AmbiguityErrorMisc::None
}
};
this.ambiguity_errors.push(AmbiguityError {
this.get_mut().ambiguity_errors.push(AmbiguityError {
kind,
ident: orig_ident,
b1: innermost_binding,
@@ -725,8 +731,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: CmResolver<'r, 'ra, 'tcx>,
module: ModuleOrUniformRoot<'ra>,
ident: Ident,
ns: Namespace,
@@ -738,8 +744,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: CmResolver<'r, 'ra, 'tcx>,
module: ModuleOrUniformRoot<'ra>,
mut ident: Ident,
ns: Namespace,
@@ -776,12 +782,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: CmResolver<'r, 'ra, 'tcx>,
module: ModuleOrUniformRoot<'ra>,
ident: Ident,
ns: Namespace,
@@ -812,7 +817,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 +872,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.get_mut().finalize_module_binding(
ident,
binding,
if resolution.non_glob_binding.is_some() { resolution.glob_binding } else { None },
@@ -875,7 +882,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
);
}
let check_usable = |this: &Self, binding: NameBinding<'ra>| {
let check_usable = |this: CmResolver<'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 +898,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 +969,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 +1056,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: CmResolver<'r, 'ra, 'tcx>,
resolution: &NameResolution<'ra>,
binding: Option<NameBinding<'ra>>,
ns: Namespace,
@@ -1086,7 +1093,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
match self.resolve_ident_in_module(
match self.reborrow().resolve_ident_in_module(
module,
*source,
ns,
@@ -1409,8 +1416,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: CmResolver<'r, 'ra, 'tcx>,
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path in import
parent_scope: &ParentScope<'ra>,
@@ -1418,10 +1425,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: CmResolver<'r, 'ra, 'tcx>,
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path in import
parent_scope: &ParentScope<'ra>,
@@ -1440,8 +1446,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: CmResolver<'r, 'ra, 'tcx>,
path: &[Segment],
opt_ns: Option<Namespace>, // `None` indicates a module path in import
parent_scope: &ParentScope<'ra>,
@@ -1457,18 +1463,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();
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| {
fn record_segment_res<'r, 'ra, 'tcx>(
mut this: CmResolver<'r, 'ra, 'tcx>,
finalize: Option<Finalize>,
res: Res,
id: Option<NodeId>,
) {
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));
this.get_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 is_last = segment_idx + 1 == path.len();
let ns = if is_last { opt_ns.unwrap_or(TypeNS) } else { TypeNS };
@@ -1507,7 +1518,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 +1540,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,7 +1573,8 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
let binding = if let Some(module) = module {
self.resolve_ident_in_module(
self.reborrow()
.resolve_ident_in_module(
module,
ident,
ns,
@@ -1576,7 +1588,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
&& let Some(TypeNS | ValueNS) = opt_ns
{
assert!(ignore_import.is_none());
match self.resolve_ident_in_lexical_scope(
match self.get_mut().resolve_ident_in_lexical_scope(
ident,
ns,
parent_scope,
@@ -1588,7 +1600,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 +1609,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,9 +1630,11 @@ 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..] {
if finalize.is_some() {
for error in &mut self.get_mut().privacy_errors[privacy_errors_len..] {
error.outermost_res = Some((res, ident));
}
}
let maybe_assoc = opt_ns != Some(MacroNS) && PathSource::Type.is_expected(res);
if let Some(def_id) = binding.res().module_like_def_id() {
@@ -1628,7 +1642,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 +1655,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.get_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 +1697,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
));
}
let mut this = self.reborrow();
return PathResult::failed(
ident,
is_last,
@@ -1684,7 +1705,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
module_had_parse_errors,
module,
|| {
self.report_path_resolution_error(
this.get_mut().report_path_resolution_error(
path,
opt_ns,
parent_scope,
@@ -1701,7 +1722,9 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
self.lint_if_path_starts_with_module(finalize, path, second_binding);
if let Some(finalize) = finalize {
self.get_mut().lint_if_path_starts_with_module(finalize, path, second_binding);
}
PathResult::Module(match module {
Some(module) => module,

View File

@@ -33,9 +33,10 @@ use crate::errors::{
ConsiderAddingMacroExport, ConsiderMarkingAsPub,
};
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,
AmbiguityError, AmbiguityKind, BindingKey, CmResolver, Determinacy, Finalize, ImportSuggestion,
Module, ModuleOrUniformRoot, NameBinding, NameBindingData, NameBindingKind, ParentScope,
PathResult, PerNS, ResolutionError, Resolver, ScopeSet, Segment, Used, module_to_string,
names_to_string,
};
type Res = def::Res<NodeId>;
@@ -551,13 +552,14 @@ 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.assert_speculative = true;
let mut prev_indeterminate_count = usize::MAX;
let mut indeterminate_count = self.indeterminate_imports.len() * 3;
while indeterminate_count < prev_indeterminate_count {
prev_indeterminate_count = indeterminate_count;
indeterminate_count = 0;
for import in mem::take(&mut self.indeterminate_imports) {
let import_indeterminate_count = self.resolve_import(import);
let import_indeterminate_count = self.cm().resolve_import(import);
indeterminate_count += import_indeterminate_count;
match import_indeterminate_count {
0 => self.determined_imports.push(import),
@@ -565,6 +567,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
}
self.assert_speculative = false;
}
pub(crate) fn finalize_imports(&mut self) {
@@ -837,7 +840,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
///
/// Meanwhile, if resolve successful, the resolved bindings are written
/// into the module.
fn resolve_import(&mut self, import: Import<'ra>) -> usize {
fn resolve_import<'r>(mut self: CmResolver<'r, 'ra, 'tcx>, import: Import<'ra>) -> usize {
debug!(
"(resolving import for module) resolving import `{}::...` in `{}`",
Segment::names_to_string(&import.module_path),
@@ -846,7 +849,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.reborrow().maybe_resolve_path(
&import.module_path,
None,
&import.parent_scope,
@@ -866,19 +869,21 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
(source, target, bindings, type_ns_only)
}
ImportKind::Glob { .. } => {
self.resolve_glob_import(import);
// FIXME: Use mutable resolver directly as a hack, this should be an output of
// specualtive resolution.
self.get_mut_unchecked().resolve_glob_import(import);
return 0;
}
_ => unreachable!(),
};
let mut indeterminate_count = 0;
self.per_ns(|this, ns| {
self.per_ns_cm(|this, ns| {
if !type_ns_only || ns == TypeNS {
if bindings[ns].get() != PendingBinding::Pending {
return;
};
let binding_result = this.maybe_resolve_ident_in_module(
let binding_result = this.reborrow().maybe_resolve_ident_in_module(
module,
source,
ns,
@@ -901,16 +906,30 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
// We need the `target`, `source` can be extracted.
let imported_binding = this.import(binding, import);
this.define_binding_local(parent, target, ns, imported_binding);
// FIXME: Use mutable resolver directly as a hack, this should be an output of
// specualtive resolution.
this.get_mut_unchecked().define_binding_local(
parent,
target,
ns,
imported_binding,
);
PendingBinding::Ready(Some(imported_binding))
}
Err(Determinacy::Determined) => {
// Don't remove underscores from `single_imports`, they were never added.
if target.name != kw::Underscore {
let key = BindingKey::new(target, ns);
this.update_local_resolution(parent, key, false, |_, resolution| {
// FIXME: Use mutable resolver directly as a hack, this should be an output of
// specualtive resolution.
this.get_mut_unchecked().update_local_resolution(
parent,
key,
false,
|_, resolution| {
resolution.single_imports.swap_remove(&import);
});
},
);
}
PendingBinding::Ready(None)
}
@@ -943,7 +962,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.cm().resolve_path(
&import.module_path,
None,
&import.parent_scope,
@@ -1060,7 +1079,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,7 +1122,7 @@ 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(
if let PathResult::Module(ModuleOrUniformRoot::Module(module)) = self.cm().resolve_path(
&path,
None,
&import.parent_scope,
@@ -1121,7 +1140,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.cm().resolve_ident_in_module(
module,
ident,
ns,
@@ -1184,7 +1203,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.cm().resolve_ident_in_module(
module,
ident,
ns,
@@ -1373,7 +1392,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 +1445,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
return;
}
match this.early_resolve_ident_in_lexical_scope(
match this.cm().early_resolve_ident_in_lexical_scope(
target,
ScopeSet::All(ns),
&import.parent_scope,

View File

@@ -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,
@@ -1484,7 +1484,7 @@ impl<'a, 'ast, 'ra, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> {
opt_ns: Option<Namespace>, // `None` indicates a module path in import
finalize: Option<Finalize>,
) -> PathResult<'ra> {
self.r.resolve_path_with_ribs(
self.r.cm().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.cm().resolve_macro_path(
&path,
None,
&self.parent_scope,
false,
false,
None,
None,
) {
return Ok(Some(PartialRes::new(res)));
}
}

View File

@@ -2389,7 +2389,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.cm().maybe_resolve_ident_in_module(
ModuleOrUniformRoot::Module(module),
ident,
ns,

View File

@@ -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)]
@@ -162,11 +163,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: &[],
}
}
@@ -1054,6 +1055,9 @@ pub struct Resolver<'ra, 'tcx> {
graph_root: Module<'ra>,
/// Assert that we are in speculative resolution mode.
assert_speculative: bool,
prelude: Option<Module<'ra>>,
extern_prelude: FxIndexMap<Macros20NormalizedIdent, ExternPreludeEntry<'ra>>,
@@ -1156,10 +1160,11 @@ pub struct Resolver<'ra, 'tcx> {
unused_macro_rules: FxIndexMap<NodeId, DenseBitSet<usize>>,
proc_macro_stubs: FxHashSet<LocalDefId>,
/// Traces collected during macro resolution and validated when it's complete.
// FIXME: Remove interior mutability when speculative resolution produces these as outputs.
single_segment_macro_resolutions:
Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>,
RefCell<Vec<(Ident, MacroKind, ParentScope<'ra>, Option<NameBinding<'ra>>, Option<Span>)>>,
multi_segment_macro_resolutions:
Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>,
RefCell<Vec<(Vec<Segment>, Span, MacroKind, ParentScope<'ra>, Option<Res>, Namespace)>>,
builtin_attrs: Vec<(Ident, ParentScope<'ra>)>,
/// `derive(Copy)` marks items they are applied to so they are treated specially later.
/// Derive macros cannot modify the item themselves and have to store the markers in the global
@@ -1527,6 +1532,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
// The outermost module has def ID 0; this is not reflected in the
// AST.
graph_root,
assert_speculative: false, // Only set/cleared in Resolver::resolve_imports for now
prelude: None,
extern_prelude,
@@ -1644,7 +1650,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);
@@ -1792,6 +1798,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
/// Returns a conditionally mutable resolver.
///
/// Currently only dependent on `assert_speculative`, if `assert_speculative` is false,
/// the resolver will allow mutation; otherwise, it will be immutable.
fn cm(&mut self) -> CmResolver<'_, 'ra, 'tcx> {
CmResolver::new(self, !self.assert_speculative)
}
/// Runs the function on each namespace.
fn per_ns<F: FnMut(&mut Self, Namespace)>(&mut self, mut f: F) {
f(self, TypeNS);
@@ -1799,6 +1813,15 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
f(self, MacroNS);
}
fn per_ns_cm<'r, F: FnMut(&mut CmResolver<'r, 'ra, 'tcx>, Namespace)>(
mut self: CmResolver<'r, 'ra, 'tcx>,
mut f: F,
) {
f(&mut self, TypeNS);
f(&mut self, ValueNS);
f(&mut self, MacroNS);
}
fn is_builtin_macro(&self, res: Res) -> bool {
self.get_macro(res).is_some_and(|macro_data| macro_data.ext.builtin_name.is_some())
}
@@ -1852,14 +1875,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
self.visit_scopes(ScopeSet::All(TypeNS), parent_scope, ctxt, |this, scope, _, _| {
self.cm().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);
this.get_mut().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);
this.get_mut().traits_in_module(module, assoc_item, &mut found_traits);
}
}
Scope::ExternPrelude | Scope::ToolPrelude | Scope::BuiltinTypes => {}
@@ -2002,11 +2025,14 @@ 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(
let empty_module = self.empty_module;
let arenas = self.arenas;
self.cm()
.maybe_resolve_ident_in_module(
ModuleOrUniformRoot::Module(prelude),
ident,
MacroNS,
&ParentScope::module(self.empty_module, self),
&ParentScope::module(empty_module, arenas),
None,
)
.is_ok()
@@ -2180,7 +2206,11 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
fn extern_prelude_get(&mut self, ident: Ident, finalize: bool) -> Option<NameBinding<'ra>> {
fn extern_prelude_get<'r>(
mut self: CmResolver<'r, 'ra, 'tcx>,
ident: Ident,
finalize: bool,
) -> Option<NameBinding<'ra>> {
let mut record_use = None;
let entry = self.extern_prelude.get(&Macros20NormalizedIdent::new(ident));
let binding = entry.and_then(|entry| match entry.binding.get() {
@@ -2216,7 +2246,7 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
});
if let Some(binding) = record_use {
self.record_use(ident, binding, Used::Scope);
self.get_mut().record_use(ident, binding, Used::Scope);
}
binding
@@ -2251,7 +2281,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.cm().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(..), _)))
@@ -2330,9 +2360,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.cm().maybe_resolve_ident_in_module(
ModuleOrUniformRoot::Module(module),
ident,
ValueNS,
@@ -2426,3 +2456,63 @@ impl Finalize {
pub fn provide(providers: &mut Providers) {
providers.registered_tools = macros::registered_tools;
}
mod ref_mut {
use std::ops::Deref;
/// A wrapper around a mutable reference that conditionally allows mutable access.
pub(crate) struct RefOrMut<'a, T> {
p: &'a mut T,
mutable: bool,
}
impl<'a, T> Deref for RefOrMut<'a, T> {
type Target = T;
fn deref(&self) -> &Self::Target {
self.p
}
}
impl<'a, T> AsRef<T> for RefOrMut<'a, T> {
fn as_ref(&self) -> &T {
self.p
}
}
impl<'a, T> RefOrMut<'a, T> {
pub(crate) fn new(p: &'a mut T, mutable: bool) -> Self {
RefOrMut { p, mutable }
}
/// This is needed because this wraps a `&mut T` and is therefore not `Copy`.
pub(crate) fn reborrow(&mut self) -> RefOrMut<'_, T> {
RefOrMut { p: self.p, mutable: self.mutable }
}
/// Returns a mutable reference to the inner value if allowed.
///
/// # Panics
/// Panics if the `mutable` flag is false.
#[track_caller]
pub(crate) fn get_mut(&mut self) -> &mut T {
match self.mutable {
false => panic!("Can't mutably borrow speculative resolver"),
true => self.p,
}
}
/// Returns a mutable reference to the inner value without checking if
/// it's in a mutable state.
pub(crate) fn get_mut_unchecked(&mut self) -> &mut T {
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>>;

View File

@@ -41,9 +41,9 @@ use crate::errors::{
};
use crate::imports::Import;
use crate::{
BindingKey, DeriveData, Determinacy, Finalize, InvocationParent, MacroData, ModuleKind,
ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult, ResolutionError,
Resolver, ScopeSet, Segment, Used,
BindingKey, CmResolver, DeriveData, Determinacy, Finalize, InvocationParent, MacroData,
ModuleKind, ModuleOrUniformRoot, NameBinding, NameBindingKind, ParentScope, PathResult,
ResolutionError, Resolver, ScopeSet, Segment, Used,
};
type Res = def::Res<NodeId>;
@@ -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.cm().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<LocalDefId>,
suggestion_span: Option<Span>,
) -> Result<(Arc<SyntaxExtension>, Res), Indeterminate> {
let (ext, res) = match self.resolve_macro_or_delegation_path(
let (ext, res) = match self.cm().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: CmResolver<'r, 'ra, 'tcx>,
path: &ast::Path,
kind: Option<MacroKind>,
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: CmResolver<'r, 'ra, 'tcx>,
ast_path: &ast::Path,
kind: Option<MacroKind>,
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,8 @@ 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((
// FIXME: Should be an output of Speculative Resolution.
self.multi_segment_macro_resolutions.borrow_mut().push((
path,
path_span,
kind,
@@ -791,7 +797,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 +812,8 @@ 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((
// FIXME: Should be an output of Speculative Resolution.
self.single_segment_macro_resolutions.borrow_mut().push((
path[0].ident,
kind,
*parent_scope,
@@ -817,7 +824,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,
@@ -872,13 +879,14 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
};
let macro_resolutions = mem::take(&mut self.multi_segment_macro_resolutions);
// FIXME: Should be an output of Speculative Resolution.
let macro_resolutions = self.multi_segment_macro_resolutions.take();
for (mut path, path_span, kind, parent_scope, initial_res, ns) in macro_resolutions {
// FIXME: Path resolution will ICE if segment IDs present.
for seg in &mut path {
seg.id = None;
}
match self.resolve_path(
match self.cm().resolve_path(
&path,
Some(ns),
&parent_scope,
@@ -905,8 +913,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
.cm()
.maybe_resolve_path(&path, Some(ValueNS), &parent_scope, None)
&& partial_res.unresolved_segments() == 0
{
let sm = self.tcx.sess.source_map();
@@ -948,9 +957,10 @@ impl<'ra, 'tcx> Resolver<'ra, 'tcx> {
}
}
let macro_resolutions = mem::take(&mut self.single_segment_macro_resolutions);
// FIXME: Should be an output of Speculative Resolution.
let macro_resolutions = self.single_segment_macro_resolutions.take();
for (ident, kind, parent_scope, initial_binding, sugg_span) in macro_resolutions {
match self.early_resolve_ident_in_lexical_scope(
match self.cm().early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::Macro(kind),
&parent_scope,
@@ -1005,7 +1015,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.cm().early_resolve_ident_in_lexical_scope(
ident,
ScopeSet::Macro(MacroKind::Attr),
&parent_scope,
@@ -1090,8 +1100,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: CmResolver<'r, 'ra, 'tcx>,
path: &ast::Path,
parent_scope: &ParentScope<'ra>,
invoc_in_mod_inert_attr: Option<(LocalDefId, NodeId)>,
@@ -1110,7 +1120,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 +1216,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.cm().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);