Repository: rust-lang/rust-analyzer
Pull request #17461 (2024-06-20 08:22:10)

fix: Fix flycheck panicking when cancelled
Fixes https://github.com/rust-lang/rust-analyzer/issues/17445


Patch:
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index 36be514347..4584400e66 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -386,6 +386,7 @@ impl FlycheckActor {
                 "did  cancel flycheck"
             );
             command_handle.cancel();
+            self.command_receiver.take();
             self.report_progress(Progress::DidCancel);
             self.status = FlycheckStatus::Finished;
         }
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index eadb2e19d1..f83e266744 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -91,6 +91,7 @@ pub(crate) fn fixup_syntax(
             preorder.skip_subtree();
             continue;
         }
+
         // In some other situations, we can fix things by just appending some tokens.
         match_ast! {
             match node {
@@ -275,62 +276,6 @@ pub(crate) fn fixup_syntax(
                         ]);
                     }
                 },
-                ast::RecordExprField(it) => {
-                    if let Some(colon) = it.colon_token() {
-                        if it.name_ref().is_some() {
-                            append.insert(colon.into(), vec![
-                                Leaf::Ident(Ident {
-                                    text: "__ra_fixup".into(),
-                                    span: fake_span(node_range)
-                                })
-                            ]);
-                        }
-                    }
-                },
-                ast::Path(it) => {
-                    if let Some(colon) = it.coloncolon_token() {
-                        if it.segment().is_none() {
-                            append.insert(colon.into(), vec![
-                                Leaf::Ident(Ident {
-                                    text: "__ra_fixup".into(),
-                                    span: fake_span(node_range)
-                                })
-                            ]);
-                        }
-                    }
-                },
-                ast::ArgList(it) => {
-                    if it.r_paren_token().is_none() {
-                        append.insert(node.into(), vec![
-                            Leaf::Punct(Punct {
-                                span: fake_span(node_range),
-                                char: ')',
-                                spacing: Spacing::Alone
-                            })
-                        ]);
-                    }
-                },
-                ast::ArgList(it) => {
-                    if it.r_paren_token().is_none() {
-                        append.insert(node.into(), vec![
-                            Leaf::Punct(Punct {
-                                span: fake_span(node_range),
-                                char: ')',
-                                spacing: Spacing::Alone
-                            })
-                        ]);
-                    }
-                },
-                ast::ClosureExpr(it) => {
-                    if it.body().is_none() {
-                        append.insert(node.into(), vec![
-                            Leaf::Ident(Ident {
-                                text: "__ra_fixup".into(),
-                                span: fake_span(node_range)
-                            })
-                        ]);
-                    }
-                },
                 _ => (),
             }
         }
@@ -814,70 +759,4 @@ fn foo () {loop { }}
 "#]],
         )
     }
