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:
@@ -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);
|
||||
|
||||
Reference in New Issue
Block a user