Repository: rust-lang/rust-analyzer
Pull request #12982 (2022-08-09 01:50:29)

Implement IntoFuture type inference
One of my projects is using [IntoFuture](https://doc.rust-lang.org/std/future/trait.IntoFuture.html) to make our async code a little less verbose. However, rust-analyzer can't infer the output type of an await expression if the value uses `IntoFuture` to convert into another type. So we're getting `{unknown}` types everywhere since switching.

`foo.await` itself [desugars](https://github.com/rust-lang/rust/blob/e4417cf020fbcd6182c11637bc6b8694434bd81a/compiler/rustc_ast_lowering/src/expr.rs#L644-L658) into a `match into_future(foo) {}`, with every `Future` impl getting a [default](https://github.com/rust-lang/rust/blob/e4417cf020fbcd6182c11637bc6b8694434bd81a/library/core/src/future/into_future.rs#L131-L139) `IntoFuture` implementation. I'm not sure if we want to disable the old `future_trait` paths, since this only recently [stabilize](https://github.com/rust-lang/rust/pull/98718).


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 7c6796d70b..703f0e5b8a 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -710,7 +710,6 @@ dependencies = [
  "ide-db",
  "itertools",
  "profile",
- "serde_json",
  "sourcegen",
  "stdx",
  "syntax",
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index 469b28c2d9..2397cf5015 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -451,7 +451,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
         if let GenericDefId::TraitId(id) = *self {
             let trait_ref = id.lookup(db).source(db).value;
             let idx = idx_iter.next().unwrap();
-            params.insert(idx, Either::Right(trait_ref));
+            params.insert(idx, Either::Right(trait_ref))
         }
 
         if let Some(generic_params_list) = generic_params_list {
diff --git a/crates/hir-def/src/visibility.rs b/crates/hir-def/src/visibility.rs
index 087268a9ec..6e22a877a9 100644
--- a/crates/hir-def/src/visibility.rs
+++ b/crates/hir-def/src/visibility.rs
@@ -224,7 +224,7 @@ pub(crate) fn field_visibilities_query(
     let resolver = variant_id.module(db).resolver(db);
     let mut res = ArenaMap::default();
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, field_data.visibility.resolve(db, &resolver));
+        res.insert(field_id, field_data.visibility.resolve(db, &resolver))
     }
     Arc::new(res)
 }
diff --git a/crates/hir-expand/src/builtin_fn_macro.rs b/crates/hir-expand/src/builtin_fn_macro.rs
index c21b35cdc0..76da7c9f1e 100644
--- a/crates/hir-expand/src/builtin_fn_macro.rs
+++ b/crates/hir-expand/src/builtin_fn_macro.rs
@@ -357,12 +357,6 @@ fn unquote_str(lit: &tt::Literal) -> Option<String> {
     token.value().map(|it| it.into_owned())
 }
 
-fn unquote_char(lit: &tt::Literal) -> Option<char> {
-    let lit = ast::make::tokens::literal(&lit.to_string());
-    let token = ast::Char::cast(lit)?;
-    token.value()
-}
-
 fn unquote_byte_string(lit: &tt::Literal) -> Option<Vec<u8>> {
     let lit = ast::make::tokens::literal(&lit.to_string());
     let token = ast::ByteString::cast(lit)?;
@@ -414,12 +408,8 @@ fn concat_expand(
                 // concat works with string and char literals, so remove any quotes.
                 // It also works with integer, float and boolean literals, so just use the rest
                 // as-is.
-                if let Some(c) = unquote_char(it) {
-                    text.push(c);
-                } else {
-                    let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
-                    text.push_str(&component);
-                }
+                let component = unquote_str(it).unwrap_or_else(|| it.text.to_string());
+                text.push_str(&component);
             }
             // handle boolean literals
             tt::TokenTree::Leaf(tt::Leaf::Ident(id))
diff --git a/crates/hir-expand/src/fixup.rs b/crates/hir-expand/src/fixup.rs
index 46257b6bc4..e46f43a878 100644
--- a/crates/hir-expand/src/fixup.rs
+++ b/crates/hir-expand/src/fixup.rs
@@ -67,6 +67,7 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
             preorder.skip_subtree();
             continue;
         }
+
         // In some other situations, we can fix things by just appending some tokens.
         let end_range = TextRange::empty(node.text_range().end());
         match_ast! {
@@ -193,75 +194,7 @@ pub(crate) fn fixup_syntax(node: &SyntaxNode) -> SyntaxFixups {
                     }
                 },
                 // FIXME: foo::
-                ast::MatchExpr(it) => {
-                    if it.expr().is_none() {
-                        let match_token = match it.match_token() {
-                            Some(t) => t,
-                            None => continue
-                        };
-                        append.insert(match_token.into(), vec![
-                            SyntheticToken {
-                                kind: SyntaxKind::IDENT,
-                                text: "__ra_fixup".into(),
-                                range: end_range,
-                                id: EMPTY_ID
-                            },
-                        ]);
-                    }
-                    if it.match_arm_list().is_none() {
-                        // No match arms
-                        append.insert(node.clone().into(), vec![
-                            SyntheticToken {
-                                kind: SyntaxKind::L_CURLY,
-                                text: "{".into(),
-                                range: end_range,
-                                id: EMPTY_ID,
-                            },
-                            SyntheticToken {
-                                kind: SyntaxKind::R_CURLY,
-                                text: "}".into(),
-                                range: end_range,
-                                id: EMPTY_ID,
-                            },
-                        ]);
-                    }
-                },
-                ast::ForExpr(it) => {
-                    let for_token = match it.for_token() {
-                        Some(token) => token,
-                        None => continue
-                    };
-
-                    let [pat, in_token, iter] = [
-                        (SyntaxKind::UNDERSCORE, "_"),
-                        (SyntaxKind::IN_KW, "in"),
-                        (SyntaxKind::IDENT, "__ra_fixup")
-                    ].map(|(kind, text)| SyntheticToken { kind, text: text.into(), range: end_range, id: EMPTY_ID});
-
-                    if it.pat().is_none() && it.in_token().is_none() && it.iterable().is_none() {
-                        append.insert(for_token.into(), vec![pat, in_token, iter]);
-                    // does something funky -- see test case for_no_pat
-                    } else if it.pat().is_none() {
-                        append.insert(for_token.into(), vec![pat]);
-                    }
-
-                    if it.loop_body().is_none() {
-                        append.insert(node.clone().into(), vec![
-                            SyntheticToken {
-                                kind: SyntaxKind::L_CURLY,
-                                text: "{".into(),
-                                range: end_range,
-                                id: EMPTY_ID,
-                            },
-                            SyntheticToken {
-                                kind: SyntaxKind::R_CURLY,
-                                text: "}".into(),
-                                range: end_range,
-                                id: EMPTY_ID,
-                            },
-                        ]);
-                    }
-                },
+                // FIXME: for, match etc.
                 _ => (),
             }
         }
@@ -354,111 +287,6 @@ mod tests {
         assert_eq!(tt.to_string(), original_as_tt.to_string());
     }
 
