Auto merge of #17967 - Veykril:mbe-tests, r=Veykril

internal: Lay basic ground work for standalone mbe tests

Most of our mbe hir-def tests don't actually do anything name res relevant, we can (and should) move those down the stack into `mbe/hir-expand`.
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 3616fa9..032e4a8 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -374,37 +374,6 @@
         self.arena.alloc(data)
     }
 
-    /// Remove the crate from crate graph. If any crates depend on this crate, the dependency would be replaced
-    /// with the second input.
-    pub fn remove_and_replace(
-        &mut self,
-        id: CrateId,
-        replace_with: CrateId,
-    ) -> Result<(), CyclicDependenciesError> {
-        for (x, data) in self.arena.iter() {
-            if x == id {
-                continue;
-            }
-            for edge in &data.dependencies {
-                if edge.crate_id == id {
-                    self.check_cycle_after_dependency(edge.crate_id, replace_with)?;
-                }
-            }
-        }
-        // if everything was ok, start to replace
-        for (x, data) in self.arena.iter_mut() {
-            if x == id {
-                continue;
-            }
-            for edge in &mut data.dependencies {
-                if edge.crate_id == id {
-                    edge.crate_id = replace_with;
-                }
-            }
-        }
-        Ok(())
-    }
-
     pub fn add_dep(
         &mut self,
         from: CrateId,
@@ -412,26 +381,17 @@
     ) -> Result<(), CyclicDependenciesError> {
         let _p = tracing::info_span!("add_dep").entered();
 
-        self.check_cycle_after_dependency(from, dep.crate_id)?;
-
-        self.arena[from].add_dep(dep);
-        Ok(())
-    }
-
-    /// Check if adding a dep from `from` to `to` creates a cycle. To figure
-    /// that out, look for a  path in the *opposite* direction, from `to` to
-    /// `from`.
-    fn check_cycle_after_dependency(
-        &self,
-        from: CrateId,
-        to: CrateId,
-    ) -> Result<(), CyclicDependenciesError> {
-        if let Some(path) = self.find_path(&mut FxHashSet::default(), to, from) {
+        // Check if adding a dep from `from` to `to` creates a cycle. To figure
+        // that out, look for a  path in the *opposite* direction, from `to` to
+        // `from`.
+        if let Some(path) = self.find_path(&mut FxHashSet::default(), dep.crate_id, from) {
             let path = path.into_iter().map(|it| (it, self[it].display_name.clone())).collect();
             let err = CyclicDependenciesError { path };
-            assert!(err.from().0 == from && err.to().0 == to);
+            assert!(err.from().0 == from && err.to().0 == dep.crate_id);
             return Err(err);
         }
+
+        self.arena[from].add_dep(dep);
         Ok(())
     }
 
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 8b6cde9..e5c493a 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -11,7 +11,7 @@
     ConstBlockLoc, EnumVariantId, GeneralConstId, StaticId,
 };
 use hir_expand::Lookup;
-use stdx::never;
+use stdx::{never, IsNoneOr};
 use triomphe::Arc;
 
 use crate::{
@@ -184,6 +184,22 @@
     }
 }
 
