Repository: rust-lang/rust-analyzer
Pull request #13212 (2022-09-09 18:05:36)

Add config to unconditionally prefer core imports over std
Fixes https://github.com/rust-lang/rust-analyzer/issues/12979


Patch:
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index 89e961f84f..f46054e8cc 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -16,9 +16,14 @@ use crate::{
 
 /// Find a path that can be used to refer to a certain item. This can depend on
 /// *from where* you're referring to the item, hence the `from` parameter.
-pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
+pub fn find_path(
+    db: &dyn DefDatabase,
+    item: ItemInNs,
+    from: ModuleId,
+    prefer_core: bool,
+) -> Option<ModPath> {
     let _p = profile::span("find_path");
-    find_path_inner(db, item, from, None)
+    find_path_inner(db, item, from, None, prefer_core)
 }
 
 pub fn find_path_prefixed(
@@ -26,9 +31,10 @@ pub fn find_path_prefixed(
     item: ItemInNs,
     from: ModuleId,
     prefix_kind: PrefixKind,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     let _p = profile::span("find_path_prefixed");
-    find_path_inner(db, item, from, Some(prefix_kind))
+    find_path_inner(db, item, from, Some(prefix_kind), prefer_core)
 }
 
 const MAX_PATH_LEN: usize = 15;
@@ -100,12 +106,22 @@ fn find_path_inner(
     item: ItemInNs,
     from: ModuleId,
     prefixed: Option<PrefixKind>,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     // FIXME: Do fast path for std/core libs?
 
     let mut visited_modules = FxHashSet::default();
     let def_map = from.def_map(db);
-    find_path_inner_(db, &def_map, from, item, MAX_PATH_LEN, prefixed, &mut visited_modules)
+    find_path_inner_(
+        db,
+        &def_map,
+        from,
+        item,
+        MAX_PATH_LEN,
+        prefixed,
+        &mut visited_modules,
+        prefer_core,
+    )
 }
 
 fn find_path_inner_(
@@ -116,6 +132,7 @@ fn find_path_inner_(
     max_len: usize,
     mut prefixed: Option<PrefixKind>,
     visited_modules: &mut FxHashSet<ModuleId>,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     if max_len == 0 {
         return None;
@@ -191,7 +208,9 @@ fn find_path_inner_(
     // Recursive case:
     // - if the item is an enum variant, refer to it via the enum
     if let Some(ModuleDefId::EnumVariantId(variant)) = item.as_module_def_id() {
-        if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
+        if let Some(mut path) =
+            find_path(db, ItemInNs::Types(variant.parent.into()), from, prefer_core)
+        {
             let data = db.enum_data(variant.parent);
             path.push_segment(data.variants[variant.local_id].name.clone());
             return Some(path);
@@ -202,7 +221,7 @@ fn find_path_inner_(
     }
 
     // - otherwise, look for modules containing (reexporting) it and import it from one of those
-    let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
+    let prefer_no_std = prefer_core || db.crate_supports_no_std(crate_root.krate);
     let mut best_path = None;
     let mut best_path_len = max_len;
 
@@ -223,6 +242,7 @@ fn find_path_inner_(
                 best_path_len - 1,
                 prefixed,
                 visited_modules,
+                prefer_core,
             ) {
                 path.push_segment(name);
 
@@ -253,6 +273,7 @@ fn find_path_inner_(
                     best_path_len - 1,
                     prefixed,
                     visited_modules,
+                    prefer_core,
                 )?;
                 cov_mark::hit!(partially_imported);
                 path.push_segment(info.path.segments.last()?.clone());
@@ -428,7 +449,8 @@ mod tests {
             .take_types()
             .unwrap();
 
-        let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind);
+        let found_path =
+            find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
         assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
     }
 
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index d2f9c2b8b1..874abdaea8 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -533,6 +533,7 @@ impl HirDisplay for Ty {
                             f.db.upcast(),
                             ItemInNs::Types((*def_id).into()),
                             module_id,
+                            false,
                         ) {
                             write!(f, "{}", path)?;
                         } else {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e4bb63a864..5fa4c15162 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -582,8 +582,13 @@ impl Module {
 
     /// Finds a path that can be used to refer to the given item from within
     /// this module, if possible.
-    pub fn find_use_path(self, db: &dyn DefDatabase, item: impl Into<ItemInNs>) -> Option<ModPath> {
-        hir_def::find_path::find_path(db, item.into().into(), self.into())
+    pub fn find_use_path(
+        self,
+        db: &dyn DefDatabase,
+        item: impl Into<ItemInNs>,
+        prefer_core: bool,
+    ) -> Option<ModPath> {
+        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_core)
     }
 
     /// Finds a path that can be used to refer to the given item from within
@@ -593,8 +598,15 @@ impl Module {
         db: &dyn DefDatabase,
         item: impl Into<ItemInNs>,
         prefix_kind: PrefixKind,
+        prefer_core: bool,
     ) -> Option<ModPath> {
-        hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
+        hir_def::find_path::find_path_prefixed(
+            db,
+            item.into().into(),
+            self.into(),
+            prefix_kind,
+            prefer_core,
+        )
     }
 }
 
diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
index d4d148c774..fe2dfca6d5 100644
--- a/crates/ide-assists/src/assist_config.rs
+++ b/crates/ide-assists/src/assist_config.rs
@@ -13,4 +13,5 @@ pub struct AssistConfig {
     pub snippet_cap: Option<SnippetCap>,
     pub allowed: Option<Vec<AssistKind>>,
     pub insert_use: InsertUseConfig,
+    pub prefer_core: bool,
 }
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 1a7919a5a1..d4e21b778c 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -87,7 +87,7 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
             .into_iter()
             .filter_map(|variant| {
                 Some((
-                    build_pat(ctx.db(), module, variant)?,
+                    build_pat(ctx.db(), module, variant, ctx.config.prefer_core)?,
                     variant.should_be_hidden(ctx.db(), module.krate()),
                 ))
             })
@@ -132,8 +132,9 @@ pub(crate) fn add_missing_match_arms(acc: &mut Assists, ctx: &AssistContext<'_>)
                 let is_hidden = variants
                     .iter()
                     .any(|variant| variant.should_be_hidden(ctx.db(), module.krate()));
-                let patterns =
-                    variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
+                let patterns = variants.into_iter().filter_map(|variant| {
+                    build_pat(ctx.db(), module, variant, ctx.config.prefer_core)
+                });
 
                 (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
             })
@@ -349,10 +350,16 @@ fn resolve_tuple_of_enum_def(
         .collect()
 }
 
-fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Option<ast::Pat> {
+fn build_pat(
+    db: &RootDatabase,
+    module: hir::Module,
+    var: ExtendedVariant,
+    prefer_core: bool,
+) -> Option<ast::Pat> {
     match var {
         ExtendedVariant::Variant(var) => {
-            let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
+            let path =
+                mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_core)?);
 
             // FIXME: use HIR for this; it doesn't currently expose struct vs. tuple vs. unit variants though
             let pat: ast::Pat = match var.source(db)?.value.kind() {
diff --git a/crates/ide-assists/src/handlers/auto_import.rs b/crates/ide-assists/src/handlers/auto_import.rs
index 949cf3167a..88a6b8558c 100644
--- a/crates/ide-assists/src/handlers/auto_import.rs
+++ b/crates/ide-assists/src/handlers/auto_import.rs
@@ -89,8 +89,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists, GroupLabel};
 // ```
 pub(crate) fn auto_import(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
-    let mut proposed_imports =
-        import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
+    let mut proposed_imports = import_assets.search_for_imports(
+        &ctx.sema,
+        ctx.config.insert_use.prefix_kind,
+        ctx.config.prefer_core,
+    );
     if proposed_imports.is_empty() {
         return None;
     }
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 30f6dd41a1..e0c0e9a484 100644
--- a/crates/ide-assists/src/handlers/convert_into_to_from.rs
+++ b/crates/ide-assists/src/handlers/convert_into_to_from.rs
@@ -50,7 +50,7 @@ pub(crate) fn convert_into_to_from(acc: &mut Assists, ctx: &AssistContext<'_>) -
             _ => return None,
         };
 
-        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?)
+        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def, ctx.config.prefer_core)?)
     };
 
     let dest_type = match &ast_trait {
diff --git a/crates/ide-assists/src/handlers/extract_function.rs b/crates/ide-assists/src/handlers/extract_function.rs
index 52a55ead3a..749d94d5a9 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -152,6 +152,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,
+                        ctx.config.prefer_core,
                     );
 
                     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 ddc2052e7a..431f7b3c0f 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
@@ -409,6 +409,7 @@ fn process_references(
                     ctx.sema.db,
                     *enum_module_def,
                     ctx.config.insert_use.prefix_kind,
+                    ctx.config.prefer_core,
                 );
                 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 b484635121..cf4ed84281 100644
--- a/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/crates/ide-assists/src/handlers/generate_deref.rs
@@ -58,7 +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_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
+    let trait_path =
+        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?;
 
     let field_type = field.ty()?;
     let field_name = field.name()?;
@@ -98,7 +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_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
+    let trait_path =
+        module.find_use_path(ctx.db(), ModuleDef::Trait(trait_), ctx.config.prefer_core)?;
 
     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 6c93875e9e..ceb7dac0fe 100644
--- a/crates/ide-assists/src/handlers/generate_new.rs
+++ b/crates/ide-assists/src/handlers/generate_new.rs
@@ -60,8 +60,11 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
 
                 let item_in_ns = hir::ItemInNs::from(hir::ModuleDef::from(ty.as_adt()?));
 
-                let type_path = current_module
-                    .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
+                let type_path = current_module.find_use_path(
+                    ctx.sema.db,
+                    item_for_path_search(ctx.sema.db, item_in_ns)?,
+                    ctx.config.prefer_core,
+                )?;
 
                 let expr = use_trivial_constructor(
                     &ctx.sema.db,
diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs
index 121f8b4a13..cb81ebd228 100644
--- a/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -44,8 +44,11 @@ pub(crate) fn qualify_method_call(acc: &mut Assists, ctx: &AssistContext<'_>) ->
     let current_module = ctx.sema.scope(call.syntax())?.module();
     let target_module_def = ModuleDef::from(resolved_call);
     let item_in_ns = ItemInNs::from(target_module_def);
-    let receiver_path = current_module
-        .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
+    let receiver_path = current_module.find_use_path(
+        ctx.sema.db,
+        item_for_path_search(ctx.sema.db, item_in_ns)?,
+        ctx.config.prefer_core,
+    )?;
 
     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 0c2e9da386..232cd39e8b 100644
--- a/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/crates/ide-assists/src/handlers/qualify_path.rs
@@ -37,7 +37,8 @@ use crate::{
 // ```
 pub(crate) fn qualify_path(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let (import_assets, syntax_under_caret) = find_importable_node(ctx)?;
-    let mut proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
+    let mut proposed_imports =
+        import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_core);
     if proposed_imports.is_empty() {
         return None;
     }
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 d139f78a6f..04a1366327 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
@@ -85,7 +85,7 @@ pub(crate) fn replace_derive_with_manual_impl(
     })
     .flat_map(|trait_| {
         current_module
-            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
+            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_), ctx.config.prefer_core)
             .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 2419fa11c1..533e1670a0 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
@@ -67,6 +67,7 @@ pub(crate) fn replace_qualified_name_with_use(
                 ctx.sema.db,
                 module,
                 ctx.config.insert_use.prefix_kind,
+                ctx.config.prefer_core,
             )
         })
         .flatten();
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 55c3e28392..89a971e544 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -551,7 +551,9 @@ fn enum_variants_with_paths(
     }
 
     for variant in variants {
-        if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
+        if let Some(path) =
+            ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant), ctx.config.prefer_core)
+        {
             // Variants with trivial paths are already added by the existing completion logic,
             // so we should avoid adding these twice
             if path.segments().len() > 1 {
diff --git a/crates/ide-completion/src/completions/expr.rs b/crates/ide-completion/src/completions/expr.rs
index 588b52cc1e..1ccf33a96b 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -165,7 +165,11 @@ pub(crate) fn complete_expr_path(
                     hir::Adt::Struct(strukt) => {
                         let path = ctx
                             .module
-                            .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
+                            .find_use_path(
+                                ctx.db,
+                                hir::ModuleDef::from(strukt),
+                                ctx.config.prefer_core,
+                            )
                             .filter(|it| it.len() > 1);
 
                         acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
@@ -183,7 +187,7 @@ pub(crate) fn complete_expr_path(
                     hir::Adt::Union(un) => {
                         let path = ctx
                             .module
-                            .find_use_path(ctx.db, hir::ModuleDef::from(un))
+                            .find_use_path(ctx.db, hir::ModuleDef::from(un), ctx.config.prefer_core)
                             .filter(|it| it.len() > 1);
 
                         acc.add_union_literal(ctx, un, path, None);
diff --git a/crates/ide-completion/src/completions/flyimport.rs b/crates/ide-completion/src/completions/flyimport.rs
index f04cc15d7f..528959943b 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -262,7 +262,11 @@ fn import_on_the_fly(
 
     acc.add_all(
         import_assets
-            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
+            .search_for_imports(
+                &ctx.sema,
+                ctx.config.insert_use.prefix_kind,
+                ctx.config.prefer_core,
+            )
             .into_iter()
             .filter(ns_filter)
             .filter(|import| {
@@ -306,7 +310,11 @@ fn import_on_the_fly_pat_(
 
     acc.add_all(
         import_assets
-            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
+            .search_for_imports(
+                &ctx.sema,
+                ctx.config.insert_use.prefix_kind,
+                ctx.config.prefer_core,
+            )
             .into_iter()
             .filter(ns_filter)
             .filter(|import| {
@@ -344,7 +352,7 @@ fn import_on_the_fly_method(
     let user_input_lowercased = potential_import_name.to_lowercase();
 
     import_assets
-        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
+        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind, ctx.config.prefer_core)
         .into_iter()
         .filter(|import| {
             !ctx.is_item_hidden(&import.item_to_import)
diff --git a/crates/ide-completion/src/completions/mod_.rs b/crates/ide-completion/src/completions/mod_.rs
index 950731eb4c..9c975b9295 100644
--- a/crates/ide-completion/src/completions/mod_.rs
+++ b/crates/ide-completion/src/completions/mod_.rs
@@ -53,7 +53,6 @@ pub(crate) fn complete_mod(
     let existing_mod_declarations = current_module
         .children(ctx.db)
         .filter_map(|module| Some(module.name(ctx.db)?.to_string()))
-        .filter(|module| module != ctx.original_token.text())
         .collect::<FxHashSet<_>>();
 
     let module_declaration_file =
@@ -352,23 +351,4 @@ fn ignored_bar() {}
             "#]],
         );
     }
-
-    #[test]
-    fn semi_colon_completion() {
-        check(
-            r#"
-//- /lib.rs
-mod foo;
-//- /foo.rs
-mod bar {
-    mod baz$0
-}
-//- /foo/bar/baz.rs
-fn baz() {}
-"#,
-            expect![[r#"
-                md baz;
-            "#]],
-        );
-    }
 }
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index 80d6af2816..54ebce1eb7 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -17,6 +17,7 @@ pub struct CompletionConfig {
     pub callable: Option<CallableSnippets>,
     pub snippet_cap: Option<SnippetCap>,
     pub insert_use: InsertUseConfig,
+    pub prefer_core: bool,
     pub snippets: Vec<Snippet>,
 }
 
diff --git a/crates/ide-completion/src/lib.rs b/crates/ide-completion/src/lib.rs
index ae1a440d06..7cefb6bb4a 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -234,7 +234,12 @@ pub fn resolve_completion_edits(
         );
         let import = items_with_name
             .filter_map(|candidate| {
-                current_module.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
+                current_module.find_use_path_prefixed(
+                    db,
+                    candidate,
+                    config.insert_use.prefix_kind,
+                    config.prefer_core,
+                )
             })
             .find(|mod_path| mod_path.to_string() == full_import_path);
         if let Some(import_path) = import {
diff --git a/crates/ide-completion/src/snippet.rs b/crates/ide-completion/src/snippet.rs
index dc1039fa62..2dc62bbdc6 100644
--- a/crates/ide-completion/src/snippet.rs
+++ b/crates/ide-completion/src/snippet.rs
@@ -174,8 +174,12 @@ fn import_edits(ctx: &CompletionContext<'_>, requires: &[GreenNode]) -> Option<V
             hir::PathResolution::Def(def) => def.into(),
             _ => return None,
         };
-        let path =
-            ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
+        let path = ctx.module.find_use_path_prefixed(
+            ctx.db,
+            item,
+            ctx.config.insert_use.prefix_kind,
+            ctx.config.prefer_core,
+        )?;
         Some((path.len() > 1).then(|| LocatedImport::new(path.clone(), item, item, None)))
     };
     let mut res = Vec::with_capacity(requires.len());
diff --git a/crates/ide-db/src/imports/import_assets.rs b/crates/ide-db/src/imports/import_assets.rs
index 26ef86155e..53bc516109 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -212,18 +212,20 @@ impl ImportAssets {
         &self,
         sema: &Semantics<'_, RootDatabase>,
         prefix_kind: PrefixKind,
+        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for_imports");
-        self.search_for(sema, Some(prefix_kind))
+        self.search_for(sema, Some(prefix_kind), prefer_core)
     }
 
     /// This may return non-absolute paths if a part of the returned path is already imported into scope.
     pub fn search_for_relative_paths(
         &self,
         sema: &Semantics<'_, RootDatabase>,
+        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for_relative_paths");
-        self.search_for(sema, None)
+        self.search_for(sema, None, prefer_core)
     }
 
     pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) {
@@ -242,6 +244,7 @@ impl ImportAssets {
         &self,
         sema: &Semantics<'_, RootDatabase>,
         prefixed: Option<PrefixKind>,
+        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for");
 
@@ -252,6 +255,7 @@ impl ImportAssets {
                 item_for_path_search(sema.db, item)?,
                 &self.module_with_candidate,
                 prefixed,
+                prefer_core,
             )
         };
 
@@ -564,11 +568,12 @@ fn get_mod_path(
     item_to_search: ItemInNs,
     module_with_candidate: &Module,
     prefixed: Option<PrefixKind>,
+    prefer_core: bool,
 ) -> Option<ModPath> {
     if let Some(prefix_kind) = prefixed {
-        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind)
+        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind, prefer_core)
     } else {
-        module_with_candidate.find_use_path(db, item_to_search)
+        module_with_candidate.find_use_path(db, item_to_search, prefer_core)
     }
 }
 
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index 40af9e6fe2..12d873b4a0 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -173,6 +173,7 @@ impl<'a> Ctx<'a> {
                             let found_path = self.target_module.find_use_path(
                                 self.source_scope.db.upcast(),
                                 hir::ModuleDef::Trait(trait_ref),
+                                false,
                             )?;
                             match ast::make::ty_path(mod_path_to_ast(&found_path)) {
                                 ast::Type::PathType(path_ty) => Some(path_ty),
@@ -209,7 +210,7 @@ impl<'a> Ctx<'a> {
                 }
 
                 let found_path =
-                    self.target_module.find_use_path(self.source_scope.db.upcast(), def)?;
+                    self.target_module.find_use_path(self.source_scope.db.upcast(), def, false)?;
                 let res = mod_path_to_ast(&found_path).clone_for_update();
                 if let Some(args) = path.segment().and_then(|it| it.generic_arg_list()) {
                     if let Some(segment) = res.segment() {
diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
index a21db5b2ce..06073ca1b2 100644
--- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -137,6 +137,7 @@ pub(crate) fn json_in_items(
                                         sema.db,
                                         it,
                                         config.insert_use.prefix_kind,
+                                        config.prefer_core,
                                     ) {
                                         insert_use(
                                             &scope,
@@ -152,6 +153,7 @@ pub(crate) fn json_in_items(
                                         sema.db,
                                         it,
                                         config.insert_use.prefix_kind,
+                                        config.prefer_core,
                                     ) {
                                         insert_use(
                                             &scope,
diff --git a/crates/ide-diagnostics/src/handlers/missing_fields.rs b/crates/ide-diagnostics/src/handlers/missing_fields.rs
index edb1fc0919..5a81a55d82 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -124,6 +124,7 @@ fn fixes(ctx: &DiagnosticsContext<'_>, d: &hir::MissingFields) -> Option<Vec<Ass
                         let type_path = current_module?.find_use_path(
                             ctx.sema.db,
                             item_for_path_search(ctx.sema.db, item_in_ns)?,
+                            ctx.config.prefer_core,
                         )?;
 
                         use_trivial_constructor(
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 61e63ea7a9..22e644bb59 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -150,6 +150,7 @@ pub struct DiagnosticsConfig {
     pub expr_fill_default: ExprFillDefaultMode,
     // FIXME: We may want to include a whole `AssistConfig` here
     pub insert_use: InsertUseConfig,
+    pub prefer_core: bool,
 }
 
 impl DiagnosticsConfig {
@@ -170,6 +171,7 @@ impl DiagnosticsConfig {
                 group: false,
                 skip_glob_imports: false,
             },
+            prefer_core: false,
         }
     }
 }
diff --git a/crates/ide-ssr/src/matching.rs b/crates/ide-ssr/src/matching.rs
index e3a837ddcd..57b5ab6abd 100644
--- a/crates/ide-ssr/src/matching.rs
+++ b/crates/ide-ssr/src/matching.rs
@@ -648,9 +648,10 @@ impl Match {
             .module();
         for (path, resolved_path) in &template.resolved_paths {
             if let hir::PathResolution::Def(module_def) = resolved_path.resolution {
-                let mod_path = module.find_use_path(sema.db, module_def).ok_or_else(|| {
-                    match_error!("Failed to render template path `{}` at match location")
-                })?;
+                let mod_path =
+                    module.find_use_path(sema.db, module_def, false).ok_or_else(|| {
+                        match_error!("Failed to render template path `{}` at match location")
+                    })?;
                 self.rendered_template_paths.insert(path.clone(), mod_path);
             }
         }
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index d1b1d2c331..e9034daefa 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -1,5 +1,3 @@
-use std::fmt;
-
 use either::Either;
 use hir::{known, Callable, HasVisibility, HirDisplay, Mutability, Semantics, TypeInfo};
 use ide_db::{
@@ -71,7 +69,7 @@ pub enum InlayKind {
 pub struct InlayHint {
     pub range: TextRange,
     pub kind: InlayKind,
-    pub label: InlayHintLabel,
+    pub label: String,
     pub tooltip: Option<InlayTooltip>,
 }
 
@@ -82,83 +80,6 @@ pub enum InlayTooltip {
     HoverOffset(FileId, TextSize),
 }
 
-pub struct InlayHintLabel {
-    pub parts: Vec<InlayHintLabelPart>,
-}
-
-impl InlayHintLabel {
-    pub fn as_simple_str(&self) -> Option<&str> {
-        match &*self.parts {
-            [part] => part.as_simple_str(),
-            _ => None,
-        }
-    }
-
-    pub fn prepend_str(&mut self, s: &str) {
-        match &mut *self.parts {
-            [part, ..] if part.as_simple_str().is_some() => part.text = format!("{s}{}", part.text),
-            _ => self.parts.insert(0, InlayHintLabelPart { text: s.into(), linked_location: None }),
-        }
-    }
-
-    pub fn append_str(&mut self, s: &str) {
-        match &mut *self.parts {
-            [.., part] if part.as_simple_str().is_some() => part.text.push_str(s),
-            _ => self.parts.push(InlayHintLabelPart { text: s.into(), linked_location: None }),
-        }
-    }
-}
-
-impl From<String> for InlayHintLabel {
-    fn from(s: String) -> Self {
-        Self { parts: vec![InlayHintLabelPart { text: s, linked_location: None }] }
-    }
-}
-
-impl fmt::Display for InlayHintLabel {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        write!(f, "{}", self.parts.iter().map(|part| &part.text).format(""))
-    }
-}
-
-impl fmt::Debug for InlayHintLabel {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        f.debug_list().entries(&self.parts).finish()
-    }
-}
-
-pub struct InlayHintLabelPart {
-    pub text: String,
-    /// Source location represented by this label part. The client will use this to fetch the part's
-    /// hover tooltip, and Ctrl+Clicking the label part will navigate to the definition the location
-    /// refers to (not necessarily the location itself).
-    /// When setting this, no tooltip must be set on the containing hint, or VS Code will display
-    /// them both.
-    pub linked_location: Option<FileRange>,
-}
-
-impl InlayHintLabelPart {
-    pub fn as_simple_str(&self) -> Option<&str> {
-        match self {
-            Self { text, linked_location: None } => Some(text),
-            _ => None,
-        }
-    }
-}
-
-impl fmt::Debug for InlayHintLabelPart {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        match self.as_simple_str() {
-            Some(string) => string.fmt(f),
-            None => f
-                .debug_struct("InlayHintLabelPart")
-                .field("text", &self.text)
-                .field("linked_location", &self.linked_location)
-                .finish(),
-        }
-    }
-}
-
 // Feature: Inlay Hints
 //
 // rust-analyzer shows additional information inline with the source code.
@@ -271,10 +192,10 @@ fn closing_brace_hints(
 ) -> Option<()> {
     let min_lines = config.closing_brace_hints_min_lines?;
 
-    let name = |it: ast::Name| it.syntax().text_range();
+    let name = |it: ast::Name| it.syntax().text_range().start();
 
     let mut closing_token;
-    let (label, name_range) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
+    let (label, name_offset) = if let Some(item_list) = ast::AssocItemList::cast(node.clone()) {
         closing_token = item_list.r_curly_token()?;
 
         let parent = item_list.syntax().parent()?;
@@ -284,11 +205,11 @@ fn closing_brace_hints(
                     let imp = sema.to_def(&imp)?;
                     let ty = imp.self_ty(sema.db);
                     let trait_ = imp.trait_(sema.db);
-                    let hint_text = match trait_ {
+
+                    (match trait_ {
                         Some(tr) => format!("impl {} for {}", tr.name(sema.db), ty.display_truncated(sema.db, config.max_length)),
                         None => format!("impl {}", ty.display_truncated(sema.db, config.max_length)),
-                    };
-                    (hint_text, None)
+                    }, None)
                 },
                 ast::Trait(tr) => {
                     (format!("trait {}", tr.name()?), tr.name().map(name))
@@ -332,7 +253,7 @@ fn closing_brace_hints(
 
         (
             format!("{}!", mac.path()?),
-            mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range()),
+            mac.path().and_then(|it| it.segment()).map(|it| it.syntax().text_range().start()),
         )
     } else {
         return None;
@@ -357,12 +278,11 @@ fn closing_brace_hints(
         return None;
     }
 
-    let linked_location = name_range.map(|range| FileRange { file_id, range });
     acc.push(InlayHint {
         range: closing_token.text_range(),
         kind: InlayKind::ClosingBraceHint,
-        label: InlayHintLabel { parts: vec![InlayHintLabelPart { text: label, linked_location }] },
-        tooltip: None, // provided by label part location
+        label,
+        tooltip: name_offset.map(|it| InlayTooltip::HoverOffset(file_id, it)),
     });
 
     None
@@ -391,7 +311,7 @@ fn implicit_static_hints(
             acc.push(InlayHint {
                 range: t.text_range(),
                 kind: InlayKind::LifetimeHint,
-                label: "'static".to_owned().into(),
+                label: "'static".to_owned(),
                 tooltip: Some(InlayTooltip::String("Elided static lifetime".into())),
             });
         }
@@ -409,10 +329,10 @@ fn fn_lifetime_fn_hints(
         return None;
     }
 
-    let mk_lt_hint = |t: SyntaxToken, label: String| InlayHint {
+    let mk_lt_hint = |t: SyntaxToken, label| InlayHint {
         range: t.text_range(),
         kind: InlayKind::LifetimeHint,
-        label: label.into(),
+        label,
         tooltip: Some(InlayTooltip::String("Elided lifetime".into())),
     };
 
@@ -566,8 +486,7 @@ fn fn_lifetime_fn_hints(
                     "{}{}",
                     allocated_lifetimes.iter().format(", "),
                     if is_empty { "" } else { ", " }
-                )
-                .into(),
+                ),
                 tooltip: Some(InlayTooltip::String("Elided lifetimes".into())),
             });
         }
@@ -616,8 +535,7 @@ fn closure_ret_hints(
         range: param_list.syntax().text_range(),
         kind: InlayKind::ClosureReturnTypeHint,
         label: hint_iterator(sema, &famous_defs, config, &ty)
-            .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
-            .into(),
+            .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string()),
         tooltip: Some(InlayTooltip::HoverRanged(file_id, param_list.syntax().text_range())),
     });
     Some(())
@@ -644,7 +562,7 @@ fn reborrow_hints(
     acc.push(InlayHint {
         range: expr.syntax().text_range(),
         kind: InlayKind::ImplicitReborrowHint,
-        label: label.to_string().into(),
+        label: label.to_string(),
         tooltip: Some(InlayTooltip::String("Compiler inserted reborrow".into())),
     });
     Some(())
@@ -702,9 +620,9 @@ fn chaining_hints(
             acc.push(InlayHint {
                 range: expr.syntax().text_range(),
                 kind: InlayKind::ChainingHint,
-                label: hint_iterator(sema, &famous_defs, config, &ty)
-                    .unwrap_or_else(|| ty.display_truncated(sema.db, config.max_length).to_string())
-                    .into(),
+                label: hint_iterator(sema, &famous_defs, config, &ty).unwrap_or_else(|| {
+                    ty.display_truncated(sema.db, config.max_length).to_string()
+                }),
                 tooltip: Some(InlayTooltip::HoverRanged(file_id, expr.syntax().text_range())),
             });
         }
@@ -756,7 +674,7 @@ fn param_name_hints(
             InlayHint {
                 range,
                 kind: InlayKind::ParameterHint,
-                label: param_name.into(),
+                label: param_name,
                 tooltip: tooltip.map(|it| InlayTooltip::HoverOffset(it.file_id, it.range.start())),
             }
         });
@@ -787,7 +705,7 @@ fn binding_mode_hints(
         acc.push(InlayHint {
             range,
             kind: InlayKind::BindingModeHint,
-            label: r.to_string().into(),
+            label: r.to_string(),
             tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
         });
     });
@@ -802,7 +720,7 @@ fn binding_mode_hints(
             acc.push(InlayHint {
                 range,
                 kind: InlayKind::BindingModeHint,
-                label: bm.to_string().into(),
+                label: bm.to_string(),
                 tooltip: Some(InlayTooltip::String("Inferred binding mode".into())),
             });
         }
@@ -854,7 +772,7 @@ fn bind_pat_hints(
             None => pat.syntax().text_range(),
         },
         kind: InlayKind::TypeHint,
-        label: label.into(),
+        label,
         tooltip: pat
             .name()
             .map(|it| it.syntax().text_range())
@@ -2305,9 +2223,7 @@ fn main() {
                     InlayHint {
                         range: 147..172,
                         kind: ChainingHint,
-                        label: [
-                            "B",
-                        ],
+                        label: "B",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2320,9 +2236,7 @@ fn main() {
                     InlayHint {
                         range: 147..154,
                         kind: ChainingHint,
-                        label: [
-                            "A",
-                        ],
+                        label: "A",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2380,9 +2294,7 @@ fn main() {
                     InlayHint {
                         range: 143..190,
                         kind: ChainingHint,
-                        label: [
-                            "C",
-                        ],
+                        label: "C",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2395,9 +2307,7 @@ fn main() {
                     InlayHint {
                         range: 143..179,
                         kind: ChainingHint,
-                        label: [
-                            "B",
-                        ],
+                        label: "B",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2440,9 +2350,7 @@ fn main() {
                     InlayHint {
                         range: 246..283,
                         kind: ChainingHint,
-                        label: [
-                            "B<X<i32, bool>>",
-                        ],
+                        label: "B<X<i32, bool>>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2455,9 +2363,7 @@ fn main() {
                     InlayHint {
                         range: 246..265,
                         kind: ChainingHint,
-                        label: [
-                            "A<X<i32, bool>>",
-                        ],
+                        label: "A<X<i32, bool>>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2502,9 +2408,7 @@ fn main() {
                     InlayHint {
                         range: 174..241,
                         kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = ()>",
-                        ],
+                        label: "impl Iterator<Item = ()>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2517,9 +2421,7 @@ fn main() {
                     InlayHint {
                         range: 174..224,
                         kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = ()>",
-                        ],
+                        label: "impl Iterator<Item = ()>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2532,9 +2434,7 @@ fn main() {
                     InlayHint {
                         range: 174..206,
                         kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = ()>",
-                        ],
+                        label: "impl Iterator<Item = ()>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2547,9 +2447,7 @@ fn main() {
                     InlayHint {
                         range: 174..189,
                         kind: ChainingHint,
-                        label: [
-                            "&mut MyIter",
-                        ],
+                        label: "&mut MyIter",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2591,9 +2489,7 @@ fn main() {
                     InlayHint {
                         range: 124..130,
                         kind: TypeHint,
-                        label: [
-                            "Struct",
-                        ],
+                        label: "Struct",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2606,9 +2502,7 @@ fn main() {
                     InlayHint {
                         range: 145..185,
                         kind: ChainingHint,
-                        label: [
-                            "Struct",
-                        ],
+                        label: "Struct",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2621,9 +2515,7 @@ fn main() {
                     InlayHint {
                         range: 145..168,
                         kind: ChainingHint,
-                        label: [
-                            "Struct",
-                        ],
+                        label: "Struct",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2636,9 +2528,7 @@ fn main() {
                     InlayHint {
                         range: 222..228,
                         kind: ParameterHint,
-                        label: [
-                            "self",
-                        ],
+                        label: "self",
                         tooltip: Some(
                             HoverOffset(
                                 FileId(
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 0552330814..d61d69a090 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -82,8 +82,8 @@ pub use crate::{
     highlight_related::{HighlightRelatedConfig, HighlightedRange},
     hover::{HoverAction, HoverConfig, HoverDocFormat, HoverGotoTypeData, HoverResult},
     inlay_hints::{
-        ClosureReturnTypeHints, InlayHint, InlayHintLabel, InlayHintsConfig, InlayKind,
-        InlayTooltip, LifetimeElisionHints, ReborrowHints,
+        ClosureReturnTypeHints, InlayHint, InlayHintsConfig, InlayKind, InlayTooltip,
+        LifetimeElisionHints, ReborrowHints,
     },
     join_lines::JoinLinesConfig,
     markup::Markup,
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 54dcb42d99..6d1bf08124 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -263,6 +263,8 @@ config_data! {
         imports_group_enable: bool                           = "true",
         /// Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
         imports_merge_glob: bool           = "true",
+        /// Prefer to use imports of the core crate over the std crate.
+        imports_prefer_core: bool                     = "false",
         /// The path structure for newly inserted paths to use.
         imports_prefix: ImportPrefixDef               = "\"plain\"",
 
@@ -918,6 +920,7 @@ impl Config {
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
             },
             insert_use: self.insert_use_config(),
+            prefer_core: self.data.imports_prefer_core,
         }
     }
 
@@ -1133,6 +1136,7 @@ impl Config {
                 CallableCompletionDef::None => None,
             },
             insert_use: self.insert_use_config(),
+            prefer_core: self.data.imports_prefer_core,
             snippet_cap: SnippetCap::new(try_or_def!(
                 self.caps
                     .text_document
@@ -1156,6 +1160,7 @@ impl Config {
             snippet_cap: SnippetCap::new(self.experimental("snippetTextEdit")),
             allowed: None,
             insert_use: self.insert_use_config(),
+            prefer_core: self.data.imports_prefer_core,
         }
     }
 
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index e79cf3d3fd..d9b669afbe 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1362,7 +1362,7 @@ pub(crate) fn handle_inlay_hints(
             .map(|it| {
                 to_proto::inlay_hint(&snap, &line_index, inlay_hints_config.render_colons, it)
             })
-            .collect::<Result<Vec<_>>>()?,
+            .collect(),
     ))
 }
 
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index e49a98685a..5dbb64d7df 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -145,6 +145,7 @@ fn integrated_completion_benchmark() {
                 skip_glob_imports: true,
             },
             snippets: Vec::new(),
+            prefer_core: false,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -182,6 +183,7 @@ fn integrated_completion_benchmark() {
                 skip_glob_imports: true,
             },
             snippets: Vec::new(),
+            prefer_core: false,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index e083b9d0e3..102cd60295 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -9,9 +9,8 @@ use ide::{
     Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
     CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
     Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
-    InlayHintLabel, InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable,
-    Severity, SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange,
-    TextSize,
+    InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity,
+    SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
 use itertools::Itertools;
 use serde_json::to_value;
@@ -427,16 +426,9 @@ pub(crate) fn inlay_hint(
     snap: &GlobalStateSnapshot,
     line_index: &LineIndex,
     render_colons: bool,
-    mut inlay_hint: InlayHint,
-) -> Result<lsp_types::InlayHint> {
-    match inlay_hint.kind {
-        InlayKind::ParameterHint if render_colons => inlay_hint.label.append_str(":"),
-        InlayKind::TypeHint if render_colons => inlay_hint.label.prepend_str(": "),
-        InlayKind::ClosureReturnTypeHint => inlay_hint.label.prepend_str(" -> "),
-        _ => {}
-    }
-
-    Ok(lsp_types::InlayHint {
+    inlay_hint: InlayHint,
+) -> lsp_types::InlayHint {
+    lsp_types::InlayHint {
         position: match inlay_hint.kind {
             // before annotated thing
             InlayKind::ParameterHint
@@ -467,9 +459,15 @@ pub(crate) fn inlay_hint(
             | InlayKind::ImplicitReborrowHint
             | InlayKind::TypeHint
             | InlayKind::ClosingBraceHint => false,
-            InlayKind::BindingModeHint => inlay_hint.label.as_simple_str() != Some("&"),
+            InlayKind::BindingModeHint => inlay_hint.label != "&",
             InlayKind::ParameterHint | InlayKind::LifetimeHint => true,
         }),
+        label: lsp_types::InlayHintLabel::String(match inlay_hint.kind {
+            InlayKind::ParameterHint if render_colons => format!("{}:", inlay_hint.label),
+            InlayKind::TypeHint if render_colons => format!(": {}", inlay_hint.label),
+            InlayKind::ClosureReturnTypeHint => format!(" -> {}", inlay_hint.label),
+            _ => inlay_hint.label.clone(),
+        }),
         kind: match inlay_hint.kind {
             InlayKind::ParameterHint => Some(lsp_types::InlayHintKind::PARAMETER),
             InlayKind::ClosureReturnTypeHint | InlayKind::TypeHint | InlayKind::ChainingHint => {
@@ -508,36 +506,9 @@ pub(crate) fn inlay_hint(
         })(),
         tooltip: Some(match inlay_hint.tooltip {
             Some(ide::InlayTooltip::String(s)) => lsp_types::InlayHintTooltip::String(s),
-            _ => lsp_types::InlayHintTooltip::String(inlay_hint.label.to_string()),
+            _ => lsp_types::InlayHintTooltip::String(inlay_hint.label),
         }),
-        label: inlay_hint_label(snap, inlay_hint.label)?,
-    })
-}
-
-fn inlay_hint_label(
-    snap: &GlobalStateSnapshot,
-    label: InlayHintLabel,
-) -> Result<lsp_types::InlayHintLabel> {
-    Ok(match label.as_simple_str() {
-        Some(s) => lsp_types::InlayHintLabel::String(s.into()),
-        None => lsp_types::InlayHintLabel::LabelParts(
-            label
-                .parts
-                .into_iter()
-                .map(|part| {
-                    Ok(lsp_types::InlayHintLabelPart {
-                        value: part.text,
-                        tooltip: None,
-                        location: part
-                            .linked_location
-                            .map(|range| location(snap, range))
-                            .transpose()?,
-                        command: None,
-                    })
-                })
-                .collect::<Result<Vec<_>>>()?,
-        ),
-    })
+    }
 }
 
 static TOKEN_RESULT_COUNTER: AtomicU32 = AtomicU32::new(1);
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index 72b9257264..6757624aea 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -353,6 +353,11 @@ Group inserted imports by the https://rust-analyzer.github.io/manual.html#auto-i
 --
 Whether to allow import insertion to merge new imports into single path glob imports like `use std::fmt::*;`.
 --
+[[rust-analyzer.imports.prefer.core]]rust-analyzer.imports.prefer.core (default: `false`)::
++
+--
+Prefer to use imports of the core crate over the std crate.
+--
 [[rust-analyzer.imports.prefix]]rust-analyzer.imports.prefix (default: `"plain"`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index 767c5875bf..7e91d989f1 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -803,6 +803,11 @@
                     "default": true,
                     "type": "boolean"
                 },
+                "rust-analyzer.imports.prefer.core": {
+                    "markdownDescription": "Prefer to use imports of the core crate over the std crate.",
+                    "default": false,
+                    "type": "boolean"
+                },
                 "rust-analyzer.imports.prefix": {
                     "markdownDescription": "The path structure for newly inserted paths to use.",
                     "default": "plain",


Test patch:
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index 9cd66c6b3b..4e589dc86a 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -29,6 +29,7 @@ pub(crate) const TEST_CONFIG: AssistConfig = AssistConfig {
         group: true,
         skip_glob_imports: true,
     },
+    prefer_core: false,
 };
 
 pub(crate) fn with_single_file(text: &str) -> (RootDatabase, FileId) {
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index cf826648dc..d24c914856 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -66,6 +66,7 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     enable_private_editable: false,
     callable: Some(CallableSnippets::FillArguments),
     snippet_cap: SnippetCap::new(true),
+    prefer_core: false,
     insert_use: InsertUseConfig {
         granularity: ImportGranularity::Crate,
         prefix_kind: PrefixKind::Plain,