提交 ee0357af 编写于 作者: V Vadim Petrochenkov

resolve: Partially unify early and late scope-relative ident resolution

上级 afaf33dc
......@@ -1977,7 +1977,7 @@
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 @@ fn early_lookup_typo_candidate(
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 => {
......
......@@ -25,7 +25,6 @@
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};
......@@ -42,7 +41,7 @@
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;
......@@ -108,7 +107,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,
......@@ -122,13 +123,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.
......@@ -1466,7 +1471,7 @@ pub fn traits_in_scope(
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 => {
......@@ -1630,7 +1635,7 @@ fn add_to_glob_map(&mut self, import: &Import<'_>, ident: Ident) {
/// 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(
......@@ -1686,12 +1691,17 @@ fn visit_scopes<T>(
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();
......@@ -1756,7 +1766,7 @@ fn visit_scopes<T>(
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 => {
......@@ -1765,10 +1775,16 @@ fn visit_scopes<T>(
}
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 {
......@@ -1824,6 +1840,7 @@ fn resolve_ident_in_lexical_scope(
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));
}
......@@ -1873,135 +1890,49 @@ fn resolve_ident_in_lexical_scope(
_ => continue,
};
let item = self.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
parent_scope,
record_used,
path_span,
);
if let Ok(binding) = item {
// 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(
let item = self.resolve_ident_in_module_unadjusted(
ModuleOrUniformRoot::Module(module),
ident,
ns,
adjusted_parent_scope,
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);
if let Ok(binding) = item {
// The ident resolves to an item.
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
......@@ -2015,20 +1946,21 @@ fn hygienic_lexical_parent_with_compatibility_fallback(
// ---- 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::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 @@ pub fn resolve_macro_path(
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 @@ struct Flags: u8 {
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 @@ struct Flags: u8 {
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 @@ struct Flags: u8 {
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
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册