Repository: rust-lang/rust-analyzer
Pull request #18050 (2024-09-04 16:21:21)

assist: ensure `replace_qualified_name_with_use` applies to the first path segment
This change helps a bit with the discoverability of `replace_qualified_name_with_use`. Specifically, it ensures that a cursor on the first path segment (e.g., `$0std::fmt::Debug`, where `$0` is the cursor) would result in an import along the lines of `use std::fmt;` and `fmt::Debug;` at the usage sites.


Patch:
diff --git a/crates/hir-expand/src/builtin/fn_macro.rs b/crates/hir-expand/src/builtin/fn_macro.rs
index d04225b872..15fed45caf 100644
--- a/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/crates/hir-expand/src/builtin/fn_macro.rs
@@ -483,7 +483,7 @@ fn concat_expand(
                 match it.kind {
                     tt::LitKind::Char => {
                         if let Ok(c) = unescape_char(it.symbol.as_str()) {
-                            text.push(c);
+                            text.extend(c.escape_default());
                         }
                         record_span(it.span);
                     }
@@ -491,11 +491,11 @@ fn concat_expand(
                         format_to!(text, "{}", it.symbol.as_str())
                     }
                     tt::LitKind::Str => {
-                        text.push_str(unescape_str(&it.symbol).as_str());
+                        text.push_str(it.symbol.as_str());
                         record_span(it.span);
                     }
                     tt::LitKind::StrRaw(_) => {
-                        format_to!(text, "{}", it.symbol.as_str());
+                        format_to!(text, "{}", it.symbol.as_str().escape_debug());
                         record_span(it.span);
                     }
                     tt::LitKind::Byte
@@ -813,7 +813,7 @@ fn include_str_expand(
 
 fn get_env_inner(db: &dyn ExpandDatabase, arg_id: MacroCallId, key: &Symbol) -> Option<String> {
     let krate = db.lookup_intern_macro_call(arg_id).krate;
-    db.crate_graph()[krate].env.get(key.as_str())
+    db.crate_graph()[krate].env.get(key.as_str()).map(|it| it.escape_debug().to_string())
 }
 
 fn env_expand(
diff --git a/crates/hir-expand/src/builtin/quote.rs b/crates/hir-expand/src/builtin/quote.rs
index fc248c906d..5c33f817f9 100644
--- a/crates/hir-expand/src/builtin/quote.rs
+++ b/crates/hir-expand/src/builtin/quote.rs
@@ -3,7 +3,6 @@
 
 use intern::{sym, Symbol};
 use span::Span;
-use syntax::ToSmolStr;
 use tt::IdentIsRaw;
 
 use crate::name::Name;
@@ -212,8 +211,8 @@ impl_to_to_tokentrees! {
     _span: crate::tt::Literal => self { self };
     _span: crate::tt::Ident => self { self };
     _span: crate::tt::Punct => self { self };
-    span: &str => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }};
-    span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self.escape_default().to_smolstr()), span, kind: tt::LitKind::Str, suffix: None }};
+    span: &str => self { crate::tt::Literal{symbol: Symbol::intern(self), span, kind: tt::LitKind::Str, suffix: None }};
+    span: String => self { crate::tt::Literal{symbol: Symbol::intern(&self), span, kind: tt::LitKind::Str, suffix: None }};
     span: Name => self {
         let (is_raw, s) = IdentIsRaw::split_from_symbol(self.as_str());
         crate::tt::Ident{sym: Symbol::intern(s), span, is_raw }
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index caa3960a22..ae91404436 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -120,13 +120,6 @@ impl CastCheck {
             });
         }
 
-        // Chalk doesn't support trait upcasting and fails to solve some obvious goals
-        // when the trait environment contains some recursive traits (See issue #18047)
-        // We skip cast checks for such cases for now, until the next-gen solver.
-        if contains_dyn_trait(&self.cast_ty) {
-            return Ok(());
-        }
-
         if let Ok((adj, _)) = table.coerce(&self.expr_ty, &self.cast_ty) {
             apply_adjustments(self.source_expr, adj);
             set_coercion_cast(self.source_expr);
@@ -417,35 +410,3 @@ fn pointer_kind(ty: &Ty, table: &mut InferenceTable<'_>) -> Result<Option<Pointe
         }
     }
 }
