Repository: rust-analyzer/rust-analyzer
Pull request #7080 (2020-12-29 16:59:16)

Implement ConstParams for HIR
r? @flodiebold 


Patch:
diff --git a/.github/workflows/release.yaml b/.github/workflows/release.yaml
index 889ada401c..7b9fbe6b80 100644
--- a/.github/workflows/release.yaml
+++ b/.github/workflows/release.yaml
@@ -124,10 +124,10 @@ jobs:
     - name: Checkout repository
       uses: actions/checkout@v2
 
-    - name: Install Rust toolchain
+    - name: Install Rust toolchain (beta)
       uses: actions-rs/toolchain@v1
       with:
-        toolchain: stable
+        toolchain: beta
         target: aarch64-apple-darwin
         profile: minimal
         override: true
diff --git a/Cargo.lock b/Cargo.lock
index 1aa0c072d4..fd04ec3c52 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -26,9 +26,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.37"
+version = "1.0.36"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ee67c11feeac938fae061b232e38e0b6d94f97a9df10e6271319325ac4c56a86"
+checksum = "68803225a7b13e47191bab76f2687382b60d259e8cf37f6e1893658b84bb9479"
 
 [[package]]
 name = "anymap"
@@ -53,7 +53,7 @@ dependencies = [
  "either",
  "hir",
  "ide_db",
- "itertools 0.10.0",
+ "itertools",
  "profile",
  "rustc-hash",
  "stdx",
@@ -211,7 +211,7 @@ dependencies = [
  "chalk-derive",
  "chalk-ir",
  "ena",
- "itertools 0.9.0",
+ "itertools",
  "petgraph",
  "rustc-hash",
  "tracing",
@@ -250,7 +250,7 @@ dependencies = [
  "expect-test",
  "hir",
  "ide_db",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "profile",
  "rustc-hash",
@@ -348,12 +348,6 @@ version = "2.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "524cbf6897b527295dff137cec09ecf3a05f4fddffd7dfcd1585403449e74198"
 
-[[package]]
-name = "dissimilar"
-version = "1.0.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fc4b29f4b9bb94bf267d57269fd0706d343a160937108e9619fe380645428abb"
-
 [[package]]
 name = "drop_bomb"
 version = "0.1.5"
@@ -540,7 +534,7 @@ dependencies = [
  "hir_def",
  "hir_expand",
  "hir_ty",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "profile",
  "rustc-hash",
@@ -563,7 +557,7 @@ dependencies = [
  "fst",
  "hir_expand",
  "indexmap",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "mbe",
  "once_cell",
@@ -607,7 +601,7 @@ dependencies = [
  "expect-test",
  "hir_def",
  "hir_expand",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "once_cell",
  "profile",
@@ -643,7 +637,7 @@ dependencies = [
  "hir",
  "ide_db",
  "indexmap",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "oorandom",
  "profile",
@@ -667,7 +661,7 @@ dependencies = [
  "expect-test",
  "fst",
  "hir",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "once_cell",
  "profile",
@@ -747,20 +741,11 @@ dependencies = [
  "either",
 ]
 
-[[package]]
-name = "itertools"
-version = "0.10.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d572918e350e82412fe766d24b15e6682fb2ed2bbe018280caa810397cb319"
-dependencies = [
- "either",
-]
-
 [[package]]
 name = "itoa"
-version = "0.4.7"
+version = "0.4.6"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd25036021b0de88a0aff6b850051563c6516d0bf53f8638938edbb9de732736"
+checksum = "dc6f3ad7b9d11a0c00842ff8de1b60ee58661048eb8049ed33c73594f359d7e6"
 
 [[package]]
 name = "jod-thread"
@@ -1234,7 +1219,7 @@ dependencies = [
  "base_db",
  "cargo_metadata",
  "cfg",
- "itertools 0.10.0",
+ "itertools",
  "log",
  "paths",
  "proc_macro_api",
@@ -1349,7 +1334,6 @@ dependencies = [
  "anyhow",
  "cfg",
  "crossbeam-channel 0.5.0",
- "dissimilar",
  "env_logger",
  "expect-test",
  "flycheck",
@@ -1358,7 +1342,7 @@ dependencies = [
  "hir_ty",
  "ide",
  "ide_db",
- "itertools 0.10.0",
+ "itertools",
  "jod-thread",
  "log",
  "lsp-server",
@@ -1534,9 +1518,9 @@ dependencies = [
 
 [[package]]
 name = "serde_json"
-version = "1.0.61"
+version = "1.0.60"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4fceb2595057b6891a4ee808f70054bd2d12f0e97f1cbb78689b59f676df325a"
+checksum = "1500e84d27fe482ed1dc791a56eddc2f230046a040fa908c08bda1d9fb615779"
 dependencies = [
  "indexmap",
  "itoa",
@@ -1602,7 +1586,7 @@ dependencies = [
  "expect-test",
  "hir",
  "ide_db",
- "itertools 0.10.0",
+ "itertools",
  "rustc-hash",
  "syntax",
  "test_utils",
@@ -1615,9 +1599,9 @@ version = "0.0.0"
 
 [[package]]
 name = "syn"
-version = "1.0.56"
+version = "1.0.55"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a9802ddde94170d186eeee5005b798d9c159fa970403f1be19976d0cfb939b72"
+checksum = "a571a711dddd09019ccc628e1b17fe87c59b09d513c06c026877aa708334f37a"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1643,7 +1627,7 @@ dependencies = [
  "arrayvec",
  "expect-test",
  "indexmap",
- "itertools 0.10.0",
+ "itertools",
  "once_cell",
  "parser",
  "profile",
diff --git a/crates/assists/Cargo.toml b/crates/assists/Cargo.toml
index ed8ad666f7..3fd8327d6a 100644
--- a/crates/assists/Cargo.toml
+++ b/crates/assists/Cargo.toml
@@ -11,7 +11,7 @@ doctest = false
 
 [dependencies]
 rustc-hash = "1.1.0"
-itertools = "0.10.0"
+itertools = "0.9.0"
 either = "1.6.1"
 
 stdx = { path = "../stdx", version = "0.0.0" }
diff --git a/crates/assists/src/ast_transform.rs b/crates/assists/src/ast_transform.rs
index da94e9987c..4a3ed7783e 100644
--- a/crates/assists/src/ast_transform.rs
+++ b/crates/assists/src/ast_transform.rs
@@ -204,7 +204,8 @@ impl<'a> AstTransform<'a> for QualifyPaths<'a> {
             }
             PathResolution::Local(_)
             | PathResolution::TypeParam(_)
-            | PathResolution::SelfType(_) => None,
+            | PathResolution::SelfType(_)
+            | PathResolution::ConstParam(_) => None,
             PathResolution::Macro(_) => None,
             PathResolution::AssocItem(_) => None,
         }
diff --git a/crates/assists/src/handlers/extract_variable.rs b/crates/assists/src/handlers/extract_variable.rs
index 9957012fe5..d2ae137cdd 100644
--- a/crates/assists/src/handlers/extract_variable.rs
+++ b/crates/assists/src/handlers/extract_variable.rs
@@ -91,7 +91,7 @@ pub(crate) fn extract_variable(acc: &mut Assists, ctx: &AssistContext) -> Option
             // extra newlines in the indent block
             let text = indent.text();
             if text.starts_with('\n') {
-                buf.push('\n');
+                buf.push_str("\n");
                 buf.push_str(text.trim_start_matches('\n'));
             } else {
                 buf.push_str(text);
diff --git a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
index cb7a5c1042..4d6a1956bb 100644
--- a/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
+++ b/crates/assists/src/handlers/replace_derive_with_manual_impl.rs
@@ -62,22 +62,21 @@ pub(crate) fn replace_derive_with_manual_impl(
     let current_module = ctx.sema.scope(annotated_name.syntax()).module()?;
     let current_crate = current_module.krate();
 
-    let found_traits = imports_locator::find_exact_imports(
-        &ctx.sema,
-        current_crate,
-        trait_token.text().to_string(),
-    )
-    .filter_map(|candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
-        either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
-        _ => None,
-    })
-    .flat_map(|trait_| {
-        current_module
-            .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
-            .as_ref()
-            .map(mod_path_to_ast)
-            .zip(Some(trait_))
-    });
+    let found_traits =
+        imports_locator::find_exact_imports(&ctx.sema, current_crate, trait_token.text())
+            .filter_map(
+                |candidate: either::Either<hir::ModuleDef, hir::MacroDef>| match candidate {
+                    either::Either::Left(hir::ModuleDef::Trait(trait_)) => Some(trait_),
+                    _ => None,
+                },
+            )
+            .flat_map(|trait_| {
+                current_module
+                    .find_use_path(ctx.sema.db, hir::ModuleDef::Trait(trait_))
+                    .as_ref()
+                    .map(mod_path_to_ast)
+                    .zip(Some(trait_))
+            });
 
     let mut no_traits_found = true;
     for (trait_path, trait_) in found_traits.inspect(|_| no_traits_found = false) {
diff --git a/crates/assists/src/utils/import_assets.rs b/crates/assists/src/utils/import_assets.rs
index 4ce82c1ba5..ff5c0e78ee 100644
--- a/crates/assists/src/utils/import_assets.rs
+++ b/crates/assists/src/utils/import_assets.rs
@@ -179,24 +179,25 @@ impl ImportAssets {
             }
         };
 
-        let mut res = imports_locator::find_exact_imports(
-            sema,
-            current_crate,
-            self.get_search_query().to_string(),
-        )
-        .filter_map(filter)
-        .filter_map(|candidate| {
-            let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
-            if let Some(prefix_kind) = prefixed {
-                self.module_with_name_to_import.find_use_path_prefixed(db, item, prefix_kind)
-            } else {
-                self.module_with_name_to_import.find_use_path(db, item)
-            }
-            .map(|path| (path, item))
-        })
-        .filter(|(use_path, _)| use_path.len() > 1)
-        .take(20)
-        .collect::<Vec<_>>();
+        let mut res =
+            imports_locator::find_exact_imports(sema, current_crate, &self.get_search_query())
+                .filter_map(filter)
+                .filter_map(|candidate| {
+                    let item: hir::ItemInNs = candidate.either(Into::into, Into::into);
+                    if let Some(prefix_kind) = prefixed {
+                        self.module_with_name_to_import.find_use_path_prefixed(
+                            db,
+                            item,
+                            prefix_kind,
+                        )
+                    } else {
+                        self.module_with_name_to_import.find_use_path(db, item)
+                    }
+                    .map(|path| (path, item))
+                })
+                .filter(|(use_path, _)| use_path.len() > 1)
+                .take(20)
+                .collect::<Vec<_>>();
         res.sort_by_key(|(path, _)| path.clone());
         res
     }
diff --git a/crates/completion/Cargo.toml b/crates/completion/Cargo.toml
index 78e93e78ea..35e169a28c 100644
--- a/crates/completion/Cargo.toml
+++ b/crates/completion/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
 doctest = false
 
 [dependencies]
-itertools = "0.10.0"
+itertools = "0.9.0"
 log = "0.4.8"
 rustc-hash = "1.1.0"
 either = "1.6.1"
diff --git a/crates/completion/src/completions/attribute.rs b/crates/completion/src/completions/attribute.rs
index 8695eed398..19ce2482fd 100644
--- a/crates/completion/src/completions/attribute.rs
+++ b/crates/completion/src/completions/attribute.rs
@@ -234,7 +234,7 @@ fn parse_comma_sep_input(derive_input: ast::TokenTree) -> Result<FxHashSet<Strin
                         current_derive = String::new();
                     }
                 } else {
-                    current_derive.push_str(token.text().trim());
+                    current_derive.push_str(token.to_string().trim());
                 }
             }
 
diff --git a/crates/completion/src/completions/postfix.rs b/crates/completion/src/completions/postfix.rs
index 3883d6d214..d6db82a93b 100644
--- a/crates/completion/src/completions/postfix.rs
+++ b/crates/completion/src/completions/postfix.rs
@@ -502,7 +502,7 @@ fn main() {
     #[test]
     fn postfix_completion_for_format_like_strings() {
         check_edit(
-            "format",
+            "fmt",
             r#"fn main() { "{some_var:?}".<|> }"#,
             r#"fn main() { format!("{:?}", some_var) }"#,
         );
diff --git a/crates/completion/src/completions/postfix/format_like.rs b/crates/completion/src/completions/postfix/format_like.rs
index def4b13fba..88ba86acb6 100644
--- a/crates/completion/src/completions/postfix/format_like.rs
+++ b/crates/completion/src/completions/postfix/format_like.rs
@@ -22,7 +22,7 @@ use syntax::ast::{self, AstToken};
 
 /// Mapping ("postfix completion item" => "macro to use")
 static KINDS: &[(&str, &str)] = &[
-    ("format", "format!"),
+    ("fmt", "format!"),
     ("panic", "panic!"),
     ("println", "println!"),
     ("eprintln", "eprintln!"),
@@ -108,8 +108,7 @@ impl FormatStrParser {
         // "{MyStruct { val_a: 0, val_b: 1 }}".
         let mut inexpr_open_count = 0;
 
-        let mut chars = self.input.chars().peekable();
-        while let Some(chr) = chars.next() {
+        for chr in self.input.chars() {
             match (self.state, chr) {
                 (State::NotExpr, '{') => {
                     self.output.push(chr);
@@ -158,11 +157,6 @@ impl FormatStrParser {
                         inexpr_open_count -= 1;
                     }
                 }
-                (State::Expr, ':') if chars.peek().copied() == Some(':') => {
-                    // path seperator
-                    current_expr.push_str("::");
-                    chars.next();
-                }
                 (State::Expr, ':') => {
                     if inexpr_open_count == 0 {
                         // We're outside of braces, thus assume that it's a specifier, like "{Some(value):?}"
@@ -255,9 +249,6 @@ mod tests {
                 expect![["{:?}; SomeStruct { val_a: 0, val_b: 1 }"]],
             ),
             ("{     2 + 2        }", expect![["{}; 2 + 2"]]),
-            ("{strsim::jaro_winkle(a)}", expect![["{}; strsim::jaro_winkle(a)"]]),
-            ("{foo::bar::baz()}", expect![["{}; foo::bar::baz()"]]),
-            ("{foo::bar():?}", expect![["{:?}; foo::bar()"]]),
         ];
 
         for (input, output) in test_vector {
diff --git a/crates/completion/src/completions/record.rs b/crates/completion/src/completions/record.rs
index e58b9a2744..91bf4a8ad9 100644
--- a/crates/completion/src/completions/record.rs
+++ b/crates/completion/src/completions/record.rs
@@ -20,17 +20,13 @@ pub(crate) fn complete_record(acc: &mut Completions, ctx: &CompletionContext) ->
 
             let missing_fields = ctx.sema.record_literal_missing_fields(record_lit);
             if impl_default_trait && !missing_fields.is_empty() {
-                let completion_text = "..Default::default()";
-                let completion_text = completion_text
-                    .strip_prefix(ctx.token.to_string().as_str())
-                    .unwrap_or(completion_text);
                 acc.add(
                     CompletionItem::new(
                         CompletionKind::Snippet,
                         ctx.source_range(),
                         "..Default::default()",
                     )
-                    .insert_text(completion_text)
+                    .insert_text("..Default::default()")
                     .kind(CompletionItemKind::Field)
                     .build(),
                 );
@@ -52,10 +48,7 @@ mod tests {
     use expect_test::{expect, Expect};
     use ide_db::helpers::FamousDefs;
 
-    use crate::{
-        test_utils::{self, completion_list},
-        CompletionKind,
-    };
+    use crate::{test_utils::completion_list, CompletionKind};
 
     fn check(ra_fixture: &str, expect: Expect) {
         let actual = completion_list(ra_fixture, CompletionKind::Reference);
@@ -70,18 +63,6 @@ mod tests {
         expect.assert_eq(&actual);
     }
 
-    fn check_edit(what: &str, ra_fixture_before: &str, ra_fixture_after: &str) {
-        test_utils::check_edit(
-            what,
-            &format!(
-                "//- /main.rs crate:main deps:core{}\n{}",
-                ra_fixture_before,
-                FamousDefs::FIXTURE,
-            ),
-            &(ra_fixture_after.to_owned() + "\n"),
-        );
-    }
-
     #[test]
     fn test_record_literal_field_default() {
         let test_code = r#"
@@ -120,51 +101,6 @@ fn process(f: S) {
         );
     }
 
-    #[test]
-    fn test_record_literal_field_default_completion() {
-        check_edit(
-            "..Default::default()",
-            r#"
-struct S { foo: u32, bar: usize }
-
-impl core::default::Default for S {
-    fn default() -> Self {
-        S {
-            foo: 0,
-            bar: 0,
-        }
-    }
-}
-
-fn process(f: S) {
-    let other = S {
-        foo: 5,
-        .<|>
-    };
-}
-"#,
-            r#"
-struct S { foo: u32, bar: usize }
-
-impl core::default::Default for S {
-    fn default() -> Self {
-        S {
-            foo: 0,
-            bar: 0,
-        }
-    }
-}
-
-fn process(f: S) {
-    let other = S {
-        foo: 5,
-        ..Default::default()
-    };
-}
-"#,
-        );
-    }
-
     #[test]
     fn test_record_literal_field_without_default() {
         let test_code = r#"
diff --git a/crates/completion/src/completions/unqualified_path.rs b/crates/completion/src/completions/unqualified_path.rs
index 81a6d00e2b..d098497520 100644
--- a/crates/completion/src/completions/unqualified_path.rs
+++ b/crates/completion/src/completions/unqualified_path.rs
@@ -101,9 +101,8 @@ fn complete_enum_variants(acc: &mut Completions, ctx: &CompletionContext, ty: &T
 //
 // .Fuzzy search details
 //
-// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the names only
-// (i.e. in `HashMap` in the `std::collections::HashMap` path).
-// For the same reasons, avoids searching for any imports for inputs with their length less that 2 symbols.
+// To avoid an excessive amount of the results returned, completion input is checked for inclusion in the identifiers only
+// (i.e. in `HashMap` in the `std::collections::HashMap` path), also not in the module indentifiers.
 //
 // .Merge Behavior
 //
@@ -127,20 +126,15 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
     let _p = profile::span("fuzzy_completion");
     let potential_import_name = ctx.token.to_string();
 
-    if potential_import_name.len() < 2 {
-        return None;
-    }
-
     let current_module = ctx.scope.module()?;
     let anchor = ctx.name_ref_syntax.as_ref()?;
     let import_scope = ImportScope::find_insert_use_container(anchor.syntax(), &ctx.sema)?;
 
-    let user_input_lowercased = potential_import_name.to_lowercase();
     let mut all_mod_paths = imports_locator::find_similar_imports(
         &ctx.sema,
         ctx.krate?,
-        Some(40),
-        potential_import_name,
+        Some(100),
+        &potential_import_name,
         true,
     )
     .filter_map(|import_candidate| {
@@ -156,6 +150,7 @@ fn fuzzy_completion(acc: &mut Completions, ctx: &CompletionContext) -> Option<()
     .filter(|(mod_path, _)| mod_path.len() > 1)
     .collect::<Vec<_>>();
 
+    let user_input_lowercased = potential_import_name.to_lowercase();
     all_mod_paths.sort_by_cached_key(|(mod_path, _)| {
         compute_fuzzy_completion_order_key(mod_path, &user_input_lowercased)
     });
diff --git a/crates/completion/src/lib.rs b/crates/completion/src/lib.rs
index c57d05bbeb..8e27bb1532 100644
--- a/crates/completion/src/lib.rs
+++ b/crates/completion/src/lib.rs
@@ -137,7 +137,7 @@ pub fn resolve_completion_edits(
     config: &CompletionConfig,
     position: FilePosition,
     full_import_path: &str,
-    imported_name: String,
+    imported_name: &str,
 ) -> Option<Vec<TextEdit>> {
     let ctx = CompletionContext::new(db, position, config)?;
     let anchor = ctx.name_ref_syntax.as_ref()?;
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index d4ea7327eb..6dc5ad63ba 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -14,7 +14,7 @@ log = "0.4.8"
 rustc-hash = "1.1.0"
 either = "1.5.3"
 arrayvec = "0.5.1"
-itertools = "0.10.0"
+itertools = "0.9.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/hir/src/code_model.rs b/crates/hir/src/code_model.rs
index b7ded34788..97b7a8b5f5 100644
--- a/crates/hir/src/code_model.rs
+++ b/crates/hir/src/code_model.rs
@@ -18,10 +18,10 @@ use hir_def::{
     resolver::{HasResolver, Resolver},
     src::HasSource as _,
     type_ref::{Mutability, TypeRef},
-    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, DefWithBodyId, EnumId,
-    FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId, LocalEnumVariantId, LocalFieldId,
-    LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
-    UnionId,
+    AdtId, AssocContainerId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId,
+    DefWithBodyId, EnumId, FunctionId, GenericDefId, HasModule, ImplId, LifetimeParamId,
+    LocalEnumVariantId, LocalFieldId, LocalModuleId, Lookup, ModuleId, StaticId, StructId, TraitId,
+    TypeAliasId, TypeParamId, UnionId,
 };
 use hir_def::{find_path::PrefixKind, item_scope::ItemInNs, visibility::Visibility};
 use hir_expand::{
@@ -1125,7 +1125,12 @@ impl GenericDef {
                 id: LifetimeParamId { parent: self.into(), local_id },
             })
             .map(GenericParam::LifetimeParam);
-        ty_params.chain(lt_params).collect()
+        let const_params = generics
+            .consts
+            .iter()
+            .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } })
+            .map(GenericParam::ConstParam);
+        ty_params.chain(lt_params).chain(const_params).collect()
     }
 
     pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
@@ -1237,8 +1242,9 @@ impl Label {
 pub enum GenericParam {
     TypeParam(TypeParam),
     LifetimeParam(LifetimeParam),
+    ConstParam(ConstParam),
 }
-impl_from!(TypeParam, LifetimeParam for GenericParam);
+impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub struct TypeParam {
@@ -1300,6 +1306,26 @@ impl LifetimeParam {
     }
 }
 
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct ConstParam {
+    pub(crate) id: ConstParamId,
+}
+
+impl ConstParam {
+    pub fn name(self, db: &dyn HirDatabase) -> Name {
+        let params = db.generic_params(self.id.parent);
+        params.consts[self.id.local_id].name.clone()
+    }
+
+    pub fn module(self, db: &dyn HirDatabase) -> Module {
+        self.id.parent.module(db.upcast()).into()
+    }
+
+    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
+        self.id.parent.into()
+    }
+}
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct Impl {
     pub(crate) id: ImplId,
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index a0792b9a66..2422887e34 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -44,6 +44,7 @@ from_id![
     (hir_def::ImplId, crate::Impl),
     (hir_def::TypeParamId, crate::TypeParam),
     (hir_def::LifetimeParamId, crate::LifetimeParam),
+    (hir_def::ConstParamId, crate::ConstParam),
     (hir_expand::MacroDefId, crate::MacroDef)
 ];
 
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 0dc07c33e2..dd7c0c5706 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -10,8 +10,8 @@ use hir_expand::InFile;
 use syntax::ast;
 
 use crate::{
-    db::HirDatabase, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef,
-    Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
+    db::HirDatabase, Const, ConstParam, Enum, Field, FieldSource, Function, Impl, LifetimeParam,
+    MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
 };
 
 pub trait HasSource {
@@ -140,3 +140,11 @@ impl HasSource for LifetimeParam {
         child_source.map(|it| it[self.id.local_id].clone())
     }
 }
+
+impl HasSource for ConstParam {
+    type Ast = ast::ConstParam;
+    fn source(self, db: &dyn HirDatabase) -> InFile<Self::Ast> {
+        let child_source = self.id.parent.child_source(db.upcast());
+        child_source.map(|it| it[self.id.local_id].clone())
+    }
+}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 7ac9fd5079..8ac27e2dd8 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -34,9 +34,9 @@ pub use crate::{
     attrs::{HasAttrs, Namespace},
     code_model::{
         Access, Adt, AsAssocItem, AssocItem, AssocItemContainer, Callable, CallableKind, Const,
-        Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function, GenericDef,
-        HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef, ScopeDef,
-        Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
+        ConstParam, Crate, CrateDependency, DefWithBody, Enum, Field, FieldSource, Function,
+        GenericDef, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef, Module, ModuleDef,
+        ScopeDef, Static, Struct, Trait, Type, TypeAlias, TypeParam, Union, Variant, VariantDef,
     },
     has_source::HasSource,
     semantics::{PathResolution, Semantics, SemanticsScope},
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index 67cd16e311..cd689c8693 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -25,9 +25,9 @@ use crate::{
     diagnostics::Diagnostic,
     semantics::source_to_def::{ChildContainer, SourceToDefCache, SourceToDefCtx},
     source_analyzer::{resolve_hir_path, SourceAnalyzer},
-    AssocItem, Callable, Crate, Field, Function, HirFileId, Impl, InFile, Label, LifetimeParam,
-    Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type, TypeAlias, TypeParam,
-    VariantDef,
+    AssocItem, Callable, ConstParam, Crate, Field, Function, HirFileId, Impl, InFile, Label,
+    LifetimeParam, Local, MacroDef, Module, ModuleDef, Name, Path, ScopeDef, Trait, Type,
+    TypeAlias, TypeParam, VariantDef,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -38,6 +38,7 @@ pub enum PathResolution {
     Local(Local),
     /// A generic parameter
     TypeParam(TypeParam),
+    ConstParam(ConstParam),
     SelfType(Impl),
     Macro(MacroDef),
     AssocItem(AssocItem),
@@ -59,7 +60,9 @@ impl PathResolution {
             PathResolution::Def(ModuleDef::TypeAlias(alias)) => {
                 Some(TypeNs::TypeAliasId((*alias).into()))
             }
-            PathResolution::Local(_) | PathResolution::Macro(_) => None,
+            PathResolution::Local(_) | PathResolution::Macro(_) | PathResolution::ConstParam(_) => {
+                None
+            }
             PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
             PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
             PathResolution::AssocItem(AssocItem::Const(_))
@@ -744,6 +747,7 @@ to_def_impls![
     (crate::Variant, ast::Variant, enum_variant_to_def),
     (crate::TypeParam, ast::TypeParam, type_param_to_def),
     (crate::LifetimeParam, ast::LifetimeParam, lifetime_param_to_def),
+    (crate::ConstParam, ast::ConstParam, const_param_to_def),
     (crate::MacroDef, ast::MacroRules, macro_rules_to_def),
     (crate::Local, ast::IdentPat, bind_pat_to_def),
     (crate::Label, ast::Label, label_to_def),
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 424e6e8a94..4b9ebff729 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -6,9 +6,9 @@ use hir_def::{
     dyn_map::DynMap,
     expr::{LabelId, PatId},
     keys::{self, Key},
-    ConstId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId, ImplId,
-    LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
-    VariantId,
+    ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, FieldId, FunctionId, GenericDefId,
+    ImplId, LifetimeParamId, ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
+    UnionId, VariantId,
 };
 use hir_expand::{name::AsName, AstId, MacroDefKind};
 use rustc_hash::FxHashMap;
@@ -157,6 +157,18 @@ impl SourceToDefCtx<'_, '_> {
         dyn_map[keys::LIFETIME_PARAM].get(&src).copied()
     }
 
+    pub(super) fn const_param_to_def(
+        &mut self,
+        src: InFile<ast::ConstParam>,
+    ) -> Option<ConstParamId> {
+        let container: ChildContainer =
+            self.find_generic_param_container(src.as_ref().map(|it| it.syntax()))?.into();
+        let db = self.db;
+        let dyn_map =
+            &*self.cache.entry(container).or_insert_with(|| container.child_by_source(db));
+        dyn_map[keys::CONST_PARAM].get(&src).copied()
+    }
+
     // FIXME: use DynMap as well?
     pub(super) fn macro_rules_to_def(
         &mut self,
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index bddc49c05a..30a8e513dd 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -479,6 +479,7 @@ pub(crate) fn resolve_hir_path(
                 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
                 ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
                 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
+                ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()),
             };
             Some(res)
         });
diff --git a/crates/hir_def/Cargo.toml b/crates/hir_def/Cargo.toml
index e8b581e2fa..a88b5f57ee 100644
--- a/crates/hir_def/Cargo.toml
+++ b/crates/hir_def/Cargo.toml
@@ -17,7 +17,7 @@ either = "1.5.3"
 anymap = "0.12.1"
 drop_bomb = "0.1.4"
 fst = { version = "0.4", default-features = false }
-itertools = "0.10.0"
+itertools = "0.9.0"
 indexmap = "1.4.0"
 smallvec = "1.4.0"
 
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index bb8fca009a..9b5b886c2b 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -21,11 +21,11 @@ use crate::{
     keys,
     src::{HasChildSource, HasSource},
     type_ref::{LifetimeRef, TypeBound, TypeRef},
-    AdtId, GenericDefId, LifetimeParamId, LocalLifetimeParamId, LocalTypeParamId, Lookup,
-    TypeParamId,
+    AdtId, ConstParamId, GenericDefId, LifetimeParamId, LocalConstParamId, LocalLifetimeParamId,
+    LocalTypeParamId, Lookup, TypeParamId,
 };
 
-/// Data about a generic parameter (to a function, struct, impl, ...).
+/// Data about a generic type parameter (to a function, struct, impl, ...).
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct TypeParamData {
     pub name: Option<Name>,
@@ -33,12 +33,19 @@ pub struct TypeParamData {
     pub provenance: TypeParamProvenance,
 }
 
-/// Data about a generic parameter (to a function, struct, impl, ...).
+/// Data about a generic lifetime parameter (to a function, struct, impl, ...).
 #[derive(Clone, PartialEq, Eq, Debug)]
 pub struct LifetimeParamData {
     pub name: Name,
 }
 
+/// Data about a generic const parameter (to a function, struct, impl, ...).
+#[derive(Clone, PartialEq, Eq, Debug)]
+pub struct ConstParamData {
+    pub name: Name,
+    pub ty: TypeRef,
+}
+
 #[derive(Copy, Clone, PartialEq, Eq, Debug)]
 pub enum TypeParamProvenance {
     TypeParamList,
@@ -51,6 +58,7 @@ pub enum TypeParamProvenance {
 pub struct GenericParams {
     pub types: Arena<TypeParamData>,
     pub lifetimes: Arena<LifetimeParamData>,
+    pub consts: Arena<ConstParamData>,
     pub where_predicates: Vec<WherePredicate>,
 }
 
@@ -76,6 +84,7 @@ pub enum WherePredicateTypeTarget {
 pub(crate) struct SourceMap {
     pub(crate) type_params: ArenaMap<LocalTypeParamId, Either<ast::Trait, ast::TypeParam>>,
     lifetime_params: ArenaMap<LocalLifetimeParamId, ast::LifetimeParam>,
+    const_params: ArenaMap<LocalConstParamId, ast::ConstParam>,
 }
 
 impl GenericParams {
@@ -268,6 +277,13 @@ impl GenericParams {
             let lifetime_ref = LifetimeRef::new_name(name);
             self.fill_bounds(&lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
         }
+        for const_param in params.const_params() {
+            let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
+            let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
+            let param = ConstParamData { name, ty };
+            let param_id = self.consts.alloc(param);
+            sm.const_params.insert(param_id, const_param.clone());
+        }
     }
 
     fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
@@ -353,12 +369,16 @@ impl GenericParams {
         });
     }
 
-    pub fn find_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
+    pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeParamId> {
         self.types
             .iter()
             .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
     }
 
+    pub fn find_const_by_name(&self, name: &Name) -> Option<LocalConstParamId> {
+        self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None })
+    }
+
     pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
         self.types.iter().find_map(|(id, p)| {
             if p.provenance == TypeParamProvenance::TraitSelf {
@@ -390,6 +410,16 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
     }
 }
 
+impl HasChildSource<LocalConstParamId> for GenericDefId {
+    type Value = ast::ConstParam;
+    fn child_source(
+        &self,
+        db: &dyn DefDatabase,
+    ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> {
+        GenericParams::new(db, *self).1.map(|source_maps| source_maps.const_params)
+    }
+}
+
 impl ChildBySource for GenericDefId {
     fn child_by_source(&self, db: &dyn DefDatabase) -> DynMap {
         let mut res = DynMap::default();
@@ -406,6 +436,10 @@ impl ChildBySource for GenericDefId {
             let id = LifetimeParamId { parent: *self, local_id };
             res[keys::LIFETIME_PARAM].insert(sm.with_value(src.clone()), id);
         }
+        for (local_id, src) in sm.value.const_params.iter() {
+            let id = ConstParamId { parent: *self, local_id };
+            res[keys::CONST_PARAM].insert(sm.with_value(src.clone()), id);
+        }
         res
     }
 }
diff --git a/crates/hir_def/src/import_map.rs b/crates/hir_def/src/import_map.rs
index 30b22f51df..c0f1088480 100644
--- a/crates/hir_def/src/import_map.rs
+++ b/crates/hir_def/src/import_map.rs
@@ -238,53 +238,32 @@ pub enum ImportKind {
     BuiltinType,
 }
 
-/// A way to match import map contents against the search query.
-#[derive(Debug)]
-pub enum SearchMode {
-    /// Import map entry should strictly match the query string.
-    Equals,
-    /// Import map entry should contain the query string.
-    Contains,
-    /// Import map entry should contain all letters from the query string,
-    /// in the same order, but not necessary adjacent.
-    Fuzzy,
-}
-
 #[derive(Debug)]
 pub struct Query {
     query: String,
     lowercased: String,
-    name_only: bool,
-    search_mode: SearchMode,
+    anchor_end: bool,
     case_sensitive: bool,
     limit: usize,
     exclude_import_kinds: FxHashSet<ImportKind>,
 }
 
 impl Query {
-    pub fn new(query: String) -> Self {
-        let lowercased = query.to_lowercase();
+    pub fn new(query: &str) -> Self {
         Self {
-            query,
-            lowercased,
-            name_only: false,
-            search_mode: SearchMode::Contains,
+            lowercased: query.to_lowercase(),
+            query: query.to_string(),
+            anchor_end: false,
             case_sensitive: false,
             limit: usize::max_value(),
             exclude_import_kinds: FxHashSet::default(),
         }
     }
 
-    /// Matches entries' names only, ignoring the rest of
-    /// the qualifier.
-    /// Example: for `std::marker::PhantomData`, the name is `PhantomData`.
-    pub fn name_only(self) -> Self {
-        Self { name_only: true, ..self }
-    }
-
-    /// Specifies the way to search for the entries using the query.
-    pub fn search_mode(self, search_mode: SearchMode) -> Self {
-        Self { search_mode, ..self }
+    /// Only returns items whose paths end with the (case-insensitive) query string as their last
+    /// segment.
+    pub fn anchor_end(self) -> Self {
+        Self { anchor_end: true, ..self }
     }
 
     /// Limits the returned number of items to `limit`.
@@ -304,40 +283,6 @@ impl Query {
     }
 }
 
-fn contains_query(query: &Query, input_path: &ImportPath, enforce_lowercase: bool) -> bool {
-    let mut input = if query.name_only {
-        input_path.segments.last().unwrap().to_string()
-    } else {
-        input_path.to_string()
-    };
-    if enforce_lowercase || !query.case_sensitive {
-        input.make_ascii_lowercase();
-    }
-
-    let query_string =
-        if !enforce_lowercase && query.case_sensitive { &query.query } else { &query.lowercased };
-
-    match query.search_mode {
-        SearchMode::Equals => &input == query_string,
-        SearchMode::Contains => input.contains(query_string),
-        SearchMode::Fuzzy => {
-            let mut unchecked_query_chars = query_string.chars();
-            let mut mismatching_query_char = unchecked_query_chars.next();
-
-            for input_char in input.chars() {
-                match mismatching_query_char {
-                    None => return true,
-                    Some(matching_query_char) if matching_query_char == input_char => {
-                        mismatching_query_char = unchecked_query_chars.next();
-                    }
-                    _ => (),
-                }
-            }
-            mismatching_query_char.is_none()
-        }
-    }
-}
-
 /// Searches dependencies of `krate` for an importable path matching `query`.
 ///
 /// This returns a list of items that could be imported from dependencies of `krate`.
@@ -367,29 +312,39 @@ pub fn search_dependencies<'a>(
             let importables = &import_map.importables[indexed_value.value as usize..];
 
             // Path shared by the importable items in this group.
-            let common_importables_path = &import_map.map[&importables[0]].path;
-            if !contains_query(&query, common_importables_path, true) {
-                continue;
+            let path = &import_map.map[&importables[0]].path;
+
+            if query.anchor_end {
+                // Last segment must match query.
+                let last = path.segments.last().unwrap().to_string();
+                if last.to_lowercase() != query.lowercased {
+                    continue;
+                }
             }
 
-            let common_importables_path_fst = fst_path(common_importables_path);
             // Add the items from this `ModPath` group. Those are all subsequent items in
             // `importables` whose paths match `path`.
             let iter = importables
                 .iter()
                 .copied()
                 .take_while(|item| {
-                    common_importables_path_fst == fst_path(&import_map.map[item].path)
+                    let item_path = &import_map.map[item].path;
+                    fst_path(item_path) == fst_path(path)
                 })
                 .filter(|&item| match item_import_kind(item) {
                     Some(import_kind) => !query.exclude_import_kinds.contains(&import_kind),
                     None => true,
-                })
-                .filter(|item| {
-                    !query.case_sensitive // we've already checked the common importables path case-insensitively
-                        || contains_query(&query, &import_map.map[item].path, false)
                 });
-            res.extend(iter);
+
+            if query.case_sensitive {
+                // FIXME: This does not do a subsequence match.
+                res.extend(iter.filter(|item| {
+                    let item_path = &import_map.map[item].path;
+                    item_path.to_string().contains(&query.query)
+                }));
+            } else {
+                res.extend(iter);
+            }
 
             if res.len() >= query.limit {
                 res.truncate(query.limit);
@@ -432,9 +387,8 @@ fn item_import_kind(item: ItemInNs) -> Option<ImportKind> {
 mod tests {
     use base_db::{fixture::WithFixture, SourceDatabase, Upcast};
     use expect_test::{expect, Expect};
-    use stdx::format_to;
 
-    use crate::{data::FunctionData, test_db::TestDB, AssocContainerId, Lookup};
+    use crate::{test_db::TestDB, AssocContainerId, Lookup};
 
     use super::*;
 
@@ -453,32 +407,14 @@ mod tests {
             .into_iter()
             .filter_map(|item| {
                 let mark = match item {
-                    ItemInNs::Types(ModuleDefId::FunctionId(_))
-                    | ItemInNs::Values(ModuleDefId::FunctionId(_)) => "f",
                     ItemInNs::Types(_) => "t",
                     ItemInNs::Values(_) => "v",
                     ItemInNs::Macros(_) => "m",
                 };
+                let item = assoc_to_trait(&db, item);
                 item.krate(db.upcast()).map(|krate| {
                     let map = db.import_map(krate);
-
-                    let path = match assoc_to_trait(&db, item) {
-                        Some(trait_) => {
-                            let mut full_path = map.path_of(trait_).unwrap().to_string();
-                            if let ItemInNs::Types(ModuleDefId::FunctionId(function_id))
-                            | ItemInNs::Values(ModuleDefId::FunctionId(function_id)) = item
-                            {
-                                format_to!(
-                                    full_path,
-                                    "::{}",
-                                    FunctionData::fn_data_query(&db, function_id).name,
-                                );
-                            }
-                            full_path
-                        }
-                        None => map.path_of(item).unwrap().to_string(),
-                    };
-
+                    let path = map.path_of(item).unwrap();
                     format!(
                         "{}::{} ({})\n",
                         crate_graph[krate].display_name.as_ref().unwrap(),
@@ -491,15 +427,15 @@ mod tests {
         expect.assert_eq(&actual)
     }
 
-    fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> Option<ItemInNs> {
+    fn assoc_to_trait(db: &dyn DefDatabase, item: ItemInNs) -> ItemInNs {
         let assoc: AssocItemId = match item {
             ItemInNs::Types(it) | ItemInNs::Values(it) => match it {
                 ModuleDefId::TypeAliasId(it) => it.into(),
                 ModuleDefId::FunctionId(it) => it.into(),
                 ModuleDefId::ConstId(it) => it.into(),
-                _ => return None,
+                _ => return item,
             },
-            _ => return None,
+            _ => return item,
         };
 
         let container = match assoc {
@@ -509,8 +445,8 @@ mod tests {
         };
 
         match container {
-            AssocContainerId::TraitId(it) => Some(ItemInNs::Types(it.into())),
-            _ => None,
+            AssocContainerId::TraitId(it) => ItemInNs::Types(it.into()),
+            _ => item,
         }
     }
 
@@ -749,7 +685,7 @@ mod tests {
     }
 
     #[test]
-    fn search_mode() {
+    fn search() {
         let ra_fixture = r#"
             //- /main.rs crate:main deps:dep
             //- /dep.rs crate:dep deps:tdep
@@ -777,96 +713,28 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Fuzzy),
+            Query::new("fmt"),
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::Fmt (m)
                 dep::fmt::Display (t)
-                dep::format (f)
-                dep::fmt::Display::fmt (f)
-            "#]],
-        );
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Equals),
-            expect![[r#"
-                dep::fmt (t)
-                dep::Fmt (t)
-                dep::Fmt (v)
-                dep::Fmt (m)
-                dep::fmt::Display::fmt (f)
-            "#]],
-        );
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("fmt".to_string()).search_mode(SearchMode::Contains),
-            expect![[r#"
-                dep::fmt (t)
-                dep::Fmt (t)
-                dep::Fmt (v)
-                dep::Fmt (m)
+                dep::format (v)
                 dep::fmt::Display (t)
-                dep::fmt::Display::fmt (f)
             "#]],
         );
-    }
-
-    #[test]
-    fn name_only() {
-        let ra_fixture = r#"
-            //- /main.rs crate:main deps:dep
-            //- /dep.rs crate:dep deps:tdep
-            use tdep::fmt as fmt_dep;
-            pub mod fmt {
-                pub trait Display {
-                    fn fmt();
-                }
-            }
-            #[macro_export]
-            macro_rules! Fmt {
-                () => {};
-            }
-            pub struct Fmt;
-
-            pub fn format() {}
-            pub fn no() {}
-
-            //- /tdep.rs crate:tdep
-            pub mod fmt {
-                pub struct NotImportableFromMain;
-            }
-        "#;
 
         check_search(
             ra_fixture,
             "main",
-            Query::new("fmt".to_string()),
+            Query::new("fmt").anchor_end(),
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (t)
                 dep::Fmt (v)
                 dep::Fmt (m)
                 dep::fmt::Display (t)
-                dep::fmt::Display::fmt (f)
-            "#]],
-        );
-
-        check_search(
-            ra_fixture,
-            "main",
-            Query::new("fmt".to_string()).name_only(),
-            expect![[r#"
-                dep::fmt (t)
-                dep::Fmt (t)
-                dep::Fmt (v)
-                dep::Fmt (m)
-                dep::fmt::Display::fmt (f)
             "#]],
         );
     }
@@ -884,7 +752,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("FMT".to_string()),
+            Query::new("FMT"),
             expect![[r#"
                 dep::fmt (t)
                 dep::fmt (v)
@@ -896,7 +764,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("FMT".to_string()).case_sensitive(),
+            Query::new("FMT").case_sensitive(),
             expect![[r#"
                 dep::FMT (t)
                 dep::FMT (v)
@@ -925,7 +793,7 @@ mod tests {
         pub fn no() {}
     "#,
             "main",
-            Query::new("".to_string()).limit(2),
+            Query::new("").limit(2),
             expect![[r#"
                 dep::fmt (t)
                 dep::Fmt (t)
@@ -946,7 +814,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("FMT".to_string()),
+            Query::new("FMT"),
             expect![[r#"
                 dep::fmt (t)
                 dep::fmt (v)
@@ -958,7 +826,7 @@ mod tests {
         check_search(
             ra_fixture,
             "main",
-            Query::new("FMT".to_string()).exclude_import_kind(ImportKind::Adt),
+            Query::new("FMT").exclude_import_kind(ImportKind::Adt),
             expect![[r#""#]],
         );
     }
diff --git a/crates/hir_def/src/item_tree.rs b/crates/hir_def/src/item_tree.rs
index 100dbf5d65..b6f5107313 100644
--- a/crates/hir_def/src/item_tree.rs
+++ b/crates/hir_def/src/item_tree.rs
@@ -260,6 +260,7 @@ impl GenericParamsStorage {
     fn alloc(&mut self, params: GenericParams) -> GenericParamsId {
         if params.types.is_empty()
             && params.lifetimes.is_empty()
+            && params.consts.is_empty()
             && params.where_predicates.is_empty()
         {
             return GenericParamsId::EMPTY;
@@ -269,8 +270,12 @@ impl GenericParamsStorage {
     }
 }
 
-static EMPTY_GENERICS: GenericParams =
-    GenericParams { types: Arena::new(), lifetimes: Arena::new(), where_predicates: Vec::new() };
+static EMPTY_GENERICS: GenericParams = GenericParams {
+    types: Arena::new(),
+    lifetimes: Arena::new(),
+    consts: Arena::new(),
+    where_predicates: Vec::new(),
+};
 
 #[derive(Default, Debug, Eq, PartialEq)]
 struct ItemTreeData {
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs
index 9c585de2ce..89b3ed8686 100644
--- a/crates/hir_def/src/keys.rs
+++ b/crates/hir_def/src/keys.rs
@@ -8,8 +8,8 @@ use syntax::{ast, AstNode, AstPtr};
 
 use crate::{
     dyn_map::{DynMap, Policy},
-    ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId,
-    StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
+    ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId,
+    StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
 };
 
 pub type Key<K, V> = crate::dyn_map::Key<InFile<K>, V, AstPtrPolicy<K, V>>;
@@ -29,6 +29,7 @@ pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
 pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
 pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
 pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
+pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
 
 pub const MACRO: Key<ast::MacroCall, MacroDefId> = Key::new();
 
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index ba09a9126b..25f460504f 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -231,6 +231,13 @@ pub struct LifetimeParamId {
 }
 pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
 
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+pub struct ConstParamId {
+    pub parent: GenericDefId,
+    pub local_id: LocalConstParamId,
+}
+pub type LocalConstParamId = Idx<generics::ConstParamData>;
+
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ContainerId {
     ModuleId(ModuleId),
diff --git a/crates/hir_def/src/nameres.rs b/crates/hir_def/src/nameres.rs
index 5682e122db..ffd0381d43 100644
--- a/crates/hir_def/src/nameres.rs
+++ b/crates/hir_def/src/nameres.rs
@@ -249,7 +249,7 @@ impl CrateDefMap {
                     buf.push_str(" _");
                 }
 
-                buf.push('\n');
+                buf.push_str("\n");
             }
 
             for (name, child) in map.modules[module].children.iter() {
@@ -454,7 +454,7 @@ mod diagnostics {
                                     });
                                 for token in tokens {
                                     if token.kind() == SyntaxKind::IDENT
-                                        && token.text() == name.as_str()
+                                        && token.to_string() == *name
                                     {
                                         precise_location = Some(token.text_range());
                                         break 'outer;
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index f8cc5e075e..129f1dbac9 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -20,9 +20,9 @@ use crate::{
     path::{ModPath, PathKind},
     per_ns::PerNs,
     visibility::{RawVisibility, Visibility},
-    AdtId, AssocContainerId, ConstId, ContainerId, DefWithBodyId, EnumId, EnumVariantId,
-    FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId, ModuleId,
-    StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
+    AdtId, AssocContainerId, ConstId, ConstParamId, ContainerId, DefWithBodyId, EnumId,
+    EnumVariantId, FunctionId, GenericDefId, HasModule, ImplId, LocalModuleId, Lookup, ModuleDefId,
+    ModuleId, StaticId, StructId, TraitId, TypeAliasId, TypeParamId, VariantId,
 };
 
 #[derive(Debug, Clone, Default)]
@@ -93,6 +93,7 @@ pub enum ValueNs {
     StaticId(StaticId),
     StructId(StructId),
     EnumVariantId(EnumVariantId),
+    GenericParam(ConstParamId),
 }
 
 impl Resolver {
@@ -163,7 +164,7 @@ impl Resolver {
                 }
 
                 Scope::GenericParams { params, def } => {
-                    if let Some(local_id) = params.find_by_name(first_name) {
+                    if let Some(local_id) = params.find_type_by_name(first_name) {
                         let idx = if path.segments.len() == 1 { None } else { Some(1) };
                         return Some((
                             TypeNs::GenericParam(TypeParamId { local_id, parent: *def }),
@@ -285,11 +286,17 @@ impl Resolver {
                 Scope::ExprScope(_) => continue,
 
                 Scope::GenericParams { params, def } if n_segments > 1 => {
-                    if let Some(local_id) = params.find_by_name(first_name) {
+                    if let Some(local_id) = params.find_type_by_name(first_name) {
                         let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
+                Scope::GenericParams { params, def } if n_segments == 1 => {
+                    if let Some(local_id) = params.find_const_by_name(first_name) {
+                        let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def });
+                        return Some(ResolveValueResult::ValueNs(val));
+                    }
+                }
                 Scope::GenericParams { .. } => continue,
 
                 Scope::ImplDefScope(impl_) => {
diff --git a/crates/hir_expand/src/builtin_macro.rs b/crates/hir_expand/src/builtin_macro.rs
index 80b60d59fe..6382521fbb 100644
--- a/crates/hir_expand/src/builtin_macro.rs
+++ b/crates/hir_expand/src/builtin_macro.rs
@@ -259,8 +259,7 @@ fn format_args_expand(
     }
     for arg in &mut args {
         // Remove `key =`.
-        if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=' && p.spacing != tt::Spacing::Joint)
-        {
+        if matches!(arg.get(1), Some(tt::TokenTree::Leaf(tt::Leaf::Punct(p))) if p.char == '=') {
             arg.drain(..2);
         }
     }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index 2dfccd191b..965c1780a7 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -10,7 +10,7 @@ edition = "2018"
 doctest = false
 
 [dependencies]
-itertools = "0.10.0"
+itertools = "0.9.0"
 arrayvec = "0.5.1"
 smallvec = "1.2.0"
 ena = "0.14.0"
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 66bdb8e88e..f3567c49e6 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -5,8 +5,8 @@ use std::sync::Arc;
 use arena::map::ArenaMap;
 use base_db::{impl_intern_key, salsa, CrateId, Upcast};
 use hir_def::{
-    db::DefDatabase, expr::ExprId, DefWithBodyId, FunctionId, GenericDefId, ImplId, LocalFieldId,
-    TypeParamId, VariantId,
+    db::DefDatabase, expr::ExprId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId, ImplId,
+    LocalFieldId, TypeParamId, VariantId,
 };
 
 use crate::{
@@ -37,6 +37,9 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::cycle(crate::lower::impl_self_ty_recover)]
     fn impl_self_ty(&self, def: ImplId) -> Binders<Ty>;
 
+    #[salsa::invoke(crate::lower::const_param_ty_query)]
+    fn const_param_ty(&self, def: ConstParamId) -> Ty;
+
     #[salsa::invoke(crate::lower::impl_trait_query)]
     fn impl_trait(&self, def: ImplId) -> Option<Binders<TraitRef>>;
 
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index f2fc69b2f4..70a3f3075c 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -648,8 +648,6 @@ impl<'a> InferenceContext<'a> {
             }
             Expr::Array(array) => {
                 let elem_ty = match &expected.ty {
-                    // FIXME: remove when https://github.com/rust-lang/rust/issues/80501 is fixed
-                    #[allow(unreachable_patterns)]
                     ty_app!(TypeCtor::Array, st) | ty_app!(TypeCtor::Slice, st) => {
                         st.as_single().clone()
                     }
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 80d7ed10ec..5d541104e2 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -89,6 +89,7 @@ impl<'a> InferenceContext<'a> {
                     return None;
                 }
             }
+            ValueNs::GenericParam(it) => return Some(self.db.const_param_ty(it)),
         };
 
         let ty = self.db.value_ty(typable);
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 8da56cd11c..222f61a11d 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -16,9 +16,9 @@ use hir_def::{
     path::{GenericArg, Path, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{TypeBound, TypeRef},
-    AdtId, AssocContainerId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId, TypeParamId,
-    UnionId, VariantId,
+    AdtId, AssocContainerId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId,
+    GenericDefId, HasModule, ImplId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
+    TypeAliasId, TypeParamId, UnionId, VariantId,
 };
 use hir_expand::name::Name;
 use smallvec::SmallVec;
@@ -1221,6 +1221,15 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
     Binders::new(generics.len(), Ty::from_hir(&ctx, &impl_data.target_type))
 }
 
+pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
+    let parent_data = db.generic_params(def.parent);
+    let data = &parent_data.consts[def.local_id];
+    let resolver = def.parent.resolver(db.upcast());
+    let ctx = TyLoweringContext::new(db, &resolver);
+
+    Ty::from_hir(&ctx, &data.ty)
+}
+
 pub(crate) fn impl_self_ty_recover(
     db: &dyn HirDatabase,
     _cycle: &[String],
diff --git a/crates/ide/Cargo.toml b/crates/ide/Cargo.toml
index f1544dbe01..4d483580df 100644
--- a/crates/ide/Cargo.toml
+++ b/crates/ide/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
 [dependencies]
 either = "1.5.3"
 indexmap = "1.4.0"
-itertools = "0.10.0"
+itertools = "0.9.0"
 log = "0.4.8"
 rustc-hash = "1.1.0"
 oorandom = "11.1.2"
diff --git a/crates/ide/src/diagnostics.rs b/crates/ide/src/diagnostics.rs
index 79d126ff2a..0382737503 100644
--- a/crates/ide/src/diagnostics.rs
+++ b/crates/ide/src/diagnostics.rs
@@ -199,12 +199,6 @@ fn check_unnecessary_braces_in_use_statement(
 ) -> Option<()> {
     let use_tree_list = ast::UseTreeList::cast(node.clone())?;
     if let Some((single_use_tree,)) = use_tree_list.use_trees().collect_tuple() {
-        // If there is a comment inside the bracketed `use`,
-        // assume it is a commented out module path and don't show diagnostic.
-        if use_tree_list.has_inner_comment() {
-            return Some(());
-        }
-
         let use_range = use_tree_list.syntax().text_range();
         let edit =
             text_edit_for_remove_unnecessary_braces_with_self_in_use_statement(&single_use_tree)
@@ -636,22 +630,6 @@ pub struct Foo { pub a: i32, pub b: i32 }
 use a;
 use a::{c, d::e};
 
-mod a {
-    mod c {}
-    mod d {
-        mod e {}
-    }
-}
-"#,
-        );
-        check_no_diagnostics(
-            r#"
-use a;
-use a::{
-    c,
-    // d::e
-};
-
 mod a {
     mod c {}
     mod d {
diff --git a/crates/ide/src/display/navigation_target.rs b/crates/ide/src/display/navigation_target.rs
index 6431e7d6db..bcde2b6f12 100644
--- a/crates/ide/src/display/navigation_target.rs
+++ b/crates/ide/src/display/navigation_target.rs
@@ -24,6 +24,7 @@ pub enum SymbolKind {
     Impl,
     Field,
     TypeParam,
+    ConstParam,
     LifetimeParam,
     ValueParam,
     SelfParam,
@@ -225,6 +226,7 @@ impl TryToNav for Definition {
             Definition::TypeParam(it) => Some(it.to_nav(db)),
             Definition::LifetimeParam(it) => Some(it.to_nav(db)),
             Definition::Label(it) => Some(it.to_nav(db)),
+            Definition::ConstParam(it) => Some(it.to_nav(db)),
         }
     }
 }
@@ -485,6 +487,23 @@ impl ToNav for hir::LifetimeParam {
     }
 }
 
+impl ToNav for hir::ConstParam {
+    fn to_nav(&self, db: &RootDatabase) -> NavigationTarget {
+        let src = self.source(db);
+        let full_range = src.value.syntax().text_range();
+        NavigationTarget {
+            file_id: src.file_id.original_file(db),
+            name: self.name(db).to_string().into(),
+            kind: Some(SymbolKind::ConstParam),
+            full_range,
+            focus_range: src.value.name().map(|n| n.syntax().text_range()),
+            container_name: None,
+            description: None,
+            docs: None,
+        }
+    }
+}
+
 /// Get a description of a symbol.
 ///
 /// e.g. `struct Name`, `enum Name`, `fn Name`
diff --git a/crates/ide/src/doc_links.rs b/crates/ide/src/doc_links.rs
index e10516f43a..367fac05e9 100644
--- a/crates/ide/src/doc_links.rs
+++ b/crates/ide/src/doc_links.rs
@@ -193,6 +193,7 @@ fn rewrite_intra_doc_link(
         Definition::SelfType(_)
         | Definition::Local(_)
         | Definition::TypeParam(_)
+        | Definition::ConstParam(_)
         | Definition::LifetimeParam(_)
         | Definition::Label(_) => return None,
     }?;
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 73245fbe75..49eb8caae6 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -370,7 +370,10 @@ fn hover_for_definition(db: &RootDatabase, def: Definition) -> Option<Markup> {
                 Adt::Enum(it) => from_def_source(db, it, mod_path),
             })
         }
-        Definition::TypeParam(_) | Definition::LifetimeParam(_) | Definition::Label(_) => {
+        Definition::TypeParam(_)
+        | Definition::LifetimeParam(_)
+        | Definition::ConstParam(_)
+        | Definition::Label(_) => {
             // FIXME: Hover for generic param
             None
         }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index b3331f03f1..41eb139d16 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -475,7 +475,7 @@ impl Analysis {
         config: &CompletionConfig,
         position: FilePosition,
         full_import_path: &str,
-        imported_name: String,
+        imported_name: &str,
     ) -> Cancelable<Vec<TextEdit>> {
         Ok(self
             .with_db(|db| {
diff --git a/crates/ide/src/references.rs b/crates/ide/src/references.rs
index 21b2d7ca1c..fa58fc3196 100644
--- a/crates/ide/src/references.rs
+++ b/crates/ide/src/references.rs
@@ -1144,4 +1144,20 @@ fn foo<'a>() -> &'a () {
             "#]],
         );
     }
+
+    #[test]
+    fn test_find_const_param() {
+        check(
+            r#"
+fn foo<const FOO<|>: usize>() -> usize {
+    FOO
+}
+"#,
+            expect![[r#"
+                FOO ConstParam FileId(0) 7..23 13..16 Other
+
+                FileId(0) 42..45 Other
+            "#]],
+        );
+    }
 }
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 5ad96581bd..ba00852445 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -819,6 +819,7 @@ fn highlight_def(db: &RootDatabase, def: Definition) -> Highlight {
         },
         Definition::SelfType(_) => HighlightTag::Symbol(SymbolKind::Impl),
         Definition::TypeParam(_) => HighlightTag::Symbol(SymbolKind::TypeParam),
+        Definition::ConstParam(_) => HighlightTag::Symbol(SymbolKind::ConstParam),
         Definition::Local(local) => {
             let tag = if local.is_param(db) {
                 HighlightTag::Symbol(SymbolKind::ValueParam)
diff --git a/crates/ide/src/syntax_highlighting/tags.rs b/crates/ide/src/syntax_highlighting/tags.rs
index 2a6cc0cab6..8b88670798 100644
--- a/crates/ide/src/syntax_highlighting/tags.rs
+++ b/crates/ide/src/syntax_highlighting/tags.rs
@@ -77,6 +77,7 @@ impl HighlightTag {
                 SymbolKind::Function => "function",
                 SymbolKind::TypeAlias => "type_alias",
                 SymbolKind::TypeParam => "type_param",
+                SymbolKind::ConstParam => "const_param",
                 SymbolKind::LifetimeParam => "lifetime",
                 SymbolKind::Macro => "macro",
                 SymbolKind::Local => "variable",
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index ebe53c8ee8..0ad6e10009 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -19,7 +19,7 @@ fst = { version = "0.4", default-features = false }
 rustc-hash = "1.1.0"
 once_cell = "1.3.1"
 either = "1.6.1"
-itertools = "0.10.0"
+itertools = "0.9.0"
 
 stdx = { path = "../stdx", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index d33a6cb863..cc5078bf0f 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -6,8 +6,8 @@
 // FIXME: this badly needs rename/rewrite (matklad, 2020-02-06).
 
 use hir::{
-    db::HirDatabase, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local, MacroDef,
-    Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility,
+    db::HirDatabase, ConstParam, Crate, Field, HasVisibility, Impl, Label, LifetimeParam, Local,
+    MacroDef, Module, ModuleDef, Name, PathResolution, Semantics, TypeParam, Visibility,
 };
 use syntax::{
     ast::{self, AstNode},
@@ -26,6 +26,7 @@ pub enum Definition {
     Local(Local),
     TypeParam(TypeParam),
     LifetimeParam(LifetimeParam),
+    ConstParam(ConstParam),
     Label(Label),
 }
 
@@ -39,6 +40,7 @@ impl Definition {
             Definition::Local(it) => Some(it.module(db)),
             Definition::TypeParam(it) => Some(it.module(db)),
             Definition::LifetimeParam(it) => Some(it.module(db)),
+            Definition::ConstParam(it) => Some(it.module(db)),
             Definition::Label(it) => Some(it.module(db)),
         }
     }
@@ -52,6 +54,7 @@ impl Definition {
             Definition::Local(_) => None,
             Definition::TypeParam(_) => None,
             Definition::LifetimeParam(_) => None,
+            Definition::ConstParam(_) => None,
             Definition::Label(_) => None,
         }
     }
@@ -79,6 +82,7 @@ impl Definition {
             Definition::Local(it) => it.name(db)?,
             Definition::TypeParam(it) => it.name(db),
             Definition::LifetimeParam(it) => it.name(db),
+            Definition::ConstParam(it) => it.name(db),
             Definition::Label(it) => it.name(db),
         };
         Some(name)
@@ -233,6 +237,10 @@ impl NameClass {
                     let def = sema.to_def(&it)?;
                     Some(NameClass::Definition(Definition::TypeParam(def)))
                 },
+                ast::ConstParam(it) => {
+                    let def = sema.to_def(&it)?;
+                    Some(NameClass::Definition(Definition::ConstParam(def)))
+                },
                 _ => None,
             }
         }
@@ -417,6 +425,7 @@ impl From<PathResolution> for Definition {
             PathResolution::TypeParam(par) => Definition::TypeParam(par),
             PathResolution::Macro(def) => Definition::Macro(def),
             PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
+            PathResolution::ConstParam(par) => Definition::ConstParam(par),
         }
     }
 }
diff --git a/crates/ide_db/src/imports_locator.rs b/crates/ide_db/src/imports_locator.rs
index 0f4c2ca473..b2980a5d69 100644
--- a/crates/ide_db/src/imports_locator.rs
+++ b/crates/ide_db/src/imports_locator.rs
@@ -15,23 +15,19 @@ use rustc_hash::FxHashSet;
 pub fn find_exact_imports<'a>(
     sema: &Semantics<'a, RootDatabase>,
     krate: Crate,
-    name_to_import: String,
+    name_to_import: &str,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_exact_imports");
     find_imports(
         sema,
         krate,
         {
-            let mut local_query = symbol_index::Query::new(name_to_import.clone());
+            let mut local_query = symbol_index::Query::new(name_to_import.to_string());
             local_query.exact();
             local_query.limit(40);
             local_query
         },
-        import_map::Query::new(name_to_import)
-            .limit(40)
-            .name_only()
-            .search_mode(import_map::SearchMode::Equals)
-            .case_sensitive(),
+        import_map::Query::new(name_to_import).anchor_end().case_sensitive().limit(40),
     )
 }
 
@@ -39,18 +35,17 @@ pub fn find_similar_imports<'a>(
     sema: &Semantics<'a, RootDatabase>,
     krate: Crate,
     limit: Option<usize>,
-    fuzzy_search_string: String,
-    name_only: bool,
+    name_to_import: &str,
+    ignore_modules: bool,
 ) -> impl Iterator<Item = Either<ModuleDef, MacroDef>> {
     let _p = profile::span("find_similar_imports");
 
-    let mut external_query = import_map::Query::new(fuzzy_search_string.clone())
-        .search_mode(import_map::SearchMode::Fuzzy);
-    if name_only {
-        external_query = external_query.name_only();
+    let mut external_query = import_map::Query::new(name_to_import);
+    if ignore_modules {
+        external_query = external_query.exclude_import_kind(import_map::ImportKind::Module);
     }
 
-    let mut local_query = symbol_index::Query::new(fuzzy_search_string);
+    let mut local_query = symbol_index::Query::new(name_to_import.to_string());
 
     if let Some(limit) = limit {
         local_query.limit(limit);
diff --git a/crates/mbe/src/lib.rs b/crates/mbe/src/lib.rs
index b3472879d1..3ad609a005 100644
--- a/crates/mbe/src/lib.rs
+++ b/crates/mbe/src/lib.rs
@@ -14,10 +14,10 @@ mod tests;
 
 use std::fmt;
 
-pub use tt::{Delimiter, DelimiterKind, Punct};
+pub use tt::{Delimiter, Punct};
 
 use crate::{
-    parser::{parse_pattern, parse_template, Op},
+    parser::{parse_pattern, Op},
     tt_iter::TtIter,
 };
 
@@ -78,24 +78,8 @@ pub struct MacroRules {
 
 #[derive(Clone, Debug, PartialEq, Eq)]
 struct Rule {
-    lhs: MetaTemplate,
-    rhs: MetaTemplate,
-}
-
-#[derive(Clone, Debug, PartialEq, Eq)]
-struct MetaTemplate {
-    delimiter: Option<Delimiter>,
-    tokens: Vec<Result<Op, ExpandError>>,
-}
-
-impl<'a> MetaTemplate {
-    fn iter(&self) -> impl Iterator<Item = &Result<Op, ExpandError>> {
-        self.tokens.iter()
-    }
-
-    fn delimiter_kind(&self) -> Option<DelimiterKind> {
-        self.delimiter.map(|it| it.kind)
-    }
+    lhs: tt::Subtree,
+    rhs: tt::Subtree,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Eq)]
@@ -183,7 +167,7 @@ impl MacroRules {
             rules.push(rule);
             if let Err(()) = src.expect_char(';') {
                 if src.len() > 0 {
-                    return Err(ParseError::Expected("expected `;`".to_string()));
+                    return Err(ParseError::Expected("expected `:`".to_string()));
                 }
                 break;
             }
@@ -217,23 +201,23 @@ impl MacroRules {
 
 impl Rule {
     fn parse(src: &mut TtIter) -> Result<Rule, ParseError> {
-        let lhs = src
+        let mut lhs = src
             .expect_subtree()
-            .map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
+            .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
+            .clone();
+        lhs.delimiter = None;
         src.expect_char('=').map_err(|()| ParseError::Expected("expected `=`".to_string()))?;
         src.expect_char('>').map_err(|()| ParseError::Expected("expected `>`".to_string()))?;
-        let rhs = src
+        let mut rhs = src
             .expect_subtree()
-            .map_err(|()| ParseError::Expected("expected subtree".to_string()))?;
-
-        let lhs = MetaTemplate { tokens: parse_pattern(&lhs), delimiter: None };
-        let rhs = MetaTemplate { tokens: parse_template(&rhs), delimiter: None };
-
+            .map_err(|()| ParseError::Expected("expected subtree".to_string()))?
+            .clone();
+        rhs.delimiter = None;
         Ok(crate::Rule { lhs, rhs })
     }
 }
 
-fn to_parse_error(e: &ExpandError) -> ParseError {
+fn to_parse_error(e: ExpandError) -> ParseError {
     let msg = match e {
         ExpandError::InvalidRepeat => "invalid repeat".to_string(),
         _ => "invalid macro definition".to_string(),
@@ -241,22 +225,22 @@ fn to_parse_error(e: &ExpandError) -> ParseError {
     ParseError::Expected(msg)
 }
 
-fn validate(pattern: &MetaTemplate) -> Result<(), ParseError> {
-    for op in pattern.iter() {
-        let op = op.as_ref().map_err(|e| to_parse_error(&e))?;
+fn validate(pattern: &tt::Subtree) -> Result<(), ParseError> {
+    for op in parse_pattern(pattern) {
+        let op = op.map_err(to_parse_error)?;
 
         match op {
-            Op::Subtree(subtree) => validate(&subtree)?,
+            Op::TokenTree(tt::TokenTree::Subtree(subtree)) => validate(subtree)?,
             Op::Repeat { subtree, separator, .. } => {
                 // Checks that no repetition which could match an empty token
                 // https://github.com/rust-lang/rust/blob/a58b1ed44f5e06976de2bdc4d7dc81c36a96934f/src/librustc_expand/mbe/macro_rules.rs#L558
 
                 if separator.is_none() {
-                    if subtree.iter().all(|child_op| {
-                        match child_op.as_ref().map_err(to_parse_error) {
+                    if parse_pattern(subtree).all(|child_op| {
+                        match child_op.map_err(to_parse_error) {
                             Ok(Op::Var { kind, .. }) => {
                                 // vis is optional
-                                if kind.as_ref().map_or(false, |it| it == "vis") {
+                                if kind.map_or(false, |it| it == "vis") {
                                     return true;
                                 }
                             }
diff --git a/crates/mbe/src/mbe_expander/matcher.rs b/crates/mbe/src/mbe_expander/matcher.rs
index ab5f87c487..44722c0f1a 100644
--- a/crates/mbe/src/mbe_expander/matcher.rs
+++ b/crates/mbe/src/mbe_expander/matcher.rs
@@ -2,10 +2,10 @@
 
 use crate::{
     mbe_expander::{Binding, Bindings, Fragment},
-    parser::{Op, RepeatKind, Separator},
+    parser::{parse_pattern, Op, RepeatKind, Separator},
     subtree_source::SubtreeTokenSource,
     tt_iter::TtIter,
-    ExpandError, MetaTemplate,
+    ExpandError,
 };
 
 use super::ExpandResult;
@@ -83,7 +83,7 @@ impl Match {
 // sense to try using it. Matching errors are added to the `Match`. It might
 // make sense to make pattern parsing a separate step?
 
-pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match, ExpandError> {
+pub(super) fn match_(pattern: &tt::Subtree, src: &tt::Subtree) -> Result<Match, ExpandError> {
     assert!(pattern.delimiter == None);
 
     let mut res = Match::default();
@@ -101,12 +101,12 @@ pub(super) fn match_(pattern: &MetaTemplate, src: &tt::Subtree) -> Result<Match,
 
 fn match_subtree(
     res: &mut Match,
-    pattern: &MetaTemplate,
+    pattern: &tt::Subtree,
     src: &mut TtIter,
 ) -> Result<(), ExpandError> {
-    for op in pattern.iter() {
-        match op.as_ref().map_err(|err| err.clone())? {
-            Op::Leaf(lhs) => {
+    for op in parse_pattern(pattern) {
+        match op? {
+            Op::TokenTree(tt::TokenTree::Leaf(lhs)) => {
                 let rhs = match src.expect_leaf() {
                     Ok(l) => l,
                     Err(()) => {
@@ -132,7 +132,7 @@ fn match_subtree(
                     }
                 }
             }
-            Op::Subtree(lhs) => {
+            Op::TokenTree(tt::TokenTree::Subtree(lhs)) => {
                 let rhs = match src.expect_subtree() {
                     Ok(s) => s,
                     Err(()) => {
@@ -172,7 +172,7 @@ fn match_subtree(
                 }
             }
             Op::Repeat { subtree, kind, separator } => {
-                match_repeat(res, subtree, *kind, separator, src)?;
+                match_repeat(res, subtree, kind, separator, src)?;
             }
         }
     }
@@ -372,9 +372,9 @@ impl<'a> TtIter<'a> {
 
 pub(super) fn match_repeat(
     res: &mut Match,
-    pattern: &MetaTemplate,
+    pattern: &tt::Subtree,
     kind: RepeatKind,
-    separator: &Option<Separator>,
+    separator: Option<Separator>,
     src: &mut TtIter,
 ) -> Result<(), ExpandError> {
     // Dirty hack to make macro-expansion terminate.
@@ -489,12 +489,12 @@ fn match_meta_var(kind: &str, input: &mut TtIter) -> ExpandResult<Option<Fragmen
     result.map(|tt| if kind == "expr" { tt.map(Fragment::Ast) } else { tt.map(Fragment::Tokens) })
 }
 
-fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &MetaTemplate) -> Result<(), ExpandError> {
-    for op in pattern.iter() {
-        match op.as_ref().map_err(|e| e.clone())? {
+fn collect_vars(buf: &mut Vec<SmolStr>, pattern: &tt::Subtree) -> Result<(), ExpandError> {
+    for op in parse_pattern(pattern) {
+        match op? {
             Op::Var { name, .. } => buf.push(name.clone()),
-            Op::Leaf(_) => (),
-            Op::Subtree(subtree) => collect_vars(buf, subtree)?,
+            Op::TokenTree(tt::TokenTree::Leaf(_)) => (),
+            Op::TokenTree(tt::TokenTree::Subtree(subtree)) => collect_vars(buf, subtree)?,
             Op::Repeat { subtree, .. } => collect_vars(buf, subtree)?,
         }
     }
diff --git a/crates/mbe/src/mbe_expander/transcriber.rs b/crates/mbe/src/mbe_expander/transcriber.rs
index 7205312371..57592dc929 100644
--- a/crates/mbe/src/mbe_expander/transcriber.rs
+++ b/crates/mbe/src/mbe_expander/transcriber.rs
@@ -6,8 +6,8 @@ use syntax::SmolStr;
 use super::ExpandResult;
 use crate::{
     mbe_expander::{Binding, Bindings, Fragment},
-    parser::{Op, RepeatKind, Separator},
-    ExpandError, MetaTemplate,
+    parser::{parse_template, Op, RepeatKind, Separator},
+    ExpandError,
 };
 
 impl Bindings {
@@ -50,10 +50,7 @@ impl Bindings {
     }
 }
 
-pub(super) fn transcribe(
-    template: &MetaTemplate,
-    bindings: &Bindings,
-) -> ExpandResult<tt::Subtree> {
+pub(super) fn transcribe(template: &tt::Subtree, bindings: &Bindings) -> ExpandResult<tt::Subtree> {
     assert!(template.delimiter == None);
     let mut ctx = ExpandCtx { bindings: &bindings, nesting: Vec::new() };
     let mut arena: Vec<tt::TokenTree> = Vec::new();
@@ -79,35 +76,35 @@ struct ExpandCtx<'a> {
 
 fn expand_subtree(
     ctx: &mut ExpandCtx,
-    template: &MetaTemplate,
+    template: &tt::Subtree,
     arena: &mut Vec<tt::TokenTree>,
 ) -> ExpandResult<tt::Subtree> {
     // remember how many elements are in the arena now - when returning, we want to drain exactly how many elements we added. This way, the recursive uses of the arena get their own "view" of the arena, but will reuse the allocation
     let start_elements = arena.len();
     let mut err = None;
-    for op in template.iter() {
+    for op in parse_template(template) {
         let op = match op {
             Ok(op) => op,
             Err(e) => {
-                err = Some(e.clone());
+                err = Some(e);
                 break;
             }
         };
         match op {
-            Op::Leaf(tt) => arena.push(tt.clone().into()),
-            Op::Subtree(tt) => {
-                let ExpandResult { value: tt, err: e } = expand_subtree(ctx, &tt, arena);
+            Op::TokenTree(tt @ tt::TokenTree::Leaf(..)) => arena.push(tt.clone()),
+            Op::TokenTree(tt::TokenTree::Subtree(tt)) => {
+                let ExpandResult { value: tt, err: e } = expand_subtree(ctx, tt, arena);
                 err = err.or(e);
                 arena.push(tt.into());
             }
             Op::Var { name, .. } => {
-                let ExpandResult { value: fragment, err: e } = expand_var(ctx, &name);
+                let ExpandResult { value: fragment, err: e } = expand_var(ctx, name);
                 err = err.or(e);
                 push_fragment(arena, fragment);
             }
             Op::Repeat { subtree, kind, separator } => {
                 let ExpandResult { value: fragment, err: e } =
-                    expand_repeat(ctx, subtree, *kind, separator, arena);
+                    expand_repeat(ctx, subtree, kind, separator, arena);
                 err = err.or(e);
                 push_fragment(arena, fragment)
             }
@@ -164,9 +161,9 @@ fn expand_var(ctx: &mut ExpandCtx, v: &SmolStr) -> ExpandResult<Fragment> {
 
 fn expand_repeat(
     ctx: &mut ExpandCtx,
-    template: &MetaTemplate,
+    template: &tt::Subtree,
     kind: RepeatKind,
-    separator: &Option<Separator>,
+    separator: Option<Separator>,
     arena: &mut Vec<tt::TokenTree>,
 ) -> ExpandResult<Fragment> {
     let mut buf: Vec<tt::TokenTree> = Vec::new();
diff --git a/crates/mbe/src/parser.rs b/crates/mbe/src/parser.rs
index 2f3ebc8313..d681905f57 100644
--- a/crates/mbe/src/parser.rs
+++ b/crates/mbe/src/parser.rs
@@ -4,17 +4,16 @@
 use smallvec::SmallVec;
 use syntax::SmolStr;
 
-use crate::{tt_iter::TtIter, ExpandError, MetaTemplate};
+use crate::{tt_iter::TtIter, ExpandError};
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub(crate) enum Op {
-    Var { name: SmolStr, kind: Option<SmolStr> },
-    Repeat { subtree: MetaTemplate, kind: RepeatKind, separator: Option<Separator> },
-    Leaf(tt::Leaf),
-    Subtree(MetaTemplate),
+#[derive(Debug)]
+pub(crate) enum Op<'a> {
+    Var { name: &'a SmolStr, kind: Option<&'a SmolStr> },
+    Repeat { subtree: &'a tt::Subtree, kind: RepeatKind, separator: Option<Separator> },
+    TokenTree(&'a tt::TokenTree),
 }
 
-#[derive(Copy, Clone, Debug, PartialEq, Eq)]
+#[derive(Clone, Debug, PartialEq, Eq)]
 pub(crate) enum RepeatKind {
     ZeroOrMore,
     OneOrMore,
@@ -46,12 +45,16 @@ impl PartialEq for Separator {
     }
 }
 
-pub(crate) fn parse_template(template: &tt::Subtree) -> Vec<Result<Op, ExpandError>> {
-    parse_inner(&template, Mode::Template)
+pub(crate) fn parse_template(
+    template: &tt::Subtree,
+) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
+    parse_inner(template, Mode::Template)
 }
 
-pub(crate) fn parse_pattern(pattern: &tt::Subtree) -> Vec<Result<Op, ExpandError>> {
-    parse_inner(&pattern, Mode::Pattern)
+pub(crate) fn parse_pattern(
+    pattern: &tt::Subtree,
+) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
+    parse_inner(pattern, Mode::Pattern)
 }
 
 #[derive(Clone, Copy)]
@@ -60,13 +63,12 @@ enum Mode {
     Template,
 }
 
-fn parse_inner(tt: &tt::Subtree, mode: Mode) -> Vec<Result<Op, ExpandError>> {
-    let mut src = TtIter::new(&tt);
+fn parse_inner(src: &tt::Subtree, mode: Mode) -> impl Iterator<Item = Result<Op<'_>, ExpandError>> {
+    let mut src = TtIter::new(src);
     std::iter::from_fn(move || {
         let first = src.next()?;
         Some(next_op(first, &mut src, mode))
     })
-    .collect()
 }
 
 macro_rules! err {
@@ -81,20 +83,21 @@ macro_rules! bail {
     };
 }
 
-fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Result<Op, ExpandError> {
+fn next_op<'a>(
+    first: &'a tt::TokenTree,
+    src: &mut TtIter<'a>,
+    mode: Mode,
+) -> Result<Op<'a>, ExpandError> {
     let res = match first {
-        tt::TokenTree::Leaf(leaf @ tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
+        tt::TokenTree::Leaf(tt::Leaf::Punct(tt::Punct { char: '$', .. })) => {
             // Note that the '$' itself is a valid token inside macro_rules.
             let second = match src.next() {
-                None => return Ok(Op::Leaf(leaf.clone())),
+                None => return Ok(Op::TokenTree(first)),
                 Some(it) => it,
             };
             match second {
                 tt::TokenTree::Subtree(subtree) => {
                     let (separator, kind) = parse_repeat(src)?;
-                    let delimiter = subtree.delimiter;
-                    let tokens = parse_inner(&subtree, mode);
-                    let subtree = MetaTemplate { tokens, delimiter };
                     Op::Repeat { subtree, separator, kind }
                 }
                 tt::TokenTree::Leaf(leaf) => match leaf {
@@ -104,18 +107,18 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
                         if punct.char != '_' {
                             return Err(ExpandError::UnexpectedToken);
                         }
-                        let name = UNDERSCORE.clone();
+                        let name = &UNDERSCORE;
                         let kind = eat_fragment_kind(src, mode)?;
                         Op::Var { name, kind }
                     }
                     tt::Leaf::Ident(ident) => {
-                        let name = ident.text.clone();
+                        let name = &ident.text;
                         let kind = eat_fragment_kind(src, mode)?;
                         Op::Var { name, kind }
                     }
                     tt::Leaf::Literal(lit) => {
-                        if is_boolean_literal(&lit) {
-                            let name = lit.text.clone();
+                        if is_boolean_literal(lit) {
+                            let name = &lit.text;
                             let kind = eat_fragment_kind(src, mode)?;
                             Op::Var { name, kind }
                         } else {
@@ -125,22 +128,19 @@ fn next_op<'a>(first: &tt::TokenTree, src: &mut TtIter<'a>, mode: Mode) -> Resul
                 },
             }
         }
-        tt::TokenTree::Leaf(tt) => Op::Leaf(tt.clone()),
-        tt::TokenTree::Subtree(subtree) => {
-            let delimiter = subtree.delimiter;
-            let tokens = parse_inner(&subtree, mode);
-            let subtree = MetaTemplate { tokens, delimiter };
-            Op::Subtree(subtree)
-        }
+        tt => Op::TokenTree(tt),
     };
     Ok(res)
 }
 
-fn eat_fragment_kind<'a>(src: &mut TtIter<'a>, mode: Mode) -> Result<Option<SmolStr>, ExpandError> {
+fn eat_fragment_kind<'a>(
+    src: &mut TtIter<'a>,
+    mode: Mode,
+) -> Result<Option<&'a SmolStr>, ExpandError> {
     if let Mode::Pattern = mode {
         src.expect_char(':').map_err(|()| err!("bad fragment specifier 1"))?;
         let ident = src.expect_ident().map_err(|()| err!("bad fragment specifier 1"))?;
-        return Ok(Some(ident.text.clone()));
+        return Ok(Some(&ident.text));
     };
     Ok(None)
 }
diff --git a/crates/proc_macro_api/src/msg.rs b/crates/proc_macro_api/src/msg.rs
index 4cd5721016..f84ebdbc57 100644
--- a/crates/proc_macro_api/src/msg.rs
+++ b/crates/proc_macro_api/src/msg.rs
@@ -58,13 +58,7 @@ pub trait Message: Serialize + DeserializeOwned {
     fn read(inp: &mut impl BufRead) -> io::Result<Option<Self>> {
         Ok(match read_json(inp)? {
             None => None,
-            Some(text) => {
-                let mut deserializer = serde_json::Deserializer::from_str(&text);
-                // Note that some proc-macro generate very deep syntax tree
-                // We have to disable the current limit of serde here
-                deserializer.disable_recursion_limit();
-                Some(Self::deserialize(&mut deserializer)?)
-            }
+            Some(text) => Some(serde_json::from_str(&text)?),
         })
     }
     fn write(self, out: &mut impl Write) -> io::Result<()> {
diff --git a/crates/proc_macro_api/src/process.rs b/crates/proc_macro_api/src/process.rs
index 6d6ab88886..d68723ada3 100644
--- a/crates/proc_macro_api/src/process.rs
+++ b/crates/proc_macro_api/src/process.rs
@@ -92,11 +92,10 @@ fn client_loop(task_rx: Receiver<Task>, mut process: Process) {
     for Task { req, result_tx } in task_rx {
         match send_request(&mut stdin, &mut stdout, req) {
             Ok(res) => result_tx.send(res).unwrap(),
-            Err(err) => {
+            Err(_err) => {
                 log::error!(
-                    "proc macro server crashed, server process state: {:?}, server request error: {:?}",
-                    process.child.try_wait(),
-                    err
+                    "proc macro server crashed, server process state: {:?}",
+                    process.child.try_wait()
                 );
                 let res = Response::Error(ResponseError {
                     code: ErrorCode::ServerErrorEnd,
diff --git a/crates/proc_macro_srv/src/rustc_server.rs b/crates/proc_macro_srv/src/rustc_server.rs
index b54aa1f3bf..503f4c1014 100644
--- a/crates/proc_macro_srv/src/rustc_server.rs
+++ b/crates/proc_macro_srv/src/rustc_server.rs
@@ -204,18 +204,17 @@ pub mod token_stream {
                 let content = subtree
                     .token_trees
                     .iter()
-                    .fold((String::new(), true), |(last, last_to_joint), tkn| {
-                        let s = [last, to_text(tkn)].join(if last_to_joint { "" } else { " " });
-                        let mut is_joint = false;
+                    .map(|tkn| {
+                        let s = to_text(tkn);
                         if let tt::TokenTree::Leaf(tt::Leaf::Punct(punct)) = tkn {
-                            if punct.spacing == tt::Spacing::Joint {
-                                is_joint = true;
+                            if punct.spacing == tt::Spacing::Alone {
+                                return s + " ";
                             }
                         }
-                        (s, is_joint)
+                        s
                     })
-                    .0;
-
+                    .collect::<Vec<_>>()
+                    .concat();
                 let (open, close) = match subtree.delimiter.map(|it| it.kind) {
                     None => ("", ""),
                     Some(tt::DelimiterKind::Brace) => ("{", "}"),
@@ -711,32 +710,4 @@ mod tests {
         assert_eq!(srv.character('c').text, "'c'");
         assert_eq!(srv.byte_string(b"1234586\x88").text, "b\"1234586\\x88\"");
     }
-
-    #[test]
-    fn test_rustc_server_to_string() {
-        let s = TokenStream {
-            subtree: tt::Subtree {
-                delimiter: None,
-                token_trees: vec![
-                    tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
-                        text: "struct".into(),
-                        id: tt::TokenId::unspecified(),
-                    })),
-                    tt::TokenTree::Leaf(tt::Leaf::Ident(tt::Ident {
-                        text: "T".into(),
-                        id: tt::TokenId::unspecified(),
-                    })),
-                    tt::TokenTree::Subtree(tt::Subtree {
-                        delimiter: Some(tt::Delimiter {
-                            id: tt::TokenId::unspecified(),
-                            kind: tt::DelimiterKind::Brace,
-                        }),
-                        token_trees: vec![],
-                    }),
-                ],
-            },
-        };
-
-        assert_eq!(s.to_string(), "struct T {}");
-    }
 }
diff --git a/crates/project_model/Cargo.toml b/crates/project_model/Cargo.toml
index a65e422612..c55e857092 100644
--- a/crates/project_model/Cargo.toml
+++ b/crates/project_model/Cargo.toml
@@ -16,7 +16,7 @@ cargo_metadata = "=0.12.0"
 serde = { version = "1.0.106", features = ["derive"] }
 serde_json = "1.0.48"
 anyhow = "1.0.26"
-itertools = "0.10.0"
+itertools = "0.9.0"
 
 arena = { path = "../arena", version = "0.0.0" }
 cfg = { path = "../cfg", version = "0.0.0" }
diff --git a/crates/project_model/src/cargo_workspace.rs b/crates/project_model/src/cargo_workspace.rs
index 1700cb8a71..bb3b6f2efb 100644
--- a/crates/project_model/src/cargo_workspace.rs
+++ b/crates/project_model/src/cargo_workspace.rs
@@ -1,7 +1,6 @@
 //! FIXME: write short doc here
 
 use std::{
-    convert::TryInto,
     ffi::OsStr,
     ops,
     path::{Path, PathBuf},
@@ -197,23 +196,8 @@ impl CargoWorkspace {
         if let Some(target) = target {
             meta.other_options(vec![String::from("--filter-platform"), target]);
         }
-
         let mut meta = meta.exec().with_context(|| {
-            let cwd: Option<AbsPathBuf> =
-                std::env::current_dir().ok().and_then(|p| p.try_into().ok());
-
-            let workdir = cargo_toml
-                .parent()
-                .map(|p| p.to_path_buf())
-                .or(cwd)
-                .map(|dir| dir.to_string_lossy().to_string())
-                .unwrap_or_else(|| "<failed to get path>".into());
-
-            format!(
-                "Failed to run `cargo metadata --manifest-path {}` in `{}`",
-                cargo_toml.display(),
-                workdir
-            )
+            format!("Failed to run `cargo metadata --manifest-path {}`", cargo_toml.display())
         })?;
 
         let mut out_dir_by_id = FxHashMap::default();
@@ -350,11 +334,6 @@ pub(crate) fn load_extern_resources(
     let mut cmd = Command::new(toolchain::cargo());
     cmd.args(&["check", "--message-format=json", "--manifest-path"]).arg(cargo_toml);
 
-    // --all-targets includes tests, benches and examples in addition to the
-    // default lib and bins. This is an independent concept from the --targets
-    // flag below.
-    cmd.arg("--all-targets");
-
     if let Some(target) = &cargo_features.target {
         cmd.args(&["--target", target]);
     }
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 0a63593fb4..53e70eaf7b 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -17,9 +17,8 @@ path = "src/bin/main.rs"
 [dependencies]
 anyhow = "1.0.26"
 crossbeam-channel = "0.5.0"
-dissimilar = "1.0.2"
 env_logger = { version = "0.8.1", default-features = false }
-itertools = "0.10.0"
+itertools = "0.9.0"
 jod-thread = "0.1.0"
 log = "0.4.8"
 lsp-types = { version = "0.86.0", features = ["proposed"] }
diff --git a/crates/rust-analyzer/src/diff.rs b/crates/rust-analyzer/src/diff.rs
deleted file mode 100644
index 231be58077..0000000000
--- a/crates/rust-analyzer/src/diff.rs
+++ /dev/null
@@ -1,53 +0,0 @@
-//! Generate minimal `TextEdit`s from different text versions
-use dissimilar::Chunk;
-use ide::{TextEdit, TextRange, TextSize};
-
-pub(crate) fn diff(left: &str, right: &str) -> TextEdit {
-    let chunks = dissimilar::diff(left, right);
-    textedit_from_chunks(chunks)
-}
-
-fn textedit_from_chunks(chunks: Vec<dissimilar::Chunk>) -> TextEdit {
-    let mut builder = TextEdit::builder();
-    let mut pos = TextSize::default();
-
-    let mut chunks = chunks.into_iter().peekable();
-    while let Some(chunk) = chunks.next() {
-        if let (Chunk::Delete(deleted), Some(&Chunk::Insert(inserted))) = (chunk, chunks.peek()) {
-            chunks.next().unwrap();
-            let deleted_len = TextSize::of(deleted);
-            builder.replace(TextRange::at(pos, deleted_len), inserted.into());
-            pos += deleted_len;
-            continue;
-        }
-
-        match chunk {
-            Chunk::Equal(text) => {
-                pos += TextSize::of(text);
-            }
-            Chunk::Delete(deleted) => {
-                let deleted_len = TextSize::of(deleted);
-                builder.delete(TextRange::at(pos, deleted_len));
-                pos += deleted_len;
-            }
-            Chunk::Insert(inserted) => {
-                builder.insert(pos, inserted.into());
-            }
-        }
-    }
-    builder.finish()
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    #[test]
-    fn diff_applies() {
-        let mut original = String::from("fn foo(a:u32){\n}");
-        let result = "fn foo(a: u32) {}";
-        let edit = diff(&original, result);
-        edit.apply(&mut original);
-        assert_eq!(original, result);
-    }
-}
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 948cfc17ce..374fb5302b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -31,7 +31,6 @@ use serde_json::to_value;
 use stdx::{format_to, split_once};
 use syntax::{algo, ast, AstNode, TextRange, TextSize};
 
-use crate::diff::diff;
 use crate::{
     cargo_target_spec::CargoTargetSpec,
     config::RustfmtConfig,
@@ -682,7 +681,7 @@ pub(crate) fn handle_completion_resolve(
             &snap.config.completion,
             FilePosition { file_id, offset },
             &resolve_data.full_import_path,
-            resolve_data.imported_name,
+            &resolve_data.imported_name,
         )?
         .into_iter()
         .flat_map(|edit| {
@@ -841,7 +840,7 @@ pub(crate) fn handle_formatting(
     let crate_ids = snap.analysis.crate_for(file_id)?;
 
     let file_line_index = snap.analysis.file_line_index(file_id)?;
-    let file_line_endings = snap.file_line_endings(file_id);
+    let end_position = to_proto::position(&file_line_index, TextSize::of(file.as_str()));
 
     let mut rustfmt = match &snap.config.rustfmt {
         RustfmtConfig::Rustfmt { extra_args } => {
@@ -862,18 +861,16 @@ pub(crate) fn handle_formatting(
         }
     };
 
-    let mut rustfmt =
-        rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).stderr(Stdio::piped()).spawn()?;
+    let mut rustfmt = rustfmt.stdin(Stdio::piped()).stdout(Stdio::piped()).spawn()?;
 
     rustfmt.stdin.as_mut().unwrap().write_all(file.as_bytes())?;
 
     let output = rustfmt.wait_with_output()?;
     let captured_stdout = String::from_utf8(output.stdout)?;
-    let captured_stderr = String::from_utf8(output.stderr).unwrap_or_default();
 
     if !output.status.success() {
         match output.status.code() {
-            Some(1) if !captured_stderr.contains("not installed") => {
+            Some(1) => {
                 // While `rustfmt` doesn't have a specific exit code for parse errors this is the
                 // likely cause exiting with 1. Most Language Servers swallow parse errors on
                 // formatting because otherwise an error is surfaced to the user on top of the
@@ -889,9 +886,8 @@ pub(crate) fn handle_formatting(
                     format!(
                         r#"rustfmt exited with:
                            Status: {}
-                           stdout: {}
-                           stderr: {}"#,
-                        output.status, captured_stdout, captured_stderr,
+                           stdout: {}"#,
+                        output.status, captured_stdout,
                     ),
                 )
                 .into());
@@ -903,11 +899,10 @@ pub(crate) fn handle_formatting(
         // The document is already formatted correctly -- no edits needed.
         Ok(None)
     } else {
-        Ok(Some(to_proto::text_edit_vec(
-            &file_line_index,
-            file_line_endings,
-            diff(&file, &captured_stdout),
-        )))
+        Ok(Some(vec![lsp_types::TextEdit {
+            range: Range::new(Position::new(0, 0), end_position),
+            new_text: captured_stdout,
+        }]))
     }
 }
 
diff --git a/crates/rust-analyzer/src/lib.rs b/crates/rust-analyzer/src/lib.rs
index c9494e3005..d538ad69a1 100644
--- a/crates/rust-analyzer/src/lib.rs
+++ b/crates/rust-analyzer/src/lib.rs
@@ -34,7 +34,6 @@ mod request_metrics;
 mod lsp_utils;
 mod thread_pool;
 mod document;
-mod diff;
 pub mod lsp_ext;
 pub mod config;
 
diff --git a/crates/rust-analyzer/src/semantic_tokens.rs b/crates/rust-analyzer/src/semantic_tokens.rs
index c2f6a655d4..5c4366f16e 100644
--- a/crates/rust-analyzer/src/semantic_tokens.rs
+++ b/crates/rust-analyzer/src/semantic_tokens.rs
@@ -44,6 +44,7 @@ define_semantic_token_types![
     (ESCAPE_SEQUENCE, "escapeSequence"),
     (FORMAT_SPECIFIER, "formatSpecifier"),
     (GENERIC, "generic"),
+    (CONST_PARAMETER, "constParameter"),
     (LIFETIME, "lifetime"),
     (LABEL, "label"),
     (PUNCTUATION, "punctuation"),
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 1a38e79f08..999b183515 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -42,6 +42,7 @@ pub(crate) fn symbol_kind(symbol_kind: SymbolKind) -> lsp_types::SymbolKind {
         SymbolKind::Field => lsp_types::SymbolKind::Field,
         SymbolKind::Static => lsp_types::SymbolKind::Constant,
         SymbolKind::Const => lsp_types::SymbolKind::Constant,
+        SymbolKind::ConstParam => lsp_types::SymbolKind::Constant,
         SymbolKind::Impl => lsp_types::SymbolKind::Object,
         SymbolKind::Local
         | SymbolKind::SelfParam
@@ -378,6 +379,7 @@ fn semantic_token_type_and_modifiers(
             SymbolKind::Impl => lsp_types::SemanticTokenType::TYPE,
             SymbolKind::Field => lsp_types::SemanticTokenType::PROPERTY,
             SymbolKind::TypeParam => lsp_types::SemanticTokenType::TYPE_PARAMETER,
+            SymbolKind::ConstParam => semantic_tokens::CONST_PARAMETER,
             SymbolKind::LifetimeParam => semantic_tokens::LIFETIME,
             SymbolKind::Label => semantic_tokens::LABEL,
             SymbolKind::ValueParam => lsp_types::SemanticTokenType::PARAMETER,
diff --git a/crates/ssr/Cargo.toml b/crates/ssr/Cargo.toml
index 339eda86a3..98ed25fb69 100644
--- a/crates/ssr/Cargo.toml
+++ b/crates/ssr/Cargo.toml
@@ -12,7 +12,7 @@ doctest = false
 
 [dependencies]
 rustc-hash = "1.1.0"
-itertools = "0.10.0"
+itertools = "0.9.0"
 
 text_edit = { path = "../text_edit", version = "0.0.0" }
 syntax = { path = "../syntax", version = "0.0.0" }
diff --git a/crates/ssr/src/matching.rs b/crates/ssr/src/matching.rs
index 6cf8314317..99b187311a 100644
--- a/crates/ssr/src/matching.rs
+++ b/crates/ssr/src/matching.rs
@@ -473,9 +473,7 @@ impl<'db, 'sema> Matcher<'db, 'sema> {
                         }
                         SyntaxElement::Node(n) => {
                             if let Some(first_token) = n.first_token() {
-                                if Some(first_token.text().as_str())
-                                    == next_pattern_token.as_deref()
-                                {
+                                if Some(first_token.to_string()) == next_pattern_token {
                                     if let Some(SyntaxElement::Node(p)) = pattern.next() {
                                         // We have a subtree that starts with the next token in our pattern.
                                         self.attempt_match_token_tree(phase, &p, &n)?;
diff --git a/crates/syntax/Cargo.toml b/crates/syntax/Cargo.toml
index 5d8389ade5..21015591c7 100644
--- a/crates/syntax/Cargo.toml
+++ b/crates/syntax/Cargo.toml
@@ -11,7 +11,7 @@ edition = "2018"
 doctest = false
 
 [dependencies]
-itertools = "0.10.0"
+itertools = "0.9.0"
 rowan = "0.10.0"
 rustc_lexer = { version = "695.0.0", package = "rustc-ap-rustc_lexer" }
 rustc-hash = "1.1.0"
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 2aa472fb49..c45cb514a0 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -193,14 +193,6 @@ impl ast::UseTreeList {
             .and_then(ast::UseTree::cast)
             .expect("UseTreeLists are always nested in UseTrees")
     }
-
-    pub fn has_inner_comment(&self) -> bool {
-        self.syntax()
-            .children_with_tokens()
-            .filter_map(|it| it.into_token())
-            .find_map(ast::Comment::cast)
-            .is_some()
-    }
 }
 
 impl ast::Impl {
diff --git a/editors/code/package.json b/editors/code/package.json
index 587f11b902..13749a0849 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -283,14 +283,6 @@
                     "default": null,
                     "markdownDescription": "Path to rust-analyzer executable (points to bundled binary by default). If this is set, then `#rust-analyzer.updates.channel#` setting is not used"
                 },
-                "rust-analyzer.server.extraEnv": {
-                    "type": [
-                        "null",
-                        "object"
-                    ],
-                    "default": null,
-                    "markdownDescription": "Extra environment variables that will be passed to the rust-analyzer executable. Useful for passing e.g. `RA_LOG` for debugging."
-                },
                 "rust-analyzer.trace.server": {
                     "type": "string",
                     "scope": "window",
diff --git a/editors/code/src/client.ts b/editors/code/src/client.ts
index 539e487ec9..63ab82dde7 100644
--- a/editors/code/src/client.ts
+++ b/editors/code/src/client.ts
@@ -6,10 +6,6 @@ import { DocumentSemanticsTokensSignature, DocumentSemanticsTokensEditsSignature
 import { assert } from './util';
 import { WorkspaceEdit } from 'vscode';
 
-export interface Env {
-    [name: string]: string;
-}
-
 function renderCommand(cmd: ra.CommandLink) {
     return `[${cmd.title}](command:${cmd.command}?${encodeURIComponent(JSON.stringify(cmd.arguments))} '${cmd.tooltip!}')`;
 }
@@ -31,17 +27,14 @@ async function semanticHighlightingWorkaround<R, F extends (...args: any[]) => v
     return res;
 }
 
-export function createClient(serverPath: string, cwd: string, extraEnv: Env): lc.LanguageClient {
+export function createClient(serverPath: string, cwd: string): lc.LanguageClient {
     // '.' Is the fallback if no folder is open
     // TODO?: Workspace folders support Uri's (eg: file://test.txt).
     // It might be a good idea to test if the uri points to a file.
 
-    const newEnv = Object.assign({}, process.env);
-    Object.assign(newEnv, extraEnv);
-
     const run: lc.Executable = {
         command: serverPath,
-        options: { cwd, env: newEnv },
+        options: { cwd },
     };
     const serverOptions: lc.ServerOptions = {
         run,
diff --git a/editors/code/src/commands.ts b/editors/code/src/commands.ts
index b12e134ca9..9d4823a34d 100644
--- a/editors/code/src/commands.ts
+++ b/editors/code/src/commands.ts
@@ -469,14 +469,8 @@ export function resolveCodeAction(ctx: Ctx): Cmd {
         if (!item.edit) {
             return;
         }
-        const itemEdit = item.edit;
-        const edit = client.protocol2CodeConverter.asWorkspaceEdit(itemEdit);
-        // filter out all text edits and recreate the WorkspaceEdit without them so we can apply
-        // snippet edits on our own
-        const itemEditWithoutTextEdits = { ...item, documentChanges: itemEdit.documentChanges?.filter(change => "kind" in change) };
-        const editWithoutTextEdits = client.protocol2CodeConverter.asWorkspaceEdit(itemEditWithoutTextEdits);
-        await applySnippetWorkspaceEdit(edit);
-        await vscode.workspace.applyEdit(editWithoutTextEdits);
+        const edit = client.protocol2CodeConverter.asWorkspaceEdit(item.edit);
+        await vscode.workspace.applyEdit(edit);
     };
 }
 
diff --git a/editors/code/src/config.ts b/editors/code/src/config.ts
index fe9f3b4a87..848e92af99 100644
--- a/editors/code/src/config.ts
+++ b/editors/code/src/config.ts
@@ -1,5 +1,4 @@
 import * as vscode from 'vscode';
-import { Env } from './client';
 import { log } from "./util";
 
 export type UpdatesChannel = "stable" | "nightly";
@@ -14,7 +13,6 @@ export class Config {
     readonly rootSection = "rust-analyzer";
     private readonly requiresReloadOpts = [
         "serverPath",
-        "server",
         "cargo",
         "procMacro",
         "files",
@@ -94,7 +92,6 @@ export class Config {
     }
 
     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"); }
     get traceExtension() { return this.get<boolean>("trace.extension"); }
diff --git a/editors/code/src/ctx.ts b/editors/code/src/ctx.ts
index e7585184bd..d39864d330 100644
--- a/editors/code/src/ctx.ts
+++ b/editors/code/src/ctx.ts
@@ -24,7 +24,7 @@ export class Ctx {
         serverPath: string,
         cwd: string,
     ): Promise<Ctx> {
-        const client = createClient(serverPath, cwd, config.serverExtraEnv);
+        const client = createClient(serverPath, cwd);
 
         const statusBar = vscode.window.createStatusBarItem(vscode.StatusBarAlignment.Left);
         extCtx.subscriptions.push(statusBar);


Test patch:
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index a61282d5a7..8d431b9201 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -2375,3 +2375,19 @@ fn infer_operator_overload() {
         "#]],
     );
 }
+
+#[test]
+fn infer_const_params() {
+    check_infer(
+        r#"
+        fn foo<const FOO: usize>() {
+            let bar = FOO;
+        }
+        "#,
+        expect![[r#"
+            27..49 '{     ...FOO; }': ()
+            37..40 'bar': usize
+            43..46 'FOO': usize
+        "#]],
+    );
+}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlighting.html b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
index 72ff9dd40e..02270b0770 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlighting.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlighting.html
@@ -118,6 +118,10 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="keyword control">loop</span> <span class="punctuation">{</span><span class="punctuation">}</span>
 <span class="punctuation">}</span>
 
+<span class="keyword">fn</span> <span class="function declaration">const_param</span><span class="punctuation">&lt;</span><span class="keyword">const</span> <span class="const_param declaration">FOO</span><span class="punctuation">:</span> <span class="builtin_type">usize</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="builtin_type">usize</span> <span class="punctuation">{</span>
+    <span class="const_param">FOO</span>
+<span class="punctuation">}</span>
+
 <span class="keyword">use</span> <span class="module">ops</span><span class="operator">::</span><span class="trait">Fn</span><span class="punctuation">;</span>
 <span class="keyword">fn</span> <span class="function declaration">baz</span><span class="punctuation">&lt;</span><span class="type_param declaration">F</span><span class="punctuation">:</span> <span class="trait">Fn</span><span class="punctuation">(</span><span class="punctuation">)</span> <span class="operator">-&gt;</span> <span class="punctuation">(</span><span class="punctuation">)</span><span class="punctuation">&gt;</span><span class="punctuation">(</span><span class="value_param declaration callable">f</span><span class="punctuation">:</span> <span class="type_param">F</span><span class="punctuation">)</span> <span class="punctuation">{</span>
     <span class="value_param callable">f</span><span class="punctuation">(</span><span class="punctuation">)</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index e0df0d2b52..30b5b648e9 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -91,6 +91,10 @@ fn never() -> ! {
     loop {}
 }
 
+fn const_param<const FOO: usize>() -> usize {
+    FOO
+}
+
 use ops::Fn;
 fn baz<F: Fn() -> ()>(f: F) {
     f()
diff --git a/crates/rust-analyzer/tests/rust-analyzer/main.rs b/crates/rust-analyzer/tests/rust-analyzer/main.rs
index 84db0856d4..e51eb26261 100644
--- a/crates/rust-analyzer/tests/rust-analyzer/main.rs
+++ b/crates/rust-analyzer/tests/rust-analyzer/main.rs
@@ -190,10 +190,15 @@ pub use std::collections::HashMap;
         },
         json!([
             {
-                "newText": "",
+                "newText": r#"mod bar;
+
+fn main() {}
+
+pub use std::collections::HashMap;
+"#,
                 "range": {
-                    "end": { "character": 0, "line": 3 },
-                    "start": { "character": 11, "line": 2 }
+                    "end": { "character": 0, "line": 6 },
+                    "start": { "character": 0, "line": 0 }
                 }
             }
         ]),
@@ -243,17 +248,17 @@ pub use std::collections::HashMap;
         },
         json!([
             {
-                "newText": "",
-                "range": {
-                    "end": { "character": 0, "line": 3 },
-                    "start": { "character": 17, "line": 2 }
-                }
-            },
-            {
-                "newText": "",
+                "newText": r#"mod bar;
+
+async fn test() {}
+
+fn main() {}
+
+pub use std::collections::HashMap;
+"#,
                 "range": {
-                    "end": { "character": 0, "line": 6 },
-                    "start": { "character": 11, "line": 5 }
+                    "end": { "character": 0, "line": 9 },
+                    "start": { "character": 0, "line": 0 }
                 }
             }
         ]),
diff --git a/xtask/tests/tidy.rs b/xtask/tests/tidy.rs
index d1ffb70ad1..6bfa922e62 100644
--- a/xtask/tests/tidy.rs
+++ b/xtask/tests/tidy.rs
@@ -139,7 +139,7 @@ fn deny_clippy(path: &PathBuf, text: &String) {
         return;
     }
 
-    if text.contains("\u{61}llow(clippy") {
+    if text.contains("[\u{61}llow(clippy") {
         panic!(
             "\n\nallowing lints is forbidden: {}.
 rust-analyzer intentionally doesn't check clippy on CI.