Skip to content

Commit ee0357a

Browse files
committed
resolve: Partially unify early and late scope-relative ident resolution
1 parent afaf33d commit ee0357a

File tree

5 files changed

+96
-143
lines changed

5 files changed

+96
-143
lines changed

compiler/rustc_lint_defs/src/builtin.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -1977,7 +1977,7 @@ declare_lint! {
19771977
Warn,
19781978
"detects proc macro derives using inaccessible names from parent modules",
19791979
@future_incompatible = FutureIncompatibleInfo {
1980-
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
1980+
reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
19811981
edition: None,
19821982
};
19831983
}

compiler/rustc_resolve/src/diagnostics.rs

+2-2
Original file line numberDiff line numberDiff line change
@@ -606,7 +606,7 @@ impl<'a> Resolver<'a> {
606606
/// Lookup typo candidate in scope for a macro or import.
607607
fn early_lookup_typo_candidate(
608608
&mut self,
609-
scope_set: ScopeSet,
609+
scope_set: ScopeSet<'a>,
610610
parent_scope: &ParentScope<'a>,
611611
ident: Ident,
612612
filter_fn: &impl Fn(Res) -> bool,
@@ -662,7 +662,7 @@ impl<'a> Resolver<'a> {
662662
let root_module = this.resolve_crate_root(root_ident);
663663
this.add_module_candidates(root_module, &mut suggestions, filter_fn);
664664
}
665-
Scope::Module(module) => {
665+
Scope::Module(module, _) => {
666666
this.add_module_candidates(module, &mut suggestions, filter_fn);
667667
}
668668
Scope::RegisteredAttrs => {

compiler/rustc_resolve/src/lib.rs

+63-131
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@ use Determinacy::*;
2525
use rustc_arena::{DroplessArena, TypedArena};
2626
use rustc_ast::node_id::NodeMap;
2727
use rustc_ast::ptr::P;
28-
use rustc_ast::unwrap_or;
2928
use rustc_ast::visit::{self, Visitor};
3029
use rustc_ast::{self as ast, NodeId};
3130
use rustc_ast::{Crate, CRATE_NODE_ID};
@@ -42,7 +41,7 @@ use rustc_hir::def::Namespace::*;
4241
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
4342
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
4443
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
45-
use rustc_hir::{PrimTy, TraitCandidate};
44+
use rustc_hir::TraitCandidate;
4645
use rustc_index::vec::IndexVec;
4746
use rustc_metadata::creader::{CStore, CrateLoader};
4847
use rustc_middle::hir::exports::ExportMap;
@@ -108,7 +107,9 @@ enum Scope<'a> {
108107
DeriveHelpersCompat,
109108
MacroRules(MacroRulesScopeRef<'a>),
110109
CrateRoot,
111-
Module(Module<'a>),
110+
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
111+
// lint if it should be reported.
112+
Module(Module<'a>, Option<NodeId>),
112113
RegisteredAttrs,
113114
MacroUsePrelude,
114115
BuiltinAttrs,
@@ -122,13 +123,17 @@ enum Scope<'a> {
122123
/// with different restrictions when looking up the resolution.
123124
/// This enum is currently used only for early resolution (imports and macros),
124125
/// but not for late resolution yet.
125-
enum ScopeSet {
126+
#[derive(Clone, Copy)]
127+
enum ScopeSet<'a> {
126128
/// All scopes with the given namespace.
127129
All(Namespace, /*is_import*/ bool),
128130
/// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
129131
AbsolutePath(Namespace),
130132
/// All scopes with macro namespace and the given macro kind restriction.
131133
Macro(MacroKind),
134+
/// All scopes with the given namespace, used for partially performing late resolution.
135+
/// The node id enables lints and is used for reporting them.
136+
Late(Namespace, Module<'a>, Option<NodeId>),
132137
}
133138

134139
/// Everything you need to know about a name's location to resolve it.
@@ -1466,7 +1471,7 @@ impl<'a> Resolver<'a> {
14661471

14671472
self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
14681473
match scope {
1469-
Scope::Module(module) => {
1474+
Scope::Module(module, _) => {
14701475
this.traits_in_module(module, assoc_item, &mut found_traits);
14711476
}
14721477
Scope::StdLibPrelude => {
@@ -1630,7 +1635,7 @@ impl<'a> Resolver<'a> {
16301635
/// If the callback returns `Some` result, we stop visiting scopes and return it.
16311636
fn visit_scopes<T>(
16321637
&mut self,
1633-
scope_set: ScopeSet,
1638+
scope_set: ScopeSet<'a>,
16341639
parent_scope: &ParentScope<'a>,
16351640
ctxt: SyntaxContext,
16361641
mut visitor: impl FnMut(
@@ -1686,12 +1691,17 @@ impl<'a> Resolver<'a> {
16861691
ScopeSet::All(ns, _) => (ns, None, false),
16871692
ScopeSet::AbsolutePath(ns) => (ns, None, true),
16881693
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
1694+
ScopeSet::Late(ns, ..) => (ns, None, false),
1695+
};
1696+
let module = match scope_set {
1697+
// Start with the specified module.
1698+
ScopeSet::Late(_, module, _) => module,
1699+
// Jump out of trait or enum modules, they do not act as scopes.
1700+
_ => parent_scope.module.nearest_item_scope(),
16891701
};
1690-
// Jump out of trait or enum modules, they do not act as scopes.
1691-
let module = parent_scope.module.nearest_item_scope();
16921702
let mut scope = match ns {
16931703
_ if is_absolute_path => Scope::CrateRoot,
1694-
TypeNS | ValueNS => Scope::Module(module),
1704+
TypeNS | ValueNS => Scope::Module(module, None),
16951705
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
16961706
};
16971707
let mut ctxt = ctxt.normalize_to_macros_2_0();
@@ -1756,7 +1766,7 @@ impl<'a> Resolver<'a> {
17561766
MacroRulesScope::Invocation(invoc_id) => {
17571767
Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
17581768
}
1759-
MacroRulesScope::Empty => Scope::Module(module),
1769+
MacroRulesScope::Empty => Scope::Module(module, None),
17601770
},
17611771
Scope::CrateRoot => match ns {
17621772
TypeNS => {
@@ -1765,10 +1775,16 @@ impl<'a> Resolver<'a> {
17651775
}
17661776
ValueNS | MacroNS => break,
17671777
},
1768-
Scope::Module(module) => {
1778+
Scope::Module(module, prev_lint_id) => {
17691779
use_prelude = !module.no_implicit_prelude;
1770-
match self.hygienic_lexical_parent(module, &mut ctxt) {
1771-
Some(parent_module) => Scope::Module(parent_module),
1780+
let derive_fallback_lint_id = match scope_set {
1781+
ScopeSet::Late(.., lint_id) => lint_id,
1782+
_ => None,
1783+
};
1784+
match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
1785+
Some((parent_module, lint_id)) => {
1786+
Scope::Module(parent_module, lint_id.or(prev_lint_id))
1787+
}
17721788
None => {
17731789
ctxt.adjust(ExpnId::root());
17741790
match ns {
@@ -1824,6 +1840,7 @@ impl<'a> Resolver<'a> {
18241840
ribs: &[Rib<'a>],
18251841
) -> Option<LexicalScopeBinding<'a>> {
18261842
assert!(ns == TypeNS || ns == ValueNS);
1843+
let orig_ident = ident;
18271844
if ident.name == kw::Empty {
18281845
return Some(LexicalScopeBinding::Res(Res::Err));
18291846
}
@@ -1873,135 +1890,49 @@ impl<'a> Resolver<'a> {
18731890
_ => continue,
18741891
};
18751892

1876-
let item = self.resolve_ident_in_module_unadjusted(
1877-
ModuleOrUniformRoot::Module(module),
1878-
ident,
1879-
ns,
1880-
parent_scope,
1881-
record_used,
1882-
path_span,
1883-
);
1884-
if let Ok(binding) = item {
1885-
// The ident resolves to an item.
1886-
return Some(LexicalScopeBinding::Item(binding));
1887-
}
1888-
18891893
match module.kind {
18901894
ModuleKind::Block(..) => {} // We can see through blocks
18911895
_ => break,
18921896
}
1893-
}
18941897

1895-
ident = normalized_ident;
1896-
let mut poisoned = None;
1897-
loop {
1898-
let mut span_data = ident.span.data();
1899-
let opt_module = if let Some(node_id) = record_used_id {
1900-
self.hygienic_lexical_parent_with_compatibility_fallback(
1901-
module,
1902-
&mut span_data.ctxt,
1903-
node_id,
1904-
&mut poisoned,
1905-
)
1906-
} else {
1907-
self.hygienic_lexical_parent(module, &mut span_data.ctxt)
1908-
};
1909-
ident.span = span_data.span();
1910-
module = unwrap_or!(opt_module, break);
1911-
let adjusted_parent_scope = &ParentScope { module, ..*parent_scope };
1912-
let result = self.resolve_ident_in_module_unadjusted(
1898+
let item = self.resolve_ident_in_module_unadjusted(
19131899
ModuleOrUniformRoot::Module(module),
19141900
ident,
19151901
ns,
1916-
adjusted_parent_scope,
1902+
parent_scope,
19171903
record_used,
19181904
path_span,
19191905
);
1920-
1921-
match result {
1922-
Ok(binding) => {
1923-
if let Some(node_id) = poisoned {
1924-
self.lint_buffer.buffer_lint_with_diagnostic(
1925-
lint::builtin::PROC_MACRO_DERIVE_RESOLUTION_FALLBACK,
1926-
node_id,
1927-
ident.span,
1928-
&format!("cannot find {} `{}` in this scope", ns.descr(), ident),
1929-
BuiltinLintDiagnostics::ProcMacroDeriveResolutionFallback(ident.span),
1930-
);
1931-
}
1932-
return Some(LexicalScopeBinding::Item(binding));
1933-
}
1934-
Err(Determined) => continue,
1935-
Err(Undetermined) => {
1936-
span_bug!(ident.span, "undetermined resolution during main resolution pass")
1937-
}
1938-
}
1939-
}
1940-
1941-
if !module.no_implicit_prelude {
1942-
ident.span.adjust(ExpnId::root());
1943-
if ns == TypeNS {
1944-
if let Some(binding) = self.extern_prelude_get(ident, !record_used) {
1945-
return Some(LexicalScopeBinding::Item(binding));
1946-
}
1947-
if let Some(ident) = self.registered_tools.get(&ident) {
1948-
let binding =
1949-
(Res::ToolMod, ty::Visibility::Public, ident.span, ExpnId::root())
1950-
.to_name_binding(self.arenas);
1951-
return Some(LexicalScopeBinding::Item(binding));
1952-
}
1953-
}
1954-
if let Some(prelude) = self.prelude {
1955-
if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
1956-
ModuleOrUniformRoot::Module(prelude),
1957-
ident,
1958-
ns,
1959-
parent_scope,
1960-
false,
1961-
path_span,
1962-
) {
1963-
return Some(LexicalScopeBinding::Item(binding));
1964-
}
1965-
}
1966-
}
1967-
1968-
if ns == TypeNS {
1969-
if let Some(prim_ty) = PrimTy::from_name(ident.name) {
1970-
let binding =
1971-
(Res::PrimTy(prim_ty), ty::Visibility::Public, DUMMY_SP, ExpnId::root())
1972-
.to_name_binding(self.arenas);
1906+
if let Ok(binding) = item {
1907+
// The ident resolves to an item.
19731908
return Some(LexicalScopeBinding::Item(binding));
19741909
}
19751910
}
19761911

1977-
None
1912+
self.early_resolve_ident_in_lexical_scope(
1913+
orig_ident,
1914+
ScopeSet::Late(ns, module, record_used_id),
1915+
parent_scope,
1916+
record_used,
1917+
record_used,
1918+
path_span,
1919+
)
1920+
.ok()
1921+
.map(LexicalScopeBinding::Item)
19781922
}
19791923

19801924
fn hygienic_lexical_parent(
19811925
&mut self,
19821926
module: Module<'a>,
19831927
ctxt: &mut SyntaxContext,
1984-
) -> Option<Module<'a>> {
1928+
derive_fallback_lint_id: Option<NodeId>,
1929+
) -> Option<(Module<'a>, Option<NodeId>)> {
19851930
if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
1986-
return Some(self.macro_def_scope(ctxt.remove_mark()));
1931+
return Some((self.macro_def_scope(ctxt.remove_mark()), None));
19871932
}
19881933

19891934
if let ModuleKind::Block(..) = module.kind {
1990-
return Some(module.parent.unwrap().nearest_item_scope());
1991-
}
1992-
1993-
None
1994-
}
1995-
1996-
fn hygienic_lexical_parent_with_compatibility_fallback(
1997-
&mut self,
1998-
module: Module<'a>,
1999-
ctxt: &mut SyntaxContext,
2000-
node_id: NodeId,
2001-
poisoned: &mut Option<NodeId>,
2002-
) -> Option<Module<'a>> {
2003-
if let module @ Some(..) = self.hygienic_lexical_parent(module, ctxt) {
2004-
return module;
1935+
return Some((module.parent.unwrap().nearest_item_scope(), None));
20051936
}
20061937

20071938
// We need to support the next case under a deprecation warning
@@ -2015,20 +1946,21 @@ impl<'a> Resolver<'a> {
20151946
// ---- end
20161947
// ```
20171948
// So we have to fall back to the module's parent during lexical resolution in this case.
2018-
if let Some(parent) = module.parent {
2019-
// Inner module is inside the macro, parent module is outside of the macro.
2020-
if module.expansion != parent.expansion
2021-
&& module.expansion.is_descendant_of(parent.expansion)
2022-
{
2023-
// The macro is a proc macro derive
2024-
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
2025-
let ext = self.get_macro_by_def_id(def_id);
2026-
if ext.builtin_name.is_none()
2027-
&& ext.macro_kind() == MacroKind::Derive
2028-
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
2029-
{
2030-
*poisoned = Some(node_id);
2031-
return module.parent;
1949+
if derive_fallback_lint_id.is_some() {
1950+
if let Some(parent) = module.parent {
1951+
// Inner module is inside the macro, parent module is outside of the macro.
1952+
if module.expansion != parent.expansion
1953+
&& module.expansion.is_descendant_of(parent.expansion)
1954+
{
1955+
// The macro is a proc macro derive
1956+
if let Some(def_id) = module.expansion.expn_data().macro_def_id {
1957+
let ext = self.get_macro_by_def_id(def_id);
1958+
if ext.builtin_name.is_none()
1959+
&& ext.macro_kind() == MacroKind::Derive
1960+
&& parent.expansion.outer_expn_is_descendant_of(*ctxt)
1961+
{
1962+
return Some((parent, derive_fallback_lint_id));
1963+
}
20321964
}
20331965
}
20341966
}

0 commit comments

Comments
 (0)