+pub fn try_const_isize(db: &dyn HirDatabase, c: &Const) -> Option<i128> {
+    match &c.data(Interner).value {
+        chalk_ir::ConstValue::BoundVar(_) => None,
+        chalk_ir::ConstValue::InferenceVar(_) => None,
+        chalk_ir::ConstValue::Placeholder(_) => None,
+        chalk_ir::ConstValue::Concrete(c) => match &c.interned {
+            ConstScalar::Bytes(it, _) => Some(i128::from_le_bytes(pad16(it, true))),
+            ConstScalar::UnevaluatedConst(c, subst) => {
+                let ec = db.const_eval(*c, subst.clone(), None).ok()?;
+                try_const_isize(db, &ec)
+            }
+            _ => None,
+        },
+    }
+}
+
 pub(crate) fn const_eval_recover(
     _: &dyn HirDatabase,
     _: &Cycle,
@@ -256,8 +272,8 @@
 ) -> Result<i128, ConstEvalError> {
     let def = variant_id.into();
     let body = db.body(def);
+    let loc = variant_id.lookup(db.upcast());
     if body.exprs[body.body_expr] == Expr::Missing {
-        let loc = variant_id.lookup(db.upcast());
         let prev_idx = loc.index.checked_sub(1);
         let value = match prev_idx {
             Some(prev_idx) => {
@@ -269,13 +285,21 @@
         };
         return Ok(value);
     }
+
+    let repr = db.enum_data(loc.parent).repr;
+    let is_signed = repr.and_then(|repr| repr.int).is_none_or(|int| int.is_signed());
+
     let mir_body = db.monomorphized_mir_body(
         def,
         Substitution::empty(Interner),
         db.trait_environment_for_body(def),
     )?;
     let c = interpret_mir(db, mir_body, false, None).0?;
-    let c = try_const_usize(db, &c).unwrap() as i128;
+    let c = if is_signed {
+        try_const_isize(db, &c).unwrap()
+    } else {
+        try_const_usize(db, &c).unwrap() as i128
+    };
     Ok(c)
 }
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 527ecf0..6328a3c 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2208,6 +2208,35 @@
         db.function_data(self.id).is_async()
     }
 