-
-fn contains_dyn_trait(ty: &Ty) -> bool {
-    use std::ops::ControlFlow;
-
-    use chalk_ir::{
-        visit::{TypeSuperVisitable, TypeVisitable, TypeVisitor},
-        DebruijnIndex,
-    };
-
-    struct DynTraitVisitor;
-
-    impl TypeVisitor<Interner> for DynTraitVisitor {
-        type BreakTy = ();
-
-        fn as_dyn(&mut self) -> &mut dyn TypeVisitor<Interner, BreakTy = Self::BreakTy> {
-            self
-        }
-
-        fn interner(&self) -> Interner {
-            Interner
-        }
-
-        fn visit_ty(&mut self, ty: &Ty, outer_binder: DebruijnIndex) -> ControlFlow<Self::BreakTy> {
-            match ty.kind(Interner) {
-                TyKind::Dyn(_) => ControlFlow::Break(()),
-                _ => ty.super_visit_with(self.as_dyn(), outer_binder),
-            }
-        }
-    }
-
-    ty.visit_with(DynTraitVisitor.as_dyn(), DebruijnIndex::INNERMOST).is_break()
-}
diff --git a/crates/hir-ty/src/infer/unify.rs b/crates/hir-ty/src/infer/unify.rs
index d38380e4a3..99ad678980 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -902,10 +902,6 @@ impl<'a> InferenceTable<'a> {
 
     /// Check if given type is `Sized` or not
     pub(crate) fn is_sized(&mut self, ty: &Ty) -> bool {
-        // Early return for some obvious types
-        if matches!(ty.kind(Interner), TyKind::Scalar(..) | TyKind::Ref(..) | TyKind::Raw(..)) {
-            return true;
-        }
         if let Some((AdtId::StructId(id), subst)) = ty.as_adt() {
             let struct_data = self.db.struct_data(id);
             if let Some((last_field, _)) = struct_data.variant_data.fields().iter().last() {
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e3bd756208..3b8b901fa1 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2553,17 +2553,6 @@ impl Const {
         Type::from_value_def(db, self.id)
     }
 
-    /// Evaluate the constant and return the result as a string.
-    ///
-    /// This function is intended for IDE assistance, different from [`Const::render_eval`].
-    pub fn eval(self, db: &dyn HirDatabase, edition: Edition) -> Result<String, ConstEvalError> {
-        let c = db.const_eval(self.id.into(), Substitution::empty(Interner), None)?;
-        Ok(format!("{}", c.display(db, edition)))
-    }
-
-    /// Evaluate the constant and return the result as a string, with more detailed information.
-    ///
-    /// This function is intended for user-facing display.
     pub fn render_eval(
         self,
         db: &dyn HirDatabase,
diff --git a/crates/ide-assists/src/handlers/inline_const_as_literal.rs b/crates/ide-assists/src/handlers/inline_const_as_literal.rs
index 6b504a918b..f1c2acdd3e 100644
--- a/crates/ide-assists/src/handlers/inline_const_as_literal.rs
+++ b/crates/ide-assists/src/handlers/inline_const_as_literal.rs
@@ -53,7 +53,10 @@ pub(crate) fn inline_const_as_literal(acc: &mut Assists, ctx: &AssistContext<'_>
             | ast::Expr::BinExpr(_)
             | ast::Expr::CallExpr(_) => {
                 let edition = ctx.sema.scope(variable.syntax())?.krate().edition(ctx.db());
-                konst.eval(ctx.sema.db, edition).ok()?
+                match konst.render_eval(ctx.sema.db, edition) {
+                    Ok(result) => result,
+                    Err(_) => return None,
+                }
             }
             _ => return None,
         };
@@ -124,14 +127,12 @@ mod tests {
         ("u64", "0", NUMBER),
         ("u128", "0", NUMBER),
         ("usize", "0", NUMBER),
-        ("usize", "16", NUMBER),
         ("i8", "0", NUMBER),
         ("i16", "0", NUMBER),
         ("i32", "0", NUMBER),
         ("i64", "0", NUMBER),
         ("i128", "0", NUMBER),
         ("isize", "0", NUMBER),
-        ("isize", "16", NUMBER),
         ("bool", "false", BOOL),
         ("&str", "\"str\"", STR),
         ("char", "'c'", CHAR),
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index f2c360a9d5..d55bc3ea5d 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -600,7 +600,7 @@ fn foo(a: A) { a.$0 }
 struct A {}
 trait Trait { fn the_method(&self); }
 impl Trait for A {}
-fn foo(a: A) { a.the_method();$0 }
+fn foo(a: A) { a.the_method()$0 }
 "#,
         );
     }
diff --git a/crates/ide-completion/src/config.rs b/crates/ide-completion/src/config.rs
index 0d403f49b7..d885b82ec9 100644
--- a/crates/ide-completion/src/config.rs
+++ b/crates/ide-completion/src/config.rs
@@ -19,7 +19,6 @@ pub struct CompletionConfig {
     pub term_search_fuel: u64,
     pub full_function_signatures: bool,
     pub callable: Option<CallableSnippets>,
-    pub add_semicolon_to_unit: bool,
     pub snippet_cap: Option<SnippetCap>,
     pub insert_use: InsertUseConfig,
     pub prefer_no_std: bool,
diff --git a/crates/ide-completion/src/render.rs b/crates/ide-completion/src/render.rs
index f2e9de9382..2bec2eb87b 100644
--- a/crates/ide-completion/src/render.rs
+++ b/crates/ide-completion/src/render.rs
@@ -1185,7 +1185,7 @@ fn main() { fo$0 }
                         label: "main()",
                         source_range: 68..70,
                         delete: 68..70,
-                        insert: "main();$0",
+                        insert: "main()$0",
                         kind: SymbolKind(
                             Function,
                         ),
@@ -1244,7 +1244,7 @@ fn main() { let _: m::Spam = S$0 }
                         label: "main()",
                         source_range: 75..76,
                         delete: 75..76,
-                        insert: "main();$0",
+                        insert: "main()$0",
                         kind: SymbolKind(
                             Function,
                         ),
@@ -1331,7 +1331,7 @@ fn main() { som$0 }
                         label: "main()",
                         source_range: 56..59,
                         delete: 56..59,
-                        insert: "main();$0",
+                        insert: "main()$0",
                         kind: SymbolKind(
                             Function,
                         ),
@@ -1342,7 +1342,7 @@ fn main() { som$0 }
                         label: "something_deprecated()",
                         source_range: 56..59,
                         delete: 56..59,
-                        insert: "something_deprecated();$0",
+                        insert: "something_deprecated()$0",
                         kind: SymbolKind(
                             Function,
                         ),
@@ -1413,7 +1413,7 @@ impl S {
                         label: "bar()",
                         source_range: 94..94,
                         delete: 94..94,
-                        insert: "bar();$0",
+                        insert: "bar()$0",
                         kind: SymbolKind(
                             Method,
                         ),
@@ -1540,7 +1540,7 @@ fn foo(s: S) { s.$0 }
                         label: "the_method()",
                         source_range: 81..81,
                         delete: 81..81,
-                        insert: "the_method();$0",
+                        insert: "the_method()$0",
                         kind: SymbolKind(
                             Method,
                         ),
@@ -2789,7 +2789,7 @@ fn main() {
             r#"
 mod m { pub fn r#type {} }
 fn main() {
-    m::r#type();$0
+    m::r#type()$0
 }
 "#,
         )
@@ -2963,7 +2963,7 @@ fn main() {
                         label: "flush()",
                         source_range: 193..193,
                         delete: 193..193,
-                        insert: "flush();$0",
+                        insert: "flush()$0",
                         kind: SymbolKind(
                             Method,
                         ),
@@ -2990,7 +2990,7 @@ fn main() {
                         label: "write()",
                         source_range: 193..193,
                         delete: 193..193,
-                        insert: "write();$0",
+                        insert: "write()$0",
                         kind: SymbolKind(
                             Method,
                         ),
diff --git a/crates/ide-completion/src/render/function.rs b/crates/ide-completion/src/render/function.rs
index 7e5e69665f..29820cb203 100644
--- a/crates/ide-completion/src/render/function.rs
+++ b/crates/ide-completion/src/render/function.rs
@@ -1,12 +1,10 @@
 //! Renderer for function calls.
 
-use std::ops::ControlFlow;
-
 use hir::{db::HirDatabase, AsAssocItem, HirDisplay};
 use ide_db::{SnippetCap, SymbolKind};
 use itertools::Itertools;
 use stdx::{format_to, to_lower_snake_case};
-use syntax::{ast, format_smolstr, AstNode, Edition, SmolStr, SyntaxKind, ToSmolStr, T};
+use syntax::{format_smolstr, AstNode, Edition, SmolStr, ToSmolStr};
 
 use crate::{
     context::{CompletionContext, DotAccess, DotAccessKind, PathCompletionCtx, PathKind},
@@ -162,16 +160,7 @@ fn render(
         .lookup_by(name.unescaped().display(db).to_smolstr());
 
     if let Some((cap, (self_param, params))) = complete_call_parens {
-        add_call_parens(
-            &mut item,
-            completion,
-            cap,
-            call,
-            escaped_call,
-            self_param,
-            params,
-            &ret_type,
-        );
+        add_call_parens(&mut item, completion, cap, call, escaped_call, self_param, params);
     }
 
     match ctx.import_to_add {
@@ -228,11 +217,10 @@ pub(super) fn add_call_parens<'b>(
     escaped_name: SmolStr,
     self_param: Option<hir::SelfParam>,
     params: Vec<hir::Param>,
-    ret_type: &hir::Type,
 ) -> &'b mut Builder {
     cov_mark::hit!(inserts_parens_for_function_calls);
 
-    let (mut snippet, label_suffix) = if self_param.is_none() && params.is_empty() {
+    let (snippet, label_suffix) = if self_param.is_none() && params.is_empty() {
         (format!("{escaped_name}()$0"), "()")
     } else {
         builder.trigger_call_info();
@@ -277,35 +265,6 @@ pub(super) fn add_call_parens<'b>(
 
         (snippet, "(…)")
     };
-    if ret_type.is_unit() && ctx.config.add_semicolon_to_unit {
-        let next_non_trivia_token =
-            std::iter::successors(ctx.token.next_token(), |it| it.next_token())
-                .find(|it| !it.kind().is_trivia());
-        let in_match_arm = ctx.token.parent_ancestors().try_for_each(|ancestor| {
-            if ast::MatchArm::can_cast(ancestor.kind()) {
-                ControlFlow::Break(true)
-            } else if matches!(ancestor.kind(), SyntaxKind::EXPR_STMT | SyntaxKind::BLOCK_EXPR) {
-                ControlFlow::Break(false)
-            } else {
-                ControlFlow::Continue(())
-            }
-        });
-        // FIXME: This will assume expr macros are not inside match, we need to somehow go to the "parent" of the root node.
-        let in_match_arm = match in_match_arm {
-            ControlFlow::Continue(()) => false,
-            ControlFlow::Break(it) => it,
-        };
-        let complete_token = if in_match_arm { T![,] } else { T![;] };
-        if next_non_trivia_token.map(|it| it.kind()) != Some(complete_token) {
-            cov_mark::hit!(complete_semicolon);
-            let ch = if in_match_arm { ',' } else { ';' };
-            if snippet.ends_with("$0") {
-                snippet.insert(snippet.len() - "$0".len(), ch);
-            } else {
-                snippet.push(ch);
-            }
-        }
-    }
     builder.label(SmolStr::from_iter([&name, label_suffix])).insert_snippet(cap, snippet)
 }
 
@@ -434,7 +393,7 @@ fn main() { no_$0 }
 "#,
             r#"
 fn no_args() {}
-fn main() { no_args();$0 }
+fn main() { no_args()$0 }
 "#,
         );
 
@@ -446,7 +405,7 @@ fn main() { with_$0 }
 "#,
             r#"
 fn with_args(x: i32, y: String) {}
-fn main() { with_args(${1:x}, ${2:y});$0 }
+fn main() { with_args(${1:x}, ${2:y})$0 }
 "#,
         );
 
@@ -455,14 +414,14 @@ fn main() { with_args(${1:x}, ${2:y});$0 }
             r#"
 struct S;
 impl S {
-    fn foo(&self) -> i32 { 0 }
+    fn foo(&self) {}
 }
 fn bar(s: &S) { s.f$0 }
 "#,
             r#"
 struct S;
 impl S {
-    fn foo(&self) -> i32 { 0 }
+    fn foo(&self) {}
 }
 fn bar(s: &S) { s.foo()$0 }
 "#,
@@ -485,7 +444,7 @@ impl S {
     fn foo(&self, x: i32) {}
 }
 fn bar(s: &S) {
-    s.foo(${1:x});$0
+    s.foo(${1:x})$0
 }
 "#,
         );
@@ -504,7 +463,7 @@ impl S {
 struct S {}
 impl S {
     fn foo(&self, x: i32) {
-        self.foo(${1:x});$0
+        self.foo(${1:x})$0
     }
 }
 "#,
@@ -527,7 +486,7 @@ struct S;
 impl S {
     fn foo(&self) {}
 }
-fn main() { S::foo(${1:&self});$0 }
+fn main() { S::foo(${1:&self})$0 }
 "#,
         );
     }
@@ -544,7 +503,7 @@ fn main() { with_$0 }
 "#,
             r#"
 fn with_args(x: i32, y: String) {}
-fn main() { with_args($0); }
+fn main() { with_args($0) }
 "#,
         );
     }
@@ -559,7 +518,7 @@ fn main() { f$0 }
 "#,
             r#"
 fn foo(_foo: i32, ___bar: bool, ho_ge_: String) {}
-fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_});$0 }
+fn main() { foo(${1:foo}, ${2:bar}, ${3:ho_ge_})$0 }
 "#,
         );
     }
@@ -581,7 +540,7 @@ struct Foo {}
 fn ref_arg(x: &Foo) {}
 fn main() {
     let x = Foo {};
-    ref_arg(${1:&x});$0
+    ref_arg(${1:&x})$0
 }
 "#,
         );
@@ -604,7 +563,7 @@ struct Foo {}
 fn ref_arg(x: &mut Foo) {}
 fn main() {
     let x = Foo {};
-    ref_arg(${1:&mut x});$0
+    ref_arg(${1:&mut x})$0
 }
 "#,
         );
@@ -637,7 +596,7 @@ impl Bar {
 fn main() {
     let x = Foo {};
     let y = Bar {};
-    y.apply_foo(${1:&x});$0
+    y.apply_foo(${1:&x})$0
 }
 "#,
         );
@@ -658,7 +617,7 @@ fn main() {
 fn take_mutably(mut x: &i32) {}
 
 fn main() {
-    take_mutably(${1:x});$0
+    take_mutably(${1:x})$0
 }
 "#,
         );
@@ -691,7 +650,7 @@ fn qux(Foo { bar }: Foo) {
 }
 
 fn main() {
-  qux(${1:foo});$0
+  qux(${1:foo})$0
 }
 "#,
         );
