Repository: rust-lang/rust-analyzer
Pull request #13209 (2022-09-09 08:39:45)

feat: type inference for generators
This PR implements basic type inference for generator and yield expressions.

Things not included in this PR:
- Generator upvars and generator witnesses are not implemented. They are only used to determine auto trait impls, so basic type inference should be fine without them, but method resolutions with auto trait bounds may not be resolved correctly.

Open questions:
- I haven't (yet) implemented `HirDisplay` for `TyKind::Generator`, so generator types are just shown as "{{generator}}" (in tests, inlay hints, hovers, etc.), which is not really nice. How should we show them?
- I added moderate amount of stuffs to minicore. I especially didn't want to add `impl<T> Deref for &T` and `impl<T> Deref for &mut T` exclusively for tests for generators; should I move them into the test fixtures or can they be placed in minicore?

cc #4309


Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index f4d472e3d5..303a10615b 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -34,7 +34,6 @@ jobs:
           - os: ubuntu-20.04
             target: x86_64-unknown-linux-gnu
             code-target: linux-x64
-            container: ubuntu:18.04
           - os: ubuntu-20.04
             target: aarch64-unknown-linux-gnu
             code-target: linux-arm64
@@ -50,7 +49,6 @@ jobs:
 
     name: dist (${{ matrix.target }})
     runs-on: ${{ matrix.os }}
-    container: ${{ matrix.container }}
 
     env:
       RA_TARGET: ${{ matrix.target }}
@@ -61,14 +59,6 @@ jobs:
         with:
           fetch-depth: ${{ env.FETCH_DEPTH }}
 
-      - name: Install toolchain dependencies
-        if: matrix.container == 'ubuntu:18.04'
-        shell: bash
-        run: |
-          apt-get update && apt-get install -y build-essential curl
-          curl --proto '=https' --tlsv1.2 --retry 10 --retry-connrefused -fsSL "https://sh.rustup.rs" | sh -s -- --profile minimal --default-toolchain none -y
-          echo "${CARGO_HOME:-$HOME/.cargo}/bin" >> $GITHUB_PATH
-
       - name: Install Rust toolchain
         run: |
           rustup update --no-self-update stable
diff --git a/crates/hir-def/src/body/lower.rs b/crates/hir-def/src/body/lower.rs
index 3b3297f781..c4f91e49a6 100644
--- a/crates/hir-def/src/body/lower.rs
+++ b/crates/hir-def/src/body/lower.rs
@@ -29,8 +29,9 @@ use crate::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinUint},
     db::DefDatabase,
     expr::{
-        dummy_expr_id, Array, BindingAnnotation, Expr, ExprId, FloatTypeWrapper, Label, LabelId,
-        Literal, MatchArm, Pat, PatId, RecordFieldPat, RecordLitField, Statement,
+        dummy_expr_id, Array, BindingAnnotation, ClosureKind, Expr, ExprId, FloatTypeWrapper,
+        Label, LabelId, Literal, MatchArm, Movability, Pat, PatId, RecordFieldPat, RecordLitField,
+        Statement,
     },
     intern::Interned,
     item_scope::BuiltinShadowMode,
@@ -97,6 +98,7 @@ pub(super) fn lower(
         name_to_pat_grouping: Default::default(),
         is_lowering_inside_or_pat: false,
         is_lowering_assignee_expr: false,
+        is_lowering_generator: false,
     }
     .collect(params, body)
 }
@@ -111,6 +113,7 @@ struct ExprCollector<'a> {
     name_to_pat_grouping: FxHashMap<Name, Vec<PatId>>,
     is_lowering_inside_or_pat: bool,
     is_lowering_assignee_expr: bool,
+    is_lowering_generator: bool,
 }
 
 impl ExprCollector<'_> {
@@ -358,6 +361,7 @@ impl ExprCollector<'_> {
                 self.alloc_expr(Expr::Return { expr }, syntax_ptr)
             }
             ast::Expr::YieldExpr(e) => {
+                self.is_lowering_generator = true;
                 let expr = e.expr().map(|e| self.collect_expr(e));
                 self.alloc_expr(Expr::Yield { expr }, syntax_ptr)
             }
@@ -459,13 +463,31 @@ impl ExprCollector<'_> {
                     .ret_type()
                     .and_then(|r| r.ty())
                     .map(|it| Interned::new(TypeRef::from_ast(&self.ctx(), it)));
+
+                let prev_is_lowering_generator = self.is_lowering_generator;
+                self.is_lowering_generator = false;
+
                 let body = self.collect_expr_opt(e.body());
+
+                let closure_kind = if self.is_lowering_generator {
+                    let movability = if e.static_token().is_some() {
+                        Movability::Static
+                    } else {
+                        Movability::Movable
+                    };
+                    ClosureKind::Generator(movability)
+                } else {
+                    ClosureKind::Closure
+                };
+                self.is_lowering_generator = prev_is_lowering_generator;
+
                 self.alloc_expr(
                     Expr::Closure {
                         args: args.into(),
                         arg_types: arg_types.into(),
                         ret_type,
                         body,
+                        closure_kind,
                     },
                     syntax_ptr,
                 )
diff --git a/crates/hir-def/src/body/pretty.rs b/crates/hir-def/src/body/pretty.rs
index f2fed95444..35686af388 100644
--- a/crates/hir-def/src/body/pretty.rs
+++ b/crates/hir-def/src/body/pretty.rs
@@ -3,7 +3,7 @@
 use std::fmt::{self, Write};
 
 use crate::{
-    expr::{Array, BindingAnnotation, Literal, Statement},
+    expr::{Array, BindingAnnotation, ClosureKind, Literal, Movability, Statement},
     pretty::{print_generic_args, print_path, print_type_ref},
     type_ref::TypeRef,
 };
@@ -350,7 +350,10 @@ impl<'a> Printer<'a> {
                 self.print_expr(*index);
                 w!(self, "]");
             }
-            Expr::Closure { args, arg_types, ret_type, body } => {
+            Expr::Closure { args, arg_types, ret_type, body, closure_kind } => {
+                if let ClosureKind::Generator(Movability::Static) = closure_kind {
+                    w!(self, "static ");
+                }
                 w!(self, "|");
                 for (i, (pat, ty)) in args.iter().zip(arg_types.iter()).enumerate() {
                     if i != 0 {
diff --git a/crates/hir-def/src/expr.rs b/crates/hir-def/src/expr.rs
index 419d3feec3..1626465502 100644
--- a/crates/hir-def/src/expr.rs
+++ b/crates/hir-def/src/expr.rs
@@ -198,6 +198,7 @@ pub enum Expr {
         arg_types: Box<[Option<Interned<TypeRef>>]>,
         ret_type: Option<Interned<TypeRef>>,
         body: ExprId,
+        closure_kind: ClosureKind,
     },
     Tuple {
         exprs: Box<[ExprId]>,
@@ -211,6 +212,18 @@ pub enum Expr {
     Underscore,
 }
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum ClosureKind {
+    Closure,
+    Generator(Movability),
+}
+
+#[derive(Debug, Clone, Copy, PartialEq, Eq)]
+pub enum Movability {
+    Static,
+    Movable,
+}
+
 #[derive(Debug, Clone, Eq, PartialEq)]
 pub enum Array {
     ElementList { elements: Box<[ExprId]>, is_assignee_expr: bool },
diff --git a/crates/hir-def/src/find_path.rs b/crates/hir-def/src/find_path.rs
index f46054e8cc..89e961f84f 100644
--- a/crates/hir-def/src/find_path.rs
+++ b/crates/hir-def/src/find_path.rs
@@ -16,14 +16,9 @@ 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,
-    prefer_core: bool,
-) -> Option<ModPath> {
+pub fn find_path(db: &dyn DefDatabase, item: ItemInNs, from: ModuleId) -> Option<ModPath> {
     let _p = profile::span("find_path");
-    find_path_inner(db, item, from, None, prefer_core)
+    find_path_inner(db, item, from, None)
 }
 
 pub fn find_path_prefixed(
@@ -31,10 +26,9 @@ 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), prefer_core)
+    find_path_inner(db, item, from, Some(prefix_kind))
 }
 
 const MAX_PATH_LEN: usize = 15;
@@ -106,22 +100,12 @@ 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,
-        prefer_core,
-    )
+    find_path_inner_(db, &def_map, from, item, MAX_PATH_LEN, prefixed, &mut visited_modules)
 }
 
 fn find_path_inner_(
@@ -132,7 +116,6 @@ 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;
@@ -208,9 +191,7 @@ 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, prefer_core)
-        {
+        if let Some(mut path) = find_path(db, ItemInNs::Types(variant.parent.into()), from) {
             let data = db.enum_data(variant.parent);
             path.push_segment(data.variants[variant.local_id].name.clone());
             return Some(path);
@@ -221,7 +202,7 @@ fn find_path_inner_(
     }
 
     // - otherwise, look for modules containing (reexporting) it and import it from one of those
-    let prefer_no_std = prefer_core || db.crate_supports_no_std(crate_root.krate);
+    let prefer_no_std = db.crate_supports_no_std(crate_root.krate);
     let mut best_path = None;
     let mut best_path_len = max_len;
 
@@ -242,7 +223,6 @@ fn find_path_inner_(
                 best_path_len - 1,
                 prefixed,
                 visited_modules,
-                prefer_core,
             ) {
                 path.push_segment(name);
 
@@ -273,7 +253,6 @@ 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());
@@ -449,8 +428,7 @@ mod tests {
             .take_types()
             .unwrap();
 
-        let found_path =
-            find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind, false);
+        let found_path = find_path_inner(&db, ItemInNs::Types(resolved), module, prefix_kind);
         assert_eq!(found_path, Some(mod_path), "{:?}", prefix_kind);
     }
 
diff --git a/crates/hir-ty/src/builder.rs b/crates/hir-ty/src/builder.rs
index 94d7806cb6..3ae7fb2a61 100644
--- a/crates/hir-ty/src/builder.rs
+++ b/crates/hir-ty/src/builder.rs
@@ -9,8 +9,8 @@ use chalk_ir::{
     AdtId, BoundVar, DebruijnIndex, Scalar,
 };
 use hir_def::{
-    builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
-    TypeAliasId,
+    builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, DefWithBodyId,
+    GenericDefId, TraitId, TypeAliasId,
 };
 use smallvec::SmallVec;
 
@@ -205,6 +205,38 @@ impl TyBuilder<()> {
         )
     }
 
+    /// Creates a `TyBuilder` to build `Substitution` for a generator defined in `parent`.
+    ///
+    /// A generator's substitution consists of:
+    /// - generic parameters in scope on `parent`
+    /// - resume type of generator
+    /// - yield type of generator ([`Generator::Yield`](std::ops::Generator::Yield))
+    /// - return type of generator ([`Generator::Return`](std::ops::Generator::Return))
+    /// in this order.
+    ///
+    /// This method prepopulates the builder with placeholder substitution of `parent`, so you
+    /// should only push exactly 3 `GenericArg`s before building.
+    pub fn subst_for_generator(db: &dyn HirDatabase, parent: DefWithBodyId) -> TyBuilder<()> {
+        let parent_subst = match parent.as_generic_def_id() {
+            Some(parent) => generics(db.upcast(), parent).placeholder_subst(db),
+            // Static initializers *may* contain generators.
+            None => Substitution::empty(Interner),
+        };
+        let builder = TyBuilder::new(
+            (),
+            parent_subst
+                .iter(Interner)
+                .map(|arg| match arg.constant(Interner) {
+                    Some(c) => ParamKind::Const(c.data(Interner).ty.clone()),
+                    None => ParamKind::Type,
+                })
+                // These represent resume type, yield type, and return type of generator.
+                .chain(std::iter::repeat(ParamKind::Type).take(3))
+                .collect(),
+        );
+        builder.use_parent_substs(&parent_subst)
+    }
+
     pub fn build(self) -> Substitution {
         let ((), subst) = self.build_internal();
         subst
diff --git a/crates/hir-ty/src/chalk_db.rs b/crates/hir-ty/src/chalk_db.rs
index faec99c7d3..c5cf6729d1 100644
--- a/crates/hir-ty/src/chalk_db.rs
+++ b/crates/hir-ty/src/chalk_db.rs
@@ -11,6 +11,7 @@ use chalk_solve::rust_ir::{self, OpaqueTyDatumBound, WellKnownTrait};
 
 use base_db::CrateId;
 use hir_def::{
+    expr::Movability,
     lang_item::{lang_attr, LangItemTarget},
     AssocItemId, GenericDefId, HasModule, ItemContainerId, Lookup, ModuleId, TypeAliasId,
 };
@@ -26,9 +27,9 @@ use crate::{
     to_assoc_type_id, to_chalk_trait_id,
     traits::ChalkContext,
     utils::generics,
-    AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId, Interner, ProjectionTy,
-    ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef, TraitRefExt, Ty, TyBuilder,
-    TyExt, TyKind, WhereClause,
+    wrap_empty_binders, AliasEq, AliasTy, BoundVar, CallableDefId, DebruijnIndex, FnDefId,
+    Interner, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Substitution, TraitRef,
+    TraitRefExt, Ty, TyBuilder, TyExt, TyKind, WhereClause,
 };
 
 pub(crate) type AssociatedTyDatum = chalk_solve::rust_ir::AssociatedTyDatum<Interner>;
@@ -372,17 +373,63 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
     }
     fn generator_datum(
         &self,
-        _: chalk_ir::GeneratorId<Interner>,
+        id: chalk_ir::GeneratorId<Interner>,
     ) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorDatum<Interner>> {
-        // FIXME
-        unimplemented!()
+        let (parent, expr) = self.db.lookup_intern_generator(id.into());
+
+        // We fill substitution with unknown type, because we only need to know whether the generic
+        // params are types or consts to build `Binders` and those being filled up are for
+        // `resume_type`, `yield_type`, and `return_type` of the generator in question.
+        let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
+
+        let len = subst.len(Interner);
+        let input_output = rust_ir::GeneratorInputOutputDatum {
+            resume_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 3))
+                .intern(Interner),
+            yield_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 2))
+                .intern(Interner),
+            return_type: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, len - 1))
+                .intern(Interner),
+            // FIXME: calculate upvars
+            upvars: vec![],
+        };
+
+        let it = subst
+            .iter(Interner)
+            .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
+        let input_output = crate::make_type_and_const_binders(it, input_output);
+
+        let movability = match self.db.body(parent)[expr] {
+            hir_def::expr::Expr::Closure {
+                closure_kind: hir_def::expr::ClosureKind::Generator(movability),
+                ..
+            } => movability,
+            _ => unreachable!("non generator expression interned as generator"),
+        };
+        let movability = match movability {
+            Movability::Static => rust_ir::Movability::Static,
+            Movability::Movable => rust_ir::Movability::Movable,
+        };
+
+        Arc::new(rust_ir::GeneratorDatum { movability, input_output })
     }
     fn generator_witness_datum(
         &self,
-        _: chalk_ir::GeneratorId<Interner>,
+        id: chalk_ir::GeneratorId<Interner>,
     ) -> std::sync::Arc<chalk_solve::rust_ir::GeneratorWitnessDatum<Interner>> {
-        // FIXME
-        unimplemented!()
+        // FIXME: calculate inner types
+        let inner_types =
+            rust_ir::GeneratorWitnessExistential { types: wrap_empty_binders(vec![]) };
+
+        let (parent, _) = self.db.lookup_intern_generator(id.into());
+        // See the comment in `generator_datum()` for unknown types.
+        let subst = TyBuilder::subst_for_generator(self.db, parent).fill_with_unknown().build();
+        let it = subst
+            .iter(Interner)
+            .map(|it| it.constant(Interner).map(|c| c.data(Interner).ty.clone()));
+        let inner_types = crate::make_type_and_const_binders(it, inner_types);
+
+        Arc::new(rust_ir::GeneratorWitnessDatum { inner_types })
     }
 
     fn unification_database(&self) -> &dyn chalk_ir::UnificationDatabase<Interner> {
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index dd5639f00d..c4f7685cd1 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -116,6 +116,8 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
     #[salsa::interned]
     fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
+    #[salsa::interned]
+    fn intern_generator(&self, id: (DefWithBodyId, ExprId)) -> InternedGeneratorId;
 
     #[salsa::invoke(chalk_db::associated_ty_data_query)]
     fn associated_ty_data(&self, id: chalk_db::AssocTypeId) -> Arc<chalk_db::AssociatedTyDatum>;
@@ -150,14 +152,6 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
         id: chalk_db::AssociatedTyValueId,
     ) -> Arc<chalk_db::AssociatedTyValue>;
 
