Auto merge of #83103 - petrochenkov:unilex, r=Aaron1011
resolve: Partially unify early and late scope-relative identifier resolution Reuse `early_resolve_ident_in_lexical_scope` instead of a chunk of code in `resolve_ident_in_lexical_scope` doing the same job. `early_resolve_ident_in_lexical_scope`/`visit_scopes` had to be slightly extended to be able to 1) start from a specific module instead of the current parent scope and 2) report one deprecation lint. `early_resolve_ident_in_lexical_scope` still doesn't support walking through "ribs", that part is left in `resolve_ident_in_lexical_scope` (moreover, I'm pretty sure it's buggy, but that's a separate issue, cc https://github.com/rust-lang/rust/issues/52389 at least).
This commit is contained in:
commit
8cd7d86ce2
5 changed files with 97 additions and 144 deletions
|
@ -1935,7 +1935,7 @@ declare_lint! {
|
|||
Warn,
|
||||
"detects proc macro derives using inaccessible names from parent modules",
|
||||
@future_incompatible = FutureIncompatibleInfo {
|
||||
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
|
||||
reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
|
||||
edition: None,
|
||||
};
|
||||
}
|
||||
|
|
|
@ -606,7 +606,7 @@ impl<'a> Resolver<'a> {
|
|||
/// Lookup typo candidate in scope for a macro or import.
|
||||
fn early_lookup_typo_candidate(
|
||||
&mut self,
|
||||
scope_set: ScopeSet,
|
||||
scope_set: ScopeSet<'a>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
ident: Ident,
|
||||
filter_fn: &impl Fn(Res) -> bool,
|
||||
|
@ -662,7 +662,7 @@ impl<'a> Resolver<'a> {
|
|||
let root_module = this.resolve_crate_root(root_ident);
|
||||
this.add_module_candidates(root_module, &mut suggestions, filter_fn);
|
||||
}
|
||||
Scope::Module(module) => {
|
||||
Scope::Module(module, _) => {
|
||||
this.add_module_candidates(module, &mut suggestions, filter_fn);
|
||||
}
|
||||
Scope::RegisteredAttrs => {
|
||||
|
|
|
@ -26,7 +26,6 @@ use Determinacy::*;
|
|||
use rustc_arena::{DroplessArena, TypedArena};
|
||||
use rustc_ast::node_id::NodeMap;
|
||||
use rustc_ast::ptr::P;
|
||||
use rustc_ast::unwrap_or;
|
||||
use rustc_ast::visit::{self, Visitor};
|
||||
use rustc_ast::{self as ast, NodeId};
|
||||
use rustc_ast::{Crate, CRATE_NODE_ID};
|
||||
|
@ -43,7 +42,7 @@ use rustc_hir::def::Namespace::*;
|
|||
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
|
||||
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
|
||||
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
|
||||
use rustc_hir::{PrimTy, TraitCandidate};
|
||||
use rustc_hir::TraitCandidate;
|
||||
use rustc_index::vec::IndexVec;
|
||||
use rustc_metadata::creader::{CStore, CrateLoader};
|
||||
use rustc_middle::hir::exports::ExportMap;
|
||||
|
@ -109,7 +108,9 @@ enum Scope<'a> {
|
|||
DeriveHelpersCompat,
|
||||
MacroRules(MacroRulesScopeRef<'a>),
|
||||
CrateRoot,
|
||||
Module(Module<'a>),
|
||||
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
|
||||
// lint if it should be reported.
|
||||
Module(Module<'a>, Option<NodeId>),
|
||||
RegisteredAttrs,
|
||||
MacroUsePrelude,
|
||||
BuiltinAttrs,
|
||||
|
@ -123,13 +124,17 @@ enum Scope<'a> {
|
|||
/// with different restrictions when looking up the resolution.
|
||||
/// This enum is currently used only for early resolution (imports and macros),
|
||||
/// but not for late resolution yet.
|
||||
enum ScopeSet {
|
||||
#[derive(Clone, Copy)]
|
||||
enum ScopeSet<'a> {
|
||||
/// All scopes with the given namespace.
|
||||
All(Namespace, /*is_import*/ bool),
|
||||
/// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
|
||||
AbsolutePath(Namespace),
|
||||
/// All scopes with macro namespace and the given macro kind restriction.
|
||||
Macro(MacroKind),
|
||||
/// All scopes with the given namespace, used for partially performing late resolution.
|
||||
/// The node id enables lints and is used for reporting them.
|
||||
Late(Namespace, Module<'a>, Option<NodeId>),
|
||||
}
|
||||
|
||||
/// Everything you need to know about a name's location to resolve it.
|
||||
|
@ -1467,7 +1472,7 @@ impl<'a> Resolver<'a> {
|
|||
|
||||
self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
|
||||
match scope {
|
||||
Scope::Module(module) => {
|
||||
Scope::Module(module, _) => {
|
||||
this.traits_in_module(module, assoc_item, &mut found_traits);
|
||||
}
|
||||
Scope::StdLibPrelude => {
|
||||
|
@ -1631,7 +1636,7 @@ impl<'a> Resolver<'a> {
|
|||
/// If the callback returns `Some` result, we stop visiting scopes and return it.
|
||||
fn visit_scopes<T>(
|
||||
&mut self,
|
||||
scope_set: ScopeSet,
|
||||
scope_set: ScopeSet<'a>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
ctxt: SyntaxContext,
|
||||
mut visitor: impl FnMut(
|
||||
|
@ -1687,12 +1692,17 @@ impl<'a> Resolver<'a> {
|
|||
ScopeSet::All(ns, _) => (ns, None, false),
|
||||
ScopeSet::AbsolutePath(ns) => (ns, None, true),
|
||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
|
||||
ScopeSet::Late(ns, ..) => (ns, None, false),
|
||||
};
|
||||
let module = match scope_set {
|
||||
// Start with the specified module.
|
||||
ScopeSet::Late(_, module, _) => module,
|
||||
// Jump out of trait or enum modules, they do not act as scopes.
|
||||
_ => parent_scope.module.nearest_item_scope(),
|
||||
};
|
||||
// Jump out of trait or enum modules, they do not act as scopes.
|
||||
let module = parent_scope.module.nearest_item_scope();
|
||||
let mut scope = match ns {
|
||||
_ if is_absolute_path => Scope::CrateRoot,
|
||||
TypeNS | ValueNS => Scope::Module(module),
|
||||
TypeNS | ValueNS => Scope::Module(module, None),
|
||||
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
|
||||
};
|
||||
let mut ctxt = ctxt.normalize_to_macros_2_0();
|
||||
|
@ -1757,7 +1767,7 @@ impl<'a> Resolver<'a> {
|
|||
MacroRulesScope::Invocation(invoc_id) => {
|
||||
Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
|
||||
}
|
||||
MacroRulesScope::Empty => Scope::Module(module),
|
||||
MacroRulesScope::Empty => Scope::Module(module, None),
|
||||
},
|
||||
Scope::CrateRoot => match ns {
|
||||
TypeNS => {
|
||||
|
@ -1766,10 +1776,16 @@ impl<'a> Resolver<'a> {
|
|||
}
|
||||
ValueNS | MacroNS => break,
|
||||
},
|
||||
Scope::Module(module) => {
|
||||
Scope::Module(module, prev_lint_id) => {
|
||||
use_prelude = !module.no_implicit_prelude;
|
||||
match self.hygienic_lexical_parent(module, &mut ctxt) {
|
||||
Some(parent_module) => Scope::Module(parent_module),
|
||||
let derive_fallback_lint_id = match scope_set {
|
||||
ScopeSet::Late(.., lint_id) => lint_id,
|
||||
_ => None,
|
||||
};
|
||||
match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
|
||||
Some((parent_module, lint_id)) => {
|
||||
Scope::Module(parent_module, lint_id.or(prev_lint_id))
|
||||
}
|
||||
None => {
|
||||
ctxt.adjust(ExpnId::root());
|
||||
match ns {
|
||||
|
@ -1825,6 +1841,7 @@ impl<'a> Resolver<'a> {
|
|||
ribs: &[Rib<'a>],
|
||||
) -> Option<LexicalScopeBinding<'a>> {
|
||||
assert!(ns == TypeNS || ns == ValueNS);
|
||||
let orig_ident = ident;
|
||||
if ident.name == kw::Empty {
|
||||
return Some(LexicalScopeBinding::Res(Res::Err));
|
||||
}
|
||||
|
@ -1874,6 +1891,11 @@ impl<'a> Resolver<'a> {
|
|||
_ => continue,
|
||||
};
|
||||
|
||||
match module.kind {
|
||||
ModuleKind::Block(..) => {} // We can see through blocks
|
||||
_ => break,
|
||||
}
|
||||
|
||||
let item = self.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
|
@ -1886,123 +1908,32 @@ impl<'a> Resolver<'a> {
|
|||
// The ident resolves to an item.
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
}
|
||||
|
||||
match module.kind {
|
||||
ModuleKind::Block(..) => {} // We can see through blocks
|
||||
_ => break,
|
||||
}
|
||||
}
|
||||
|
||||
ident = normalized_ident;
|
||||
let mut poisoned = None;
|
||||
loop {
|
||||
let mut span_data = ident.span.data();
|
||||
let opt_module = if let Some(node_id) = record_used_id {
|
||||
self.hygienic_lexical_parent_with_compatibility_fallback(
|
||||
module,
|
||||
&mut span_data.ctxt,
|
||||
node_id,
|
||||
&mut poisoned,
|
||||
)
|
||||
} else {
|
||||
self.hygienic_lexical_parent(module, &mut span_data.ctxt)
|
||||
};
|
||||
ident.span = span_data.span();
|
||||
module = unwrap_or!(opt_module, break);
|
||||
let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
|
||||
let result = self.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
adjusted_parent_scope,
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
|
||||
match result {
|
||||
Ok(binding) => {
|
||||
if let Some(node_id) = poisoned {
|
||||
self.lint_buffer.buffer_lint_with_diagnostic(
|
||||
lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||
node_id,
|
||||
ident.span,
|
||||
&format!("cannot find {} `{}` in this scope", ns.descr(), ident),
|
||||
BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(ident.span),
|
||||
);
|
||||
}
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
}
|
||||
Err(Determined) => continue,
|
||||
Err(Undetermined) => {
|
||||
span_bug!(ident.span, "undetermined resolution during main resolution pass")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if !module.no_implicit_prelude {
|
||||
ident.span.adjust(ExpnId::root());
|
||||
if ns == TypeNS {
|
||||
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
}
|
||||
if let Some(ident) = self.registered_tools.get(&ident) {
|
||||
let binding =
|
||||
(Res::ToolMod, ty::Visibility::Public, ident.span, ExpnId::root())
|
||||
.to_name_binding(self.arenas);
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
}
|
||||
}
|
||||
if let Some(prelude) = self.prelude {
|
||||
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
|
||||
ModuleOrUniformRoot::Module(prelude),
|
||||
ident,
|
||||
ns,
|
||||
parent_scope,
|
||||
false,
|
||||
path_span,
|
||||
) {
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ns == TypeNS {
|
||||
if let Some(prim_ty) = PrimTy::from_name(ident.name) {
|
||||
let binding =
|
||||
(Res::PrimTy(prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
|
||||
.to_name_binding(self.arenas);
|
||||
return Some(LexicalScopeBinding::Item(binding));
|
||||
}
|
||||
}
|
||||
|
||||
None
|
||||
self.early_resolve_ident_in_lexical_scope(
|
||||
orig_ident,
|
||||
ScopeSet::Late(ns, module, record_used_id),
|
||||
parent_scope,
|
||||
record_used,
|
||||
record_used,
|
||||
path_span,
|
||||
)
|
||||
.ok()
|
||||
.map(LexicalScopeBinding::Item)
|
||||
}
|
||||
|
||||
fn hygienic_lexical_parent(
|
||||
&mut self,
|
||||
module: Module<'a>,
|
||||
ctxt: &mut SyntaxContext,
|
||||
) -> Option<Module<'a>> {
|
||||
derive_fallback_lint_id: Option<NodeId>,
|
||||
) -> Option<(Module<'a>, Option<NodeId>)> {
|
||||
if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
|
||||
return Some(self.macro_def_scope(ctxt.remove_mark()));
|
||||
return Some((self.macro_def_scope(ctxt.remove_mark()), None));
|
||||
}
|
||||
|
||||
if let ModuleKind::Block(..) = module.kind {
|
||||
return Some(module.parent.unwrap().nearest_item_scope());
|
||||
}
|
||||
|
||||
None
|
||||
}
|
||||
|
||||
fn hygienic_lexical_parent_with_compatibility_fallback(
|
||||
&mut self,
|
||||
module: Module<'a>,
|
||||
ctxt: &mut SyntaxContext,
|
||||
node_id: NodeId,
|
||||
poisoned: &mut Option<NodeId>,
|
||||
) -> Option<Module<'a>> {
|
||||
if let module @ Some(..) = self.hygienic_lexical_parent(module, ctxt) {
|
||||
return module;
|
||||
return Some((module.parent.unwrap().nearest_item_scope(), None));
|
||||
}
|
||||
|
||||
// We need to support the next case under a deprecation warning
|
||||
|
@ -2016,20 +1947,21 @@ impl<'a> Resolver<'a> {
|
|||
// ---- end
|
||||
// ```
|
||||
// So we have to fall back to the module's parent during lexical resolution in this case.
|
||||
if let Some(parent) = module.parent {
|
||||
// Inner module is inside the macro, parent module is outside of the macro.
|
||||
if module.expansion != parent.expansion
|
||||
&& module.expansion.is_descendant_of(parent.expansion)
|
||||
{
|
||||
// The macro is a proc macro derive
|
||||
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
|
||||
let ext = self.get_macro_by_def_id(def_id);
|
||||
if ext.builtin_name.is_none()
|
||||
&& ext.macro_kind() == MacroKind::Derive
|
||||
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
|
||||
{
|
||||
*poisoned = Some(node_id);
|
||||
return module.parent;
|
||||
if derive_fallback_lint_id.is_some() {
|
||||
if let Some(parent) = module.parent {
|
||||
// Inner module is inside the macro, parent module is outside of the macro.
|
||||
if module.expansion != parent.expansion
|
||||
&& module.expansion.is_descendant_of(parent.expansion)
|
||||
{
|
||||
// The macro is a proc macro derive
|
||||
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
|
||||
let ext = self.get_macro_by_def_id(def_id);
|
||||
if ext.builtin_name.is_none()
|
||||
&& ext.macro_kind() == MacroKind::Derive
|
||||
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
|
||||
{
|
||||
return Some((parent, derive_fallback_lint_id));
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -24,7 +24,8 @@ use rustc_hir::def_id;
|
|||
use rustc_hir::PrimTy;
|
||||
use rustc_middle::middle::stability;
|
||||
use rustc_middle::ty;
|
||||
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, SOFT_UNSTABLE, UNUSED_MACROS};
|
||||
use rustc_session::lint::builtin::{LEGACY_DERIVE_HELPERS, PROC_MACRO_DERIVE_RESOLUTION_FALLBACK};
|
||||
use rustc_session::lint::builtin::{SOFT_UNSTABLE, UNUSED_MACROS};
|
||||
use rustc_session::lint::BuiltinLintDiagnostics;
|
||||
use rustc_session::parse::feature_err;
|
||||
use rustc_session::Session;
|
||||
|
@ -642,7 +643,7 @@ impl<'a> Resolver<'a> {
|
|||
crate fn early_resolve_ident_in_lexical_scope(
|
||||
&mut self,
|
||||
orig_ident: Ident,
|
||||
scope_set: ScopeSet,
|
||||
scope_set: ScopeSet<'a>,
|
||||
parent_scope: &ParentScope<'a>,
|
||||
record_used: bool,
|
||||
force: bool,
|
||||
|
@ -669,6 +670,7 @@ impl<'a> Resolver<'a> {
|
|||
ScopeSet::All(ns, is_import) => (ns, None, is_import),
|
||||
ScopeSet::AbsolutePath(ns) => (ns, None, false),
|
||||
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
|
||||
ScopeSet::Late(ns, ..) => (ns, None, false),
|
||||
};
|
||||
|
||||
// This is *the* result, resolution from the scope closest to the resolved identifier.
|
||||
|
@ -777,19 +779,34 @@ impl<'a> Resolver<'a> {
|
|||
Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
|
||||
}
|
||||
}
|
||||
Scope::Module(module) => {
|
||||
Scope::Module(module, derive_fallback_lint_id) => {
|
||||
let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
|
||||
let binding = this.resolve_ident_in_module_unadjusted_ext(
|
||||
ModuleOrUniformRoot::Module(module),
|
||||
ident,
|
||||
ns,
|
||||
adjusted_parent_scope,
|
||||
true,
|
||||
!matches!(scope_set, ScopeSet::Late(..)),
|
||||
record_used,
|
||||
path_span,
|
||||
);
|
||||
match binding {
|
||||
Ok(binding) => {
|
||||
if let Some(lint_id) = derive_fallback_lint_id {
|
||||
this.lint_buffer.buffer_lint_with_diagnostic(
|
||||
PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
|
||||
lint_id,
|
||||
orig_ident.span,
|
||||
&format!(
|
||||
"cannot find {} `{}` in this scope",
|
||||
ns.descr(),
|
||||
ident
|
||||
),
|
||||
BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(
|
||||
orig_ident.span,
|
||||
),
|
||||
);
|
||||
}
|
||||
let misc_flags = if ptr::eq(module, this.graph_root) {
|
||||
Flags::MISC_SUGGEST_CRATE
|
||||
} else if module.is_normal() {
|
||||
|
@ -873,7 +890,7 @@ impl<'a> Resolver<'a> {
|
|||
Ok((binding, flags))
|
||||
if sub_namespace_match(binding.macro_kind(), macro_kind) =>
|
||||
{
|
||||
if !record_used {
|
||||
if !record_used || matches!(scope_set, ScopeSet::Late(..)) {
|
||||
return Some(Ok(binding));
|
||||
}
|
||||
|
||||
|
|
|
@ -46,7 +46,8 @@ LL | #[derive(generate_mod::CheckDerive)]
|
|||
|
|
||||
= note: `#[warn(proc_macro_derive_resolution_fallback)]` on by default
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
|
||||
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
|
||||
= note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: cannot find type `OuterDerive` in this scope
|
||||
--> $DIR/generate-mod.rs:16:10
|
||||
|
@ -55,7 +56,8 @@ LL | #[derive(generate_mod::CheckDerive)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
|
||||
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
|
||||
= note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: cannot find type `FromOutside` in this scope
|
||||
--> $DIR/generate-mod.rs:23:14
|
||||
|
@ -64,7 +66,8 @@ LL | #[derive(generate_mod::CheckDerive)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
|
||||
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
|
||||
= note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
warning: cannot find type `OuterDerive` in this scope
|
||||
--> $DIR/generate-mod.rs:23:14
|
||||
|
@ -73,7 +76,8 @@ LL | #[derive(generate_mod::CheckDerive)]
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^ names from parent modules are not accessible without an explicit import
|
||||
|
|
||||
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
|
||||
= note: for more information, see issue #50504 <https://github.com/rust-lang/rust/issues/50504>
|
||||
= note: for more information, see issue #83583 <https://github.com/rust-lang/rust/issues/83583>
|
||||
= note: this warning originates in a derive macro (in Nightly builds, run with -Z macro-backtrace for more info)
|
||||
|
||||
error: aborting due to 4 previous errors; 4 warnings emitted
|
||||
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue