Repository: rust-analyzer/rust-analyzer
Pull request #7162 (2021-01-05 04:22:34)

Introduce queries to avoid problems when performing completion for enums with many variants
This change introduces two new queries to compute:
  1) attributes for all variants of an enum, and
  2) attributes for all fields of a variant.

The purpose of this change is to avoid the current n^2 behavior when rendering completion for variants (which prevents completion for enums with large numbers of variants).


Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index fd22ea88a7..889ada401c 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -15,8 +15,8 @@ env:
   RUSTUP_MAX_RETRIES: 10
 
 jobs:
-  dist-x86_64-pc-windows-msvc:
-    name: dist (x86_64-pc-windows-msvc)
+  dist-windows:
+    name: dist (Windows)
     runs-on: windows-latest
     env:
       RA_TARGET: x86_64-pc-windows-msvc
@@ -45,41 +45,11 @@ jobs:
     - name: Upload artifacts
       uses: actions/upload-artifact@v1
       with:
-        name: dist-x86_64-pc-windows-msvc
+        name: dist-windows-latest
         path: ./dist
 
-  dist-aarch64-pc-windows-msvc:
-    name: dist (aarch64-pc-windows-msvc)
-    runs-on: windows-latest
-    env:
-      RA_TARGET: aarch64-pc-windows-msvc
-
-    steps:
-    - name: Checkout repository
-      uses: actions/checkout@v2
-
-    - name: Rename existing rust toolchain
-      run: Rename-Item C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc C:\Users\runneradmin\.rustup\toolchains\stable-x86_64-pc-windows-msvc.old
-
-    - name: Install Rust toolchain
-      uses: actions-rs/toolchain@v1
-      with:
-        toolchain: stable
-        target: aarch64-pc-windows-msvc
-        profile: minimal
-        override: true
-
-    - name: Dist
-      run: cargo xtask dist
-
-    - name: Upload artifacts
-      uses: actions/upload-artifact@v1
-      with:
-        name: dist-aarch64-pc-windows-msvc
-        path: ./dist
-
-  dist-x86_64-unknown-linux-gnu:
-    name: dist (x86_64-unknown-linux-gnu)
+  dist-ubuntu:
+    name: dist (Ubuntu 16.04)
     runs-on: ubuntu-16.04
     env:
       RA_TARGET: x86_64-unknown-linux-gnu
@@ -115,11 +85,11 @@ jobs:
     - name: Upload artifacts
       uses: actions/upload-artifact@v1
       with:
-        name: dist-x86_64-unknown-linux-gnu
+        name: dist-ubuntu-16.04
         path: ./dist
 
-  dist-x86_64-apple-darwin:
-    name: dist (x86_64-apple-darwin)
+  dist-macos-latest:
+    name: dist (MacOS latest)
     runs-on: macos-latest
     env:
       RA_TARGET: x86_64-apple-darwin
@@ -141,11 +111,11 @@ jobs:
     - name: Upload artifacts
       uses: actions/upload-artifact@v1
       with:
-        name: dist-x86_64-apple-darwin
+        name: dist-macos-latest
         path: ./dist
 
-  dist-aarch64-apple-darwin:
-    name: dist (aarch64-apple-darwin)
+  dist-macos-11:
+    name: dist (MacOS 11.0)
     runs-on: macos-11.0
     env:
       RA_TARGET: aarch64-apple-darwin
@@ -168,13 +138,13 @@ jobs:
     - name: Upload artifacts
       uses: actions/upload-artifact@v1
       with:
-        name: dist-aarch64-apple-darwin
+        name: dist-macos-11.0
         path: ./dist
 
   publish:
     name: publish
     runs-on: ubuntu-16.04
-    needs: ['dist-x86_64-pc-windows-msvc', 'dist-aarch64-pc-windows-msvc', 'dist-x86_64-unknown-linux-gnu', 'dist-x86_64-apple-darwin', 'dist-aarch64-apple-darwin']
+    needs: ['dist-windows', 'dist-ubuntu', 'dist-macos-latest', 'dist-macos-11']
     steps:
     - name: Install Nodejs
       uses: actions/setup-node@v1
@@ -195,23 +165,19 @@ jobs:
 
     - uses: actions/download-artifact@v1
       with:
-        name: dist-aarch64-apple-darwin
-        path: dist
-    - uses: actions/download-artifact@v1
-      with:
-        name: dist-x86_64-apple-darwin
+        name: dist-macos-11.0
         path: dist
     - uses: actions/download-artifact@v1
       with:
-        name: dist-x86_64-unknown-linux-gnu
+        name: dist-macos-latest
         path: dist
     - uses: actions/download-artifact@v1
       with:
-        name: dist-x86_64-pc-windows-msvc
+        name: dist-ubuntu-16.04
         path: dist
     - uses: actions/download-artifact@v1
       with:
-        name: dist-aarch64-pc-windows-msvc
+        name: dist-windows-latest
         path: dist
     - run: ls -al ./dist
 
diff --git a/Cargo.lock b/Cargo.lock
index f87c590a4c..4aaee3ab1d 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -2,9 +2,9 @@
 # It is not intended for manual editing.
 [[package]]
 name = "addr2line"
-version = "0.14.1"
+version = "0.14.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a55f82cfe485775d02112886f4169bde0c5894d75e79ead7eafe7e40a25e45f7"
+checksum = "7c0929d69e78dd9bf5408269919fcbcaeb2e35e5d43e5815517cdc6a8e11a423"
 dependencies = [
  "gimli",
 ]
@@ -132,7 +132,7 @@ version = "0.12.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d5a5f7b42f606b7f23674f6f4d877628350682bc40687d3fae65679a58d55345"
 dependencies = [
- "semver",
+ "semver 0.11.0",
  "serde",
  "serde_json",
 ]
@@ -168,9 +168,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.47.0"
+version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f00f6342a387edc822002d36a381e117afcac9f744951ff75fbf4a218edea5c"
+checksum = "ec7dacf94958d1a930b95d049d9443860859af59eadc77849392093eb577bcee"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -180,9 +180,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.47.0"
+version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c686e69913591ae753e5526e73cbee39db3d9b0a92cc9078ab780cabf1c70aa9"
+checksum = "a1a5b38ede247def17da87f4badb62396a5753db6048e2011d3089d8b3796c67"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -191,9 +191,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.47.0"
+version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "310fdcac0340dab4163b766baa8067266e3b909108d1ac1b5246c033bde63975"
+checksum = "7a18db146d7a023edc20ad094e8c2284451f7888719645004979617d1f17c041"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -204,9 +204,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.47.0"
+version = "0.45.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "c3c3252116111c3548f1164ab8d98c67c49848b3bde10dd11b650fd023e91c72"
+checksum = "7f73e0de04a0f394e47ed8118e00541bcf681d7c3c2ef500fa743eb4cf3a4850"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -487,6 +487,19 @@ version = "0.3.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3dcaa9ae7725d12cdb85b3ad99a434db70b468c09ded17e012d86b5c1010f7a7"
 
+[[package]]
+name = "generator"
+version = "0.6.23"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "8cdc09201b2e8ca1b19290cf7e65de2246b8e91fb6874279722189c4de7b94dc"
+dependencies = [
+ "cc",
+ "libc",
+ "log",
+ "rustc_version",
+ "winapi 0.3.9",
+]
+
 [[package]]
 name = "gimli"
 version = "0.23.0"
@@ -820,6 +833,19 @@ dependencies = [
  "cfg-if 0.1.10",
 ]
 
+[[package]]
+name = "loom"
+version = "0.3.6"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "a0e8460f2f2121162705187214720353c517b97bdfb3494c0b1e33d83ebe4bed"
+dependencies = [
+ "cfg-if 0.1.10",
+ "generator",
+ "scoped-tls",
+ "serde",
+ "serde_json",
+]
+
 [[package]]
 name = "lsp-server"
 version = "0.5.0"