-    #[salsa::invoke(crate::traits::normalize_projection_query)]
-    #[salsa::transparent]
-    fn normalize_projection(
-        &self,
-        projection: crate::ProjectionTy,
-        env: Arc<crate::TraitEnvironment>,
-    ) -> Option<crate::Ty>;
-
     #[salsa::invoke(trait_solve_wait)]
     #[salsa::transparent]
     fn trait_solve(
@@ -226,6 +220,10 @@ impl_intern_key!(InternedOpaqueTyId);
 pub struct InternedClosureId(salsa::InternId);
 impl_intern_key!(InternedClosureId);
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct InternedGeneratorId(salsa::InternId);
+impl_intern_key!(InternedGeneratorId);
+
 /// This exists just for Chalk, because Chalk just has a single `FnDefId` where
 /// we have different IDs for struct and enum variant constructors.
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Ord, PartialOrd)]
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index 874abdaea8..71763430ea 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -20,6 +20,7 @@ use hir_def::{
 };
 use hir_expand::{hygiene::Hygiene, name::Name};
 use itertools::Itertools;
+use smallvec::SmallVec;
 use syntax::SmolStr;
 
 use crate::{
@@ -221,6 +222,7 @@ pub enum DisplaySourceCodeError {
     PathNotFound,
     UnknownType,
     Closure,
+    Generator,
 }
 
 pub enum HirDisplayError {
@@ -533,7 +535,6 @@ impl HirDisplay for Ty {
                             f.db.upcast(),
                             ItemInNs::Types((*def_id).into()),
                             module_id,
-                            false,
                         ) {
                             write!(f, "{}", path)?;
                         } else {
@@ -783,7 +784,34 @@ impl HirDisplay for Ty {
                 write!(f, "{{unknown}}")?;
             }
             TyKind::InferenceVar(..) => write!(f, "_")?,
-            TyKind::Generator(..) => write!(f, "{{generator}}")?,
+            TyKind::Generator(_, subst) => {
+                if f.display_target.is_source_code() {
+                    return Err(HirDisplayError::DisplaySourceCodeError(
+                        DisplaySourceCodeError::Generator,
+                    ));
+                }
+
+                let subst = subst.as_slice(Interner);
+                let a: Option<SmallVec<[&Ty; 3]>> = subst
+                    .get(subst.len() - 3..)
+                    .map(|args| args.iter().map(|arg| arg.ty(Interner)).collect())
+                    .flatten();
+
+                if let Some([resume_ty, yield_ty, ret_ty]) = a.as_deref() {
+                    write!(f, "|")?;
+                    resume_ty.hir_fmt(f)?;
+                    write!(f, "|")?;
+
+                    write!(f, " yields ")?;
+                    yield_ty.hir_fmt(f)?;
+
+                    write!(f, " -> ")?;
+                    ret_ty.hir_fmt(f)?;
+                } else {
+                    // This *should* be unreachable, but fallback just in case.
+                    write!(f, "{{generator}}")?;
+                }
+            }
             TyKind::GeneratorWitness(..) => write!(f, "{{generator witness}}")?,
         }
         Ok(())
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index e37763e8ea..d351eb599c 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -332,7 +332,7 @@ pub struct InferenceResult {
     /// unresolved or missing subpatterns or subpatterns of mismatched types.
     pub type_of_pat: ArenaMap<PatId, Ty>,
     type_mismatches: FxHashMap<ExprOrPatId, TypeMismatch>,
-    /// Interned Unknown to return references to.
+    /// Interned common types to return references to.
     standard_types: InternedStandardTypes,
     /// Stores the types which were implicitly dereferenced in pattern binding modes.
     pub pat_adjustments: FxHashMap<PatId, Vec<Ty>>,
@@ -412,6 +412,8 @@ pub(crate) struct InferenceContext<'a> {
     /// closures, but currently this is the only field that will change there,
     /// so it doesn't make sense.
     return_ty: Ty,
+    /// The resume type and the yield type, respectively, of the generator being inferred.
+    resume_yield_tys: Option<(Ty, Ty)>,
     diverges: Diverges,
     breakables: Vec<BreakableContext>,
 }
@@ -476,6 +478,7 @@ impl<'a> InferenceContext<'a> {
             table: unify::InferenceTable::new(db, trait_env.clone()),
             trait_env,
             return_ty: TyKind::Error.intern(Interner), // set in collect_fn_signature
+            resume_yield_tys: None,
             db,
             owner,
             body,
@@ -673,6 +676,10 @@ impl<'a> InferenceContext<'a> {
         )
     }
 
+    fn resolve_obligations_as_possible(&mut self) {
+        self.table.resolve_obligations_as_possible();
+    }
+
     fn push_obligation(&mut self, o: DomainGoal) {
         self.table.register_obligation(o.cast(Interner));
     }
@@ -692,6 +699,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_ty_shallow(&mut self, ty: &Ty) -> Ty {
+        self.resolve_obligations_as_possible();
         self.table.resolve_ty_shallow(ty)
     }
 
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 3ead929098..094e460dbf 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -12,6 +12,7 @@ use crate::{
 use super::{Expectation, InferenceContext};
 
 impl InferenceContext<'_> {
+    // This function handles both closures and generators.
     pub(super) fn deduce_closure_type_from_expectations(
         &mut self,
         closure_expr: ExprId,
@@ -27,6 +28,11 @@ impl InferenceContext<'_> {
         // Deduction from where-clauses in scope, as well as fn-pointer coercion are handled here.
         let _ = self.coerce(Some(closure_expr), closure_ty, &expected_ty);
 
+        // Generators are not Fn* so return early.
+        if matches!(closure_ty.kind(Interner), TyKind::Generator(..)) {
+            return;
+        }
+
         // Deduction based on the expected `dyn Fn` is done separately.
         if let TyKind::Dyn(dyn_ty) = expected_ty.kind(Interner) {
             if let Some(sig) = self.deduce_sig_from_dyn_ty(dyn_ty) {
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 2d04a864a2..e3d6be23e6 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -10,7 +10,10 @@ use chalk_ir::{
     cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
 };
 use hir_def::{
-    expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, LabelId, Literal, Statement, UnaryOp},
+    expr::{
+        ArithOp, Array, BinaryOp, ClosureKind, CmpOp, Expr, ExprId, LabelId, Literal, Statement,
+        UnaryOp,
+    },
     generics::TypeOrConstParamData,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
@@ -216,7 +219,7 @@ impl<'a> InferenceContext<'a> {
                 self.diverges = Diverges::Maybe;
                 TyBuilder::unit()
             }
-            Expr::Closure { body, args, ret_type, arg_types } => {
+            Expr::Closure { body, args, ret_type, arg_types, closure_kind } => {
                 assert_eq!(args.len(), arg_types.len());
 
                 let mut sig_tys = Vec::new();
@@ -244,20 +247,40 @@ impl<'a> InferenceContext<'a> {
                     ),
                 })
                 .intern(Interner);
-                let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
-                let closure_ty =
-                    TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
-                        .intern(Interner);
+
+                let (ty, resume_yield_tys) = if matches!(closure_kind, ClosureKind::Generator(_)) {
+                    // FIXME: report error when there are more than 1 parameter.
+                    let resume_ty = match sig_tys.first() {
+                        // When `sig_tys.len() == 1` the first type is the return type, not the
+                        // first parameter type.
+                        Some(ty) if sig_tys.len() > 1 => ty.clone(),
+                        _ => self.result.standard_types.unit.clone(),
+                    };
+                    let yield_ty = self.table.new_type_var();
+
+                    let subst = TyBuilder::subst_for_generator(self.db, self.owner)
+                        .push(resume_ty.clone())
+                        .push(yield_ty.clone())
+                        .push(ret_ty.clone())
+                        .build();
+
+                    let generator_id = self.db.intern_generator((self.owner, tgt_expr)).into();
+                    let generator_ty = TyKind::Generator(generator_id, subst).intern(Interner);
+
+                    (generator_ty, Some((resume_ty, yield_ty)))
+                } else {
+                    let closure_id = self.db.intern_closure((self.owner, tgt_expr)).into();
+                    let closure_ty =
+                        TyKind::Closure(closure_id, Substitution::from1(Interner, sig_ty.clone()))
+                            .intern(Interner);
+
+                    (closure_ty, None)
+                };
 
                 // Eagerly try to relate the closure type with the expected
                 // type, otherwise we often won't have enough information to
                 // infer the body.
-                self.deduce_closure_type_from_expectations(
-                    tgt_expr,
-                    &closure_ty,
-                    &sig_ty,
-                    expected,
-                );
+                self.deduce_closure_type_from_expectations(tgt_expr, &ty, &sig_ty, expected);
 
                 // Now go through the argument patterns
                 for (arg_pat, arg_ty) in args.iter().zip(sig_tys) {
@@ -266,6 +289,8 @@ impl<'a> InferenceContext<'a> {
 
                 let prev_diverges = mem::replace(&mut self.diverges, Diverges::Maybe);
                 let prev_ret_ty = mem::replace(&mut self.return_ty, ret_ty.clone());
+                let prev_resume_yield_tys =
+                    mem::replace(&mut self.resume_yield_tys, resume_yield_tys);
 
                 self.with_breakable_ctx(BreakableKind::Border, self.err_ty(), None, |this| {
                     this.infer_expr_coerce(*body, &Expectation::has_type(ret_ty));
@@ -273,8 +298,9 @@ impl<'a> InferenceContext<'a> {
 
                 self.diverges = prev_diverges;
                 self.return_ty = prev_ret_ty;
+                self.resume_yield_tys = prev_resume_yield_tys;
 
-                closure_ty
+                ty
             }
             Expr::Call { callee, args, .. } => {
                 let callee_ty = self.infer_expr(*callee, &Expectation::none());
@@ -423,11 +449,18 @@ impl<'a> InferenceContext<'a> {
                 TyKind::Never.intern(Interner)
             }
             Expr::Yield { expr } => {
-                // FIXME: track yield type for coercion
-                if let Some(expr) = expr {
-                    self.infer_expr(*expr, &Expectation::none());
+                if let Some((resume_ty, yield_ty)) = self.resume_yield_tys.clone() {
+                    if let Some(expr) = expr {
+                        self.infer_expr_coerce(*expr, &Expectation::has_type(yield_ty));
+                    } else {
+                        let unit = self.result.standard_types.unit.clone();
+                        let _ = self.coerce(Some(tgt_expr), &unit, &yield_ty);
+                    }
+                    resume_ty
+                } else {
+                    // FIXME: report error (yield expr in non-generator)
+                    TyKind::Error.intern(Interner)
                 }
-                TyKind::Never.intern(Interner)
             }
             Expr::RecordLit { path, fields, spread, .. } => {
                 let (ty, def_id) = self.resolve_variant(path.as_deref(), false);
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index de4a5446e5..a82a331d4b 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -196,6 +196,20 @@ pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
     make_binders_with_count(db, usize::MAX, generics, value)
 }
 
+// FIXME: get rid of this
+pub fn make_canonical<T: HasInterner<Interner = Interner>>(
+    value: T,
+    kinds: impl IntoIterator<Item = TyVariableKind>,
+) -> Canonical<T> {
+    let kinds = kinds.into_iter().map(|tk| {
+        chalk_ir::CanonicalVarKind::new(
+            chalk_ir::VariableKind::Ty(tk),
+            chalk_ir::UniverseIndex::ROOT,
+        )
+    });
+    Canonical { value, binders: chalk_ir::CanonicalVarKinds::from_iter(Interner, kinds) }
+}
+
 // FIXME: get rid of this, just replace it by FnPointer
 /// A function signature as seen by type inference: Several parameter types and
 /// one return type.
diff --git a/crates/hir-ty/src/mapping.rs b/crates/hir-ty/src/mapping.rs
index d765fee0e1..f80fb39c1f 100644
--- a/crates/hir-ty/src/mapping.rs
+++ b/crates/hir-ty/src/mapping.rs
@@ -103,6 +103,18 @@ impl From<crate::db::InternedClosureId> for chalk_ir::ClosureId<Interner> {
     }
 }
 
+impl From<chalk_ir::GeneratorId<Interner>> for crate::db::InternedGeneratorId {
+    fn from(id: chalk_ir::GeneratorId<Interner>) -> Self {
+        Self::from_intern_id(id.0)
+    }
+}
+
+impl From<crate::db::InternedGeneratorId> for chalk_ir::GeneratorId<Interner> {
+    fn from(id: crate::db::InternedGeneratorId) -> Self {
+        chalk_ir::GeneratorId(id.as_intern_id())
+    }
+}
+
 pub fn to_foreign_def_id(id: TypeAliasId) -> ForeignDefId {
     chalk_ir::ForeignDefId(salsa::InternKey::as_intern_id(&id))
 }
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index dbf2750032..9a63d5013b 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -914,10 +914,22 @@ fn iterate_trait_method_candidates(
     let db = table.db;
     let env = table.trait_env.clone();
     let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
+    // if ty is `dyn Trait`, the trait doesn't need to be in scope
+    let inherent_trait =
+        self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
+    let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
+        // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
+        .then(|| {
+            env.traits_in_scope_from_clauses(self_ty.clone())
+                .flat_map(|t| all_super_traits(db.upcast(), t))
+        })
+        .into_iter()
+        .flatten();
+    let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
 
     let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
 
-    'traits: for &t in traits_in_scope {
+    'traits: for t in traits {
         let data = db.trait_data(t);
 
         // Traits annotated with `#[rustc_skip_array_during_method_dispatch]` are skipped during
@@ -967,43 +979,6 @@ fn iterate_inherent_methods(
 ) -> ControlFlow<()> {
     let db = table.db;
     let env = table.trait_env.clone();
-
-    // For trait object types and placeholder types with trait bounds, the methods of the trait and
-    // its super traits are considered inherent methods. This matters because these methods have
-    // higher priority than the other traits' methods, which would be considered in
-    // `iterate_trait_method_candidates()` only after this function.
-    match self_ty.kind(Interner) {
-        TyKind::Placeholder(_) => {
-            let env = table.trait_env.clone();
-            let traits = env
-                .traits_in_scope_from_clauses(self_ty.clone())
-                .flat_map(|t| all_super_traits(db.upcast(), t));
-            iterate_inherent_trait_methods(
-                self_ty,
-                table,
-                name,
-                receiver_ty,
-                receiver_adjustments.clone(),
-                callback,
-                traits,
-            )?;
-        }
-        TyKind::Dyn(_) => {
-            let principal_trait = self_ty.dyn_trait().unwrap();
-            let traits = all_super_traits(db.upcast(), principal_trait);
-            iterate_inherent_trait_methods(
-                self_ty,
-                table,
-                name,
-                receiver_ty,
-                receiver_adjustments.clone(),
-                callback,
-                traits.into_iter(),
-            )?;
-        }
-        _ => {}
-    }
-
     let def_crates = match def_crates(db, self_ty, env.krate) {
         Some(k) => k,
         None => return ControlFlow::Continue(()),
@@ -1045,28 +1020,6 @@ fn iterate_inherent_methods(
     }
     return ControlFlow::Continue(());
 
-    fn iterate_inherent_trait_methods(
-        self_ty: &Ty,
-        table: &mut InferenceTable<'_>,
-        name: Option<&Name>,
-        receiver_ty: Option<&Ty>,
-        receiver_adjustments: Option<ReceiverAdjustments>,
-        callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
-        traits: impl Iterator<Item = TraitId>,
-    ) -> ControlFlow<()> {
-        let db = table.db;
-        for t in traits {
-            let data = db.trait_data(t);
-            for &(_, item) in data.items.iter() {
-                // We don't pass `visible_from_module` as all trait items should be visible.
-                if is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
-                    callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
-                }
-            }
-        }
-        ControlFlow::Continue(())
-    }
-
     fn impls_for_self_ty(
         impls: &InherentImpls,
         self_ty: &Ty,
diff --git a/crates/hir-ty/src/traits.rs b/crates/hir-ty/src/traits.rs
index aaff894b34..77afeb3217 100644
--- a/crates/hir-ty/src/traits.rs
+++ b/crates/hir-ty/src/traits.rs
@@ -1,6 +1,6 @@
 //! Trait solving using Chalk.
 
-use std::{env::var, sync::Arc};
+use std::env::var;
 
 use chalk_ir::GoalData;
 use chalk_recursive::Cache;
@@ -12,9 +12,8 @@ use stdx::panic_context;
 use syntax::SmolStr;
 
 use crate::{
-    db::HirDatabase, infer::unify::InferenceTable, AliasEq, AliasTy, Canonical, DomainGoal, Goal,
-    Guidance, InEnvironment, Interner, ProjectionTy, Solution, TraitRefExt, Ty, TyKind,
-    WhereClause,
+    db::HirDatabase, AliasEq, AliasTy, Canonical, DomainGoal, Goal, Guidance, InEnvironment,
+    Interner, Solution, TraitRefExt, Ty, TyKind, WhereClause,
 };
 
 /// This controls how much 'time' we give the Chalk solver before giving up.
@@ -65,16 +64,6 @@ impl TraitEnvironment {
     }
 }
 
-pub(crate) fn normalize_projection_query(
-    db: &dyn HirDatabase,
-    projection: ProjectionTy,
-    env: Arc<TraitEnvironment>,
-) -> Option<Ty> {
-    let mut table = InferenceTable::new(db, env.clone());
-    let ty = table.normalize_projection_ty(projection);
-    Some(table.resolve_completely(ty))
-}
-
 /// Solve a trait goal using Chalk.
 pub(crate) fn trait_solve_query(
     db: &dyn HirDatabase,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 7dd891c86e..e4bb63a864 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -63,9 +63,10 @@ use hir_ty::{
     primitive::UintTy,
     subst_prefix,
     traits::FnTrait,
-    AliasTy, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast, ClosureId,
-    GenericArgData, Interner, ParamKind, QuantifiedWhereClause, Scalar, Substitution,
-    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, WhereClause,
+    AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
+    ClosureId, DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind,
+    QuantifiedWhereClause, Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty,
+    TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind, WhereClause,
 };
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
@@ -581,13 +582,8 @@ 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>,
-        prefer_core: bool,
-    ) -> Option<ModPath> {
-        hir_def::find_path::find_path(db, item.into().into(), self.into(), prefer_core)
+    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())
     }
 
     /// Finds a path that can be used to refer to the given item from within
@@ -597,15 +593,8 @@ 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,
-            prefer_core,
-        )
+        hir_def::find_path::find_path_prefixed(db, item.into().into(), self.into(), prefix_kind)
     }
 }
 
@@ -2891,8 +2880,28 @@ impl Type {
                 }
             })
             .build();
+        let goal = hir_ty::make_canonical(
+            InEnvironment::new(
+                &self.env.env,
+                AliasEq {
+                    alias: AliasTy::Projection(projection),
+                    ty: TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, 0))
+                        .intern(Interner),
+                }
+                .cast(Interner),
+            ),
+            [TyVariableKind::General].into_iter(),
+        );
 
-        db.normalize_projection(projection, self.env.clone()).map(|ty| self.derived(ty))
+        match db.trait_solve(self.env.krate, goal)? {
+            Solution::Unique(s) => s
+                .value
+                .subst
+                .as_slice(Interner)
+                .first()
+                .map(|ty| self.derived(ty.assert_ty_ref(Interner).clone())),
+            Solution::Ambig(_) => None,
+        }
     }
 
     pub fn is_copy(&self, db: &dyn HirDatabase) -> bool {
diff --git a/crates/ide-assists/src/assist_config.rs b/crates/ide-assists/src/assist_config.rs
index fe2dfca6d5..d4d148c774 100644
--- a/crates/ide-assists/src/assist_config.rs
+++ b/crates/ide-assists/src/assist_config.rs
@@ -13,5 +13,4 @@ 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 d4e21b778c..1a7919a5a1 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, ctx.config.prefer_core)?,
+                    build_pat(ctx.db(), module, variant)?,
                     variant.should_be_hidden(ctx.db(), module.krate()),
                 ))
             })