+    pub fn returns_impl_future(self, db: &dyn HirDatabase) -> bool {
+        if self.is_async(db) {
+            return true;
+        }
+
+        let Some(impl_traits) = self.ret_type(db).as_impl_traits(db) else { return false };
+        let Some(future_trait_id) =
+            db.lang_item(self.ty(db).env.krate, LangItem::Future).and_then(|t| t.as_trait())
+        else {
+            return false;
+        };
+        let Some(sized_trait_id) =
+            db.lang_item(self.ty(db).env.krate, LangItem::Sized).and_then(|t| t.as_trait())
+        else {
+            return false;
+        };
+
+        let mut has_impl_future = false;
+        impl_traits
+            .filter(|t| {
+                let fut = t.id == future_trait_id;
+                has_impl_future |= fut;
+                !fut && t.id != sized_trait_id
+            })
+            // all traits but the future trait must be auto traits
+            .all(|t| t.is_auto(db))
+            && has_impl_future
+    }
+
     /// Does this function have `#[test]` attribute?
     pub fn is_test(self, db: &dyn HirDatabase) -> bool {
         db.function_data(self.id).attrs.is_test()
diff --git a/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs b/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs
new file mode 100644
index 0000000..fafc344
--- /dev/null
+++ b/crates/ide-assists/src/handlers/explicit_enum_discriminant.rs
@@ -0,0 +1,206 @@
+use hir::Semantics;
+use ide_db::{
+    assists::{AssistId, AssistKind},
+    source_change::SourceChangeBuilder,
+    RootDatabase,
+};
+use syntax::{ast, AstNode};
+
+use crate::{AssistContext, Assists};
+
+// Assist: explicit_enum_discriminant
+//
+// Adds explicit discriminant to all enum variants.
+//
+// ```
+// enum TheEnum$0 {
+//     Foo,
+//     Bar,
+//     Baz = 42,
+//     Quux,
+// }
+// ```
+// ->
+// ```
+// enum TheEnum {
+//     Foo = 0,
+//     Bar = 1,
+//     Baz = 42,
+//     Quux = 43,
+// }
+// ```
+pub(crate) fn explicit_enum_discriminant(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let enum_node = ctx.find_node_at_offset::<ast::Enum>()?;
+    let enum_def = ctx.sema.to_def(&enum_node)?;
+
+    let is_data_carrying = enum_def.is_data_carrying(ctx.db());
+    let has_primitive_repr = enum_def.repr(ctx.db()).and_then(|repr| repr.int).is_some();
+
+    // Data carrying enums without a primitive repr have no stable discriminants.
+    if is_data_carrying && !has_primitive_repr {
+        return None;
+    }
+
+    let variant_list = enum_node.variant_list()?;
+
+    // Don't offer the assist if the enum has no variants or if all variants already have an
+    // explicit discriminant.
+    if variant_list.variants().all(|variant_node| variant_node.expr().is_some()) {
+        return None;
+    }
+
+    acc.add(
+        AssistId("explicit_enum_discriminant", AssistKind::RefactorRewrite),
+        "Add explicit enum discriminants",
+        enum_node.syntax().text_range(),
+        |builder| {
+            for variant_node in variant_list.variants() {
+                add_variant_discriminant(&ctx.sema, builder, &variant_node);
+            }
+        },
+    );
+
+    Some(())
+}
+
+fn add_variant_discriminant(
+    sema: &Semantics<'_, RootDatabase>,
+    builder: &mut SourceChangeBuilder,
+    variant_node: &ast::Variant,
+) {
+    if variant_node.expr().is_some() {
+        return;
+    }
+
+    let Some(variant_def) = sema.to_def(variant_node) else {
+        return;
+    };
+    let Ok(discriminant) = variant_def.eval(sema.db) else {
+        return;
+    };
+
+    let variant_range = variant_node.syntax().text_range();
+
+    builder.insert(variant_range.end(), format!(" = {discriminant}"));
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::{check_assist, check_assist_not_applicable};
+
+    use super::explicit_enum_discriminant;
+
+    #[test]
+    fn non_primitive_repr_non_data_bearing_add_discriminant() {
+        check_assist(
+            explicit_enum_discriminant,
+            r#"
+enum TheEnum$0 {
+    Foo,
+    Bar,
+    Baz = 42,
+    Quux,
+    FooBar = -5,
+    FooBaz,
+}
+"#,
+            r#"
+enum TheEnum {
+    Foo = 0,
+    Bar = 1,
+    Baz = 42,
+    Quux = 43,
+    FooBar = -5,
+    FooBaz = -4,
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn primitive_repr_data_bearing_add_discriminant() {
+        check_assist(
+            explicit_enum_discriminant,
+            r#"
+#[repr(u8)]
+$0enum TheEnum {
+    Foo { x: u32 },
+    Bar,
+    Baz(String),
+    Quux,
+}
+"#,
+            r#"
+#[repr(u8)]
+enum TheEnum {
+    Foo { x: u32 } = 0,
+    Bar = 1,
+    Baz(String) = 2,
+    Quux = 3,
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn non_primitive_repr_data_bearing_not_applicable() {
+        check_assist_not_applicable(
+            explicit_enum_discriminant,
+            r#"
+enum TheEnum$0 {
+    Foo,
+    Bar(u16),
+    Baz,
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn primitive_repr_non_data_bearing_add_discriminant() {
+        check_assist(
+            explicit_enum_discriminant,
+            r#"
+#[repr(i64)]
+enum TheEnum {
+    Foo = 1 << 63,
+    Bar,
+    Baz$0 = 0x7fff_ffff_ffff_fffe,
+    Quux,
+}
+"#,
+            r#"
+#[repr(i64)]
+enum TheEnum {
+    Foo = 1 << 63,
+    Bar = -9223372036854775807,
+    Baz = 0x7fff_ffff_ffff_fffe,
+    Quux = 9223372036854775807,
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn discriminants_already_explicit_not_applicable() {
+        check_assist_not_applicable(
+            explicit_enum_discriminant,
+            r#"
+enum TheEnum$0 {
+    Foo = 0,
+    Bar = 4,
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn empty_enum_not_applicable() {
+        check_assist_not_applicable(
+            explicit_enum_discriminant,
+            r#"
+enum TheEnum$0 {}
+"#,
+        );
+    }
+}
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index c88cb3d..b2ccd1f 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -136,6 +136,7 @@
     mod destructure_tuple_binding;
     mod desugar_doc_comment;
     mod expand_glob_import;
+    mod explicit_enum_discriminant;
     mod extract_expressions_from_format_string;
     mod extract_function;
     mod extract_module;
@@ -266,6 +267,7 @@
             destructure_tuple_binding::destructure_tuple_binding,
             destructure_struct_binding::destructure_struct_binding,
             expand_glob_import::expand_glob_import,
+            explicit_enum_discriminant::explicit_enum_discriminant,
             extract_expressions_from_format_string::extract_expressions_from_format_string,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
             extract_type_alias::extract_type_alias,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index dce7bbf..48e12a8 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -910,6 +910,29 @@
 }
 
 #[test]
+fn doctest_explicit_enum_discriminant() {
+    check_doc_test(
+        "explicit_enum_discriminant",
+        r#####"
+enum TheEnum$0 {
+    Foo,
+    Bar,
+    Baz = 42,
+    Quux,
+}
+"#####,
+        r#####"
+enum TheEnum {
+    Foo = 0,
+    Bar = 1,
+    Baz = 42,
+    Quux = 43,
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_extract_expressions_from_format_string() {
     check_doc_test(
         "extract_expressions_from_format_string",
diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs
index fc6e1eb..e93bb8d 100644
--- a/crates/ide-completion/src/completions/item_list/trait_impl.rs
+++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs
@@ -31,14 +31,14 @@
 //! }
 //! ```
 
-use hir::HasAttrs;
+use hir::{HasAttrs, Name};
 use ide_db::{
     documentation::HasDocs, path_transform::PathTransform,
     syntax_helpers::insert_whitespace_into_node, traits::get_missing_assoc_items, SymbolKind,
 };
 use syntax::{
-    ast::{self, edit_in_place::AttrsOwnerEdit, HasTypeBounds},
-    format_smolstr, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T,
+    ast::{self, edit_in_place::AttrsOwnerEdit, make, HasGenericArgs, HasTypeBounds},
+    format_smolstr, ted, AstNode, SmolStr, SyntaxElement, SyntaxKind, TextRange, ToSmolStr, T,
 };
 use text_edit::TextEdit;
 
@@ -178,12 +178,36 @@
     func: hir::Function,
     impl_def: hir::Impl,
 ) {
-    let fn_name = func.name(ctx.db);
+    let fn_name = &func.name(ctx.db);
+    let sugar: &[_] = if func.is_async(ctx.db) {
+        &[AsyncSugaring::Async, AsyncSugaring::Desugar]
+    } else if func.returns_impl_future(ctx.db) {
+        &[AsyncSugaring::Plain, AsyncSugaring::Resugar]
+    } else {
+        &[AsyncSugaring::Plain]
+    };
+    for &sugaring in sugar {
+        add_function_impl_(acc, ctx, replacement_range, func, impl_def, fn_name, sugaring);
+    }
+}
 
-    let is_async = func.is_async(ctx.db);
+fn add_function_impl_(
+    acc: &mut Completions,
+    ctx: &CompletionContext<'_>,
+    replacement_range: TextRange,
+    func: hir::Function,
+    impl_def: hir::Impl,
+    fn_name: &Name,
+    async_sugaring: AsyncSugaring,
+) {
+    let async_ = if let AsyncSugaring::Async | AsyncSugaring::Resugar = async_sugaring {
+        "async "
+    } else {
+        ""
+    };
     let label = format_smolstr!(
         "{}fn {}({})",
-        if is_async { "async " } else { "" },
+        async_,
         fn_name.display(ctx.db, ctx.edition),
         if func.assoc_fn_params(ctx.db).is_empty() { "" } else { ".." }
     );
@@ -195,22 +219,14 @@
     });
 
     let mut item = CompletionItem::new(completion_kind, replacement_range, label, ctx.edition);
-    item.lookup_by(format!(
-        "{}fn {}",
-        if is_async { "async " } else { "" },
-        fn_name.display(ctx.db, ctx.edition)
-    ))
-    .set_documentation(func.docs(ctx.db))
-    .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
+    item.lookup_by(format!("{}fn {}", async_, fn_name.display(ctx.db, ctx.edition)))
+        .set_documentation(func.docs(ctx.db))
+        .set_relevance(CompletionRelevance { is_item_from_trait: true, ..Default::default() });
 
     if let Some(source) = ctx.sema.source(func) {
-        let assoc_item = ast::AssocItem::Fn(source.value);
-        if let Some(transformed_item) = get_transformed_assoc_item(ctx, assoc_item, impl_def) {
-            let transformed_fn = match transformed_item {
-                ast::AssocItem::Fn(func) => func,
-                _ => unreachable!(),
-            };
-
+        if let Some(transformed_fn) =
+            get_transformed_fn(ctx, source.value, impl_def, async_sugaring)
+        {
             let function_decl = function_declaration(&transformed_fn, source.file_id.is_macro());
             match ctx.config.snippet_cap {
                 Some(cap) => {
@@ -227,6 +243,14 @@
     }
 }
 
+#[derive(Copy, Clone)]
+enum AsyncSugaring {
+    Desugar,
+    Resugar,
+    Async,
+    Plain,
+}
+
 /// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
 fn get_transformed_assoc_item(
     ctx: &CompletionContext<'_>,
@@ -251,6 +275,82 @@
     Some(assoc_item)
 }
 
+/// Transform a relevant associated item to inline generics from the impl, remove attrs and docs, etc.
+fn get_transformed_fn(
+    ctx: &CompletionContext<'_>,
+    fn_: ast::Fn,
+    impl_def: hir::Impl,
+    async_: AsyncSugaring,
+) -> Option<ast::Fn> {
+    let trait_ = impl_def.trait_(ctx.db)?;
+    let source_scope = &ctx.sema.scope(fn_.syntax())?;
+    let target_scope = &ctx.sema.scope(ctx.sema.source(impl_def)?.syntax().value)?;
+    let transform = PathTransform::trait_impl(
+        target_scope,
+        source_scope,
+        trait_,
+        ctx.sema.source(impl_def)?.value,
+    );
+
+    let fn_ = fn_.clone_for_update();
+    // FIXME: Paths in nested macros are not handled well. See
+    // `macro_generated_assoc_item2` test.
+    transform.apply(fn_.syntax());
+    fn_.remove_attrs_and_docs();
+    match async_ {
+        AsyncSugaring::Desugar => {
+            match fn_.ret_type() {
+                Some(ret_ty) => {
+                    let ty = ret_ty.ty()?;
+                    ted::replace(
+                        ty.syntax(),
+                        make::ty(&format!("impl Future<Output = {ty}>"))
+                            .syntax()
+                            .clone_for_update(),
+                    );
+                }
+                None => ted::append_child(
+                    fn_.param_list()?.syntax(),
+                    make::ret_type(make::ty("impl Future<Output = ()>"))
+                        .syntax()
+                        .clone_for_update(),
+                ),
+            }
+            fn_.async_token().unwrap().detach();
+        }
+        AsyncSugaring::Resugar => {
+            let ty = fn_.ret_type()?.ty()?;
+            match &ty {
+                // best effort guessing here
+                ast::Type::ImplTraitType(t) => {
+                    let output = t.type_bound_list()?.bounds().find_map(|b| match b.ty()? {
+                        ast::Type::PathType(p) => {
+                            let p = p.path()?.segment()?;
+                            if p.name_ref()?.text() != "Future" {
+                                return None;
+                            }
+                            match p.generic_arg_list()?.generic_args().next()? {
+                                ast::GenericArg::AssocTypeArg(a)
+                                    if a.name_ref()?.text() == "Output" =>
+                                {
+                                    a.ty()
+                                }
+                                _ => None,
+                            }
+                        }
+                        _ => None,
+                    })?;
+                    ted::replace(ty.syntax(), output.syntax());
+                }
+                _ => (),
+            }
+            ted::prepend_child(fn_.syntax(), make::token(T![async]));
+        }
+        AsyncSugaring::Async | AsyncSugaring::Plain => (),
+    }
+    Some(fn_)
+}
+
 fn add_type_alias_impl(
     acc: &mut Completions,
     ctx: &CompletionContext<'_>,
@@ -1404,4 +1504,132 @@
 "#,
         );
     }
+
+    #[test]
+    fn impl_fut() {
+        check_edit(
+            "fn foo",
+            r#"
+//- minicore: future, send, sized
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    fn foo(&self) -> impl Future<Output = usize> + Send;
+}
+
+impl DesugaredAsyncTrait for () {
+    $0
+}
+"#,
+            r#"
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    fn foo(&self) -> impl Future<Output = usize> + Send;
+}
+
+impl DesugaredAsyncTrait for () {
+    fn foo(&self) -> impl Future<Output = usize> + Send {
+    $0
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn impl_fut_resugared() {
+        check_edit(
+            "async fn foo",
+            r#"
+//- minicore: future, send, sized
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    fn foo(&self) -> impl Future<Output = usize> + Send;
+}
+
+impl DesugaredAsyncTrait for () {
+    $0
+}
+"#,
+            r#"
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    fn foo(&self) -> impl Future<Output = usize> + Send;
+}
+
+impl DesugaredAsyncTrait for () {
+    async fn foo(&self) -> usize {
+    $0
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn async_desugared() {
+        check_edit(
+            "fn foo",
+            r#"
+//- minicore: future, send, sized
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    async fn foo(&self) -> usize;
+}
+
+impl DesugaredAsyncTrait for () {
+    $0
+}
+"#,
+            r#"
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    async fn foo(&self) -> usize;
+}
+
+impl DesugaredAsyncTrait for () {
+     fn foo(&self) -> impl Future<Output = usize> {
+    $0
+}
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn async_() {
+        check_edit(
+            "async fn foo",
+            r#"
+//- minicore: future, send, sized
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    async fn foo(&self) -> usize;
+}
+
+impl DesugaredAsyncTrait for () {
+    $0
+}
+"#,
+            r#"
+use core::future::Future;
+
+trait DesugaredAsyncTrait {
+    async fn foo(&self) -> usize;
+}
+
+impl DesugaredAsyncTrait for () {
+    async fn foo(&self) -> usize {
+    $0
+}
+}
+"#,
+        );
+    }
 }
diff --git a/crates/ide-completion/src/tests/item_list.rs b/crates/ide-completion/src/tests/item_list.rs
index 8aad7bf..532d492 100644
--- a/crates/ide-completion/src/tests/item_list.rs
+++ b/crates/ide-completion/src/tests/item_list.rs
@@ -313,6 +313,7 @@
             ct const CONST1: () =
             fn async fn function2()
             fn fn function1()
+            fn fn function2()
             ma makro!(…)            macro_rules! makro
             md module
             ta type Type1 =
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 7834238..4fc9ef3 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -1554,6 +1554,6 @@
 
 fn add_dep_inner(graph: &mut CrateGraph, from: CrateId, dep: Dependency) {
     if let Err(err) = graph.add_dep(from, dep) {
-        tracing::error!("{}", err)
+        tracing::warn!("{}", err)
     }
 }
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index abf1a1f..2eb9c1e 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -1162,7 +1162,7 @@
 
     pub(super) static SOURCE_FILE: LazyLock<Parse<SourceFile>> = LazyLock::new(|| {
         SourceFile::parse(
-            "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, { let _ @ [] })\n;\n\nimpl A for B where: {}", Edition::CURRENT,
+            "const C: <()>::Item = ( true && true , true || true , 1 != 1, 2 == 2, 3 < 3, 4 <= 4, 5 > 5, 6 >= 6, !true, *p, &p , &mut p, async { let _ @ [] })\n;\n\nimpl A for B where: {}", Edition::CURRENT,
         )
     });
 
diff --git a/crates/syntax/src/ted.rs b/crates/syntax/src/ted.rs
index 29788d0..8592df1 100644
--- a/crates/syntax/src/ted.rs
+++ b/crates/syntax/src/ted.rs
@@ -147,6 +147,11 @@
     insert_raw(position, child);
 }
 
+pub fn prepend_child(node: &(impl Into<SyntaxNode> + Clone), child: impl Element) {
+    let position = Position::first_child_of(node);
+    insert(position, child);
+}
+
 fn ws_before(position: &Position, new: &SyntaxElement) -> Option<SyntaxToken> {
     let prev = match &position.repr {
         PositionRepr::FirstChild(_) => return None,