Skip to content

Commit 8cd7d86

Browse files
committed
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 #52389 at least).
2 parents 9b0edb7 + ee0357a commit 8cd7d86

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
@@ -1935,7 +1935,7 @@ declare_lint! {
19351935
Warn,
19361936
"detects proc macro derives using inaccessible names from parent modules",
19371937
@future_incompatible = FutureIncompatibleInfo {
1938-
reference: "issue #50504 <https://github.com/rust-lang/rust/issues/50504>",
1938+
reference: "issue #83583 <https://github.com/rust-lang/rust/issues/83583>",
19391939
edition: None,
19401940
};
19411941
}

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
@@ -26,7 +26,6 @@ use Determinacy::*;
2626
use rustc_arena::{DroplessArena, TypedArena};
2727
use rustc_ast::node_id::NodeMap;
2828
use rustc_ast::ptr::P;
29-
use rustc_ast::unwrap_or;
3029
use rustc_ast::visit::{self, Visitor};
3130
use rustc_ast::{self as ast, NodeId};
3231
use rustc_ast::{Crate, CRATE_NODE_ID};
@@ -43,7 +42,7 @@ use rustc_hir::def::Namespace::*;
4342
use rustc_hir::def::{self, CtorOf, DefKind, NonMacroAttrKind, PartialRes};
4443
use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, CRATE_DEF_INDEX};
4544
use rustc_hir::definitions::{DefKey, DefPathData, Definitions};
46-
use rustc_hir::{PrimTy, TraitCandidate};
45+
use rustc_hir::TraitCandidate;
4746
use rustc_index::vec::IndexVec;
4847
use rustc_metadata::creader::{CStore, CrateLoader};
4948
use rustc_middle::hir::exports::ExportMap;
@@ -109,7 +108,9 @@ enum Scope<'a> {
109108
DeriveHelpersCompat,
110109
MacroRules(MacroRulesScopeRef<'a>),
111110
CrateRoot,
112-
Module(Module<'a>),
111+
// The node ID is for reporting the `PROC_MACRO_DERIVE_RESOLUTION_FALLBACK`
112+
// lint if it should be reported.
113+
Module(Module<'a>, Option<NodeId>),
113114
RegisteredAttrs,
114115
MacroUsePrelude,
115116
BuiltinAttrs,
@@ -123,13 +124,17 @@ enum Scope<'a> {
123124
/// with different restrictions when looking up the resolution.
124125
/// This enum is currently used only for early resolution (imports and macros),
125126
/// but not for late resolution yet.
126-
enum ScopeSet {
127+
#[derive(Clone, Copy)]
128+
enum ScopeSet<'a> {
127129
/// All scopes with the given namespace.
128130
All(Namespace, /*is_import*/ bool),
129131
/// Crate root, then extern prelude (used for mixed 2015-2018 mode in macros).
130132
AbsolutePath(Namespace),
131133
/// All scopes with macro namespace and the given macro kind restriction.
132134
Macro(MacroKind),
135+
/// All scopes with the given namespace, used for partially performing late resolution.
136+
/// The node id enables lints and is used for reporting them.
137+
Late(Namespace, Module<'a>, Option<NodeId>),
133138
}
134139

135140
/// Everything you need to know about a name's location to resolve it.
@@ -1467,7 +1472,7 @@ impl<'a> Resolver<'a> {
14671472

14681473
self.visit_scopes(ScopeSet::All(TypeNS, false), parent_scope, ctxt, |this, scope, _, _| {
14691474
match scope {
1470-
Scope::Module(module) => {
1475+
Scope::Module(module, _) => {
14711476
this.traits_in_module(module, assoc_item, &mut found_traits);
14721477
}
14731478
Scope::StdLibPrelude => {
@@ -1631,7 +1636,7 @@ impl<'a> Resolver<'a> {
16311636
/// If the callback returns `Some` result, we stop visiting scopes and return it.
16321637
fn visit_scopes<T>(
16331638
&mut self,
1634-
scope_set: ScopeSet,
1639+
scope_set: ScopeSet<'a>,
16351640
parent_scope: &ParentScope<'a>,
16361641
ctxt: SyntaxContext,
16371642
mut visitor: impl FnMut(
@@ -1687,12 +1692,17 @@ impl<'a> Resolver<'a> {
16871692
ScopeSet::All(ns, _) => (ns, None, false),
16881693
ScopeSet::AbsolutePath(ns) => (ns, None, true),
16891694
ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false),
1695+
ScopeSet::Late(ns, ..) => (ns, None, false),
1696+
};
1697+
let module = match scope_set {
1698+
// Start with the specified module.
1699+
ScopeSet::Late(_, module, _) => module,
1700+
// Jump out of trait or enum modules, they do not act as scopes.
1701+
_ => parent_scope.module.nearest_item_scope(),
16901702
};
1691-
// Jump out of trait or enum modules, they do not act as scopes.
1692-
let module = parent_scope.module.nearest_item_scope();
16931703
let mut scope = match ns {
16941704
_ if is_absolute_path => Scope::CrateRoot,
1695-
TypeNS | ValueNS => Scope::Module(module),
1705+
TypeNS | ValueNS => Scope::Module(module, None),
16961706
MacroNS => Scope::DeriveHelpers(parent_scope.expansion),
16971707
};
16981708
let mut ctxt = ctxt.normalize_to_macros_2_0();
@@ -1757,7 +1767,7 @@ impl<'a> Resolver<'a> {
17571767
MacroRulesScope::Invocation(invoc_id) => {
17581768
Scope::MacroRules(self.invocation_parent_scopes[&invoc_id].macro_rules)
17591769
}
1760-
MacroRulesScope::Empty => Scope::Module(module),
1770+
MacroRulesScope::Empty => Scope::Module(module, None),
17611771
},
17621772
Scope::CrateRoot => match ns {
17631773
TypeNS => {
@@ -1766,10 +1776,16 @@ impl<'a> Resolver<'a> {
17661776
}
17671777
ValueNS | MacroNS => break,
17681778
},
1769-
Scope::Module(module) => {
1779+
Scope::Module(module, prev_lint_id) => {
17701780
use_prelude = !module.no_implicit_prelude;
1771-
match self.hygienic_lexical_parent(module, &mut ctxt) {
1772-
Some(parent_module) => Scope::Module(parent_module),
1781+
let derive_fallback_lint_id = match scope_set {
1782+
ScopeSet::Late(.., lint_id) => lint_id,
1783+
_ => None,
1784+
};
1785+
match self.hygienic_lexical_parent(module, &mut ctxt, derive_fallback_lint_id) {
1786+
Some((parent_module, lint_id)) => {
1787+
Scope::Module(parent_module, lint_id.or(prev_lint_id))
1788+
}
17731789
None => {
17741790
ctxt.adjust(ExpnId::root());
17751791
match ns {
@@ -1825,6 +1841,7 @@ impl<'a> Resolver<'a> {
18251841
ribs: &[Rib<'a>],
18261842
) -> Option<LexicalScopeBinding<'a>> {
18271843
assert!(ns == TypeNS || ns == ValueNS);
1844+
let orig_ident = ident;
18281845
if ident.name == kw::Empty {
18291846
return Some(LexicalScopeBinding::Res(Res::Err));
18301847
}
@@ -1874,135 +1891,49 @@ impl<'a> Resolver<'a> {
18741891
_ => continue,
18751892
};
18761893

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

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

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

19811925
fn hygienic_lexical_parent(
19821926
&mut self,
19831927
module: Module<'a>,
19841928
ctxt: &mut SyntaxContext,
1985-
) -> Option<Module<'a>> {
1929+
derive_fallback_lint_id: Option<NodeId>,
1930+
) -> Option<(Module<'a>, Option<NodeId>)> {
19861931
if !module.expansion.outer_expn_is_descendant_of(*ctxt) {
1987-
return Some(self.macro_def_scope(ctxt.remove_mark()));
1932+
return Some((self.macro_def_scope(ctxt.remove_mark()), None));
19881933
}
19891934

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

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

0 commit comments

Comments
 (0)