@@ -132,9 +132,8 @@ 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, ctx.config.prefer_core)
-                });
+                let patterns =
+                    variants.into_iter().filter_map(|variant| build_pat(ctx.db(), module, variant));
 
                 (ast::Pat::from(make::tuple_pat(patterns)), is_hidden)
             })
@@ -350,16 +349,10 @@ fn resolve_tuple_of_enum_def(
         .collect()
 }
 
-fn build_pat(
-    db: &RootDatabase,
-    module: hir::Module,
-    var: ExtendedVariant,
-    prefer_core: bool,
-) -> Option<ast::Pat> {
+fn build_pat(db: &RootDatabase, module: hir::Module, var: ExtendedVariant) -> Option<ast::Pat> {
     match var {
         ExtendedVariant::Variant(var) => {
-            let path =
-                mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var), prefer_core)?);
+            let path = mod_path_to_ast(&module.find_use_path(db, ModuleDef::from(var))?);
 
             // 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 88a6b8558c..949cf3167a 100644
--- a/crates/ide-assists/src/handlers/auto_import.rs
+++ b/crates/ide-assists/src/handlers/auto_import.rs
@@ -89,11 +89,8 @@ 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,
-        ctx.config.prefer_core,
-    );
+    let mut proposed_imports =
+        import_assets.search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind);
     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 e0c0e9a484..30f6dd41a1 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, ctx.config.prefer_core)?)