-    #[test]
-    fn just_for_token() {
-        check(
-            r#"
-fn foo() {
-    for
-}
-"#,
-            expect![[r#"
-fn foo () {for _ in __ra_fixup {}}
-"#]],
-        )
-    }
-
-    #[test]
-    fn for_no_iter_pattern() {
-        check(
-            r#"
-fn foo() {
-    for {}
-}
-"#,
-            expect![[r#"
-fn foo () {for _ in __ra_fixup {}}
-"#]],
-        )
-    }
-
-    #[test]
-    fn for_no_body() {
-        check(
-            r#"
-fn foo() {
-    for bar in qux
-}
-"#,
-            expect![[r#"
-fn foo () {for bar in qux {}}
-"#]],
-        )
-    }
-
-    // FIXME: https://github.com/rust-lang/rust-analyzer/pull/12937#discussion_r937633695
-    #[test]
-    fn for_no_pat() {
-        check(
-            r#"
-fn foo() {
-    for in qux {
-
-    }
-}
-"#,
-            expect![[r#"
-fn foo () {__ra_fixup}
-"#]],
-        )
-    }
-
-    #[test]
-    fn match_no_expr_no_arms() {
-        check(
-            r#"
-fn foo() {
-    match
-}
-"#,
-            expect![[r#"
-fn foo () {match __ra_fixup {}}
-"#]],
-        )
-    }
-
-    #[test]
-    fn match_expr_no_arms() {
-        check(
-            r#"
-fn foo() {
-    match x {
-
-    }
-}
-"#,
-            expect![[r#"
-fn foo () {match x {}}
-"#]],
-        )
-    }
-
-    #[test]
-    fn match_no_expr() {
-        check(
-            r#"
-fn foo() {
-    match {
-        _ => {}
-    }
-}
-"#,
-            expect![[r#"
-fn foo () {match __ra_fixup {}}
-"#]],
-        )
-    }
-
     #[test]
     fn incomplete_field_expr_1() {
         check(
diff --git a/crates/hir-expand/src/mod_path.rs b/crates/hir-expand/src/mod_path.rs
index fea09521e8..9ddafe0181 100644
--- a/crates/hir-expand/src/mod_path.rs
+++ b/crates/hir-expand/src/mod_path.rs
@@ -257,6 +257,7 @@ macro_rules! __known_path {
     (core::ops::RangeToInclusive) => {};
     (core::ops::RangeInclusive) => {};
     (core::future::Future) => {};
+    (core::future::IntoFuture) => {};
     (core::ops::Try) => {};
     ($path:path) => {
         compile_error!("Please register your known path in the path module")
diff --git a/crates/hir-expand/src/name.rs b/crates/hir-expand/src/name.rs
index 47d191822d..757db79db4 100644
--- a/crates/hir-expand/src/name.rs
+++ b/crates/hir-expand/src/name.rs
@@ -258,6 +258,7 @@ pub mod known {
         Try,
         Ok,
         Future,
+        IntoFuture,
         Result,
         Option,
         Output,
@@ -391,6 +392,7 @@ pub mod known {
         future_trait,
         index,
         index_mut,
+        into_future,
         mul_assign,
         mul,
         neg,
diff --git a/crates/hir-expand/src/quote.rs b/crates/hir-expand/src/quote.rs
index e839e97bf0..82f410ecda 100644
--- a/crates/hir-expand/src/quote.rs
+++ b/crates/hir-expand/src/quote.rs
@@ -196,8 +196,8 @@ impl_to_to_tokentrees! {
     tt::Literal => self { self };
     tt::Ident => self { self };
     tt::Punct => self { self };
-    &str => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}};
-    String => self { tt::Literal{text: format!("\"{}\"", self.escape_default()).into(), id: tt::TokenId::unspecified()}}
+    &str => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}};
+    String => self { tt::Literal{text: format!("\"{}\"", self.escape_debug()).into(), id: tt::TokenId::unspecified()}}
 }
 
 #[cfg(test)]
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 46eeea0e6f..95a7229e87 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -875,7 +875,10 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn resolve_future_future_output(&self) -> Option<TypeAliasId> {
-        let trait_ = self.resolve_lang_item(name![future_trait])?.as_trait()?;
+        let trait_ = self
+            .resolver
+            .resolve_known_trait(self.db.upcast(), &path![core::future::IntoFuture])
+            .or_else(|| self.resolve_lang_item(name![future_trait])?.as_trait())?;
         self.db.trait_data(trait_).associated_type_by_name(&name![Output])
     }
 
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 239f66bcb7..3ed9c941f4 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -1126,7 +1126,7 @@ pub(crate) fn field_types_query(
     let ctx =
         TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)));
+        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)))
     }
     Arc::new(res)
 }
diff --git a/crates/hir/src/diagnostics.rs b/crates/hir/src/diagnostics.rs
index 50374f4b3f..6c6c11ea4e 100644
--- a/crates/hir/src/diagnostics.rs
+++ b/crates/hir/src/diagnostics.rs
@@ -14,7 +14,6 @@ use crate::{MacroKind, Type};
 
 macro_rules! diagnostics {
     ($($diag:ident,)*) => {
-        #[derive(Debug)]
         pub enum AnyDiagnostic {$(
             $diag(Box<$diag>),
         )*}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 8f984210e1..46d24b9f14 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2777,20 +2777,32 @@ impl Type {
         self.ty.is_unknown()
     }
 
-    /// Checks that particular type `ty` implements `std::future::Future`.
+    /// Checks that particular type `ty` implements `std::future::IntoFuture` or
+    /// `std::future::Future`.
     /// This function is used in `.await` syntax completion.
-    pub fn impls_future(&self, db: &dyn HirDatabase) -> bool {
-        let std_future_trait = db
-            .lang_item(self.env.krate, SmolStr::new_inline("future_trait"))
-            .and_then(|it| it.as_trait());
-        let std_future_trait = match std_future_trait {
+    pub fn impls_into_future(&self, db: &dyn HirDatabase) -> bool {
+        let trait_ = db
+            .lang_item(self.env.krate, SmolStr::new_inline("into_future"))
+            .and_then(|it| {
+                let into_future_fn = it.as_function()?;
+                let assoc_item = as_assoc_item(db, AssocItem::Function, into_future_fn)?;
+                let into_future_trait = assoc_item.containing_trait_or_trait_impl(db)?;
+                Some(into_future_trait.id)
+            })
+            .or_else(|| {
+                let future_trait =
+                    db.lang_item(self.env.krate, SmolStr::new_inline("future_trait"))?;
+                future_trait.as_trait()
+            });
+
+        let trait_ = match trait_ {
             Some(it) => it,
             None => return false,
         };
 
         let canonical_ty =
             Canonical { value: self.ty.clone(), binders: CanonicalVarKinds::empty(Interner) };
-        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), std_future_trait)
+        method_resolution::implements_trait(&canonical_ty, db, self.env.clone(), trait_)
     }
 
     /// Checks that particular type `ty` implements `std::ops::FnOnce`.
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index f5e2e44307..9418afa91d 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -27,6 +27,7 @@ use hir_def::{
 use hir_expand::{
     builtin_fn_macro::BuiltinFnLikeExpander,
     hygiene::Hygiene,
+    mod_path::path,
     name,
     name::{AsName, Name},
     HirFileId, InFile,
@@ -269,14 +270,35 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         await_expr: &ast::AwaitExpr,
     ) -> Option<FunctionId> {
-        let ty = self.ty_of_expr(db, &await_expr.expr()?.into())?;
+        let mut ty = self.ty_of_expr(db, &await_expr.expr()?.into())?.clone();
+
+        let into_future_trait = self
+            .resolver
+            .resolve_known_trait(db.upcast(), &path![core::future::IntoFuture])
+            .map(Trait::from);
+
+        if let Some(into_future_trait) = into_future_trait {
+            let type_ = Type::new_with_resolver(db, &self.resolver, ty.clone());
+            if type_.impls_trait(db, into_future_trait, &[]) {
+                let items = into_future_trait.items(db);
+                let into_future_type = items.into_iter().find_map(|item| match item {
+                    AssocItem::TypeAlias(alias)
+                        if alias.name(db) == hir_expand::name![IntoFuture] =>
+                    {
+                        Some(alias)
+                    }
+                    _ => None,
+                })?;
+                let future_trait = type_.normalize_trait_assoc_type(db, &[], into_future_type)?;
+                ty = future_trait.ty;
+            }
+        }
 
-        let op_fn = db
+        let poll_fn = db
             .lang_item(self.resolver.krate(), hir_expand::name![poll].to_smol_str())?
             .as_function()?;
-        let substs = hir_ty::TyBuilder::subst_for_def(db, op_fn).push(ty.clone()).build();
-
-        Some(self.resolve_impl_method_or_trait_def(db, op_fn, &substs))
+        let substs = hir_ty::TyBuilder::subst_for_def(db, poll_fn).push(ty.clone()).build();
+        Some(self.resolve_impl_method_or_trait_def(db, poll_fn, &substs))
     }
 
     pub(crate) fn resolve_prefix_expr(
diff --git a/crates/ide-assists/src/assist_context.rs b/crates/ide-assists/src/assist_context.rs
index 8c7670e0cb..f9b4266142 100644
--- a/crates/ide-assists/src/assist_context.rs
+++ b/crates/ide-assists/src/assist_context.rs
@@ -1,20 +1,28 @@
 //! See [`AssistContext`].
 
+use std::mem;
+
 use hir::Semantics;
-use ide_db::base_db::{FileId, FileRange};
-use ide_db::{label::Label, RootDatabase};
+use ide_db::{
+    base_db::{AnchoredPathBuf, FileId, FileRange},
+    SnippetCap,
+};
+use ide_db::{
+    label::Label,
+    source_change::{FileSystemEdit, SourceChange},
+    RootDatabase,
+};
 use syntax::{
     algo::{self, find_node_at_offset, find_node_at_range},
-    AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxToken, TextRange,
-    TextSize, TokenAtOffset,
+    AstNode, AstToken, Direction, SourceFile, SyntaxElement, SyntaxKind, SyntaxNode, SyntaxNodePtr,
+    SyntaxToken, TextRange, TextSize, TokenAtOffset,
 };
+use text_edit::{TextEdit, TextEditBuilder};
 
 use crate::{
     assist_config::AssistConfig, Assist, AssistId, AssistKind, AssistResolveStrategy, GroupLabel,
 };
 
-pub(crate) use ide_db::source_change::{SourceChangeBuilder, TreeMutator};
-
 /// `AssistContext` allows to apply an assist or check if it could be applied.
 ///
 /// Assists use a somewhat over-engineered approach, given the current needs.
@@ -155,7 +163,7 @@ impl Assists {
         id: AssistId,
         label: impl Into<String>,
         target: TextRange,
-        f: impl FnOnce(&mut SourceChangeBuilder),
+        f: impl FnOnce(&mut AssistBuilder),
     ) -> Option<()> {
         let mut f = Some(f);
         self.add_impl(None, id, label.into(), target, &mut |it| f.take().unwrap()(it))
@@ -167,7 +175,7 @@ impl Assists {
         id: AssistId,
         label: impl Into<String>,
         target: TextRange,
-        f: impl FnOnce(&mut SourceChangeBuilder),
+        f: impl FnOnce(&mut AssistBuilder),
     ) -> Option<()> {
         let mut f = Some(f);
         self.add_impl(Some(group), id, label.into(), target, &mut |it| f.take().unwrap()(it))
@@ -179,7 +187,7 @@ impl Assists {
         id: AssistId,
         label: String,
         target: TextRange,
-        f: &mut dyn FnMut(&mut SourceChangeBuilder),
+        f: &mut dyn FnMut(&mut AssistBuilder),
     ) -> Option<()> {
         if !self.is_allowed(&id) {
             return None;
@@ -187,7 +195,7 @@ impl Assists {
 
         let mut trigger_signature_help = false;
         let source_change = if self.resolve.should_resolve(&id) {
-            let mut builder = SourceChangeBuilder::new(self.file);
+            let mut builder = AssistBuilder::new(self.file);
             f(&mut builder);
             trigger_signature_help = builder.trigger_signature_help;
             Some(builder.finish())
@@ -208,3 +216,132 @@ impl Assists {
         }
     }
 }
+
+pub(crate) struct AssistBuilder {
+    edit: TextEditBuilder,
+    file_id: FileId,
+    source_change: SourceChange,
+    trigger_signature_help: bool,
+
+    /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin.
+    mutated_tree: Option<TreeMutator>,
+}
+
+pub(crate) struct TreeMutator {
+    immutable: SyntaxNode,
+    mutable_clone: SyntaxNode,
+}
+
+impl TreeMutator {
+    pub(crate) fn new(immutable: &SyntaxNode) -> TreeMutator {
+        let immutable = immutable.ancestors().last().unwrap();
+        let mutable_clone = immutable.clone_for_update();
+        TreeMutator { immutable, mutable_clone }
+    }
+
+    pub(crate) fn make_mut<N: AstNode>(&self, node: &N) -> N {
+        N::cast(self.make_syntax_mut(node.syntax())).unwrap()
+    }
+
+    pub(crate) fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode {
+        let ptr = SyntaxNodePtr::new(node);
+        ptr.to_node(&self.mutable_clone)
+    }
+}
+
+impl AssistBuilder {
+    pub(crate) fn new(file_id: FileId) -> AssistBuilder {
+        AssistBuilder {
+            edit: TextEdit::builder(),
+            file_id,
+            source_change: SourceChange::default(),
+            trigger_signature_help: false,
+            mutated_tree: None,
+        }
+    }
+
+    pub(crate) fn edit_file(&mut self, file_id: FileId) {
+        self.commit();
+        self.file_id = file_id;
+    }
+
+    fn commit(&mut self) {
+        if let Some(tm) = self.mutated_tree.take() {
+            algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit)
+        }
+
+        let edit = mem::take(&mut self.edit).finish();
+        if !edit.is_empty() {
+            self.source_change.insert_source_edit(self.file_id, edit);
+        }
+    }
+
+    pub(crate) fn make_mut<N: AstNode>(&mut self, node: N) -> N {
+        self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node)
+    }
+    /// Returns a copy of the `node`, suitable for mutation.
+    ///
+    /// Syntax trees in rust-analyzer are typically immutable, and mutating
+    /// operations panic at runtime. However, it is possible to make a copy of
+    /// the tree and mutate the copy freely. Mutation is based on interior
+    /// mutability, and different nodes in the same tree see the same mutations.
+    ///
+    /// The typical pattern for an assist is to find specific nodes in the read
+    /// phase, and then get their mutable couterparts using `make_mut` in the
+    /// mutable state.
+    pub(crate) fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode {
+        self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node)
+    }
+
+    /// Remove specified `range` of text.
+    pub(crate) fn delete(&mut self, range: TextRange) {
+        self.edit.delete(range)
+    }
+    /// Append specified `text` at the given `offset`
+    pub(crate) fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
+        self.edit.insert(offset, text.into())
+    }
+    /// Append specified `snippet` at the given `offset`
+    pub(crate) fn insert_snippet(
+        &mut self,
+        _cap: SnippetCap,
+        offset: TextSize,
+        snippet: impl Into<String>,
+    ) {
+        self.source_change.is_snippet = true;
+        self.insert(offset, snippet);
+    }
+    /// Replaces specified `range` of text with a given string.
+    pub(crate) fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
+        self.edit.replace(range, replace_with.into())
+    }
+    /// Replaces specified `range` of text with a given `snippet`.
+    pub(crate) fn replace_snippet(
+        &mut self,
+        _cap: SnippetCap,
+        range: TextRange,
+        snippet: impl Into<String>,
+    ) {
+        self.source_change.is_snippet = true;
+        self.replace(range, snippet);
+    }
+    pub(crate) fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
+        algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
+    }
+    pub(crate) fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
+        let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() };
+        self.source_change.push_file_system_edit(file_system_edit);
+    }
+    pub(crate) fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) {
+        let file_system_edit = FileSystemEdit::MoveFile { src, dst };
+        self.source_change.push_file_system_edit(file_system_edit);
+    }
+    pub(crate) fn trigger_signature_help(&mut self) {
+        self.trigger_signature_help = true;
+    }
+
+    fn finish(mut self) -> SourceChange {
+        self.commit();
+        mem::take(&mut self.source_change)
+    }
+}
diff --git a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
index d8f5227084..4ab8e93a29 100644
--- a/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
+++ b/crates/ide-assists/src/handlers/convert_tuple_struct_to_named_struct.rs
@@ -5,7 +5,7 @@ use syntax::{
     match_ast, SyntaxNode,
 };
 
-use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
+use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
 
 // Assist: convert_tuple_struct_to_named_struct
 //
@@ -80,7 +80,7 @@ pub(crate) fn convert_tuple_struct_to_named_struct(
 
 fn edit_struct_def(
     ctx: &AssistContext<'_>,
-    edit: &mut SourceChangeBuilder,
+    edit: &mut AssistBuilder,
     strukt: &Either<ast::Struct, ast::Variant>,
     tuple_fields: ast::TupleFieldList,
     names: Vec<ast::Name>,
@@ -122,7 +122,7 @@ fn edit_struct_def(
 
 fn edit_struct_references(
     ctx: &AssistContext<'_>,
-    edit: &mut SourceChangeBuilder,
+    edit: &mut AssistBuilder,
     strukt: Either<hir::Struct, hir::Variant>,
     names: &[ast::Name],
 ) {
@@ -132,7 +132,7 @@ fn edit_struct_references(
     };
     let usages = strukt_def.usages(&ctx.sema).include_self_refs().all();
 
-    let edit_node = |edit: &mut SourceChangeBuilder, node: SyntaxNode| -> Option<()> {
+    let edit_node = |edit: &mut AssistBuilder, node: SyntaxNode| -> Option<()> {
         match_ast! {
             match node {
                 ast::TupleStructPat(tuple_struct_pat) => {
@@ -203,7 +203,7 @@ fn edit_struct_references(
 
 fn edit_field_references(
     ctx: &AssistContext<'_>,
-    edit: &mut SourceChangeBuilder,
+    edit: &mut AssistBuilder,
     fields: impl Iterator<Item = ast::TupleField>,
     names: &[ast::Name],
 ) {
diff --git a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
index dc581ff3bd..c1f57532bb 100644
--- a/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
+++ b/crates/ide-assists/src/handlers/destructure_tuple_binding.rs
@@ -8,7 +8,7 @@ use syntax::{
     TextRange,
 };
 
-use crate::assist_context::{AssistContext, Assists, SourceChangeBuilder};
+use crate::assist_context::{AssistBuilder, AssistContext, Assists};
 
 // Assist: destructure_tuple_binding
 //
@@ -151,7 +151,7 @@ struct TupleData {
 }
 fn edit_tuple_assignment(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     data: &TupleData,
     in_sub_pattern: bool,
 ) {
@@ -195,7 +195,7 @@ fn edit_tuple_assignment(
 
 fn edit_tuple_usages(
     data: &TupleData,
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     ctx: &AssistContext<'_>,
     in_sub_pattern: bool,
 ) {
@@ -211,7 +211,7 @@ fn edit_tuple_usages(
 }
 fn edit_tuple_usage(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     usage: &FileReference,
     data: &TupleData,
     in_sub_pattern: bool,
@@ -239,7 +239,7 @@ fn edit_tuple_usage(
 
 fn edit_tuple_field_usage(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     data: &TupleData,
     index: TupleIndex,
 ) {
diff --git a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
index dfb5652126..a93648f2d3 100644
--- a/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
+++ b/crates/ide-assists/src/handlers/extract_struct_from_enum_variant.rs
@@ -20,7 +20,7 @@ use syntax::{
     SyntaxNode, T,
 };
 
-use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
+use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
 
 // Assist: extract_struct_from_enum_variant
 //
@@ -374,7 +374,7 @@ fn apply_references(
 
 fn process_references(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     visited_modules: &mut FxHashSet<Module>,
     enum_module_def: &ModuleDef,
     variant_hir_name: &Name,
diff --git a/crates/ide-assists/src/handlers/generate_deref.rs b/crates/ide-assists/src/handlers/generate_deref.rs
index b484635121..b9637ee8d7 100644
--- a/crates/ide-assists/src/handlers/generate_deref.rs
+++ b/crates/ide-assists/src/handlers/generate_deref.rs
@@ -8,7 +8,7 @@ use syntax::{
 };
 
 use crate::{
-    assist_context::{AssistContext, Assists, SourceChangeBuilder},
+    assist_context::{AssistBuilder, AssistContext, Assists},
     utils::generate_trait_impl_text,
     AssistId, AssistKind,
 };
@@ -120,7 +120,7 @@ fn generate_tuple_deref(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()
 }
 
 fn generate_edit(
-    edit: &mut SourceChangeBuilder,
+    edit: &mut AssistBuilder,
     strukt: ast::Struct,
     field_type_syntax: &SyntaxNode,
     field_name: impl Display,
diff --git a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
index 2fc754e3e5..ce91dd2370 100644
--- a/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
+++ b/crates/ide-assists/src/handlers/introduce_named_lifetime.rs
@@ -5,7 +5,7 @@ use syntax::{
     AstNode, TextRange,
 };
 
-use crate::{assist_context::SourceChangeBuilder, AssistContext, AssistId, AssistKind, Assists};
+use crate::{assist_context::AssistBuilder, AssistContext, AssistId, AssistKind, Assists};
 
 static ASSIST_NAME: &str = "introduce_named_lifetime";
 static ASSIST_LABEL: &str = "Introduce named lifetime";
@@ -140,7 +140,7 @@ enum NeedsLifetime {
 }
 
 impl NeedsLifetime {
-    fn make_mut(self, builder: &mut SourceChangeBuilder) -> Self {
+    fn make_mut(self, builder: &mut AssistBuilder) -> Self {
         match self {
             Self::SelfParam(it) => Self::SelfParam(builder.make_mut(it)),
             Self::RefType(it) => Self::RefType(builder.make_mut(it)),
diff --git a/crates/ide-assists/src/handlers/remove_unused_param.rs b/crates/ide-assists/src/handlers/remove_unused_param.rs
index bd2e8fbe38..59ea94ea1f 100644
--- a/crates/ide-assists/src/handlers/remove_unused_param.rs
+++ b/crates/ide-assists/src/handlers/remove_unused_param.rs
@@ -8,8 +8,7 @@ use syntax::{
 use SyntaxKind::WHITESPACE;
 
 use crate::{
-    assist_context::SourceChangeBuilder, utils::next_prev, AssistContext, AssistId, AssistKind,
-    Assists,
+    assist_context::AssistBuilder, utils::next_prev, AssistContext, AssistId, AssistKind, Assists,
 };
 
 // Assist: remove_unused_param
@@ -89,7 +88,7 @@ pub(crate) fn remove_unused_param(acc: &mut Assists, ctx: &AssistContext<'_>) ->
 
 fn process_usages(
     ctx: &AssistContext<'_>,
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     file_id: FileId,
     references: Vec<FileReference>,
     arg_to_remove: usize,
diff --git a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
index d139f78a6f..bd50208da5 100644
--- a/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/ide-assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -10,7 +10,7 @@ use syntax::{
 };
 
 use crate::{
-    assist_context::{AssistContext, Assists, SourceChangeBuilder},
+    assist_context::{AssistBuilder, AssistContext, Assists},
     utils::{
         add_trait_assoc_items_to_impl, filter_assoc_items, gen_trait_fn_body,
         generate_trait_impl_text, render_snippet, Cursor, DefaultMethods,
@@ -224,7 +224,7 @@ fn impl_def_from_trait(
 }
 
 fn update_attribute(
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     old_derives: &[ast::Path],
     old_tree: &ast::TokenTree,
     old_trait_path: &ast::Path,
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 103e3259fa..3e61d0741d 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -20,7 +20,7 @@ use syntax::{
     SyntaxNode, TextRange, TextSize, T,
 };
 
-use crate::assist_context::{AssistContext, SourceChangeBuilder};
+use crate::assist_context::{AssistBuilder, AssistContext};
 
 pub(crate) mod suggest_name;
 mod gen_trait_fn_body;
@@ -484,7 +484,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
 }
 
 pub(crate) fn add_method_to_adt(
-    builder: &mut SourceChangeBuilder,
+    builder: &mut AssistBuilder,
     adt: &ast::Adt,
     impl_def: Option<ast::Impl>,
     method: &str,
diff --git a/crates/ide-assists/src/utils/suggest_name.rs b/crates/ide-assists/src/utils/suggest_name.rs
index 779cdbc93c..68d59daef4 100644
--- a/crates/ide-assists/src/utils/suggest_name.rs
+++ b/crates/ide-assists/src/utils/suggest_name.rs
@@ -55,6 +55,7 @@ const USELESS_METHODS: &[&str] = &[
     "iter",
     "into_iter",
     "iter_mut",
+    "into_future",
 ];
 
 pub(crate) fn for_generic_parameter(ty: &ast::ImplTraitType) -> SmolStr {
diff --git a/crates/ide-completion/src/completions/dot.rs b/crates/ide-completion/src/completions/dot.rs
index cf40ca489c..02004ff7b6 100644
--- a/crates/ide-completion/src/completions/dot.rs
+++ b/crates/ide-completion/src/completions/dot.rs
@@ -19,7 +19,7 @@ pub(crate) fn complete_dot(
     };
 
     // Suggest .await syntax for types that implement Future trait
-    if receiver_ty.impls_future(ctx.db) {
+    if receiver_ty.impls_into_future(ctx.db) {
         let mut item =
             CompletionItem::new(CompletionItemKind::Keyword, ctx.source_range(), "await");
         item.detail("expr.await");
diff --git a/crates/ide-completion/src/completions/keyword.rs b/crates/ide-completion/src/completions/keyword.rs
index 3989a451bd..1d03c8cc5c 100644
--- a/crates/ide-completion/src/completions/keyword.rs
+++ b/crates/ide-completion/src/completions/keyword.rs
@@ -75,16 +75,17 @@ impl Future for A {}
 fn foo(a: A) { a.$0 }
 "#,
             expect![[r#"
-                kw await expr.await
-                sn box   Box::new(expr)
-                sn call  function(expr)
-                sn dbg   dbg!(expr)
-                sn dbgr  dbg!(&expr)
-                sn let   let
-                sn letm  let mut
-                sn match match expr {}
-                sn ref   &expr
-                sn refm  &mut expr
+                kw await                  expr.await
+                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                sn box                    Box::new(expr)
+                sn call                   function(expr)
+                sn dbg                    dbg!(expr)
+                sn dbgr                   dbg!(&expr)
+                sn let                    let
+                sn letm                   let mut
+                sn match                  match expr {}
+                sn ref                    &expr
+                sn refm                   &mut expr
             "#]],
         );
 
@@ -98,18 +99,45 @@ fn foo() {
 }
 "#,
             expect![[r#"
-                kw await expr.await
-                sn box   Box::new(expr)
-                sn call  function(expr)
-                sn dbg   dbg!(expr)
-                sn dbgr  dbg!(&expr)
-                sn let   let
-                sn letm  let mut
-                sn match match expr {}
-                sn ref   &expr
-                sn refm  &mut expr
+                kw await                  expr.await
+                me into_future() (use core::future::IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                sn box                    Box::new(expr)
+                sn call                   function(expr)
+                sn dbg                    dbg!(expr)
+                sn dbgr                   dbg!(&expr)
+                sn let                    let
+                sn letm                   let mut
+                sn match                  match expr {}
+                sn ref                    &expr
+                sn refm                   &mut expr
             "#]],
-        )
+        );
+    }
+
+    #[test]
+    fn test_completion_await_impls_into_future() {
+        check(
+            r#"
+//- minicore: future
+use core::future::*;
+struct A {}
+impl IntoFuture for A {}
+fn foo(a: A) { a.$0 }
+"#,
+            expect![[r#"
+                kw await                  expr.await
+                me into_future() (as IntoFuture) fn(self) -> <Self as IntoFuture>::IntoFuture
+                sn box                    Box::new(expr)
+                sn call                   function(expr)
+                sn dbg                    dbg!(expr)
+                sn dbgr                   dbg!(&expr)
+                sn let                    let
+                sn letm                   let mut
+                sn match                  match expr {}
+                sn ref                    &expr
+                sn refm                   &mut expr
+            "#]],
+        );
     }
 
     #[test]
diff --git a/crates/ide-db/src/source_change.rs b/crates/ide-db/src/source_change.rs
index 21314ad74e..8132c73ef2 100644
--- a/crates/ide-db/src/source_change.rs
+++ b/crates/ide-db/src/source_change.rs
@@ -3,15 +3,12 @@
 //!
 //! It can be viewed as a dual for `Change`.
 
-use std::{collections::hash_map::Entry, iter, mem};
+use std::{collections::hash_map::Entry, iter};
 
 use base_db::{AnchoredPathBuf, FileId};
 use rustc_hash::FxHashMap;
 use stdx::never;
-use syntax::{algo, AstNode, SyntaxNode, SyntaxNodePtr, TextRange, TextSize};
-use text_edit::{TextEdit, TextEditBuilder};
-
-use crate::SnippetCap;
+use text_edit::TextEdit;
 
 #[derive(Default, Debug, Clone)]
 pub struct SourceChange {
@@ -84,135 +81,6 @@ impl From<FxHashMap<FileId, TextEdit>> for SourceChange {
     }
 }
 
-pub struct SourceChangeBuilder {
-    pub edit: TextEditBuilder,
-    pub file_id: FileId,
-    pub source_change: SourceChange,
-    pub trigger_signature_help: bool,
-
-    /// Maps the original, immutable `SyntaxNode` to a `clone_for_update` twin.
-    pub mutated_tree: Option<TreeMutator>,
-}
-
-pub struct TreeMutator {
-    immutable: SyntaxNode,
-    mutable_clone: SyntaxNode,
-}
-
-impl TreeMutator {
-    pub fn new(immutable: &SyntaxNode) -> TreeMutator {
-        let immutable = immutable.ancestors().last().unwrap();
-        let mutable_clone = immutable.clone_for_update();
-        TreeMutator { immutable, mutable_clone }
-    }
-
-    pub fn make_mut<N: AstNode>(&self, node: &N) -> N {
-        N::cast(self.make_syntax_mut(node.syntax())).unwrap()
-    }
-
-    pub fn make_syntax_mut(&self, node: &SyntaxNode) -> SyntaxNode {
-        let ptr = SyntaxNodePtr::new(node);
-        ptr.to_node(&self.mutable_clone)
-    }
-}
-
-impl SourceChangeBuilder {
-    pub fn new(file_id: FileId) -> SourceChangeBuilder {
-        SourceChangeBuilder {
-            edit: TextEdit::builder(),
-            file_id,
-            source_change: SourceChange::default(),
-            trigger_signature_help: false,
-            mutated_tree: None,
-        }
-    }
-
-    pub fn edit_file(&mut self, file_id: FileId) {
-        self.commit();
-        self.file_id = file_id;
-    }
-
-    fn commit(&mut self) {
-        if let Some(tm) = self.mutated_tree.take() {
-            algo::diff(&tm.immutable, &tm.mutable_clone).into_text_edit(&mut self.edit)
-        }
-
-        let edit = mem::take(&mut self.edit).finish();
-        if !edit.is_empty() {
-            self.source_change.insert_source_edit(self.file_id, edit);
-        }
-    }
-
-    pub fn make_mut<N: AstNode>(&mut self, node: N) -> N {
-        self.mutated_tree.get_or_insert_with(|| TreeMutator::new(node.syntax())).make_mut(&node)
-    }
-    /// Returns a copy of the `node`, suitable for mutation.
-    ///
-    /// Syntax trees in rust-analyzer are typically immutable, and mutating
-    /// operations panic at runtime. However, it is possible to make a copy of
-    /// the tree and mutate the copy freely. Mutation is based on interior
-    /// mutability, and different nodes in the same tree see the same mutations.
-    ///
-    /// The typical pattern for an assist is to find specific nodes in the read
-    /// phase, and then get their mutable couterparts using `make_mut` in the
-    /// mutable state.
-    pub fn make_syntax_mut(&mut self, node: SyntaxNode) -> SyntaxNode {
-        self.mutated_tree.get_or_insert_with(|| TreeMutator::new(&node)).make_syntax_mut(&node)
-    }
-
-    /// Remove specified `range` of text.
-    pub fn delete(&mut self, range: TextRange) {
-        self.edit.delete(range)
-    }
-    /// Append specified `text` at the given `offset`
-    pub fn insert(&mut self, offset: TextSize, text: impl Into<String>) {
-        self.edit.insert(offset, text.into())
-    }
-    /// Append specified `snippet` at the given `offset`
-    pub fn insert_snippet(
-        &mut self,
-        _cap: SnippetCap,
-        offset: TextSize,
-        snippet: impl Into<String>,
-    ) {
-        self.source_change.is_snippet = true;
-        self.insert(offset, snippet);
-    }
-    /// Replaces specified `range` of text with a given string.
-    pub fn replace(&mut self, range: TextRange, replace_with: impl Into<String>) {
-        self.edit.replace(range, replace_with.into())
-    }
-    /// Replaces specified `range` of text with a given `snippet`.
-    pub fn replace_snippet(
-        &mut self,
-        _cap: SnippetCap,
-        range: TextRange,
-        snippet: impl Into<String>,
-    ) {
-        self.source_change.is_snippet = true;
-        self.replace(range, snippet);
-    }
-    pub fn replace_ast<N: AstNode>(&mut self, old: N, new: N) {
-        algo::diff(old.syntax(), new.syntax()).into_text_edit(&mut self.edit)
-    }
-    pub fn create_file(&mut self, dst: AnchoredPathBuf, content: impl Into<String>) {
-        let file_system_edit = FileSystemEdit::CreateFile { dst, initial_contents: content.into() };
-        self.source_change.push_file_system_edit(file_system_edit);
-    }
-    pub fn move_file(&mut self, src: FileId, dst: AnchoredPathBuf) {
-        let file_system_edit = FileSystemEdit::MoveFile { src, dst };
-        self.source_change.push_file_system_edit(file_system_edit);
-    }
-    pub fn trigger_signature_help(&mut self) {
-        self.trigger_signature_help = true;
-    }
-
-    pub fn finish(mut self) -> SourceChange {
-        self.commit();
-        mem::take(&mut self.source_change)
-    }
-}
-
 #[derive(Debug, Clone)]
 pub enum FileSystemEdit {
     CreateFile { dst: AnchoredPathBuf, initial_contents: String },
diff --git a/crates/ide-diagnostics/Cargo.toml b/crates/ide-diagnostics/Cargo.toml
index 9b9e21a4dd..e221425edd 100644
--- a/crates/ide-diagnostics/Cargo.toml
+++ b/crates/ide-diagnostics/Cargo.toml
@@ -15,7 +15,6 @@ itertools = "0.10.3"
 
 
 either = "1.7.0"
-serde_json = "1.0.82"
 
 profile = { path = "../profile", version = "0.0.0" }
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/ide-diagnostics/src/handlers/inactive_code.rs b/crates/ide-diagnostics/src/handlers/inactive_code.rs
index 5694f33525..97ea5c456a 100644
--- a/crates/ide-diagnostics/src/handlers/inactive_code.rs
+++ b/crates/ide-diagnostics/src/handlers/inactive_code.rs
@@ -43,7 +43,7 @@ mod tests {
     use crate::{tests::check_diagnostics_with_config, DiagnosticsConfig};
 
     pub(crate) fn check(ra_fixture: &str) {
-        let config = DiagnosticsConfig::test_sample();
+        let config = DiagnosticsConfig::default();
         check_diagnostics_with_config(config, ra_fixture)
     }
 
diff --git a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs b/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
deleted file mode 100644
index a21db5b2ce..0000000000
--- a/crates/ide-diagnostics/src/handlers/json_is_not_rust.rs
+++ /dev/null
@@ -1,310 +0,0 @@
-//! This diagnostic provides an assist for creating a struct definition from a JSON
-//! example.
-
-use hir::{PathResolution, Semantics};
-use ide_db::{
-    base_db::FileId,
-    helpers::mod_path_to_ast,
-    imports::insert_use::{insert_use, ImportScope},
-    source_change::SourceChangeBuilder,
-    RootDatabase,
-};
-use itertools::Itertools;
-use stdx::{format_to, never};
-use syntax::{
-    ast::{self, make},
-    SyntaxKind, SyntaxNode,
-};
-use text_edit::TextEdit;
-
-use crate::{fix, Diagnostic, DiagnosticsConfig, Severity};
-
-#[derive(Default)]
-struct State {
-    result: String,
-    struct_counts: usize,
-    has_serialize: bool,
-    has_deserialize: bool,
-}
-
-impl State {
-    fn generate_new_name(&mut self) -> ast::Name {
-        self.struct_counts += 1;
-        make::name(&format!("Struct{}", self.struct_counts))
-    }
-
-    fn serde_derive(&self) -> String {
-        let mut v = vec![];
-        if self.has_serialize {
-            v.push("Serialize");
-        }
-        if self.has_deserialize {
-            v.push("Deserialize");
-        }
-        match v.as_slice() {
-            [] => "".to_string(),
-            [x] => format!("#[derive({x})]\n"),
-            [x, y] => format!("#[derive({x}, {y})]\n"),
-            _ => {
-                never!();
-                "".to_string()
-            }
-        }
-    }
-
-    fn build_struct(&mut self, value: &serde_json::Map<String, serde_json::Value>) -> ast::Type {
-        let name = self.generate_new_name();
-        let ty = make::ty(&name.to_string());
-        let strukt = make::struct_(
-            None,
-            name,
-            None,
-            make::record_field_list(value.iter().sorted_unstable_by_key(|x| x.0).map(
-                |(name, value)| make::record_field(None, make::name(name), self.type_of(value)),
-            ))
-            .into(),
-        );
-        format_to!(self.result, "{}{}\n", self.serde_derive(), strukt);
-        ty
-    }
-
-    fn type_of(&mut self, value: &serde_json::Value) -> ast::Type {
-        match value {
-            serde_json::Value::Null => make::ty_unit(),
-            serde_json::Value::Bool(_) => make::ty("bool"),
-            serde_json::Value::Number(it) => make::ty(if it.is_i64() { "i64" } else { "f64" }),
-            serde_json::Value::String(_) => make::ty("String"),
-            serde_json::Value::Array(it) => {
-                let ty = match it.iter().next() {
-                    Some(x) => self.type_of(x),
-                    None => make::ty_placeholder(),
-                };
-                make::ty(&format!("Vec<{ty}>"))
-            }
-            serde_json::Value::Object(x) => self.build_struct(x),
-        }
-    }
-}
-
-pub(crate) fn json_in_items(
-    sema: &Semantics<'_, RootDatabase>,
-    acc: &mut Vec<Diagnostic>,
-    file_id: FileId,
-    node: &SyntaxNode,
-    config: &DiagnosticsConfig,
-) {
-    (|| {
-        if node.kind() == SyntaxKind::ERROR
-            && node.first_token().map(|x| x.kind()) == Some(SyntaxKind::L_CURLY)
-            && node.last_token().map(|x| x.kind()) == Some(SyntaxKind::R_CURLY)
-        {
-            let node_string = node.to_string();
-            if let Ok(it) = serde_json::from_str(&node_string) {
-                if let serde_json::Value::Object(it) = it {
-                    let import_scope = ImportScope::find_insert_use_container(node, sema)?;
-                    let range = node.text_range();
-                    let mut edit = TextEdit::builder();
-                    edit.delete(range);
-                    let mut state = State::default();
-                    let semantics_scope = sema.scope(node)?;
-                    let scope_resolve =
-                        |it| semantics_scope.speculative_resolve(&make::path_from_text(it));
-                    let scope_has = |it| scope_resolve(it).is_some();
-                    let deserialize_resolved = scope_resolve("::serde::Deserialize");
-                    let serialize_resolved = scope_resolve("::serde::Serialize");
-                    state.has_deserialize = deserialize_resolved.is_some();
-                    state.has_serialize = serialize_resolved.is_some();
-                    state.build_struct(&it);
-                    edit.insert(range.start(), state.result);
-                    acc.push(
-                        Diagnostic::new(
-                            "json-is-not-rust",
-                            "JSON syntax is not valid as a Rust item",
-                            range,
-                        )
-                        .severity(Severity::WeakWarning)
-                        .with_fixes(Some(vec![{
-                            let mut scb = SourceChangeBuilder::new(file_id);
-                            let scope = match import_scope.clone() {
-                                ImportScope::File(it) => ImportScope::File(scb.make_mut(it)),
-                                ImportScope::Module(it) => ImportScope::Module(scb.make_mut(it)),
-                                ImportScope::Block(it) => ImportScope::Block(scb.make_mut(it)),
-                            };
-                            let current_module = semantics_scope.module();
-                            if !scope_has("Serialize") {
-                                if let Some(PathResolution::Def(it)) = serialize_resolved {
-                                    if let Some(it) = current_module.find_use_path_prefixed(
-                                        sema.db,
-                                        it,
-                                        config.insert_use.prefix_kind,
-                                    ) {
-                                        insert_use(
-                                            &scope,
-                                            mod_path_to_ast(&it),
-                                            &config.insert_use,
-                                        );
-                                    }
-                                }
-                            }
-                            if !scope_has("Deserialize") {
-                                if let Some(PathResolution::Def(it)) = deserialize_resolved {
-                                    if let Some(it) = current_module.find_use_path_prefixed(
-                                        sema.db,
-                                        it,
-                                        config.insert_use.prefix_kind,
-                                    ) {
-                                        insert_use(
-                                            &scope,
-                                            mod_path_to_ast(&it),
-                                            &config.insert_use,
-                                        );
-                                    }
-                                }
-                            }
-                            let mut sc = scb.finish();
-                            sc.insert_source_edit(file_id, edit.finish());
-                            fix("convert_json_to_struct", "Convert JSON to struct", sc, range)
-                        }])),
-                    );
-                }
-            }
-        }
-        Some(())
-    })();
-}
-
-#[cfg(test)]
-mod tests {
-    use crate::{
-        tests::{check_diagnostics_with_config, check_fix, check_no_fix},
-        DiagnosticsConfig,
-    };
-
-    #[test]
-    fn diagnostic_for_simple_case() {
-        let mut config = DiagnosticsConfig::test_sample();
-        config.disabled.insert("syntax-error".to_string());
-        check_diagnostics_with_config(
-            config,
-            r#"
-            { "foo": "bar" }
-         // ^^^^^^^^^^^^^^^^ 💡 weak: JSON syntax is not valid as a Rust item
-"#,
-        );
-    }
-
-    #[test]
-    fn types_of_primitives() {
-        check_fix(
-            r#"
-            //- /lib.rs crate:lib deps:serde
-            use serde::Serialize;
-
-            fn some_garbage() {
-
-            }
-
-            {$0
-                "foo": "bar",
-                "bar": 2.3,
-                "baz": null,
-                "bay": 57,
-                "box": true
-            }
-            //- /serde.rs crate:serde
-
-            pub trait Serialize {
-                fn serialize() -> u8;
-            }
-            "#,
-            r#"
-            use serde::Serialize;
-
-            fn some_garbage() {
-
-            }
-
-            #[derive(Serialize)]
-            struct Struct1{ bar: f64, bay: i64, baz: (), r#box: bool, foo: String }
-
-            "#,
-        );
-    }
-
-    #[test]
-    fn nested_structs() {
-        check_fix(
-            r#"
-            {$0
-                "foo": "bar",
-                "bar": {
-                    "kind": "Object",
-                    "value": {}
-                }
-            }
-            "#,
-            r#"
-            struct Struct3{  }
-            struct Struct2{ kind: String, value: Struct3 }
-            struct Struct1{ bar: Struct2, foo: String }
-
-            "#,
-        );
-    }
-
-    #[test]
-    fn arrays() {
-        check_fix(
-            r#"
-            //- /lib.rs crate:lib deps:serde
-            {
-                "of_string": ["foo", "2", "x"], $0
-                "of_object": [{
-                    "x": 10,
-                    "y": 20
-                }, {
-                    "x": 10,
-                    "y": 20
-                }],
-                "nested": [[[2]]],
-                "empty": []
-            }
-            //- /serde.rs crate:serde
-
-            pub trait Serialize {
-                fn serialize() -> u8;
-            }
-            pub trait Deserialize {
-                fn deserialize() -> u8;
-            }
-            "#,
-            r#"
-            use serde::Serialize;
-            use serde::Deserialize;
-
-            #[derive(Serialize, Deserialize)]
-            struct Struct2{ x: i64, y: i64 }
-            #[derive(Serialize, Deserialize)]
-            struct Struct1{ empty: Vec<_>, nested: Vec<Vec<Vec<i64>>>, of_object: Vec<Struct2>, of_string: Vec<String> }
-
-            "#,
-        );
-    }
-
-    #[test]
-    fn no_emit_outside_of_item_position() {
-        check_no_fix(
-            r#"
-            fn foo() {
-                let json = {$0
-                    "foo": "bar",
-                    "bar": {
-                        "kind": "Object",
-                        "value": {}
-                    }
-                };
-            }
-            "#,
-        );
-    }
-}
diff --git a/crates/ide-diagnostics/src/handlers/macro_error.rs b/crates/ide-diagnostics/src/handlers/macro_error.rs
index 43ff4ed5a6..d6a66dc150 100644
--- a/crates/ide-diagnostics/src/handlers/macro_error.rs
+++ b/crates/ide-diagnostics/src/handlers/macro_error.rs
@@ -79,7 +79,7 @@ pub macro panic {
 
     #[test]
     fn include_macro_should_allow_empty_content() {
-        let mut config = DiagnosticsConfig::test_sample();
+        let mut config = DiagnosticsConfig::default();
 
         // FIXME: This is a false-positive, the file is actually linked in via
         // `include!` macro
diff --git a/crates/ide-diagnostics/src/lib.rs b/crates/ide-diagnostics/src/lib.rs
index 61e63ea7a9..41abaa836f 100644
--- a/crates/ide-diagnostics/src/lib.rs
+++ b/crates/ide-diagnostics/src/lib.rs
@@ -50,7 +50,6 @@ mod handlers {
     pub(crate) mod field_shorthand;
     pub(crate) mod useless_braces;
     pub(crate) mod unlinked_file;
-    pub(crate) mod json_is_not_rust;
 }
 
 #[cfg(test)]
@@ -60,7 +59,6 @@ use hir::{diagnostics::AnyDiagnostic, InFile, Semantics};
 use ide_db::{
     assists::{Assist, AssistId, AssistKind, AssistResolveStrategy},
     base_db::{FileId, FileRange, SourceDatabase},
-    imports::insert_use::InsertUseConfig,
     label::Label,
     source_change::SourceChange,
     FxHashSet, RootDatabase,
@@ -141,37 +139,13 @@ impl Default for ExprFillDefaultMode {
     }
 }
 
-#[derive(Debug, Clone)]
+#[derive(Default, Debug, Clone)]
 pub struct DiagnosticsConfig {
     pub proc_macros_enabled: bool,
     pub proc_attr_macros_enabled: bool,
     pub disable_experimental: bool,
     pub disabled: FxHashSet<String>,
     pub expr_fill_default: ExprFillDefaultMode,
-    // FIXME: We may want to include a whole `AssistConfig` here
-    pub insert_use: InsertUseConfig,
-}
-
-impl DiagnosticsConfig {
-    pub fn test_sample() -> Self {
-        use hir::PrefixKind;
-        use ide_db::imports::insert_use::ImportGranularity;
-
-        Self {
-            proc_macros_enabled: Default::default(),
-            proc_attr_macros_enabled: Default::default(),
-            disable_experimental: Default::default(),
-            disabled: Default::default(),
-            expr_fill_default: Default::default(),
-            insert_use: InsertUseConfig {
-                granularity: ImportGranularity::Preserve,
-                enforce_granularity: false,
-                prefix_kind: PrefixKind::Plain,
-                group: false,
-                skip_glob_imports: false,
-            },
-        }
-    }
 }
 
 struct DiagnosticsContext<'a> {
@@ -198,12 +172,9 @@ pub fn diagnostics(
         }),
     );
 
-    let parse = sema.parse(file_id);
-
-    for node in parse.syntax().descendants() {
+    for node in parse.tree().syntax().descendants() {
         handlers::useless_braces::useless_braces(&mut res, file_id, &node);
         handlers::field_shorthand::field_shorthand(&mut res, file_id, &node);
-        handlers::json_is_not_rust::json_in_items(&sema, &mut res, file_id, &node, &config);
     }
 
     let module = sema.to_module_def(file_id);
diff --git a/crates/ide/src/goto_definition.rs b/crates/ide/src/goto_definition.rs
index b2123b9a87..c7a922e6cc 100644
--- a/crates/ide/src/goto_definition.rs
+++ b/crates/ide/src/goto_definition.rs
@@ -1664,6 +1664,40 @@ fn f() {
         );
     }
 
+    #[test]
+    fn goto_await_into_future_poll() {
+        check(
+            r#"
+//- minicore: future
+
+struct Futurable;
+
+impl core::future::IntoFuture for Futurable {
+    type IntoFuture = MyFut;
+}
+
+struct MyFut;
+
+impl core::future::Future for MyFut {
+    type Output = ();
+
+    fn poll(
+     //^^^^
+        self: std::pin::Pin<&mut Self>,
+        cx: &mut std::task::Context<'_>
+    ) -> std::task::Poll<Self::Output>
+    {
+        ()
+    }
+}
+
+fn f() {
+    Futurable.await$0;
+}
+"#,
+        );
+    }
+
     #[test]
     fn goto_try_op() {
         check(
diff --git a/crates/parser/src/grammar/patterns.rs b/crates/parser/src/grammar/patterns.rs
index 7e21a808da..4cbf103061 100644
--- a/crates/parser/src/grammar/patterns.rs
+++ b/crates/parser/src/grammar/patterns.rs
@@ -75,16 +75,6 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
         //         Some(1..) => ()
         //     }
         //
-        //     match () {
-        //         S { a: 0 } => (),
-        //         S { a: 1.. } => (),
-        //     }
-        //
-        //     match () {
-        //         [0] => (),
-        //         [1..] => (),
-        //     }
-        //
         //     match (10 as u8, 5 as u8) {
         //         (0, _) => (),
         //         (1.., _) => ()
@@ -98,27 +88,11 @@ fn pattern_single_r(p: &mut Parser<'_>, recovery_set: TokenSet) {
                 let m = lhs.precede(p);
                 p.bump(range_op);
 
-                // testing if we're at one of the following positions:
-                // `0 .. =>`
-                //       ^
-                // `let 0 .. =`
-                //           ^
-                // `let 0..: _ =`
-                //         ^
-                // (1.., _)
-                //     ^
-                // `Some(0 .. )`
-                //            ^
-                // `S { t: 0.. }`
-                //             ^
-                // `[0..]`
-                //      ^
-                if matches!(p.current(), T![=] | T![,] | T![:] | T![')'] | T!['}'] | T![']']) {
+                // `0 .. =>` or `let 0 .. =` or `Some(0 .. )`
+                //       ^                ^                ^
+                if p.at(T![=]) | p.at(T![')']) | p.at(T![,]) {
                     // test half_open_range_pat
-                    // fn f() {
-                    //     let 0 .. = 1u32;
-                    //     let 0..: _ = 1u32;
-                    // }
+                    // fn f() { let 0 .. = 1u32; }
                 } else {
                     atom_pat(p, recovery_set);
                 }
diff --git a/crates/rust-analyzer/src/cli/diagnostics.rs b/crates/rust-analyzer/src/cli/diagnostics.rs
index 247007db0a..52511ceb58 100644
--- a/crates/rust-analyzer/src/cli/diagnostics.rs
+++ b/crates/rust-analyzer/src/cli/diagnostics.rs
@@ -43,7 +43,7 @@ impl flags::Diagnostics {
                 println!("processing crate: {}, module: {}", crate_name, _vfs.file_path(file_id));
                 for diagnostic in analysis
                     .diagnostics(
-                        &DiagnosticsConfig::test_sample(),
+                        &DiagnosticsConfig::default(),
                         AssistResolveStrategy::None,
                         file_id,
                     )
diff --git a/crates/rust-analyzer/src/cli/flags.rs b/crates/rust-analyzer/src/cli/flags.rs
index 080e2fb443..19907ebddb 100644
--- a/crates/rust-analyzer/src/cli/flags.rs
+++ b/crates/rust-analyzer/src/cli/flags.rs
@@ -10,10 +10,6 @@ xflags::xflags! {
     src "./src/cli/flags.rs"
 
     /// LSP server for the Rust programming language.
-    ///
-    /// Subcommands and their flags do not provide any stability guarantees and may be removed or
-    /// changed without notice. Top-level flags that are not are marked as [Unstable] provide
-    /// backwards-compatibility and may be relied on.
     cmd rust-analyzer {
         /// Verbosity level, can be repeated multiple times.
         repeated -v, --verbose
@@ -25,7 +21,7 @@ xflags::xflags! {
         /// Flush log records to the file immediately.
         optional --no-log-buffering
 
-        /// [Unstable] Wait until a debugger is attached to (requires debug build).
+        /// Wait until a debugger is attached to (requires debug build).
         optional --wait-dbg
 
         default cmd lsp-server {
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 1629c1dd32..ac0fdf85a7 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -881,7 +881,6 @@ impl Config {
                 ExprFillDefaultDef::Todo => ExprFillDefaultMode::Todo,
                 ExprFillDefaultDef::Default => ExprFillDefaultMode::Default,
             },
-            insert_use: self.insert_use_config(),
         }
     }
 
diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs
index 4e0ee63f32..ce0224ec74 100644
--- a/crates/sourcegen/src/lib.rs
+++ b/crates/sourcegen/src/lib.rs
@@ -136,7 +136,7 @@ impl fmt::Display for Location {
 }
 
 fn ensure_rustfmt(sh: &Shell) {
-    let version = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap_or_default();
+    let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
     if !version.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -147,15 +147,13 @@ fn ensure_rustfmt(sh: &Shell) {
 
 pub fn reformat(text: String) -> String {
     let sh = Shell::new().unwrap();
+    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
     ensure_rustfmt(&sh);
     let rustfmt_toml = project_root().join("rustfmt.toml");
-    let mut stdout = cmd!(
-        sh,
-        "rustup run stable rustfmt --config-path {rustfmt_toml} --config fn_single_line=true"
-    )
-    .stdin(text)
-    .read()
-    .unwrap();
+    let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
+        .stdin(text)
+        .read()
+        .unwrap();
     if !stdout.ends_with('\n') {
         stdout.push('\n');
     }
diff --git a/crates/syntax/src/ast/operators.rs b/crates/syntax/src/ast/operators.rs
index 8f7b3fb600..a687ba0b77 100644
--- a/crates/syntax/src/ast/operators.rs
+++ b/crates/syntax/src/ast/operators.rs
@@ -111,10 +111,10 @@ impl fmt::Display for BinaryOp {
             BinaryOp::ArithOp(op) => fmt::Display::fmt(op, f),
             BinaryOp::CmpOp(op) => fmt::Display::fmt(op, f),
             BinaryOp::Assignment { op } => {
+                f.write_str("=")?;
                 if let Some(op) = op {
                     fmt::Display::fmt(op, f)?;
                 }
-                f.write_str("=")?;
                 Ok(())
             }
         }
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index 1b793bb0b1..bf55329ca1 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -326,22 +326,8 @@ export function toggleInlayHints(_ctx: Ctx): Cmd {
         const config = vscode.workspace.getConfiguration("editor.inlayHints", {
             languageId: "rust",
         });
-
-        const value = config.get("enabled");
-        let stringValue;
-        if (typeof value === "string") {
-            stringValue = value;
-        } else {
-            stringValue = value ? "on" : "off";
-        }
-        const nextValues: Record<string, string> = {
-            on: "off",
-            off: "on",
-            onUnlessPressed: "offUnlessPressed",
-            offUnlessPressed: "onUnlessPressed",
-        };
-        const nextValue = nextValues[stringValue] ?? "on";
-        await config.update("enabled", nextValue, vscode.ConfigurationTarget.Global);
+        const value = !config.get("enabled");
+        await config.update("enabled", value, vscode.ConfigurationTarget.Global);
     };
 }
 
diff --git a/lib/la-arena/src/lib.rs b/lib/la-arena/src/lib.rs
index a3fe59e946..dadee43b10 100644
--- a/lib/la-arena/src/lib.rs
+++ b/lib/la-arena/src/lib.rs
@@ -12,7 +12,7 @@ use std::{
 };
 
 mod map;
-pub use map::{ArenaMap, Entry, OccupiedEntry, VacantEntry};
+pub use map::ArenaMap;
 
 /// The raw index of a value in an arena.
 #[derive(Clone, Copy, PartialEq, Eq, PartialOrd, Ord, Hash)]
@@ -208,16 +208,6 @@ impl<T> Arena<T> {
         Arena { data: Vec::new() }
     }
 
-    /// Create a new empty arena with specific capacity.
-    ///
-    /// ```
-    /// let arena: la_arena::Arena<i32> = la_arena::Arena::with_capacity(42);
-    /// assert!(arena.is_empty());
-    /// ```
-    pub fn with_capacity(capacity: usize) -> Arena<T> {
-        Arena { data: Vec::with_capacity(capacity) }
-    }
-
     /// Empties the arena, removing all contained values.
     ///
     /// ```
diff --git a/lib/la-arena/src/map.rs b/lib/la-arena/src/map.rs
index 5f347e2745..d27f086d37 100644
--- a/lib/la-arena/src/map.rs
+++ b/lib/la-arena/src/map.rs
@@ -11,52 +11,12 @@ pub struct ArenaMap<IDX, V> {
 }
 
 impl<T, V> ArenaMap<Idx<T>, V> {
-    /// Creates a new empty map.
-    pub const fn new() -> Self {
-        Self { v: Vec::new(), _ty: PhantomData }
-    }
-
-    /// Create a new empty map with specific capacity.
-    pub fn with_capacity(capacity: usize) -> Self {
-        Self { v: Vec::with_capacity(capacity), _ty: PhantomData }
-    }
-
-    /// Reserves capacity for at least additional more elements to be inserted in the map.
-    pub fn reserve(&mut self, additional: usize) {
-        self.v.reserve(additional);
-    }
-
-    /// Clears the map, removing all elements.
-    pub fn clear(&mut self) {
-        self.v.clear();
-    }
-
-    /// Shrinks the capacity of the map as much as possible.
-    pub fn shrink_to_fit(&mut self) {
-        let min_len = self.v.iter().rposition(|slot| slot.is_some()).map_or(0, |i| i + 1);
-        self.v.truncate(min_len);
-        self.v.shrink_to_fit();
-    }
-
-    /// Returns whether the map contains a value for the specified index.
-    pub fn contains_idx(&self, idx: Idx<T>) -> bool {
-        matches!(self.v.get(Self::to_idx(idx)), Some(Some(_)))
-    }
-
-    /// Removes an index from the map, returning the value at the index if the index was previously in the map.
-    pub fn remove(&mut self, idx: Idx<T>) -> Option<V> {
-        self.v.get_mut(Self::to_idx(idx))?.take()
-    }
-
     /// Inserts a value associated with a given arena index into the map.
-    ///
-    /// If the map did not have this index present, None is returned.
-    /// Otherwise, the value is updated, and the old value is returned.
-    pub fn insert(&mut self, idx: Idx<T>, t: V) -> Option<V> {
+    pub fn insert(&mut self, idx: Idx<T>, t: V) {
         let idx = Self::to_idx(idx);
 
         self.v.resize_with((idx + 1).max(self.v.len()), || None);
-        self.v[idx].replace(t)
+        self.v[idx] = Some(t);
     }
 
     /// Returns a reference to the value associated with the provided index
@@ -86,16 +46,6 @@ impl<T, V> ArenaMap<Idx<T>, V> {
         self.v.iter().enumerate().filter_map(|(idx, o)| Some((Self::from_idx(idx), o.as_ref()?)))
     }
 
-    /// Gets the given key's corresponding entry in the map for in-place manipulation.
-    pub fn entry(&mut self, idx: Idx<T>) -> Entry<'_, Idx<T>, V> {
-        let idx = Self::to_idx(idx);
-        self.v.resize_with((idx + 1).max(self.v.len()), || None);
-        match &mut self.v[idx] {
-            slot @ Some(_) => Entry::Occupied(OccupiedEntry { slot, _ty: PhantomData }),
-            slot @ None => Entry::Vacant(VacantEntry { slot, _ty: PhantomData }),
-        }
-    }
-
     fn to_idx(idx: Idx<T>) -> usize {
         u32::from(idx.into_raw()) as usize
     }
@@ -120,119 +70,6 @@ impl<T, V> std::ops::IndexMut<Idx<V>> for ArenaMap<Idx<V>, T> {
 
 impl<T, V> Default for ArenaMap<Idx<V>, T> {
     fn default() -> Self {
-        Self::new()
-    }
-}
-
-impl<T, V> Extend<(Idx<V>, T)> for ArenaMap<Idx<V>, T> {
-    fn extend<I: IntoIterator<Item = (Idx<V>, T)>>(&mut self, iter: I) {
-        iter.into_iter().for_each(move |(k, v)| {
-            self.insert(k, v);
-        });
-    }
-}
-
-impl<T, V> FromIterator<(Idx<V>, T)> for ArenaMap<Idx<V>, T> {
-    fn from_iter<I: IntoIterator<Item = (Idx<V>, T)>>(iter: I) -> Self {
-        let mut this = Self::new();
-        this.extend(iter);
-        this
-    }
-}
-
-/// A view into a single entry in a map, which may either be vacant or occupied.
-///
-/// This `enum` is constructed from the [`entry`] method on [`ArenaMap`].
-///
-/// [`entry`]: ArenaMap::entry
-pub enum Entry<'a, IDX, V> {
-    /// A vacant entry.
-    Vacant(VacantEntry<'a, IDX, V>),
-    /// An occupied entry.
-    Occupied(OccupiedEntry<'a, IDX, V>),
-}
-
-impl<'a, IDX, V> Entry<'a, IDX, V> {
-    /// Ensures a value is in the entry by inserting the default if empty, and returns a mutable reference to
-    /// the value in the entry.
-    pub fn or_insert(self, default: V) -> &'a mut V {
-        match self {
-            Self::Vacant(ent) => ent.insert(default),
-            Self::Occupied(ent) => ent.into_mut(),
-        }
-    }
-
-    /// Ensures a value is in the entry by inserting the result of the default function if empty, and returns
-    /// a mutable reference to the value in the entry.
-    pub fn or_insert_with<F: FnOnce() -> V>(self, default: F) -> &'a mut V {
-        match self {
-            Self::Vacant(ent) => ent.insert(default()),
-            Self::Occupied(ent) => ent.into_mut(),
-        }
-    }
-
-    /// Provides in-place mutable access to an occupied entry before any potential inserts into the map.
-    pub fn and_modify<F: FnOnce(&mut V)>(mut self, f: F) -> Self {
-        if let Self::Occupied(ent) = &mut self {
-            f(ent.get_mut());
-        }
-        self
-    }
-}
-
-impl<'a, IDX, V> Entry<'a, IDX, V>
-where
-    V: Default,
-{
-    /// Ensures a value is in the entry by inserting the default value if empty, and returns a mutable reference
-    /// to the value in the entry.
-    pub fn or_default(self) -> &'a mut V {
-        self.or_insert_with(Default::default)
-    }
-}
-
-/// A view into an vacant entry in a [`ArenaMap`]. It is part of the [`Entry`] enum.
-pub struct VacantEntry<'a, IDX, V> {
-    slot: &'a mut Option<V>,
-    _ty: PhantomData<IDX>,
-}
-
-impl<'a, IDX, V> VacantEntry<'a, IDX, V> {
-    /// Sets the value of the entry with the `VacantEntry`’s key, and returns a mutable reference to it.
-    pub fn insert(self, value: V) -> &'a mut V {
-        self.slot.insert(value)
-    }
-}
-
-/// A view into an occupied entry in a [`ArenaMap`]. It is part of the [`Entry`] enum.
-pub struct OccupiedEntry<'a, IDX, V> {
-    slot: &'a mut Option<V>,
-    _ty: PhantomData<IDX>,
-}
-
-impl<'a, IDX, V> OccupiedEntry<'a, IDX, V> {
-    /// Gets a reference to the value in the entry.
-    pub fn get(&self) -> &V {
-        self.slot.as_ref().expect("Occupied")
-    }
-
-    /// Gets a mutable reference to the value in the entry.
-    pub fn get_mut(&mut self) -> &mut V {
-        self.slot.as_mut().expect("Occupied")
-    }
-
-    /// Converts the entry into a mutable reference to its value.
-    pub fn into_mut(self) -> &'a mut V {
-        self.slot.as_mut().expect("Occupied")
-    }
-
-    /// Sets the value of the entry with the `OccupiedEntry`’s key, and returns the entry’s old value.
-    pub fn insert(&mut self, value: V) -> V {
-        self.slot.replace(value).expect("Occupied")
-    }
-
-    /// Takes the value of the entry out of the map, and returns it.
-    pub fn remove(self) -> V {
-        self.slot.take().expect("Occupied")
+        ArenaMap { v: Vec::new(), _ty: PhantomData }
     }
 }


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 4f626105a5..92dffa7f37 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
@@ -295,13 +295,13 @@ fn test_concat_expand() {
 #[rustc_builtin_macro]
 macro_rules! concat {}
 
-fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false, '"', '\0'); }
+fn main() { concat!("foo", "r", 0, r#"bar"#, "\n", false); }
 "##,
         expect![[r##"
 #[rustc_builtin_macro]
 macro_rules! concat {}
 
-fn main() { "foor0bar\nfalse\"\u{0}"; }
+fn main() { "foor0bar\nfalse"; }
 "##]],
     );
 }
diff --git a/crates/hir-ty/src/tests/traits.rs b/crates/hir-ty/src/tests/traits.rs
index 75802a5eb4..730ebe2357 100644
--- a/crates/hir-ty/src/tests/traits.rs
+++ b/crates/hir-ty/src/tests/traits.rs
@@ -137,6 +137,31 @@ fn not_send() -> Box<dyn Future<Output = ()> + 'static> {
     );
 }
 
+#[test]
+fn into_future_trait() {
+    check_types(
+        r#"
+//- minicore: future
+struct Futurable;
+impl core::future::IntoFuture for Futurable {
+    type Output = u64;
+    type IntoFuture = IntFuture;
+}
+
+struct IntFuture;
+impl core::future::Future for IntFuture {
+    type Output = u64;
+}
+
+fn test() {
+    let r = Futurable;
+    let v = r.await;
+    v;
+} //^ u64
+"#,
+    );
+}
+
 #[test]
 fn infer_try() {
     check_types(
diff --git a/crates/ide-diagnostics/src/tests.rs b/crates/ide-diagnostics/src/tests.rs
index 729619cfde..7312bca32f 100644
--- a/crates/ide-diagnostics/src/tests.rs
+++ b/crates/ide-diagnostics/src/tests.rs
@@ -37,7 +37,7 @@ fn check_nth_fix(nth: usize, ra_fixture_before: &str, ra_fixture_after: &str) {
     let after = trim_indent(ra_fixture_after);
 
     let (db, file_position) = RootDatabase::with_position(ra_fixture_before);
-    let mut conf = DiagnosticsConfig::test_sample();
+    let mut conf = DiagnosticsConfig::default();
     conf.expr_fill_default = ExprFillDefaultMode::Default;
     let diagnostic =
         super::diagnostics(&db, &conf, &AssistResolveStrategy::All, file_position.file_id)
@@ -69,7 +69,7 @@ pub(crate) fn check_no_fix(ra_fixture: &str) {
     let (db, file_position) = RootDatabase::with_position(ra_fixture);
     let diagnostic = super::diagnostics(
         &db,
-        &DiagnosticsConfig::test_sample(),
+        &DiagnosticsConfig::default(),
         &AssistResolveStrategy::All,
         file_position.file_id,
     )
@@ -82,7 +82,7 @@ pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
     let (db, file_id) = RootDatabase::with_single_file(ra_fixture);
     let diagnostics = super::diagnostics(
         &db,
-        &DiagnosticsConfig::test_sample(),
+        &DiagnosticsConfig::default(),
         &AssistResolveStrategy::All,
         file_id,
     );
@@ -91,7 +91,7 @@ pub(crate) fn check_expect(ra_fixture: &str, expect: Expect) {
 
 #[track_caller]
 pub(crate) fn check_diagnostics(ra_fixture: &str) {
-    let mut config = DiagnosticsConfig::test_sample();
+    let mut config = DiagnosticsConfig::default();
     config.disabled.insert("inactive-code".to_string());
     check_diagnostics_with_config(config, ra_fixture)
 }
@@ -127,7 +127,7 @@ pub(crate) fn check_diagnostics_with_config(config: DiagnosticsConfig, ra_fixtur
 
 #[test]
 fn test_disabled_diagnostics() {
-    let mut config = DiagnosticsConfig::test_sample();
+    let mut config = DiagnosticsConfig::default();
     config.disabled.insert("unresolved-module".into());
 
     let (db, file_id) = RootDatabase::with_single_file(r#"mod foo;"#);
@@ -137,7 +137,7 @@ fn test_disabled_diagnostics() {
 
     let diagnostics = super::diagnostics(
         &db,
-        &DiagnosticsConfig::test_sample(),
+        &DiagnosticsConfig::default(),
         &AssistResolveStrategy::All,
         file_id,
     );
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 382735cb36..99be7c6648 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -958,7 +958,7 @@ pub struct Struct;
 
 #[test]
 #[cfg_attr(
-    not(all(unix, target_pointer_width = "64")),
+    all(unix, not(target_pointer_width = "64")),
     ignore = "depends on `DefaultHasher` outputs"
 )]
 fn test_rainbow_highlighting() {
diff --git a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast
index cfef5d3f95..44c967e8dc 100644
--- a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast
+++ b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rast
@@ -172,122 +172,6 @@ SOURCE_FILE
               WHITESPACE "\n    "
               R_CURLY "}"
         WHITESPACE "\n\n    "
-        EXPR_STMT
-          MATCH_EXPR
-            MATCH_KW "match"
-            WHITESPACE " "
-            TUPLE_EXPR
-              L_PAREN "("
-              R_PAREN ")"
-            WHITESPACE " "
-            MATCH_ARM_LIST
-              L_CURLY "{"
-              WHITESPACE "\n        "
-              MATCH_ARM
-                RECORD_PAT
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "S"
-                  WHITESPACE " "
-                  RECORD_PAT_FIELD_LIST
-                    L_CURLY "{"
-                    WHITESPACE " "
-                    RECORD_PAT_FIELD
-                      NAME_REF
-                        IDENT "a"
-                      COLON ":"
-                      WHITESPACE " "
-                      LITERAL_PAT
-                        LITERAL
-                          INT_NUMBER "0"
-                    WHITESPACE " "
-                    R_CURLY "}"
-                WHITESPACE " "
-                FAT_ARROW "=>"
-                WHITESPACE " "
-                TUPLE_EXPR
-                  L_PAREN "("
-                  R_PAREN ")"
-                COMMA ","
-              WHITESPACE "\n        "
-              MATCH_ARM
-                RECORD_PAT
-                  PATH
-                    PATH_SEGMENT
-                      NAME_REF
-                        IDENT "S"
-                  WHITESPACE " "
-                  RECORD_PAT_FIELD_LIST
-                    L_CURLY "{"
-                    WHITESPACE " "
-                    RECORD_PAT_FIELD
-                      NAME_REF
-                        IDENT "a"
-                      COLON ":"
-                      WHITESPACE " "
-                      RANGE_PAT
-                        LITERAL_PAT
-                          LITERAL
-                            INT_NUMBER "1"
-                        DOT2 ".."
-                    WHITESPACE " "
-                    R_CURLY "}"
-                WHITESPACE " "
-                FAT_ARROW "=>"
-                WHITESPACE " "
-                TUPLE_EXPR
-                  L_PAREN "("
-                  R_PAREN ")"
-                COMMA ","
-              WHITESPACE "\n    "
-              R_CURLY "}"
-        WHITESPACE "\n\n    "
-        EXPR_STMT
-          MATCH_EXPR
-            MATCH_KW "match"
-            WHITESPACE " "
-            TUPLE_EXPR
-              L_PAREN "("
-              R_PAREN ")"
-            WHITESPACE " "
-            MATCH_ARM_LIST
-              L_CURLY "{"
-              WHITESPACE "\n        "
-              MATCH_ARM
-                SLICE_PAT
-                  L_BRACK "["
-                  LITERAL_PAT
-                    LITERAL
-                      INT_NUMBER "0"
-                  R_BRACK "]"
-                WHITESPACE " "
-                FAT_ARROW "=>"
-                WHITESPACE " "
-                TUPLE_EXPR
-                  L_PAREN "("
-                  R_PAREN ")"
-                COMMA ","
-              WHITESPACE "\n        "
-              MATCH_ARM
-                SLICE_PAT
-                  L_BRACK "["
-                  RANGE_PAT
-                    LITERAL_PAT
-                      LITERAL
-                        INT_NUMBER "1"
-                    DOT2 ".."
-                  R_BRACK "]"
-                WHITESPACE " "
-                FAT_ARROW "=>"
-                WHITESPACE " "
-                TUPLE_EXPR
-                  L_PAREN "("
-                  R_PAREN ")"
-                COMMA ","
-              WHITESPACE "\n    "
-              R_CURLY "}"
-        WHITESPACE "\n\n    "
         MATCH_EXPR
           MATCH_KW "match"
           WHITESPACE " "
diff --git a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs
index 2411d51096..6c586a8956 100644
--- a/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs
+++ b/crates/parser/test_data/parser/inline/ok/0058_range_pat.rs
@@ -11,16 +11,6 @@ fn main() {
         Some(1..) => ()
     }
 
-    match () {
-        S { a: 0 } => (),
-        S { a: 1.. } => (),
-    }
-
-    match () {
-        [0] => (),
-        [1..] => (),
-    }
-
     match (10 as u8, 5 as u8) {
         (0, _) => (),
         (1.., _) => ()
diff --git a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast
index 4b401b60df..3d3587a706 100644
--- a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast
+++ b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rast
@@ -11,7 +11,7 @@ SOURCE_FILE
     BLOCK_EXPR
       STMT_LIST
         L_CURLY "{"
-        WHITESPACE "\n    "
+        WHITESPACE " "
         LET_STMT
           LET_KW "let"
           WHITESPACE " "
@@ -27,25 +27,6 @@ SOURCE_FILE
           LITERAL
             INT_NUMBER "1u32"
           SEMICOLON ";"
-        WHITESPACE "\n    "
-        LET_STMT
-          LET_KW "let"
-          WHITESPACE " "
-          RANGE_PAT
-            LITERAL_PAT
-              LITERAL
-                INT_NUMBER "0"
-            DOT2 ".."
-          COLON ":"
-          WHITESPACE " "
-          INFER_TYPE
-            UNDERSCORE "_"
-          WHITESPACE " "
-          EQ "="
-          WHITESPACE " "
-          LITERAL
-            INT_NUMBER "1u32"
-          SEMICOLON ";"
-        WHITESPACE "\n"
+        WHITESPACE " "
         R_CURLY "}"
   WHITESPACE "\n"
diff --git a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs
index c9386a221a..1360eda056 100644
--- a/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs
+++ b/crates/parser/test_data/parser/inline/ok/0166_half_open_range_pat.rs
@@ -1,4 +1,1 @@
-fn f() {
-    let 0 .. = 1u32;
-    let 0..: _ = 1u32;
-}
+fn f() { let 0 .. = 1u32; }
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 58099a58de..18f95925d9 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -13,8 +13,9 @@ use xshell::cmd;
 fn check_code_formatting() {
     let sh = &Shell::new().unwrap();
     sh.change_dir(sourcegen::project_root());
+    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
 
-    let out = cmd!(sh, "rustup run stable rustfmt --version").read().unwrap();
+    let out = cmd!(sh, "rustfmt --version").read().unwrap();
     if !out.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -22,9 +23,9 @@ fn check_code_formatting() {
         )
     }
 
-    let res = cmd!(sh, "rustup run stable cargo fmt -- --check").run();
+    let res = cmd!(sh, "cargo fmt -- --check").run();
     if res.is_err() {
-        let _ = cmd!(sh, "rustup run stable cargo fmt").run();
+        let _ = cmd!(sh, "cargo fmt").run();
     }
     res.unwrap()
 }
diff --git a/crates/test-utils/src/minicore.rs b/crates/test-utils/src/minicore.rs
index f48d1ec66a..6df29db474 100644
--- a/crates/test-utils/src/minicore.rs
+++ b/crates/test-utils/src/minicore.rs
@@ -471,6 +471,21 @@ pub mod future {
         #[lang = "poll"]
         fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
     }
+
+    pub trait IntoFuture {
+        type Output;
+        type IntoFuture: Future<Output = Self::Output>;
+        #[lang = "into_future"]
+        fn into_future(self) -> Self::IntoFuture;
+    }
+
+    impl<F: Future> IntoFuture for F {
+        type Output = F::Output;
+        type IntoFuture = F;
+        fn into_future(self) -> F {
+            self
+        }
+    }
 }
 pub mod task {
     pub enum Poll<T> {