Repository: rust-lang/rust-analyzer
Pull request #17666 (2024-07-22 07:54:51)

Simplify


Patch:
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index 91594aecd0..a3a602c2c1 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -2,12 +2,11 @@
 
 use std::{cell::Cell, cmp::Ordering, iter};
 
-use base_db::{CrateId, CrateOrigin, LangCrateOrigin};
 use hir_expand::{
     name::{AsName, Name},
     Lookup,
 };
-use intern::sym;
+use intern::{sym, Symbol};
 use rustc_hash::FxHashSet;
 
 use crate::{
@@ -38,8 +37,7 @@ pub fn find_path(
 
     // within block modules, forcing a `self` or `crate` prefix will not allow using inner items, so
     // default to plain paths.
-    let item_module = item.module(db)?;
-    if item_module.is_within_block() {
+    if item.module(db).is_some_and(ModuleId::is_within_block) {
         prefix_kind = PrefixKind::Plain;
     }
     cfg.prefer_no_std = cfg.prefer_no_std || db.crate_supports_no_std(from.krate());
@@ -56,17 +54,23 @@ pub fn find_path(
         },
         item,
         MAX_PATH_LEN,
-        db.crate_graph()[item_module.krate()].origin.is_lang(),
     )
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq, PartialOrd, Ord)]
+#[derive(Copy, Clone, Debug, PartialEq, Eq)]
 enum Stability {
     Unstable,
     Stable,
 }
 use Stability::*;
 
+fn zip_stability(a: Stability, b: Stability) -> Stability {
+    match (a, b) {
+        (Stable, Stable) => Stable,
+        _ => Unstable,
+    }
+}
+
 const MAX_PATH_LEN: usize = 15;
 const FIND_PATH_FUEL: usize = 10000;
 
@@ -104,18 +108,12 @@ struct FindPathCtx<'db> {
 }
 
 /// Attempts to find a path to refer to the given `item` visible from the `from` ModuleId