+        mod_path_to_ast(&module.find_use_path(ctx.db(), src_type_def)?)
     };
 
     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 749d94d5a9..52a55ead3a 100644
--- a/crates/ide-assists/src/handlers/extract_function.rs
+++ b/crates/ide-assists/src/handlers/extract_function.rs
@@ -152,7 +152,6 @@ 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 431f7b3c0f..ddc2052e7a 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,7 +409,6 @@ 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 cf4ed84281..b484635121 100644
--- a/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/crates/ide-assists/src/handlers/generate_deref.rs
@@ -58,8 +58,7 @@ 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_), ctx.config.prefer_core)?;
+    let trait_path = module.find_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
 
     let field_type = field.ty()?;
     let field_name = field.name()?;
@@ -99,8 +98,7 @@ 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_), ctx.config.prefer_core)?;
+    let trait_path = module.find_use_path(ctx.db(), ModuleDef::Trait(trait_))?;
 
     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 ceb7dac0fe..6c93875e9e 100644
--- a/crates/ide-assists/src/handlers/generate_new.rs
+++ b/crates/ide-assists/src/handlers/generate_new.rs
@@ -60,11 +60,8 @@ 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)?,
-                    ctx.config.prefer_core,
-                )?;
+                let type_path = current_module
+                    .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
 
                 let expr = use_trivial_constructor(
                     &ctx.sema.db,
diff --git a/crates/ide-assists/src/handlers/move_format_string_arg.rs b/crates/ide-assists/src/handlers/move_format_string_arg.rs
deleted file mode 100644
index 92b2fa79d7..0000000000
--- a/crates/ide-assists/src/handlers/move_format_string_arg.rs
+++ /dev/null
@@ -1,268 +0,0 @@
-use crate::{AssistContext, Assists};
-use ide_db::{
-    assists::{AssistId, AssistKind},
-    syntax_helpers::{
-        format_string::is_format_string,
-        format_string_exprs::{parse_format_exprs, Arg},
-    },
-};
-use itertools::Itertools;
-use syntax::{ast, AstNode, AstToken, NodeOrToken, SyntaxKind::COMMA, TextRange};
-
-// Assist: move_format_string_arg
-//
-// Move an expression out of a format string.
-//
-// ```
-// macro_rules! format_args {
-//     ($lit:literal $(tt:tt)*) => { 0 },
-// }
-// macro_rules! print {
-//     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-// }
-//
-// fn main() {
-//     print!("{x + 1}$0");
-// }
-// ```
-// ->
-// ```
-// macro_rules! format_args {
-//     ($lit:literal $(tt:tt)*) => { 0 },
-// }
-// macro_rules! print {
-//     ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-// }
-//
-// fn main() {
-//     print!("{}"$0, x + 1);
-// }
-// ```
-
-pub(crate) fn move_format_string_arg(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
-    let fmt_string = ctx.find_token_at_offset::<ast::String>()?;
-    let tt = fmt_string.syntax().parent().and_then(ast::TokenTree::cast)?;
-
-    let expanded_t = ast::String::cast(
-        ctx.sema.descend_into_macros_with_kind_preference(fmt_string.syntax().clone()),
-    )?;
-    if !is_format_string(&expanded_t) {
-        return None;
-    }
-
-    let (new_fmt, extracted_args) = parse_format_exprs(fmt_string.text()).ok()?;
-    if extracted_args.is_empty() {
-        return None;
-    }
-
-    acc.add(
-        AssistId(
-            "move_format_string_arg",
-            // if there aren't any expressions, then make the assist a RefactorExtract
-            if extracted_args.iter().filter(|f| matches!(f, Arg::Expr(_))).count() == 0 {
-                AssistKind::RefactorExtract
-            } else {
-                AssistKind::QuickFix
-            },
-        ),
-        "Extract format args",
-        tt.syntax().text_range(),
-        |edit| {
-            let fmt_range = fmt_string.syntax().text_range();
-
-            // Replace old format string with new format string whose arguments have been extracted
-            edit.replace(fmt_range, new_fmt);
-
-            // Insert cursor at end of format string
-            edit.insert(fmt_range.end(), "$0");
-
-            // Extract existing arguments in macro
-            let tokens =
-                tt.token_trees_and_tokens().filter_map(NodeOrToken::into_token).collect_vec();
-
-            let mut existing_args: Vec<String> = vec![];
-
-            let mut current_arg = String::new();
-            if let [_opening_bracket, format_string, _args_start_comma, tokens @ .., end_bracket] =
-                tokens.as_slice()
-            {
-                for t in tokens {
-                    if t.kind() == COMMA {
-                        existing_args.push(current_arg.trim().into());
-                        current_arg.clear();
-                    } else {
-                        current_arg.push_str(t.text());
-                    }
-                }
-                existing_args.push(current_arg.trim().into());
-
-                // delete everything after the format string till end bracket
-                // we're going to insert the new arguments later
-                edit.delete(TextRange::new(
-                    format_string.text_range().end(),
-                    end_bracket.text_range().start(),
-                ));
-            }
-
-            // Start building the new args
-            let mut existing_args = existing_args.into_iter();
-            let mut args = String::new();
-
-            let mut placeholder_idx = 1;
-
-            for extracted_args in extracted_args {
-                // remove expr from format string
-                args.push_str(", ");
-
-                match extracted_args {
-                    Arg::Ident(s) | Arg::Expr(s) => {
-                        // insert arg
-                        args.push_str(&s);
-                    }
-                    Arg::Placeholder => {
-                        // try matching with existing argument
-                        match existing_args.next() {
-                            Some(ea) => {
-                                args.push_str(&ea);
-                            }
-                            None => {
-                                // insert placeholder
-                                args.push_str(&format!("${placeholder_idx}"));
-                                placeholder_idx += 1;
-                            }
-                        }
-                    }
-                }
-            }
-
-            // Insert new args
-            edit.insert(fmt_range.end(), args);
-        },
-    );
-
-    Some(())
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::tests::check_assist;
-
-    const MACRO_DECL: &'static str = r#"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
-macro_rules! print {
-    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-}
-"#;
-
-    fn add_macro_decl(s: &'static str) -> String {
-        MACRO_DECL.to_string() + s
-    }
-
-    #[test]
-    fn multiple_middle_arg() {
-        check_assist(
-            move_format_string_arg,
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {x + 1:b} {}$0", y + 2, 2);
-}
-"#,
-            ),
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {:b} {}"$0, y + 2, x + 1, 2);
-}
-"#,
-            ),
-        );
-    }
-
-    #[test]
-    fn single_arg() {
-        check_assist(
-            move_format_string_arg,
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{obj.value:b}$0",);
-}
-"#,
-            ),
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{:b}"$0, obj.value);
-}
-"#,
-            ),
-        );
-    }
-
-    #[test]
-    fn multiple_middle_placeholders_arg() {
-        check_assist(
-            move_format_string_arg,
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {x + 1:b} {} {}$0", y + 2, 2);
-}
-"#,
-            ),
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {:b} {} {}"$0, y + 2, x + 1, 2, $1);
-}
-"#,
-            ),
-        );
-    }
-
-    #[test]
-    fn multiple_trailing_args() {
-        check_assist(
-            move_format_string_arg,
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {x + 1:b} {Struct(1, 2)}$0", 1);
-}
-"#,
-            ),
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
-}
-"#,
-            ),
-        );
-    }
-
-    #[test]
-    fn improper_commas() {
-        check_assist(
-            move_format_string_arg,
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {x + 1:b} {Struct(1, 2)}$0", 1,);
-}
-"#,
-            ),
-            &add_macro_decl(
-                r#"
-fn main() {
-    print!("{} {:b} {}"$0, 1, x + 1, Struct(1, 2));
-}
-"#,
-            ),
-        );
-    }
-}
diff --git a/crates/ide-assists/src/handlers/qualify_method_call.rs b/crates/ide-assists/src/handlers/qualify_method_call.rs
index cb81ebd228..121f8b4a13 100644
--- a/crates/ide-assists/src/handlers/qualify_method_call.rs
+++ b/crates/ide-assists/src/handlers/qualify_method_call.rs
@@ -44,11 +44,8 @@ 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)?,
-        ctx.config.prefer_core,
-    )?;
+    let receiver_path = current_module
+        .find_use_path(ctx.sema.db, item_for_path_search(ctx.sema.db, item_in_ns)?)?;
 
     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 232cd39e8b..0c2e9da386 100644
--- a/crates/ide-assists/src/handlers/qualify_path.rs
+++ b/crates/ide-assists/src/handlers/qualify_path.rs
@@ -37,8 +37,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 mut proposed_imports =
-        import_assets.search_for_relative_paths(&ctx.sema, ctx.config.prefer_core);
+    let mut proposed_imports = import_assets.search_for_relative_paths(&ctx.sema);
     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 04a1366327..d139f78a6f 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_), ctx.config.prefer_core)
