Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 1e1b081

Browse files
committed
resolve: Decouple scope visiting process from visitor actions
1 parent b302f62 commit 1e1b081

File tree

2 files changed

+170
-138
lines changed

2 files changed

+170
-138
lines changed

src/librustc_resolve/lib.rs

Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -109,6 +109,7 @@ impl Determinacy {
109109
/// A specific scope in which a name can be looked up.
110110
/// This enum is currently used only for early resolution (imports and macros),
111111
/// but not for late resolution yet.
112+
#[derive(Clone, Copy)]
112113
enum Scope<'a> {
113114
DeriveHelpers,
114115
MacroRules(LegacyScope<'a>),
@@ -2143,6 +2144,128 @@ impl<'a> Resolver<'a> {
21432144
}
21442145
}
21452146

2147+
/// A generic scope visitor.
2148+
/// Visits scopes in order to resolve some identifier in them or perform other actions.
2149+
/// If the callback returns `Some` result, we stop visiting scopes and return it.
2150+
fn visit_scopes<T>(
2151+
&mut self,
2152+
scope_set: ScopeSet,
2153+
parent_scope: &ParentScope<'a>,
2154+
mut ident: Ident,
2155+
mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
2156+
) -> Option<T> {
2157+
// General principles:
2158+
// 1. Not controlled (user-defined) names should have higher priority than controlled names
2159+
// built into the language or standard library. This way we can add new names into the
2160+
// language or standard library without breaking user code.
2161+
// 2. "Closed set" below means new names cannot appear after the current resolution attempt.
2162+
// Places to search (in order of decreasing priority):
2163+
// (Type NS)
2164+
// 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
2165+
// (open set, not controlled).
2166+
// 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
2167+
// (open, not controlled).
2168+
// 3. Extern prelude (open, the open part is from macro expansions, not controlled).
2169+
// 4. Tool modules (closed, controlled right now, but not in the future).
2170+
// 5. Standard library prelude (de-facto closed, controlled).
2171+
// 6. Language prelude (closed, controlled).
2172+
// (Value NS)
2173+
// 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
2174+
// (open set, not controlled).
2175+
// 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
2176+
// (open, not controlled).
2177+
// 3. Standard library prelude (de-facto closed, controlled).
2178+
// (Macro NS)
2179+
// 1-3. Derive helpers (open, not controlled). All ambiguities with other names
2180+
// are currently reported as errors. They should be higher in priority than preludes
2181+
// and probably even names in modules according to the "general principles" above. They
2182+
// also should be subject to restricted shadowing because are effectively produced by
2183+
// derives (you need to resolve the derive first to add helpers into scope), but they
2184+
// should be available before the derive is expanded for compatibility.
2185+
// It's mess in general, so we are being conservative for now.
2186+
// 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
2187+
// priority than prelude macros, but create ambiguities with macros in modules.
2188+
// 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
2189+
// (open, not controlled). Have higher priority than prelude macros, but create
2190+
// ambiguities with `macro_rules`.
2191+
// 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
2192+
// 4a. User-defined prelude from macro-use
2193+
// (open, the open part is from macro expansions, not controlled).
2194+
// 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
2195+
// 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
2196+
// 6. Language prelude: builtin attributes (closed, controlled).
2197+
// 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
2198+
// but introduced by legacy plugins using `register_attribute`. Priority is somewhere
2199+
// in prelude, not sure where exactly (creates ambiguities with any other prelude names).
2200+
2201+
let (ns, is_absolute_path) = match scope_set {
2202+
ScopeSet::Import(ns) => (ns, false),
2203+
ScopeSet::AbsolutePath(ns) => (ns, true),
2204+
ScopeSet::Macro(_) => (MacroNS, false),
2205+
ScopeSet::Module => (TypeNS, false),
2206+
};
2207+
let mut scope = match ns {
2208+
_ if is_absolute_path => Scope::CrateRoot,
2209+
TypeNS | ValueNS => Scope::Module(parent_scope.module),
2210+
MacroNS => Scope::DeriveHelpers,
2211+
};
2212+
2213+
loop {
2214+
if let break_result @ Some(..) = visitor(self, scope, ident) {
2215+
return break_result;
2216+
}
2217+
2218+
scope = match scope {
2219+
Scope::DeriveHelpers =>
2220+
Scope::MacroRules(parent_scope.legacy),
2221+
Scope::MacroRules(legacy_scope) => match legacy_scope {
2222+
LegacyScope::Binding(binding) => Scope::MacroRules(
2223+
binding.parent_legacy_scope
2224+
),
2225+
LegacyScope::Invocation(invoc) => Scope::MacroRules(
2226+
invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
2227+
),
2228+
LegacyScope::Empty => Scope::Module(parent_scope.module),
2229+
}
2230+
Scope::CrateRoot => match ns {
2231+
TypeNS => {
2232+
ident.span.adjust(Mark::root());
2233+
Scope::ExternPrelude
2234+
}
2235+
ValueNS | MacroNS => break,
2236+
}
2237+
Scope::Module(module) => {
2238+
match self.hygienic_lexical_parent(module, &mut ident.span) {
2239+
Some(parent_module) => Scope::Module(parent_module),
2240+
None => {
2241+
ident.span.adjust(Mark::root());
2242+
match ns {
2243+
TypeNS => Scope::ExternPrelude,
2244+
ValueNS => Scope::StdLibPrelude,
2245+
MacroNS => Scope::MacroUsePrelude,
2246+
}
2247+
}
2248+
}
2249+
}
2250+
Scope::MacroUsePrelude => Scope::StdLibPrelude,
2251+
Scope::BuiltinMacros => Scope::BuiltinAttrs,
2252+
Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
2253+
Scope::LegacyPluginHelpers => break, // nowhere else to search
2254+
Scope::ExternPrelude if is_absolute_path => break,
2255+
Scope::ExternPrelude => Scope::ToolPrelude,
2256+
Scope::ToolPrelude => Scope::StdLibPrelude,
2257+
Scope::StdLibPrelude => match ns {
2258+
TypeNS => Scope::BuiltinTypes,
2259+
ValueNS => break, // nowhere else to search
2260+
MacroNS => Scope::BuiltinMacros,
2261+
}
2262+
Scope::BuiltinTypes => break, // nowhere else to search
2263+
};
2264+
}
2265+
2266+
None
2267+
}
2268+
21462269
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
21472270
/// More specifically, we proceed up the hierarchy of scopes and return the binding for
21482271
/// `ident` in the first scope that defines it (or None if no scopes define it).

0 commit comments

Comments
 (0)