-
-    #[test]
-    fn fixup_path() {
-        check(
-            r#"
-fn foo() {
-    path::
-}
-"#,
-            expect![[r#"
-fn foo () {path :: __ra_fixup}
-"#]],
-        )
-    }
-
-    #[test]
-    fn fixup_record_ctor_field() {
-        check(
-            r#"
-fn foo() {
-    R { f: }
-}
-"#,
-            expect![[r#"
-fn foo () {R {f : __ra_fixup}}
-"#]],
-        )
-    }
-
-    #[test]
-    fn fixup_arg_list() {
-        check(
-            r#"
-fn foo() {
-    foo(a
-}
-"#,
-            expect![[r#"
-fn foo () { foo ( a ) }
-"#]],
-        );
-        check(
-            r#"
-fn foo() {
-    bar.foo(a
-}
-"#,
-            expect![[r#"
-fn foo () { bar . foo ( a ) }
-"#]],
-        );
-    }
-
-    #[test]
-    fn fixup_closure() {
-        check(
-            r#"
-fn foo() {
-    ||
-}
-"#,
-            expect![[r#"
-fn foo () {|| __ra_fixup}
-"#]],
-        );
-    }
 }
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index cd31845a51..ff78fe0d54 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -1426,7 +1426,6 @@ fn generic_args_sans_defaults<'ga>(
                     }
                     // otherwise, if the arg is equal to the param default, hide it (unless the
                     // default is an error which can happen for the trait Self type)
-                    #[allow(unstable_name_collisions)]
                     default_parameters.get(i).is_none_or(|default_parameter| {
                         // !is_err(default_parameter.skip_binders())
                         //     &&
diff --git a/crates/hir/src/term_search.rs b/crates/hir/src/term_search.rs
index aa046b02e2..7b70cdf459 100644
--- a/crates/hir/src/term_search.rs
+++ b/crates/hir/src/term_search.rs
@@ -325,7 +325,6 @@ pub fn term_search<DB: HirDatabase>(ctx: &TermSearchCtx<'_, DB>) -> Vec<Expr> {
     let mut solutions: Vec<Expr> = tactics::trivial(ctx, &defs, &mut lookup).collect();
     // Use well known types tactic before iterations as it does not depend on other tactics
     solutions.extend(tactics::famous_types(ctx, &defs, &mut lookup));
-    solutions.extend(tactics::assoc_const(ctx, &defs, &mut lookup));
 
     while should_continue() {
         lookup.new_round();
diff --git a/crates/hir/src/term_search/expr.rs b/crates/hir/src/term_search/expr.rs
index bb687f5e73..8173427cd9 100644
--- a/crates/hir/src/term_search/expr.rs
+++ b/crates/hir/src/term_search/expr.rs
@@ -9,8 +9,8 @@ use hir_ty::{
 use itertools::Itertools;
 
 use crate::{
-    Adt, AsAssocItem, AssocItemContainer, Const, ConstParam, Field, Function, GenericDef, Local,
-    ModuleDef, SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
+    Adt, AsAssocItem, Const, ConstParam, Field, Function, GenericDef, Local, ModuleDef,
+    SemanticsScope, Static, Struct, StructKind, Trait, Type, Variant,
 };
 
 /// Helper function to get path to `ModuleDef`
@@ -138,17 +138,7 @@ impl Expr {
         let db = sema_scope.db;
         let mod_item_path_str = |s, def| mod_item_path_str(s, def, cfg);
         match self {
-            Expr::Const(it) => match it.as_assoc_item(db).map(|it| it.container(db)) {
-                Some(container) => {
-                    let container_name = container_name(container, sema_scope, cfg)?;
-                    let const_name = it
-                        .name(db)
-                        .map(|c| c.display(db.upcast()).to_string())
-                        .unwrap_or(String::new());
-                    Ok(format!("{container_name}::{const_name}"))
-                }
-                None => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
-            },
+            Expr::Const(it) => mod_item_path_str(sema_scope, &ModuleDef::Const(*it)),
             Expr::Static(it) => mod_item_path_str(sema_scope, &ModuleDef::Static(*it)),
             Expr::Local(it) => Ok(it.name(db).display(db.upcast()).to_string()),
             Expr::ConstParam(it) => Ok(it.name(db).display(db.upcast()).to_string()),
@@ -163,7 +153,22 @@ impl Expr {
 
                 match func.as_assoc_item(db).map(|it| it.container(db)) {
                     Some(container) => {
-                        let container_name = container_name(container, sema_scope, cfg)?;
+                        let container_name = match container {
+                            crate::AssocItemContainer::Trait(trait_) => {
+                                mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_))?
+                            }
+                            crate::AssocItemContainer::Impl(imp) => {
+                                let self_ty = imp.self_ty(db);
+                                // Should it be guaranteed that `mod_item_path` always exists?
+                                match self_ty
+                                    .as_adt()
+                                    .and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg))
+                                {
+                                    Some(path) => path.display(sema_scope.db.upcast()).to_string(),
+                                    None => self_ty.display(db).to_string(),
+                                }
+                            }
+                        };
                         let fn_name = func.name(db).display(db.upcast()).to_string();
                         Ok(format!("{container_name}::{fn_name}({args})"))
                     }
@@ -409,25 +414,3 @@ impl Expr {
         matches!(self, Expr::Many(_))
     }
 }
-
-/// Helper function to find name of container
-fn container_name(
-    container: AssocItemContainer,
-    sema_scope: &SemanticsScope<'_>,
-    cfg: ImportPathConfig,
-) -> Result<String, DisplaySourceCodeError> {
-    let container_name = match container {
-        crate::AssocItemContainer::Trait(trait_) => {
-            mod_item_path_str(sema_scope, &ModuleDef::Trait(trait_), cfg)?
-        }
-        crate::AssocItemContainer::Impl(imp) => {
-            let self_ty = imp.self_ty(sema_scope.db);
-            // Should it be guaranteed that `mod_item_path` always exists?
-            match self_ty.as_adt().and_then(|adt| mod_item_path(sema_scope, &adt.into(), cfg)) {
-                Some(path) => path.display(sema_scope.db.upcast()).to_string(),
-                None => self_ty.display(sema_scope.db).to_string(),
-            }
-        }
-    };
-    Ok(container_name)
-}
diff --git a/crates/hir/src/term_search/tactics.rs b/crates/hir/src/term_search/tactics.rs
index b738e6af77..7ac63562bb 100644
--- a/crates/hir/src/term_search/tactics.rs
+++ b/crates/hir/src/term_search/tactics.rs
@@ -80,10 +80,7 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
         lookup.insert(ty.clone(), std::iter::once(expr.clone()));
 
         // Don't suggest local references as they are not valid for return
-        if matches!(expr, Expr::Local(_))
-            && ty.contains_reference(db)
-            && ctx.config.enable_borrowcheck
-        {
+        if matches!(expr, Expr::Local(_)) && ty.contains_reference(db) {
             return None;
         }
 
@@ -91,52 +88,6 @@ pub(super) fn trivial<'a, DB: HirDatabase>(
     })
 }
 
-/// # Associated constant tactic
-///
-/// Attempts to fulfill the goal by trying constants defined as associated items.
-/// Only considers them on types that are in scope.
-///
-/// # Arguments
-/// * `ctx` - Context for the term search
-/// * `defs` - Set of items in scope at term search target location
-/// * `lookup` - Lookup table for types
-///
-/// Returns iterator that yields elements that unify with `goal`.
-///
-/// _Note that there is no use of calling this tactic in every iteration as the output does not
-/// depend on the current state of `lookup`_
-pub(super) fn assoc_const<'a, DB: HirDatabase>(
-    ctx: &'a TermSearchCtx<'a, DB>,
-    defs: &'a FxHashSet<ScopeDef>,
-    lookup: &'a mut LookupTable,
-) -> impl Iterator<Item = Expr> + 'a {
-    let db = ctx.sema.db;
-    let module = ctx.scope.module();
-
-    defs.iter()
-        .filter_map(|def| match def {
-            ScopeDef::ModuleDef(ModuleDef::Adt(it)) => Some(it),
-            _ => None,
-        })
-        .flat_map(|it| Impl::all_for_type(db, it.ty(db)))
-        .filter(|it| !it.is_unsafe(db))
-        .flat_map(|it| it.items(db))
-        .filter(move |it| it.is_visible_from(db, module))
-        .filter_map(AssocItem::as_const)
-        .filter_map(|it| {
-            let expr = Expr::Const(it);
-            let ty = it.ty(db);
-
-            if ty.contains_unknown() {
-                return None;
-            }
-
-            lookup.insert(ty.clone(), std::iter::once(expr.clone()));
-
-            ty.could_unify_with_deeply(db, &ctx.goal).then_some(expr)
-        })
-}
-
 /// # Data constructor tactic
 ///
 /// Attempts different data constructors for enums and structs in scope
diff --git a/crates/ide-assists/src/handlers/term_search.rs b/crates/ide-assists/src/handlers/term_search.rs
index 8a9229c549..94e0519cba 100644
--- a/crates/ide-assists/src/handlers/term_search.rs
+++ b/crates/ide-assists/src/handlers/term_search.rs
@@ -290,34 +290,4 @@ fn f() { let a = 1; let b: Foo<i32> = todo$0!(); }"#,
 fn f() { let a = 1; let b: Foo<i32> = Foo(a); }"#,
         )
     }
-
-    #[test]
-    fn test_struct_assoc_item() {
-        check_assist(
-            term_search,
-            r#"//- minicore: todo, unimplemented
-struct Foo;
-impl Foo { const FOO: i32 = 0; }
-fn f() { let a: i32 = todo$0!(); }"#,
-            r#"struct Foo;
-impl Foo { const FOO: i32 = 0; }
-fn f() { let a: i32 = Foo::FOO; }"#,
-        )
-    }
-
-    #[test]
-    fn test_trait_assoc_item() {
-        check_assist(
-            term_search,
-            r#"//- minicore: todo, unimplemented
-struct Foo;
-trait Bar { const BAR: i32; }
-impl Bar for Foo { const BAR: i32 = 0; }
-fn f() { let a: i32 = todo$0!(); }"#,
-            r#"struct Foo;
-trait Bar { const BAR: i32; }
-impl Bar for Foo { const BAR: i32 = 0; }
-fn f() { let a: i32 = Foo::BAR; }"#,
-        )
-    }
 }
diff --git a/crates/ide-completion/src/completions/field.rs b/crates/ide-completion/src/completions/field.rs
index b795bbd872..53fcb7ca6c 100644
--- a/crates/ide-completion/src/completions/field.rs
+++ b/crates/ide-completion/src/completions/field.rs
@@ -20,9 +20,9 @@ pub(crate) fn complete_field_list_tuple_variant(
     } = path_ctx
     {
         let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
-        add_keyword("pub(crate)", "pub(crate) $0");
-        add_keyword("pub(super)", "pub(super) $0");
-        add_keyword("pub", "pub $0");
+        add_keyword("pub(crate)", "pub(crate)");
+        add_keyword("pub(super)", "pub(super)");
+        add_keyword("pub", "pub");
     }
 }
 
@@ -32,8 +32,8 @@ pub(crate) fn complete_field_list_record_variant(
 ) {
     if ctx.qualifier_ctx.vis_node.is_none() {
         let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
-        add_keyword("pub(crate)", "pub(crate) $0");
-        add_keyword("pub(super)", "pub(super) $0");
-        add_keyword("pub", "pub $0");
+        add_keyword("pub(crate)", "pub(crate)");
+        add_keyword("pub(super)", "pub(super)");
+        add_keyword("pub", "pub");
     }
 }
diff --git a/crates/ide-completion/src/completions/item_list.rs b/crates/ide-completion/src/completions/item_list.rs
index 02298b1e9b..ce36681326 100644
--- a/crates/ide-completion/src/completions/item_list.rs
+++ b/crates/ide-completion/src/completions/item_list.rs
@@ -79,7 +79,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
     let in_trait = matches!(kind, Some(ItemListKind::Trait));
     let in_trait_impl = matches!(kind, Some(ItemListKind::TraitImpl(_)));
     let in_inherent_impl = matches!(kind, Some(ItemListKind::Impl));
-    let no_vis_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
+    let no_qualifiers = ctx.qualifier_ctx.vis_node.is_none();
     let in_block = kind.is_none();
 
     if !in_trait_impl {
@@ -89,7 +89,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
             }
             if in_item_list {
                 add_keyword("trait", "trait $1 {\n    $0\n}");
-                if no_vis_qualifiers {
+                if no_qualifiers {
                     add_keyword("impl", "impl $1 {\n    $0\n}");
                 }
             }
@@ -100,20 +100,19 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
             add_keyword("enum", "enum $1 {\n    $0\n}");
             add_keyword("mod", "mod $0");
             add_keyword("static", "static $0");
-            add_keyword("async", "async $0");
             add_keyword("struct", "struct $0");
             add_keyword("trait", "trait $1 {\n    $0\n}");
             add_keyword("union", "union $1 {\n    $0\n}");
             add_keyword("use", "use $0");
-            if no_vis_qualifiers {
+            if no_qualifiers {
                 add_keyword("impl", "impl $1 {\n    $0\n}");
             }
         }
 
-        if !in_trait && !in_block && no_vis_qualifiers {
-            add_keyword("pub(crate)", "pub(crate) $0");
-            add_keyword("pub(super)", "pub(super) $0");
-            add_keyword("pub", "pub $0");
+        if !in_trait && !in_block && no_qualifiers {
+            add_keyword("pub(crate)", "pub(crate)");
+            add_keyword("pub(super)", "pub(super)");
+            add_keyword("pub", "pub");
         }
 
         if in_extern_block {
@@ -127,7 +126,7 @@ fn add_keywords(acc: &mut Completions, ctx: &CompletionContext<'_>, kind: Option
             }
 
             add_keyword("fn", "fn $1($2) {\n    $0\n}");
-            add_keyword("unsafe", "unsafe $0");
+            add_keyword("unsafe", "unsafe");
             add_keyword("const", "const $0");
         }
     }
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index d79b539882..1322c05e30 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -14,9 +14,9 @@ pub(crate) fn complete_for_and_where(
     match keyword_item {
         Item::Impl(it) => {
             if it.for_token().is_none() && it.trait_().is_none() && it.self_ty().is_some() {
-                add_keyword("for", "for $0");
+                add_keyword("for", "for");
             }
-            add_keyword("where", "where $0");
+            add_keyword("where", "where");
         }
         Item::Enum(_)
         | Item::Fn(_)
@@ -24,7 +24,7 @@ pub(crate) fn complete_for_and_where(
         | Item::Trait(_)
         | Item::TypeAlias(_)
         | Item::Union(_) => {
-            add_keyword("where", "where $0");
+            add_keyword("where", "where");
         }
         _ => (),
     }
diff --git a/crates/ide-completion/src/completions/pattern.rs b/crates/ide-completion/src/completions/pattern.rs
index 60cfb7e5a8..40b2c831a5 100644
--- a/crates/ide-completion/src/completions/pattern.rs
+++ b/crates/ide-completion/src/completions/pattern.rs
@@ -14,27 +14,25 @@ pub(crate) fn complete_pattern(
     ctx: &CompletionContext<'_>,
     pattern_ctx: &PatternContext,
 ) {
-    let mut add_keyword = |kw, snippet| acc.add_keyword_snippet(ctx, kw, snippet);
-
     match pattern_ctx.parent_pat.as_ref() {
         Some(Pat::RangePat(_) | Pat::BoxPat(_)) => (),
         Some(Pat::RefPat(r)) => {
             if r.mut_token().is_none() {
-                add_keyword("mut", "mut $0");
+                acc.add_keyword(ctx, "mut");
             }
         }
         _ => {
             let tok = ctx.token.text_range().start();
             match (pattern_ctx.ref_token.as_ref(), pattern_ctx.mut_token.as_ref()) {
                 (None, None) => {
-                    add_keyword("ref", "ref $0");
-                    add_keyword("mut", "mut $0");
+                    acc.add_keyword(ctx, "ref");
+                    acc.add_keyword(ctx, "mut");
                 }
                 (None, Some(m)) if tok < m.text_range().start() => {
-                    add_keyword("ref", "ref $0");
+                    acc.add_keyword(ctx, "ref");
                 }
                 (Some(r), None) if tok > r.text_range().end() => {
-                    add_keyword("mut", "mut $0");
+                    acc.add_keyword(ctx, "mut");
                 }
                 _ => (),
             }
diff --git a/crates/ide-completion/src/completions/postfix.rs b/crates/ide-completion/src/completions/postfix.rs
index 5041ef8d8a..a230edd39b 100644
--- a/crates/ide-completion/src/completions/postfix.rs
+++ b/crates/ide-completion/src/completions/postfix.rs
@@ -668,7 +668,7 @@ fn main() {
         check_edit(
             "unsafe",
             r#"fn main() { let x = true else {panic!()}.$0}"#,
-            r#"fn main() { let x = true else {panic!()}.unsafe $0}"#,
+            r#"fn main() { let x = true else {panic!()}.unsafe}"#,
         );
     }
 
diff --git a/crates/ide-completion/src/completions/vis.rs b/crates/ide-completion/src/completions/vis.rs
index 0ea5157fb4..e0a959ad0b 100644
--- a/crates/ide-completion/src/completions/vis.rs
+++ b/crates/ide-completion/src/completions/vis.rs
@@ -33,7 +33,7 @@ pub(crate) fn complete_vis_path(
         Qualified::No => {
             if !has_in_token {
                 cov_mark::hit!(kw_completion_in);
-                acc.add_keyword_snippet(ctx, "in", "in $0");
+                acc.add_keyword(ctx, "in");
             }
             acc.add_nameref_keywords(ctx);
         }
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index ebdc813f3d..905c7eebfa 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -1799,7 +1799,6 @@ fn go(world: &WorldSnapshot) { go(w$0) }
 "#,
             expect![[r#"
                 lc world [type+name+local]
-                ex world [type]
                 st WorldSnapshot {…} []
                 st &WorldSnapshot {…} [type]
                 st WorldSnapshot []
diff --git a/crates/ide-db/src/prime_caches.rs b/crates/ide-db/src/prime_caches.rs
index 62104fb7dc..b4486d1502 100644
--- a/crates/ide-db/src/prime_caches.rs
+++ b/crates/ide-db/src/prime_caches.rs
@@ -11,9 +11,9 @@ use hir::db::DefDatabase;
 use crate::{
     base_db::{
         salsa::{Database, ParallelDatabase, Snapshot},
-        Cancelled, CrateId, SourceDatabase, SourceDatabaseExt,
+        Cancelled, CrateGraph, CrateId, SourceDatabase, SourceDatabaseExt,
     },
-    FxIndexMap, RootDatabase,
+    FxHashSet, FxIndexMap, RootDatabase,
 };
 
 /// We're indexing many crates.
@@ -36,10 +36,19 @@ pub fn parallel_prime_caches(
 
     let graph = db.crate_graph();
     let mut crates_to_prime = {
+        let crate_ids = compute_crates_to_prime(db, &graph);
+
         let mut builder = topologic_sort::TopologicalSortIter::builder();
 
-        for crate_id in graph.iter() {
-            builder.add(crate_id, graph[crate_id].dependencies.iter().map(|d| d.crate_id));
+        for &crate_id in &crate_ids {
+            let crate_data = &graph[crate_id];
+            let dependencies = crate_data
+                .dependencies
+                .iter()
+                .map(|d| d.crate_id)
+                .filter(|i| crate_ids.contains(i));
+
+            builder.add(crate_id, dependencies);
         }
 
         builder.build()
@@ -53,20 +62,13 @@ pub fn parallel_prime_caches(
     let (work_sender, progress_receiver) = {
         let (progress_sender, progress_receiver) = crossbeam_channel::unbounded();
         let (work_sender, work_receiver) = crossbeam_channel::unbounded();
-        let graph = graph.clone();
         let prime_caches_worker = move |db: Snapshot<RootDatabase>| {
             while let Ok((crate_id, crate_name)) = work_receiver.recv() {
                 progress_sender
                     .send(ParallelPrimeCacheWorkerProgress::BeginCrate { crate_id, crate_name })?;
 
-                let file_id = graph[crate_id].root_file_id;
-                let root_id = db.file_source_root(file_id);
-                if db.source_root(root_id).is_library {
-                    db.crate_def_map(crate_id);
-                } else {
-                    // This also computes the DefMap
-                    db.import_map(crate_id);
-                }
+                // This also computes the DefMap
+                db.import_map(crate_id);
 
                 progress_sender.send(ParallelPrimeCacheWorkerProgress::EndCrate { crate_id })?;
             }
@@ -74,13 +76,13 @@ pub fn parallel_prime_caches(
             Ok::<_, crossbeam_channel::SendError<_>>(())
         };
 
-        for id in 0..num_worker_threads {
+        for _ in 0..num_worker_threads {
             let worker = prime_caches_worker.clone();
             let db = db.snapshot();
 
             stdx::thread::Builder::new(stdx::thread::ThreadIntent::Worker)
                 .allow_leak(true)
-                .name(format!("PrimeCaches#{id}"))
+                .name("PrimeCaches".to_owned())
                 .spawn(move || Cancelled::catch(|| worker(db)))
                 .expect("failed to spawn thread");
         }
@@ -94,7 +96,7 @@ pub fn parallel_prime_caches(
     // an index map is used to preserve ordering so we can sort the progress report in order of
     // "longest crate to index" first
     let mut crates_currently_indexing =
-        FxIndexMap::with_capacity_and_hasher(num_worker_threads, Default::default());
+        FxIndexMap::with_capacity_and_hasher(num_worker_threads as _, Default::default());
 
     while crates_done < crates_total {
         db.unwind_if_cancelled();
@@ -142,3 +144,19 @@ pub fn parallel_prime_caches(
         cb(progress);
     }
 }
+
+fn compute_crates_to_prime(db: &RootDatabase, graph: &CrateGraph) -> FxHashSet<CrateId> {
+    // We're only interested in the workspace crates and the `ImportMap`s of their direct
+    // dependencies, though in practice the latter also compute the `DefMap`s.
+    // We don't prime transitive dependencies because they're generally not visible in
+    // the current workspace.
+    graph
+        .iter()
+        .filter(|&id| {
+            let file_id = graph[id].root_file_id;
+            let root_id = db.file_source_root(file_id);
+            !db.source_root(root_id).is_library
+        })
+        .flat_map(|id| graph[id].dependencies.iter().map(|krate| krate.crate_id))
+        .collect()
+}
diff --git a/crates/ide-diagnostics/src/handlers/unlinked_file.rs b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
index cbf50d13f5..15fb42e006 100644
--- a/crates/ide-diagnostics/src/handlers/unlinked_file.rs
+++ b/crates/ide-diagnostics/src/handlers/unlinked_file.rs
@@ -11,7 +11,7 @@ use ide_db::{
 use paths::Utf8Component;
 use syntax::{
     ast::{self, edit::IndentLevel, HasModuleItem, HasName},
-    AstNode, TextRange,
+    AstNode,
 };
 use text_edit::TextEdit;
 
@@ -35,27 +35,7 @@ pub(crate) fn unlinked_file(
         "file not included in module tree"
     };
 
-    let mut range = ctx.sema.db.parse(file_id).syntax_node().text_range();
-    let mut unused = true;
-
-    if fixes.is_none() {
-        // If we don't have a fix, the unlinked-file diagnostic is not
-        // actionable. This generally means that rust-analyzer hasn't
-        // finished startup, or we couldn't find the Cargo.toml.
-        //
-        // Only show this diagnostic on the first three characters of
-        // the file, to avoid overwhelming the user during startup.
-        range = FileLoader::file_text(ctx.sema.db, file_id)
-            .char_indices()
-            .take(3)
-            .last()
-            .map(|(i, _)| i)
-            .map(|i| TextRange::up_to(i.try_into().unwrap()))
-            .unwrap_or(range);
-        // Prefer a diagnostic underline over graying out the text,
-        // since we're only highlighting a small region.
-        unused = false;
-    }
+    let range = ctx.sema.db.parse(file_id).syntax_node().text_range();
 
     acc.push(
         Diagnostic::new(
@@ -63,7 +43,7 @@ pub(crate) fn unlinked_file(
             message,
             FileRange { file_id, range },
         )
-        .with_unused(unused)
+        .with_unused(true)
         .with_fixes(fixes),
     );
 }
diff --git a/crates/ide/src/extend_selection.rs b/crates/ide/src/extend_selection.rs
index e8d6dc9734..b706e959d3 100644
--- a/crates/ide/src/extend_selection.rs
+++ b/crates/ide/src/extend_selection.rs
@@ -210,13 +210,7 @@ fn extend_single_word_in_comment_or_string(
     let start_idx = before.rfind(non_word_char)? as u32;
     let end_idx = after.find(non_word_char).unwrap_or(after.len()) as u32;
 
-    // FIXME: use `ceil_char_boundary` from `std::str` when it gets stable
-    // https://github.com/rust-lang/rust/issues/93743
-    fn ceil_char_boundary(text: &str, index: u32) -> u32 {
-        (index..).find(|&index| text.is_char_boundary(index as usize)).unwrap_or(text.len() as u32)
-    }
-
-    let from: TextSize = ceil_char_boundary(text, start_idx + 1).into();
+    let from: TextSize = (start_idx + 1).into();
     let to: TextSize = (cursor_position + end_idx).into();
 
     let range = TextRange::new(from, to);
@@ -668,18 +662,4 @@ fn main() { let (
             ],
         );
     }
-
-    #[test]
-    fn extend_selection_inside_str_with_wide_char() {
-        // should not panic
-        do_check(
-            r#"fn main() { let x = "═$0═══════"; }"#,
-            &[
-                r#""════════""#,
-                r#"let x = "════════";"#,
-                r#"{ let x = "════════"; }"#,
-                r#"fn main() { let x = "════════"; }"#,
-            ],
-        );
-    }
 }
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 3f10bed511..e9c48ab1e7 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -455,23 +455,6 @@ fn ty_to_text_edit(
 // * elided lifetimes
 // * compiler inserted reborrows
 //
-// Note: inlay hints for function argument names are heuristically omitted to reduce noise and will not appear if
-// any of the
-// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L92-L99[following criteria]
-// are met:
-//
-// * the parameter name is a suffix of the function's name
-// * the argument is a qualified constructing or call expression where the qualifier is an ADT
-// * exact argument<->parameter match(ignoring leading underscore) or parameter is a prefix/suffix
-//   of argument with _ splitting it off
-// * the parameter name starts with `ra_fixture`
-// * the parameter name is a
-// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L200[well known name]
-// in a unary function
-// * the parameter name is a
-// link:https://github.com/rust-lang/rust-analyzer/blob/6b8b8ff4c56118ddee6c531cde06add1aad4a6af/crates/ide/src/inlay_hints/param_name.rs#L201[single character]
-// in a unary function
-//
 // image::https://user-images.githubusercontent.com/48062697/113020660-b5f98b80-917a-11eb-8d70-3be3fd558cdd.png[]
 pub(crate) fn inlay_hints(
     db: &RootDatabase,
diff --git a/crates/load-cargo/src/lib.rs b/crates/load-cargo/src/lib.rs
index de68b86714..cb785195a0 100644
--- a/crates/load-cargo/src/lib.rs
+++ b/crates/load-cargo/src/lib.rs
@@ -285,54 +285,28 @@ impl SourceRootConfig {
     /// If a `SourceRoot` doesn't have a parent and is local then it is not contained in this mapping but it can be asserted that it is a root `SourceRoot`.
     pub fn source_root_parent_map(&self) -> FxHashMap<SourceRootId, SourceRootId> {
         let roots = self.fsc.roots();
-
-        let mut map = FxHashMap::default();
-
-        // See https://github.com/rust-lang/rust-analyzer/issues/17409
-        //
-        // We can view the connections between roots as a graph. The problem is
-        // that this graph may contain cycles, so when adding edges, it is necessary
-        // to check whether it will lead to a cycle.
-        //
-        // Since we ensure that each node has at most one outgoing edge (because
-        // each SourceRoot can have only one parent), we can use a disjoint-set to
-        // maintain the connectivity between nodes. If an edge’s two nodes belong
-        // to the same set, they are already connected.
-        let mut dsu = FxHashMap::default();
-        fn find_parent(dsu: &mut FxHashMap<u64, u64>, id: u64) -> u64 {
-            if let Some(&parent) = dsu.get(&id) {
-                let parent = find_parent(dsu, parent);
-                dsu.insert(id, parent);
-                parent
-            } else {
-                id
-            }
-        }
-
-        for (idx, (root, root_id)) in roots.iter().enumerate() {
-            if !self.local_filesets.contains(root_id)
-                || map.contains_key(&SourceRootId(*root_id as u32))
-            {
-                continue;
-            }
-
-            for (root2, root2_id) in roots[..idx].iter().rev() {
-                if self.local_filesets.contains(root2_id)
-                    && root_id != root2_id
-                    && root.starts_with(root2)
-                {
-                    // check if the edge will create a cycle
-                    if find_parent(&mut dsu, *root_id) != find_parent(&mut dsu, *root2_id) {
-                        map.insert(SourceRootId(*root_id as u32), SourceRootId(*root2_id as u32));
-                        dsu.insert(*root_id, *root2_id);
+        roots
+            .iter()
+            .enumerate()
+            .filter(|(_, (_, id))| self.local_filesets.contains(id))
+            .filter_map(|(idx, (root, root_id))| {
+                // We are interested in parents if they are also local source roots.
+                // So instead of a non-local parent we may take a local ancestor as a parent to a node.
+                //
+                // Here paths in roots are sorted lexicographically, so if a root
+                // is a parent of another root, it will be before it in the list.
+                roots[..idx].iter().find_map(|(root2, root2_id)| {
+                    if self.local_filesets.contains(root2_id)
+                        && root.starts_with(root2)
+                        && root_id != root2_id
+                    {
+                        return Some((root_id, root2_id));
                     }
-
-                    break;
-                }
-            }
-        }
-
-        map
+                    None
+                })
+            })
+            .map(|(&child, &parent)| (SourceRootId(child as u32), SourceRootId(parent as u32)))
+            .collect()
     }
 }
 
@@ -618,20 +592,4 @@ mod tests {
 
         assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0)),])
     }
-
-    #[test]
-    fn circular_reference() {
-        let mut builder = FileSetConfigBuilder::default();
-        builder.add_file_set(vec![
-            VfsPath::new_virtual_path("/ROOT/def".to_owned()),
-            VfsPath::new_virtual_path("/ROOT/def/abc/def".to_owned()),
-        ]);
-        builder.add_file_set(vec![VfsPath::new_virtual_path("/ROOT/def/abc".to_owned())]);
-        let fsc = builder.build();
-        let src = SourceRootConfig { fsc, local_filesets: vec![0, 1] };
-        let mut vc = src.source_root_parent_map().into_iter().collect::<Vec<_>>();
-        vc.sort_by(|x, y| x.0 .0.cmp(&y.0 .0));
-
-        assert_eq!(vc, vec![(SourceRootId(1), SourceRootId(0)),])
-    }
 }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index e8504979be..ef890fa3e6 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -2531,6 +2531,7 @@ macro_rules! _impl_for_config_data {
                 #[allow(non_snake_case)]
                 $vis fn $field(&self, source_root: Option<SourceRootId>) -> &$ty {
                     let mut par: Option<SourceRootId> = source_root;
+                    let mut traversals = 0;
                     while let Some(source_root_id) = par {
                         par = self.source_root_parent_map.get(&source_root_id).copied();
                         if let Some((config, _)) = self.ratoml_files.get(&source_root_id) {
@@ -2538,6 +2539,14 @@ macro_rules! _impl_for_config_data {
                                 return value;
                             }
                         }
+                        // Prevent infinite loops caused by cycles by giving up when it's
+                        // clear that we must have either visited all source roots or
+                        // encountered a cycle.
+                        traversals += 1;
+                        if traversals >= self.source_root_parent_map.len() {
+                            // i.e. no source root contains the config we're looking for
+                            break;
+                        }
                     }
 
                     if let Some((root_path_ratoml, _)) = self.root_ratoml.as_ref() {
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index b5d816b0ce..cb23755861 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -442,7 +442,7 @@ fn api_walkthrough() {
     assert!(expr_syntax.siblings_with_tokens(Direction::Next).any(|it| it.kind() == T!['}']));
     assert_eq!(
         expr_syntax.descendants_with_tokens().count(),
-        8, // 5 tokens `1`, ` `, `+`, ` `, `1`
+        8, // 5 tokens `1`, ` `, `+`, ` `, `!`
            // 2 child literal expressions: `1`, `1`
            // 1 the node itself: `1 + 1`
     );
diff --git a/docs/dev/README.md b/docs/dev/README.md
index 002b8ba2a6..8897f02e27 100644
--- a/docs/dev/README.md
+++ b/docs/dev/README.md
@@ -145,7 +145,7 @@ To log all communication between the server and the client, there are two choice
   ```
   env RA_LOG=lsp_server=debug code .
   ```
-* You can log on the client side, by the `rust-analyzer: Toggle LSP Logs` command or enabling `"rust-analyzer.trace.server": "verbose"` workspace setting.
+* You can log on the client side, by enabling `"rust-analyzer.trace.server": "verbose"` workspace setting.
   These logs are shown in a separate tab in the output and could be used with LSP inspector.
   Kudos to [@DJMcNab](https://github.com/DJMcNab) for setting this awesome infra up!
 
diff --git a/docs/user/manual.adoc b/docs/user/manual.adoc
index e1c1c54ec4..8e6c53d0c5 100644
--- a/docs/user/manual.adoc
+++ b/docs/user/manual.adoc
@@ -21,7 +21,7 @@ The LSP allows various code editors, like VS Code, Emacs or Vim, to implement se
 To improve this document, send a pull request: +
 https://github.com/rust-lang/rust-analyzer/blob/master/docs/user/manual.adoc[https://github.com/rust-analyzer/.../manual.adoc]
 
-The manual is written in https://asciidoc.org[AsciiDoc] and includes some extra files which are generated from the source code. Run `cargo test` and `cargo xtask codegen` to create these and then `asciidoctor manual.adoc` to create an HTML copy.
+The manual is written in https://asciidoc.org[AsciiDoc] and includes some extra files which are generated from the source code. Run `cargo test` and `cargo test -p xtask` to create these and then `asciidoctor manual.adoc` to create an HTML copy.
 ====
 
 If you have questions about using rust-analyzer, please ask them in the https://users.rust-lang.org/c/ide/14["`IDEs and Editors`"] topic of Rust users forum.
@@ -591,7 +591,7 @@ The next thing to check would be panic messages in rust-analyzer's log.
 Log messages are printed to stderr, in VS Code you can see them in the `Output > Rust Analyzer Language Server` tab of the panel.
 To see more logs, set the `RA_LOG=info` environment variable, this can be done either by setting the environment variable manually or by using `rust-analyzer.server.extraEnv`, note that both of these approaches require the server to be restarted.
 
-To fully capture LSP messages between the editor and the server, run the `rust-analyzer: Toggle LSP Logs` command and check
+To fully capture LSP messages between the editor and the server, set `"rust-analyzer.trace.server": "verbose"` config and check
 `Output > Rust Analyzer Language Server Trace`.
 
 The root cause for many "`nothing works`" problems is that rust-analyzer fails to understand the project structure.
diff --git a/editors/code/package.json b/editors/code/package.json
index db2a989106..b447106d99 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -300,11 +300,6 @@
                 "command": "rust-analyzer.toggleCheckOnSave",
                 "title": "Toggle Check on Save",
                 "category": "rust-analyzer"
-            },
-            {
-                "command": "rust-analyzer.toggleLSPLogs",
-                "title": "Toggle LSP Logs",
-                "category": "rust-analyzer"
             }
         ],
         "keybindings": [
@@ -3128,10 +3123,6 @@
                 {
                     "command": "rust-analyzer.viewMemoryLayout",
                     "when": "inRustProject"
-                },
-                {
-                    "command": "rust-analyzer.toggleLSPLogs",
-                    "when": "inRustProject"
                 }
             ],
             "editor/context": [
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index f0f9fab1c6..c226aefeab 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -1489,16 +1489,3 @@ export function toggleCheckOnSave(ctx: Ctx): Cmd {
         ctx.refreshServerStatus();
     };
 }
-
-export function toggleLSPLogs(ctx: Ctx): Cmd {
-    return async () => {
-        const config = vscode.workspace.getConfiguration("rust-analyzer");
-        const targetValue =
-            config.get<string | undefined>("trace.server") === "verbose" ? undefined : "verbose";
-
-        await config.update("trace.server", targetValue, vscode.ConfigurationTarget.Workspace);
-        if (targetValue && ctx.client && ctx.client.traceOutputChannel) {
-            ctx.client.traceOutputChannel.show();
-        }
-    };
-}
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index a9bf54c776..788f9a0c14 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -177,7 +177,6 @@ function createCommands(): Record<string, CommandFactory> {
         serverVersion: { enabled: commands.serverVersion },
         viewMemoryLayout: { enabled: commands.viewMemoryLayout },
         toggleCheckOnSave: { enabled: commands.toggleCheckOnSave },
-        toggleLSPLogs: { enabled: commands.toggleLSPLogs },
         // Internal commands which are invoked by the server.
         applyActionGroup: { enabled: commands.applyActionGroup },
         applySnippetWorkspaceEdit: { enabled: commands.applySnippetWorkspaceEditCommand },
diff --git a/rust-version b/rust-version
index c605feb6ee..207ef6c5de 100644
--- a/rust-version
+++ b/rust-version
@@ -1,1 +1,1 @@
-3d5d7a24f76006b391d8a53d903ae64c1b4a52d2
+6579ed89f0fcc26da71afdd11d30d63f6f812a0a


Test patch:
diff --git a/crates/ide-completion/src/tests/expression.rs b/crates/ide-completion/src/tests/expression.rs
index 545c2a2a8a..a653314233 100644
--- a/crates/ide-completion/src/tests/expression.rs
+++ b/crates/ide-completion/src/tests/expression.rs
@@ -141,7 +141,6 @@ impl Unit {
             un Union        Union
             ev TupleV(…)    TupleV(u32)
             bt u32          u32
-            kw async
             kw const
             kw crate::
             kw enum
@@ -218,7 +217,6 @@ fn complete_in_block() {
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw enum
@@ -266,7 +264,6 @@ fn complete_after_if_expr() {
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw else
@@ -339,7 +336,6 @@ fn completes_in_loop_ctx() {
         expect![[r#"
             fn my()        fn()
             bt u32         u32
-            kw async
             kw break
             kw const
             kw continue
@@ -803,7 +799,6 @@ fn foo() { if foo {} $0 }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw else
@@ -844,7 +839,6 @@ fn foo() { if foo {} el$0 }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw else
@@ -933,7 +927,6 @@ fn foo() { if foo {} $0 let x = 92; }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw else
@@ -974,7 +967,6 @@ fn foo() { if foo {} el$0 let x = 92; }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw else
@@ -1015,7 +1007,6 @@ fn foo() { if foo {} el$0 { let x = 92; } }
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw else
@@ -1068,7 +1059,6 @@ pub struct UnstableThisShouldNotBeListed;
             fn main()      fn()
             md std
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw enum
@@ -1121,7 +1111,6 @@ pub struct UnstableButWeAreOnNightlyAnyway;
             md std
             st UnstableButWeAreOnNightlyAnyway UnstableButWeAreOnNightlyAnyway
             bt u32                    u32
-            kw async
             kw const
             kw crate::
             kw enum
diff --git a/crates/ide-completion/src/tests/item.rs b/crates/ide-completion/src/tests/item.rs
index 09254aed7c..de3fd05189 100644
--- a/crates/ide-completion/src/tests/item.rs
+++ b/crates/ide-completion/src/tests/item.rs
@@ -6,8 +6,6 @@ use expect_test::{expect, Expect};
 
 use crate::tests::{completion_list, BASE_ITEMS_FIXTURE};
 
-use super::check_edit;
-
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(&format!("{BASE_ITEMS_FIXTURE}{ra_fixture}"));
     expect.assert_eq(&actual)
@@ -154,90 +152,3 @@ struct Foo {
         "#]],
     )
 }
-
-#[test]
-fn add_space_after_vis_kw() {
-    check_edit(
-        "pub(crate)",
-        r"
-$0
-",
-        r#"
-pub(crate) $0
-"#,
-    );
-
-    check_edit(
-        "pub",
-        r"
-$0
-",
-        r#"
-pub $0
-"#,
-    );
-
-    check_edit(
-        "pub(super)",
-        r"
-$0
-",
-        r#"
-pub(super) $0
-"#,
-    );
-
-    check_edit(
-        "in",
-        r"
-pub($0)
-",
-        r#"
-pub(in $0)
-"#,
-    );
-}
-
-#[test]
-fn add_space_after_unsafe_kw() {
-    check_edit(
-        "unsafe",
-        r"
-$0
-",
-        r#"
-unsafe $0
-"#,
-    );
-}
-
-#[test]
-fn add_space_after_for_where_kw() {
-    check_edit(
-        "for",
-        r#"
-struct S {}
-
-impl Copy $0
-"#,
-        r#"
-struct S {}
-
-impl Copy for $0
-"#,
-    );
-
-    check_edit(
-        "where",
-        r#"
-struct S {}
-
-impl Copy for S $0
-"#,
-        r#"
-struct S {}
-
-impl Copy for S where $0
-"#,
-    );
-}
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs
index c37900478e..2b5b4dd773 100644
--- a/crates/ide-completion/src/tests/item_list.rs
+++ b/crates/ide-completion/src/tests/item_list.rs
@@ -14,7 +14,6 @@ fn in_mod_item_list() {
         r#"mod tests { $0 }"#,
         expect![[r#"
             ma makro!(…)           macro_rules! makro
-            kw async
             kw const
             kw crate::
             kw enum
@@ -48,7 +47,6 @@ fn in_source_file_item_list() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             md module
-            kw async
             kw const
             kw crate::
             kw enum
@@ -81,7 +79,6 @@ fn in_item_list_after_attr() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             md module
-            kw async
             kw const
             kw crate::
             kw enum
@@ -135,7 +132,6 @@ fn after_visibility() {
     check(
         r#"pub $0"#,
         expect![[r#"
-            kw async
             kw const
             kw enum
             kw extern
@@ -360,7 +356,6 @@ fn after_unit_struct() {
         expect![[r#"
             ma makro!(…)           macro_rules! makro
             md module
-            kw async
             kw const
             kw crate::
             kw enum
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index 8720cb555a..67cf551fce 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -819,34 +819,3 @@ pub enum Enum {
         "#]],
     );
 }
-
-#[test]
-fn add_space_after_mut_ref_kw() {
-    check_edit(
-        "mut",
-        r#"
-fn foo() {
-    let $0
-}
-"#,
-        r#"
-fn foo() {
-    let mut $0
-}
-"#,
-    );
-
-    check_edit(
-        "ref",
-        r#"
-fn foo() {
-    let $0
-}
-"#,
-        r#"
-fn foo() {
-    let ref $0
-}
-"#,
-    );
-}
diff --git a/crates/ide-completion/src/tests/record.rs b/crates/ide-completion/src/tests/record.rs
index 56162bb57b..e64ec74c61 100644
--- a/crates/ide-completion/src/tests/record.rs
+++ b/crates/ide-completion/src/tests/record.rs
@@ -2,8 +2,6 @@ use expect_test::{expect, Expect};
 
 use crate::tests::completion_list;
 
-use super::check_edit;
-
 fn check(ra_fixture: &str, expect: Expect) {
     let actual = completion_list(ra_fixture);
     expect.assert_eq(&actual);
@@ -303,48 +301,3 @@ fn foo() {
         expect![[r#""#]],
     )
 }
-
-#[test]
-fn add_space_after_vis_kw() {
-    check_edit(
-        "pub(crate)",
-        r"
-pub(crate) struct S {
-    $0
-}
-",
-        r#"
-pub(crate) struct S {
-    pub(crate) $0
-}
-"#,
-    );
-
-    check_edit(
-        "pub",
-        r"
-pub struct S {
-    $0
-}
-",
-        r#"
-pub struct S {
-    pub $0
-}
-"#,
-    );
-
-    check_edit(
-        "pub(super)",
-        r"
-pub(super) struct S {
-    $0
-}
-",
-        r#"
-pub(super) struct S {
-    pub(super) $0
-}
-"#,
-    );
-}
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 2ae7d37889..69d8fe9104 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -1017,7 +1017,6 @@ fn here_we_go() {
             fn here_we_go()    fn()
             st Foo (alias Bar) Foo
             bt u32             u32
-            kw async
             kw const
             kw crate::
             kw enum
@@ -1067,7 +1066,6 @@ fn here_we_go() {
             fn here_we_go()           fn()
             st Foo (alias Bar, Qux, Baz) Foo
             bt u32                    u32
-            kw async
             kw const
             kw crate::
             kw enum
@@ -1190,7 +1188,6 @@ fn bar() { qu$0 }
             fn bar()             fn()
             fn foo() (alias qux) fn()
             bt u32               u32
-            kw async
             kw const
             kw crate::
             kw enum
@@ -1446,7 +1443,6 @@ fn foo() {
         expect![[r#"
             fn foo()       fn()
             bt u32         u32
-            kw async
             kw const
             kw crate::
             kw enum