@@ -1368,9 +1394,9 @@ dependencies = [
 
 [[package]]
 name = "rustc-ap-rustc_lexer"
-version = "697.0.0"
+version = "695.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "67adbe260a0a11910624d6d28c0304fcf7b063e666682111005c83b09f73429d"
+checksum = "390bad134705b0bff02cd9541ac66df751a91c3cc734c3369cd6151ca269caed"
 dependencies = [
  "unicode-xid",
 ]
@@ -1387,6 +1413,15 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "08d43f7aa6b08d49f382cde6a7982047c3426db949b1424bc4b7ec9ae12c6ce2"
 
+[[package]]
+name = "rustc_version"
+version = "0.2.3"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "138e3e0acb6c9fb258b19b67cb8abd63c00679d2851805ea151465464fe9030a"
+dependencies = [
+ "semver 0.9.0",
+]
+
 [[package]]
 name = "ryu"
 version = "1.0.5"
@@ -1443,16 +1478,31 @@ version = "1.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
+[[package]]
+name = "semver"
+version = "0.9.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "1d7eb9ef2c18661902cc47e535f9bc51b78acd254da71d375c2f6720d9a40403"
+dependencies = [
+ "semver-parser 0.7.0",
+]
+
 [[package]]
 name = "semver"
 version = "0.11.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f301af10236f6df4160f7c3f04eec6dbc70ace82d23326abad5edee88801c6b6"
 dependencies = [
- "semver-parser",
+ "semver-parser 0.10.1",
  "serde",
 ]
 
+[[package]]
+name = "semver-parser"
+version = "0.7.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "388a1df253eca08550bef6c72392cfe7c30914bf41df5269b68cbd6ff8f570a3"
+
 [[package]]
 name = "semver-parser"
 version = "0.10.1"
@@ -1516,11 +1566,12 @@ dependencies = [
 
 [[package]]
 name = "sharded-slab"
-version = "0.1.1"
+version = "0.1.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "79c719719ee05df97490f80a45acfc99e5a30ce98a1e4fb67aee422745ae14e3"
+checksum = "7b4921be914e16899a80adefb821f8ddb7974e3f1250223575a44ed994882127"
 dependencies = [
  "lazy_static",
+ "loom",
 ]
 
 [[package]]
@@ -1531,9 +1582,9 @@ checksum = "c111b5bd5695e56cffe5129854aa230b39c93a305372fdbb2668ca2394eea9f8"
 
 [[package]]
 name = "smallvec"
-version = "1.6.0"
+version = "1.5.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a55ca5f3b68e41c979bf8c46a6f1da892ca4db8f94023ce0bd32407573b1ac0"
+checksum = "ae524f056d7d770e174287294f562e95044c68e88dec909a00d2094805db9d75"
 
 [[package]]
 name = "smol_str"
@@ -1564,9 +1615,9 @@ version = "0.0.0"
 
 [[package]]
 name = "syn"
-version = "1.0.57"
+version = "1.0.56"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4211ce9909eb971f111059df92c45640aad50a619cf55cd76476be803c4c68e6"
+checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1775,16 +1826,15 @@ dependencies = [
 
 [[package]]
 name = "tracing-tree"
-version = "0.1.7"
+version = "0.1.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "023e80cdb7c8468b7aade1d756afa2acbe2ae0a6142a25ec664b5239d6ef2794"
+checksum = "43aac8afb493b08e1e1904956f7407c1e671b9c83b26a17e1bd83d6a3520e350"
 dependencies = [
  "ansi_term",
  "atty",
  "chrono",
  "termcolor",
  "tracing",
- "tracing-log",
  "tracing-subscriber",
 ]
 
diff --git a/crates/assists/src/handlers/pull_assignment_up.rs b/crates/assists/src/handlers/extract_assignment.rs
similarity index 84%
rename from crates/assists/src/handlers/pull_assignment_up.rs
rename to crates/assists/src/handlers/extract_assignment.rs
index 560d93e101..ae99598c00 100644
--- a/crates/assists/src/handlers/pull_assignment_up.rs
+++ b/crates/assists/src/handlers/extract_assignment.rs
@@ -9,9 +9,9 @@ use crate::{
     AssistId, AssistKind,
 };
 
-// Assist: pull_assignment_up
+// Assist: extract_assignment
 //
-// Extracts variable assignment to outside an if or match statement.
+// Extracts variable assigment to outside an if or match statement.
 //
 // ```
 // fn main() {
@@ -36,7 +36,7 @@ use crate::{
 //     };
 // }
 // ```
-pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
+pub(crate) fn extract_assigment(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let assign_expr = ctx.find_node_at_offset::<ast::BinExpr>()?;
     let name_expr = if assign_expr.op_kind()? == ast::BinOp::Assignment {
         assign_expr.lhs()?
@@ -61,8 +61,8 @@ pub(crate) fn pull_assignment_up(acc: &mut Assists, ctx: &AssistContext) -> Opti
     let expr_stmt = make::expr_stmt(new_stmt);
 
     acc.add(
-        AssistId("pull_assignment_up", AssistKind::RefactorExtract),
-        "Pull assignment up",
+        AssistId("extract_assignment", AssistKind::RefactorExtract),
+        "Extract assignment",
         old_stmt.syntax().text_range(),
         move |edit| {
             edit.replace(old_stmt.syntax().text_range(), format!("{} = {};", name_expr, expr_stmt));
@@ -104,7 +104,7 @@ fn exprify_if(
             ast::ElseBranch::Block(exprify_block(block, sema, name)?)
         }
         ast::ElseBranch::IfExpr(expr) => {
-            mark::hit!(test_pull_assignment_up_chained_if);
+            mark::hit!(test_extract_assigment_chained_if);
             ast::ElseBranch::IfExpr(ast::IfExpr::cast(
                 exprify_if(&expr, sema, name)?.syntax().to_owned(),
             )?)
@@ -144,7 +144,7 @@ fn is_equivalent(
 ) -> bool {
     match (expr0, expr1) {
         (ast::Expr::FieldExpr(field_expr0), ast::Expr::FieldExpr(field_expr1)) => {
-            mark::hit!(test_pull_assignment_up_field_assignment);
+            mark::hit!(test_extract_assignment_field_assignment);
             sema.resolve_field(field_expr0) == sema.resolve_field(field_expr1)
         }
         (ast::Expr::PathExpr(path0), ast::Expr::PathExpr(path1)) => {
@@ -167,9 +167,9 @@ mod tests {
     use crate::tests::{check_assist, check_assist_not_applicable};
 
     #[test]
-    fn test_pull_assignment_up_if() {
+    fn test_extract_assignment_if() {
         check_assist(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -194,9 +194,9 @@ fn foo() {
     }
 
     #[test]
-    fn test_pull_assignment_up_match() {
+    fn test_extract_assignment_match() {
         check_assist(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -233,9 +233,9 @@ fn foo() {
     }
 
     #[test]
-    fn test_pull_assignment_up_not_last_not_applicable() {
+    fn test_extract_assignment_not_last_not_applicable() {
         check_assist_not_applicable(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -251,10 +251,10 @@ fn foo() {
     }
 
     #[test]
-    fn test_pull_assignment_up_chained_if() {
-        mark::check!(test_pull_assignment_up_chained_if);
+    fn test_extract_assignment_chained_if() {
+        mark::check!(test_extract_assigment_chained_if);
         check_assist(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -283,9 +283,9 @@ fn foo() {
     }
 
     #[test]
-    fn test_pull_assignment_up_retains_stmts() {
+    fn test_extract_assigment_retains_stmts() {
         check_assist(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -314,9 +314,9 @@ fn foo() {
     }
 
     #[test]
-    fn pull_assignment_up_let_stmt_not_applicable() {
+    fn extract_assignment_let_stmt_not_applicable() {
         check_assist_not_applicable(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -331,9 +331,9 @@ fn foo() {
     }
 
     #[test]
-    fn pull_assignment_up_if_missing_assigment_not_applicable() {
+    fn extract_assignment_if_missing_assigment_not_applicable() {
         check_assist_not_applicable(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -346,9 +346,9 @@ fn foo() {
     }
 
     #[test]
-    fn pull_assignment_up_match_missing_assigment_not_applicable() {
+    fn extract_assignment_match_missing_assigment_not_applicable() {
         check_assist_not_applicable(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 fn foo() {
     let mut a = 1;
@@ -367,10 +367,10 @@ fn foo() {
     }
 
     #[test]
-    fn test_pull_assignment_up_field_assignment() {
-        mark::check!(test_pull_assignment_up_field_assignment);
+    fn test_extract_assignment_field_assignment() {
+        mark::check!(test_extract_assignment_field_assignment);
         check_assist(
-            pull_assignment_up,
+            extract_assigment,
             r#"
 struct A(usize);
 
diff --git a/crates/assists/src/lib.rs b/crates/assists/src/lib.rs
index 01baa65fe0..212464f859 100644
--- a/crates/assists/src/lib.rs
+++ b/crates/assists/src/lib.rs
@@ -116,6 +116,7 @@ mod handlers {
     mod convert_integer_literal;
     mod early_return;
     mod expand_glob_import;
+    mod extract_assignment;
     mod extract_module_to_file;
     mod extract_struct_from_enum_variant;
     mod extract_variable;
@@ -124,8 +125,8 @@ mod handlers {
     mod flip_binexpr;
     mod flip_comma;
     mod flip_trait_bound;
-    mod generate_default_from_enum_variant;
     mod generate_derive;
+    mod generate_default_from_enum_variant;
     mod generate_from_impl_for_enum;
     mod generate_function;
     mod generate_impl;
@@ -138,7 +139,6 @@ mod handlers {
     mod merge_match_arms;
     mod move_bounds;
     mod move_guard;
-    mod pull_assignment_up;
     mod qualify_path;
     mod raw_string;
     mod remove_dbg;
@@ -168,6 +168,7 @@ mod handlers {
             convert_integer_literal::convert_integer_literal,
             early_return::convert_to_guarded_return,
             expand_glob_import::expand_glob_import,
+            extract_assignment::extract_assigment,
             extract_module_to_file::extract_module_to_file,
             extract_struct_from_enum_variant::extract_struct_from_enum_variant,
             extract_variable::extract_variable,
@@ -176,8 +177,8 @@ mod handlers {
             flip_binexpr::flip_binexpr,
             flip_comma::flip_comma,
             flip_trait_bound::flip_trait_bound,
-            generate_default_from_enum_variant::generate_default_from_enum_variant,
             generate_derive::generate_derive,
+            generate_default_from_enum_variant::generate_default_from_enum_variant,
             generate_from_impl_for_enum::generate_from_impl_for_enum,
             generate_function::generate_function,
             generate_impl::generate_impl,
@@ -191,7 +192,6 @@ mod handlers {
             move_bounds::move_bounds_to_where_clause,
             move_guard::move_arm_cond_to_match_guard,
             move_guard::move_guard_to_arm_body,
-            pull_assignment_up::pull_assignment_up,
             qualify_path::qualify_path,
             raw_string::add_hash,
             raw_string::make_usual_string,
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index 1a4aa78fb0..62eccf4752 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -5,7 +5,9 @@ use arrayvec::ArrayVec;
 use base_db::{CrateDisplayName, CrateId, Edition, FileId};
 use either::Either;
 use hir_def::{
-    adt::{ReprKind, StructKind, VariantData},
+    adt::ReprKind,
+    adt::StructKind,
+    adt::VariantData,
     builtin_type::BuiltinType,
     expr::{BindingAnnotation, LabelId, Pat, PatId},
     import_map,
@@ -29,7 +31,7 @@ use hir_expand::{
 };
 use hir_ty::{
     autoderef,
-    display::{write_bounds_like_dyn_trait, HirDisplayError, HirFormatter},
+    display::{HirDisplayError, HirFormatter},
     method_resolution,
     traits::{FnTrait, Solution, SolutionVariables},
     ApplicationTy, BoundVar, CallableDefId, Canonical, DebruijnIndex, FnSig, GenericPredicate,
@@ -743,18 +745,6 @@ impl Function {
         db.function_data(self.id).name.clone()
     }
 
-    /// Get this function's return type
-    pub fn ret_type(self, db: &dyn HirDatabase) -> Type {
-        let resolver = self.id.resolver(db.upcast());
-        let ret_type = &db.function_data(self.id).ret_type;
-        let ctx = hir_ty::TyLoweringContext::new(db, &resolver);
-        let environment = TraitEnvironment::lower(db, &resolver);
-        Type {
-            krate: self.id.lookup(db.upcast()).container.module(db.upcast()).krate,
-            ty: InEnvironment { value: Ty::from_hir_ext(&ctx, ret_type).0, environment },
-        }
-    }
-
     pub fn self_param(self, db: &dyn HirDatabase) -> Option<SelfParam> {
         if !db.function_data(self.id).has_self_param {
             return None;
@@ -1288,18 +1278,6 @@ impl TypeParam {
         }
     }
 
-    pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
-        db.generic_predicates_for_param(self.id)
-            .into_iter()
-            .filter_map(|pred| match &pred.value {
-                hir_ty::GenericPredicate::Implemented(trait_ref) => {
-                    Some(Trait::from(trait_ref.trait_))
-                }
-                _ => None,
-            })
-            .collect()
-    }
-
     pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
         let params = db.generic_defaults(self.id.parent);
         let local_idx = hir_ty::param_idx(db, self.id)?;
@@ -1315,20 +1293,6 @@ impl TypeParam {
     }
 }
 
-impl HirDisplay for TypeParam {
-    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
-        write!(f, "{}", self.name(f.db))?;
-        let bounds = f.db.generic_predicates_for_param(self.id);
-        let substs = Substs::type_params(f.db, self.id.parent);
-        let predicates = bounds.iter().cloned().map(|b| b.subst(&substs)).collect::<Vec<_>>();
-        if !(predicates.is_empty() || f.omit_verbose_types()) {
-            write!(f, ": ")?;
-            write_bounds_like_dyn_trait(&predicates, f)?;
-        }
-        Ok(())
-    }
-}
-
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct LifetimeParam {
     pub(crate) id: LifetimeParamId,
@@ -1367,12 +1331,6 @@ impl ConstParam {
     pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
         self.id.parent.into()
     }
-
-    pub fn ty(self, db: &dyn HirDatabase) -> Type {
-        let def = self.id.parent;
-        let krate = def.module(db.upcast()).krate;
-        Type::new(db, krate, def, db.const_param_ty(self.id))
-    }
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 6b79e7badf..9e6426b314 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -2,6 +2,7 @@
 
 use std::{ops, sync::Arc};
 
+use arena::map::ArenaMap;
 use base_db::CrateId;
 use cfg::{CfgExpr, CfgOptions};
 use either::Either;
@@ -21,7 +22,8 @@ use crate::{
     nameres::ModuleSource,
     path::{ModPath, PathKind},
     src::HasChildSource,
-    AdtId, AttrDefId, GenericParamId, Lookup,
+    AdtId, AttrDefId, EnumId, GenericParamId, HasModule, LocalEnumVariantId, LocalFieldId, Lookup,
+    VariantId,
 };
 
 /// Holds documentation
@@ -210,16 +212,10 @@ impl Attrs {
                 }
             }
             AttrDefId::FieldId(it) => {
-                let src = it.parent.child_source(db);
-                match &src.value[it.local_id] {
-                    Either::Left(_tuple) => RawAttrs::default(),
-                    Either::Right(record) => RawAttrs::from_attrs_owner(db, src.with_value(record)),
-                }
+                return db.fields_attrs(it.parent)[it.local_id].clone();
             }
-            AttrDefId::EnumVariantId(var_id) => {
-                let src = var_id.parent.child_source(db);
-                let src = src.as_ref().map(|it| &it[var_id.local_id]);
-                RawAttrs::from_attrs_owner(db, src.map(|it| it as &dyn AttrsOwner))
+            AttrDefId::EnumVariantId(it) => {
+                return db.variants_attrs(it.parent)[it.local_id].clone();
             }
             AttrDefId::AdtId(it) => match it {
                 AdtId::StructId(it) => attrs_from_item_tree(it.lookup(db).id, db),
@@ -259,6 +255,46 @@ impl Attrs {
         raw_attrs.filter(db, def.krate(db))
     }
 
+    pub(crate) fn variants_attrs_query(
+        db: &dyn DefDatabase,
+        e: EnumId,
+    ) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>> {
+        let krate = e.lookup(db).container.module(db).krate;
+        let src = e.child_source(db);
+        let mut res = ArenaMap::default();
+
+        for (id, var) in src.value.iter() {
+            let attrs = RawAttrs::from_attrs_owner(db, src.with_value(var as &dyn AttrsOwner))
+                .filter(db, krate);
+
+            res.insert(id, attrs)
+        }
+
+        Arc::new(res)
+    }
+
+    pub(crate) fn fields_attrs_query(
+        db: &dyn DefDatabase,
+        v: VariantId,
+    ) -> Arc<ArenaMap<LocalFieldId, Attrs>> {
+        let krate = v.module(db).krate;
+        let src = v.child_source(db);
+        let mut res = ArenaMap::default();
+
+        for (id, fld) in src.value.iter() {
+            let attrs = match fld {
+                Either::Left(_tuple) => Attrs::default(),
+                Either::Right(record) => {
+                    RawAttrs::from_attrs_owner(db, src.with_value(record)).filter(db, krate)
+                }
+            };
+
+            res.insert(id, attrs);
+        }
+
+        Arc::new(res)
+    }
+
     pub fn by_key(&self, key: &'static str) -> AttrQuery<'_> {
         AttrQuery { attrs: self, key }
     }
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index d1a459066d..d3bf5b34cf 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -1,6 +1,7 @@
 //! Defines database & queries for name resolution.
 use std::sync::Arc;
 
+use arena::map::ArenaMap;
 use base_db::{salsa, CrateId, SourceDatabase, Upcast};
 use hir_expand::{db::AstDatabase, HirFileId};
 use syntax::SmolStr;
@@ -16,8 +17,8 @@ use crate::{
     lang_item::{LangItemTarget, LangItems},
     nameres::CrateDefMap,
     AttrDefId, ConstId, ConstLoc, DefWithBodyId, EnumId, EnumLoc, FunctionId, FunctionLoc,
-    GenericDefId, ImplId, ImplLoc, StaticId, StaticLoc, StructId, StructLoc, TraitId, TraitLoc,
-    TypeAliasId, TypeAliasLoc, UnionId, UnionLoc,
+    GenericDefId, ImplId, ImplLoc, LocalEnumVariantId, LocalFieldId, StaticId, StaticLoc, StructId,
+    StructLoc, TraitId, TraitLoc, TypeAliasId, TypeAliasLoc, UnionId, UnionLoc, VariantId,
 };
 
 #[salsa::query_group(InternDatabaseStorage)]
@@ -92,6 +93,12 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
     #[salsa::invoke(GenericParams::generic_params_query)]
     fn generic_params(&self, def: GenericDefId) -> Arc<GenericParams>;
 
+    #[salsa::invoke(Attrs::variants_attrs_query)]
+    fn variants_attrs(&self, def: EnumId) -> Arc<ArenaMap<LocalEnumVariantId, Attrs>>;
+
+    #[salsa::invoke(Attrs::fields_attrs_query)]
+    fn fields_attrs(&self, def: VariantId) -> Arc<ArenaMap<LocalFieldId, Attrs>>;
+
     #[salsa::invoke(Attrs::attrs_query)]
     fn attrs(&self, def: AttrDefId) -> Attrs;
 
diff --git a/crates/hir_expand/src/proc_macro.rs b/crates/hir_expand/src/proc_macro.rs
index 1923daca55..7c77f6ce0a 100644
--- a/crates/hir_expand/src/proc_macro.rs
+++ b/crates/hir_expand/src/proc_macro.rs
@@ -58,7 +58,7 @@ impl ProcMacroExpander {
 }
 
 fn eat_punct(cursor: &mut Cursor, c: char) -> bool {
-    if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = cursor.token_tree() {
+    if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = cursor.token_tree() {
         if punct.char == c {
             *cursor = cursor.bump();
             return true;
@@ -68,7 +68,7 @@ fn eat_punct(cursor: &mut Cursor, c: char) -> bool {
 }
 
 fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool {
-    if let Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) = cursor.token_tree() {
+    if let Some(tt::TokenTree::Subtree(subtree)) = cursor.token_tree() {
         if Some(kind) == subtree.delimiter_kind() {
             *cursor = cursor.bump_subtree();
             return true;
@@ -78,7 +78,7 @@ fn eat_subtree(cursor: &mut Cursor, kind: tt::DelimiterKind) -> bool {
 }
 
 fn eat_ident(cursor: &mut Cursor, t: &str) -> bool {
-    if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) = cursor.token_tree() {
+    if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = cursor.token_tree() {
         if t == ident.text.as_str() {
             *cursor = cursor.bump();
             return true;
@@ -88,7 +88,7 @@ fn eat_ident(cursor: &mut Cursor, t: &str) -> bool {
 }
 
 fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> {
-    let buffer = TokenBuffer::from_tokens(&tt.token_trees);
+    let buffer = TokenBuffer::new(&tt.token_trees);
     let mut p = buffer.begin();
     let mut result = tt::Subtree::default();
 
@@ -106,7 +106,7 @@ fn remove_derive_attrs(tt: &tt::Subtree) -> Option<tt::Subtree> {
             }
         }
 
-        result.token_trees.push(curr.token_tree()?.cloned());
+        result.token_trees.push(curr.token_tree()?.clone());
         p = curr.bump();
     }
 
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index b0a453961e..3d17785902 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -17,9 +17,9 @@ ena = "0.14.0"
 log = "0.4.8"
 rustc-hash = "1.1.0"
 scoped-tls = "1"
-chalk-solve = { version = "0.47", default-features = false }
-chalk-ir = "0.47"
-chalk-recursive = "0.47"
+chalk-solve = { version = "0.45", default-features = false }
+chalk-ir = "0.45"
+chalk-recursive = "0.45"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 hir_def = { path = "../hir_def", version = "0.0.0" }
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index a54225c18b..0e827a29e7 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -595,7 +595,7 @@ impl HirDisplay for FnSig {
     }
 }
 
-pub fn write_bounds_like_dyn_trait(
+fn write_bounds_like_dyn_trait(
     predicates: &[GenericPredicate],
     f: &mut HirFormatter,
 ) -> Result<(), HirDisplayError> {
diff --git a/crates/ide/src/display/short_label.rs b/crates/ide/src/display/short_label.rs
index 990f740b8b..ea49d9f970 100644
--- a/crates/ide/src/display/short_label.rs
+++ b/crates/ide/src/display/short_label.rs
@@ -87,17 +87,6 @@ impl ShortLabel for ast::Variant {
     }
 }
 
-impl ShortLabel for ast::ConstParam {
-    fn short_label(&self) -> Option<String> {
-        let mut buf = "const ".to_owned();
-        buf.push_str(self.name()?.text().as_str());
-        if let Some(type_ref) = self.ty() {
-            format_to!(buf, ": {}", type_ref.syntax());
-        }
-        Some(buf)
-    }
-}
-
 fn short_label_from_ty<T>(node: &T, ty: Option<ast::Type>, prefix: &str) -> Option<String>
 where
     T: NameOwner + VisibilityOwner,
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index f2ad95cb60..2737c900f4 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -70,7 +70,7 @@ impl HoverConfig {
 #[derive(Debug, Clone)]
 pub enum HoverAction {
     Runnable(Runnable),
-    Implementation(FilePosition),
+    Implementaion(FilePosition),
     GoToType(Vec<HoverGotoTypeData>),
 }
 
@@ -116,13 +116,12 @@ pub(crate) fn hover(
     };
     if let Some(definition) = definition {
         if let Some(markup) = hover_for_definition(db, definition) {
-            let markup = markup.as_str();
             let markup = if !markdown {
-                remove_markdown(markup)
+                remove_markdown(&markup.as_str())
             } else if links_in_hover {
-                rewrite_links(db, markup, &definition)
+                rewrite_links(db, &markup.as_str(), &definition)
             } else {
-                remove_links(markup)
+                remove_links(&markup.as_str())
             };
             res.markup = Markup::from(markup);
             if let Some(action) = show_implementations_action(db, definition) {
@@ -176,24 +175,22 @@ pub(crate) fn hover(
 
 fn show_implementations_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
     fn to_action(nav_target: NavigationTarget) -> HoverAction {
-        HoverAction::Implementation(FilePosition {
+        HoverAction::Implementaion(FilePosition {
             file_id: nav_target.file_id,
             offset: nav_target.focus_or_full_range().start(),
         })
     }
 
-    let adt = match def {
-        Definition::ModuleDef(ModuleDef::Trait(it)) => return it.try_to_nav(db).map(to_action),
-        Definition::ModuleDef(ModuleDef::Adt(it)) => Some(it),
-        Definition::SelfType(it) => it.target_ty(db).as_adt(),
+    match def {
+        Definition::ModuleDef(it) => match it {
+            ModuleDef::Adt(Adt::Struct(it)) => Some(to_action(it.try_to_nav(db)?)),
+            ModuleDef::Adt(Adt::Union(it)) => Some(to_action(it.try_to_nav(db)?)),
+            ModuleDef::Adt(Adt::Enum(it)) => Some(to_action(it.try_to_nav(db)?)),
+            ModuleDef::Trait(it) => Some(to_action(it.try_to_nav(db)?)),
+            _ => None,
+        },
         _ => None,
-    }?;
-    match adt {
-        Adt::Struct(it) => it.try_to_nav(db),
-        Adt::Union(it) => it.try_to_nav(db),
-        Adt::Enum(it) => it.try_to_nav(db),
     }
-    .map(to_action)
 }
 
 fn runnable_action(
@@ -228,46 +225,45 @@ fn runnable_action(
 }
 
 fn goto_type_action(db: &RootDatabase, def: Definition) -> Option<HoverAction> {
-    let mut targets: Vec<ModuleDef> = Vec::new();
-    let mut push_new_def = |item: ModuleDef| {
-        if !targets.contains(&item) {
-            targets.push(item);
-        }
-    };
+    match def {
+        Definition::Local(it) => {
+            let mut targets: Vec<ModuleDef> = Vec::new();
+            let mut push_new_def = |item: ModuleDef| {
+                if !targets.contains(&item) {
+                    targets.push(item);
+                }
+            };
 
-    if let Definition::TypeParam(it) = def {
-        it.trait_bounds(db).into_iter().for_each(|it| push_new_def(it.into()));
-    } else {
-        let ty = match def {
-            Definition::Local(it) => it.ty(db),
-            Definition::ConstParam(it) => it.ty(db),
-            _ => return None,
-        };
-
-        ty.walk(db, |t| {
-            if let Some(adt) = t.as_adt() {
-                push_new_def(adt.into());
-            } else if let Some(trait_) = t.as_dyn_trait() {
-                push_new_def(trait_.into());
-            } else if let Some(traits) = t.as_impl_traits(db) {
-                traits.into_iter().for_each(|it| push_new_def(it.into()));
-            } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
-                push_new_def(trait_.into());
-            }
-        });
+            it.ty(db).walk(db, |t| {
+                if let Some(adt) = t.as_adt() {
+                    push_new_def(adt.into());
+                } else if let Some(trait_) = t.as_dyn_trait() {
+                    push_new_def(trait_.into());
+                } else if let Some(traits) = t.as_impl_traits(db) {
+                    traits.into_iter().for_each(|it| push_new_def(it.into()));
+                } else if let Some(trait_) = t.as_associated_type_parent_trait(db) {
+                    push_new_def(trait_.into());
+                }
+            });
+
+            let targets = targets
+                .into_iter()
+                .filter_map(|it| {
+                    Some(HoverGotoTypeData {
+                        mod_path: render_path(
+                            db,
+                            it.module(db)?,
+                            it.name(db).map(|name| name.to_string()),
+                        ),
+                        nav: it.try_to_nav(db)?,
+                    })
+                })
+                .collect();
+
+            Some(HoverAction::GoToType(targets))
+        }
+        _ => None,
     }
-
-    let targets = targets
-        .into_iter()
-        .filter_map(|it| {
-            Some(HoverGotoTypeData {
-                mod_path: render_path(db, it.module(db)?, it.name(db).map(|name| name.to_string())),
-                nav: it.try_to_nav(db)?,
-            })
-        })
-        .collect();
-
-    Some(HoverAction::GoToType(targets))
 }
 
 fn hover_markup(
@@ -374,8 +370,10 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
         }
         Definition::Label(it) => Some(Markup::fenced_block(&it.name(db))),
         Definition::LifetimeParam(it) => Some(Markup::fenced_block(&it.name(db))),
-        Definition::TypeParam(type_param) => Some(Markup::fenced_block(&type_param.display(db))),
-        Definition::ConstParam(it) => from_def_source(db, it, None),
+        Definition::TypeParam(_) | Definition::ConstParam(_) => {
+            // FIXME: Hover for generic param
+            None
+        }
     };
 
     fn from_def_source<A, D>(db: &RootDatabase, def: D, mod_path: Option<String>) -> Option<Markup>
@@ -1395,7 +1393,7 @@ fn bar() { fo<|>o(); }
             r"unsafe trait foo<|>() {}",
             expect![[r#"
                 [
-                    Implementation(
+                    Implementaion(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2107,7 +2105,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
             r#"trait foo<|>() {}"#,
             expect![[r#"
                 [
-                    Implementation(
+                    Implementaion(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2126,7 +2124,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
             r"struct foo<|>() {}",
             expect![[r#"
                 [
-                    Implementation(
+                    Implementaion(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2145,7 +2143,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
             r#"union foo<|>() {}"#,
             expect![[r#"
                 [
-                    Implementation(
+                    Implementaion(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2164,7 +2162,7 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
             r"enum foo<|>() { A, B }",
             expect![[r#"
                 [
-                    Implementation(
+                    Implementaion(
                         FilePosition {
                             file_id: FileId(
                                 0,
@@ -2177,25 +2175,6 @@ fn foo() { let bar = Bar; bar.fo<|>o(); }
         );
     }
 
-    #[test]
-    fn test_hover_self_has_impl_action() {
-        check_actions(
-            r#"struct foo where Self<|>:;"#,
-            expect![[r#"
-                [
-                    Implementation(
-                        FilePosition {
-                            file_id: FileId(
-                                0,
-                            ),
-                            offset: 7,
-                        },
-                    ),
-                ]
-            "#]],
-        );
-    }
-
     #[test]
     fn test_hover_test_has_action() {
         check_actions(
@@ -3084,71 +3063,6 @@ fn main() { let s<|>t = test().get(); }
         );
     }
 
-    #[test]
-    fn test_hover_const_param_has_goto_type_action() {
-        check_actions(
-            r#"
-struct Bar;
-struct Foo<const BAR: Bar>;
-
-impl<const BAR: Bar> Foo<BAR<|>> {}
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Bar",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..11,
-                                    focus_range: 7..10,
-                                    name: "Bar",
-                                    kind: Struct,
-                                    description: "struct Bar",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_hover_type_param_has_goto_type_action() {
-        check_actions(
-            r#"
-trait Foo {}
-
-fn foo<T: Foo>(t: T<|>){}
-"#,
-            expect![[r#"
-                [
-                    GoToType(
-                        [
-                            HoverGotoTypeData {
-                                mod_path: "test::Foo",
-                                nav: NavigationTarget {
-                                    file_id: FileId(
-                                        0,
-                                    ),
-                                    full_range: 0..12,
-                                    focus_range: 6..9,
-                                    name: "Foo",
-                                    kind: Trait,
-                                    description: "trait Foo",
-                                },
-                            },
-                        ],
-                    ),
-                ]
-            "#]],
-        );
-    }
-
     #[test]
     fn hover_displays_normalized_crate_names() {
         check(
@@ -3343,68 +3257,4 @@ fn foo() {
             "#]],
         );
     }
-
-    #[test]
-    fn hover_type_param() {
-        check(
-            r#"
-struct Foo<T>(T);
-trait Copy {}
-trait Clone {}
-trait Sized {}
-impl<T: Copy + Clone> Foo<T<|>> where T: Sized {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T: Copy + Clone + Sized
-                ```
-            "#]],
-        );
-        check(
-            r#"
-struct Foo<T>(T);
-impl<T> Foo<T<|>> {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T
-                ```
-                "#]],
-        );
-        // lifetimes aren't being substituted yet
-        check(
-            r#"
-struct Foo<T>(T);
-impl<T: 'static> Foo<T<|>> {}
-"#,
-            expect![[r#"
-                *T*
-
-                ```rust
-                T: {error}
-                ```
-                "#]],
-        );
-    }
-
-    #[test]
-    fn hover_const_param() {
-        check(
-            r#"
-struct Foo<const LEN: usize>;
-impl<const LEN: usize> Foo<LEN<|>> {}
-"#,
-            expect![[r#"
-                *LEN*
-
-                ```rust
-                const LEN: usize
-                ```
-            "#]],
-        );
-    }
 }
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index fdc8844cef..ab5f87c487 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -309,7 +309,7 @@ impl<'a> TtIter<'a> {
             }
         }
 
-        let buffer = TokenBuffer::from_tokens(&self.inner.as_slice());
+        let buffer = TokenBuffer::new(&self.inner.as_slice());
         let mut src = SubtreeTokenSource::new(&buffer);
         let mut sink = OffsetTokenSink { cursor: buffer.begin(), error: false };
 
@@ -336,11 +336,11 @@ impl<'a> TtIter<'a> {
             err = Some(err!("no tokens consumed"));
         }
         let res = match res.len() {
-            1 => Some(res[0].cloned()),
+            1 => Some(res[0].clone()),
             0 => None,
             _ => Some(tt::TokenTree::Subtree(tt::Subtree {
                 delimiter: None,
-                token_trees: res.into_iter().map(|it| it.cloned()).collect(),
+                token_trees: res.into_iter().cloned().collect(),
             })),
         };
         ExpandResult { value: res, err }
diff --git a/crates/mbe/src/subtree_source.rs b/crates/mbe/src/subtree_source.rs
index d7433bd353..d10d4b70e3 100644
--- a/crates/mbe/src/subtree_source.rs
+++ b/crates/mbe/src/subtree_source.rs
@@ -1,104 +1,129 @@
 //! FIXME: write short doc here
 
 use parser::{Token, TokenSource};
+use std::cell::{Cell, Ref, RefCell};
 use syntax::{lex_single_syntax_kind, SmolStr, SyntaxKind, SyntaxKind::*, T};
-use tt::buffer::TokenBuffer;
+use tt::buffer::{Cursor, TokenBuffer};
 
 #[derive(Debug, Clone, Eq, PartialEq)]
 struct TtToken {
-    tt: Token,
+    kind: SyntaxKind,
+    is_joint_to_next: bool,
     text: SmolStr,
 }
 
-pub(crate) struct SubtreeTokenSource {
-    cached: Vec<TtToken>,
+pub(crate) struct SubtreeTokenSource<'a> {
+    cached_cursor: Cell<Cursor<'a>>,
+    cached: RefCell<Vec<Option<TtToken>>>,
     curr: (Token, usize),
 }
 
-impl<'a> SubtreeTokenSource {
+impl<'a> SubtreeTokenSource<'a> {
     // Helper function used in test
     #[cfg(test)]
     pub(crate) fn text(&self) -> SmolStr {
-        match self.cached.get(self.curr.1) {
+        match *self.get(self.curr.1) {
             Some(ref tt) => tt.text.clone(),
             _ => SmolStr::new(""),
         }
     }
 }
 
-impl<'a> SubtreeTokenSource {
-    pub(crate) fn new(buffer: &TokenBuffer) -> SubtreeTokenSource {
-        let mut current = buffer.begin();
-        let mut cached = Vec::with_capacity(100);
+impl<'a> SubtreeTokenSource<'a> {
+    pub(crate) fn new(buffer: &'a TokenBuffer) -> SubtreeTokenSource<'a> {
+        let cursor = buffer.begin();
 
-        while !current.eof() {
-            let cursor = current;
-            let tt = cursor.token_tree();
+        let mut res = SubtreeTokenSource {
+            curr: (Token { kind: EOF, is_jointed_to_next: false }, 0),
+            cached_cursor: Cell::new(cursor),
+            cached: RefCell::new(Vec::with_capacity(10)),
+        };
+        res.curr = (res.mk_token(0), 0);
+        res
+    }
 
-            // Check if it is lifetime
-            if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(punct), _)) = tt {
+    fn mk_token(&self, pos: usize) -> Token {
+        match *self.get(pos) {
+            Some(ref tt) => Token { kind: tt.kind, is_jointed_to_next: tt.is_joint_to_next },
+            None => Token { kind: EOF, is_jointed_to_next: false },
+        }
+    }
+
+    fn get(&self, pos: usize) -> Ref<Option<TtToken>> {
+        fn is_lifetime(c: Cursor) -> Option<(Cursor, SmolStr)> {
+            let tkn = c.token_tree();
+
+            if let Some(tt::TokenTree::Leaf(tt::Leaf::Punct(punct))) = tkn {
                 if punct.char == '\'' {
-                    let next = cursor.bump();
-                    if let Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Ident(ident), _)) =
-                        next.token_tree()
-                    {
-                        let text = SmolStr::new("'".to_string() + &ident.text);
-                        cached.push(TtToken {
-                            tt: Token { kind: LIFETIME_IDENT, is_jointed_to_next: false },
-                            text,
-                        });
-                        current = next.bump();
-                        continue;
+                    let next = c.bump();
+                    if let Some(tt::TokenTree::Leaf(tt::Leaf::Ident(ident))) = next.token_tree() {
+                        let res_cursor = next.bump();
+                        let text = SmolStr::new("'".to_string() + &ident.to_string());
+
+                        return Some((res_cursor, text));
                     } else {
                         panic!("Next token must be ident : {:#?}", next.token_tree());
                     }
                 }
             }
 
-            current = match tt {
-                Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
-                    cached.push(convert_leaf(&leaf));
-                    cursor.bump()
+            None
+        }
+
+        if pos < self.cached.borrow().len() {
+            return Ref::map(self.cached.borrow(), |c| &c[pos]);
+        }
+
+        {
+            let mut cached = self.cached.borrow_mut();
+            while pos >= cached.len() {
+                let cursor = self.cached_cursor.get();
+                if cursor.eof() {
+                    cached.push(None);
+                    continue;
                 }
-                Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
-                    cached.push(convert_delim(subtree.delimiter_kind(), false));
-                    cursor.subtree().unwrap()
+
+                if let Some((curr, text)) = is_lifetime(cursor) {
+                    cached.push(Some(TtToken {
+                        kind: LIFETIME_IDENT,
+                        is_joint_to_next: false,
+                        text,
+                    }));
+                    self.cached_cursor.set(curr);
+                    continue;
                 }
-                None => {
-                    if let Some(subtree) = cursor.end() {
-                        cached.push(convert_delim(subtree.delimiter_kind(), true));
-                        cursor.bump()
-                    } else {
-                        continue;
+
+                match cursor.token_tree() {
+                    Some(tt::TokenTree::Leaf(leaf)) => {
+                        cached.push(Some(convert_leaf(&leaf)));
+                        self.cached_cursor.set(cursor.bump());
+                    }
+                    Some(tt::TokenTree::Subtree(subtree)) => {
+                        self.cached_cursor.set(cursor.subtree().unwrap());
+                        cached.push(Some(convert_delim(subtree.delimiter_kind(), false)));
+                    }
+                    None => {
+                        if let Some(subtree) = cursor.end() {
+                            cached.push(Some(convert_delim(subtree.delimiter_kind(), true)));
+                            self.cached_cursor.set(cursor.bump());
+                        }
                     }
                 }
-            };
+            }
         }
 
-        let mut res = SubtreeTokenSource {
-            curr: (Token { kind: EOF, is_jointed_to_next: false }, 0),
-            cached,
-        };
-        res.curr = (res.token(0), 0);
-        res
-    }
-
-    fn token(&self, pos: usize) -> Token {
-        match self.cached.get(pos) {
-            Some(it) => it.tt,
-            None => Token { kind: EOF, is_jointed_to_next: false },
-        }
+        Ref::map(self.cached.borrow(), |c| &c[pos])
     }
 }
 
-impl<'a> TokenSource for SubtreeTokenSource {
+impl<'a> TokenSource for SubtreeTokenSource<'a> {
     fn current(&self) -> Token {
         self.curr.0
     }
 
     /// Lookahead n token
     fn lookahead_nth(&self, n: usize) -> Token {
-        self.token(self.curr.1 + n)
+        self.mk_token(self.curr.1 + n)
     }
 
     /// bump cursor to next token
@@ -106,12 +131,13 @@ impl<'a> TokenSource for SubtreeTokenSource {
         if self.current().kind == EOF {
             return;
         }
-        self.curr = (self.token(self.curr.1 + 1), self.curr.1 + 1);
+
+        self.curr = (self.mk_token(self.curr.1 + 1), self.curr.1 + 1);
     }
 
     /// Is the current token a specified keyword?
     fn is_keyword(&self, kw: &str) -> bool {
-        match self.cached.get(self.curr.1) {
+        match *self.get(self.curr.1) {
             Some(ref t) => t.text == *kw,
             _ => false,
         }
@@ -129,7 +155,7 @@ fn convert_delim(d: Option<tt::DelimiterKind>, closing: bool) -> TtToken {
     let idx = closing as usize;
     let kind = kinds[idx];
     let text = if !texts.is_empty() { &texts[idx..texts.len() - (1 - idx)] } else { "" };
-    TtToken { tt: Token { kind, is_jointed_to_next: false }, text: SmolStr::new(text) }
+    TtToken { kind, is_joint_to_next: false, text: SmolStr::new(text) }
 }
 
 fn convert_literal(l: &tt::Literal) -> TtToken {
@@ -143,7 +169,7 @@ fn convert_literal(l: &tt::Literal) -> TtToken {
         })
         .unwrap_or_else(|| panic!("Fail to convert given literal {:#?}", &l));
 
-    TtToken { tt: Token { kind, is_jointed_to_next: false }, text: l.text.clone() }
+    TtToken { kind, is_joint_to_next: false, text: l.text.clone() }
 }
 
 fn convert_ident(ident: &tt::Ident) -> TtToken {
@@ -154,7 +180,7 @@ fn convert_ident(ident: &tt::Ident) -> TtToken {
         _ => SyntaxKind::from_keyword(ident.text.as_str()).unwrap_or(IDENT),
     };
 
-    TtToken { tt: Token { kind, is_jointed_to_next: false }, text: ident.text.clone() }
+    TtToken { kind, is_joint_to_next: false, text: ident.text.clone() }
 }
 
 fn convert_punct(p: tt::Punct) -> TtToken {
@@ -168,7 +194,7 @@ fn convert_punct(p: tt::Punct) -> TtToken {
         let s: &str = p.char.encode_utf8(&mut buf);
         SmolStr::new(s)
     };
-    TtToken { tt: Token { kind, is_jointed_to_next: p.spacing == tt::Spacing::Joint }, text }
+    TtToken { kind, is_joint_to_next: p.spacing == tt::Spacing::Joint, text }
 }
 
 fn convert_leaf(leaf: &tt::Leaf) -> TtToken {
@@ -182,7 +208,6 @@ fn convert_leaf(leaf: &tt::Leaf) -> TtToken {
 #[cfg(test)]
 mod tests {
     use super::{convert_literal, TtToken};
-    use parser::Token;
     use syntax::{SmolStr, SyntaxKind};
 
     #[test]
@@ -193,7 +218,8 @@ mod tests {
                 text: SmolStr::new("-42.0")
             }),
             TtToken {
-                tt: Token { kind: SyntaxKind::FLOAT_NUMBER, is_jointed_to_next: false },
+                kind: SyntaxKind::FLOAT_NUMBER,
+                is_joint_to_next: false,
                 text: SmolStr::new("-42.0")
             }
         );
diff --git a/crates/mbe/src/syntax_bridge.rs b/crates/mbe/src/syntax_bridge.rs
index 671036e1ca..265c0d63d8 100644
--- a/crates/mbe/src/syntax_bridge.rs
+++ b/crates/mbe/src/syntax_bridge.rs
@@ -70,12 +70,15 @@ pub fn token_tree_to_syntax_node(
     tt: &tt::Subtree,
     fragment_kind: FragmentKind,
 ) -> Result<(Parse<SyntaxNode>, TokenMap), ExpandError> {
-    let buffer = match tt {
-        tt::Subtree { delimiter: None, token_trees } => {
-            TokenBuffer::from_tokens(token_trees.as_slice())
+    let tmp;
+    let tokens = match tt {
+        tt::Subtree { delimiter: None, token_trees } => token_trees.as_slice(),
+        _ => {
+            tmp = [tt.clone().into()];
+            &tmp[..]
         }
-        _ => TokenBuffer::from_subtree(tt),
     };
+    let buffer = TokenBuffer::new(&tokens);
     let mut token_source = SubtreeTokenSource::new(&buffer);
     let mut tree_sink = TtTreeSink::new(buffer.begin());
     parser::parse_fragment(&mut token_source, &mut tree_sink, fragment_kind);
@@ -411,7 +414,7 @@ trait TokenConvertor {
     fn id_alloc(&mut self) -> &mut TokenIdAlloc;
 }
 
-impl<'a> SrcToken for (&'a RawToken, &'a str) {
+impl<'a> SrcToken for (RawToken, &'a str) {
     fn kind(&self) -> SyntaxKind {
         self.0.kind
     }
@@ -428,7 +431,7 @@ impl<'a> SrcToken for (&'a RawToken, &'a str) {
 impl RawConvertor<'_> {}
 
 impl<'a> TokenConvertor for RawConvertor<'a> {
-    type Token = (&'a RawToken, &'a str);
+    type Token = (RawToken, &'a str);
 
     fn convert_doc_comment(&self, token: &Self::Token) -> Option<Vec<tt::TokenTree>> {
         convert_doc_comment(&doc_comment(token.1))
@@ -439,11 +442,11 @@ impl<'a> TokenConvertor for RawConvertor<'a> {
         let range = TextRange::at(self.offset, token.len);
         self.offset += token.len;
 
-        Some(((token, &self.text[range]), range))
+        Some(((*token, &self.text[range]), range))
     }
 
     fn peek(&self) -> Option<Self::Token> {
-        let token = self.inner.as_slice().get(0);
+        let token = self.inner.as_slice().get(0).cloned();
 
         token.map(|it| {
             let range = TextRange::at(self.offset, it.len);
@@ -598,16 +601,17 @@ impl<'a> TtTreeSink<'a> {
     }
 }
 
-fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> &'static str {
+fn delim_to_str(d: Option<tt::DelimiterKind>, closing: bool) -> SmolStr {
     let texts = match d {
         Some(tt::DelimiterKind::Parenthesis) => "()",
         Some(tt::DelimiterKind::Brace) => "{}",
         Some(tt::DelimiterKind::Bracket) => "[]",
-        None => return "",
+        None => return "".into(),
     };
 
     let idx = closing as usize;
-    &texts[idx..texts.len() - (1 - idx)]
+    let text = &texts[idx..texts.len() - (1 - idx)];
+    text.into()
 }
 
 impl<'a> TreeSink for TtTreeSink<'a> {
@@ -622,32 +626,29 @@ impl<'a> TreeSink for TtTreeSink<'a> {
 
         let mut last = self.cursor;
         for _ in 0..n_tokens {
-            let tmp_str: SmolStr;
             if self.cursor.eof() {
                 break;
             }
             last = self.cursor;
-            let text: &str = match self.cursor.token_tree() {
-                Some(tt::buffer::TokenTreeRef::Leaf(leaf, _)) => {
+            let text: SmolStr = match self.cursor.token_tree() {
+                Some(tt::TokenTree::Leaf(leaf)) => {
                     // Mark the range if needed
                     let (text, id) = match leaf {
-                        tt::Leaf::Ident(ident) => (&ident.text, ident.id),
+                        tt::Leaf::Ident(ident) => (ident.text.clone(), ident.id),
                         tt::Leaf::Punct(punct) => {
                             assert!(punct.char.is_ascii());
                             let char = &(punct.char as u8);
-                            tmp_str = SmolStr::new_inline(
-                                std::str::from_utf8(std::slice::from_ref(char)).unwrap(),
-                            );
-                            (&tmp_str, punct.id)
+                            let text = std::str::from_utf8(std::slice::from_ref(char)).unwrap();
+                            (SmolStr::new_inline(text), punct.id)
                         }
-                        tt::Leaf::Literal(lit) => (&lit.text, lit.id),
+                        tt::Leaf::Literal(lit) => (lit.text.clone(), lit.id),
                     };
                     let range = TextRange::at(self.text_pos, TextSize::of(text.as_str()));
                     self.token_map.insert(id, range);
                     self.cursor = self.cursor.bump();
                     text
                 }
-                Some(tt::buffer::TokenTreeRef::Subtree(subtree, _)) => {
+                Some(tt::TokenTree::Subtree(subtree)) => {
                     self.cursor = self.cursor.subtree().unwrap();
                     if let Some(id) = subtree.delimiter.map(|it| it.id) {
                         self.open_delims.insert(id, self.text_pos);
@@ -671,7 +672,7 @@ impl<'a> TreeSink for TtTreeSink<'a> {
                 }
             };
             self.buf += &text;
-            self.text_pos += TextSize::of(text);
+            self.text_pos += TextSize::of(text.as_str());
         }
 
         let text = SmolStr::new(self.buf.as_str());
@@ -681,8 +682,8 @@ impl<'a> TreeSink for TtTreeSink<'a> {
         // Add whitespace between adjoint puncts
         let next = last.bump();
         if let (
-            Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(curr), _)),
-            Some(tt::buffer::TokenTreeRef::Leaf(tt::Leaf::Punct(_), _)),
+            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(curr))),
+            Some(tt::TokenTree::Leaf(tt::Leaf::Punct(_))),
         ) = (last.token_tree(), next.token_tree())
         {
             // Note: We always assume the semi-colon would be the last token in
@@ -741,7 +742,7 @@ mod tests {
         )
         .expand_tt("literals!(foo);");
         let tts = &[expansion.into()];
-        let buffer = tt::buffer::TokenBuffer::from_tokens(tts);
+        let buffer = tt::buffer::TokenBuffer::new(tts);
         let mut tt_src = SubtreeTokenSource::new(&buffer);
         let mut tokens = vec![];
         while tt_src.current().kind != EOF {
diff --git a/crates/parser/src/grammar.rs b/crates/parser/src/grammar.rs
index bb9ffea8be..63cc900272 100644
--- a/crates/parser/src/grammar.rs
+++ b/crates/parser/src/grammar.rs
@@ -66,10 +66,6 @@ pub(crate) mod fragments {
         expressions::stmt(p, expressions::StmtWithSemi::No)
     }
 
-    pub(crate) fn stmt_optional_semi(p: &mut Parser) {
-        expressions::stmt(p, expressions::StmtWithSemi::Optional)
-    }
-
     pub(crate) fn opt_visibility(p: &mut Parser) {
         let _ = super::opt_visibility(p);
     }
diff --git a/crates/parser/src/lib.rs b/crates/parser/src/lib.rs
index 9dfe63028c..811e740f98 100644
--- a/crates/parser/src/lib.rs
+++ b/crates/parser/src/lib.rs
@@ -88,7 +88,6 @@ pub enum FragmentKind {
     Path,
     Expr,
     Statement,
-    StatementOptionalSemi,
     Type,
     Pattern,
     Item,
@@ -119,7 +118,6 @@ pub fn parse_fragment(
         FragmentKind::Visibility => grammar::fragments::opt_visibility,
         FragmentKind::MetaItem => grammar::fragments::meta_item,
         FragmentKind::Statement => grammar::fragments::stmt,
-        FragmentKind::StatementOptionalSemi => grammar::fragments::stmt_optional_semi,
         FragmentKind::Items => grammar::fragments::macro_items,
         FragmentKind::Statements => grammar::fragments::macro_stmts,
         FragmentKind::Attr => grammar::fragments::attr,
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index c21ca044ae..dd486070b9 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -1648,7 +1648,7 @@ fn prepare_hover_actions(
     actions
         .iter()
         .filter_map(|it| match it {
-            HoverAction::Implementation(position) => show_impl_command_link(snap, position),
+            HoverAction::Implementaion(position) => show_impl_command_link(snap, position),
             HoverAction::Runnable(r) => runnable_action_links(snap, file_id, r.clone()),
             HoverAction::GoToType(targets) => goto_type_action_links(snap, targets),
         })
diff --git a/crates/ssr/src/parsing.rs b/crates/ssr/src/parsing.rs
index 3d5e4feb7d..f3b084bafe 100644
--- a/crates/ssr/src/parsing.rs
+++ b/crates/ssr/src/parsing.rs
@@ -73,18 +73,11 @@ impl ParsedRule {
             placeholders_by_stand_in: pattern.placeholders_by_stand_in(),
             rules: Vec::new(),
         };
-
-        let raw_template_stmt = raw_template.map(ast::Stmt::parse);
-        if let raw_template_expr @ Some(Ok(_)) = raw_template.map(ast::Expr::parse) {
-            builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_expr);
-        } else {
-            builder.try_add(ast::Expr::parse(&raw_pattern), raw_template_stmt.clone());
-        }
+        builder.try_add(ast::Expr::parse(&raw_pattern), raw_template.map(ast::Expr::parse));
         builder.try_add(ast::Type::parse(&raw_pattern), raw_template.map(ast::Type::parse));
         builder.try_add(ast::Item::parse(&raw_pattern), raw_template.map(ast::Item::parse));
         builder.try_add(ast::Path::parse(&raw_pattern), raw_template.map(ast::Path::parse));
         builder.try_add(ast::Pat::parse(&raw_pattern), raw_template.map(ast::Pat::parse));
-        builder.try_add(ast::Stmt::parse(&raw_pattern), raw_template_stmt);
         builder.build()
     }
 }
@@ -95,11 +88,7 @@ struct RuleBuilder {
 }
 
 impl RuleBuilder {
-    fn try_add<T: AstNode, T2: AstNode>(
-        &mut self,
-        pattern: Result<T, ()>,
-        template: Option<Result<T2, ()>>,
-    ) {
+    fn try_add<T: AstNode>(&mut self, pattern: Result<T, ()>, template: Option<Result<T, ()>>) {
         match (pattern, template) {
             (Ok(pattern), Some(Ok(template))) => self.rules.push(ParsedRule {
                 placeholders_by_stand_in: self.placeholders_by_stand_in.clone(),
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index cfeaed9e67..1810779449 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -13,7 +13,7 @@ doctest = false
 [dependencies]
 itertools = "0.10.0"
 rowan = "0.10.0"
-rustc_lexer = { version = "697.0.0", package = "rustc-ap-rustc_lexer" }
+rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
 arrayvec = "0.5.1"
 once_cell = "1.3.1"
diff --git a/crates/syntax/src/lib.rs b/crates/syntax/src/lib.rs
index da151e3289..4d272f367a 100644
--- a/crates/syntax/src/lib.rs
+++ b/crates/syntax/src/lib.rs
@@ -212,13 +212,6 @@ impl ast::Attr {
     }
 }
 
-impl ast::Stmt {
-    /// Returns `text`, parsed as statement, but only if it has no errors.
-    pub fn parse(text: &str) -> Result<Self, ()> {
-        parsing::parse_text_fragment(text, parser::FragmentKind::StatementOptionalSemi)
-    }
-}
-
 /// Matches a `SyntaxNode` against an `ast` type.
 ///
 /// # Example:
diff --git a/crates/tt/src/buffer.rs b/crates/tt/src/buffer.rs
index 3606c887dc..02c771f70f 100644
--- a/crates/tt/src/buffer.rs
+++ b/crates/tt/src/buffer.rs
@@ -1,6 +1,6 @@
 //! FIXME: write short doc here
 
-use crate::{Leaf, Subtree, TokenTree};
+use crate::{Subtree, TokenTree};
 
 #[derive(Copy, Clone, Debug, Eq, PartialEq)]
 struct EntryId(usize);
@@ -13,7 +13,7 @@ struct EntryPtr(EntryId, usize);
 #[derive(Debug)]
 enum Entry<'t> {
     // Mimicking types from proc-macro.
-    Subtree(Option<&'t TokenTree>, &'t Subtree, EntryId),
+    Subtree(&'t TokenTree, EntryId),
     Leaf(&'t TokenTree),
     // End entries contain a pointer to the entry from the containing
     // token tree, or None if this is the outermost level.
@@ -27,64 +27,37 @@ pub struct TokenBuffer<'t> {
     buffers: Vec<Box<[Entry<'t>]>>,
 }
 
-trait TokenList<'a> {
-    fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>);
-}
+impl<'t> TokenBuffer<'t> {
+    pub fn new(tokens: &'t [TokenTree]) -> TokenBuffer<'t> {
+        let mut buffers = vec![];
+
+        let idx = TokenBuffer::new_inner(tokens, &mut buffers, None);
+        assert_eq!(idx, 0);
 
-impl<'a> TokenList<'a> for &'a [TokenTree] {
-    fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) {
+        TokenBuffer { buffers }
+    }
+
+    fn new_inner(
+        tokens: &'t [TokenTree],
+        buffers: &mut Vec<Box<[Entry<'t>]>>,
+        next: Option<EntryPtr>,
+    ) -> usize {
         // Must contain everything in tokens and then the Entry::End
-        let start_capacity = self.len() + 1;
+        let start_capacity = tokens.len() + 1;
         let mut entries = Vec::with_capacity(start_capacity);
         let mut children = vec![];
-        for (idx, tt) in self.iter().enumerate() {
+
+        for (idx, tt) in tokens.iter().enumerate() {
             match tt {
                 TokenTree::Leaf(_) => {
                     entries.push(Entry::Leaf(tt));
                 }
                 TokenTree::Subtree(subtree) => {
                     entries.push(Entry::End(None));
-                    children.push((idx, (subtree, Some(tt))));
+                    children.push((idx, (subtree, tt)));
                 }
             }
         }
-        (children, entries)
-    }
-}
-
-impl<'a> TokenList<'a> for &'a Subtree {
-    fn entries(&self) -> (Vec<(usize, (&'a Subtree, Option<&'a TokenTree>))>, Vec<Entry<'a>>) {
-        // Must contain everything in tokens and then the Entry::End
-        let mut entries = vec![];
-        let mut children = vec![];
-        entries.push(Entry::End(None));
-        children.push((0usize, (*self, None)));
-        (children, entries)
-    }
-}
-
-impl<'t> TokenBuffer<'t> {
-    pub fn from_tokens(tokens: &'t [TokenTree]) -> TokenBuffer<'t> {
-        Self::new(tokens)
-    }
-
-    pub fn from_subtree(subtree: &'t Subtree) -> TokenBuffer<'t> {
-        Self::new(subtree)
-    }
-
-    fn new<T: TokenList<'t>>(tokens: T) -> TokenBuffer<'t> {
-        let mut buffers = vec![];
-        let idx = TokenBuffer::new_inner(tokens, &mut buffers, None);
-        assert_eq!(idx, 0);
-        TokenBuffer { buffers }
-    }
-
-    fn new_inner<T: TokenList<'t>>(
-        tokens: T,
-        buffers: &mut Vec<Box<[Entry<'t>]>>,
-        next: Option<EntryPtr>,
-    ) -> usize {
-        let (children, mut entries) = tokens.entries();
 
         entries.push(Entry::End(next));
         let res = buffers.len();
@@ -92,11 +65,11 @@ impl<'t> TokenBuffer<'t> {
 
         for (child_idx, (subtree, tt)) in children {
             let idx = TokenBuffer::new_inner(
-                subtree.token_trees.as_slice(),
+                &subtree.token_trees,
                 buffers,
                 Some(EntryPtr(EntryId(res), child_idx + 1)),
             );
-            buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, subtree, EntryId(idx));
+            buffers[res].as_mut()[child_idx] = Entry::Subtree(tt, EntryId(idx));
         }
 
         res
@@ -114,24 +87,6 @@ impl<'t> TokenBuffer<'t> {
     }
 }
 
-#[derive(Debug)]
-pub enum TokenTreeRef<'a> {
-    Subtree(&'a Subtree, Option<&'a TokenTree>),
-    Leaf(&'a Leaf, &'a TokenTree),
-}
-
-impl<'a> TokenTreeRef<'a> {
-    pub fn cloned(&self) -> TokenTree {
-        match &self {
-            TokenTreeRef::Subtree(subtree, tt) => match tt {
-                Some(it) => (*it).clone(),
-                None => (*subtree).clone().into(),
-            },
-            TokenTreeRef::Leaf(_, tt) => (*tt).clone(),
-        }
-    }
-}
-
 /// A safe version of `Cursor` from `syn` crate https://github.com/dtolnay/syn/blob/6533607f91686545cb034d2838beea338d9d0742/src/buffer.rs#L125
 #[derive(Copy, Clone, Debug)]
 pub struct Cursor<'a> {
@@ -159,11 +114,12 @@ impl<'a> Cursor<'a> {
         match self.entry() {
             Some(Entry::End(Some(ptr))) => {
                 let idx = ptr.1;
-                if let Some(Entry::Subtree(_, subtree, _)) =
+                if let Some(Entry::Subtree(TokenTree::Subtree(subtree), _)) =
                     self.buffer.entry(&EntryPtr(ptr.0, idx - 1))
                 {
                     return Some(subtree);
                 }
+
                 None
             }
             _ => None,
@@ -178,7 +134,7 @@ impl<'a> Cursor<'a> {
     /// a cursor into that subtree
     pub fn subtree(self) -> Option<Cursor<'a>> {
         match self.entry() {
-            Some(Entry::Subtree(_, _, entry_id)) => {
+            Some(Entry::Subtree(_, entry_id)) => {
                 Some(Cursor::create(self.buffer, EntryPtr(*entry_id, 0)))
             }
             _ => None,
@@ -186,13 +142,10 @@ impl<'a> Cursor<'a> {
     }
 
     /// If the cursor is pointing at a `TokenTree`, returns it
-    pub fn token_tree(self) -> Option<TokenTreeRef<'a>> {
+    pub fn token_tree(self) -> Option<&'a TokenTree> {
         match self.entry() {
-            Some(Entry::Leaf(tt)) => match tt {
-                TokenTree::Leaf(leaf) => Some(TokenTreeRef::Leaf(leaf, *tt)),
-                TokenTree::Subtree(subtree) => Some(TokenTreeRef::Subtree(subtree, Some(tt))),
-            },
-            Some(Entry::Subtree(tt, subtree, _)) => Some(TokenTreeRef::Subtree(subtree, *tt)),
+            Some(Entry::Leaf(tt)) => Some(tt),
+            Some(Entry::Subtree(tt, _)) => Some(tt),
             Some(Entry::End(_)) => None,
             None => None,
         }
@@ -219,7 +172,7 @@ impl<'a> Cursor<'a> {
     /// a cursor into that subtree
     pub fn bump_subtree(self) -> Cursor<'a> {
         match self.entry() {
-            Some(Entry::Subtree(_, _, _)) => self.subtree().unwrap(),
+            Some(Entry::Subtree(_, _)) => self.subtree().unwrap(),
             _ => self.bump(),
         }
     }
diff --git a/editors/code/package.json b/editors/code/package.json
index 63db870647..3e55a35234 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -280,7 +280,7 @@
                     "default": true,
                     "description": "Whether to ask for permission before downloading any files from the Internet."
                 },
-                "rust-analyzer.server.path": {
+                "rust-analyzer.serverPath": {
                     "type": [
                         "null",
                         "string"
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index ebe4de1ea5..fe9f3b4a87 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -93,9 +93,7 @@ export class Config {
         return this.cfg.get<T>(path)!;
     }
 
-    get serverPath() {
-        return this.get<null | string>("server.path") ?? this.get<null | string>("serverPath");
-    }
+    get serverPath() { return this.get<null | string>("serverPath"); }
     get serverExtraEnv() { return this.get<Env | null>("server.extraEnv") ?? {}; }
     get channel() { return this.get<UpdatesChannel>("updates.channel"); }
     get askBeforeDownload() { return this.get<boolean>("updates.askBeforeDownload"); }
diff --git a/editors/code/src/main.ts b/editors/code/src/main.ts
index 4c132cabee..60907dfd40 100644
--- a/editors/code/src/main.ts
+++ b/editors/code/src/main.ts
@@ -287,15 +287,16 @@ async function getServer(config: Config, state: PersistentState): Promise<string
     };
     if (config.package.releaseTag === null) return "rust-analyzer";
 
-    const platforms: { [key: string]: string } = {
-        "ia32 win32": "x86_64-pc-windows-msvc",
-        "x64 win32": "x86_64-pc-windows-msvc",
-        "x64 linux": "x86_64-unknown-linux-gnu",
-        "x64 darwin": "x86_64-apple-darwin",
-        "arm64 win32": "aarch64-pc-windows-msvc",
-        "arm64 darwin": "aarch64-apple-darwin",
-    };
-    const platform = platforms[`${process.arch} ${process.platform}`];
+    let platform: string | undefined;
+    if ((process.arch === "x64" || process.arch === "ia32") && process.platform === "win32") {
+        platform = "x86_64-pc-windows-msvc";
+    } else if (process.arch === "x64" && process.platform === "linux") {
+        platform = "x86_64-unknown-linux-gnu";
+    } else if (process.arch === "x64" && process.platform === "darwin") {
+        platform = "x86_64-apple-darwin";
+    } else if (process.arch === "arm64" && process.platform === "darwin") {
+        platform = "aarch64-apple-darwin";
+    }
     if (platform === undefined) {
         vscode.window.showErrorMessage(
             "Unfortunately we don't ship binaries for your platform yet. " +


Test patch:
diff --git a/crates/assists/src/tests/generated.rs b/crates/assists/src/tests/generated.rs
index 85e3c67429..b91a816e89 100644
--- a/crates/assists/src/tests/generated.rs
+++ b/crates/assists/src/tests/generated.rs
@@ -237,6 +237,35 @@ fn qux(bar: Bar, baz: Baz) {}
     )
 }
 
+#[test]
+fn doctest_extract_assignment() {
+    check_doc_test(
+        "extract_assignment",
+        r#####"
+fn main() {
+    let mut foo = 6;
+
+    if true {
+        <|>foo = 5;
+    } else {
+        foo = 4;
+    }
+}
+"#####,
+        r#####"
+fn main() {
+    let mut foo = 6;
+
+    foo = if true {
+        5
+    } else {
+        4
+    };
+}
+"#####,
+    )
+}
+
 #[test]
 fn doctest_extract_module_to_file() {
     check_doc_test(
@@ -737,35 +766,6 @@ fn handle(action: Action) {
     )
 }
 
-#[test]
-fn doctest_pull_assignment_up() {
-    check_doc_test(
-        "pull_assignment_up",
-        r#####"
-fn main() {
-    let mut foo = 6;
-
-    if true {
-        <|>foo = 5;
-    } else {
-        foo = 4;
-    }
-}
-"#####,
-        r#####"
-fn main() {
-    let mut foo = 6;
-
-    foo = if true {
-        5
-    } else {
-        4
-    };
-}
-"#####,
-    )
-}
-
 #[test]
 fn doctest_qualify_path() {
     check_doc_test(
diff --git a/crates/ssr/src/tests.rs b/crates/ssr/src/tests.rs
index db9cb8ca15..63131f6ca5 100644
--- a/crates/ssr/src/tests.rs
+++ b/crates/ssr/src/tests.rs
@@ -159,97 +159,6 @@ fn assert_match_failure_reason(pattern: &str, code: &str, snippet: &str, expecte
     assert_eq!(reasons, vec![expected_reason]);
 }
 
-#[test]
-fn ssr_let_stmt_in_macro_match() {
-    assert_matches(
-        "let a = 0",
-        r#"
-            macro_rules! m1 { ($a:stmt) => {$a}; }
-            fn f() {m1!{ let a = 0 };}"#,
-        // FIXME: Whitespace is not part of the matched block
-        &["leta=0"],
-    );
-}
-
-#[test]
-fn ssr_let_stmt_in_fn_match() {
-    assert_matches("let $a = 10;", "fn main() { let x = 10; x }", &["let x = 10;"]);
-    assert_matches("let $a = $b;", "fn main() { let x = 10; x }", &["let x = 10;"]);
-}
-
-#[test]
-fn ssr_block_expr_match() {
-    assert_matches("{ let $a = $b; }", "fn main() { let x = 10; }", &["{ let x = 10; }"]);
-    assert_matches("{ let $a = $b; $c }", "fn main() { let x = 10; x }", &["{ let x = 10; x }"]);
-}
-
-#[test]
-fn ssr_let_stmt_replace() {
-    // Pattern and template with trailing semicolon
-    assert_ssr_transform(
-        "let $a = $b; ==>> let $a = 11;",
-        "fn main() { let x = 10; x }",
-        expect![["fn main() { let x = 11; x }"]],
-    );
-}
-
-#[test]
-fn ssr_let_stmt_replace_expr() {
-    // Trailing semicolon should be dropped from the new expression
-    assert_ssr_transform(
-        "let $a = $b; ==>> $b",
-        "fn main() { let x = 10; }",
-        expect![["fn main() { 10 }"]],
-    );
-}
-
-#[test]
-fn ssr_blockexpr_replace_stmt_with_stmt() {
-    assert_ssr_transform(
-        "if $a() {$b;} ==>> $b;",
-        "{
-    if foo() {
-        bar();
-    }
-    Ok(())
-}",
-        expect![[r#"{
-    bar();
-    Ok(())
-}"#]],
-    );
-}
-
-#[test]
-fn ssr_blockexpr_match_trailing_expr() {
-    assert_matches(
-        "if $a() {$b;}",
-        "{
-    if foo() {
-        bar();
-    }
-}",
-        &["if foo() {
-        bar();
-    }"],
-    );
-}
-
-#[test]
-fn ssr_blockexpr_replace_trailing_expr_with_stmt() {
-    assert_ssr_transform(
-        "if $a() {$b;} ==>> $b;",
-        "{
-    if foo() {
-        bar();
-    }
-}",
-        expect![["{
-    bar();
-}"]],
-    );
-}
-
 #[test]
 fn ssr_function_to_method() {
     assert_ssr_transform(
diff --git a/crates/syntax/src/tests.rs b/crates/syntax/src/tests.rs
index 9d3433c9db..8c217dfe01 100644
--- a/crates/syntax/src/tests.rs
+++ b/crates/syntax/src/tests.rs
@@ -102,15 +102,6 @@ fn type_parser_tests() {
     );
 }
 
-#[test]
-fn stmt_parser_tests() {
-    fragment_parser_dir_test(
-        &["parser/fragments/stmt/ok"],
-        &["parser/fragments/stmt/err"],
-        crate::ast::Stmt::parse,
-    );
-}
-
 #[test]
 fn parser_fuzz_tests() {
     for (_, text) in collect_rust_files(&test_data_dir(), &["parser/fuzz-failures"]) {
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast
deleted file mode 100644
index 5df7507e2d..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rast
+++ /dev/null
@@ -1,1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs
deleted file mode 100644
index 988df07059..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_attr.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-#[foo]
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast
deleted file mode 100644
index 5df7507e2d..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rast
+++ /dev/null
@@ -1,1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs
deleted file mode 100644
index 7e3b2fd493..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_multiple_stmts.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-a(); b(); c()
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast
deleted file mode 100644
index 5df7507e2d..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rast
+++ /dev/null
@@ -1,1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs
deleted file mode 100644
index 2d06f37663..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_open_parenthesis.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-(
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast
deleted file mode 100644
index 5df7507e2d..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rast
+++ /dev/null
@@ -1,1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs
deleted file mode 100644
index 092bc2b041..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_semicolon.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-;
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast
deleted file mode 100644
index 5df7507e2d..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rast
+++ /dev/null
@@ -1,1 +0,0 @@
-ERROR
diff --git a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs
deleted file mode 100644
index ca49acb079..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/err/0000_unterminated_expr.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-1 +
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast
deleted file mode 100644
index 274fdf16de..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rast
+++ /dev/null
@@ -1,9 +0,0 @@
-EXPR_STMT@0..5
-  BIN_EXPR@0..5
-    LITERAL@0..1
-      INT_NUMBER@0..1 "1"
-    WHITESPACE@1..2 " "
-    PLUS@2..3 "+"
-    WHITESPACE@3..4 " "
-    LITERAL@4..5
-      INT_NUMBER@4..5 "1"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs
deleted file mode 100644
index 8d2f0971e2..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-1 + 1
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast
deleted file mode 100644
index 6c946091f3..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rast
+++ /dev/null
@@ -1,69 +0,0 @@
-EXPR_STMT@0..55
-  BLOCK_EXPR@0..55
-    L_CURLY@0..1 "{"
-    WHITESPACE@1..6 "\n    "
-    LET_STMT@6..20
-      LET_KW@6..9 "let"
-      WHITESPACE@9..10 " "
-      IDENT_PAT@10..11
-        NAME@10..11
-          IDENT@10..11 "x"
-      WHITESPACE@11..12 " "
-      EQ@12..13 "="
-      WHITESPACE@13..14 " "
-      CALL_EXPR@14..19
-        PATH_EXPR@14..17
-          PATH@14..17
-            PATH_SEGMENT@14..17
-              NAME_REF@14..17
-                IDENT@14..17 "foo"
-        ARG_LIST@17..19
-          L_PAREN@17..18 "("
-          R_PAREN@18..19 ")"
-      SEMICOLON@19..20 ";"
-    WHITESPACE@20..25 "\n    "
-    LET_STMT@25..39
-      LET_KW@25..28 "let"
-      WHITESPACE@28..29 " "
-      IDENT_PAT@29..30
-        NAME@29..30
-          IDENT@29..30 "y"
-      WHITESPACE@30..31 " "
-      EQ@31..32 "="
-      WHITESPACE@32..33 " "
-      CALL_EXPR@33..38
-        PATH_EXPR@33..36
-          PATH@33..36
-            PATH_SEGMENT@33..36
-              NAME_REF@33..36
-                IDENT@33..36 "bar"
-        ARG_LIST@36..38
-          L_PAREN@36..37 "("
-          R_PAREN@37..38 ")"
-      SEMICOLON@38..39 ";"
-    WHITESPACE@39..44 "\n    "
-    CALL_EXPR@44..53
-      PATH_EXPR@44..46
-        PATH@44..46
-          PATH_SEGMENT@44..46
-            NAME_REF@44..46
-              IDENT@44..46 "Ok"
-      ARG_LIST@46..53
-        L_PAREN@46..47 "("
-        BIN_EXPR@47..52
-          PATH_EXPR@47..48
-            PATH@47..48
-              PATH_SEGMENT@47..48
-                NAME_REF@47..48
-                  IDENT@47..48 "x"
-          WHITESPACE@48..49 " "
-          PLUS@49..50 "+"
-          WHITESPACE@50..51 " "
-          PATH_EXPR@51..52
-            PATH@51..52
-              PATH_SEGMENT@51..52
-                NAME_REF@51..52
-                  IDENT@51..52 "y"
-        R_PAREN@52..53 ")"
-    WHITESPACE@53..54 "\n"
-    R_CURLY@54..55 "}"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs
deleted file mode 100644
index ffa5c1e66e..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_expr_block.rs
+++ /dev/null
@@ -1,5 +0,0 @@
-{
-    let x = foo();
-    let y = bar();
-    Ok(x + y)
-}
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast
deleted file mode 100644
index 8c186da93e..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rast
+++ /dev/null
@@ -1,11 +0,0 @@
-EXPR_STMT@0..6
-  CALL_EXPR@0..5
-    PATH_EXPR@0..3
-      PATH@0..3
-        PATH_SEGMENT@0..3
-          NAME_REF@0..3
-            IDENT@0..3 "foo"
-    ARG_LIST@3..5
-      L_PAREN@3..4 "("
-      R_PAREN@4..5 ")"
-  SEMICOLON@5..6 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs
deleted file mode 100644
index a280f9a5cc..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_fn_call.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-foo();
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast
deleted file mode 100644
index 8ab38da21c..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rast
+++ /dev/null
@@ -1,12 +0,0 @@
-LET_STMT@0..11
-  LET_KW@0..3 "let"
-  WHITESPACE@3..4 " "
-  IDENT_PAT@4..5
-    NAME@4..5
-      IDENT@4..5 "x"
-  WHITESPACE@5..6 " "
-  EQ@6..7 "="
-  WHITESPACE@7..8 " "
-  LITERAL@8..10
-    INT_NUMBER@8..10 "10"
-  SEMICOLON@10..11 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs
deleted file mode 100644
index de8a7f1fc6..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_let_stmt.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-let x = 10;
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast
deleted file mode 100644
index 81d6df29a5..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rast
+++ /dev/null
@@ -1,21 +0,0 @@
-EXPR_STMT@0..18
-  MACRO_CALL@0..17
-    PATH@0..2
-      PATH_SEGMENT@0..2
-        NAME_REF@0..2
-          IDENT@0..2 "m1"
-    BANG@2..3 "!"
-    TOKEN_TREE@3..17
-      L_CURLY@3..4 "{"
-      WHITESPACE@4..5 " "
-      LET_KW@5..8 "let"
-      WHITESPACE@8..9 " "
-      IDENT@9..10 "a"
-      WHITESPACE@10..11 " "
-      EQ@11..12 "="
-      WHITESPACE@12..13 " "
-      INT_NUMBER@13..14 "0"
-      SEMICOLON@14..15 ";"
-      WHITESPACE@15..16 " "
-      R_CURLY@16..17 "}"
-  SEMICOLON@17..18 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs
deleted file mode 100644
index 075f30159b..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_let_stmt.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-m1!{ let a = 0; };
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast
deleted file mode 100644
index 81d6df29a5..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rast
+++ /dev/null
@@ -1,21 +0,0 @@
-EXPR_STMT@0..18
-  MACRO_CALL@0..17
-    PATH@0..2
-      PATH_SEGMENT@0..2
-        NAME_REF@0..2
-          IDENT@0..2 "m1"
-    BANG@2..3 "!"
-    TOKEN_TREE@3..17
-      L_CURLY@3..4 "{"
-      WHITESPACE@4..5 " "
-      LET_KW@5..8 "let"
-      WHITESPACE@8..9 " "
-      IDENT@9..10 "a"
-      WHITESPACE@10..11 " "
-      EQ@11..12 "="
-      WHITESPACE@12..13 " "
-      INT_NUMBER@13..14 "0"
-      SEMICOLON@14..15 ";"
-      WHITESPACE@15..16 " "
-      R_CURLY@16..17 "}"
-  SEMICOLON@17..18 ";"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs
deleted file mode 100644
index 075f30159b..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_macro_unterminated_let_stmt.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-m1!{ let a = 0; };
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast
deleted file mode 100644
index 64c5d29691..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rast
+++ /dev/null
@@ -1,22 +0,0 @@
-STRUCT@0..28
-  STRUCT_KW@0..6 "struct"
-  WHITESPACE@6..7 " "
-  NAME@7..10
-    IDENT@7..10 "Foo"
-  WHITESPACE@10..11 " "
-  RECORD_FIELD_LIST@11..28
-    L_CURLY@11..12 "{"
-    WHITESPACE@12..17 "\n    "
-    RECORD_FIELD@17..25
-      NAME@17..20
-        IDENT@17..20 "bar"
-      COLON@20..21 ":"
-      WHITESPACE@21..22 " "
-      PATH_TYPE@22..25
-        PATH@22..25
-          PATH_SEGMENT@22..25
-            NAME_REF@22..25
-              IDENT@22..25 "u32"
-    COMMA@25..26 ","
-    WHITESPACE@26..27 "\n"
-    R_CURLY@27..28 "}"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs
deleted file mode 100644
index e5473e3ac8..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_struct_item.rs
+++ /dev/null
@@ -1,3 +0,0 @@
-struct Foo {
-    bar: u32,
-}
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast
deleted file mode 100644
index 9089906bce..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rast
+++ /dev/null
@@ -1,10 +0,0 @@
-EXPR_STMT@0..5
-  CALL_EXPR@0..5
-    PATH_EXPR@0..3
-      PATH@0..3
-        PATH_SEGMENT@0..3
-          NAME_REF@0..3
-            IDENT@0..3 "foo"
-    ARG_LIST@3..5
-      L_PAREN@3..4 "("
-      R_PAREN@4..5 ")"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs
deleted file mode 100644
index eb28ef4401..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_fn_call.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-foo()
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast
deleted file mode 100644
index 37663671fa..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rast
+++ /dev/null
@@ -1,11 +0,0 @@
-LET_STMT@0..10
-  LET_KW@0..3 "let"
-  WHITESPACE@3..4 " "
-  IDENT_PAT@4..5
-    NAME@4..5
-      IDENT@4..5 "x"
-  WHITESPACE@5..6 " "
-  EQ@6..7 "="
-  WHITESPACE@7..8 " "
-  LITERAL@8..10
-    INT_NUMBER@8..10 "10"
diff --git a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs b/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs
deleted file mode 100644
index 78364b2a96..0000000000
--- a/crates/syntax/test_data/parser/fragments/stmt/ok/0000_unterminated_let_stmt.rs
+++ /dev/null
@@ -1,1 +0,0 @@
-let x = 10