-fn find_path_inner(
-    ctx: &FindPathCtx<'_>,
-    item: ItemInNs,
-    max_len: usize,
-    is_std_item: bool,
-) -> Option<ModPath> {
+fn find_path_inner(ctx: &FindPathCtx<'_>, item: ItemInNs, max_len: usize) -> Option<ModPath> {
     // - if the item is a module, jump straight to module search
-    if !is_std_item {
-        if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
-            return find_path_for_module(ctx, &mut FxHashSet::default(), module_id, true, max_len)
-                .map(|choice| choice.path);
-        }
+    if let ItemInNs::Types(ModuleDefId::ModuleId(module_id)) = item {
+        let mut visited_modules = FxHashSet::default();
+        return find_path_for_module(ctx, &mut visited_modules, module_id, max_len)
+            .map(|(item, _)| item);
     }
 
     let may_be_in_scope = match ctx.prefix {
@@ -133,17 +131,14 @@ fn find_path_inner(
 
     // - if the item is in the prelude, return the name from there
     if let Some(value) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) {
-        return Some(value.path);
+        return Some(value);
     }
 
     if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
         // - if the item is an enum variant, refer to it via the enum
-        if let Some(mut path) = find_path_inner(
-            ctx,
-            ItemInNs::Types(variant.lookup(ctx.db).parent.into()),
-            max_len,
-            is_std_item,
-        ) {
+        if let Some(mut path) =
+            find_path_inner(ctx, ItemInNs::Types(variant.lookup(ctx.db).parent.into()), max_len)
+        {
             path.push_segment(ctx.db.enum_variant_data(variant).name.clone());
             return Some(path);
         }
@@ -152,42 +147,22 @@ fn find_path_inner(
         // variant somewhere
     }
 
-    if is_std_item {
-        // The item we are searching for comes from the sysroot libraries, so skip prefer looking in
-        // the sysroot libraries directly.
-        // We do need to fallback as the item in question could be re-exported by another crate
-        // while not being a transitive dependency of the current crate.
-        if let Some(choice) = find_in_sysroot(ctx, &mut FxHashSet::default(), item, max_len) {
-            return Some(choice.path);
-        }
-    }
+    let mut visited_modules = FxHashSet::default();
 
-    let mut best_choice = None;
-    calculate_best_path(ctx, &mut FxHashSet::default(), item, max_len, &mut best_choice);
-    best_choice.map(|choice| choice.path)
+    calculate_best_path(ctx, &mut visited_modules, item, max_len).map(|(item, _)| item)
 }
 
 #[tracing::instrument(skip_all)]
 fn find_path_for_module(
     ctx: &FindPathCtx<'_>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
+    visited_modules: &mut FxHashSet<ModuleId>,
     module_id: ModuleId,
-    maybe_extern: bool,
     max_len: usize,
-) -> Option<Choice> {
-    if max_len == 0 {
-        // recursive base case, we can't find a path of length 0
-        return None;
-    }
+) -> Option<(ModPath, Stability)> {
     if let Some(crate_root) = module_id.as_crate_root() {
-        if !maybe_extern || crate_root == ctx.from.derive_crate_root() {
+        if crate_root == ctx.from.derive_crate_root() {
             // - if the item is the crate root, return `crate`
-            return Some(Choice {
-                path: ModPath::from_segments(PathKind::Crate, None),
-                path_text_len: 5,
-                stability: Stable,
-                prefer_due_to_prelude: false,
-            });
+            return Some((ModPath::from_segments(PathKind::Crate, None), Stable));
         }
         // - otherwise if the item is the crate root of a dependency crate, return the name from the extern prelude
 
@@ -214,7 +189,7 @@ fn find_path_for_module(
             } else {
                 PathKind::Plain
             };
-            return Some(Choice::new(ctx.cfg.prefer_prelude, kind, name.clone(), Stable));
+            return Some((ModPath::from_segments(kind, iter::once(name.clone())), Stable));
         }
     }
 
@@ -232,39 +207,27 @@ fn find_path_for_module(
         );
         if let Some(scope_name) = scope_name {
             // - if the item is already in scope, return the name under which it is
-            return Some(Choice::new(
-                ctx.cfg.prefer_prelude,
-                ctx.prefix.path_kind(),
-                scope_name,
+            return Some((
+                ModPath::from_segments(ctx.prefix.path_kind(), iter::once(scope_name)),
                 Stable,
             ));
         }
     }
 
     // - if the module can be referenced as self, super or crate, do that
-    if let Some(kind) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) {
-        if ctx.prefix != PrefixKind::ByCrate || kind == PathKind::Crate {
-            return Some(Choice {
-                path: ModPath::from_segments(kind, None),
-                path_text_len: path_kind_len(kind),
-                stability: Stable,
-                prefer_due_to_prelude: false,
-            });
+    if let Some(mod_path) = is_kw_kind_relative_to_from(ctx.from_def_map, module_id, ctx.from) {
+        if ctx.prefix != PrefixKind::ByCrate || mod_path.kind == PathKind::Crate {
+            return Some((mod_path, Stable));
         }
     }
 
     // - if the module is in the prelude, return it by that path
-    let item = ItemInNs::Types(module_id.into());
-    if let Some(choice) = find_in_prelude(ctx.db, ctx.from_def_map, item, ctx.from) {
-        return Some(choice);
-    }
-    let mut best_choice = None;
-    if maybe_extern {
-        calculate_best_path(ctx, visited_modules, item, max_len, &mut best_choice);
-    } else {
-        calculate_best_path_local(ctx, visited_modules, item, max_len, &mut best_choice);
+    if let Some(mod_path) =
+        find_in_prelude(ctx.db, ctx.from_def_map, ItemInNs::Types(module_id.into()), ctx.from)
+    {
+        return Some((mod_path, Stable));
     }
-    best_choice
+    calculate_best_path(ctx, visited_modules, ItemInNs::Types(module_id.into()), max_len)
 }
 
 fn find_in_scope(
@@ -289,7 +252,7 @@ fn find_in_prelude(
     local_def_map: &DefMap,
     item: ItemInNs,
     from: ModuleId,
-) -> Option<Choice> {
+) -> Option<ModPath> {
     let (prelude_module, _) = local_def_map.prelude()?;
     let prelude_def_map = prelude_module.def_map(db);
     let prelude_scope = &prelude_def_map[prelude_module.local_id].scope;
@@ -311,7 +274,7 @@ fn find_in_prelude(
         });
 
     if found_and_same_def.unwrap_or(true) {
-        Some(Choice::new(false, PathKind::Plain, name.clone(), Stable))
+        Some(ModPath::from_segments(PathKind::Plain, iter::once(name.clone())))
     } else {
         None
     }
@@ -321,7 +284,7 @@ fn is_kw_kind_relative_to_from(
     def_map: &DefMap,
     item: ModuleId,
     from: ModuleId,
-) -> Option<PathKind> {
+) -> Option<ModPath> {
     if item.krate != from.krate || item.is_within_block() || from.is_within_block() {
         return None;
     }
@@ -329,11 +292,14 @@ fn is_kw_kind_relative_to_from(
     let from = from.local_id;
     if item == from {
         // - if the item is the module we're in, use `self`
-        Some(PathKind::SELF)
+        Some(ModPath::from_segments(PathKind::SELF, None))
     } else if let Some(parent_id) = def_map[from].parent {
         if item == parent_id {
             // - if the item is the parent module, use `super` (this is not used recursively, since `super::super` is ugly)
-            Some(if parent_id == DefMap::ROOT { PathKind::Crate } else { PathKind::Super(1) })
+            Some(ModPath::from_segments(
+                if parent_id == DefMap::ROOT { PathKind::Crate } else { PathKind::Super(1) },
+                None,
+            ))
         } else {
             None
         }
@@ -345,11 +311,15 @@ fn is_kw_kind_relative_to_from(
 #[tracing::instrument(skip_all)]
 fn calculate_best_path(
     ctx: &FindPathCtx<'_>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
+    visited_modules: &mut FxHashSet<ModuleId>,
     item: ItemInNs,
     max_len: usize,
-    best_choice: &mut Option<Choice>,
-) {
+) -> Option<(ModPath, Stability)> {
+    if max_len <= 1 {
+        // recursive base case, we can't find a path prefix of length 0, one segment is occupied by
+        // the item's name itself.
+        return None;
+    }
     let fuel = ctx.fuel.get();
     if fuel == 0 {
         // we ran out of fuel, so we stop searching here
@@ -358,208 +328,146 @@ fn calculate_best_path(
             item.krate(ctx.db),
             ctx.from.krate()
         );
-        return;
+        return None;
     }
     ctx.fuel.set(fuel - 1);
 
-    if item.krate(ctx.db) == Some(ctx.from.krate) {
+    let mut best_path = None;
+    let mut best_path_len = max_len;
+    let mut process = |mut path: (ModPath, Stability), name, best_path_len: &mut _| {
+        path.0.push_segment(name);
+        let new_path = match best_path.take() {
+            Some(best_path) => select_best_path(best_path, path, ctx.cfg),
+            None => path,
+        };
+        if new_path.1 == Stable {
+            *best_path_len = new_path.0.len();
+        }
+        match &mut best_path {
+            Some((old_path, old_stability)) => {
+                *old_path = new_path.0;
+                *old_stability = zip_stability(*old_stability, new_path.1);
+            }
+            None => best_path = Some(new_path),
+        }
+    };
+    let db = ctx.db;
+    if item.krate(db) == Some(ctx.from.krate) {
         // Item was defined in the same crate that wants to import it. It cannot be found in any
         // dependency in this case.
-        calculate_best_path_local(ctx, visited_modules, item, max_len, best_choice)
+        // FIXME: cache the `find_local_import_locations` output?
+        find_local_import_locations(db, item, ctx.from, ctx.from_def_map, |name, module_id| {
+            if !visited_modules.insert(module_id) {
+                return;
+            }
+            // we are looking for paths of length up to best_path_len, any longer will make it be
+            // less optimal. The -1 is due to us pushing name onto it afterwards.
+            if let Some(path) =
+                find_path_for_module(ctx, visited_modules, module_id, best_path_len - 1)
+            {
+                process(path, name.clone(), &mut best_path_len);
+            }
+        })
     } else {
         // Item was defined in some upstream crate. This means that it must be exported from one,
         // too (unless we can't name it at all). It could *also* be (re)exported by the same crate
         // that wants to import it here, but we always prefer to use the external path here.
 
-        ctx.db.crate_graph()[ctx.from.krate].dependencies.iter().for_each(|dep| {
-            find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id)
-        });
-    }
-}
-
-fn find_in_sysroot(
-    ctx: &FindPathCtx<'_>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
-    item: ItemInNs,
-    max_len: usize,
-) -> Option<Choice> {
-    let crate_graph = ctx.db.crate_graph();
-    let dependencies = &crate_graph[ctx.from.krate].dependencies;
-    let mut best_choice = None;
-    let mut search = |lang, best_choice: &mut _| {
-        if let Some(dep) = dependencies.iter().filter(|it| it.is_sysroot()).find(|dep| {
-            match crate_graph[dep.crate_id].origin {
-                CrateOrigin::Lang(l) => l == lang,
-                _ => false,
-            }
-        }) {
-            find_in_dep(ctx, visited_modules, item, max_len, best_choice, dep.crate_id);
-        }
-    };
-    if ctx.cfg.prefer_no_std {
-        search(LangCrateOrigin::Core, &mut best_choice);
-        if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
-            return best_choice;
-        }
-        search(LangCrateOrigin::Std, &mut best_choice);
-        if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
-            return best_choice;
-        }
-    } else {
-        search(LangCrateOrigin::Std, &mut best_choice);
-        if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
-            return best_choice;
-        }
-        search(LangCrateOrigin::Core, &mut best_choice);
-        if matches!(best_choice, Some(Choice { stability: Stable, .. })) {
-            return best_choice;
-        }
-    }
-    let mut best_choice = None;
-    dependencies.iter().filter(|it| it.is_sysroot()).for_each(|dep| {
-        find_in_dep(ctx, visited_modules, item, max_len, &mut best_choice, dep.crate_id);
-    });
-    best_choice
-}
+        for dep in &db.crate_graph()[ctx.from.krate].dependencies {
+            let import_map = db.import_map(dep.crate_id);
+            let Some(import_info_for) = import_map.import_info_for(item) else { continue };
+            for info in import_info_for {
+                if info.is_doc_hidden {
+                    // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
+                    continue;
+                }
 
-fn find_in_dep(
-    ctx: &FindPathCtx<'_>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
-    item: ItemInNs,
-    max_len: usize,
-    best_choice: &mut Option<Choice>,
-    dep: CrateId,
-) {
-    let import_map = ctx.db.import_map(dep);
-    let Some(import_info_for) = import_map.import_info_for(item) else {
-        return;
-    };
-    for info in import_info_for {
-        if info.is_doc_hidden {
-            // the item or import is `#[doc(hidden)]`, so skip it as it is in an external crate
-            continue;
-        }
+                // Determine best path for containing module and append last segment from `info`.
+                // FIXME: we should guide this to look up the path locally, or from the same crate again?
+                let path =
+                    find_path_for_module(ctx, visited_modules, info.container, best_path_len - 1);
+                let Some((path, path_stability)) = path else {
+                    continue;
+                };
+                cov_mark::hit!(partially_imported);
+                let path = (
+                    path,
+                    zip_stability(path_stability, if info.is_unstable { Unstable } else { Stable }),
+                );
 
-        // Determine best path for containing module and append last segment from `info`.
-        // FIXME: we should guide this to look up the path locally, or from the same crate again?
-        let choice = find_path_for_module(
-            ctx,
-            visited_modules,
-            info.container,
-            true,
-            best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1,
-        );
-        let Some(mut choice) = choice else {
-            continue;
-        };
-        cov_mark::hit!(partially_imported);
-        if info.is_unstable {
-            choice.stability = Unstable;
+                process(path, info.name.clone(), &mut best_path_len);
+            }
         }
-
-        Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, info.name.clone());
     }
+    best_path
 }
 
-fn calculate_best_path_local(
-    ctx: &FindPathCtx<'_>,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
-    item: ItemInNs,
-    max_len: usize,
-    best_choice: &mut Option<Choice>,
-) {
-    // FIXME: cache the `find_local_import_locations` output?
-    find_local_import_locations(
-        ctx.db,
-        item,
-        ctx.from,
-        ctx.from_def_map,
-        visited_modules,
-        |visited_modules, name, module_id| {
-            // we are looking for paths of length up to best_path_len, any longer will make it be
-            // less optimal. The -1 is due to us pushing name onto it afterwards.
-            if let Some(choice) = find_path_for_module(
-                ctx,
-                visited_modules,
-                module_id,
-                false,
-                best_choice.as_ref().map_or(max_len, |it| it.path.len()) - 1,
-            ) {
-                Choice::try_select(best_choice, choice, ctx.cfg.prefer_prelude, name.clone());
+/// Select the best (most relevant) path between two paths.
+/// This accounts for stability, path length whether, std should be chosen over alloc/core paths as
+/// well as ignoring prelude like paths or not.
+fn select_best_path(
+    old_path @ (_, old_stability): (ModPath, Stability),
+    new_path @ (_, new_stability): (ModPath, Stability),
+    cfg: ImportPathConfig,
+) -> (ModPath, Stability) {
+    match (old_stability, new_stability) {
+        (Stable, Unstable) => return old_path,
+        (Unstable, Stable) => return new_path,
+        _ => {}
+    }
+    let std_crates: [Symbol; 3] = [sym::std.clone(), sym::core.clone(), sym::alloc.clone()];
+
+    let choose = |new: (ModPath, _), old: (ModPath, _)| {
+        let (new_path, _) = &new;
+        let (old_path, _) = &old;
+        let new_has_prelude = new_path.segments().iter().any(|seg| *seg == sym::prelude.clone());
+        let old_has_prelude = old_path.segments().iter().any(|seg| *seg == sym::prelude.clone());
+        match (new_has_prelude, old_has_prelude, cfg.prefer_prelude) {
+            (true, false, true) | (false, true, false) => new,
+            (true, false, false) | (false, true, true) => old,
+            // no prelude difference in the paths, so pick the shorter one
+            (true, true, _) | (false, false, _) => {
+                let new_path_is_shorter = new_path
+                    .len()
+                    .cmp(&old_path.len())
+                    .then_with(|| new_path.textual_len().cmp(&old_path.textual_len()))
+                    .is_lt();
+                if new_path_is_shorter {
+                    new
+                } else {
+                    old
+                }
             }
-        },
-    );
-}
-
-struct Choice {
-    path: ModPath,
-    /// The length in characters of the path
-    path_text_len: usize,
-    /// The stability of the path
-    stability: Stability,
-    /// Whether this path contains a prelude segment and preference for it has been signaled
-    prefer_due_to_prelude: bool,
-}
-
-impl Choice {
-    fn new(prefer_prelude: bool, kind: PathKind, name: Name, stability: Stability) -> Self {
-        Self {
-            path_text_len: path_kind_len(kind) + name.as_str().len(),
-            stability,
-            prefer_due_to_prelude: prefer_prelude && name == sym::prelude,
-            path: ModPath::from_segments(kind, iter::once(name)),
         }
-    }
-
-    fn push(mut self, prefer_prelude: bool, name: Name) -> Self {
-        self.path_text_len += name.as_str().len();
-        self.prefer_due_to_prelude |= prefer_prelude && name == sym::prelude;
-        self.path.push_segment(name);
-        self
-    }
+    };
 
-    fn try_select(
-        current: &mut Option<Choice>,
-        mut other: Choice,
-        prefer_prelude: bool,
-        name: Name,
-    ) {
-        let Some(current) = current else {
-            *current = Some(other.push(prefer_prelude, name));
-            return;
-        };
-        match other
-            .stability
-            .cmp(&current.stability)
-            .then_with(|| other.prefer_due_to_prelude.cmp(&current.prefer_due_to_prelude))
-            .then_with(|| (current.path.len()).cmp(&(other.path.len() + 1)))
+    match (old_path.0.segments().first(), new_path.0.segments().first()) {
+        (Some(old), Some(new))
+            if std_crates.contains(old.symbol()) && std_crates.contains(new.symbol()) =>
         {
-            Ordering::Less => return,
-            Ordering::Equal => {
-                other.path_text_len += name.as_str().len();
-                if let Ordering::Less | Ordering::Equal =
-                    current.path_text_len.cmp(&other.path_text_len)
-                {
-                    return;
-                }
-            }
-            Ordering::Greater => {
-                other.path_text_len += name.as_str().len();
+            let rank = match cfg.prefer_no_std {
+                false => |name: &Name| match name {
+                    name if *name == sym::core.clone() => 0,
+                    name if *name == sym::alloc.clone() => 1,
+                    name if *name == sym::std.clone() => 2,
+                    _ => unreachable!(),
+                },
+                true => |name: &Name| match name {
+                    name if *name == sym::core.clone() => 2,
+                    name if *name == sym::alloc.clone() => 1,
+                    name if *name == sym::std.clone() => 0,
+                    _ => unreachable!(),
+                },
+            };
+            let nrank = rank(new);
+            let orank = rank(old);
+            match nrank.cmp(&orank) {
+                Ordering::Less => old_path,
+                Ordering::Equal => choose(new_path, old_path),
+                Ordering::Greater => new_path,
             }
         }
-        other.path.push_segment(name);
-        *current = other;
-    }
-}
-
-fn path_kind_len(kind: PathKind) -> usize {
-    match kind {
-        PathKind::Plain => 0,
-        PathKind::Super(0) => 4,
-        PathKind::Super(s) => s as usize * 5,
-        PathKind::Crate => 5,
-        PathKind::Abs => 2,
-        PathKind::DollarCrate(_) => 0,
+        _ => choose(new_path, old_path),
     }
 }
 
@@ -569,8 +477,7 @@ fn find_local_import_locations(
     item: ItemInNs,
     from: ModuleId,
     def_map: &DefMap,
-    visited_modules: &mut FxHashSet<(ItemInNs, ModuleId)>,
-    mut cb: impl FnMut(&mut FxHashSet<(ItemInNs, ModuleId)>, &Name, ModuleId),
+    mut cb: impl FnMut(&Name, ModuleId),
 ) {
     let _p = tracing::info_span!("find_local_import_locations").entered();
 
@@ -583,29 +490,32 @@ fn find_local_import_locations(
     let mut worklist = def_map[from.local_id]
         .children
         .values()
-        .map(|&child| def_map.module_id(child))
+        .map(|child| def_map.module_id(*child))
+        // FIXME: do we need to traverse out of block expressions here?
         .chain(iter::successors(from.containing_module(db), |m| m.containing_module(db)))
-        .zip(iter::repeat(false))
         .collect::<Vec<_>>();
+    let mut seen: FxHashSet<_> = FxHashSet::default();
 
     let def_map = def_map.crate_root().def_map(db);
-    let mut block_def_map;
-    let mut cursor = 0;
-
-    while let Some(&mut (module, ref mut processed)) = worklist.get_mut(cursor) {
-        cursor += 1;
-        if !visited_modules.insert((item, module)) {
-            // already processed this module
-            continue;
+
+    while let Some(module) = worklist.pop() {
+        if !seen.insert(module) {
+            continue; // already processed this module
         }
-        *processed = true;
-        let data = if module.block.is_some() {
-            // Re-query the block's DefMap
-            block_def_map = module.def_map(db);
-            &block_def_map[module.local_id]
+        let ext_def_map;
+        let data = if module.krate == from.krate {
+            if module.block.is_some() {
+                // Re-query the block's DefMap
+                ext_def_map = module.def_map(db);
+                &ext_def_map[module.local_id]
+            } else {
+                // Reuse the root DefMap
+                &def_map[module.local_id]
+            }
         } else {
-            // Reuse the root DefMap
-            &def_map[module.local_id]
+            // The crate might reexport a module defined in another crate.
+            ext_def_map = module.def_map(db);
+            &ext_def_map[module.local_id]
         };
 
         if let Some((name, vis, declared)) = data.scope.name_of(item) {
@@ -628,30 +538,18 @@ fn find_local_import_locations(
                 // the item and we're a submodule of it, so can we.
                 // Also this keeps the cached data smaller.
                 if declared || is_pub_or_explicit {
-                    cb(visited_modules, name, module);
+                    cb(name, module);
                 }
             }
         }
 
         // Descend into all modules visible from `from`.
         for (module, vis) in data.scope.modules_in_scope() {
-            if module.krate != from.krate {
-                // We don't need to look at modules from other crates as our item has to be in the
-                // current crate
-                continue;
-            }
-            if visited_modules.contains(&(item, module)) {
-                continue;
-            }
-
             if vis.is_visible_from(db, from) {
-                worklist.push((module, false));
+                worklist.push(module);
             }
         }
     }
-    worklist.into_iter().filter(|&(_, processed)| processed).for_each(|(module, _)| {
-        visited_modules.remove(&(item, module));
-    });
 }
 
 #[cfg(test)]
@@ -1619,6 +1517,8 @@ fn main() {
 
     #[test]
     fn from_inside_module() {
+        // This worked correctly, but the test suite logic was broken.
+        cov_mark::check!(submodule_in_testdb);
         check_found_path(
             r#"
 mod baz {
@@ -1643,35 +1543,6 @@ mod bar {
         )
     }
 
-    #[test]
-    fn from_inside_module2() {
-        check_found_path(
-            r#"
-mod qux {
-    pub mod baz {
-        pub struct Foo {}
-    }
-
-    mod bar {
-        fn bar() {
-            $0;
-        }
-    }
-}
-
-            "#,
-            "crate::qux::baz::Foo",
-            expect![[r#"
-                Plain  (imports ✔): super::baz::Foo
-                Plain  (imports ✖): super::baz::Foo
-                ByCrate(imports ✔): crate::qux::baz::Foo
-                ByCrate(imports ✖): crate::qux::baz::Foo
-                BySelf (imports ✔): super::baz::Foo
-                BySelf (imports ✖): super::baz::Foo
-            "#]],
-        )
-    }
-
     #[test]
     fn from_inside_module_with_inner_items() {
         check_found_path(
@@ -2047,34 +1918,4 @@ pub fn c() {}
             "#]],
         );
     }
-
-    #[test]
-    fn prefer_long_std_over_short_extern() {
-        check_found_path(
-            r#"
-//- /lib.rs crate:main deps:futures_lite,std,core
-$0
-//- /futures_lite.rs crate:futures_lite deps:std,core
-pub use crate::future::Future;
-pub mod future {
-    pub use core::future::Future;
-}
-//- /std.rs crate:std deps:core
-pub use core::future;
-//- /core.rs crate:core
-pub mod future {
-    pub trait Future {}
-}
-"#,
-            "core::future::Future",
-            expect![[r#"
-                Plain  (imports ✔): std::future::Future
-                Plain  (imports ✖): std::future::Future
-                ByCrate(imports ✔): std::future::Future
-                ByCrate(imports ✖): std::future::Future
-                BySelf (imports ✔): std::future::Future
-                BySelf (imports ✖): std::future::Future
-            "#]],
-        );
-    }
 }
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 58aca96429..4b35c1ae71 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -16,7 +16,6 @@ use hir_expand::{
     name::{AsName, Name},
     proc_macro::CustomProcMacroExpander,
     ExpandTo, HirFileId, InFile, MacroCallId, MacroCallKind, MacroDefId, MacroDefKind,
-    MacroFileIdExt,
 };
 use intern::{sym, Interned};
 use itertools::{izip, Itertools};
@@ -1398,12 +1397,7 @@ impl DefCollector<'_> {
         // Then, fetch and process the item tree. This will reuse the expansion result from above.
         let item_tree = self.db.file_item_tree(file_id);
 
-        let mod_dir = if macro_call_id.as_macro_file().is_include_macro(self.db.upcast()) {
-            ModDir::root()
-        } else {
-            self.mod_dirs[&module_id].clone()
-        };
-
+        let mod_dir = self.mod_dirs[&module_id].clone();
         ModCollector {
             def_collector: &mut *self,
             macro_depth: depth,
diff --git a/crates/hir-def/src/nameres/mod_resolution.rs b/crates/hir-def/src/nameres/mod_resolution.rs
index ab4ffbb2c1..19fdd8e33d 100644
--- a/crates/hir-def/src/nameres/mod_resolution.rs
+++ b/crates/hir-def/src/nameres/mod_resolution.rs
@@ -1,7 +1,7 @@
 //! This module resolves `mod foo;` declaration to file.
 use arrayvec::ArrayVec;
 use base_db::AnchoredPath;
-use hir_expand::{name::Name, HirFileIdExt};
+use hir_expand::{name::Name, HirFileIdExt, MacroFileIdExt};
 use limit::Limit;
 use span::EditionedFileId;
 use syntax::ToSmolStr as _;
@@ -73,6 +73,10 @@ impl ModDir {
             Some(attr_path) => {
                 candidate_files.push(self.dir_path.join_attr(attr_path, self.root_non_dir_owner))
             }
+            None if file_id.macro_file().map_or(false, |it| it.is_include_macro(db.upcast())) => {
+                candidate_files.push(format!("{}.rs", name.display(db.upcast())));
+                candidate_files.push(format!("{}/mod.rs", name.display(db.upcast())));
+            }
             None => {
                 candidate_files.push(format!(
                     "{}{}.rs",
diff --git a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index a12e201cf3..7bf8af4cab 100644
--- a/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -86,15 +86,6 @@ impl<'db> MatchCheckCtx<'db> {
         arms: &[MatchArm<'db>],
         scrut_ty: Ty,
     ) -> Result<UsefulnessReport<'db, Self>, ()> {
-        if scrut_ty.contains_unknown() {
-            return Err(());
-        }
-        for arm in arms {
-            if arm.pat.ty().contains_unknown() {
-                return Err(());
-            }
-        }
-
         // FIXME: Determine place validity correctly. For now, err on the safe side.
         let place_validity = PlaceValidity::MaybeInvalid;
         // Measured to take ~100ms on modern hardware.
diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
index f1de6aba05..82d8db4258 100644
--- a/crates/ide-assists/src/assist_config.rs
+++ b/crates/ide-assists/src/assist_config.rs
@@ -4,6 +4,7 @@
 //! module, and we use to statically check that we only produce snippet
 //! assists if we are allowed to.
 
+use hir::ImportPathConfig;
 use ide_db::{imports::insert_use::InsertUseConfig, SnippetCap};
 
 use crate::AssistKind;
@@ -20,3 +21,13 @@ pub struct AssistConfig {
     pub term_search_fuel: u64,
     pub term_search_borrowck: bool,
 }
+
+impl AssistConfig {
+    pub fn import_path_config(&self) -> ImportPathConfig {
+        ImportPathConfig {
+            prefer_no_std: self.prefer_no_std,
+            prefer_prelude: self.prefer_prelude,
+            prefer_absolute: self.prefer_absolute,
+        }
+    }
+}
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index e1bf6b27bc..f4569ca848 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -71,11 +71,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
         .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
         .collect();
 
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     let module = ctx.sema.scope(expr.syntax())?.module();
     let (mut missing_pats, is_non_exhaustive, has_hidden_variants): (
diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs
index 80e80507ad..db53e49d84 100644
--- a/crates/ide-assists/src/handlers/auto_import.rs
+++ b/crates/ide-assists/src/handlers/auto_import.rs
@@ -1,6 +1,6 @@
 use std::cmp::Reverse;
 
-use hir::{db::HirDatabase, ImportPathConfig, Module};
+use hir::{db::HirDatabase, Module};
 use ide_db::{
     helpers::mod_path_to_ast,
     imports::{
@@ -90,11 +90,7 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 // # pub mod std { pub mod collections { pub struct HashMap { } } }
 // ```
 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
     let mut proposed_imports: Vec<_> = import_assets
@@ -108,7 +104,6 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
         NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
         NodeOrToken::Token(token) => token.text_range(),
     };
-    let group_label = group_label(import_assets.import_candidate());
     let scope = ImportScope::find_insert_use_container(
         &match syntax_under_caret {
             NodeOrToken::Node(it) => it,
@@ -121,18 +116,12 @@ pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path));
     proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
 
-    let current_node = match ctx.covering_element() {
-        NodeOrToken::Node(node) => Some(node),
-        NodeOrToken::Token(token) => token.parent(),
-    };
-
-    let current_module =
-        current_node.as_ref().and_then(|node| ctx.sema.scope(node)).map(|scope| scope.module());
-
+    let current_module = ctx.sema.scope(scope.as_syntax_node()).map(|scope| scope.module());
     // prioritize more relevant imports
     proposed_imports
         .sort_by_key(|import| Reverse(relevance_score(ctx, import, current_module.as_ref())));
 
+    let group_label = group_label(import_assets.import_candidate());
     for import in proposed_imports {
         let import_path = import.import_path;
 
@@ -226,7 +215,7 @@ fn group_label(import_candidate: &ImportCandidate) -> GroupLabel {
 
 /// Determine how relevant a given import is in the current context. Higher scores are more
 /// relevant.
-fn relevance_score(
+pub(crate) fn relevance_score(
     ctx: &AssistContext<'_>,
     import: &LocatedImport,
     current_module: Option<&Module>,
diff --git a/crates/ide-assists/src/handlers/bool_to_enum.rs b/crates/ide-assists/src/handlers/bool_to_enum.rs
index 65fd01fa51..3a0754d60f 100644
--- a/crates/ide-assists/src/handlers/bool_to_enum.rs
+++ b/crates/ide-assists/src/handlers/bool_to_enum.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use hir::{ImportPathConfig, ModuleDef};
+use hir::ModuleDef;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -337,11 +337,7 @@ fn augment_references_with_imports(
 ) -> Vec<FileReferenceWithImport> {
     let mut visited_modules = FxHashSet::default();
 
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     references
         .into_iter()
diff --git a/crates/ide-assists/src/handlers/convert_into_to_from.rs b/crates/ide-assists/src/handlers/convert_into_to_from.rs
index 5349e86cf3..5aa94590e6 100644
--- a/crates/ide-assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs
@@ -1,4 +1,3 @@
-use hir::ImportPathConfig;
 use ide_db::{famous_defs::FamousDefs, helpers::mod_path_to_ast, traits::resolve_target_trait};
 use syntax::ast::{self, AstNode, HasGenericArgs, HasName};
 
@@ -44,11 +43,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
         return None;
     }
 
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     let src_type_path = {
         let src_type_path = src_type.syntax().descendants().find_map(ast::Path::cast)?;
diff --git a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
index 7432fc7709..0f0b4442d8 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_return_type_to_struct.rs
@@ -1,5 +1,5 @@
 use either::Either;
-use hir::{ImportPathConfig, ModuleDef};
+use hir::ModuleDef;
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -183,11 +183,7 @@ fn augment_references_with_imports(
 ) -> Vec<(ast::NameLike, Option<(ImportScope, ast::Path)>)> {
     let mut visited_modules = FxHashSet::default();
 
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     references
         .iter()
diff --git a/crates/ide-assists/src/handlers/destructure_struct_binding.rs b/crates/ide-assists/src/handlers/destructure_struct_binding.rs
index da902f7e10..095b8f958d 100644
--- a/crates/ide-assists/src/handlers/destructure_struct_binding.rs
+++ b/crates/ide-assists/src/handlers/destructure_struct_binding.rs
@@ -1,4 +1,4 @@
-use hir::{sym, HasVisibility, ImportPathConfig};
+use hir::{sym, HasVisibility};
 use ide_db::{
     assists::{AssistId, AssistKind},
     defs::Definition,
@@ -87,11 +87,7 @@ fn collect_data(ident_pat: ast::IdentPat, ctx: &AssistContext<'_>) -> Option<Str
     let ty = ctx.sema.type_of_binding_in_pat(&ident_pat)?;
     let hir::Adt::Struct(struct_type) = ty.strip_references().as_adt()? else { return None };
 
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     let module = ctx.sema.scope(ident_pat.syntax())?.module();
     let struct_def = hir::ModuleDef::from(struct_type);
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 20c37f9233..0a2cb6d5ef 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -3,8 +3,8 @@ use std::{iter, ops::RangeInclusive};
 use ast::make;
 use either::Either;
 use hir::{
-    DescendPreference, HasSource, HirDisplay, ImportPathConfig, InFile, Local, LocalSource,
-    ModuleDef, PathResolution, Semantics, TypeInfo, TypeParam,
+    DescendPreference, HasSource, HirDisplay, InFile, Local, LocalSource, ModuleDef,
+    PathResolution, Semantics, TypeInfo, TypeParam,
 };
 use ide_db::{
     defs::{Definition, NameRefClass},
@@ -213,11 +213,7 @@ pub(crate) fn extract_function(acc: &mut Assists, ctx: &AssistContext<'_>) -> Op
                         ctx.sema.db,
                         ModuleDef::from(control_flow_enum),
                         ctx.config.insert_use.prefix_kind,
-                        ImportPathConfig {
-                            prefer_no_std: ctx.config.prefer_no_std,
-                            prefer_prelude: ctx.config.prefer_prelude,
-                            prefer_absolute: ctx.config.prefer_absolute,
-                        },
+                        ctx.config.import_path_config(),
                     );
 
                     if let Some(mod_path) = mod_path {
diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index cd483c1b57..a62fdeb617 100644
--- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -1,7 +1,7 @@
 use std::iter;
 
 use either::Either;
-use hir::{ImportPathConfig, Module, ModuleDef, Name, Variant};
+use hir::{Module, ModuleDef, Name, Variant};
 use ide_db::{
     defs::Definition,
     helpers::mod_path_to_ast,
@@ -390,11 +390,7 @@ fn process_references(
                     ctx.sema.db,
                     *enum_module_def,
                     ctx.config.insert_use.prefix_kind,
-                    ImportPathConfig {
-                        prefer_no_std: ctx.config.prefer_no_std,
-                        prefer_prelude: ctx.config.prefer_prelude,
-                        prefer_absolute: ctx.config.prefer_absolute,
-                    },
+                    ctx.config.import_path_config(),
                 );
                 if let Some(mut mod_path) = mod_path {
                     mod_path.pop_segment();
diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs
index cc33439dd5..2ac7057fe7 100644
--- a/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/crates/ide-assists/src/handlers/generate_deref.rs
@@ -1,6 +1,6 @@
 use std::fmt::Display;
 
-use hir::{ImportPathConfig, ModPath, ModuleDef};
+use hir::{ModPath, ModuleDef};
 use ide_db::{famous_defs::FamousDefs, RootDatabase};
 use syntax::{
     ast::{self, HasName},
@@ -58,15 +58,8 @@ fn generate_record_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<(
 
     let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
     let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
-    let trait_path = module.find_path(
-        ctx.db(),
-        ModuleDef::Trait(trait_),
-        ImportPathConfig {
-            prefer_no_std: ctx.config.prefer_no_std,
-            prefer_prelude: ctx.config.prefer_prelude,
-            prefer_absolute: ctx.config.prefer_absolute,
-        },
-    )?;
+    let trait_path =
+        module.find_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.import_path_config())?;
 
     let field_type = field.ty()?;
     let field_name = field.name()?;
@@ -106,15 +99,8 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
 
     let module = ctx.sema.to_def(&strukt)?.module(ctx.db());
     let trait_ = deref_type_to_generate.to_trait(&ctx.sema, module.krate())?;
-    let trait_path = module.find_path(
-        ctx.db(),
-        ModuleDef::Trait(trait_),
-        ImportPathConfig {
-            prefer_no_std: ctx.config.prefer_no_std,
-            prefer_prelude: ctx.config.prefer_prelude,
-            prefer_absolute: ctx.config.prefer_absolute,
-        },
-    )?;
+    let trait_path =
+        module.find_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.import_path_config())?;
 
     let field_type = field.ty()?;
     let target = field.syntax().text_range();
diff --git a/crates/ide-assists/src/handlers/generate_new.rs b/crates/ide-assists/src/handlers/generate_new.rs
index 6056c80888..b985b5e66c 100644
--- a/crates/ide-assists/src/handlers/generate_new.rs
+++ b/crates/ide-assists/src/handlers/generate_new.rs
@@ -1,4 +1,3 @@
-use hir::ImportPathConfig;
 use ide_db::{
     imports::import_assets::item_for_path_search, use_trivial_constructor::use_trivial_constructor,
 };
@@ -62,11 +61,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
                 let type_path = current_module.find_path(
                     ctx.sema.db,
                     item_for_path_search(ctx.sema.db, item_in_ns)?,
-                    ImportPathConfig {
-                        prefer_no_std: ctx.config.prefer_no_std,
-                        prefer_prelude: ctx.config.prefer_prelude,
-                        prefer_absolute: ctx.config.prefer_absolute,
-                    },
+                    ctx.config.import_path_config(),
                 )?;
 
                 let expr = use_trivial_constructor(
diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs
index 89e24fafc5..b1e98045fc 100644
--- a/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -1,7 +1,4 @@
-use hir::{
-    db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, ImportPathConfig, ItemInNs,
-    ModuleDef,
-};
+use hir::{db::HirDatabase, AsAssocItem, AssocItem, AssocItemContainer, ItemInNs, ModuleDef};
 use ide_db::assists::{AssistId, AssistKind};
 use syntax::{ast, AstNode};
 
@@ -50,11 +47,7 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let receiver_path = current_module.find_path(
         ctx.sema.db,
         item_for_path_search(ctx.sema.db, item_in_ns)?,
-        ImportPathConfig {
-            prefer_no_std: ctx.config.prefer_no_std,
-            prefer_prelude: ctx.config.prefer_prelude,
-            prefer_absolute: ctx.config.prefer_absolute,
-        },
+        ctx.config.import_path_config(),
     )?;
 
     let qualify_candidate = QualifyCandidate::ImplMethod(ctx.sema.db, call, resolved_call);
diff --git a/crates/ide-assists/src/handlers/qualify_path.rs b/crates/ide-assists/src/handlers/qualify_path.rs
index 4164a4c102..d8e7da15d5 100644
--- a/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/crates/ide-assists/src/handlers/qualify_path.rs
@@ -1,6 +1,7 @@
+use std::cmp::Reverse;
 use std::iter;
 
-use hir::{AsAssocItem, ImportPathConfig};
+use hir::AsAssocItem;
 use ide_db::RootDatabase;
 use ide_db::{
     helpers::mod_path_to_ast,
@@ -38,11 +39,7 @@ use crate::{
 // ```
 pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
-    let cfg = ImportPathConfig {
-        prefer_no_std: ctx.config.prefer_no_std,
-        prefer_prelude: ctx.config.prefer_prelude,
-        prefer_absolute: ctx.config.prefer_absolute,
-    };
+    let cfg = ctx.config.import_path_config();
 
     let mut proposed_imports: Vec<_> =
         import_assets.search_for_relative_paths(&ctx.sema, cfg).collect();
@@ -50,12 +47,8 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
         return None;
     }
 
-    let range = match &syntax_under_caret {
-        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
-        NodeOrToken::Token(token) => token.text_range(),
-    };
     let candidate = import_assets.import_candidate();
-    let qualify_candidate = match syntax_under_caret {
+    let qualify_candidate = match syntax_under_caret.clone() {
         NodeOrToken::Node(syntax_under_caret) => match candidate {
             ImportCandidate::Path(candidate) if candidate.qualifier.is_some() => {
                 cov_mark::hit!(qualify_path_qualifier_start);
@@ -89,6 +82,22 @@ pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
     proposed_imports.sort_by(|a, b| a.import_path.cmp(&b.import_path));
     proposed_imports.dedup_by(|a, b| a.import_path == b.import_path);
 
+    let range = match &syntax_under_caret {
+        NodeOrToken::Node(node) => ctx.sema.original_range(node).range,
+        NodeOrToken::Token(token) => token.text_range(),
+    };
+    let current_module = ctx
+        .sema
+        .scope(&match syntax_under_caret {
+            NodeOrToken::Node(node) => node.clone(),
+            NodeOrToken::Token(t) => t.parent()?,
+        })
+        .map(|scope| scope.module());
+    // prioritize more relevant imports
+    proposed_imports.sort_by_key(|import| {
+        Reverse(super::auto_import::relevance_score(ctx, import, current_module.as_ref()))
+    });
+
     let group_label = group_label(candidate);
     for import in proposed_imports {
         acc.add_group(
diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index 5582256a17..5ff4af19fb 100644
--- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -1,4 +1,4 @@
-use hir::{ImportPathConfig, InFile, MacroFileIdExt, ModuleDef};
+use hir::{InFile, MacroFileIdExt, ModuleDef};
 use ide_db::{helpers::mod_path_to_ast, imports::import_assets::NameToImport, items_locator};
 use itertools::Itertools;
 use syntax::{
@@ -83,15 +83,7 @@ pub(crate) fn replace_derive_with_manual_impl(
     })
     .flat_map(|trait_| {
         current_module
-            .find_path(
-                ctx.sema.db,
-                hir::ModuleDef::Trait(trait_),
-                ImportPathConfig {
-                    prefer_no_std: ctx.config.prefer_no_std,
-                    prefer_prelude: ctx.config.prefer_prelude,
-                    prefer_absolute: ctx.config.prefer_absolute,
-                },
-            )
+            .find_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.import_path_config())
             .as_ref()
             .map(mod_path_to_ast)
             .zip(Some(trait_))
diff --git a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
index b4e1a49aab..d0aa835e79 100644
--- a/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
+++ b/crates/ide-assists/src/handlers/replace_qualified_name_with_use.rs
@@ -1,4 +1,4 @@
-use hir::{AsAssocItem, ImportPathConfig};
+use hir::AsAssocItem;
 use ide_db::{
     helpers::mod_path_to_ast,
     imports::insert_use::{insert_use, ImportScope},
@@ -67,11 +67,7 @@ pub(crate) fn replace_qualified_name_with_use(
                 ctx.sema.db,
                 module,
                 ctx.config.insert_use.prefix_kind,
-                ImportPathConfig {
-                    prefer_no_std: ctx.config.prefer_no_std,
-                    prefer_prelude: ctx.config.prefer_prelude,
-                    prefer_absolute: ctx.config.prefer_absolute,
-                },
+                ctx.config.import_path_config(),
             )
         })
         .flatten();
diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs
index 7a91179975..4913cfdea9 100644
--- a/crates/ide-assists/src/handlers/term_search.rs
+++ b/crates/ide-assists/src/handlers/term_search.rs
@@ -1,8 +1,5 @@
 //! Term search assist
-use hir::{
-    term_search::{TermSearchConfig, TermSearchCtx},
-    ImportPathConfig,
-};
+use hir::term_search::{TermSearchConfig, TermSearchCtx};
 use ide_db::{
     assists::{AssistId, AssistKind, GroupLabel},
     famous_defs::FamousDefs,
@@ -54,16 +51,7 @@ pub(crate) fn term_search(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<
     let paths = paths
         .into_iter()
         .filter_map(|path| {
-            path.gen_source_code(
-                &scope,
-                &mut formatter,
-                ImportPathConfig {
-                    prefer_no_std: ctx.config.prefer_no_std,
-                    prefer_prelude: ctx.config.prefer_prelude,
-                    prefer_absolute: ctx.config.prefer_absolute,
-                },
-            )
-            .ok()
+            path.gen_source_code(&scope, &mut formatter, ctx.config.import_path_config()).ok()
         })
         .unique();
 
diff --git a/crates/ide-assists/src/handlers/toggle_async_sugar.rs b/crates/ide-assists/src/handlers/toggle_async_sugar.rs
index 31d18a6013..98975a324d 100644
--- a/crates/ide-assists/src/handlers/toggle_async_sugar.rs
+++ b/crates/ide-assists/src/handlers/toggle_async_sugar.rs
@@ -1,4 +1,4 @@
-use hir::{ImportPathConfig, ModuleDef};
+use hir::ModuleDef;
 use ide_db::{
     assists::{AssistId, AssistKind},
     famous_defs::FamousDefs,
@@ -139,11 +139,7 @@ pub(crate) fn desugar_async_into_impl_future(
     let trait_path = module.find_path(
         ctx.db(),
         ModuleDef::Trait(future_trait),
-        ImportPathConfig {
-            prefer_no_std: ctx.config.prefer_no_std,
-            prefer_prelude: ctx.config.prefer_prelude,
-            prefer_absolute: ctx.config.prefer_absolute,
-        },
+        ctx.config.import_path_config(),
     )?;
     let trait_path = trait_path.display(ctx.db());
 
diff --git a/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 4e52d28051..4c25532228 100644
--- a/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -745,18 +745,6 @@ fn f() {
         0
     }
 }
-"#,
-        );
-    }
-
-    #[test]
-    fn regression_17585() {
-        check_diagnostics(
-            r#"
-fn f() {
-    let (_, _, _, ..) = (true, 42);
-     // ^^^^^^^^^^^^^ error: expected (bool, i32), found (bool, i32, {unknown})
-}
 "#,
         );
     }
diff --git a/crates/parser/src/grammar/paths.rs b/crates/parser/src/grammar/paths.rs
index 01b8f9e918..86e19fbe5f 100644
--- a/crates/parser/src/grammar/paths.rs
+++ b/crates/parser/src/grammar/paths.rs
@@ -2,6 +2,8 @@ use super::*;
 
 pub(super) const PATH_FIRST: TokenSet =
     TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self], T![:], T![<]]);
+pub(super) const WEAK_DYN_PATH_FIRST: TokenSet =
+    TokenSet::new(&[IDENT, T![self], T![super], T![crate], T![Self]]);
 
 pub(super) fn is_path_start(p: &Parser<'_>) -> bool {
     is_use_path_start(p) || p.at(T![<]) || p.at(T![Self])
diff --git a/crates/parser/src/grammar/types.rs b/crates/parser/src/grammar/types.rs
index f4e57d3d6f..9a1c6dfdf7 100644
--- a/crates/parser/src/grammar/types.rs
+++ b/crates/parser/src/grammar/types.rs
@@ -1,3 +1,5 @@
+use crate::grammar::paths::WEAK_DYN_PATH_FIRST;
+
 use super::*;
 
 pub(super) const TYPE_FIRST: TokenSet = paths::PATH_FIRST.union(TokenSet::new(&[
@@ -49,7 +51,13 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
         T![dyn] => dyn_trait_type(p),
         // Some path types are not allowed to have bounds (no plus)
         T![<] => path_type_bounds(p, allow_bounds),
-        T![ident] if !p.edition().at_least_2018() && is_dyn_weak(p) => dyn_trait_type_weak(p),
+        T![ident]
+            if !p.edition().at_least_2018()
+                && p.at_contextual_kw(T![dyn])
+                && WEAK_DYN_PATH_FIRST.contains(p.nth(1)) =>
+        {
+            dyn_trait_type_weak(p)
+        }
         _ if paths::is_path_start(p) => path_or_macro_type_(p, allow_bounds),
         LIFETIME_IDENT if p.nth_at(1, T![+]) => bare_dyn_trait_type(p),
         _ => {
@@ -58,25 +66,6 @@ fn type_with_bounds_cond(p: &mut Parser<'_>, allow_bounds: bool) {
     }
 }
 
-fn is_dyn_weak(p: &Parser<'_>) -> bool {
-    const WEAK_DYN_PATH_FIRST: TokenSet = TokenSet::new(&[
-        IDENT,
-        T![self],
-        T![super],
-        T![crate],
-        T![Self],
-        T![lifetime_ident],
-        T![?],
-        T![for],
-        T!['('],
-    ]);
-
-    p.at_contextual_kw(T![dyn]) && {
-        let la = p.nth(1);
-        WEAK_DYN_PATH_FIRST.contains(la) && (la != T![:] || la != T![<])
-    }
-}
-
 pub(super) fn ascription(p: &mut Parser<'_>) {
     assert!(p.at(T![:]));
     p.bump(T![:]);
@@ -300,14 +289,9 @@ fn dyn_trait_type(p: &mut Parser<'_>) {
 }
 
 // test dyn_trait_type_weak 2015
-// type DynPlain = dyn Path;
-// type DynRef = &dyn Path;
-// type DynLt = dyn 'a + Path;
-// type DynQuestion = dyn ?Path;
-// type DynFor = dyn for<'a> Path;
-// type DynParen = dyn(Path);
-// type Path = dyn::Path;
-// type Generic = dyn<Path>;
+// type A = dyn Iterator<Item=Foo<'a>> + 'a;
+// type A = &dyn Iterator<Item=Foo<'a>> + 'a;
+// type A = dyn::Path;
 fn dyn_trait_type_weak(p: &mut Parser<'_>) {
     assert!(p.at_contextual_kw(T![dyn]));
     let m = p.start();
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 6a3ccd1009..f3ee7a98ac 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -857,7 +857,7 @@ impl Config {
             tracing::info!("updating config from JSON: {:#}", json);
             if !(json.is_null() || json.as_object().map_or(false, |it| it.is_empty())) {
                 let mut json_errors = vec![];
-                let detached_files = get_field_json::<Vec<Utf8PathBuf>>(
+                let detached_files = get_field::<Vec<Utf8PathBuf>>(
                     &mut json,
                     &mut json_errors,
                     "detachedFiles",
@@ -2660,7 +2660,7 @@ macro_rules! _config_data {
 
             fn from_json(json: &mut serde_json::Value, error_sink: &mut Vec<(String, serde_json::Error)>) -> Self {
                 Self {$(
-                    $field: get_field_json(
+                    $field: get_field(
                         json,
                         error_sink,
                         stringify!($field),
@@ -2778,7 +2778,7 @@ impl GlobalLocalConfigInput {
     }
 }
 
-fn get_field_json<T: DeserializeOwned>(
+fn get_field<T: DeserializeOwned>(
     json: &mut serde_json::Value,
     error_sink: &mut Vec<(String, serde_json::Error)>,
     field: &'static str,


Test patch:
diff --git a/crates/hir-def/src/nameres/tests/macros.rs b/crates/hir-def/src/nameres/tests/macros.rs
index 390c934f6d..d278b75e81 100644
--- a/crates/hir-def/src/nameres/tests/macros.rs
+++ b/crates/hir-def/src/nameres/tests/macros.rs
@@ -1309,116 +1309,6 @@ pub mod ip_address {
     );
 }
 
-#[test]
-fn include_with_submod_file() {
-    check(
-        r#"
-//- minicore: include
-//- /lib.rs
-include!("out_dir/includes.rs");
-
-//- /out_dir/includes.rs
-pub mod company_name {
-    pub mod network {
-        pub mod v1;
-    }
-}
-//- /out_dir/company_name/network/v1.rs
-pub struct IpAddress {
-    pub ip_type: &'static str,
-}
-/// Nested message and enum types in `IpAddress`.
-pub mod ip_address {
-    pub enum IpType {
-        IpV4(u32),
-    }
-}
-
-"#,
-        expect![[r#"
-            crate
-            company_name: t
-
-            crate::company_name
-            network: t
-
-            crate::company_name::network
-            v1: t
-
-            crate::company_name::network::v1
-            IpAddress: t
-            ip_address: t
-
-            crate::company_name::network::v1::ip_address
-            IpType: t
-        "#]],
-    );
-}
-
-#[test]
-fn include_many_mods() {
-    check(
-        r#"
-//- /lib.rs
-#[rustc_builtin_macro]
-macro_rules! include { () => {} }
-
-mod nested {
-    include!("out_dir/includes.rs");
-
-    mod different_company {
-        include!("out_dir/different_company/mod.rs");
-    }
-
-    mod util;
-}
-
-//- /nested/util.rs
-pub struct Helper {}
-//- /out_dir/includes.rs
-pub mod company_name {
-    pub mod network {
-        pub mod v1;
-    }
-}
-//- /out_dir/company_name/network/v1.rs
-pub struct IpAddress {}
-//- /out_dir/different_company/mod.rs
-pub mod network;
-//- /out_dir/different_company/network.rs
-pub struct Url {}
-
-"#,
-        expect![[r#"
-            crate
-            nested: t
-
-            crate::nested
-            company_name: t
-            different_company: t
-            util: t
-
-            crate::nested::company_name
-            network: t
-
-            crate::nested::company_name::network
-            v1: t
-
-            crate::nested::company_name::network::v1
-            IpAddress: t
-
-            crate::nested::different_company
-            network: t
-
-            crate::nested::different_company::network
-            Url: t
-
-            crate::nested::util
-            Helper: t
-        "#]],
-    );
-}
-
 #[test]
 fn macro_use_imports_all_macro_types() {
     let db = TestDB::with_files(
diff --git a/crates/hir-def/src/test_db.rs b/crates/hir-def/src/test_db.rs
index f44472eae5..3f002af9d2 100644
--- a/crates/hir-def/src/test_db.rs
+++ b/crates/hir-def/src/test_db.rs
@@ -148,6 +148,7 @@ impl TestDB {
             };
 
             if size != Some(new_size) {
+                cov_mark::hit!(submodule_in_testdb);
                 size = Some(new_size);
                 res = module;
             }
diff --git a/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast b/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
index dcc66dc1e2..00ca92402c 100644
--- a/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
+++ b/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rast
@@ -5,7 +5,7 @@ SOURCE_FILE
     TYPE_KW "type"
     WHITESPACE " "
     NAME
-      IDENT "DynPlain"
+      IDENT "A"
     WHITESPACE " "
     EQ "="
     WHITESPACE " "
@@ -18,14 +18,38 @@ SOURCE_FILE
             PATH
               PATH_SEGMENT
                 NAME_REF
-                  IDENT "Path"
+                  IDENT "Iterator"
+                GENERIC_ARG_LIST
+                  L_ANGLE "<"
+                  ASSOC_TYPE_ARG
+                    NAME_REF
+                      IDENT "Item"
+                    EQ "="
+                    PATH_TYPE
+                      PATH
+                        PATH_SEGMENT
+                          NAME_REF
+                            IDENT "Foo"
+                          GENERIC_ARG_LIST
+                            L_ANGLE "<"
+                            LIFETIME_ARG
+                              LIFETIME
+                                LIFETIME_IDENT "'a"
+                            R_ANGLE ">"
+                  R_ANGLE ">"
+        WHITESPACE " "
+        PLUS "+"
+        WHITESPACE " "
+        TYPE_BOUND
+          LIFETIME
+            LIFETIME_IDENT "'a"
     SEMICOLON ";"
   WHITESPACE "\n"
   TYPE_ALIAS
     TYPE_KW "type"
     WHITESPACE " "
     NAME
-      IDENT "DynRef"
+      IDENT "A"
     WHITESPACE " "
     EQ "="
     WHITESPACE " "
@@ -40,111 +64,38 @@ SOURCE_FILE
               PATH
                 PATH_SEGMENT
                   NAME_REF
-                    IDENT "Path"
-    SEMICOLON ";"
-  WHITESPACE "\n"
-  TYPE_ALIAS
-    TYPE_KW "type"
-    WHITESPACE " "
-    NAME
-      IDENT "DynLt"
-    WHITESPACE " "
-    EQ "="
-    WHITESPACE " "
-    DYN_TRAIT_TYPE
-      DYN_KW "dyn"
-      WHITESPACE " "
-      TYPE_BOUND_LIST
-        TYPE_BOUND
-          LIFETIME
-            LIFETIME_IDENT "'a"
-        WHITESPACE " "
-        PLUS "+"
-        WHITESPACE " "
-        TYPE_BOUND
-          PATH_TYPE
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "Path"
-    SEMICOLON ";"
-  WHITESPACE "\n"
-  TYPE_ALIAS
-    TYPE_KW "type"
-    WHITESPACE " "
-    NAME
-      IDENT "DynQuestion"
-    WHITESPACE " "
-    EQ "="
-    WHITESPACE " "
-    DYN_TRAIT_TYPE
-      DYN_KW "dyn"
-      WHITESPACE " "
-      TYPE_BOUND_LIST
-        TYPE_BOUND
-          QUESTION "?"
-          PATH_TYPE
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "Path"
-    SEMICOLON ";"
-  WHITESPACE "\n"
-  TYPE_ALIAS
-    TYPE_KW "type"
-    WHITESPACE " "
-    NAME
-      IDENT "DynFor"
-    WHITESPACE " "
-    EQ "="
-    WHITESPACE " "
-    DYN_TRAIT_TYPE
-      DYN_KW "dyn"
-      WHITESPACE " "
-      TYPE_BOUND_LIST
-        TYPE_BOUND
-          FOR_TYPE
-            FOR_KW "for"
-            GENERIC_PARAM_LIST
-              L_ANGLE "<"
-              LIFETIME_PARAM
-                LIFETIME
-                  LIFETIME_IDENT "'a"
-              R_ANGLE ">"
-            WHITESPACE " "
-            PATH_TYPE
-              PATH
-                PATH_SEGMENT
-                  NAME_REF
-                    IDENT "Path"
-    SEMICOLON ";"
-  WHITESPACE "\n"
-  TYPE_ALIAS
-    TYPE_KW "type"
-    WHITESPACE " "
-    NAME
-      IDENT "DynParen"
-    WHITESPACE " "
-    EQ "="
-    WHITESPACE " "
-    DYN_TRAIT_TYPE
-      DYN_KW "dyn"
-      TYPE_BOUND_LIST
-        TYPE_BOUND
-          L_PAREN "("
-          PATH_TYPE
-            PATH
-              PATH_SEGMENT
-                NAME_REF
-                  IDENT "Path"
-          R_PAREN ")"
+                    IDENT "Iterator"
+                  GENERIC_ARG_LIST
+                    L_ANGLE "<"
+                    ASSOC_TYPE_ARG
+                      NAME_REF
+                        IDENT "Item"
+                      EQ "="
+                      PATH_TYPE
+                        PATH
+                          PATH_SEGMENT
+                            NAME_REF
+                              IDENT "Foo"
+                            GENERIC_ARG_LIST
+                              L_ANGLE "<"
+                              LIFETIME_ARG
+                                LIFETIME
+                                  LIFETIME_IDENT "'a"
+                              R_ANGLE ">"
+                    R_ANGLE ">"
+          WHITESPACE " "
+          PLUS "+"
+          WHITESPACE " "
+          TYPE_BOUND
+            LIFETIME
+              LIFETIME_IDENT "'a"
     SEMICOLON ";"
   WHITESPACE "\n"
   TYPE_ALIAS
     TYPE_KW "type"
     WHITESPACE " "
     NAME
-      IDENT "Path"
+      IDENT "A"
     WHITESPACE " "
     EQ "="
     WHITESPACE " "
@@ -160,27 +111,3 @@ SOURCE_FILE
             IDENT "Path"
     SEMICOLON ";"
   WHITESPACE "\n"
-  TYPE_ALIAS
-    TYPE_KW "type"
-    WHITESPACE " "
-    NAME
-      IDENT "Generic"
-    WHITESPACE " "
-    EQ "="
-    WHITESPACE " "
-    PATH_TYPE
-      PATH
-        PATH_SEGMENT
-          NAME_REF
-            IDENT "dyn"
-          GENERIC_ARG_LIST
-            L_ANGLE "<"
-            TYPE_ARG
-              PATH_TYPE
-                PATH
-                  PATH_SEGMENT
-                    NAME_REF
-                      IDENT "Path"
-            R_ANGLE ">"
-    SEMICOLON ";"
-  WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rs b/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rs
index c4ef1f2b7a..c4941e65bf 100644
--- a/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rs
+++ b/crates/parser/test_data/parser/inline/ok/dyn_trait_type_weak.rs
@@ -1,9 +1,4 @@
 // 2015
-type DynPlain = dyn Path;
-type DynRef = &dyn Path;
-type DynLt = dyn 'a + Path;
-type DynQuestion = dyn ?Path;
-type DynFor = dyn for<'a> Path;
-type DynParen = dyn(Path);
-type Path = dyn::Path;
-type Generic = dyn<Path>;
+type A = dyn Iterator<Item=Foo<'a>> + 'a;
+type A = &dyn Iterator<Item=Foo<'a>> + 'a;
+type A = dyn::Path;
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index c10ff4aede..19c81a7c5f 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -246,7 +246,6 @@ impl ChangeFixture {
             for (from, to, prelude) in crate_deps {
                 let from_id = crates[&from];
                 let to_id = crates[&to];
-                let sysroot = crate_graph[to_id].origin.is_lang();
                 crate_graph
                     .add_dep(
                         from_id,
@@ -254,7 +253,7 @@ impl ChangeFixture {
                             CrateName::new(&to).unwrap(),
                             to_id,
                             prelude,
-                            sysroot,
+                            false,
                         ),
                     )
                     .unwrap();