Repository: rust-lang/rust-analyzer
Pull request #18093 (2024-09-10 16:44:55)

Skip checks for cast to dyn traits
It seems that chalk fails to solve some obvious goals when there are some recursiveness in trait environments.
And it doesn't support trait upcasting yet. rust-lang/chalk#796

This PR just skips for casting into types containing `dyn Trait` to prevent false positive diagnostics like #18047 and #18083


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 ae91404436..caa3960a22 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -120,6 +120,13 @@ 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);
@@ -410,3 +417,35 @@ 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 99ad678980..d38380e4a3 100644
--- a/crates/hir-ty/src/infer/unify.rs
+++ b/crates/hir-ty/src/infer/unify.rs
@@ -902,6 +902,10 @@ 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/ide-diagnostics/src/handlers/invalid_cast.rs b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
index 9eb4e618c0..90527c578e 100644
--- a/crates/ide-diagnostics/src/handlers/invalid_cast.rs
+++ b/crates/ide-diagnostics/src/handlers/invalid_cast.rs
@@ -556,6 +556,7 @@ 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(
@@ -1004,4 +1005,99 @@ 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/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,
-}


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\""; }
-"##]],
-    );
-}