@@ -777,115 +736,6 @@ fn g(foo: ()#[baz = "qux"] mut ba$0)
             r#"
 fn f(foo: (), #[baz = "qux"] mut bar: u32) {}
 fn g(foo: (), #[baz = "qux"] mut bar: u32)
-"#,
-        );
-    }
-
-    #[test]
-    fn complete_semicolon_for_unit() {
-        cov_mark::check!(complete_semicolon);
-        check_edit(
-            r#"foo"#,
-            r#"
-fn foo() {}
-fn bar() {
-    foo$0
-}
-"#,
-            r#"
-fn foo() {}
-fn bar() {
-    foo();$0
-}
-"#,
-        );
-        check_edit(
-            r#"foo"#,
-            r#"
-fn foo(a: i32) {}
-fn bar() {
-    foo$0
-}
-"#,
-            r#"
-fn foo(a: i32) {}
-fn bar() {
-    foo(${1:a});$0
-}
-"#,
-        );
-        check_edit(
-            r#"foo"#,
-            r#"
-fn foo(a: i32) {}
-fn bar() {
-    foo$0;
-}
-"#,
-            r#"
-fn foo(a: i32) {}
-fn bar() {
-    foo(${1:a})$0;
-}
-"#,
-        );
-        check_edit_with_config(
-            CompletionConfig { add_semicolon_to_unit: false, ..TEST_CONFIG },
-            r#"foo"#,
-            r#"
-fn foo(a: i32) {}
-fn bar() {
-    foo$0
-}
-"#,
-            r#"
-fn foo(a: i32) {}
-fn bar() {
-    foo(${1:a})$0
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn complete_comma_for_unit_match_arm() {
-        cov_mark::check!(complete_semicolon);
-        check_edit(
-            r#"foo"#,
-            r#"
-fn foo() {}
-fn bar() {
-    match Some(false) {
-        v => fo$0
-    }
-}
-"#,
-            r#"
-fn foo() {}
-fn bar() {
-    match Some(false) {
-        v => foo(),$0
-    }
-}
-"#,
-        );
-        check_edit(
-            r#"foo"#,
-            r#"
-fn foo() {}
-fn bar() {
-    match Some(false) {
-        v => fo$0,
-    }
-}
-"#,
-            r#"
-fn foo() {}
-fn bar() {
-    match Some(false) {
-        v => foo()$0,
-    }
-}
 "#,
         );
     }
diff --git a/crates/ide-db/src/syntax_helpers/suggest_name.rs b/crates/ide-db/src/syntax_helpers/suggest_name.rs
index e60deb3bf5..6ee526a67e 100644
--- a/crates/ide-db/src/syntax_helpers/suggest_name.rs
+++ b/crates/ide-db/src/syntax_helpers/suggest_name.rs
@@ -18,9 +18,7 @@ const USELESS_TRAITS: &[&str] = &["Send", "Sync", "Copy", "Clone", "Eq", "Partia
 ///
 /// **NOTE**: they all must be snake lower case
 const USELESS_NAMES: &[&str] =
-    &["new", "default", "option", "some", "none", "ok", "err", "str", "string", "from", "into"];
-
-const USELESS_NAME_PREFIXES: &[&str] = &["from_", "with_", "into_"];
+    &["new", "default", "option", "some", "none", "ok", "err", "str", "string"];
 
 /// Generic types replaced by their first argument
 ///
@@ -191,10 +189,6 @@ fn normalize(name: &str) -> Option<String> {
         return None;
     }
 
-    if USELESS_NAME_PREFIXES.iter().any(|prefix| name.starts_with(prefix)) {
-        return None;
-    }
-
     if !is_valid_name(&name) {
         return None;
     }
@@ -837,92 +831,4 @@ fn foo<T>(some_struct: S<T>) { $0some_struct.some_field$0 }
             "some_field",
         );
     }
-
-    #[test]
-    fn from_and_to_func() {
-        check(
-            r#"
-//- minicore: from
-struct Foo;
-struct Bar;
-
-impl From<Foo> for Bar {
-    fn from(_: Foo) -> Self {
-        Bar;
-    }
-}
-
-fn f(_: Bar) {}
-
-fn main() {
-    let foo = Foo {};
-    f($0Bar::from(foo)$0);
-}
-"#,
-            "bar",
-        );
-
-        check(
-            r#"
-//- minicore: from
-struct Foo;
-struct Bar;
-
-impl From<Foo> for Bar {
-    fn from(_: Foo) -> Self {
-        Bar;
-    }
-}
-
-fn f(_: Bar) {}
-
-fn main() {
-    let foo = Foo {};
-    f($0Into::<Bar>::into(foo)$0);
-}
-"#,
-            "bar",
-        );
-    }
-
-    #[test]
-    fn useless_name_prefix() {
-        check(
-            r#"
-struct Foo;
-struct Bar;
-
-impl Bar {
-    fn from_foo(_: Foo) -> Self {
-        Foo {}
-    }
-}
-
-fn main() {
-    let foo = Foo {};
-    let _ = $0Bar::from_foo(foo)$0;
-}
-"#,
-            "bar",
-        );
-
-        check(
-            r#"
-struct Foo;
-struct Bar;
-
-impl Bar {
-    fn with_foo(_: Foo) -> Self {
-        Bar {}
-    }
-}
-
-fn main() {
-    let foo = Foo {};
-    let _ = $0Bar::with_foo(foo)$0;
-}
-"#,
-            "bar",
-        );
-    }
 }
diff --git a/crates/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 90527c578e..9eb4e618c0 100644
--- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -556,7 +556,6 @@ fn unprincipled<'a, 'b>(x: *mut (dyn Send + 'a)) -> *mut (dyn Sync + 'b) {
         );
     }
 
-    #[ignore = "issue #18047"]
     #[test]
     fn ptr_to_trait_obj_wrap_upcast() {
         check_diagnostics(
@@ -1005,99 +1004,4 @@ fn _slice(bar: &[i32]) -> bool {
             &["E0308"],
         );
     }
-
-    #[test]
-    fn trait_upcasting() {
-        check_diagnostics(
-            r#"
-//- minicore: coerce_unsized, dispatch_from_dyn
-#![feature(trait_upcasting)]
-trait Foo {}
-trait Bar: Foo {}
-
-impl dyn Bar {
-    fn bar(&self) {
-        _ = self as &dyn Foo;
-    }
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn issue_18047() {
-        check_diagnostics(
-            r#"
-//- minicore: coerce_unsized, dispatch_from_dyn
-trait LocalFrom<T> {
-    fn from(_: T) -> Self;
-}
-trait LocalInto<T> {
-    fn into(self) -> T;
-}
-
-impl<T, U> LocalInto<U> for T
-where
-    U: LocalFrom<T>,
-{
-    fn into(self) -> U {
-        U::from(self)
-    }
-}
-
-impl<T> LocalFrom<T> for T {
-    fn from(t: T) -> T {
-        t
-    }
-}
-
-trait Foo {
-    type ErrorType;
-    type Assoc;
-}
-
-trait Bar {
-    type ErrorType;
-}
-
-struct ErrorLike;
-
-impl<E> LocalFrom<E> for ErrorLike
-where
-    E: Trait + 'static,
-{
-    fn from(_: E) -> Self {
-        loop {}
-    }
-}
-
-trait Baz {
-    type Assoc: Bar;
-    type Error: LocalInto<ErrorLike>;
-}
-
-impl<T, U> Baz for T
-where
-    T: Foo<Assoc = U>,
-    T::ErrorType: LocalInto<ErrorLike>,
-    U: Bar,
-    <U as Bar>::ErrorType: LocalInto<ErrorLike>,
-{
-    type Assoc = U;
-    type Error = T::ErrorType;
-}
-struct S;
-trait Trait {}
-impl Trait for S {}
-
-fn test<T>()
-where
-    T: Baz,
-    T::Assoc: 'static,
-{
-    let _ = &S as &dyn Trait;
-}
-"#,
-        );
-    }
 }
diff --git a/crates/rust-analyzer/src/bin/main.rs b/crates/rust-analyzer/src/bin/main.rs
index 41b42573f0..21b481c1fa 100644
--- a/crates/rust-analyzer/src/bin/main.rs
+++ b/crates/rust-analyzer/src/bin/main.rs
@@ -82,7 +82,6 @@ fn actual_main() -> anyhow::Result<ExitCode> {
         flags::RustAnalyzerCmd::Highlight(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::AnalysisStats(cmd) => cmd.run(verbosity)?,
         flags::RustAnalyzerCmd::Diagnostics(cmd) => cmd.run()?,
-        flags::RustAnalyzerCmd::UnresolvedReferences(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Ssr(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Search(cmd) => cmd.run()?,
         flags::RustAnalyzerCmd::Lsif(cmd) => cmd.run()?,
diff --git a/crates/rust-analyzer/src/cli.rs b/crates/rust-analyzer/src/cli.rs
index a7ec5af89f..5eb6ff664f 100644
--- a/crates/rust-analyzer/src/cli.rs
+++ b/crates/rust-analyzer/src/cli.rs
@@ -13,7 +13,6 @@ mod rustc_tests;
 mod scip;
 mod ssr;
 mod symbols;
-mod unresolved_references;
 
 mod progress_report;
 
diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs
index 73e71658d1..16d90de661 100644
--- a/crates/rust-analyzer/src/cli/flags.rs
+++ b/crates/rust-analyzer/src/cli/flags.rs
@@ -124,19 +124,6 @@ xflags::xflags! {
             optional --proc-macro-srv path: PathBuf
         }
 
-        /// Report unresolved references
-        cmd unresolved-references {
-            /// Directory with Cargo.toml.
-            required path: PathBuf
-
-            /// Don't run build scripts or load `OUT_DIR` values by running `cargo check` before analysis.
-            optional --disable-build-scripts
-            /// Don't use expand proc macros.
-            optional --disable-proc-macros
-            /// Run a custom proc-macro-srv binary.
-            optional --proc-macro-srv path: PathBuf
-        }
-
         cmd ssr {
             /// A structured search replace rule (`$a.foo($b) ==>> bar($a, $b)`)
             repeated rule: SsrRule
@@ -194,7 +181,6 @@ pub enum RustAnalyzerCmd {
     RunTests(RunTests),
     RustcTests(RustcTests),
     Diagnostics(Diagnostics),
-    UnresolvedReferences(UnresolvedReferences),
     Ssr(Ssr),
     Search(Search),
     Lsif(Lsif),
@@ -264,15 +250,6 @@ pub struct Diagnostics {
     pub proc_macro_srv: Option<PathBuf>,
 }
 
-#[derive(Debug)]
-pub struct UnresolvedReferences {
-    pub path: PathBuf,
-
-    pub disable_build_scripts: bool,
-    pub disable_proc_macros: bool,
-    pub proc_macro_srv: Option<PathBuf>,
-}
-
 #[derive(Debug)]
 pub struct Ssr {
     pub rule: Vec<SsrRule>,
diff --git a/crates/rust-analyzer/src/cli/unresolved_references.rs b/crates/rust-analyzer/src/cli/unresolved_references.rs
deleted file mode 100644
index 986bd018b4..0000000000
--- a/crates/rust-analyzer/src/cli/unresolved_references.rs
+++ /dev/null
@@ -1,175 +0,0 @@
-//! Reports references in code that the IDE layer cannot resolve.
-use hir::{db::HirDatabase, AnyDiagnostic, Crate, HirFileIdExt as _, Module, Semantics};
-use ide::{AnalysisHost, RootDatabase, TextRange};
-use ide_db::{
-    base_db::{SourceDatabase, SourceRootDatabase},
-    defs::NameRefClass,
-    EditionedFileId, FxHashSet, LineIndexDatabase as _,
-};
-use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
-use parser::SyntaxKind;
-use syntax::{ast, AstNode, WalkEvent};
-use vfs::FileId;
-
-use crate::cli::flags;
-
-impl flags::UnresolvedReferences {
-    pub fn run(self) -> anyhow::Result<()> {
-        const STACK_SIZE: usize = 1024 * 1024 * 8;
-
-        let handle = stdx::thread::Builder::new(stdx::thread::ThreadIntent::LatencySensitive)
-            .name("BIG_STACK_THREAD".into())
-            .stack_size(STACK_SIZE)
-            .spawn(|| self.run_())
-            .unwrap();
-
-        handle.join()
-    }
-
-    fn run_(self) -> anyhow::Result<()> {
-        let root =
-            vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(&self.path)).normalize();
-        let config = crate::config::Config::new(
-            root.clone(),
-            lsp_types::ClientCapabilities::default(),
-            vec![],
-            None,
-        );
-        let cargo_config = config.cargo(None);
-        let with_proc_macro_server = if let Some(p) = &self.proc_macro_srv {
-            let path = vfs::AbsPathBuf::assert_utf8(std::env::current_dir()?.join(p));
-            ProcMacroServerChoice::Explicit(path)
-        } else {
-            ProcMacroServerChoice::Sysroot
-        };
-        let load_cargo_config = LoadCargoConfig {
-            load_out_dirs_from_check: !self.disable_build_scripts,
-            with_proc_macro_server,
-            prefill_caches: false,
-        };
-        let (db, vfs, _proc_macro) =
-            load_workspace_at(&self.path, &cargo_config, &load_cargo_config, &|_| {})?;
-        let host = AnalysisHost::with_database(db);
-        let db = host.raw_database();
-        let sema = Semantics::new(db);
-
-        let mut visited_files = FxHashSet::default();
-
-        let work = all_modules(db).into_iter().filter(|module| {
-            let file_id = module.definition_source_file_id(db).original_file(db);
-            let source_root = db.file_source_root(file_id.into());
-            let source_root = db.source_root(source_root);
-            !source_root.is_library
-        });
-
-        for module in work {
-            let file_id = module.definition_source_file_id(db).original_file(db);
-            if !visited_files.contains(&file_id) {
-                let crate_name =
-                    module.krate().display_name(db).as_deref().unwrap_or("unknown").to_owned();
-                let file_path = vfs.file_path(file_id.into());
-                eprintln!("processing crate: {crate_name}, module: {file_path}",);
-
-                let line_index = db.line_index(file_id.into());
-                let file_text = db.file_text(file_id.into());
-
-                for range in find_unresolved_references(db, &sema, file_id.into(), &module) {
-                    let line_col = line_index.line_col(range.start());
-                    let line = line_col.line + 1;
-                    let col = line_col.col + 1;
-                    let text = &file_text[range];
-                    println!("{file_path}:{line}:{col}: {text}");
-                }
-
-                visited_files.insert(file_id);
-            }
-        }
-
-        eprintln!();
-        eprintln!("scan complete");
-
-        Ok(())
-    }
-}
-
-fn all_modules(db: &dyn HirDatabase) -> Vec<Module> {
-    let mut worklist: Vec<_> =
-        Crate::all(db).into_iter().map(|krate| krate.root_module()).collect();
-    let mut modules = Vec::new();
-
-    while let Some(module) = worklist.pop() {
-        modules.push(module);
-        worklist.extend(module.children(db));
-    }
-
-    modules
-}
-
-fn find_unresolved_references(
-    db: &RootDatabase,
-    sema: &Semantics<'_, RootDatabase>,
-    file_id: FileId,
-    module: &Module,
-) -> Vec<TextRange> {
-    let mut unresolved_references = all_unresolved_references(sema, file_id);
-
-    // remove unresolved references which are within inactive code
-    let mut diagnostics = Vec::new();
-    module.diagnostics(db, &mut diagnostics, false);
-    for diagnostic in diagnostics {
-        let AnyDiagnostic::InactiveCode(inactive_code) = diagnostic else {
-            continue;
-        };
-
-        let node = inactive_code.node;
-        let range = node.map(|it| it.text_range()).original_node_file_range_rooted(db);
-
-        if range.file_id != file_id {
-            continue;
-        }
-
-        unresolved_references.retain(|r| !range.range.contains_range(*r));
-    }
-
-    unresolved_references
-}
-
-fn all_unresolved_references(
-    sema: &Semantics<'_, RootDatabase>,
-    file_id: FileId,
-) -> Vec<TextRange> {
-    let file_id = sema
-        .attach_first_edition(file_id)
-        .unwrap_or_else(|| EditionedFileId::current_edition(file_id));
-    let file = sema.parse(file_id);
-    let root = file.syntax();
-
-    let mut unresolved_references = Vec::new();
-    for event in root.preorder() {
-        let WalkEvent::Enter(syntax) = event else {
-            continue;
-        };
-        let Some(name_ref) = ast::NameRef::cast(syntax) else {
-            continue;
-        };
-        let Some(descended_name_ref) = name_ref.syntax().first_token().and_then(|tok| {
-            sema.descend_into_macros_single_exact(tok).parent().and_then(ast::NameRef::cast)
-        }) else {
-            continue;
-        };
-
-        // if we can classify the name_ref, it's not unresolved
-        if NameRefClass::classify(sema, &descended_name_ref).is_some() {
-            continue;
-        }
-
-        // if we couldn't classify it, but it's in an attr, ignore it. See #10935
-        if descended_name_ref.syntax().ancestors().any(|it| it.kind() == SyntaxKind::ATTR) {
-            continue;
-        }
-
-        // otherwise, it's unresolved
-        unresolved_references.push(name_ref.syntax().text_range());
-    }
-    unresolved_references
-}
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 35be6d0cf7..e4e8c9c6d9 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -420,10 +420,6 @@ config_data! {
         assist_termSearch_fuel: usize = 1800,
 
 
-        /// Whether to automatically add a semicolon when completing unit-returning functions.
-        ///
-        /// In `match` arms it completes a comma instead.
-        completion_addSemicolonToUnit: bool = true,
         /// Toggles the additional completions that automatically add imports when completed.
         /// Note that your client must specify the `additionalTextEdits` LSP client capability to truly have this feature enabled.
         completion_autoimport_enable: bool       = true,
@@ -1445,7 +1441,6 @@ impl Config {
                 CallableCompletionDef::AddParentheses => Some(CallableSnippets::AddParentheses),
                 CallableCompletionDef::None => None,
             },
-            add_semicolon_to_unit: *self.completion_addSemicolonToUnit(source_root),
             snippet_cap: SnippetCap::new(self.completion_snippet()),
             insert_use: self.insert_use_config(source_root),
             prefer_no_std: self.imports_preferNoStd(source_root).to_owned(),
diff --git a/crates/rust-analyzer/src/integrated_benchmarks.rs b/crates/rust-analyzer/src/integrated_benchmarks.rs
index 118469df73..28f4b809d6 100644
--- a/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -167,7 +167,6 @@ fn integrated_completion_benchmark() {
             prefer_absolute: false,
             snippets: Vec::new(),
             limit: None,
-            add_semicolon_to_unit: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -214,7 +213,6 @@ fn integrated_completion_benchmark() {
             prefer_absolute: false,
             snippets: Vec::new(),
             limit: None,
-            add_semicolon_to_unit: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
@@ -259,7 +257,6 @@ fn integrated_completion_benchmark() {
             prefer_absolute: false,
             snippets: Vec::new(),
             limit: None,
-            add_semicolon_to_unit: true,
         };
         let position =
             FilePosition { file_id, offset: TextSize::try_from(completion_offset).unwrap() };
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index dbbb290b4f..b68374848b 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -40,7 +40,6 @@ pub mod ast;
 #[doc(hidden)]
 pub mod fuzz;
 pub mod hacks;
-pub mod syntax_editor;
 pub mod ted;
 pub mod utils;
 
diff --git a/crates/syntax/src/syntax_editor.rs b/crates/syntax/src/syntax_editor.rs
deleted file mode 100644
index eb114f5e5f..0000000000
--- a/crates/syntax/src/syntax_editor.rs
+++ /dev/null
@@ -1,611 +0,0 @@
-//! Syntax Tree editor
-//!
-//! Inspired by Roslyn's [`SyntaxEditor`], but is temporarily built upon mutable syntax tree editing.
-//!
-//! [`SyntaxEditor`]: https://github.com/dotnet/roslyn/blob/43b0b05cc4f492fd5de00f6f6717409091df8daa/src/Workspaces/Core/Portable/Editing/SyntaxEditor.cs
-
-use std::{
-    num::NonZeroU32,
-    ops::RangeInclusive,
-    sync::atomic::{AtomicU32, Ordering},
-};
-
-use rowan::TextRange;
-use rustc_hash::FxHashMap;
-
-use crate::{SyntaxElement, SyntaxNode, SyntaxToken};
-
-mod edit_algo;
-mod mapping;
-
-pub use mapping::{SyntaxMapping, SyntaxMappingBuilder};
-
-#[derive(Debug)]
-pub struct SyntaxEditor {
-    root: SyntaxNode,
-    changes: Vec<Change>,
-    mappings: SyntaxMapping,
-    annotations: Vec<(SyntaxElement, SyntaxAnnotation)>,
-}
-
-impl SyntaxEditor {
-    /// Creates a syntax editor to start editing from `root`
-    pub fn new(root: SyntaxNode) -> Self {
-        Self { root, changes: vec![], mappings: SyntaxMapping::new(), annotations: vec![] }
-    }
-
-    pub fn add_annotation(&mut self, element: impl Element, annotation: SyntaxAnnotation) {
-        self.annotations.push((element.syntax_element(), annotation))
-    }
-
-    pub fn merge(&mut self, mut other: SyntaxEditor) {
-        debug_assert!(
-            self.root == other.root || other.root.ancestors().any(|node| node == self.root),
-            "{:?} is not in the same tree as {:?}",
-            other.root,
-            self.root
-        );
-
-        self.changes.append(&mut other.changes);
-        self.mappings.merge(other.mappings);
-        self.annotations.append(&mut other.annotations);
-    }
-
-    pub fn insert(&mut self, position: Position, element: impl Element) {
-        debug_assert!(is_ancestor_or_self(&position.parent(), &self.root));
-        self.changes.push(Change::Insert(position, element.syntax_element()))
-    }
-
-    pub fn insert_all(&mut self, position: Position, elements: Vec<SyntaxElement>) {
-        debug_assert!(is_ancestor_or_self(&position.parent(), &self.root));
-        self.changes.push(Change::InsertAll(position, elements))
-    }
-
-    pub fn delete(&mut self, element: impl Element) {
-        let element = element.syntax_element();
-        debug_assert!(is_ancestor_or_self_of_element(&element, &self.root));
-        debug_assert!(
-            !matches!(&element, SyntaxElement::Node(node) if node == &self.root),
-            "should not delete root node"
-        );
-        self.changes.push(Change::Replace(element.syntax_element(), None));
-    }
-
-    pub fn replace(&mut self, old: impl Element, new: impl Element) {
-        let old = old.syntax_element();
-        debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
-        self.changes.push(Change::Replace(old.syntax_element(), Some(new.syntax_element())));
-    }
-
-    pub fn replace_with_many(&mut self, old: impl Element, new: Vec<SyntaxElement>) {
-        let old = old.syntax_element();
-        debug_assert!(is_ancestor_or_self_of_element(&old, &self.root));
-        debug_assert!(
-            !(matches!(&old, SyntaxElement::Node(node) if node == &self.root) && new.len() > 1),
-            "cannot replace root node with many elements"
-        );
-        self.changes.push(Change::ReplaceWithMany(old.syntax_element(), new));
-    }
-
-    pub fn replace_all(&mut self, range: RangeInclusive<SyntaxElement>, new: Vec<SyntaxElement>) {
-        if range.start() == range.end() {
-            self.replace_with_many(range.start(), new);
-            return;
-        }
-
-        debug_assert!(is_ancestor_or_self_of_element(range.start(), &self.root));
-        self.changes.push(Change::ReplaceAll(range, new))
-    }
-
-    pub fn finish(self) -> SyntaxEdit {
-        edit_algo::apply_edits(self)
-    }
-}
-
-/// Represents a completed [`SyntaxEditor`] operation.
-pub struct SyntaxEdit {
-    old_root: SyntaxNode,
-    new_root: SyntaxNode,
-    changed_elements: Vec<SyntaxElement>,
-    annotations: FxHashMap<SyntaxAnnotation, Vec<SyntaxElement>>,
-}
-
-impl SyntaxEdit {
-    /// Root of the initial unmodified syntax tree.
-    pub fn old_root(&self) -> &SyntaxNode {
-        &self.old_root
-    }
-
-    /// Root of the modified syntax tree.
-    pub fn new_root(&self) -> &SyntaxNode {
-        &self.new_root
-    }
-
-    /// Which syntax elements in the modified syntax tree were inserted or
-    /// modified as part of the edit.
-    ///
-    /// Note that for syntax nodes, only the upper-most parent of a set of
-    /// changes is included, not any child elements that may have been modified.
-    pub fn changed_elements(&self) -> &[SyntaxElement] {
-        self.changed_elements.as_slice()
-    }
-
-    /// Finds which syntax elements have been annotated with the given
-    /// annotation.
-    ///
-    /// Note that an annotation might not appear in the modified syntax tree if
-    /// the syntax elements that were annotated did not make it into the final
-    /// syntax tree.
-    pub fn find_annotation(&self, annotation: SyntaxAnnotation) -> &[SyntaxElement] {
-        self.annotations.get(&annotation).as_ref().map_or(&[], |it| it.as_slice())
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-#[repr(transparent)]
-pub struct SyntaxAnnotation(NonZeroU32);
-
-impl SyntaxAnnotation {
-    /// Creates a unique syntax annotation to attach data to.
-    pub fn new() -> Self {
-        static COUNTER: AtomicU32 = AtomicU32::new(1);
-
-        // Only consistency within a thread matters, as SyntaxElements are !Send
-        let id = COUNTER.fetch_add(1, Ordering::Relaxed);
-
-        Self(NonZeroU32::new(id).expect("syntax annotation id overflow"))
-    }
-}
-
-impl Default for SyntaxAnnotation {
-    fn default() -> Self {
-        Self::new()
-    }
-}
-
-/// Position describing where to insert elements
-#[derive(Debug)]
-pub struct Position {
-    repr: PositionRepr,
-}
-
-impl Position {
-    pub(crate) fn parent(&self) -> SyntaxNode {
-        self.place().0
-    }
-
-    pub(crate) fn place(&self) -> (SyntaxNode, usize) {
-        match &self.repr {
-            PositionRepr::FirstChild(parent) => (parent.clone(), 0),
-            PositionRepr::After(child) => (child.parent().unwrap(), child.index() + 1),
-        }
-    }
-}
-
-#[derive(Debug)]
-enum PositionRepr {
-    FirstChild(SyntaxNode),
-    After(SyntaxElement),
-}
-
-impl Position {
-    pub fn after(elem: impl Element) -> Position {
-        let repr = PositionRepr::After(elem.syntax_element());
-        Position { repr }
-    }
-
-    pub fn before(elem: impl Element) -> Position {
-        let elem = elem.syntax_element();
-        let repr = match elem.prev_sibling_or_token() {
-            Some(it) => PositionRepr::After(it),
-            None => PositionRepr::FirstChild(elem.parent().unwrap()),
-        };
-        Position { repr }
-    }
-
-    pub fn first_child_of(node: &(impl Into<SyntaxNode> + Clone)) -> Position {
-        let repr = PositionRepr::FirstChild(node.clone().into());
-        Position { repr }
-    }
-
-    pub fn last_child_of(node: &(impl Into<SyntaxNode> + Clone)) -> Position {
-        let node = node.clone().into();
-        let repr = match node.last_child_or_token() {
-            Some(it) => PositionRepr::After(it),
-            None => PositionRepr::FirstChild(node),
-        };
-        Position { repr }
-    }
-}
-
-#[derive(Debug)]
-enum Change {
-    /// Inserts a single element at the specified position.
-    Insert(Position, SyntaxElement),
-    /// Inserts many elements in-order at the specified position.
-    InsertAll(Position, Vec<SyntaxElement>),
-    /// Represents both a replace single element and a delete element operation.
-    Replace(SyntaxElement, Option<SyntaxElement>),
-    /// Replaces a single element with many elements.
-    ReplaceWithMany(SyntaxElement, Vec<SyntaxElement>),
-    /// Replaces a range of elements with another list of elements.
-    /// Range will always have start != end.
-    ReplaceAll(RangeInclusive<SyntaxElement>, Vec<SyntaxElement>),
-}
-
-impl Change {
-    fn target_range(&self) -> TextRange {
-        match self {
-            Change::Insert(target, _) | Change::InsertAll(target, _) => match &target.repr {
-                PositionRepr::FirstChild(parent) => TextRange::at(
-                    parent.first_child_or_token().unwrap().text_range().start(),
-                    0.into(),
-                ),
-                PositionRepr::After(child) => TextRange::at(child.text_range().end(), 0.into()),
-            },
-            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => target.text_range(),
-            Change::ReplaceAll(range, _) => {
-                range.start().text_range().cover(range.end().text_range())
-            }
-        }
-    }
-
-    fn target_parent(&self) -> SyntaxNode {
-        match self {
-            Change::Insert(target, _) | Change::InsertAll(target, _) => target.parent(),
-            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => match target {
-                SyntaxElement::Node(target) => target.parent().unwrap_or_else(|| target.clone()),
-                SyntaxElement::Token(target) => target.parent().unwrap(),
-            },
-            Change::ReplaceAll(target, _) => target.start().parent().unwrap(),
-        }
-    }
-
-    fn change_kind(&self) -> ChangeKind {
-        match self {
-            Change::Insert(_, _) | Change::InsertAll(_, _) => ChangeKind::Insert,
-            Change::Replace(_, _) | Change::ReplaceWithMany(_, _) => ChangeKind::Replace,
-            Change::ReplaceAll(_, _) => ChangeKind::ReplaceRange,
-        }
-    }
-}
-
-#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
-enum ChangeKind {
-    Insert,
-    ReplaceRange,
-    Replace,
-}
-
-/// Utility trait to allow calling syntax editor functions with references or owned
-/// nodes. Do not use outside of this module.
-pub trait Element {
-    fn syntax_element(self) -> SyntaxElement;
-}
-
-impl<E: Element + Clone> Element for &'_ E {
-    fn syntax_element(self) -> SyntaxElement {
-        self.clone().syntax_element()
-    }
-}
-
-impl Element for SyntaxElement {
-    fn syntax_element(self) -> SyntaxElement {
-        self
-    }
-}
-
-impl Element for SyntaxNode {
-    fn syntax_element(self) -> SyntaxElement {
-        self.into()
-    }
-}
-
-impl Element for SyntaxToken {
-    fn syntax_element(self) -> SyntaxElement {
-        self.into()
-    }
-}
-
-fn is_ancestor_or_self(node: &SyntaxNode, ancestor: &SyntaxNode) -> bool {
-    node == ancestor || node.ancestors().any(|it| &it == ancestor)
-}
-
-fn is_ancestor_or_self_of_element(node: &SyntaxElement, ancestor: &SyntaxNode) -> bool {
-    matches!(node, SyntaxElement::Node(node) if node == ancestor)
-        || node.ancestors().any(|it| &it == ancestor)
-}
-
-#[cfg(test)]
-mod tests {
-    use expect_test::expect;
-    use itertools::Itertools;
-
-    use crate::{
-        ast::{self, make, HasName},
-        AstNode,
-    };
-
-    use super::*;
-
-    fn make_ident_pat(
-        editor: Option<&mut SyntaxEditor>,
-        ref_: bool,
-        mut_: bool,
-        name: ast::Name,
-    ) -> ast::IdentPat {
-        let ast = make::ident_pat(ref_, mut_, name.clone()).clone_for_update();
-
-        if let Some(editor) = editor {
-            let mut mapping = SyntaxMappingBuilder::new(ast.syntax().clone());
-            mapping.map_node(name.syntax().clone(), ast.name().unwrap().syntax().clone());
-            mapping.finish(editor);
-        }
-
-        ast
-    }
-
-    fn make_let_stmt(
-        editor: Option<&mut SyntaxEditor>,
-        pattern: ast::Pat,
-        ty: Option<ast::Type>,
-        initializer: Option<ast::Expr>,
-    ) -> ast::LetStmt {
-        let ast =
-            make::let_stmt(pattern.clone(), ty.clone(), initializer.clone()).clone_for_update();
-
-        if let Some(editor) = editor {
-            let mut mapping = SyntaxMappingBuilder::new(ast.syntax().clone());
-            mapping.map_node(pattern.syntax().clone(), ast.pat().unwrap().syntax().clone());
-            if let Some(input) = ty {
-                mapping.map_node(input.syntax().clone(), ast.ty().unwrap().syntax().clone());
-            }
-            if let Some(input) = initializer {
-                mapping
-                    .map_node(input.syntax().clone(), ast.initializer().unwrap().syntax().clone());
-            }
-            mapping.finish(editor);
-        }
-
-        ast
-    }
-
-    fn make_block_expr(
-        editor: Option<&mut SyntaxEditor>,
-        stmts: impl IntoIterator<Item = ast::Stmt>,
-        tail_expr: Option<ast::Expr>,
-    ) -> ast::BlockExpr {
-        let stmts = stmts.into_iter().collect_vec();
-        let input = stmts.iter().map(|it| it.syntax().clone()).collect_vec();
-
-        let ast = make::block_expr(stmts, tail_expr.clone()).clone_for_update();
-
-        if let Some((editor, stmt_list)) = editor.zip(ast.stmt_list()) {
-            let mut mapping = SyntaxMappingBuilder::new(stmt_list.syntax().clone());
-
-            mapping.map_children(
-                input.into_iter(),
-                stmt_list.statements().map(|it| it.syntax().clone()),
-            );
-
-            if let Some((input, output)) = tail_expr.zip(stmt_list.tail_expr()) {
-                mapping.map_node(input.syntax().clone(), output.syntax().clone());
-            }
-
-            mapping.finish(editor);
-        }
-
-        ast
-    }
-
-    #[test]
-    fn basic_usage() {
-        let root = make::match_arm(
-            [make::wildcard_pat().into()],
-            None,
-            make::expr_tuple([
-                make::expr_bin_op(
-                    make::expr_literal("2").into(),
-                    ast::BinaryOp::ArithOp(ast::ArithOp::Add),
-                    make::expr_literal("2").into(),
-                ),
-                make::expr_literal("true").into(),
-            ]),
-        );
-
-        let to_wrap = root.syntax().descendants().find_map(ast::TupleExpr::cast).unwrap();
-        let to_replace = root.syntax().descendants().find_map(ast::BinExpr::cast).unwrap();
-
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
-
-        let name = make::name("var_name");
-        let name_ref = make::name_ref("var_name").clone_for_update();
-
-        let placeholder_snippet = SyntaxAnnotation::new();
-        editor.add_annotation(name.syntax(), placeholder_snippet);
-        editor.add_annotation(name_ref.syntax(), placeholder_snippet);
-
-        let make_ident_pat = make_ident_pat(Some(&mut editor), false, false, name);
-        let make_let_stmt = make_let_stmt(
-            Some(&mut editor),
-            make_ident_pat.into(),
-            None,
-            Some(to_replace.clone().into()),
-        );
-        let new_block = make_block_expr(
-            Some(&mut editor),
-            [make_let_stmt.into()],
-            Some(to_wrap.clone().into()),
-        );
-
-        editor.replace(to_replace.syntax(), name_ref.syntax());
-        editor.replace(to_wrap.syntax(), new_block.syntax());
-
-        let edit = editor.finish();
-
-        let expect = expect![[r#"
-            _ => {
-                let var_name = 2 + 2;
-                (var_name, true)
-            }"#]];
-        expect.assert_eq(&edit.new_root.to_string());
-
-        assert_eq!(edit.find_annotation(placeholder_snippet).len(), 2);
-        assert!(edit
-            .annotations
-            .iter()
-            .flat_map(|(_, elements)| elements)
-            .all(|element| element.ancestors().any(|it| &it == edit.new_root())))
-    }
-
-    #[test]
-    fn test_insert_independent() {
-        let root = make::block_expr(
-            [make::let_stmt(
-                make::ext::simple_ident_pat(make::name("second")).into(),
-                None,
-                Some(make::expr_literal("2").into()),
-            )
-            .into()],
-            None,
-        );
-
-        let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
-
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
-
-        editor.insert(
-            Position::first_child_of(root.stmt_list().unwrap().syntax()),
-            make_let_stmt(
-                None,
-                make::ext::simple_ident_pat(make::name("first")).into(),
-                None,
-                Some(make::expr_literal("1").into()),
-            )
-            .syntax(),
-        );
-
-        editor.insert(
-            Position::after(second_let.syntax()),
-            make_let_stmt(
-                None,
-                make::ext::simple_ident_pat(make::name("third")).into(),
-                None,
-                Some(make::expr_literal("3").into()),
-            )
-            .syntax(),
-        );
-
-        let edit = editor.finish();
-
-        let expect = expect![[r#"
-            let first = 1;{
-                let second = 2;let third = 3;
-            }"#]];
-        expect.assert_eq(&edit.new_root.to_string());
-    }
-
-    #[test]
-    fn test_insert_dependent() {
-        let root = make::block_expr(
-            [],
-            Some(
-                make::block_expr(
-                    [make::let_stmt(
-                        make::ext::simple_ident_pat(make::name("second")).into(),
-                        None,
-                        Some(make::expr_literal("2").into()),
-                    )
-                    .into()],
-                    None,
-                )
-                .into(),
-            ),
-        );
-
-        let inner_block =
-            root.syntax().descendants().flat_map(ast::BlockExpr::cast).nth(1).unwrap();
-        let second_let = root.syntax().descendants().find_map(ast::LetStmt::cast).unwrap();
-
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
-
-        let new_block_expr =
-            make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone())));
-
-        let first_let = make_let_stmt(
-            Some(&mut editor),
-            make::ext::simple_ident_pat(make::name("first")).into(),
-            None,
-            Some(make::expr_literal("1").into()),
-        );
-
-        let third_let = make_let_stmt(
-            Some(&mut editor),
-            make::ext::simple_ident_pat(make::name("third")).into(),
-            None,
-            Some(make::expr_literal("3").into()),
-        );
-
-        editor.insert(
-            Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
-            first_let.syntax(),
-        );
-        editor.insert(Position::after(second_let.syntax()), third_let.syntax());
-        editor.replace(inner_block.syntax(), new_block_expr.syntax());
-
-        let edit = editor.finish();
-
-        let expect = expect![[r#"
-            {
-                {
-                let first = 1;{
-                let second = 2;let third = 3;
-            }
-            }
-            }"#]];
-        expect.assert_eq(&edit.new_root.to_string());
-    }
-
-    #[test]
-    fn test_replace_root_with_dependent() {
-        let root = make::block_expr(
-            [make::let_stmt(
-                make::ext::simple_ident_pat(make::name("second")).into(),
-                None,
-                Some(make::expr_literal("2").into()),
-            )
-            .into()],
-            None,
-        );
-
-        let inner_block = root.clone();
-
-        let mut editor = SyntaxEditor::new(root.syntax().clone());
-
-        let new_block_expr =
-            make_block_expr(Some(&mut editor), [], Some(ast::Expr::BlockExpr(inner_block.clone())));
-
-        let first_let = make_let_stmt(
-            Some(&mut editor),
-            make::ext::simple_ident_pat(make::name("first")).into(),
-            None,
-            Some(make::expr_literal("1").into()),
-        );
-
-        editor.insert(
-            Position::first_child_of(inner_block.stmt_list().unwrap().syntax()),
-            first_let.syntax(),
-        );
-        editor.replace(inner_block.syntax(), new_block_expr.syntax());
-
-        let edit = editor.finish();
-
-        let expect = expect![[r#"
-            {
-                let first = 1;{
-                let second = 2;
-            }
-            }"#]];
-        expect.assert_eq(&edit.new_root.to_string());
-    }
-}
diff --git a/crates/syntax/src/syntax_editor/edit_algo.rs b/crates/syntax/src/syntax_editor/edit_algo.rs
deleted file mode 100644
index b769c94110..0000000000
--- a/crates/syntax/src/syntax_editor/edit_algo.rs
+++ /dev/null
@@ -1,367 +0,0 @@
-//! Implementation of applying changes to a syntax tree.
-
-use std::{cmp::Ordering, collections::VecDeque, ops::RangeInclusive};
-
-use rowan::TextRange;
-use rustc_hash::FxHashMap;
-
-use crate::{
-    syntax_editor::{mapping::MissingMapping, Change, ChangeKind, PositionRepr},
-    SyntaxElement, SyntaxNode, SyntaxNodePtr,
-};
-
-use super::{SyntaxEdit, SyntaxEditor};
-
-pub(super) fn apply_edits(editor: SyntaxEditor) -> SyntaxEdit {
-    // Algorithm overview:
-    //
-    // - Sort changes by (range, type)
-    //   - Ensures that parent edits are before child edits
-    //   - Ensures that inserts will be guaranteed to be inserted at the right range
-    // - Validate changes
-    //   - Checking for invalid changes is easy since the changes will be sorted by range
-    // - Fixup change targets
-    //   - standalone change? map to original syntax tree
-    //   - dependent change?
-    //     - try to map to parent change (either independent or another dependent)
-    //     - note: need to keep track of a parent change stack, since a change can be a parent of multiple changes
-    // - Apply changes
-    //   - find changes to apply to real tree by applying nested changes first
-    //   - changed nodes become part of the changed node set (useful for the formatter to only change those parts)
-    // - Propagate annotations
-
-    let SyntaxEditor { root, mut changes, mappings, annotations } = editor;
-
-    let mut node_depths = FxHashMap::<SyntaxNode, usize>::default();
-    let mut get_node_depth = |node: SyntaxNode| {
-        *node_depths.entry(node).or_insert_with_key(|node| node.ancestors().count())
-    };
-
-    // Sort changes by range, then depth, then change kind, so that we can:
-    // - ensure that parent edits are ordered before child edits
-    // - ensure that inserts will be guaranteed to be inserted at the right range
-    // - easily check for disjoint replace ranges
-    changes.sort_by(|a, b| {
-        a.target_range()
-            .start()
-            .cmp(&b.target_range().start())
-            .then_with(|| {
-                let a_target = a.target_parent();
-                let b_target = b.target_parent();
-
-                if a_target == b_target {
-                    return Ordering::Equal;
-                }
-
-                get_node_depth(a_target).cmp(&get_node_depth(b_target))
-            })
-            .then(a.change_kind().cmp(&b.change_kind()))
-    });
-
-    let disjoint_replaces_ranges = changes
-        .iter()
-        .zip(changes.iter().skip(1))
-        .filter(|(l, r)| {
-            // We only care about checking for disjoint replace ranges
-            matches!(
-                (l.change_kind(), r.change_kind()),
-                (
-                    ChangeKind::Replace | ChangeKind::ReplaceRange,
-                    ChangeKind::Replace | ChangeKind::ReplaceRange
-                )
-            )
-        })
-        .all(|(l, r)| {
-            get_node_depth(l.target_parent()) != get_node_depth(r.target_parent())
-                || l.target_range().intersect(r.target_range()).is_none()
-        });
-
-    if stdx::never!(
-        !disjoint_replaces_ranges,
-        "some replace change ranges intersect: {:?}",
-        changes
-    ) {
-        return SyntaxEdit {
-            old_root: root.clone(),
-            new_root: root,
-            annotations: Default::default(),
-            changed_elements: vec![],
-        };
-    }
-
-    #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)]
-    struct DependentChange {
-        parent: u32,
-        child: u32,
-    }
-
-    // Build change tree
-    let mut changed_ancestors: VecDeque<ChangedAncestor> = VecDeque::new();
-    let mut dependent_changes = vec![];
-    let mut independent_changes = vec![];
-
-    for (change_index, change) in changes.iter().enumerate() {
-        // Check if this change is dependent on another change (i.e. it's contained within another range)
-        if let Some(index) = changed_ancestors
-            .iter()
-            .rev()
-            .position(|ancestor| ancestor.affected_range().contains_range(change.target_range()))
-        {
-            // Pop off any ancestors that aren't applicable
-            changed_ancestors.drain((index + 1)..);
-
-            // FIXME: Resolve changes that depend on a range of elements
-            let ancestor = &changed_ancestors[index];
-
-            dependent_changes.push(DependentChange {
-                parent: ancestor.change_index as u32,
-                child: change_index as u32,
-            });
-        } else {
-            // This change is independent of any other change
-
-            // Drain the changed ancestors since we're no longer in a set of dependent changes
-            changed_ancestors.drain(..);
-
-            independent_changes.push(change_index as u32);
-        }
-
-        // Add to changed ancestors, if applicable
-        match change {
-            Change::Insert(_, _) | Change::InsertAll(_, _) => {}
-            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
-                changed_ancestors.push_back(ChangedAncestor::single(target, change_index))
-            }
-            Change::ReplaceAll(range, _) => {
-                changed_ancestors.push_back(ChangedAncestor::multiple(range, change_index))
-            }
-        }
-    }
-
-    // Map change targets to the correct syntax nodes
-    let tree_mutator = TreeMutator::new(&root);
-    let mut changed_elements = vec![];
-
-    for index in independent_changes {
-        match &mut changes[index as usize] {
-            Change::Insert(target, _) | Change::InsertAll(target, _) => {
-                match &mut target.repr {
-                    PositionRepr::FirstChild(parent) => {
-                        *parent = tree_mutator.make_syntax_mut(parent);
-                    }
-                    PositionRepr::After(child) => {
-                        *child = tree_mutator.make_element_mut(child);
-                    }
-                };
-            }
-            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
-                *target = tree_mutator.make_element_mut(target);
-            }
-            Change::ReplaceAll(range, _) => {
-                let start = tree_mutator.make_element_mut(range.start());
-                let end = tree_mutator.make_element_mut(range.end());
-
-                *range = start..=end;
-            }
-        }
-
-        // Collect changed elements
-        match &changes[index as usize] {
-            Change::Insert(_, element) => changed_elements.push(element.clone()),
-            Change::InsertAll(_, elements) => changed_elements.extend(elements.iter().cloned()),
-            Change::Replace(_, Some(element)) => changed_elements.push(element.clone()),
-            Change::Replace(_, None) => {}
-            Change::ReplaceWithMany(_, elements) => {
-                changed_elements.extend(elements.iter().cloned())
-            }
-            Change::ReplaceAll(_, elements) => changed_elements.extend(elements.iter().cloned()),
-        }
-    }
-
-    for DependentChange { parent, child } in dependent_changes.into_iter() {
-        let (input_ancestor, output_ancestor) = match &changes[parent as usize] {
-            // No change will depend on an insert since changes can only depend on nodes in the root tree
-            Change::Insert(_, _) | Change::InsertAll(_, _) => unreachable!(),
-            Change::Replace(target, Some(new_target)) => {
-                (to_owning_node(target), to_owning_node(new_target))
-            }
-            // Silently drop outdated change
-            Change::Replace(_, None) => continue,
-            Change::ReplaceAll(_, _) | Change::ReplaceWithMany(_, _) => {
-                unimplemented!("cannot resolve changes that depend on replacing many elements")
-            }
-        };
-
-        let upmap_target_node = |target: &SyntaxNode| {
-            match mappings.upmap_child(target, &input_ancestor, &output_ancestor) {
-                Ok(it) => it,
-                Err(MissingMapping(current)) => unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}"),
-            }
-        };
-
-        let upmap_target = |target: &SyntaxElement| {
-            match mappings.upmap_child_element(target, &input_ancestor, &output_ancestor) {
-                Ok(it) => it,
-                Err(MissingMapping(current)) => unreachable!("no mappings exist between {current:?} (ancestor of {input_ancestor:?}) and {output_ancestor:?}"),
-            }
-        };
-
-        match &mut changes[child as usize] {
-            Change::Insert(target, _) | Change::InsertAll(target, _) => match &mut target.repr {
-                PositionRepr::FirstChild(parent) => {
-                    *parent = upmap_target_node(parent);
-                }
-                PositionRepr::After(child) => {
-                    *child = upmap_target(child);
-                }
-            },
-            Change::Replace(target, _) | Change::ReplaceWithMany(target, _) => {
-                *target = upmap_target(target);
-            }
-            Change::ReplaceAll(range, _) => {
-                *range = upmap_target(range.start())..=upmap_target(range.end());
-            }
-        }
-    }
-
-    // Apply changes
-    let mut root = tree_mutator.mutable_clone;
-
-    for change in changes {
-        match change {
-            Change::Insert(position, element) => {
-                let (parent, index) = position.place();
-                parent.splice_children(index..index, vec![element]);
-            }
-            Change::InsertAll(position, elements) => {
-                let (parent, index) = position.place();
-                parent.splice_children(index..index, elements);
-            }
-            Change::Replace(target, None) => {
-                target.detach();
-            }
-            Change::Replace(SyntaxElement::Node(target), Some(new_target)) if target == root => {
-                root = new_target.into_node().expect("root node replacement should be a node");
-            }
-            Change::Replace(target, Some(new_target)) => {
-                let parent = target.parent().unwrap();
-                parent.splice_children(target.index()..target.index() + 1, vec![new_target]);
-            }
-            Change::ReplaceWithMany(target, elements) => {
-                let parent = target.parent().unwrap();
-                parent.splice_children(target.index()..target.index() + 1, elements);
-            }
-            Change::ReplaceAll(range, elements) => {
-                let start = range.start().index();
-                let end = range.end().index();
-                let parent = range.start().parent().unwrap();
-                parent.splice_children(start..end + 1, elements);
-            }
-        }
-    }
-
-    // Propagate annotations
-    let annotations = annotations.into_iter().filter_map(|(element, annotation)| {
-        match mappings.upmap_element(&element, &root) {
-            // Needed to follow the new tree to find the resulting element
-            Some(Ok(mapped)) => Some((mapped, annotation)),
-            // Element did not need to be mapped
-            None => Some((element, annotation)),
-            // Element did not make it to the final tree
-            Some(Err(_)) => None,
-        }
-    });
-
-    let mut annotation_groups = FxHashMap::default();
-
-    for (element, annotation) in annotations {
-        annotation_groups.entry(annotation).or_insert(vec![]).push(element);
-    }
-
-    SyntaxEdit {
-        old_root: tree_mutator.immutable,
-        new_root: root,
-        changed_elements,
-        annotations: annotation_groups,
-    }
-}
-
-fn to_owning_node(element: &SyntaxElement) -> SyntaxNode {
-    match element {
-        SyntaxElement::Node(node) => node.clone(),
-        SyntaxElement::Token(token) => token.parent().unwrap().clone(),
-    }
-}
-
-struct ChangedAncestor {
-    kind: ChangedAncestorKind,
-    change_index: usize,
-}
-
-enum ChangedAncestorKind {
-    Single { node: SyntaxNode },
-    Range { _changed_elements: RangeInclusive<SyntaxElement>, _in_parent: SyntaxNode },
-}
-
-impl ChangedAncestor {
-    fn single(element: &SyntaxElement, change_index: usize) -> Self {
-        let kind = match element {
-            SyntaxElement::Node(node) => ChangedAncestorKind::Single { node: node.clone() },
-            SyntaxElement::Token(token) => {
-                ChangedAncestorKind::Single { node: token.parent().unwrap() }
-            }
-        };
-
-        Self { kind, change_index }
-    }
-
-    fn multiple(range: &RangeInclusive<SyntaxElement>, change_index: usize) -> Self {
-        Self {
-            kind: ChangedAncestorKind::Range {
-                _changed_elements: range.clone(),
-                _in_parent: range.start().parent().unwrap(),
-            },
-            change_index,
-        }
-    }
-
-    fn affected_range(&self) -> TextRange {
-        match &self.kind {
-            ChangedAncestorKind::Single { node } => node.text_range(),
-            ChangedAncestorKind::Range { _changed_elements: changed_nodes, _in_parent: _ } => {
-                TextRange::new(
-                    changed_nodes.start().text_range().start(),
-                    changed_nodes.end().text_range().end(),
-                )
-            }
-        }
-    }
-}
-
-struct TreeMutator {
-    immutable: SyntaxNode,
-    mutable_clone: SyntaxNode,
-}
-
-impl TreeMutator {
-    fn new(immutable: &SyntaxNode) -> TreeMutator {
-        let immutable = immutable.clone();
-        let mutable_clone = immutable.clone_for_update();
-        TreeMutator { immutable, mutable_clone }
-    }
-
-    fn make_element_mut(&self, element: &SyntaxElement) -> SyntaxElement {
-        match element {
-            SyntaxElement::Node(node) => SyntaxElement::Node(self.make_syntax_mut(node)),
-            SyntaxElement::Token(token) => {
-                let parent = self.make_syntax_mut(&token.parent().unwrap());
-                parent.children_with_tokens().nth(token.index()).unwrap()
-            }
-        }
-    }
-
-    fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode {
-        let ptr = SyntaxNodePtr::new(node);
-        ptr.to_node(&self.mutable_clone)
-    }
-}
diff --git a/crates/syntax/src/syntax_editor/mapping.rs b/crates/syntax/src/syntax_editor/mapping.rs
deleted file mode 100644
index 9bb5e6d933..0000000000
--- a/crates/syntax/src/syntax_editor/mapping.rs
+++ /dev/null
@@ -1,272 +0,0 @@
-//! Maps syntax elements through disjoint syntax nodes.
-//!
-//! [`SyntaxMappingBuilder`] should be used to create mappings to add to a [`SyntaxEditor`]
-
-use itertools::Itertools;
-use rustc_hash::FxHashMap;
-
-use crate::{SyntaxElement, SyntaxNode};
-
-use super::SyntaxEditor;
-
-#[derive(Debug, Default)]
-pub struct SyntaxMapping {
-    // important information to keep track of:
-    // node -> node
-    // token -> token (implicit in mappings)
-    // input parent -> output parent (for deep lookups)
-
-    // mappings ->  parents
-    entry_parents: Vec<SyntaxNode>,
-    node_mappings: FxHashMap<SyntaxNode, MappingEntry>,
-}
-
-impl SyntaxMapping {
-    pub fn new() -> Self {
-        Self::default()
-    }
-
-    /// Like [`SyntaxMapping::upmap_child`] but for syntax elements.
-    pub fn upmap_child_element(
-        &self,
-        child: &SyntaxElement,
-        input_ancestor: &SyntaxNode,
-        output_ancestor: &SyntaxNode,
-    ) -> Result<SyntaxElement, MissingMapping> {
-        match child {
-            SyntaxElement::Node(node) => {
-                self.upmap_child(node, input_ancestor, output_ancestor).map(SyntaxElement::Node)
-            }
-            SyntaxElement::Token(token) => {
-                let upmap_parent =
-                    self.upmap_child(&token.parent().unwrap(), input_ancestor, output_ancestor)?;
-
-                let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
-                debug_assert!(
-                    element.as_token().is_some_and(|it| it.kind() == token.kind()),
-                    "token upmapping mapped to the wrong node ({token:?} -> {element:?})"
-                );
-
-                Ok(element)
-            }
-        }
-    }
-
-    /// Maps a child node of the input ancestor to the corresponding node in
-    /// the output ancestor.
-    pub fn upmap_child(
-        &self,
-        child: &SyntaxNode,
-        input_ancestor: &SyntaxNode,
-        output_ancestor: &SyntaxNode,
-    ) -> Result<SyntaxNode, MissingMapping> {
-        debug_assert!(
-            child == input_ancestor
-                || child.ancestors().any(|ancestor| &ancestor == input_ancestor)
-        );
-
-        // Build a list mapping up to the first mappable ancestor
-        let to_first_upmap = if child != input_ancestor {
-            std::iter::successors(Some((child.index(), child.clone())), |(_, current)| {
-                let parent = current.parent().unwrap();
-
-                if &parent == input_ancestor {
-                    return None;
-                }
-
-                Some((parent.index(), parent))
-            })
-            .map(|(i, _)| i)
-            .collect::<Vec<_>>()
-        } else {
-            vec![]
-        };
-
-        // Progressively up-map the input ancestor until we get to the output ancestor
-        let to_output_ancestor = if input_ancestor != output_ancestor {
-            self.upmap_to_ancestor(input_ancestor, output_ancestor)?
-        } else {
-            vec![]
-        };
-
-        let to_map_down =
-            to_output_ancestor.into_iter().rev().chain(to_first_upmap.into_iter().rev());
-
-        let mut target = output_ancestor.clone();
-
-        for index in to_map_down {
-            target = target
-                .children_with_tokens()
-                .nth(index)
-                .and_then(|it| it.into_node())
-                .expect("equivalent ancestor node should be present in target tree");
-        }
-
-        debug_assert_eq!(child.kind(), target.kind());
-
-        Ok(target)
-    }
-
-    fn upmap_to_ancestor(
-        &self,
-        input_ancestor: &SyntaxNode,
-        output_ancestor: &SyntaxNode,
-    ) -> Result<Vec<usize>, MissingMapping> {
-        let mut current =
-            self.upmap_node_single(input_ancestor).unwrap_or_else(|| input_ancestor.clone());
-        let mut upmap_chain = vec![current.index()];
-
-        loop {
-            let Some(parent) = current.parent() else { break };
-
-            if &parent == output_ancestor {
-                return Ok(upmap_chain);
-            }
-
-            current = match self.upmap_node_single(&parent) {
-                Some(next) => next,
-                None => parent,
-            };
-            upmap_chain.push(current.index());
-        }
-
-        Err(MissingMapping(current))
-    }
-
-    pub fn upmap_element(
-        &self,
-        input: &SyntaxElement,
-        output_root: &SyntaxNode,
-    ) -> Option<Result<SyntaxElement, MissingMapping>> {
-        match input {
-            SyntaxElement::Node(node) => {
-                Some(self.upmap_node(node, output_root)?.map(SyntaxElement::Node))
-            }
-            SyntaxElement::Token(token) => {
-                let upmap_parent = match self.upmap_node(&token.parent().unwrap(), output_root)? {
-                    Ok(it) => it,
-                    Err(err) => return Some(Err(err)),
-                };
-
-                let element = upmap_parent.children_with_tokens().nth(token.index()).unwrap();
-                debug_assert!(
-                    element.as_token().is_some_and(|it| it.kind() == token.kind()),
-                    "token upmapping mapped to the wrong node ({token:?} -> {element:?})"
-                );
-
-                Some(Ok(element))
-            }
-        }
-    }
-
-    pub fn upmap_node(
-        &self,
-        input: &SyntaxNode,
-        output_root: &SyntaxNode,
-    ) -> Option<Result<SyntaxNode, MissingMapping>> {
-        // Try to follow the mapping tree, if it exists
-        let input_mapping = self.upmap_node_single(input);
-        let input_ancestor =
-            input.ancestors().find_map(|ancestor| self.upmap_node_single(&ancestor));
-
-        match (input_mapping, input_ancestor) {
-            (Some(input_mapping), _) => {
-                // A mapping exists at the input, follow along the tree
-                Some(self.upmap_child(&input_mapping, &input_mapping, output_root))
-            }
-            (None, Some(input_ancestor)) => {
-                // A mapping exists at an ancestor, follow along the tree
-                Some(self.upmap_child(input, &input_ancestor, output_root))
-            }
-            (None, None) => {
-                // No mapping exists at all, is the same position in the final tree
-                None
-            }
-        }
-    }
-
-    pub fn merge(&mut self, mut other: SyntaxMapping) {
-        // Remap other's entry parents to be after the current list of entry parents
-        let remap_base: u32 = self.entry_parents.len().try_into().unwrap();
-
-        self.entry_parents.append(&mut other.entry_parents);
-        self.node_mappings.extend(other.node_mappings.into_iter().map(|(node, entry)| {
-            (node, MappingEntry { parent: entry.parent + remap_base, ..entry })
-        }));
-    }
-
-    /// Follows the input one step along the syntax mapping tree
-    fn upmap_node_single(&self, input: &SyntaxNode) -> Option<SyntaxNode> {
-        let MappingEntry { parent, child_slot } = self.node_mappings.get(input)?;
-
-        let output = self.entry_parents[*parent as usize]
-            .children_with_tokens()
-            .nth(*child_slot as usize)
-            .and_then(SyntaxElement::into_node)
-            .unwrap();
-
-        debug_assert_eq!(input.kind(), output.kind());
-        Some(output)
-    }
-
-    fn add_mapping(&mut self, syntax_mapping: SyntaxMappingBuilder) {
-        let SyntaxMappingBuilder { parent_node, node_mappings } = syntax_mapping;
-
-        let parent_entry: u32 = self.entry_parents.len().try_into().unwrap();
-        self.entry_parents.push(parent_node);
-
-        let node_entries = node_mappings
-            .into_iter()
-            .map(|(node, slot)| (node, MappingEntry { parent: parent_entry, child_slot: slot }));
-
-        self.node_mappings.extend(node_entries);
-    }
-}
-
-#[derive(Debug)]
-pub struct SyntaxMappingBuilder {
-    parent_node: SyntaxNode,
-    node_mappings: Vec<(SyntaxNode, u32)>,
-}
-
-impl SyntaxMappingBuilder {
-    pub fn new(parent_node: SyntaxNode) -> Self {
-        Self { parent_node, node_mappings: vec![] }
-    }
-
-    pub fn map_node(&mut self, input: SyntaxNode, output: SyntaxNode) {
-        debug_assert_eq!(output.parent().as_ref(), Some(&self.parent_node));
-        self.node_mappings.push((input, output.index() as u32));
-    }
-
-    pub fn map_children(
-        &mut self,
-        input: impl Iterator<Item = SyntaxNode>,
-        output: impl Iterator<Item = SyntaxNode>,
-    ) {
-        for pairs in input.zip_longest(output) {
-            let (input, output) = match pairs {
-                itertools::EitherOrBoth::Both(l, r) => (l, r),
-                itertools::EitherOrBoth::Left(_) => {
-                    unreachable!("mapping more input nodes than there are output nodes")
-                }
-                itertools::EitherOrBoth::Right(_) => break,
-            };
-
-            self.map_node(input, output);
-        }
-    }
-
-    pub fn finish(self, editor: &mut SyntaxEditor) {
-        editor.mappings.add_mapping(self);
-    }
-}
-
-#[derive(Debug)]
-pub struct MissingMapping(pub SyntaxNode);
-
-#[derive(Debug, Clone, Copy)]
-struct MappingEntry {
-    parent: u32,
-    child_slot: u32,
-}
diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc
index f37fd7f4ab..4fcf580e75 100644
--- a/docs/user/generated_config.adoc
+++ b/docs/user/generated_config.adoc
@@ -261,13 +261,6 @@ Aliased as `"checkOnSave.targets"`.
 Whether `--workspace` should be passed to `cargo check`.
 If false, `-p <package>` will be passed instead.
 --
-[[rust-analyzer.completion.addSemicolonToUnit]]rust-analyzer.completion.addSemicolonToUnit (default: `true`)::
-+
---
-Whether to automatically add a semicolon when completing unit-returning functions.
-
-In `match` arms it completes a comma instead.
---
 [[rust-analyzer.completion.autoimport.enable]]rust-analyzer.completion.autoimport.enable (default: `true`)::
 +
 --
diff --git a/editors/code/package.json b/editors/code/package.json
index b66f0a64d5..0b029460b3 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -1027,16 +1027,6 @@
                     }
                 }
             },
-            {
-                "title": "completion",
-                "properties": {
-                    "rust-analyzer.completion.addSemicolonToUnit": {
-                        "markdownDescription": "Whether to automatically add a semicolon when completing unit-returning functions.\n\nIn `match` arms it completes a comma instead.",
-                        "default": true,
-                        "type": "boolean"
-                    }
-                }
-            },
             {
                 "title": "completion",
                 "properties": {


Test patch:
diff --git a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index a3b48831a0..37ae1ab39b 100644
--- a/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -528,21 +528,3 @@ fn main() { foobar; }
 "##]],
     );
 }
-
-#[test]
-fn test_quote_string() {
-    check(
-        r##"
-#[rustc_builtin_macro]
-macro_rules! stringify {}
-
-fn main() { stringify!("hello"); }
-"##,
-        expect![[r##"
-#[rustc_builtin_macro]
-macro_rules! stringify {}
-
-fn main() { "\"hello\""; }
-"##]],
-    );
-}
diff --git a/crates/ide-completion/src/tests.rs b/crates/ide-completion/src/tests.rs
index 9d77d97007..04ba7e1f41 100644
--- a/crates/ide-completion/src/tests.rs
+++ b/crates/ide-completion/src/tests.rs
@@ -70,7 +70,6 @@ pub(crate) const TEST_CONFIG: CompletionConfig = CompletionConfig {
     term_search_fuel: 200,
     full_function_signatures: false,
     callable: Some(CallableSnippets::FillArguments),
-    add_semicolon_to_unit: true,
     snippet_cap: SnippetCap::new(true),
     insert_use: InsertUseConfig {
         granularity: ImportGranularity::Crate,
diff --git a/crates/ide-completion/src/tests/flyimport.rs b/crates/ide-completion/src/tests/flyimport.rs
index 0b532064fb..8350fdcc4c 100644
--- a/crates/ide-completion/src/tests/flyimport.rs
+++ b/crates/ide-completion/src/tests/flyimport.rs
@@ -53,7 +53,7 @@ fn main() {
 use dep::io::stdin;
 
 fn main() {
-    stdin();$0
+    stdin()$0
 }
 "#,
     );
@@ -274,7 +274,7 @@ fn trait_function_fuzzy_completion() {
 use dep::test_mod::TestTrait;
 
 fn main() {
-    dep::test_mod::TestStruct::weird_function();$0
+    dep::test_mod::TestStruct::weird_function()$0
 }
 "#,
     );
@@ -368,7 +368,7 @@ use dep::test_mod::TestTrait;
 
 fn main() {
     let test_struct = dep::test_mod::TestStruct {};
-    test_struct.random_method();$0
+    test_struct.random_method()$0
 }
 "#,
     );
@@ -419,7 +419,7 @@ impl foo::TestTrait for fundamental::Box<TestStruct> {
 
 fn main() {
     let t = fundamental::Box(TestStruct);
-    t.some_method();$0
+    t.some_method()$0
 }
 "#,
     );
@@ -466,7 +466,7 @@ impl foo::TestTrait for &TestStruct {
 
 fn main() {
     let t = &TestStruct;
-    t.some_method();$0
+    t.some_method()$0
 }
 "#,
     );
@@ -507,7 +507,7 @@ fn completion<T: Wrapper>(whatever: T) {
 use foo::{NotInScope, Wrapper};
 
 fn completion<T: Wrapper>(whatever: T) {
-    whatever.inner().not_in_scope();$0
+    whatever.inner().not_in_scope()$0
 }
 "#,
     );
@@ -579,7 +579,7 @@ fn main() {
 use dep::test_mod::TestTrait;
 
 fn main() {
-    dep::test_mod::TestAlias::random_method();$0
+    dep::test_mod::TestAlias::random_method()$0
 }
 "#,
     );
@@ -702,7 +702,7 @@ fn main() {
 use dep::test_mod::TestTrait;
 
 fn main() {
-    dep::test_mod::TestStruct::another_function();$0
+    dep::test_mod::TestStruct::another_function()$0
 }
 "#,
     );
diff --git a/crates/ide-completion/src/tests/raw_identifiers.rs b/crates/ide-completion/src/tests/raw_identifiers.rs
index d81b3d697a..bc630189ed 100644
--- a/crates/ide-completion/src/tests/raw_identifiers.rs
+++ b/crates/ide-completion/src/tests/raw_identifiers.rs
@@ -30,7 +30,7 @@ fn foo() {
 "#,
         expect![[r#"
             fn foo() {
-                a::dyn();$0
+                a::dyn()$0
         "#]],
     );
 
@@ -45,7 +45,7 @@ fn foo() {
 "#,
         expect![[r#"
             fn foo() {
-                a::dyn();$0
+                a::dyn()$0
         "#]],
     );
 }
@@ -63,7 +63,7 @@ fn foo() {
 "#,
         expect![[r#"
             fn foo() {
-                a::r#dyn();$0
+                a::r#dyn()$0
         "#]],
     );
 
@@ -78,7 +78,7 @@ fn foo() {
 "#,
         expect![[r#"
             fn foo() {
-                a::r#dyn();$0
+                a::r#dyn()$0
         "#]],
     );
 }
diff --git a/crates/ide-completion/src/tests/special.rs b/crates/ide-completion/src/tests/special.rs
index 508f6248dd..2ae7d37889 100644
--- a/crates/ide-completion/src/tests/special.rs
+++ b/crates/ide-completion/src/tests/special.rs
@@ -63,7 +63,7 @@ fn _alpha() {}
 "#,
         r#"
 fn main() {
-    _alpha();$0
+    _alpha()$0
 }
 fn _alpha() {}
 "#,