]> git.lizzy.rs Git - rust.git/commitdiff
resolve: Decouple scope visiting process from visitor actions
authorVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 11 Jul 2019 20:05:35 +0000 (23:05 +0300)
committerVadim Petrochenkov <vadim.petrochenkov@gmail.com>
Thu, 18 Jul 2019 10:42:45 +0000 (13:42 +0300)
src/librustc_resolve/lib.rs
src/librustc_resolve/macros.rs

index 8d95025d02b6621424550681fbfa784a9a62c0a5..5cc0c499ec32ca80a7d81b1f51c23d9205b47cad 100644 (file)
@@ -109,6 +109,7 @@ fn determined(determined: bool) -> Determinacy {
 /// A specific scope in which a name can be looked up.
 /// This enum is currently used only for early resolution (imports and macros),
 /// but not for late resolution yet.
+#[derive(Clone, Copy)]
 enum Scope<'a> {
     DeriveHelpers,
     MacroRules(LegacyScope<'a>),
@@ -2143,6 +2144,128 @@ fn add_to_glob_map(&mut self, directive: &ImportDirective<'_>, ident: Ident) {
         }
     }
 
+    /// A generic scope visitor.
+    /// Visits scopes in order to resolve some identifier in them or perform other actions.
+    /// If the callback returns `Some` result, we stop visiting scopes and return it.
+    fn visit_scopes<T>(
+        &mut self,
+        scope_set: ScopeSet,
+        parent_scope: &ParentScope<'a>,
+        mut ident: Ident,
+        mut visitor: impl FnMut(&mut Self, Scope<'a>, Ident) -> Option<T>,
+    ) -> Option<T> {
+        // General principles:
+        // 1. Not controlled (user-defined) names should have higher priority than controlled names
+        //    built into the language or standard library. This way we can add new names into the
+        //    language or standard library without breaking user code.
+        // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
+        // Places to search (in order of decreasing priority):
+        // (Type NS)
+        // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
+        //    (open set, not controlled).
+        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled).
+        // 3. Extern prelude (open, the open part is from macro expansions, not controlled).
+        // 4. Tool modules (closed, controlled right now, but not in the future).
+        // 5. Standard library prelude (de-facto closed, controlled).
+        // 6. Language prelude (closed, controlled).
+        // (Value NS)
+        // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
+        //    (open set, not controlled).
+        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled).
+        // 3. Standard library prelude (de-facto closed, controlled).
+        // (Macro NS)
+        // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
+        //    are currently reported as errors. They should be higher in priority than preludes
+        //    and probably even names in modules according to the "general principles" above. They
+        //    also should be subject to restricted shadowing because are effectively produced by
+        //    derives (you need to resolve the derive first to add helpers into scope), but they
+        //    should be available before the derive is expanded for compatibility.
+        //    It's mess in general, so we are being conservative for now.
+        // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
+        //    priority than prelude macros, but create ambiguities with macros in modules.
+        // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
+        //    (open, not controlled). Have higher priority than prelude macros, but create
+        //    ambiguities with `macro_rules`.
+        // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
+        // 4a. User-defined prelude from macro-use
+        //    (open, the open part is from macro expansions, not controlled).
+        // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
+        // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
+        // 6. Language prelude: builtin attributes (closed, controlled).
+        // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
+        //    but introduced by legacy plugins using `register_attribute`. Priority is somewhere
+        //    in prelude, not sure where exactly (creates ambiguities with any other prelude names).
+
+        let (ns, is_absolute_path) = match scope_set {
+            ScopeSet::Import(ns) => (ns, false),
+            ScopeSet::AbsolutePath(ns) => (ns, true),
+            ScopeSet::Macro(_) => (MacroNS, false),
+            ScopeSet::Module => (TypeNS, false),
+        };
+        let mut scope = match ns {
+            _ if is_absolute_path => Scope::CrateRoot,
+            TypeNS | ValueNS => Scope::Module(parent_scope.module),
+            MacroNS => Scope::DeriveHelpers,
+        };
+
+        loop {
+            if let break_result @ Some(..) = visitor(self, scope, ident) {
+                return break_result;
+            }
+
+            scope = match scope {
+                Scope::DeriveHelpers =>
+                    Scope::MacroRules(parent_scope.legacy),
+                Scope::MacroRules(legacy_scope) => match legacy_scope {
+                    LegacyScope::Binding(binding) => Scope::MacroRules(
+                        binding.parent_legacy_scope
+                    ),
+                    LegacyScope::Invocation(invoc) => Scope::MacroRules(
+                        invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
+                    ),
+                    LegacyScope::Empty => Scope::Module(parent_scope.module),
+                }
+                Scope::CrateRoot => match ns {
+                    TypeNS => {
+                        ident.span.adjust(Mark::root());
+                        Scope::ExternPrelude
+                    }
+                    ValueNS | MacroNS => break,
+                }
+                Scope::Module(module) => {
+                    match self.hygienic_lexical_parent(module, &mut ident.span) {
+                        Some(parent_module) => Scope::Module(parent_module),
+                        None => {
+                            ident.span.adjust(Mark::root());
+                            match ns {
+                                TypeNS => Scope::ExternPrelude,
+                                ValueNS => Scope::StdLibPrelude,
+                                MacroNS => Scope::MacroUsePrelude,
+                            }
+                        }
+                    }
+                }
+                Scope::MacroUsePrelude => Scope::StdLibPrelude,
+                Scope::BuiltinMacros => Scope::BuiltinAttrs,
+                Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
+                Scope::LegacyPluginHelpers => break, // nowhere else to search
+                Scope::ExternPrelude if is_absolute_path => break,
+                Scope::ExternPrelude => Scope::ToolPrelude,
+                Scope::ToolPrelude => Scope::StdLibPrelude,
+                Scope::StdLibPrelude => match ns {
+                    TypeNS => Scope::BuiltinTypes,
+                    ValueNS => break, // nowhere else to search
+                    MacroNS => Scope::BuiltinMacros,
+                }
+                Scope::BuiltinTypes => break, // nowhere else to search
+            };
+        }
+
+        None
+    }
+
     /// This resolves the identifier `ident` in the namespace `ns` in the current lexical scope.
     /// More specifically, we proceed up the hierarchy of scopes and return the binding for
     /// `ident` in the first scope that defines it (or None if no scopes define it).
