@@ -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 ) ]
112113enum 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