+            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
             .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 533e1670a0..2419fa11c1 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,7 +67,6 @@ 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-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index 812d22efbd..e52544db5f 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -136,7 +136,6 @@ mod handlers {
     mod flip_binexpr;
     mod flip_comma;
     mod flip_trait_bound;
-    mod move_format_string_arg;
     mod generate_constant;
     mod generate_default_from_enum_variant;
     mod generate_default_from_new;
@@ -255,7 +254,6 @@ mod handlers {
             merge_imports::merge_imports,
             merge_match_arms::merge_match_arms,
             move_bounds::move_bounds_to_where_clause,
-            move_format_string_arg::move_format_string_arg,
             move_guard::move_arm_cond_to_match_guard,
             move_guard::move_guard_to_arm_body,
             move_module_to_file::move_module_to_file,
diff --git a/crates/ide-completion/src/completions.rs b/crates/ide-completion/src/completions.rs
index 89a971e544..55c3e28392 100644
--- a/crates/ide-completion/src/completions.rs
+++ b/crates/ide-completion/src/completions.rs
@@ -551,9 +551,7 @@ fn enum_variants_with_paths(
     }
 
     for variant in variants {
-        if let Some(path) =
-            ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant), ctx.config.prefer_core)
-        {
+        if let Some(path) = ctx.module.find_use_path(ctx.db, hir::ModuleDef::from(variant)) {
             // 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 1ccf33a96b..588b52cc1e 100644
--- a/crates/ide-completion/src/completions/expr.rs
+++ b/crates/ide-completion/src/completions/expr.rs
@@ -165,11 +165,7 @@ pub(crate) fn complete_expr_path(
                     hir::Adt::Struct(strukt) => {
                         let path = ctx
                             .module
-                            .find_use_path(
-                                ctx.db,
-                                hir::ModuleDef::from(strukt),
-                                ctx.config.prefer_core,
-                            )
+                            .find_use_path(ctx.db, hir::ModuleDef::from(strukt))
                             .filter(|it| it.len() > 1);
 
                         acc.add_struct_literal(ctx, path_ctx, strukt, path, None);
@@ -187,7 +183,7 @@ pub(crate) fn complete_expr_path(
                     hir::Adt::Union(un) => {
                         let path = ctx
                             .module
-                            .find_use_path(ctx.db, hir::ModuleDef::from(un), ctx.config.prefer_core)
+                            .find_use_path(ctx.db, hir::ModuleDef::from(un))
                             .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 528959943b..f04cc15d7f 100644
--- a/crates/ide-completion/src/completions/flyimport.rs
+++ b/crates/ide-completion/src/completions/flyimport.rs
@@ -262,11 +262,7 @@ fn import_on_the_fly(
 
     acc.add_all(
         import_assets
-            .search_for_imports(
-                &ctx.sema,
-                ctx.config.insert_use.prefix_kind,
-                ctx.config.prefer_core,
-            )
+            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
             .into_iter()
             .filter(ns_filter)
             .filter(|import| {
@@ -310,11 +306,7 @@ fn import_on_the_fly_pat_(
 
     acc.add_all(
         import_assets
-            .search_for_imports(
-                &ctx.sema,
-                ctx.config.insert_use.prefix_kind,
-                ctx.config.prefer_core,
-            )
+            .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
             .into_iter()
             .filter(ns_filter)
             .filter(|import| {
@@ -352,7 +344,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, ctx.config.prefer_core)
+        .search_for_imports(&ctx.sema, ctx.config.insert_use.prefix_kind)
         .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/completions/postfix/format_like.rs b/crates/ide-completion/src/completions/postfix/format_like.rs
index b43bdb9ab9..b273a4cb53 100644
--- a/crates/ide-completion/src/completions/postfix/format_like.rs
+++ b/crates/ide-completion/src/completions/postfix/format_like.rs
@@ -16,11 +16,8 @@
 //
 // image::https://user-images.githubusercontent.com/48062697/113020656-b560f500-917a-11eb-87de-02991f61beb8.gif[]
 
-use ide_db::{
-    syntax_helpers::format_string_exprs::{parse_format_exprs, with_placeholders},
-    SnippetCap,
-};
-use syntax::{ast, AstToken};
+use ide_db::SnippetCap;
+use syntax::ast::{self, AstToken};
 
 use crate::{
     completions::postfix::build_postfix_snippet_builder, context::CompletionContext, Completions,
@@ -46,24 +43,250 @@ pub(crate) fn add_format_like_completions(
     cap: SnippetCap,
     receiver_text: &ast::String,
 ) {
+    let input = match string_literal_contents(receiver_text) {
+        // It's not a string literal, do not parse input.
+        Some(input) => input,
+        None => return,
+    };
+
     let postfix_snippet = match build_postfix_snippet_builder(ctx, cap, dot_receiver) {
         Some(it) => it,
         None => return,
     };
+    let mut parser = FormatStrParser::new(input);
 
-    if let Ok((out, exprs)) = parse_format_exprs(receiver_text.text()) {
-        let exprs = with_placeholders(exprs);
+    if parser.parse().is_ok() {
         for (label, macro_name) in KINDS {
-            let snippet = format!(r#"{}({}, {})"#, macro_name, out, exprs.join(", "));
+            let snippet = parser.to_suggestion(macro_name);
 
             postfix_snippet(label, macro_name, &snippet).add_to(acc);
         }
     }
 }
 
+/// Checks whether provided item is a string literal.
+fn string_literal_contents(item: &ast::String) -> Option<String> {
+    let item = item.text();
+    if item.len() >= 2 && item.starts_with('\"') && item.ends_with('\"') {
+        return Some(item[1..item.len() - 1].to_owned());
+    }
+
+    None
+}
+
+/// Parser for a format-like string. It is more allowing in terms of string contents,
+/// as we expect variable placeholders to be filled with expressions.
+#[derive(Debug)]
+pub(crate) struct FormatStrParser {
+    input: String,
+    output: String,
+    extracted_expressions: Vec<String>,
+    state: State,
+    parsed: bool,
+}
+
+#[derive(Debug, Clone, Copy, PartialEq)]
+enum State {
+    NotExpr,
+    MaybeExpr,
+    Expr,
+    MaybeIncorrect,
+    FormatOpts,
+}
+
+impl FormatStrParser {
+    pub(crate) fn new(input: String) -> Self {
+        Self {
+            input,
+            output: String::new(),
+            extracted_expressions: Vec::new(),
+            state: State::NotExpr,
+            parsed: false,
+        }
+    }
+
+    pub(crate) fn parse(&mut self) -> Result<(), ()> {
+        let mut current_expr = String::new();
+
+        let mut placeholder_id = 1;
+
+        // Count of open braces inside of an expression.
+        // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
+        // "{MyStruct { val_a: 0, val_b: 1 }}".
+        let mut inexpr_open_count = 0;
+
+        // We need to escape '\' and '$'. See the comments on `get_receiver_text()` for detail.
+        let mut chars = self.input.chars().peekable();
+        while let Some(chr) = chars.next() {
+            match (self.state, chr) {
+                (State::NotExpr, '{') => {
+                    self.output.push(chr);
+                    self.state = State::MaybeExpr;
+                }
+                (State::NotExpr, '}') => {
+                    self.output.push(chr);
+                    self.state = State::MaybeIncorrect;
+                }
+                (State::NotExpr, _) => {
+                    if matches!(chr, '\\' | '$') {
+                        self.output.push('\\');
+                    }
+                    self.output.push(chr);
+                }
+                (State::MaybeIncorrect, '}') => {
+                    // It's okay, we met "}}".
+                    self.output.push(chr);
+                    self.state = State::NotExpr;
+                }
+                (State::MaybeIncorrect, _) => {
+                    // Error in the string.
+                    return Err(());
+                }
+                (State::MaybeExpr, '{') => {
+                    self.output.push(chr);
+                    self.state = State::NotExpr;
+                }
+                (State::MaybeExpr, '}') => {
+                    // This is an empty sequence '{}'. Replace it with placeholder.
+                    self.output.push(chr);
+                    self.extracted_expressions.push(format!("${}", placeholder_id));
+                    placeholder_id += 1;
+                    self.state = State::NotExpr;
+                }
+                (State::MaybeExpr, _) => {
+                    if matches!(chr, '\\' | '$') {
+                        current_expr.push('\\');
+                    }
+                    current_expr.push(chr);
+                    self.state = State::Expr;
+                }
+                (State::Expr, '}') => {
+                    if inexpr_open_count == 0 {
+                        self.output.push(chr);
+                        self.extracted_expressions.push(current_expr.trim().into());
+                        current_expr = String::new();
+                        self.state = State::NotExpr;
+                    } else {
+                        // We're closing one brace met before inside of the expression.
+                        current_expr.push(chr);
+                        inexpr_open_count -= 1;
+                    }
+                }
+                (State::Expr, ':') if chars.peek().copied() == Some(':') => {
+                    // path separator
+                    current_expr.push_str("::");
+                    chars.next();
+                }
+                (State::Expr, ':') => {
+                    if inexpr_open_count == 0 {
+                        // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
+                        self.output.push(chr);
+                        self.extracted_expressions.push(current_expr.trim().into());
+                        current_expr = String::new();
+                        self.state = State::FormatOpts;
+                    } else {
+                        // We're inside of braced expression, assume that it's a struct field name/value delimiter.
+                        current_expr.push(chr);
+                    }
+                }
+                (State::Expr, '{') => {
+                    current_expr.push(chr);
+                    inexpr_open_count += 1;
+                }
+                (State::Expr, _) => {
+                    if matches!(chr, '\\' | '$') {
+                        current_expr.push('\\');
+                    }
+                    current_expr.push(chr);
+                }
+                (State::FormatOpts, '}') => {
+                    self.output.push(chr);
+                    self.state = State::NotExpr;
+                }
+                (State::FormatOpts, _) => {
+                    if matches!(chr, '\\' | '$') {
+                        self.output.push('\\');
+                    }
+                    self.output.push(chr);
+                }
+            }
+        }
+
+        if self.state != State::NotExpr {
+            return Err(());
+        }
+
+        self.parsed = true;
+        Ok(())
+    }
+
+    pub(crate) fn to_suggestion(&self, macro_name: &str) -> String {
+        assert!(self.parsed, "Attempt to get a suggestion from not parsed expression");
+
+        let expressions_as_string = self.extracted_expressions.join(", ");
+        format!(r#"{}("{}", {})"#, macro_name, self.output, expressions_as_string)
+    }
+}
+
 #[cfg(test)]
 mod tests {
     use super::*;
+    use expect_test::{expect, Expect};
+
+    fn check(input: &str, expect: &Expect) {
+        let mut parser = FormatStrParser::new((*input).to_owned());
+        let outcome_repr = if parser.parse().is_ok() {
+            // Parsing should be OK, expected repr is "string; expr_1, expr_2".
+            if parser.extracted_expressions.is_empty() {
+                parser.output
+            } else {
+                format!("{}; {}", parser.output, parser.extracted_expressions.join(", "))
+            }
+        } else {
+            // Parsing should fail, expected repr is "-".
+            "-".to_owned()
+        };
+
+        expect.assert_eq(&outcome_repr);
+    }
+
+    #[test]
+    fn format_str_parser() {
+        let test_vector = &[
+            ("no expressions", expect![["no expressions"]]),
+            (r"no expressions with \$0$1", expect![r"no expressions with \\\$0\$1"]),
+            ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
+            ("{expr:?}", expect![["{:?}; expr"]]),
+            ("{expr:1$}", expect![[r"{:1\$}; expr"]]),
+            ("{$0}", expect![[r"{}; \$0"]]),
+            ("{malformed", expect![["-"]]),
+            ("malformed}", expect![["-"]]),
+            ("{{correct", expect![["{{correct"]]),
+            ("correct}}", expect![["correct}}"]]),
+            ("{correct}}}", expect![["{}}}; correct"]]),
+            ("{correct}}}}}", expect![["{}}}}}; correct"]]),
+            ("{incorrect}}", expect![["-"]]),
+            ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]),
+            ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]),
+            (
+                "{SomeStruct { val_a: 0, val_b: 1 }}",
+                expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]],
+            ),
+            ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]),
+            (
+                "{SomeStruct { val_a: 0, val_b: 1 }:?}",
+                expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
+            ),
+            ("{     2 + 2        }", expect![["{}; 2 + 2"]]),
+            ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
+            ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
+            ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
+        ];
+
+        for (input, output) in test_vector {
+            check(input, output)
+        }
+    }
 
     #[test]
     fn test_into_suggestion() {
@@ -79,10 +302,10 @@ mod tests {
         ];
 
         for (kind, input, output) in test_vector {
-            let (parsed_string, exprs) = parse_format_exprs(input).unwrap();
-            let exprs = with_placeholders(exprs);
-            let snippet = format!(r#"{}("{}", {})"#, kind, parsed_string, exprs.join(", "));
-            assert_eq!(&snippet, output);
+            let mut parser = FormatStrParser::new((*input).to_owned());
+            parser.parse().expect("Parsing must succeed");
+
+            assert_eq!(&parser.to_suggestion(*kind), output);
         }
     }
 }
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index 54ebce1eb7..80d6af2816 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -17,7 +17,6 @@ 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 7cefb6bb4a..ae1a440d06 100644
--- a/crates/ide-completion/src/lib.rs
+++ b/crates/ide-completion/src/lib.rs
@@ -234,12 +234,7 @@ 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,
-                    config.prefer_core,
-                )
+                current_module.find_use_path_prefixed(db, candidate, config.insert_use.prefix_kind)
             })
             .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 2dc62bbdc6..dc1039fa62 100644
--- a/crates/ide-completion/src/snippet.rs
+++ b/crates/ide-completion/src/snippet.rs
@@ -174,12 +174,8 @@ 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,
-            ctx.config.prefer_core,
-        )?;
+        let path =
+            ctx.module.find_use_path_prefixed(ctx.db, item, ctx.config.insert_use.prefix_kind)?;
         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 53bc516109..26ef86155e 100644
--- a/crates/ide-db/src/imports/import_assets.rs
+++ b/crates/ide-db/src/imports/import_assets.rs
@@ -212,20 +212,18 @@ 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), prefer_core)
+        self.search_for(sema, Some(prefix_kind))
     }
 
     /// 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, prefer_core)
+        self.search_for(sema, None)
     }
 
     pub fn path_fuzzy_name_to_exact(&mut self, case_sensitive: bool) {
@@ -244,7 +242,6 @@ impl ImportAssets {
         &self,
         sema: &Semantics<'_, RootDatabase>,
         prefixed: Option<PrefixKind>,
-        prefer_core: bool,
     ) -> Vec<LocatedImport> {
         let _p = profile::span("import_assets::search_for");
 
@@ -255,7 +252,6 @@ impl ImportAssets {
                 item_for_path_search(sema.db, item)?,
                 &self.module_with_candidate,
                 prefixed,
-                prefer_core,
             )
         };
 
@@ -568,12 +564,11 @@ 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, prefer_core)
+        module_with_candidate.find_use_path_prefixed(db, item_to_search, prefix_kind)
     } else {
-        module_with_candidate.find_use_path(db, item_to_search, prefer_core)
+        module_with_candidate.find_use_path(db, item_to_search)
     }
 }
 
diff --git a/crates/ide-db/src/lib.rs b/crates/ide-db/src/lib.rs
index e0bc0f89f0..1ec62a8425 100644
--- a/crates/ide-db/src/lib.rs
+++ b/crates/ide-db/src/lib.rs
@@ -38,7 +38,6 @@ pub mod syntax_helpers {
     pub mod node_ext;
     pub mod insert_whitespace_into_node;
     pub mod format_string;
-    pub mod format_string_exprs;
 
     pub use parser::LexedStr;
 }
diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs
index 12d873b4a0..40af9e6fe2 100644
--- a/crates/ide-db/src/path_transform.rs
+++ b/crates/ide-db/src/path_transform.rs
@@ -173,7 +173,6 @@ 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),
@@ -210,7 +209,7 @@ impl<'a> Ctx<'a> {
                 }
 
                 let found_path =