index 3d10859bf181ae4aad3b3e1d9f46a388bf56bf90..bc10d230dbdc0d5a5299ef8fef8ead66022ad81a 100644 (file)
@@ -59,7 +59,7 @@ pub fn root(graph_root: Module<'a>) -> Self {
 pub struct LegacyBinding<'a> {
     binding: &'a NameBinding<'a>,
     /// Legacy scope into which the `macro_rules` item was planted.
-    parent_legacy_scope: LegacyScope<'a>,
+    crate parent_legacy_scope: LegacyScope<'a>,
     ident: Ident,
 }
 
@@ -421,50 +421,6 @@ pub fn resolve_macro_path(
         force: bool,
         path_span: Span,
     ) -> Result<&'a NameBinding<'a>, Determinacy> {
-        // General principles:
-        // 1. Not controlled (user-defined) names should have higher priority than controlled names
-        //    built into the language or standard library. This way we can add new names into the
-        //    language or standard library without breaking user code.
-        // 2. "Closed set" below means new names cannot appear after the current resolution attempt.
-        // Places to search (in order of decreasing priority):
-        // (Type NS)
-        // 1. FIXME: Ribs (type parameters), there's no necessary infrastructure yet
-        //    (open set, not controlled).
-        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled).
-        // 3. Extern prelude (closed, not controlled).
-        // 4. Tool modules (closed, controlled right now, but not in the future).
-        // 5. Standard library prelude (de-facto closed, controlled).
-        // 6. Language prelude (closed, controlled).
-        // (Value NS)
-        // 1. FIXME: Ribs (local variables), there's no necessary infrastructure yet
-        //    (open set, not controlled).
-        // 2. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled).
-        // 3. Standard library prelude (de-facto closed, controlled).
-        // (Macro NS)
-        // 1-3. Derive helpers (open, not controlled). All ambiguities with other names
-        //    are currently reported as errors. They should be higher in priority than preludes
-        //    and probably even names in modules according to the "general principles" above. They
-        //    also should be subject to restricted shadowing because are effectively produced by
-        //    derives (you need to resolve the derive first to add helpers into scope), but they
-        //    should be available before the derive is expanded for compatibility.
-        //    It's mess in general, so we are being conservative for now.
-        // 1-3. `macro_rules` (open, not controlled), loop through legacy scopes. Have higher
-        //    priority than prelude macros, but create ambiguities with macros in modules.
-        // 1-3. Names in modules (both normal `mod`ules and blocks), loop through hygienic parents
-        //    (open, not controlled). Have higher priority than prelude macros, but create
-        //    ambiguities with `macro_rules`.
-        // 4. `macro_use` prelude (open, the open part is from macro expansions, not controlled).
-        // 4a. User-defined prelude from macro-use
-        //    (open, the open part is from macro expansions, not controlled).
-        // 4b. Standard library prelude is currently implemented as `macro-use` (closed, controlled)
-        // 5. Language prelude: builtin macros (closed, controlled, except for legacy plugins).
-        // 6. Language prelude: builtin attributes (closed, controlled).
-        // 4-6. Legacy plugin helpers (open, not controlled). Similar to derive helpers,
-        //    but introduced by legacy plugins using `register_attribute`. Priority is somewhere
-        //    in prelude, not sure where exactly (creates ambiguities with any other prelude names).
-
         bitflags::bitflags! {
             struct Flags: u8 {
                 const MACRO_RULES        = 1 << 0;
@@ -477,13 +433,21 @@ struct Flags: u8 {
         }
 
         assert!(force || !record_used); // `record_used` implies `force`
-        let mut ident = orig_ident.modern();
+        let ident = orig_ident.modern();
 
         // Make sure `self`, `super` etc produce an error when passed to here.
         if ident.is_path_segment_keyword() {
             return Err(Determinacy::Determined);
         }
 
+        let rust_2015 = orig_ident.span.rust_2015();
+        let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
+            ScopeSet::Import(ns) => (ns, None, true, false),
+            ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
+            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
+            ScopeSet::Module => (TypeNS, None, false, false),
+        };
+
         // This is *the* result, resolution from the scope closest to the resolved identifier.
         // However, sometimes this result is "weak" because it comes from a glob import or
         // a macro expansion, and in this case it cannot shadow names from outer scopes, e.g.
@@ -496,34 +460,22 @@ struct Flags: u8 {
         // So we have to save the innermost solution and continue searching in outer scopes
         // to detect potential ambiguities.
         let mut innermost_result: Option<(&NameBinding<'_>, Flags)> = None;
-
-        // Go through all the scopes and try to resolve the name.
-        let rust_2015 = orig_ident.span.rust_2015();
-        let (ns, macro_kind, is_import, is_absolute_path) = match scope_set {
-            ScopeSet::Import(ns) => (ns, None, true, false),
-            ScopeSet::AbsolutePath(ns) => (ns, None, false, true),
-            ScopeSet::Macro(macro_kind) => (MacroNS, Some(macro_kind), false, false),
-            ScopeSet::Module => (TypeNS, None, false, false),
-        };
-        let mut where_to_resolve = match ns {
-            _ if is_absolute_path => Scope::CrateRoot,
-            TypeNS | ValueNS => Scope::Module(parent_scope.module),
-            MacroNS => Scope::DeriveHelpers,
-        };
         let mut use_prelude = !parent_scope.module.no_implicit_prelude;
         let mut determinacy = Determinacy::Determined;
-        loop {
-            let result = match where_to_resolve {
+
+        // Go through all the scopes and try to resolve the name.
+        let break_result = self.visit_scopes(scope_set, parent_scope, ident, |this, scope, ident| {
+            let result = match scope {
                 Scope::DeriveHelpers => {
                     let mut result = Err(Determinacy::Determined);
                     for derive in &parent_scope.derives {
                         let parent_scope = ParentScope { derives: Vec::new(), ..*parent_scope };
-                        match self.resolve_macro_path(derive, MacroKind::Derive,
+                        match this.resolve_macro_path(derive, MacroKind::Derive,
                                                       &parent_scope, true, force) {
                             Ok((Some(ext), _)) => if ext.helper_attrs.contains(&ident.name) {
                                 let binding = (Res::NonMacroAttr(NonMacroAttrKind::DeriveHelper),
                                                ty::Visibility::Public, derive.span, Mark::root())
-                                               .to_name_binding(self.arenas);
+                                               .to_name_binding(this.arenas);
                                 result = Ok((binding, Flags::empty()));
                                 break;
                             }
@@ -543,8 +495,8 @@ struct Flags: u8 {
                 }
                 Scope::CrateRoot => {
                     let root_ident = Ident::new(kw::PathRoot, orig_ident.span);
-                    let root_module = self.resolve_crate_root(root_ident);
-                    let binding = self.resolve_ident_in_module_ext(
+                    let root_module = this.resolve_crate_root(root_ident);
+                    let binding = this.resolve_ident_in_module_ext(
                         ModuleOrUniformRoot::Module(root_module),
                         orig_ident,
                         ns,
@@ -555,15 +507,16 @@ struct Flags: u8 {
                     match binding {
                         Ok(binding) => Ok((binding, Flags::MODULE | Flags::MISC_SUGGEST_CRATE)),
                         Err((Determinacy::Undetermined, Weak::No)) =>
-                            return Err(Determinacy::determined(force)),
+                            return Some(Err(Determinacy::determined(force))),
                         Err((Determinacy::Undetermined, Weak::Yes)) =>
                             Err(Determinacy::Undetermined),
                         Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
                     }
                 }
                 Scope::Module(module) => {
-                    let orig_current_module = mem::replace(&mut self.current_module, module);
-                    let binding = self.resolve_ident_in_module_unadjusted_ext(
+                    use_prelude = !module.no_implicit_prelude;
+                    let orig_current_module = mem::replace(&mut this.current_module, module);
+                    let binding = this.resolve_ident_in_module_unadjusted_ext(
                         ModuleOrUniformRoot::Module(module),
                         ident,
                         ns,
@@ -572,10 +525,10 @@ struct Flags: u8 {
                         record_used,
                         path_span,
                     );
-                    self.current_module = orig_current_module;
+                    this.current_module = orig_current_module;
                     match binding {
                         Ok(binding) => {
-                            let misc_flags = if ptr::eq(module, self.graph_root) {
+                            let misc_flags = if ptr::eq(module, this.graph_root) {
                                 Flags::MISC_SUGGEST_CRATE
                             } else if module.is_normal() {
                                 Flags::MISC_SUGGEST_SELF
@@ -585,7 +538,7 @@ struct Flags: u8 {
                             Ok((binding, Flags::MODULE | misc_flags))
                         }
                         Err((Determinacy::Undetermined, Weak::No)) =>
-                            return Err(Determinacy::determined(force)),
+                            return Some(Err(Determinacy::determined(force))),
                         Err((Determinacy::Undetermined, Weak::Yes)) =>
                             Err(Determinacy::Undetermined),
                         Err((Determinacy::Determined, _)) => Err(Determinacy::Determined),
@@ -593,11 +546,11 @@ struct Flags: u8 {
                 }
                 Scope::MacroUsePrelude => {
                     if use_prelude || rust_2015 {
-                        match self.macro_use_prelude.get(&ident.name).cloned() {
+                        match this.macro_use_prelude.get(&ident.name).cloned() {
                             Some(binding) =>
                                 Ok((binding, Flags::PRELUDE | Flags::MISC_FROM_PRELUDE)),
                             None => Err(Determinacy::determined(
-                                self.graph_root.unresolved_invocations.borrow().is_empty()
+                                this.graph_root.unresolved_invocations.borrow().is_empty()
                             ))
                         }
                     } else {
@@ -605,7 +558,7 @@ struct Flags: u8 {
                     }
                 }
                 Scope::BuiltinMacros => {
-                    match self.builtin_macros.get(&ident.name).cloned() {
+                    match this.builtin_macros.get(&ident.name).cloned() {
                         Some(binding) => Ok((binding, Flags::PRELUDE)),
                         None => Err(Determinacy::Determined),
                     }
@@ -614,7 +567,7 @@ struct Flags: u8 {
                     if is_builtin_attr_name(ident.name) {
                         let binding = (Res::NonMacroAttr(NonMacroAttrKind::Builtin),
                                        ty::Visibility::Public, DUMMY_SP, Mark::root())
-                                       .to_name_binding(self.arenas);
+                                       .to_name_binding(this.arenas);
                         Ok((binding, Flags::PRELUDE))
                     } else {
                         Err(Determinacy::Determined)
@@ -622,11 +575,11 @@ struct Flags: u8 {
                 }
                 Scope::LegacyPluginHelpers => {
                     if (use_prelude || rust_2015) &&
-                       self.session.plugin_attributes.borrow().iter()
+                       this.session.plugin_attributes.borrow().iter()
                                                      .any(|(name, _)| ident.name == *name) {
                         let binding = (Res::NonMacroAttr(NonMacroAttrKind::LegacyPluginHelper),
                                        ty::Visibility::Public, DUMMY_SP, Mark::root())
-                                       .to_name_binding(self.arenas);
+                                       .to_name_binding(this.arenas);
                         Ok((binding, Flags::PRELUDE))
                     } else {
                         Err(Determinacy::Determined)
@@ -634,10 +587,10 @@ struct Flags: u8 {
                 }
                 Scope::ExternPrelude => {
                     if use_prelude || is_absolute_path {
-                        match self.extern_prelude_get(ident, !record_used) {
+                        match this.extern_prelude_get(ident, !record_used) {
                             Some(binding) => Ok((binding, Flags::PRELUDE)),
                             None => Err(Determinacy::determined(
-                                self.graph_root.unresolved_invocations.borrow().is_empty()
+                                this.graph_root.unresolved_invocations.borrow().is_empty()
                             )),
                         }
                     } else {
@@ -647,7 +600,7 @@ struct Flags: u8 {
                 Scope::ToolPrelude => {
                     if use_prelude && is_known_tool(ident.name) {
                         let binding = (Res::ToolMod, ty::Visibility::Public,
-                                       DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
+                                       DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
                         Ok((binding, Flags::PRELUDE))
                     } else {
                         Err(Determinacy::Determined)
@@ -656,8 +609,8 @@ struct Flags: u8 {
                 Scope::StdLibPrelude => {
                     let mut result = Err(Determinacy::Determined);
                     if use_prelude {
-                        if let Some(prelude) = self.prelude {
-                            if let Ok(binding) = self.resolve_ident_in_module_unadjusted(
+                        if let Some(prelude) = this.prelude {
+                            if let Ok(binding) = this.resolve_ident_in_module_unadjusted(
                                 ModuleOrUniformRoot::Module(prelude),
                                 ident,
                                 ns,
@@ -671,10 +624,10 @@ struct Flags: u8 {
                     result
                 }
                 Scope::BuiltinTypes => {
-                    match self.primitive_type_table.primitive_types.get(&ident.name).cloned() {
+                    match this.primitive_type_table.primitive_types.get(&ident.name).cloned() {
                         Some(prim_ty) => {
                             let binding = (Res::PrimTy(prim_ty), ty::Visibility::Public,
-                                           DUMMY_SP, Mark::root()).to_name_binding(self.arenas);
+                                           DUMMY_SP, Mark::root()).to_name_binding(this.arenas);
                             Ok((binding, Flags::PRELUDE))
                         }
                         None => Err(Determinacy::Determined)
@@ -685,7 +638,7 @@ struct Flags: u8 {
             match result {
                 Ok((binding, flags)) if sub_namespace_match(binding.macro_kind(), macro_kind) => {
                     if !record_used {
-                        return Ok(binding);
+                        return Some(Ok(binding));
                     }
 
                     if let Some((innermost_binding, innermost_flags)) = innermost_result {
@@ -710,11 +663,11 @@ struct Flags: u8 {
                                 Some(AmbiguityKind::LegacyHelperVsPrelude)
                             } else if innermost_flags.contains(Flags::MACRO_RULES) &&
                                       flags.contains(Flags::MODULE) &&
-                                      !self.disambiguate_legacy_vs_modern(innermost_binding,
+                                      !this.disambiguate_legacy_vs_modern(innermost_binding,
                                                                           binding) ||
                                       flags.contains(Flags::MACRO_RULES) &&
                                       innermost_flags.contains(Flags::MODULE) &&
-                                      !self.disambiguate_legacy_vs_modern(binding,
+                                      !this.disambiguate_legacy_vs_modern(binding,
                                                                           innermost_binding) {
                                 Some(AmbiguityKind::LegacyVsModern)
                             } else if innermost_binding.is_glob_import() {
@@ -735,7 +688,7 @@ struct Flags: u8 {
                                 } else {
                                     AmbiguityErrorMisc::None
                                 };
-                                self.ambiguity_errors.push(AmbiguityError {
+                                this.ambiguity_errors.push(AmbiguityError {
                                     kind,
                                     ident: orig_ident,
                                     b1: innermost_binding,
@@ -743,7 +696,7 @@ struct Flags: u8 {
                                     misc1: misc(innermost_flags),
                                     misc2: misc(flags),
                                 });
-                                return Ok(innermost_binding);
+                                return Some(Ok(innermost_binding));
                             }
                         }
                     } else {
@@ -755,55 +708,11 @@ struct Flags: u8 {
                 Err(Determinacy::Undetermined) => determinacy = Determinacy::Undetermined
             }
 
-            where_to_resolve = match where_to_resolve {
-                Scope::DeriveHelpers =>
-                    Scope::MacroRules(parent_scope.legacy),
-                Scope::MacroRules(legacy_scope) => match legacy_scope {
-                    LegacyScope::Binding(binding) => Scope::MacroRules(
-                        binding.parent_legacy_scope
-                    ),
-                    LegacyScope::Invocation(invoc) => Scope::MacroRules(
-                        invoc.output_legacy_scope.get().unwrap_or(invoc.parent_legacy_scope)
-                    ),
-                    LegacyScope::Empty => Scope::Module(parent_scope.module),
-                }
-                Scope::CrateRoot => match ns {
-                    TypeNS => {
-                        ident.span.adjust(Mark::root());
-                        Scope::ExternPrelude
-                    }
-                    ValueNS | MacroNS => break,
-                }
-                Scope::Module(module) => {
-                    match self.hygienic_lexical_parent(module, &mut ident.span) {
-                        Some(parent_module) => Scope::Module(parent_module),
-                        None => {
-                            ident.span.adjust(Mark::root());
-                            use_prelude = !module.no_implicit_prelude;
-                            match ns {
-                                TypeNS => Scope::ExternPrelude,
-                                ValueNS => Scope::StdLibPrelude,
-                                MacroNS => Scope::MacroUsePrelude,
-                            }
-                        }
-                    }
-                }
-                Scope::MacroUsePrelude => Scope::StdLibPrelude,
-                Scope::BuiltinMacros => Scope::BuiltinAttrs,
-                Scope::BuiltinAttrs => Scope::LegacyPluginHelpers,
-                Scope::LegacyPluginHelpers => break, // nowhere else to search
-                Scope::ExternPrelude if is_absolute_path => break,
-                Scope::ExternPrelude => Scope::ToolPrelude,
-                Scope::ToolPrelude => Scope::StdLibPrelude,
-                Scope::StdLibPrelude => match ns {
-                    TypeNS => Scope::BuiltinTypes,
-                    ValueNS => break, // nowhere else to search
-                    MacroNS => Scope::BuiltinMacros,
-                }
-                Scope::BuiltinTypes => break, // nowhere else to search
-            };
+            None
+        });
 
-            continue;
+        if let Some(break_result) = break_result {
+            return break_result;
         }
 
         // The first found solution was the only one, return it.