@@ -109,6 +109,7 @@ impl Determinacy {
109
109
/// A specific scope in which a name can be looked up.
110
110
/// This enum is currently used only for early resolution (imports and macros),
111
111
/// but not for late resolution yet.
112
+ #[ derive( Clone , Copy ) ]
112
113
enum Scope < ' a > {
113
114
DeriveHelpers ,
114
115
MacroRules ( LegacyScope < ' a > ) ,
@@ -2143,6 +2144,128 @@ impl<'a> Resolver<'a> {
2143
2144
}
2144
2145
}
2145
2146
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
+
2146
2269
/// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
2147
2270
/// More specifically, we proceed up the hierarchy of scopes and return the binding for
2148
2271
/// `ident` in the first scope that defines it (or None if no scopes define it).
0 commit comments