-                    self.target_module.find_use_path(self.source_scope.db.upcast(), def, false)?;
+                    self.target_module.find_use_path(self.source_scope.db.upcast(), def)?;
                 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-db/src/syntax_helpers/format_string_exprs.rs b/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
deleted file mode 100644
index ac6c6e8fee..0000000000
--- a/crates/ide-db/src/syntax_helpers/format_string_exprs.rs
+++ /dev/null
@@ -1,267 +0,0 @@
-//! Tools to work with expressions present in format string literals for the `format_args!` family of macros.
-//! Primarily meant for assists and completions.
-
-/// Enum for represenging extraced format string args.
-/// Can either be extracted expressions (which includes identifiers),
-/// or placeholders `{}`.
-#[derive(Debug, PartialEq, Eq)]
-pub enum Arg {
-    Placeholder,
-    Ident(String),
-    Expr(String),
-}
-
-/**
- Add placeholders like `$1` and `$2` in place of [`Arg::Placeholder`],
- and unwraps the [`Arg::Ident`] and [`Arg::Expr`] enums.
- ```rust
- # use ide_db::syntax_helpers::format_string_exprs::*;
- assert_eq!(with_placeholders(vec![Arg::Ident("ident".to_owned()), Arg::Placeholder, Arg::Expr("expr + 2".to_owned())]), vec!["ident".to_owned(), "$1".to_owned(), "expr + 2".to_owned()])
- ```
-*/
-
-pub fn with_placeholders(args: Vec<Arg>) -> Vec<String> {
-    let mut placeholder_id = 1;
-    args.into_iter()
-        .map(move |a| match a {
-            Arg::Expr(s) | Arg::Ident(s) => s,
-            Arg::Placeholder => {
-                let s = format!("${placeholder_id}");
-                placeholder_id += 1;
-                s
-            }
-        })
-        .collect()
-}
-
-/**
- Parser for a format-like string. It is more allowing in terms of string contents,
- as we expect variable placeholders to be filled with expressions.
-
- Built for completions and assists, and escapes `\` and `$` in output.
- (See the comments on `get_receiver_text()` for detail.)
- Splits a format string that may contain expressions
- like
- ```rust
- assert_eq!(parse("{ident} {} {expr + 42} ").unwrap(), ("{} {} {}", vec![Arg::Ident("ident"), Arg::Placeholder, Arg::Expr("expr + 42")]));
- ```
-*/
-pub fn parse_format_exprs(input: &str) -> Result<(String, Vec<Arg>), ()> {
-    #[derive(Debug, Clone, Copy, PartialEq)]
-    enum State {
-        NotArg,
-        MaybeArg,
-        Expr,
-        Ident,
-        MaybeIncorrect,
-        FormatOpts,
-    }
-
-    let mut state = State::NotArg;
-    let mut current_expr = String::new();
-    let mut extracted_expressions = Vec::new();
-    let mut output = String::new();
-
-    // Count of open braces inside of an expression.
-    // We assume that user knows what they're doing, thus we treat it like a correct pattern, e.g.
-    // "{MyStruct { val_a: 0, val_b: 1 }}".
-    let mut inexpr_open_count = 0;
-
-    let mut chars = input.chars().peekable();
-    while let Some(chr) = chars.next() {
-        match (state, chr) {
-            (State::NotArg, '{') => {
-                output.push(chr);
-                state = State::MaybeArg;
-            }
-            (State::NotArg, '}') => {
-                output.push(chr);
-                state = State::MaybeIncorrect;
-            }
-            (State::NotArg, _) => {
-                if matches!(chr, '\\' | '$') {
-                    output.push('\\');
-                }
-                output.push(chr);
-            }
-            (State::MaybeIncorrect, '}') => {
-                // It's okay, we met "}}".
-                output.push(chr);
-                state = State::NotArg;
-            }
-            (State::MaybeIncorrect, _) => {
-                // Error in the string.
-                return Err(());
-            }
-            // Escaped braces `{{`
-            (State::MaybeArg, '{') => {
-                output.push(chr);
-                state = State::NotArg;
-            }
-            (State::MaybeArg, '}') => {
-                // This is an empty sequence '{}'.
-                output.push(chr);
-                extracted_expressions.push(Arg::Placeholder);
-                state = State::NotArg;
-            }
-            (State::MaybeArg, _) => {
-                if matches!(chr, '\\' | '$') {
-                    current_expr.push('\\');
-                }
-                current_expr.push(chr);
-
-                // While Rust uses the unicode sets of XID_start and XID_continue for Identifiers
-                // this is probably the best we can do to avoid a false positive
-                if chr.is_alphabetic() || chr == '_' {
-                    state = State::Ident;
-                } else {
-                    state = State::Expr;
-                }
-            }
-            (State::Ident | State::Expr, '}') => {
-                if inexpr_open_count == 0 {
-                    output.push(chr);
-
-                    if matches!(state, State::Expr) {
-                        extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
-                    } else {
-                        extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
-                    }
-
-                    current_expr = String::new();
-                    state = State::NotArg;
-                } else {
-                    // We're closing one brace met before inside of the expression.
-                    current_expr.push(chr);
-                    inexpr_open_count -= 1;
-                }
-            }
-            (State::Ident | State::Expr, ':') if matches!(chars.peek(), Some(':')) => {
-                // path separator
-                state = State::Expr;
-                current_expr.push_str("::");
-                chars.next();
-            }
-            (State::Ident | State::Expr, ':') => {
-                if inexpr_open_count == 0 {
-                    // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
-                    output.push(chr);
-
-                    if matches!(state, State::Expr) {
-                        extracted_expressions.push(Arg::Expr(current_expr.trim().into()));
-                    } else {
-                        extracted_expressions.push(Arg::Ident(current_expr.trim().into()));
-                    }
-
-                    current_expr = String::new();
-                    state = State::FormatOpts;
-                } else {
-                    // We're inside of braced expression, assume that it's a struct field name/value delimiter.
-                    current_expr.push(chr);
-                }
-            }
-            (State::Ident | State::Expr, '{') => {
-                state = State::Expr;
-                current_expr.push(chr);
-                inexpr_open_count += 1;
-            }
-            (State::Ident | State::Expr, _) => {
-                if !(chr.is_alphanumeric() || chr == '_' || chr == '#') {
-                    state = State::Expr;
-                }
-
-                if matches!(chr, '\\' | '$') {
-                    current_expr.push('\\');
-                }
-                current_expr.push(chr);
-            }
-            (State::FormatOpts, '}') => {
-                output.push(chr);
-                state = State::NotArg;
-            }
-            (State::FormatOpts, _) => {
-                if matches!(chr, '\\' | '$') {
-                    output.push('\\');
-                }
-                output.push(chr);
-            }
-        }
-    }
-
-    if state != State::NotArg {
-        return Err(());
-    }
-
-    Ok((output, extracted_expressions))
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use expect_test::{expect, Expect};
-
-    fn check(input: &str, expect: &Expect) {
-        let (output, exprs) = parse_format_exprs(input).unwrap_or(("-".to_string(), vec![]));
-        let outcome_repr = if !exprs.is_empty() {
-            format!("{}; {}", output, with_placeholders(exprs).join(", "))
-        } else {
-            output
-        };
-
-        expect.assert_eq(&outcome_repr);
-    }
-
-    #[test]
-    fn format_str_parser() {
-        let test_vector = &[
-            ("no expressions", expect![["no expressions"]]),
-            (r"no expressions with \$0$1", expect![r"no expressions with \\\$0\$1"]),
-            ("{expr} is {2 + 2}", expect![["{} is {}; expr, 2 + 2"]]),
-            ("{expr:?}", expect![["{:?}; expr"]]),
-            ("{expr:1$}", expect![[r"{:1\$}; expr"]]),
-            ("{$0}", expect![[r"{}; \$0"]]),
-            ("{malformed", expect![["-"]]),
-            ("malformed}", expect![["-"]]),
-            ("{{correct", expect![["{{correct"]]),
-            ("correct}}", expect![["correct}}"]]),
-            ("{correct}}}", expect![["{}}}; correct"]]),
-            ("{correct}}}}}", expect![["{}}}}}; correct"]]),
-            ("{incorrect}}", expect![["-"]]),
-            ("placeholders {} {}", expect![["placeholders {} {}; $1, $2"]]),
-            ("mixed {} {2 + 2} {}", expect![["mixed {} {} {}; $1, 2 + 2, $2"]]),
-            (
-                "{SomeStruct { val_a: 0, val_b: 1 }}",
-                expect![["{}; SomeStruct { val_a: 0, val_b: 1 }"]],
-            ),
-            ("{expr:?} is {2.32f64:.5}", expect![["{:?} is {:.5}; expr, 2.32f64"]]),
-            (
-                "{SomeStruct { val_a: 0, val_b: 1 }:?}",
-                expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
-            ),
-            ("{     2 + 2        }", expect![["{}; 2 + 2"]]),
-            ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
-            ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
-            ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
-        ];
-
-        for (input, output) in test_vector {
-            check(input, output)
-        }
-    }
-
-    #[test]
-    fn arg_type() {
-        assert_eq!(
-            parse_format_exprs("{_ident} {r#raw_ident} {expr.obj} {name {thing: 42} } {}")
-                .unwrap()
-                .1,
-            vec![
-                Arg::Ident("_ident".to_owned()),
-                Arg::Ident("r#raw_ident".to_owned()),
-                Arg::Expr("expr.obj".to_owned()),
-                Arg::Expr("name {thing: 42}".to_owned()),
-                Arg::Placeholder
-            ]
-        );
-    }
-}
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 06073ca1b2..a21db5b2ce 100644
--- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
@@ -137,7 +137,6 @@ pub(crate) fn json_in_items(
                                         sema.db,
                                         it,
                                         config.insert_use.prefix_kind,
-                                        config.prefer_core,
                                     ) {
                                         insert_use(
                                             &scope,
@@ -153,7 +152,6 @@ 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 5a81a55d82..edb1fc0919 100644
--- a/crates/ide-diagnostics/src/handlers/missing_fields.rs
+++ b/crates/ide-diagnostics/src/handlers/missing_fields.rs
@@ -124,7 +124,6 @@ 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 22e644bb59..61e63ea7a9 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -150,7 +150,6 @@ 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 {
@@ -171,7 +170,6 @@ 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 57b5ab6abd..e3a837ddcd 100644
--- a/crates/ide-ssr/src/matching.rs
+++ b/crates/ide-ssr/src/matching.rs
@@ -648,10 +648,9 @@ 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, false).ok_or_else(|| {
-                        match_error!("Failed to render template path `{}` at match location")
-                    })?;
+                let mod_path = module.find_use_path(sema.db, module_def).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/annotations.rs b/crates/ide/src/annotations.rs
index ba4c330bf3..210c5c7fac 100644
--- a/crates/ide/src/annotations.rs
+++ b/crates/ide/src/annotations.rs
@@ -158,7 +158,6 @@ pub(crate) fn resolve_annotation(db: &RootDatabase, mut annotation: Annotation)
                 &Semantics::new(db),
                 FilePosition { file_id, offset: annotation.range.start() },
                 None,
-                false,
             )
             .map(|result| {
                 result
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 93fcd7cad7..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())
@@ -1687,74 +1605,6 @@ fn main() {
         );
     }
 
-    #[test]
-    fn iterator_hint_regression_issue_12674() {
-        // Ensure we don't crash while solving the projection type of iterators.
-        check_expect(
-            InlayHintsConfig { chaining_hints: true, ..DISABLED_CONFIG },
-            r#"
-//- minicore: iterators
-struct S<T>(T);
-impl<T> S<T> {
-    fn iter(&self) -> Iter<'_, T> { loop {} }
-}
-struct Iter<'a, T: 'a>(&'a T);
-impl<'a, T> Iterator for Iter<'a, T> {
-    type Item = &'a T;
-    fn next(&mut self) -> Option<Self::Item> { loop {} }
-}
-struct Container<'a> {
-    elements: S<&'a str>,
-}
-struct SliceIter<'a, T>(&'a T);
-impl<'a, T> Iterator for SliceIter<'a, T> {
-    type Item = &'a T;
-    fn next(&mut self) -> Option<Self::Item> { loop {} }
-}
-
-fn main(a: SliceIter<'_, Container>) {
-    a
-    .filter_map(|c| Some(c.elements.iter().filter_map(|v| Some(v))))
-    .map(|e| e);
-}
-            "#,
-            expect![[r#"
-                [
-                    InlayHint {
-                        range: 484..554,
-                        kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = impl Iterator<Item = &&str>>",
-                        ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                484..554,
-                            ),
-                        ),
-                    },
-                    InlayHint {
-                        range: 484..485,
-                        kind: ChainingHint,
-                        label: [
-                            "SliceIter<Container>",
-                        ],
-                        tooltip: Some(
-                            HoverRanged(
-                                FileId(
-                                    0,
-                                ),
-                                484..485,
-                            ),
-                        ),
-                    },
-                ]
-            "#]],
-        );
-    }
-
     #[test]
     fn infer_call_method_return_associated_types_with_generic() {
         check_types(
@@ -2373,9 +2223,7 @@ fn main() {
                     InlayHint {
                         range: 147..172,
                         kind: ChainingHint,
-                        label: [
-                            "B",
-                        ],
+                        label: "B",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2388,9 +2236,7 @@ fn main() {
                     InlayHint {
                         range: 147..154,
                         kind: ChainingHint,
-                        label: [
-                            "A",
-                        ],
+                        label: "A",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2448,9 +2294,7 @@ fn main() {
                     InlayHint {
                         range: 143..190,
                         kind: ChainingHint,
-                        label: [
-                            "C",
-                        ],
+                        label: "C",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2463,9 +2307,7 @@ fn main() {
                     InlayHint {
                         range: 143..179,
                         kind: ChainingHint,
-                        label: [
-                            "B",
-                        ],
+                        label: "B",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2508,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(
@@ -2523,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(
@@ -2570,9 +2408,7 @@ fn main() {
                     InlayHint {
                         range: 174..241,
                         kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = ()>",
-                        ],
+                        label: "impl Iterator<Item = ()>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2585,9 +2421,7 @@ fn main() {
                     InlayHint {
                         range: 174..224,
                         kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = ()>",
-                        ],
+                        label: "impl Iterator<Item = ()>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2600,9 +2434,7 @@ fn main() {
                     InlayHint {
                         range: 174..206,
                         kind: ChainingHint,
-                        label: [
-                            "impl Iterator<Item = ()>",
-                        ],
+                        label: "impl Iterator<Item = ()>",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2615,9 +2447,7 @@ fn main() {
                     InlayHint {
                         range: 174..189,
                         kind: ChainingHint,
-                        label: [
-                            "&mut MyIter",
-                        ],
+                        label: "&mut MyIter",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2659,9 +2489,7 @@ fn main() {
                     InlayHint {
                         range: 124..130,
                         kind: TypeHint,
-                        label: [
-                            "Struct",
-                        ],
+                        label: "Struct",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2674,9 +2502,7 @@ fn main() {
                     InlayHint {
                         range: 145..185,
                         kind: ChainingHint,
-                        label: [
-                            "Struct",
-                        ],
+                        label: "Struct",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2689,9 +2515,7 @@ fn main() {
                     InlayHint {
                         range: 145..168,
                         kind: ChainingHint,
-                        label: [
-                            "Struct",
-                        ],
+                        label: "Struct",
                         tooltip: Some(
                             HoverRanged(
                                 FileId(
@@ -2704,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 065b48378b..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,
@@ -425,11 +425,8 @@ impl Analysis {
         &self,
         position: FilePosition,
         search_scope: Option<SearchScope>,
-        exclude_imports: bool,
     ) -> Cancellable<Option<Vec<ReferenceSearchResult>>> {
-        self.with_db(|db| {
-            references::find_all_refs(&Semantics::new(db), position, search_scope, exclude_imports)
-        })
+        self.with_db(|db| references::find_all_refs(&Semantics::new(db), position, search_scope))
     }
 
     /// Finds all methods and free functions for the file. Does not return tests!
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 5b410c454d..99614b645e 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -54,7 +54,6 @@ pub(crate) fn find_all_refs(
     sema: &Semantics<'_, RootDatabase>,
     position: FilePosition,
     search_scope: Option<SearchScope>,
-    exclude_imports: bool,
 ) -> Option<Vec<ReferenceSearchResult>> {
     let _p = profile::span("find_all_refs");
     let syntax = sema.parse(position.file_id).syntax().clone();
@@ -80,10 +79,6 @@ pub(crate) fn find_all_refs(
                 retain_adt_literal_usages(&mut usages, def, sema);
             }
 
-            if exclude_imports {
-                filter_import_references(&mut usages);
-            }
-
             let references = usages
                 .into_iter()
                 .map(|(file_id, refs)| {
@@ -117,17 +112,6 @@ pub(crate) fn find_all_refs(
     }
 }
 
-fn filter_import_references(usages: &mut UsageSearchResult) {
-    for (_file_id, refs) in &mut usages.references {
-        refs.retain(|it| match it.name.as_name_ref() {
-            Some(name_ref) => {
-                !name_ref.syntax().ancestors().any(|it_ref| matches!(it_ref.kind(), USE))
-            }
-            None => true,
-        });
-    }
-}
-
 pub(crate) fn find_defs<'a>(
     sema: &'a Semantics<'_, RootDatabase>,
     syntax: &SyntaxNode,
@@ -1110,7 +1094,7 @@ impl Foo {
 
     fn check_with_scope(ra_fixture: &str, search_scope: Option<SearchScope>, expect: Expect) {
         let (analysis, pos) = fixture::position(ra_fixture);
-        let refs = analysis.find_all_refs(pos, search_scope, false).unwrap().unwrap();
+        let refs = analysis.find_all_refs(pos, search_scope).unwrap().unwrap();
 
         let mut actual = String::new();
         for refs in refs {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index e0384e67d4..54dcb42d99 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -219,6 +219,7 @@ config_data! {
         files_excludeDirs: Vec<PathBuf> = "[]",
         /// Controls file watching implementation.
         files_watcher: FilesWatcherDef = "\"client\"",
+
         /// Enables highlighting of related references while the cursor is on `break`, `loop`, `while`, or `for` keywords.
         highlightRelated_breakPoints_enable: bool = "true",
         /// Enables highlighting of all exit points while the cursor is on any `return`, `?`, `fn`, or return type arrow (`->`).
@@ -262,8 +263,6 @@ 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\"",
 
@@ -360,9 +359,6 @@ config_data! {
         /// this is rust-analyzer itself, but we override this in tests).
         procMacro_server: Option<PathBuf>          = "null",
 
-        /// Exclude imports from find-all-references.
-        references_excludeImports: bool = "false",
-
         /// Command to be executed instead of 'cargo' for runnables.
         runnables_command: Option<String> = "null",
         /// Additional arguments to be passed to cargo for runnables such as
@@ -922,7 +918,6 @@ impl Config {
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
             },
             insert_use: self.insert_use_config(),
-            prefer_core: self.data.imports_prefer_core,
         }
     }
 
@@ -1138,7 +1133,6 @@ 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
@@ -1153,10 +1147,6 @@ impl Config {
         }
     }
 
-    pub fn find_all_refs_exclude_imports(&self) -> bool {
-        self.data.references_excludeImports
-    }
-
     pub fn snippet_cap(&self) -> bool {
         self.experimental("snippetTextEdit")
     }
@@ -1166,7 +1156,6 @@ 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 7b486744da..d9b669afbe 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1012,9 +1012,7 @@ pub(crate) fn handle_references(
     let _p = profile::span("handle_references");
     let position = from_proto::file_position(&snap, params.text_document_position)?;
 
-    let exclude_imports = snap.config.find_all_refs_exclude_imports();
-
-    let refs = match snap.analysis.find_all_refs(position, None, exclude_imports)? {
+    let refs = match snap.analysis.find_all_refs(position, None)? {
         None => return Ok(None),
         Some(refs) => refs,
     };
@@ -1364,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(),
     ))
 }
 
@@ -1654,9 +1652,7 @@ fn show_ref_command_link(
     position: &FilePosition,
 ) -> Option<lsp_ext::CommandLinkGroup> {
     if snap.config.hover_actions().references && snap.config.client_commands().show_reference {
-        if let Some(ref_search_res) =
-            snap.analysis.find_all_refs(*position, None, false).unwrap_or(None)
-        {
+        if let Some(ref_search_res) = snap.analysis.find_all_refs(*position, None).unwrap_or(None) {
             let uri = to_proto::url(snap, position.file_id);
             let line_index = snap.file_line_index(position.file_id).ok()?;
             let position = to_proto::position(&line_index, position.offset);
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 5dbb64d7df..e49a98685a 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -145,7 +145,6 @@ 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() };
@@ -183,7 +182,6 @@ 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/reload.rs b/crates/rust-analyzer/src/reload.rs
index e47f70fff3..f23bbca638 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -314,9 +314,7 @@ impl GlobalState {
                         let mut args = args.clone();
                         let mut path = path.clone();
 
-                        if let ProjectWorkspace::Cargo { sysroot, .. }
-                        | ProjectWorkspace::Json { sysroot, .. } = ws
-                        {
+                        if let ProjectWorkspace::Cargo { sysroot, .. } = ws {
                             tracing::debug!("Found a cargo workspace...");
                             if let Some(sysroot) = sysroot.as_ref() {
                                 tracing::debug!("Found a cargo workspace with a sysroot...");
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 2b02c64b66..72b9257264 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -353,11 +353,6 @@ 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"`)::
 +
 --
@@ -551,11 +546,6 @@ This config takes a map of crate names with the exported proc-macro names to ign
 Internal config, path to proc-macro server executable (typically,
 this is rust-analyzer itself, but we override this in tests).
 --
-[[rust-analyzer.references.excludeImports]]rust-analyzer.references.excludeImports (default: `false`)::
-+
---
-Exclude imports from find-all-references.
---
 [[rust-analyzer.runnables.command]]rust-analyzer.runnables.command (default: `null`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index cfba00d3ed..767c5875bf 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -206,6 +206,11 @@
                 "title": "Show RA Version",
                 "category": "rust-analyzer"
             },
+            {
+                "command": "rust-analyzer.toggleInlayHints",
+                "title": "Toggle inlay hints",
+                "category": "rust-analyzer"
+            },
             {
                 "command": "rust-analyzer.openDocs",
                 "title": "Open docs under cursor",
@@ -798,11 +803,6 @@
                     "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",
@@ -1036,11 +1036,6 @@
                         "string"
                     ]
                 },
-                "rust-analyzer.references.excludeImports": {
-                    "markdownDescription": "Exclude imports from find-all-references.",
-                    "default": false,
-                    "type": "boolean"
-                },
                 "rust-analyzer.runnables.command": {
                     "markdownDescription": "Command to be executed instead of 'cargo' for runnables.",
                     "default": null,
@@ -1638,6 +1633,10 @@
                     "command": "rust-analyzer.serverVersion",
                     "when": "inRustProject"
                 },
+                {
+                    "command": "rust-analyzer.toggleInlayHints",
+                    "when": "inRustProject"
+                },
                 {
                     "command": "rust-analyzer.openDocs",
                     "when": "inRustProject"
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index b9ad525e36..a21b304bbd 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -321,6 +321,30 @@ export function serverVersion(ctx: Ctx): Cmd {
     };
 }
 
+export function toggleInlayHints(_ctx: Ctx): Cmd {
+    return async () => {
+        const config = vscode.workspace.getConfiguration("editor.inlayHints", {
+            languageId: "rust",
+        });
+
+        const value = config.get("enabled");
+        let stringValue;
+        if (typeof value === "string") {
+            stringValue = value;
+        } else {
+            stringValue = value ? "on" : "off";
+        }
+        const nextValues: Record<string, string> = {
+            on: "off",
+            off: "on",
+            onUnlessPressed: "offUnlessPressed",
+            offUnlessPressed: "onUnlessPressed",
+        };
+        const nextValue = nextValues[stringValue] ?? "on";
+        await config.update("enabled", nextValue, vscode.ConfigurationTarget.Global);
+    };
+}
+
 // Opens the virtual file that will show the syntax tree
 //
 // The contents of the file come from the `TextDocumentContentProvider`
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 41bde4195e..e9b62e0cc2 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -180,6 +180,7 @@ async function initCommonContext(context: vscode.ExtensionContext, ctx: Ctx) {
 
     ctx.registerCommand("ssr", commands.ssr);
     ctx.registerCommand("serverVersion", commands.serverVersion);
+    ctx.registerCommand("toggleInlayHints", commands.toggleInlayHints);
 
     // Internal commands which are invoked by the server.
     ctx.registerCommand("runSingle", commands.runSingle);


Test patch:
diff --git a/crates/hir-ty/src/tests/coercion.rs b/crates/hir-ty/src/tests/coercion.rs
index bf59fadc2c..d301595bcd 100644
--- a/crates/hir-ty/src/tests/coercion.rs
+++ b/crates/hir-ty/src/tests/coercion.rs
@@ -294,6 +294,24 @@ fn foo() {
     );
 }
 
+#[test]
+fn generator_yield_return_coerce() {
+    check_no_mismatches(
+        r#"
+fn test() {
+    let g = || {
+        yield &1u32;
+        yield &&1u32;
+        if true {
+            return &1u32;
+        }
+        &&1u32
+    };
+}
+        "#,
+    );
+}
+
 #[test]
 fn assign_coerce() {
     check_no_mismatches(
diff --git a/crates/hir-ty/src/tests/method_resolution.rs b/crates/hir-ty/src/tests/method_resolution.rs
index ac8edb841a..81588a7c4f 100644
--- a/crates/hir-ty/src/tests/method_resolution.rs
+++ b/crates/hir-ty/src/tests/method_resolution.rs
@@ -1218,40 +1218,6 @@ fn main() {
     );
 }
 
-#[test]
-fn dyn_trait_method_priority() {
-    check_types(
-        r#"
-//- minicore: from
-trait Trait {
-    fn into(&self) -> usize { 0 }
-}
-
-fn foo(a: &dyn Trait) {
-    let _ = a.into();
-      //^usize
-}
-        "#,
-    );
-}
-
-#[test]
-fn trait_method_priority_for_placeholder_type() {
-    check_types(
-        r#"
-//- minicore: from
-trait Trait {
-    fn into(&self) -> usize { 0 }
-}
-
-fn foo<T: Trait>(a: &T) {
-    let _ = a.into();
-      //^usize
-}
-        "#,
-    );
-}
-
 #[test]
 fn autoderef_visibility_field() {
     check(
diff --git a/crates/hir-ty/src/tests/simple.rs b/crates/hir-ty/src/tests/simple.rs
index 4ea103e5d9..b42c5fe7fc 100644
--- a/crates/hir-ty/src/tests/simple.rs
+++ b/crates/hir-ty/src/tests/simple.rs
@@ -1917,6 +1917,88 @@ fn closure_return_inferred() {
     );
 }
 
+#[test]
+fn generator_types_inferred() {
+    check_infer(
+        r#"
+//- minicore: generator, deref
+use core::ops::{Generator, GeneratorState};
+use core::pin::Pin;
+
+fn f(v: i64) {}
+fn test() {
+    let mut g = |r| {
+        let a = yield 0;
+        let a = yield 1;
+        let a = yield 2;
+        "return value"
+    };
+
+    match Pin::new(&mut g).resume(0usize) {
+        GeneratorState::Yielded(y) => { f(y); }
+        GeneratorState::Complete(r) => {}
+    }
+}
+        "#,
+        expect![[r#"
+            70..71 'v': i64
+            78..80 '{}': ()
+            91..362 '{     ...   } }': ()
+            101..106 'mut g': |usize| yields i64 -> &str
+            109..218 '|r| { ...     }': |usize| yields i64 -> &str
+            110..111 'r': usize
+            113..218 '{     ...     }': &str
+            127..128 'a': usize
+            131..138 'yield 0': usize
+            137..138 '0': i64
+            152..153 'a': usize
+            156..163 'yield 1': usize
+            162..163 '1': i64
+            177..178 'a': usize
+            181..188 'yield 2': usize
+            187..188 '2': i64
+            198..212 '"return value"': &str
+            225..360 'match ...     }': ()
+            231..239 'Pin::new': fn new<&mut |usize| yields i64 -> &str>(&mut |usize| yields i64 -> &str) -> Pin<&mut |usize| yields i64 -> &str>
+            231..247 'Pin::n...mut g)': Pin<&mut |usize| yields i64 -> &str>
+            231..262 'Pin::n...usize)': GeneratorState<i64, &str>
+            240..246 '&mut g': &mut |usize| yields i64 -> &str
+            245..246 'g': |usize| yields i64 -> &str
+            255..261 '0usize': usize
+            273..299 'Genera...ded(y)': GeneratorState<i64, &str>
+            297..298 'y': i64
+            303..312 '{ f(y); }': ()
+            305..306 'f': fn f(i64)
+            305..309 'f(y)': ()
+            307..308 'y': i64
+            321..348 'Genera...ete(r)': GeneratorState<i64, &str>
+            346..347 'r': &str
+            352..354 '{}': ()
+        "#]],
+    );
+}
+
+#[test]
+fn generator_resume_yield_return_unit() {
+    check_no_mismatches(
+        r#"
+//- minicore: generator, deref
+use core::ops::{Generator, GeneratorState};
+use core::pin::Pin;
+fn test() {
+    let mut g = || {
+        let () = yield;
+    };
+
+    match Pin::new(&mut g).resume(()) {
+        GeneratorState::Yielded(()) => {}
+        GeneratorState::Complete(()) => {}
+    }
+}
+        "#,
+    );
+}
+
 #[test]
 fn fn_pointer_return() {
     check_infer(
diff --git a/crates/ide-assists/src/tests.rs b/crates/ide-assists/src/tests.rs
index 4e589dc86a..9cd66c6b3b 100644
--- a/crates/ide-assists/src/tests.rs
+++ b/crates/ide-assists/src/tests.rs
@@ -29,7 +29,6 @@ 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-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 3a696635af..227e2300f9 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -1591,37 +1591,6 @@ fn apply<T, U, F>(f: F, x: T) -> U where F: FnOnce(T) -> U {
     )
 }
 
-#[test]
-fn doctest_move_format_string_arg() {
-    check_doc_test(
-        "move_format_string_arg",
-        r#####"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
-macro_rules! print {
-    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-}
-
-fn main() {
-    print!("{x + 1}$0");
-}
-"#####,
-        r#####"
-macro_rules! format_args {
-    ($lit:literal $(tt:tt)*) => { 0 },
-}
-macro_rules! print {
-    ($($arg:tt)*) => (std::io::_print(format_args!($($arg)*)));
-}
-
-fn main() {
-    print!("{}"$0, x + 1);
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_move_from_mod_rs() {
     check_doc_test(
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index d24c914856..cf826648dc 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -66,7 +66,6 @@ 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,
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index 6df29db474..10386b5b7b 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -37,6 +37,7 @@
 //!     add:
 //!     as_ref: sized
 //!     drop:
+//!     generator: pin
 
 pub mod marker {
     // region:sized
@@ -182,6 +183,19 @@ pub mod ops {
             type Target: ?Sized;
             fn deref(&self) -> &Self::Target;
         }
+
+        impl<T: ?Sized> Deref for &T {
+            type Target = T;
+            fn deref(&self) -> &T {
+                loop {}
+            }
+        }
+        impl<T: ?Sized> Deref for &mut T {
+            type Target = T;
+            fn deref(&self) -> &T {
+                loop {}
+            }
+        }
         // region:deref_mut
         #[lang = "deref_mut"]
         pub trait DerefMut: Deref {
@@ -347,6 +361,27 @@ pub mod ops {
         fn add(self, rhs: Rhs) -> Self::Output;
     }
     // endregion:add
+
+    // region:generator
+    mod generator {
+        use crate::pin::Pin;
+
+        #[lang = "generator"]
+        pub trait Generator<R = ()> {
+            type Yield;
+            #[lang = "generator_return"]
+            type Return;
+            fn resume(self: Pin<&mut Self>, arg: R) -> GeneratorState<Self::Yield, Self::Return>;
+        }
+
+        #[lang = "generator_state"]
+        pub enum GeneratorState<Y, R> {
+            Yielded(Y),
+            Complete(R),
+        }
+    }
+    pub use self::generator::{Generator, GeneratorState};
+    // endregion:generator
 }
 
 // region:eq
@@ -455,6 +490,19 @@ pub mod pin {
     pub struct Pin<P> {
         pointer: P,
     }
+    impl<P> Pin<P> {
+        pub fn new(pointer: P) -> Pin<P> {
+            loop {}
+        }
+    }
+    // region:deref
+    impl<P: crate::ops::Deref> crate::ops::Deref for Pin<P> {
+        type Target = P::Target;
+        fn deref(&self) -> &P::Target {
+            loop {}
+        }
+    }
+    // endregion:deref
 }
 // endregion:pin