Repository: rust-lang/rust-analyzer
Pull request #18797 (2024-12-30 19:23:39)

Fix replace-if-let-with-match generates non-exhausive match
### Why
Closes: #8690 and #10583

Continuation of #10491. r? @Veykril if you don't mind?

The reason why the original author were unable to reproduce the first case in #8690 might be because of misuses of `minicore`, which creates an error in the types and make it fallback to the wildcard. Maybe we should give more information about `minicore` in the docs?

I extended the patterns marked as `FIXME` in #10491, while also covering the cases involving literals.

### What
- Add test cases for `replace_if_let_with_match`
- Cover more cases for using wildcards on `make_else_arm`



Patch:
diff --git a/crates/hir-def/src/nameres/collector.rs b/crates/hir-def/src/nameres/collector.rs
index 6474bb7e5e..5d19b849a7 100644
--- a/crates/hir-def/src/nameres/collector.rs
+++ b/crates/hir-def/src/nameres/collector.rs
@@ -1451,7 +1451,13 @@ impl DefCollector<'_> {
         depth: usize,
         container: ItemContainerId,
     ) {
-        let recursion_limit = Limit::new(self.def_map.recursion_limit() as usize);
+        let recursion_limit = self.def_map.recursion_limit() as usize;
+        let recursion_limit = Limit::new(if cfg!(test) {
+            // Without this, `body::tests::your_stack_belongs_to_me` stack-overflows in debug
+            std::cmp::min(32, recursion_limit)
+        } else {
+            recursion_limit
+        });
         if recursion_limit.check(depth).is_err() {
             cov_mark::hit!(macro_expansion_overflow);
             tracing::warn!("macro expansion is too deep");
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index a4e052a036..de8ce56df6 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -474,9 +474,7 @@ impl HirDisplay for ProjectionTy {
 
         let trait_ref = self.trait_ref(f.db);
         write!(f, "<")?;
-        trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
-        write!(f, " as ")?;
-        trait_ref.hir_fmt(f)?;
+        fmt_trait_ref(f, &trait_ref, true)?;
         write!(
             f,
             ">::{}",
@@ -1777,14 +1775,32 @@ fn write_bounds_like_dyn_trait(
     Ok(())
 }
 
+fn fmt_trait_ref(
+    f: &mut HirFormatter<'_>,
+    tr: &TraitRef,
+    use_as: bool,
+) -> Result<(), HirDisplayError> {
+    if f.should_truncate() {
+        return write!(f, "{TYPE_HINT_TRUNCATION}");
+    }
+
+    tr.self_type_parameter(Interner).hir_fmt(f)?;
+    if use_as {
+        write!(f, " as ")?;
+    } else {
+        write!(f, ": ")?;
+    }
+    let trait_ = tr.hir_trait_id();
+    f.start_location_link(trait_.into());
+    write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
+    f.end_location_link();
+    let substs = tr.substitution.as_slice(Interner);
+    hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
+}
+
 impl HirDisplay for TraitRef {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        let trait_ = self.hir_trait_id();
-        f.start_location_link(trait_.into());
-        write!(f, "{}", f.db.trait_data(trait_).name.display(f.db.upcast(), f.edition()))?;
-        f.end_location_link();
-        let substs = self.substitution.as_slice(Interner);
-        hir_fmt_generics(f, &substs[1..], None, substs[0].ty(Interner))
+        fmt_trait_ref(f, self, false)
     }
 }
 
@@ -1795,17 +1811,10 @@ impl HirDisplay for WhereClause {
         }
 
         match self {
-            WhereClause::Implemented(trait_ref) => {
-                trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
-                write!(f, ": ")?;
-                trait_ref.hir_fmt(f)?;
-            }
+            WhereClause::Implemented(trait_ref) => trait_ref.hir_fmt(f)?,
             WhereClause::AliasEq(AliasEq { alias: AliasTy::Projection(projection_ty), ty }) => {
                 write!(f, "<")?;
-                let trait_ref = &projection_ty.trait_ref(f.db);
-                trait_ref.self_type_parameter(Interner).hir_fmt(f)?;
-                write!(f, " as ")?;
-                trait_ref.hir_fmt(f)?;
+                fmt_trait_ref(f, &projection_ty.trait_ref(f.db), true)?;
                 write!(f, ">::",)?;
                 let type_alias = from_assoc_type_id(projection_ty.associated_ty_id);
                 f.start_location_link(type_alias.into());
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index a5a6bebe6d..959d62d595 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -22,7 +22,7 @@ use itertools::Itertools;
 use crate::{
     Adt, AsAssocItem, AssocItem, AssocItemContainer, Const, ConstParam, Enum, ExternCrateDecl,
     Field, Function, GenericParam, HasCrate, HasVisibility, Impl, LifetimeParam, Macro, Module,
-    SelfParam, Static, Struct, Trait, TraitAlias, TraitRef, TupleField, TyBuilder, Type, TypeAlias,
+    SelfParam, Static, Struct, Trait, TraitAlias, TupleField, TyBuilder, Type, TypeAlias,
     TypeOrConstParam, TypeParam, Union, Variant,
 };
 
@@ -743,12 +743,6 @@ impl HirDisplay for Static {
     }
 }
 
-impl HirDisplay for TraitRef {
-    fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
-        self.trait_ref.hir_fmt(f)
-    }
-}
-
 impl HirDisplay for Trait {
     fn hir_fmt(&self, f: &mut HirFormatter<'_>) -> Result<(), HirDisplayError> {
         write_trait_header(self, f)?;
diff --git a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
index 56dd6cf29a..4313cc1ac9 100644
--- a/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
+++ b/crates/ide-assists/src/handlers/replace_if_let_with_match.rs
@@ -17,7 +17,7 @@ use syntax::{
 };
 
 use crate::{
-    utils::{does_nested_pattern, does_pat_match_variant, unwrap_trivial_block},
+    utils::{does_pat_match_variant, does_pat_variant_nested_or_literal, unwrap_trivial_block},
     AssistContext, AssistId, AssistKind, Assists,
 };
 
@@ -163,7 +163,7 @@ fn make_else_arm(
                 Some(it) => {
                     if does_pat_match_variant(pat, &it.sad_pattern()) {
                         it.happy_pattern_wildcard()
-                    } else if does_nested_pattern(pat) {
+                    } else if does_pat_variant_nested_or_literal(ctx, pat) {
                         make::wildcard_pat().into()
                     } else {
                         it.sad_pattern()
@@ -702,11 +702,11 @@ fn main() {
     }
 
     #[test]
-    fn nested_type() {
+    fn test_if_let_with_match_nested_tuple_struct() {
         check_assist(
             replace_if_let_with_match,
             r#"
-//- minicore: result
+//- minicore: result, option
 fn foo(x: Result<i32, ()>) {
     let bar: Result<_, ()> = Ok(Some(1));
     $0if let Ok(Some(_)) = bar {
@@ -724,6 +724,700 @@ fn foo(x: Result<i32, ()>) {
         _ => (),
     }
 }
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+struct MyStruct(i32, i32);
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct(1, 2));
+    $0if let Ok(MyStruct(a, b)) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+struct MyStruct(i32, i32);
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct(1, 2));
+    match bar {
+        Ok(MyStruct(a, b)) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_slice() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<&[i32], ()>) {
+    let foo: Result<&[_], ()> = Ok(&[0, 1, 2]);
+    $0if let Ok([]) = foo {
+        ()
+    } else {
+        ()
+    }
+}
+        "#,
+            r#"
+fn foo(x: Result<&[i32], ()>) {
+    let foo: Result<&[_], ()> = Ok(&[0, 1, 2]);
+    match foo {
+        Ok([]) => (),
+        _ => (),
+    }
+}
+        "#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<[&'static str; 2], ()>) {
+    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+    $0if let Ok([_, "bar"]) = foobar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<[&'static str; 2], ()>) {
+    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+    match foobar {
+        Ok([_, "bar"]) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<[&'static str; 2], ()>) {
+    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+    $0if let Ok([..]) = foobar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<[&'static str; 2], ()>) {
+    let foobar: Result<_, ()> = Ok(["foo", "bar"]);
+    match foobar {
+        Ok([..]) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<&[&'static str], ()>) {
+    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+    $0if let Ok([a, ..]) = foobar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<&[&'static str], ()>) {
+    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+    match foobar {
+        Ok([a, ..]) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<&[&'static str], ()>) {
+    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+    $0if let Ok([a, .., b, c]) = foobar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<&[&'static str], ()>) {
+    let foobar: Result<&[&'static str], ()> = Ok(&["foo", "bar"]);
+    match foobar {
+        Ok([a, .., b, c]) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<Option<[&'static str; 2]>, ()>) {
+    let foobar: Result<_, ()> = Ok(Some(["foo", "bar"]));
+    $0if let Ok(Some([_, "bar"])) = foobar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<Option<[&'static str; 2]>, ()>) {
+    let foobar: Result<_, ()> = Ok(Some(["foo", "bar"]));
+    match foobar {
+        Ok(Some([_, "bar"])) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_literal() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<&'static str, ()>) {
+    let bar: Result<&_, ()> = Ok("bar");
+    $0if let Ok("foo") = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<&'static str, ()>) {
+    let bar: Result<&_, ()> = Ok("bar");
+    match bar {
+        Ok("foo") => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_tuple() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32, i32), ()>) {
+    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+    $0if let Ok((1, second, third)) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<(i32, i32, i32), ()>) {
+    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+    match bar {
+        Ok((1, second, third)) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32, i32), ()>) {
+    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+    $0if let Ok((first, second, third)) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<(i32, i32, i32), ()>) {
+    let bar: Result<(i32, i32, i32), ()> = Ok((1, 2, 3));
+    match bar {
+        Ok((first, second, third)) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_or() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    $0if let Ok(1 | 2) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    match bar {
+        Ok(1 | 2) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 2));
+    $0if let Ok((b, a) | (a, b)) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 2));
+    match bar {
+        Ok((b, a) | (a, b)) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 2));
+    $0if let Ok((1, a) | (a, 2)) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 2));
+    match bar {
+        Ok((1, a) | (a, 2)) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_range() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    $0if let Ok(1..2) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    match bar {
+        Ok(1..2) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_paren() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 1));
+    $0if let Ok(((1, 2))) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 1));
+    match bar {
+        Ok(((1, 2))) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 1));
+    $0if let Ok(((a, b))) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<(i32, i32), ()>) {
+    let bar: Result<(i32, i32), ()> = Ok((1, 1));
+    match bar {
+        Ok(((a, b))) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_macro() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+    macro_rules! is_42 {
+        () => {
+            42
+        };
+    }
+
+    let bar: Result<i32, ()> = Ok(1);
+    $0if let Ok(is_42!()) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<i32, ()>) {
+    macro_rules! is_42 {
+        () => {
+            42
+        };
+    }
+
+    let bar: Result<i32, ()> = Ok(1);
+    match bar {
+        Ok(is_42!()) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_path() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+enum MyEnum {
+    Foo,
+    Bar,
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo);
+    $0if let Ok(MyEnum::Foo) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+enum MyEnum {
+    Foo,
+    Bar,
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo);
+    match bar {
+        Ok(MyEnum::Foo) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_record() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+struct MyStruct {
+    foo: i32,
+    bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+    $0if let Ok(MyStruct { foo, bar }) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+struct MyStruct {
+    foo: i32,
+    bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+    match bar {
+        Ok(MyStruct { foo, bar }) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+struct MyStruct {
+    foo: i32,
+    bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+    $0if let Ok(MyStruct { foo, bar: 12 }) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+struct MyStruct {
+    foo: i32,
+    bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+    match bar {
+        Ok(MyStruct { foo, bar: 12 }) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+struct MyStruct {
+    foo: i32,
+    bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+    $0if let Ok(MyStruct { foo, .. }) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+struct MyStruct {
+    foo: i32,
+    bar: i32,
+}
+
+fn foo(x: Result<MyStruct, ()>) {
+    let bar: Result<MyStruct, ()> = Ok(MyStruct { foo: 1, bar: 2 });
+    match bar {
+        Ok(MyStruct { foo, .. }) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+enum MyEnum {
+    Foo(i32, i32),
+    Bar { a: i32, b: i32 },
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo(1, 2));
+    $0if let Ok(MyEnum::Bar { a, b }) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+enum MyEnum {
+    Foo(i32, i32),
+    Bar { a: i32, b: i32 },
+}
+
+fn foo(x: Result<MyEnum, ()>) {
+    let bar: Result<MyEnum, ()> = Ok(MyEnum::Foo(1, 2));
+    match bar {
+        Ok(MyEnum::Bar { a, b }) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
+    fn test_if_let_with_match_nested_ident() {
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    $0if let Ok(a @ 1..2) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    match bar {
+        Ok(a @ 1..2) => (),
+        _ => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    $0if let Ok(a) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    match bar {
+        Ok(a) => (),
+        Err(_) => (),
+    }
+}
+"#,
+        );
+
+        check_assist(
+            replace_if_let_with_match,
+            r#"
+//- minicore: result
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    $0if let Ok(a @ b @ c @ d) = bar {
+        ()
+    } else {
+        ()
+    }
+}
+"#,
+            r#"
+fn foo(x: Result<i32, ()>) {
+    let bar: Result<i32, ()> = Ok(1);
+    match bar {
+        Ok(a @ b @ c @ d) => (),
+        Err(_) => (),
+    }
+}
 "#,
         );
     }
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 3c26b04359..ce0bd46e6f 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -316,43 +316,73 @@ pub(crate) fn does_pat_match_variant(pat: &ast::Pat, var: &ast::Pat) -> bool {
     pat_head == var_head
 }
 
-pub(crate) fn does_nested_pattern(pat: &ast::Pat) -> bool {
-    let depth = calc_depth(pat, 0);
+pub(crate) fn does_pat_variant_nested_or_literal(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool {
+    check_pat_variant_nested_or_literal_with_depth(ctx, pat, 0)
+}
+
+fn check_pat_variant_from_enum(ctx: &AssistContext<'_>, pat: &ast::Pat) -> bool {
+    ctx.sema.type_of_pat(pat).map_or(true, |ty: hir::TypeInfo| {
+        ty.adjusted().as_adt().map_or(false, |adt| matches!(adt, hir::Adt::Enum(_)))
+    })
+}
 
-    if 1 < depth {
+fn check_pat_variant_nested_or_literal_with_depth(
+    ctx: &AssistContext<'_>,
+    pat: &ast::Pat,
+    depth_after_refutable: usize,
+) -> bool {
+    if depth_after_refutable > 1 {
         return true;
     }
-    false
-}
 
-fn calc_depth(pat: &ast::Pat, depth: usize) -> usize {
     match pat {
-        ast::Pat::IdentPat(_)
-        | ast::Pat::BoxPat(_)
-        | ast::Pat::RestPat(_)
-        | ast::Pat::LiteralPat(_)
+        ast::Pat::RestPat(_) | ast::Pat::WildcardPat(_) | ast::Pat::RefPat(_) => false,
+
+        ast::Pat::LiteralPat(_)
+        | ast::Pat::RangePat(_)
         | ast::Pat::MacroPat(_)
-        | ast::Pat::OrPat(_)
-        | ast::Pat::ParenPat(_)
         | ast::Pat::PathPat(_)
-        | ast::Pat::WildcardPat(_)
-        | ast::Pat::RangePat(_)
-        | ast::Pat::RecordPat(_)
-        | ast::Pat::RefPat(_)
-        | ast::Pat::SlicePat(_)
-        | ast::Pat::TuplePat(_)
-        | ast::Pat::ConstBlockPat(_) => depth,
-
-        // FIXME: Other patterns may also be nested. Currently it simply supports only `TupleStructPat`
-        ast::Pat::TupleStructPat(pat) => {
-            let mut max_depth = depth;
-            for p in pat.fields() {
-                let d = calc_depth(&p, depth + 1);
-                if d > max_depth {
-                    max_depth = d
-                }
-            }
-            max_depth
+        | ast::Pat::BoxPat(_)
+        | ast::Pat::ConstBlockPat(_) => true,
+
+        ast::Pat::IdentPat(ident_pat) => ident_pat.pat().map_or(false, |pat| {
+            check_pat_variant_nested_or_literal_with_depth(ctx, &pat, depth_after_refutable)
+        }),
+        ast::Pat::ParenPat(paren_pat) => paren_pat.pat().map_or(true, |pat| {
+            check_pat_variant_nested_or_literal_with_depth(ctx, &pat, depth_after_refutable)
+        }),
+        ast::Pat::TuplePat(tuple_pat) => tuple_pat.fields().any(|pat| {
+            check_pat_variant_nested_or_literal_with_depth(ctx, &pat, depth_after_refutable)
+        }),
+        ast::Pat::RecordPat(record_pat) => {
+            let adjusted_next_depth =
+                depth_after_refutable + if check_pat_variant_from_enum(ctx, pat) { 1 } else { 0 };
+            record_pat.record_pat_field_list().map_or(true, |pat| {
+                pat.fields().any(|pat| {
+                    pat.pat().map_or(true, |pat| {
+                        check_pat_variant_nested_or_literal_with_depth(
+                            ctx,
+                            &pat,
+                            adjusted_next_depth,
+                        )
+                    })
+                })
+            })
+        }
+        ast::Pat::OrPat(or_pat) => or_pat.pats().any(|pat| {
+            check_pat_variant_nested_or_literal_with_depth(ctx, &pat, depth_after_refutable)
+        }),
+        ast::Pat::TupleStructPat(tuple_struct_pat) => {
+            let adjusted_next_depth =
+                depth_after_refutable + if check_pat_variant_from_enum(ctx, pat) { 1 } else { 0 };
+            tuple_struct_pat.fields().any(|pat| {
+                check_pat_variant_nested_or_literal_with_depth(ctx, &pat, adjusted_next_depth)
+            })
+        }
+        ast::Pat::SlicePat(slice_pat) => {
+            let mut pats = slice_pat.pats();
+            pats.next() // Edge case for `[..]`
+                .map_or(true, |pat| !matches!(pat, ast::Pat::RestPat(_)) || pats.next().is_some())
         }
     }
 }
diff --git a/crates/ide-db/src/defs.rs b/crates/ide-db/src/defs.rs
index cef292a528..73b73736ce 100644
--- a/crates/ide-db/src/defs.rs
+++ b/crates/ide-db/src/defs.rs
@@ -13,10 +13,10 @@ use either::Either;
 use hir::{
     Adt, AsAssocItem, AsExternAssocItem, AssocItem, AttributeTemplate, BuiltinAttr, BuiltinType,
     Const, Crate, DefWithBody, DeriveHelper, DocLinkDef, ExternAssocItem, ExternCrateDecl, Field,
-    Function, GenericDef, GenericParam, GenericSubstitution, HasContainer, HasVisibility,
-    HirDisplay, Impl, InlineAsmOperand, ItemContainer, Label, Local, Macro, Module, ModuleDef,
-    Name, PathResolution, Semantics, Static, StaticLifetime, Struct, ToolModule, Trait, TraitAlias,
-    TupleField, TypeAlias, Variant, VariantDef, Visibility,
+    Function, GenericParam, GenericSubstitution, HasVisibility, HirDisplay, Impl, InlineAsmOperand,
+    Label, Local, Macro, Module, ModuleDef, Name, PathResolution, Semantics, Static,
+    StaticLifetime, Struct, ToolModule, Trait, TraitAlias, TupleField, TypeAlias, Variant,
+    VariantDef, Visibility,
 };
 use span::Edition;
 use stdx::{format_to, impl_from};
@@ -97,39 +97,9 @@ impl Definition {
     }
 
     pub fn enclosing_definition(&self, db: &RootDatabase) -> Option<Definition> {
-        fn container_to_definition(container: ItemContainer) -> Option<Definition> {
-            match container {
-                ItemContainer::Trait(it) => Some(it.into()),
-                ItemContainer::Impl(it) => Some(it.into()),
-                ItemContainer::Module(it) => Some(it.into()),
-                ItemContainer::ExternBlock() | ItemContainer::Crate(_) => None,
-            }
-        }
         match self {
-            Definition::Macro(it) => Some(it.module(db).into()),
-            Definition::Module(it) => it.parent(db).map(Definition::Module),
-            Definition::Field(it) => Some(it.parent_def(db).into()),
-            Definition::Function(it) => container_to_definition(it.container(db)),
-            Definition::Adt(it) => Some(it.module(db).into()),
-            Definition::Const(it) => container_to_definition(it.container(db)),
-            Definition::Static(it) => container_to_definition(it.container(db)),
-            Definition::Trait(it) => container_to_definition(it.container(db)),
-            Definition::TraitAlias(it) => container_to_definition(it.container(db)),
-            Definition::TypeAlias(it) => container_to_definition(it.container(db)),
-            Definition::Variant(it) => Some(Adt::Enum(it.parent_enum(db)).into()),
-            Definition::SelfType(it) => Some(it.module(db).into()),
             Definition::Local(it) => it.parent(db).try_into().ok(),
-            Definition::GenericParam(it) => Some(it.parent().into()),
-            Definition::Label(it) => it.parent(db).try_into().ok(),
-            Definition::ExternCrateDecl(it) => container_to_definition(it.container(db)),
-            Definition::DeriveHelper(it) => Some(it.derive().module(db).into()),
-            Definition::InlineAsmOperand(it) => it.parent(db).try_into().ok(),
-            Definition::BuiltinAttr(_)
-            | Definition::BuiltinType(_)
-            | Definition::BuiltinLifetime(_)
-            | Definition::TupleField(_)
-            | Definition::ToolModule(_)
-            | Definition::InlineAsmRegOrRegClass(_) => None,
+            _ => None,
         }
     }
 
@@ -962,17 +932,3 @@ impl TryFrom<DefWithBody> for Definition {
         }
     }
 }
-
-impl From<GenericDef> for Definition {
-    fn from(def: GenericDef) -> Self {
-        match def {
-            GenericDef::Function(it) => it.into(),
-            GenericDef::Adt(it) => it.into(),
-            GenericDef::Trait(it) => it.into(),
-            GenericDef::TraitAlias(it) => it.into(),
-            GenericDef::TypeAlias(it) => it.into(),
-            GenericDef::Impl(it) => it.into(),
-            GenericDef::Const(it) => it.into(),
-        }
-    }
-}
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 1431bd8ca2..e3d50fdfa9 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -429,7 +429,7 @@ pub(crate) fn hover_for_definition(
         &notable_traits,
         macro_arm,
         hovered_definition,
-        subst_types.as_ref(),
+        subst_types,
         config,
         edition,
     );
@@ -439,7 +439,7 @@ pub(crate) fn hover_for_definition(
             show_fn_references_action(sema.db, def),
             show_implementations_action(sema.db, def),
             runnable_action(sema, def, file_id),
-            goto_type_action_for_def(sema.db, def, &notable_traits, subst_types, edition),
+            goto_type_action_for_def(sema.db, def, &notable_traits, edition),
         ]
         .into_iter()
         .flatten()
@@ -531,7 +531,6 @@ fn goto_type_action_for_def(
     db: &RootDatabase,
     def: Definition,
     notable_traits: &[(hir::Trait, Vec<(Option<hir::Type>, hir::Name)>)],
-    subst_types: Option<Vec<(hir::Symbol, hir::Type)>>,
     edition: Edition,
 ) -> Option<HoverAction> {
     let mut targets: Vec<hir::ModuleDef> = Vec::new();
@@ -569,12 +568,6 @@ fn goto_type_action_for_def(
         walk_and_push_ty(db, &ty, &mut push_new_def);
     }
 
-    if let Some(subst_types) = subst_types {
-        for (_, ty) in subst_types {
-            walk_and_push_ty(db, &ty, &mut push_new_def);
-        }
-    }
-
     HoverAction::goto_type_from_targets(db, targets, edition)
 }
 
diff --git a/crates/ide/src/hover/render.rs b/crates/ide/src/hover/render.rs
index 03ab9d1ba4..d87c15154e 100644
--- a/crates/ide/src/hover/render.rs
+++ b/crates/ide/src/hover/render.rs
@@ -432,7 +432,7 @@ pub(super) fn definition(
     notable_traits: &[(Trait, Vec<(Option<Type>, Name)>)],
     macro_arm: Option<u32>,
     hovered_definition: bool,
-    subst_types: Option<&Vec<(Symbol, Type)>>,
+    subst_types: Option<Vec<(Symbol, Type)>>,
     config: &HoverConfig,
     edition: Edition,
 ) -> Markup {
@@ -715,17 +715,10 @@ pub(super) fn literal(
     let mut s = format!("```rust\n{ty}\n```\n___\n\n");
     match value {
         Ok(value) => {
-            let backtick_len = value.chars().filter(|c| *c == '`').count();
-            let backticks = "`".repeat(backtick_len + 1);
-
             if let Some(newline) = value.find('\n') {
-                format_to!(
-                    s,
-                    "value of literal (truncated up to newline): {backticks} {} {backticks}",
-                    &value[..newline]
-                )
+                format_to!(s, "value of literal (truncated up to newline): {}", &value[..newline])
             } else {
-                format_to!(s, "value of literal: {backticks} {value} {backticks}")
+                format_to!(s, "value of literal: {value}")
             }
         }
         Err(error) => format_to!(s, "invalid literal: {error}"),
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 1637d578fd..fe2760d2ba 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -96,8 +96,8 @@ pub use crate::{
     join_lines::JoinLinesConfig,
     markup::Markup,
     moniker::{
-        Moniker, MonikerDescriptorKind, MonikerIdentifier, MonikerKind, MonikerResult,
-        PackageInformation, SymbolInformationKind,
+        MonikerDescriptorKind, MonikerKind, MonikerResult, PackageInformation,
+        SymbolInformationKind,
     },
     move_item::Direction,
     navigation_target::{NavigationTarget, TryToNav, UpmappingResult},
diff --git a/crates/ide/src/moniker.rs b/crates/ide/src/moniker.rs
index 052466725f..14781b2129 100644
--- a/crates/ide/src/moniker.rs
+++ b/crates/ide/src/moniker.rs
@@ -3,7 +3,7 @@
 
 use core::fmt;
 
-use hir::{Adt, AsAssocItem, Crate, HirDisplay, MacroKind, Semantics};
+use hir::{Adt, AsAssocItem, AssocItemContainer, Crate, MacroKind, Semantics};
 use ide_db::{
     base_db::{CrateOrigin, LangCrateOrigin},
     defs::{Definition, IdentClass},
@@ -11,7 +11,6 @@ use ide_db::{
     FilePosition, RootDatabase,
 };
 use itertools::Itertools;
-use span::Edition;
 use syntax::{AstNode, SyntaxKind::*, T};
 
 use crate::{doc_links::token_as_doc_comment, parent_module::crates_for, RangeInfo};
@@ -58,8 +57,8 @@ pub enum SymbolInformationKind {
 impl From<SymbolInformationKind> for MonikerDescriptorKind {
     fn from(value: SymbolInformationKind) -> Self {
         match value {
-            SymbolInformationKind::AssociatedType => Self::Type,
-            SymbolInformationKind::Attribute => Self::Meta,
+            SymbolInformationKind::AssociatedType => Self::TypeParameter,
+            SymbolInformationKind::Attribute => Self::Macro,
             SymbolInformationKind::Constant => Self::Term,
             SymbolInformationKind::Enum => Self::Type,
             SymbolInformationKind::EnumMember => Self::Type,
@@ -71,7 +70,7 @@ impl From<SymbolInformationKind> for MonikerDescriptorKind {
             SymbolInformationKind::Parameter => Self::Parameter,
             SymbolInformationKind::SelfParameter => Self::Parameter,
             SymbolInformationKind::StaticMethod => Self::Method,
-            SymbolInformationKind::StaticVariable => Self::Term,
+            SymbolInformationKind::StaticVariable => Self::Meta,
             SymbolInformationKind::Struct => Self::Type,
             SymbolInformationKind::Trait => Self::Type,
             SymbolInformationKind::TraitMethod => Self::Method,
@@ -110,12 +109,10 @@ pub enum MonikerKind {
 }
 
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum MonikerResult {
-    /// Uniquely identifies a definition.
-    Moniker(Moniker),
-    /// Specifies that the definition is a local, and so does not have a unique identifier. Provides
-    /// a unique identifier for the container.
-    Local { enclosing_moniker: Option<Moniker> },
+pub struct MonikerResult {
+    pub identifier: MonikerIdentifier,
+    pub kind: MonikerKind,
+    pub package_information: PackageInformation,
 }
 
 impl MonikerResult {
@@ -124,15 +121,6 @@ impl MonikerResult {
     }
 }
 
-/// Information which uniquely identifies a definition which might be referenceable outside of the
-/// source file. Visibility declarations do not affect presence.
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub struct Moniker {
-    pub identifier: MonikerIdentifier,
-    pub kind: MonikerKind,
-    pub package_information: PackageInformation,
-}
-
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub struct PackageInformation {
     pub name: String,
@@ -244,106 +232,157 @@ pub(crate) fn def_to_kind(db: &RootDatabase, def: Definition) -> SymbolInformati
     }
 }
 
-/// Computes a `MonikerResult` for a definition. Result cases:
-///
-/// * `Some(MonikerResult::Moniker(_))` provides a unique `Moniker` which refers to a definition.
-///
-/// * `Some(MonikerResult::Local { .. })` provides a `Moniker` for the definition enclosing a local.
-///
-/// * `None` is returned for definitions which are not in a module: `BuiltinAttr`, `BuiltinType`,
-///   `BuiltinLifetime`, `TupleField`, `ToolModule`, and `InlineAsmRegOrRegClass`. TODO: it might be
-///   sensible to provide monikers that refer to some non-existent crate of compiler builtin
-///   definitions.
 pub(crate) fn def_to_moniker(
     db: &RootDatabase,
-    definition: Definition,
+    def: Definition,
     from_crate: Crate,
 ) -> Option<MonikerResult> {
-    match definition {
-        Definition::Local(_) | Definition::Label(_) | Definition::GenericParam(_) => {
-            return Some(MonikerResult::Local {
-                enclosing_moniker: enclosing_def_to_moniker(db, definition, from_crate),
-            });
-        }
-        _ => {}
+    if matches!(
+        def,
+        Definition::GenericParam(_)
+            | Definition::Label(_)
+            | Definition::DeriveHelper(_)
+            | Definition::BuiltinAttr(_)
+            | Definition::ToolModule(_)
+    ) {
+        return None;
     }
-    Some(MonikerResult::Moniker(def_to_non_local_moniker(db, definition, from_crate)?))
-}
 
-fn enclosing_def_to_moniker(
-    db: &RootDatabase,
-    mut def: Definition,
-    from_crate: Crate,
-) -> Option<Moniker> {
-    loop {
-        let enclosing_def = def.enclosing_definition(db)?;
-        if let Some(enclosing_moniker) = def_to_non_local_moniker(db, enclosing_def, from_crate) {
-            return Some(enclosing_moniker);
-        }
-        def = enclosing_def;
-    }
-}
-
-fn def_to_non_local_moniker(
-    db: &RootDatabase,
-    definition: Definition,
-    from_crate: Crate,
-) -> Option<Moniker> {
-    let module = definition.module(db)?;
+    let module = def.module(db)?;
     let krate = module.krate();
     let edition = krate.edition(db);
-
-    // Add descriptors for this definition and every enclosing definition.
-    let mut reverse_description = vec![];
-    let mut def = definition;
-    loop {
-        match def {
-            Definition::SelfType(impl_) => {
-                if let Some(trait_ref) = impl_.trait_ref(db) {
-                    // Trait impls use the trait type for the 2nd parameter.
-                    reverse_description.push(MonikerDescriptor {
-                        name: display(db, edition, module, trait_ref),
-                        desc: MonikerDescriptorKind::TypeParameter,
-                    });
-                }
-                // Both inherent and trait impls use the self type for the first parameter.
-                reverse_description.push(MonikerDescriptor {
-                    name: display(db, edition, module, impl_.self_ty(db)),
-                    desc: MonikerDescriptorKind::TypeParameter,
-                });
-                reverse_description.push(MonikerDescriptor {
-                    name: "impl".to_owned(),
-                    desc: MonikerDescriptorKind::Type,
+    let mut description = vec![];
+    description.extend(module.path_to_root(db).into_iter().filter_map(|x| {
+        Some(MonikerDescriptor {
+            name: x.name(db)?.display(db, edition).to_string(),
+            desc: def_to_kind(db, x.into()).into(),
+        })
+    }));
+
+    // Handle associated items within a trait
+    if let Some(assoc) = def.as_assoc_item(db) {
+        let container = assoc.container(db);
+        match container {
+            AssocItemContainer::Trait(trait_) => {
+                // Because different traits can have functions with the same name,
+                // we have to include the trait name as part of the moniker for uniqueness.
+                description.push(MonikerDescriptor {
+                    name: trait_.name(db).display(db, edition).to_string(),
+                    desc: def_to_kind(db, trait_.into()).into(),
                 });
             }
-            _ => {
-                if let Some(name) = def.name(db) {
-                    reverse_description.push(MonikerDescriptor {
-                        name: name.display(db, edition).to_string(),
-                        desc: def_to_kind(db, def).into(),
+            AssocItemContainer::Impl(impl_) => {
+                // Because a struct can implement multiple traits, for implementations
+                // we add both the struct name and the trait name to the path
+                if let Some(adt) = impl_.self_ty(db).as_adt() {
+                    description.push(MonikerDescriptor {
+                        name: adt.name(db).display(db, edition).to_string(),
+                        desc: def_to_kind(db, adt.into()).into(),
                     });
-                } else if reverse_description.is_empty() {
-                    // Don't allow the last descriptor to be absent.
-                    return None;
-                } else {
-                    match def {
-                        Definition::Module(module) if module.is_crate_root() => {}
-                        _ => {
-                            tracing::error!(?def, "Encountered enclosing definition with no name");
-                        }
-                    }
                 }
+
+                if let Some(trait_) = impl_.trait_(db) {
+                    description.push(MonikerDescriptor {
+                        name: trait_.name(db).display(db, edition).to_string(),
+                        desc: def_to_kind(db, trait_.into()).into(),
+                    });
+                }
+            }
+        }
+    }
+
+    if let Definition::Field(it) = def {
+        description.push(MonikerDescriptor {
+            name: it.parent_def(db).name(db).display(db, edition).to_string(),
+            desc: def_to_kind(db, it.parent_def(db).into()).into(),
+        });
+    }
+
+    // Qualify locals/parameters by their parent definition name.
+    if let Definition::Local(it) = def {
+        let parent = Definition::try_from(it.parent(db)).ok();
+        if let Some(parent) = parent {
+            let parent_name = parent.name(db);
+            if let Some(name) = parent_name {
+                description.push(MonikerDescriptor {
+                    name: name.display(db, edition).to_string(),
+                    desc: def_to_kind(db, parent).into(),
+                });
             }
         }
-        let Some(next_def) = def.enclosing_definition(db) else {
-            break;
-        };
-        def = next_def;
     }
-    reverse_description.reverse();
-    let description = reverse_description;
 
-    Some(Moniker {
+    let desc = def_to_kind(db, def).into();
+
+    let name_desc = match def {
+        // These are handled by top-level guard (for performance).
+        Definition::GenericParam(_)
+        | Definition::Label(_)
+        | Definition::DeriveHelper(_)
+        | Definition::BuiltinLifetime(_)
+        | Definition::BuiltinAttr(_)
+        | Definition::ToolModule(_)
+        | Definition::InlineAsmRegOrRegClass(_)
+        | Definition::InlineAsmOperand(_) => return None,
+
+        Definition::Local(local) => {
+            if !local.is_param(db) {
+                return None;
+            }
+
+            MonikerDescriptor { name: local.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::Macro(m) => {
+            MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::Function(f) => {
+            MonikerDescriptor { name: f.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::Variant(v) => {
+            MonikerDescriptor { name: v.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::Const(c) => {
+            MonikerDescriptor { name: c.name(db)?.display(db, edition).to_string(), desc }
+        }
+        Definition::Trait(trait_) => {
+            MonikerDescriptor { name: trait_.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::TraitAlias(ta) => {
+            MonikerDescriptor { name: ta.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::TypeAlias(ta) => {
+            MonikerDescriptor { name: ta.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::Module(m) => {
+            MonikerDescriptor { name: m.name(db)?.display(db, edition).to_string(), desc }
+        }
+        Definition::BuiltinType(b) => {
+            MonikerDescriptor { name: b.name().display(db, edition).to_string(), desc }
+        }
+        Definition::SelfType(imp) => MonikerDescriptor {
+            name: imp.self_ty(db).as_adt()?.name(db).display(db, edition).to_string(),
+            desc,
+        },
+        Definition::Field(it) => {
+            MonikerDescriptor { name: it.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::TupleField(it) => {
+            MonikerDescriptor { name: it.name().display(db, edition).to_string(), desc }
+        }
+        Definition::Adt(adt) => {
+            MonikerDescriptor { name: adt.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::Static(s) => {
+            MonikerDescriptor { name: s.name(db).display(db, edition).to_string(), desc }
+        }
+        Definition::ExternCrateDecl(m) => {
+            MonikerDescriptor { name: m.name(db).display(db, edition).to_string(), desc }
+        }
+    };
+
+    description.push(name_desc);
+
+    Some(MonikerResult {
         identifier: MonikerIdentifier {
             crate_name: krate.display_name(db)?.crate_name().to_string(),
             description,
@@ -378,57 +417,17 @@ fn def_to_non_local_moniker(
     })
 }
 
-fn display<T: HirDisplay>(
-    db: &RootDatabase,
-    edition: Edition,
-    module: hir::Module,
-    it: T,
-) -> String {
-    match it.display_source_code(db, module.into(), true) {
-        Ok(result) => result,
-        // Fallback on display variant that always succeeds
-        Err(_) => {
-            let fallback_result = it.display(db, edition).to_string();
-            tracing::error!(
-                display = %fallback_result, "`display_source_code` failed; falling back to using display"
-            );
-            fallback_result
-        }
-    }
-}
-
 #[cfg(test)]
 mod tests {
-    use crate::{fixture, MonikerResult};
+    use crate::fixture;
 
     use super::MonikerKind;
 
-    #[allow(dead_code)]
     #[track_caller]
     fn no_moniker(ra_fixture: &str) {
         let (analysis, position) = fixture::position(ra_fixture);
         if let Some(x) = analysis.moniker(position).unwrap() {
-            assert_eq!(x.info.len(), 0, "Moniker found but no moniker expected: {x:?}");
-        }
-    }
-
-    #[track_caller]
-    fn check_local_moniker(ra_fixture: &str, identifier: &str, package: &str, kind: MonikerKind) {
-        let (analysis, position) = fixture::position(ra_fixture);
-        let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
-        assert_eq!(x.len(), 1);
-        match x.into_iter().next().unwrap() {
-            MonikerResult::Local { enclosing_moniker: Some(x) } => {
-                assert_eq!(identifier, x.identifier.to_string());
-                assert_eq!(package, format!("{:?}", x.package_information));
-                assert_eq!(kind, x.kind);
-            }
-            MonikerResult::Local { enclosing_moniker: None } => {
-                panic!("Unexpected local with no enclosing moniker");
-            }
-            MonikerResult::Moniker(_) => {
-                panic!("Unexpected non-local moniker");
-            }
+            assert_eq!(x.info.len(), 0, "Moniker founded but no moniker expected: {x:?}");
         }
     }
 
@@ -437,16 +436,10 @@ mod tests {
         let (analysis, position) = fixture::position(ra_fixture);
         let x = analysis.moniker(position).unwrap().expect("no moniker found").info;
         assert_eq!(x.len(), 1);
-        match x.into_iter().next().unwrap() {
-            MonikerResult::Local { enclosing_moniker } => {
-                panic!("Unexpected local enclosed in {:?}", enclosing_moniker);
-            }
-            MonikerResult::Moniker(x) => {
-                assert_eq!(identifier, x.identifier.to_string());
-                assert_eq!(package, format!("{:?}", x.package_information));
-                assert_eq!(kind, x.kind);
-            }
-        }
+        let x = x.into_iter().next().unwrap();
+        assert_eq!(identifier, x.identifier.to_string());
+        assert_eq!(package, format!("{:?}", x.package_information));
+        assert_eq!(kind, x.kind);
     }
 
     #[test]
@@ -545,13 +538,15 @@ pub mod module {
     pub trait MyTrait {
         pub fn func() {}
     }
+
     struct MyStruct {}
+
     impl MyTrait for MyStruct {
         pub fn func$0() {}
     }
 }
 "#,
-            "foo::module::impl::MyStruct::MyTrait::func",
+            "foo::module::MyStruct::MyTrait::func",
             r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
             MonikerKind::Export,
         );
@@ -578,8 +573,8 @@ pub struct St {
     }
 
     #[test]
-    fn local() {
-        check_local_moniker(
+    fn no_moniker_for_local() {
+        no_moniker(
             r#"
 //- /lib.rs crate:main deps:foo
 use foo::module::func;
@@ -593,9 +588,6 @@ pub mod module {
     }
 }
 "#,
-            "foo::module::func",
-            r#"PackageInformation { name: "foo", repo: Some("https://a.b/foo.git"), version: Some("0.1.0") }"#,
-            MonikerKind::Export,
         );
     }
 }
diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs
index 700e166b23..53eeffaf97 100644
--- a/crates/ide/src/static_index.rs
+++ b/crates/ide/src/static_index.rs
@@ -48,6 +48,7 @@ pub struct TokenStaticData {
     pub references: Vec<ReferenceData>,
     pub moniker: Option<MonikerResult>,
     pub display_name: Option<String>,
+    pub enclosing_moniker: Option<MonikerResult>,
     pub signature: Option<String>,
     pub kind: SymbolInformationKind,
 }
@@ -224,6 +225,9 @@ impl StaticIndex<'_> {
                     display_name: def
                         .name(self.db)
                         .map(|name| name.display(self.db, edition).to_string()),
+                    enclosing_moniker: current_crate
+                        .zip(def.enclosing_definition(self.db))
+                        .and_then(|(cc, enclosing_def)| def_to_moniker(self.db, enclosing_def, cc)),
                     signature: Some(def.label(self.db, edition)),
                     kind: def_to_kind(self.db, def),
                 });
diff --git a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 58eed6499b..1b535d2a1c 100644
--- a/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -12,7 +12,7 @@ use std::{
 
 use intern::Symbol;
 use proc_macro::bridge::{self, server};
-use span::{FileId, Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
+use span::{Span, FIXUP_ERASED_FILE_AST_ID_MARKER};
 use tt::{TextRange, TextSize};
 
 use crate::server_impl::{
@@ -32,10 +32,8 @@ mod tt {
 
 type TokenStream = crate::server_impl::TokenStream<Span>;
 
-#[derive(Copy, Clone, PartialEq, Eq, Debug)]
-pub struct SourceFile {
-    file_id: FileId,
-}
+#[derive(Clone)]
+pub struct SourceFile;
 pub struct FreeFunctions;
 
 pub struct RaSpanServer {
@@ -293,8 +291,9 @@ impl server::TokenStream for RaSpanServer {
 }
 
 impl server::SourceFile for RaSpanServer {
-    fn eq(&mut self, file1: &Self::SourceFile, file2: &Self::SourceFile) -> bool {
-        file1 == file2
+    fn eq(&mut self, _file1: &Self::SourceFile, _file2: &Self::SourceFile) -> bool {
+        // FIXME
+        true
     }
     fn path(&mut self, _file: &Self::SourceFile) -> String {
         // FIXME
@@ -309,8 +308,9 @@ impl server::Span for RaSpanServer {
     fn debug(&mut self, span: Self::Span) -> String {
         format!("{:?}", span)
     }
-    fn source_file(&mut self, span: Self::Span) -> Self::SourceFile {
-        SourceFile { file_id: span.anchor.file_id.file_id() }
+    fn source_file(&mut self, _span: Self::Span) -> Self::SourceFile {
+        // FIXME stub, requires db
+        SourceFile {}
     }
     fn save_span(&mut self, _span: Self::Span) -> usize {
         // FIXME, quote is incompatible with third-party tools
diff --git a/crates/project-model/src/cargo_workspace.rs b/crates/project-model/src/cargo_workspace.rs
index c125c141cd..4ffe3a6265 100644
--- a/crates/project-model/src/cargo_workspace.rs
+++ b/crates/project-model/src/cargo_workspace.rs
@@ -4,7 +4,6 @@ use std::ops;
 use std::str::from_utf8;
 
 use anyhow::Context;
-use base_db::Env;
 use cargo_metadata::{CargoOpt, MetadataCommand};
 use la_arena::{Arena, Idx};
 use paths::{AbsPath, AbsPathBuf, Utf8PathBuf};
@@ -35,8 +34,6 @@ pub struct CargoWorkspace {
     target_directory: AbsPathBuf,
     manifest_path: ManifestPath,
     is_virtual_workspace: bool,
-    /// Environment variables set in the `.cargo/config` file.
-    config_env: Env,
 }
 
 impl ops::Index<Package> for CargoWorkspace {
@@ -398,7 +395,6 @@ impl CargoWorkspace {
     pub fn new(
         mut meta: cargo_metadata::Metadata,
         ws_manifest_path: ManifestPath,
-        cargo_config_env: Env,
     ) -> CargoWorkspace {
         let mut pkg_by_id = FxHashMap::default();
         let mut packages = Arena::default();
@@ -520,7 +516,6 @@ impl CargoWorkspace {
             target_directory,
             manifest_path: ws_manifest_path,
             is_virtual_workspace,
-            config_env: cargo_config_env,
         }
     }
 
@@ -607,8 +602,4 @@ impl CargoWorkspace {
     pub fn is_virtual_workspace(&self) -> bool {
         self.is_virtual_workspace
     }
-
-    pub fn env(&self) -> &Env {
-        &self.config_env
-    }
 }
diff --git a/crates/project-model/src/env.rs b/crates/project-model/src/env.rs
index 53c35ef6a7..b4714b764a 100644
--- a/crates/project-model/src/env.rs
+++ b/crates/project-model/src/env.rs
@@ -1,6 +1,5 @@
 //! Cargo-like environment variables injection.
 use base_db::Env;
-use paths::Utf8Path;
 use rustc_hash::FxHashMap;
 use toolchain::Tool;
 
@@ -74,7 +73,7 @@ pub(crate) fn cargo_config_env(
     manifest: &ManifestPath,
     extra_env: &FxHashMap<String, String>,
     sysroot: &Sysroot,
-) -> Env {
+) -> FxHashMap<String, String> {
     let mut cargo_config = sysroot.tool(Tool::Cargo, manifest.parent());
     cargo_config.envs(extra_env);
     cargo_config
@@ -86,7 +85,7 @@ pub(crate) fn cargo_config_env(
     // if successful we receive `env.key.value = "value" per entry
     tracing::debug!("Discovering cargo config env by {:?}", cargo_config);
     utf8_stdout(&mut cargo_config)
-        .map(|stdout| parse_output_cargo_config_env(manifest, stdout))
+        .map(parse_output_cargo_config_env)
         .inspect(|env| {
             tracing::debug!("Discovered cargo config env: {:?}", env);
         })
@@ -96,38 +95,18 @@ pub(crate) fn cargo_config_env(
         .unwrap_or_default()
 }
 
-fn parse_output_cargo_config_env(manifest: &ManifestPath, stdout: String) -> Env {
-    let mut env = Env::default();
-    let mut relatives = vec![];
-    for (key, val) in
-        stdout.lines().filter_map(|l| l.strip_prefix("env.")).filter_map(|l| l.split_once(" = "))
-    {
-        let val = val.trim_matches('"').to_owned();
-        if let Some((key, modifier)) = key.split_once('.') {
-            match modifier {
-                "relative" => relatives.push((key, val)),
-                "value" => _ = env.insert(key, val),
-                _ => {
-                    tracing::warn!(
-                        "Unknown modifier in cargo config env: {}, expected `relative` or `value`",
-                        modifier
-                    );
-                    continue;
-                }
+fn parse_output_cargo_config_env(stdout: String) -> FxHashMap<String, String> {
+    stdout
+        .lines()
+        .filter_map(|l| l.strip_prefix("env."))
+        .filter_map(|l| l.split_once(" = "))
+        .filter_map(|(k, v)| {
+            if k.contains('.') {
+                k.strip_suffix(".value").zip(Some(v))
+            } else {
+                Some((k, v))
             }
-        } else {
-            env.insert(key, val);
-        }
-    }
-    // FIXME: The base here should be the parent of the `.cargo/config` file, not the manifest.
-    // But cargo does not provide this information.
-    let base = <_ as AsRef<Utf8Path>>::as_ref(manifest.parent());
-    for (key, val) in relatives {
-        if let Some(val) = env.get(&val) {
-            env.insert(key, base.join(val).to_string());
-        } else {
-            env.insert(key, base.to_string());
-        }
-    }
-    env
+        })
+        .map(|(key, value)| (key.to_owned(), value.trim_matches('"').to_owned()))
+        .collect()
 }
diff --git a/crates/project-model/src/sysroot.rs b/crates/project-model/src/sysroot.rs
index 9d3dc37c58..b0fdd3fa41 100644
--- a/crates/project-model/src/sysroot.rs
+++ b/crates/project-model/src/sysroot.rs
@@ -422,7 +422,7 @@ impl Sysroot {
             res.packages.remove(idx);
         });
 
-        let cargo_workspace = CargoWorkspace::new(res, library_manifest, Default::default());
+        let cargo_workspace = CargoWorkspace::new(res, library_manifest);
         Some(Sysroot {
             root: sysroot_dir.clone(),
             src_root: Some(sysroot_src_dir.clone()),
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index 9598316178..233f94203e 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -78,6 +78,8 @@ pub enum ProjectWorkspaceKind {
         /// The rustc workspace loaded for this workspace. An `Err(None)` means loading has been
         /// disabled or was otherwise not requested.
         rustc: Result<Box<(CargoWorkspace, WorkspaceBuildScripts)>, Option<String>>,
+        /// Environment variables set in the `.cargo/config` file.
+        cargo_config_extra_env: FxHashMap<String, String>,
         set_test: bool,
     },
     /// Project workspace was specified using a `rust-project.json` file.
@@ -97,6 +99,8 @@ pub enum ProjectWorkspaceKind {
         file: ManifestPath,
         /// Is this file a cargo script file?
         cargo: Option<(CargoWorkspace, WorkspaceBuildScripts, Option<Arc<anyhow::Error>>)>,
+        /// Environment variables set in the `.cargo/config` file.
+        cargo_config_extra_env: FxHashMap<String, String>,
         set_test: bool,
     },
 }
@@ -106,7 +110,14 @@ impl fmt::Debug for ProjectWorkspace {
         // Make sure this isn't too verbose.
         let Self { kind, sysroot, rustc_cfg, toolchain, target_layout, cfg_overrides } = self;
         match kind {
-            ProjectWorkspaceKind::Cargo { cargo, error: _, build_scripts, rustc, set_test } => f
+            ProjectWorkspaceKind::Cargo {
+                cargo,
+                error: _,
+                build_scripts,
+                rustc,
+                cargo_config_extra_env,
+                set_test,
+            } => f
                 .debug_struct("Cargo")
                 .field("root", &cargo.workspace_root().file_name())
                 .field("n_packages", &cargo.packages().len())
@@ -119,6 +130,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("n_cfg_overrides", &cfg_overrides.len())
                 .field("toolchain", &toolchain)
                 .field("data_layout", &target_layout)
+                .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .field("set_test", set_test)
                 .field("build_scripts", &build_scripts.error().unwrap_or("ok"))
                 .finish(),
@@ -134,7 +146,12 @@ impl fmt::Debug for ProjectWorkspace {
 
                 debug_struct.finish()
             }
-            ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test } => f
+            ProjectWorkspaceKind::DetachedFile {
+                file,
+                cargo: cargo_script,
+                cargo_config_extra_env,
+                set_test,
+            } => f
                 .debug_struct("DetachedFiles")
                 .field("file", &file)
                 .field("cargo_script", &cargo_script.is_some())
@@ -144,6 +161,7 @@ impl fmt::Debug for ProjectWorkspace {
                 .field("toolchain", &toolchain)
                 .field("data_layout", &target_layout)
                 .field("n_cfg_overrides", &cfg_overrides.len())
+                .field("cargo_config_extra_env", &cargo_config_extra_env)
                 .field("set_test", set_test)
                 .finish(),
         }
@@ -271,14 +289,14 @@ impl ProjectWorkspace {
                 progress,
             ) {
                 Ok((meta, _error)) => {
-                    let workspace = CargoWorkspace::new(meta, cargo_toml.clone(), Env::default());
-                    let build_scripts = WorkspaceBuildScripts::rustc_crates(
+                    let workspace = CargoWorkspace::new(meta, cargo_toml.clone());
+                    let buildscripts = WorkspaceBuildScripts::rustc_crates(
                         &workspace,
                         cargo_toml.parent(),
                         &config.extra_env,
                         &sysroot,
                     );
-                    Ok(Box::new((workspace, build_scripts)))
+                    Ok(Box::new((workspace, buildscripts)))
                 }
                 Err(e) => {
                     tracing::error!(
@@ -330,13 +348,14 @@ impl ProjectWorkspace {
                 "Failed to read Cargo metadata from Cargo.toml file {cargo_toml}, {toolchain:?}",
             )
         })?;
+        let cargo = CargoWorkspace::new(meta, cargo_toml.clone());
         let cargo_config_extra_env = cargo_config_env(cargo_toml, &config.extra_env, &sysroot);
-        let cargo = CargoWorkspace::new(meta, cargo_toml.clone(), cargo_config_extra_env);
         Ok(ProjectWorkspace {
             kind: ProjectWorkspaceKind::Cargo {
                 cargo,
                 build_scripts: WorkspaceBuildScripts::default(),
                 rustc,
+                cargo_config_extra_env,
                 error: error.map(Arc::new),
                 set_test: config.set_test,
             },
@@ -431,19 +450,19 @@ impl ProjectWorkspace {
         )
         .ok()
         .map(|(ws, error)| {
-            let cargo_config_extra_env =
-                cargo_config_env(detached_file, &config.extra_env, &sysroot);
             (
-                CargoWorkspace::new(ws, detached_file.clone(), cargo_config_extra_env),
+                CargoWorkspace::new(ws, detached_file.clone()),
                 WorkspaceBuildScripts::default(),
                 error.map(Arc::new),
             )
         });
 
+        let cargo_config_extra_env = cargo_config_env(detached_file, &config.extra_env, &sysroot);
         Ok(ProjectWorkspace {
             kind: ProjectWorkspaceKind::DetachedFile {
                 file: detached_file.to_owned(),
                 cargo: cargo_script,
+                cargo_config_extra_env,
                 set_test: config.set_test,
             },
             sysroot,
@@ -624,7 +643,14 @@ impl ProjectWorkspace {
                 .chain(mk_sysroot())
                 .unique()
                 .collect(),
-            ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _, set_test: _ } => {
+            ProjectWorkspaceKind::Cargo {
+                cargo,
+                rustc,
+                build_scripts,
+                cargo_config_extra_env: _,
+                error: _,
+                set_test: _,
+            } => {
                 cargo
                     .packages()
                     .map(|pkg| {
@@ -761,18 +787,23 @@ impl ProjectWorkspace {
                 extra_env,
                 cfg_overrides,
             ),
-            ProjectWorkspaceKind::Cargo { cargo, rustc, build_scripts, error: _, set_test } => {
-                cargo_to_crate_graph(
-                    load,
-                    rustc.as_ref().map(|a| a.as_ref()).ok(),
-                    cargo,
-                    sysroot,
-                    rustc_cfg.clone(),
-                    cfg_overrides,
-                    build_scripts,
-                    *set_test,
-                )
-            }
+            ProjectWorkspaceKind::Cargo {
+                cargo,
+                rustc,
+                build_scripts,
+                cargo_config_extra_env: _,
+                error: _,
+                set_test,
+            } => cargo_to_crate_graph(
+                load,
+                rustc.as_ref().map(|a| a.as_ref()).ok(),
+                cargo,
+                sysroot,
+                rustc_cfg.clone(),
+                cfg_overrides,
+                build_scripts,
+                *set_test,
+            ),
             ProjectWorkspaceKind::DetachedFile { file, cargo: cargo_script, set_test, .. } => {
                 if let Some((cargo, build_scripts, _)) = cargo_script {
                     cargo_to_crate_graph(
@@ -817,6 +848,7 @@ impl ProjectWorkspace {
                 ProjectWorkspaceKind::Cargo {
                     cargo,
                     rustc,
+                    cargo_config_extra_env,
                     build_scripts: _,
                     error: _,
                     set_test: _,
@@ -824,11 +856,16 @@ impl ProjectWorkspace {
                 ProjectWorkspaceKind::Cargo {
                     cargo: o_cargo,
                     rustc: o_rustc,
+                    cargo_config_extra_env: o_cargo_config_extra_env,
                     build_scripts: _,
                     error: _,
                     set_test: _,
                 },
-            ) => cargo == o_cargo && rustc == o_rustc,
+            ) => {
+                cargo == o_cargo
+                    && rustc == o_rustc
+                    && cargo_config_extra_env == o_cargo_config_extra_env
+            }
             (ProjectWorkspaceKind::Json(project), ProjectWorkspaceKind::Json(o_project)) => {
                 project == o_project
             }
@@ -836,14 +873,20 @@ impl ProjectWorkspace {
                 ProjectWorkspaceKind::DetachedFile {
                     file,
                     cargo: Some((cargo_script, _, _)),
+                    cargo_config_extra_env,
                     set_test: _,
                 },
                 ProjectWorkspaceKind::DetachedFile {
                     file: o_file,
                     cargo: Some((o_cargo_script, _, _)),
+                    cargo_config_extra_env: o_cargo_config_extra_env,
                     set_test: _,
                 },
-            ) => file == o_file && cargo_script == o_cargo_script,
+            ) => {
+                file == o_file
+                    && cargo_script == o_cargo_script
+                    && cargo_config_extra_env == o_cargo_config_extra_env
+            }
             _ => return false,
         }) && sysroot == o_sysroot
             && rustc_cfg == o_rustc_cfg
@@ -1359,7 +1402,7 @@ fn add_target_crate_root(
         opts
     };
 
-    let mut env = cargo.env().clone();
+    let mut env = Env::default();
     inject_cargo_package_env(&mut env, pkg);
     inject_cargo_env(&mut env);
     inject_rustc_tool_env(&mut env, cargo, cargo_name, kind);
diff --git a/crates/rust-analyzer/src/cli/lsif.rs b/crates/rust-analyzer/src/cli/lsif.rs
index eb5c44418b..33c4f31fbe 100644
--- a/crates/rust-analyzer/src/cli/lsif.rs
+++ b/crates/rust-analyzer/src/cli/lsif.rs
@@ -4,9 +4,8 @@ use std::env;
 use std::time::Instant;
 
 use ide::{
-    Analysis, AnalysisHost, FileId, FileRange, MonikerKind, MonikerResult, PackageInformation,
-    RootDatabase, StaticIndex, StaticIndexedFile, TokenId, TokenStaticData,
-    VendoredLibrariesConfig,
+    Analysis, AnalysisHost, FileId, FileRange, MonikerKind, PackageInformation, RootDatabase,
+    StaticIndex, StaticIndexedFile, TokenId, TokenStaticData, VendoredLibrariesConfig,
 };
 use ide_db::{line_index::WideEncoding, LineIndexDatabase};
 use load_cargo::{load_workspace, LoadCargoConfig, ProcMacroServerChoice};
@@ -168,7 +167,7 @@ impl LsifManager<'_, '_> {
                 out_v: result_set_id.into(),
             }));
         }
-        if let Some(MonikerResult::Moniker(moniker)) = token.moniker {
+        if let Some(moniker) = token.moniker {
             let package_id = self.get_package_id(moniker.package_information);
             let moniker_id = self.add_vertex(lsif::Vertex::Moniker(lsp_types::Moniker {
                 scheme: "rust-analyzer".to_owned(),
diff --git a/crates/rust-analyzer/src/cli/scip.rs b/crates/rust-analyzer/src/cli/scip.rs
index 36870851a8..ff009e6954 100644
--- a/crates/rust-analyzer/src/cli/scip.rs
+++ b/crates/rust-analyzer/src/cli/scip.rs
@@ -3,16 +3,14 @@
 use std::{path::PathBuf, time::Instant};
 
 use ide::{
-    AnalysisHost, LineCol, Moniker, MonikerDescriptorKind, MonikerIdentifier, MonikerResult,
-    RootDatabase, StaticIndex, StaticIndexedFile, SymbolInformationKind, TextRange, TokenId,
-    TokenStaticData, VendoredLibrariesConfig,
+    AnalysisHost, LineCol, MonikerDescriptorKind, MonikerResult, StaticIndex, StaticIndexedFile,
+    SymbolInformationKind, TextRange, TokenId, VendoredLibrariesConfig,
 };
 use ide_db::LineIndexDatabase;
 use load_cargo::{load_workspace_at, LoadCargoConfig, ProcMacroServerChoice};
 use rustc_hash::{FxHashMap, FxHashSet};
-use scip::types::{self as scip_types, SymbolInformation};
+use scip::types as scip_types;
 use tracing::error;
-use vfs::FileId;
 
 use crate::{
     cli::flags,
@@ -85,56 +83,32 @@ impl flags::Scip {
             text_document_encoding: scip_types::TextEncoding::UTF8.into(),
             special_fields: Default::default(),
         };
-
         let mut documents = Vec::new();
 
-        // All TokenIds where an Occurrence has been emitted that references a symbol.
-        let mut token_ids_referenced: FxHashSet<TokenId> = FxHashSet::default();
-        // All TokenIds where the SymbolInformation has been written to the document.
-        let mut token_ids_emitted: FxHashSet<TokenId> = FxHashSet::default();
-        // All FileIds emitted as documents.
-        let mut file_ids_emitted: FxHashSet<FileId> = FxHashSet::default();
-
-        // All non-local symbols encountered, for detecting duplicate symbol errors.
-        let mut nonlocal_symbols_emitted: FxHashSet<String> = FxHashSet::default();
-        // List of (source_location, symbol) for duplicate symbol errors to report.
-        let mut duplicate_symbol_errors: Vec<(String, String)> = Vec::new();
-        // This is called after definitions have been deduplicated by token_ids_emitted. The purpose
-        // is to detect reuse of symbol names because this causes ambiguity about their meaning.
-        let mut record_error_if_symbol_already_used =
-            |symbol: String,
-             is_inherent_impl: bool,
-             relative_path: &str,
-             line_index: &LineIndex,
-             text_range: TextRange| {
-                let is_local = symbol.starts_with("local ");
-                if !is_local && !nonlocal_symbols_emitted.insert(symbol.clone()) {
-                    if is_inherent_impl {
-                        // FIXME: See #18772. Duplicate SymbolInformation for inherent impls is
-                        // omitted. It would be preferable to emit them with numbers with
-                        // disambiguation, but this is more complex to implement.
-                        false
-                    } else {
-                        let source_location =
-                            text_range_to_string(relative_path, line_index, text_range);
-                        duplicate_symbol_errors.push((source_location, symbol));
-                        // Keep duplicate SymbolInformation. This behavior is preferred over
-                        // omitting so that the issue might be visible within downstream tools.
-                        true
-                    }
-                } else {
-                    true
-                }
-            };
-
-        // Generates symbols from token monikers.
-        let mut symbol_generator = SymbolGenerator::new();
+        let mut symbols_emitted: FxHashSet<TokenId> = FxHashSet::default();
+        let mut tokens_to_symbol: FxHashMap<TokenId, String> = FxHashMap::default();
+        let mut tokens_to_enclosing_symbol: FxHashMap<TokenId, Option<String>> =
+            FxHashMap::default();
 
         for StaticIndexedFile { file_id, tokens, .. } in si.files {
-            symbol_generator.clear_document_local_state();
+            let mut local_count = 0;
+            let mut new_local_symbol = || {
+                let new_symbol = scip::types::Symbol::new_local(local_count);
+                local_count += 1;
+
+                new_symbol
+            };
 
-            let Some(relative_path) = get_relative_filepath(&vfs, &root, file_id) else { continue };
-            let line_index = get_line_index(db, file_id);
+            let relative_path = match get_relative_filepath(&vfs, &root, file_id) {
+                Some(relative_path) => relative_path,
+                None => continue,
+            };
+
+            let line_index = LineIndex {
+                index: db.line_index(file_id),
+                encoding: PositionEncoding::Utf8,
+                endings: LineEndings::Unix,
+            };
 
             let mut occurrences = Vec::new();
             let mut symbols = Vec::new();
@@ -142,58 +116,71 @@ impl flags::Scip {
             tokens.into_iter().for_each(|(text_range, id)| {
                 let token = si.tokens.get(id).unwrap();
 
-                let (symbol, enclosing_symbol, is_inherent_impl) =
-                    if let Some(TokenSymbols { symbol, enclosing_symbol, is_inherent_impl }) =
-                        symbol_generator.token_symbols(id, token)
-                    {
-                        (symbol, enclosing_symbol, is_inherent_impl)
-                    } else {
-                        ("".to_owned(), None, false)
-                    };
-
-                if !symbol.is_empty() {
-                    let is_defined_in_this_document = match token.definition {
-                        Some(def) => def.file_id == file_id,
-                        _ => false,
-                    };
-                    if is_defined_in_this_document {
-                        if token_ids_emitted.insert(id) {
-                            // token_ids_emitted does deduplication. This checks that this results
-                            // in unique emitted symbols, as otherwise references are ambiguous.
-                            let should_emit = record_error_if_symbol_already_used(
-                                symbol.clone(),
-                                is_inherent_impl,
-                                relative_path.as_str(),
-                                &line_index,
-                                text_range,
-                            );
-                            if should_emit {
-                                symbols.push(compute_symbol_info(
-                                    symbol.clone(),
-                                    enclosing_symbol,
-                                    token,
-                                ));
-                            }
-                        }
-                    } else {
-                        token_ids_referenced.insert(id);
-                    }
-                }
-
-                // If the range of the def and the range of the token are the same, this must be the definition.
-                // they also must be in the same file. See https://github.com/rust-lang/rust-analyzer/pull/17988
-                let is_definition = match token.definition {
-                    Some(def) => def.file_id == file_id && def.range == text_range,
-                    _ => false,
-                };
+                let range = text_range_to_scip_range(&line_index, text_range);
+                let symbol = tokens_to_symbol
+                    .entry(id)
+                    .or_insert_with(|| {
+                        let symbol = token
+                            .moniker
+                            .as_ref()
+                            .map(moniker_to_symbol)
+                            .unwrap_or_else(&mut new_local_symbol);
+                        scip::symbol::format_symbol(symbol)
+                    })
+                    .clone();
+                let enclosing_symbol = tokens_to_enclosing_symbol
+                    .entry(id)
+                    .or_insert_with(|| {
+                        token
+                            .enclosing_moniker
+                            .as_ref()
+                            .map(moniker_to_symbol)
+                            .map(scip::symbol::format_symbol)
+                    })
+                    .clone();
 
                 let mut symbol_roles = Default::default();
-                if is_definition {
-                    symbol_roles |= scip_types::SymbolRole::Definition as i32;
+
+                if let Some(def) = token.definition {
+                    // if the range of the def and the range of the token are the same, this must be the definition.
+                    // they also must be in the same file. See https://github.com/rust-lang/rust-analyzer/pull/17988
+                    if def.file_id == file_id && def.range == text_range {
+                        symbol_roles |= scip_types::SymbolRole::Definition as i32;
+                    }
+
+                    if symbols_emitted.insert(id) {
+                        let documentation = match &token.documentation {
+                            Some(doc) => vec![doc.as_str().to_owned()],
+                            None => vec![],
+                        };
+
+                        let position_encoding =
+                            scip_types::PositionEncoding::UTF8CodeUnitOffsetFromLineStart.into();
+                        let signature_documentation =
+                            token.signature.clone().map(|text| scip_types::Document {
+                                relative_path: relative_path.clone(),
+                                language: "rust".to_owned(),
+                                text,
+                                position_encoding,
+                                ..Default::default()
+                            });
+                        let symbol_info = scip_types::SymbolInformation {
+                            symbol: symbol.clone(),
+                            documentation,
+                            relationships: Vec::new(),
+                            special_fields: Default::default(),
+                            kind: symbol_kind(token.kind).into(),
+                            display_name: token.display_name.clone().unwrap_or_default(),
+                            signature_documentation: signature_documentation.into(),
+                            enclosing_symbol: enclosing_symbol.unwrap_or_default(),
+                        };
+
+                        symbols.push(symbol_info)
+                    }
                 }
 
                 occurrences.push(scip_types::Occurrence {
-                    range: text_range_to_scip_range(&line_index, text_range),
+                    range,
                     symbol,
                     symbol_roles,
                     override_documentation: Vec::new(),
@@ -219,63 +206,15 @@ impl flags::Scip {
                 position_encoding,
                 special_fields: Default::default(),
             });
-            if !file_ids_emitted.insert(file_id) {
-                panic!("Invariant violation: file emitted multiple times.");
-            }
-        }
-
-        // Collect all symbols referenced by the files but not defined within them.
-        let mut external_symbols = Vec::new();
-        for id in token_ids_referenced.difference(&token_ids_emitted) {
-            let id = *id;
-            let token = si.tokens.get(id).unwrap();
-
-            let Some(definition) = token.definition else {
-                break;
-            };
-
-            let file_id = definition.file_id;
-            let Some(relative_path) = get_relative_filepath(&vfs, &root, file_id) else { continue };
-            let line_index = get_line_index(db, file_id);
-            let text_range = definition.range;
-            if file_ids_emitted.contains(&file_id) {
-                tracing::error!(
-                    "Bug: definition at {} should have been in an SCIP document but was not.",
-                    text_range_to_string(relative_path.as_str(), &line_index, text_range)
-                );
-                continue;
-            }
-
-            let TokenSymbols { symbol, enclosing_symbol, .. } = symbol_generator
-                .token_symbols(id, token)
-                .expect("To have been referenced, the symbol must be in the cache.");
-
-            record_error_if_symbol_already_used(
-                symbol.clone(),
-                false,
-                relative_path.as_str(),
-                &line_index,
-                text_range,
-            );
-            external_symbols.push(compute_symbol_info(symbol.clone(), enclosing_symbol, token));
         }
 
         let index = scip_types::Index {
             metadata: Some(metadata).into(),
             documents,
-            external_symbols,
+            external_symbols: Vec::new(),
             special_fields: Default::default(),
         };
 
-        if !duplicate_symbol_errors.is_empty() {
-            eprintln!("{}", DUPLICATE_SYMBOLS_MESSAGE);
-            for (source_location, symbol) in duplicate_symbol_errors {
-                eprintln!("{}", source_location);
-                eprintln!("  Duplicate symbol: {}", symbol);
-                eprintln!();
-            }
-        }
-
         let out_path = self.output.unwrap_or_else(|| PathBuf::from(r"index.scip"));
         scip::write_message_to_file(out_path, index)
             .map_err(|err| anyhow::format_err!("Failed to write scip to file: {}", err))?;
@@ -285,53 +224,6 @@ impl flags::Scip {
     }
 }
 
-// FIXME: Known buggy cases are described here.
-const DUPLICATE_SYMBOLS_MESSAGE: &str = "
-Encountered duplicate scip symbols, indicating an internal rust-analyzer bug. These duplicates are
-included in the output, but this causes information lookup to be ambiguous and so information about
-these symbols presented by downstream tools may be incorrect.
-
-Known rust-analyzer bugs that can cause this:
-
-  * Definitions in crate example binaries which have the same symbol as definitions in the library
-    or some other example.
-
-  * Struct/enum/const/static/impl definitions nested in a function do not mention the function name.
-    See #18771.
-
-Duplicate symbols encountered:
-";
-
-fn compute_symbol_info(
-    symbol: String,
-    enclosing_symbol: Option<String>,
-    token: &TokenStaticData,
-) -> SymbolInformation {
-    let documentation = match &token.documentation {
-        Some(doc) => vec![doc.as_str().to_owned()],
-        None => vec![],
-    };
-
-    let position_encoding = scip_types::PositionEncoding::UTF8CodeUnitOffsetFromLineStart.into();
-    let signature_documentation = token.signature.clone().map(|text| scip_types::Document {
-        relative_path: "".to_owned(),
-        language: "rust".to_owned(),
-        text,
-        position_encoding,
-        ..Default::default()
-    });
-    scip_types::SymbolInformation {
-        symbol,
-        documentation,
-        relationships: Vec::new(),
-        special_fields: Default::default(),
-        kind: symbol_kind(token.kind).into(),
-        display_name: token.display_name.clone().unwrap_or_default(),
-        signature_documentation: signature_documentation.into(),
-        enclosing_symbol: enclosing_symbol.unwrap_or_default(),
-    }
-}
-
 fn get_relative_filepath(
     vfs: &vfs::Vfs,
     rootpath: &vfs::AbsPathBuf,
@@ -340,14 +232,6 @@ fn get_relative_filepath(
     Some(vfs.file_path(file_id).as_path()?.strip_prefix(rootpath)?.as_str().to_owned())
 }
 
-fn get_line_index(db: &RootDatabase, file_id: FileId) -> LineIndex {
-    LineIndex {
-        index: db.line_index(file_id),
-        encoding: PositionEncoding::Utf8,
-        endings: LineEndings::Unix,
-    }
-}
-
 // SCIP Ranges have a (very large) optimization that ranges if they are on the same line
 // only encode as a vector of [start_line, start_col, end_col].
 //
@@ -363,13 +247,6 @@ fn text_range_to_scip_range(line_index: &LineIndex, range: TextRange) -> Vec<i32
     }
 }
 
-fn text_range_to_string(relative_path: &str, line_index: &LineIndex, range: TextRange) -> String {
-    let LineCol { line: start_line, col: start_col } = line_index.index.line_col(range.start());
-    let LineCol { line: end_line, col: end_col } = line_index.index.line_col(range.end());
-
-    format!("{relative_path}:{start_line}:{start_col}-{end_line}:{end_col}")
-}
-
 fn new_descriptor_str(
     name: &str,
     suffix: scip_types::descriptor::Suffix,
@@ -382,6 +259,14 @@ fn new_descriptor_str(
     }
 }
 
+fn new_descriptor(name: &str, suffix: scip_types::descriptor::Suffix) -> scip_types::Descriptor {
+    if name.contains('\'') {
+        new_descriptor_str(&format!("`{name}`"), suffix)
+    } else {
+        new_descriptor_str(name, suffix)
+    }
+}
+
 fn symbol_kind(kind: SymbolInformationKind) -> scip_types::symbol_information::Kind {
     use scip_types::symbol_information::Kind as ScipKind;
     match kind {
@@ -410,91 +295,17 @@ fn symbol_kind(kind: SymbolInformationKind) -> scip_types::symbol_information::K
     }
 }
 
-#[derive(Clone)]
-struct TokenSymbols {
-    symbol: String,
-    /// Definition that contains this one. Only set when `symbol` is local.
-    enclosing_symbol: Option<String>,
-    /// True if this symbol is for an inherent impl. This is used to only emit `SymbolInformation`
-    /// for a struct's first inherent impl, since their symbol names are not disambiguated.
-    is_inherent_impl: bool,
-}
-
-struct SymbolGenerator {
-    token_to_symbols: FxHashMap<TokenId, Option<TokenSymbols>>,
-    local_count: usize,
-}
-
-impl SymbolGenerator {
-    fn new() -> Self {
-        SymbolGenerator { token_to_symbols: FxHashMap::default(), local_count: 0 }
-    }
-
-    fn clear_document_local_state(&mut self) {
-        self.local_count = 0;
-    }
-
-    fn token_symbols(&mut self, id: TokenId, token: &TokenStaticData) -> Option<TokenSymbols> {
-        let mut local_count = self.local_count;
-        let token_symbols = self
-            .token_to_symbols
-            .entry(id)
-            .or_insert_with(|| {
-                Some(match token.moniker.as_ref()? {
-                    MonikerResult::Moniker(moniker) => TokenSymbols {
-                        symbol: scip::symbol::format_symbol(moniker_to_symbol(moniker)),
-                        enclosing_symbol: None,
-                        is_inherent_impl: moniker
-                            .identifier
-                            .description
-                            .get(moniker.identifier.description.len() - 2)
-                            .map_or(false, |descriptor| {
-                                descriptor.desc == MonikerDescriptorKind::Type
-                                    && descriptor.name == "impl"
-                            }),
-                    },
-                    MonikerResult::Local { enclosing_moniker } => {
-                        let local_symbol = scip::types::Symbol::new_local(local_count);
-                        local_count += 1;
-                        TokenSymbols {
-                            symbol: scip::symbol::format_symbol(local_symbol),
-                            enclosing_symbol: enclosing_moniker
-                                .as_ref()
-                                .map(moniker_to_symbol)
-                                .map(scip::symbol::format_symbol),
-                            is_inherent_impl: false,
-                        }
-                    }
-                })
-            })
-            .clone();
-        self.local_count = local_count;
-        token_symbols
-    }
-}
-
-fn moniker_to_symbol(moniker: &Moniker) -> scip_types::Symbol {
-    scip_types::Symbol {
-        scheme: "rust-analyzer".into(),
-        package: Some(scip_types::Package {
-            manager: "cargo".to_owned(),
-            name: moniker.package_information.name.clone(),
-            version: moniker.package_information.version.clone().unwrap_or_else(|| ".".to_owned()),
-            special_fields: Default::default(),
-        })
-        .into(),
-        descriptors: moniker_descriptors(&moniker.identifier),
-        special_fields: Default::default(),
-    }
-}
-
-fn moniker_descriptors(identifier: &MonikerIdentifier) -> Vec<scip_types::Descriptor> {
+fn moniker_to_symbol(moniker: &MonikerResult) -> scip_types::Symbol {
     use scip_types::descriptor::Suffix::*;
-    identifier
+
+    let package_name = moniker.package_information.name.clone();
+    let version = moniker.package_information.version.clone();
+    let descriptors = moniker
+        .identifier
         .description
         .iter()
         .map(|desc| {
-            new_descriptor_str(
+            new_descriptor(
                 &desc.name,
                 match desc.desc {
                     MonikerDescriptorKind::Namespace => Namespace,
@@ -508,13 +319,27 @@ fn moniker_descriptors(identifier: &MonikerIdentifier) -> Vec<scip_types::Descri
                 },
             )
         })
-        .collect()
+        .collect();
+
+    scip_types::Symbol {
+        scheme: "rust-analyzer".into(),
+        package: Some(scip_types::Package {
+            manager: "cargo".to_owned(),
+            name: package_name,
+            version: version.unwrap_or_else(|| ".".to_owned()),
+            special_fields: Default::default(),
+        })
+        .into(),
+        descriptors,
+        special_fields: Default::default(),
+    }
 }
 
 #[cfg(test)]
 mod test {
     use super::*;
     use ide::{FilePosition, TextSize};
+    use scip::symbol::format_symbol;
     use test_fixture::ChangeFixture;
     use vfs::VfsPath;
 
@@ -551,21 +376,7 @@ mod test {
             for &(range, id) in &file.tokens {
                 if range.contains(offset - TextSize::from(1)) {
                     let token = si.tokens.get(id).unwrap();
-                    found_symbol = match token.moniker.as_ref() {
-                        None => None,
-                        Some(MonikerResult::Moniker(moniker)) => {
-                            Some(scip::symbol::format_symbol(moniker_to_symbol(moniker)))
-                        }
-                        Some(MonikerResult::Local { enclosing_moniker: Some(moniker) }) => {
-                            Some(format!(
-                                "local enclosed by {}",
-                                scip::symbol::format_symbol(moniker_to_symbol(moniker))
-                            ))
-                        }
-                        Some(MonikerResult::Local { enclosing_moniker: None }) => {
-                            Some("unenclosed local".to_owned())
-                        }
-                    };
+                    found_symbol = token.moniker.as_ref().map(moniker_to_symbol);
                     break;
                 }
             }
@@ -577,7 +388,9 @@ mod test {
         }
 
         assert!(found_symbol.is_some(), "must have one symbol {found_symbol:?}");
-        assert_eq!(found_symbol.unwrap(), expected);
+        let res = found_symbol.unwrap();
+        let formatted = format_symbol(res);
+        assert_eq!(formatted, expected);
     }
 
     #[test]
@@ -654,7 +467,8 @@ pub mod module {
         }
     }
     "#,
-            "rust-analyzer cargo foo 0.1.0 module/MyTrait#MyType#",
+            // "foo::module::MyTrait::MyType",
+            "rust-analyzer cargo foo 0.1.0 module/MyTrait#[MyType]",
         );
     }
 
@@ -675,7 +489,8 @@ pub mod module {
         }
     }
     "#,
-            "rust-analyzer cargo foo 0.1.0 module/impl#[MyStruct][MyTrait]func().",
+            // "foo::module::MyStruct::MyTrait::func",
+            "rust-analyzer cargo foo 0.1.0 module/MyStruct#MyTrait#func().",
         );
     }
 
@@ -711,7 +526,7 @@ pub mod example_mod {
     pub fn func(x$0: usize) {}
 }
 "#,
-            "local enclosed by rust-analyzer cargo foo 0.1.0 example_mod/func().",
+            "rust-analyzer cargo foo 0.1.0 example_mod/func().(x)",
         );
     }
 
@@ -731,7 +546,7 @@ pub mod example_mod {
     }
 }
 "#,
-            "local enclosed by rust-analyzer cargo foo 0.1.0 example_mod/func().",
+            "rust-analyzer cargo foo 0.1.0 example_mod/func().(x)",
         );
     }
 
@@ -751,7 +566,7 @@ pub mod example_mod {
         }
     }
     "#,
-            "local enclosed by rust-analyzer cargo foo 0.1.0 module/func().",
+            "",
         );
     }
 
@@ -794,7 +609,7 @@ pub mod example_mod {
     }
 
     #[test]
-    fn symbol_for_type_alias() {
+    fn symbol_for_for_type_alias() {
         check_symbol(
             r#"
     //- /workspace/lib.rs crate:main
@@ -804,70 +619,6 @@ pub mod example_mod {
         );
     }
 
-    // FIXME: This test represents current misbehavior.
-    #[test]
-    fn symbol_for_nested_function() {
-        check_symbol(
-            r#"
-    //- /workspace/lib.rs crate:main
-    pub fn func() {
-       pub fn inner_func$0() {}
-    }
-    "#,
-            "rust-analyzer cargo main . inner_func().",
-            // FIXME: This should be a local:
-            // "local enclosed by rust-analyzer cargo main . func().",
-        );
-    }
-
-    // FIXME: This test represents current misbehavior.
-    #[test]
-    fn symbol_for_struct_in_function() {
-        check_symbol(
-            r#"
-    //- /workspace/lib.rs crate:main
-    pub fn func() {
-       struct SomeStruct$0 {}
-    }
-    "#,
-            "rust-analyzer cargo main . SomeStruct#",
-            // FIXME: This should be a local:
-            // "local enclosed by rust-analyzer cargo main . func().",
-        );
-    }
-
-    // FIXME: This test represents current misbehavior.
-    #[test]
-    fn symbol_for_const_in_function() {
-        check_symbol(
-            r#"
-    //- /workspace/lib.rs crate:main
-    pub fn func() {
-       const SOME_CONST$0: u32 = 1;
-    }
-    "#,
-            "rust-analyzer cargo main . SOME_CONST.",
-            // FIXME: This should be a local:
-            // "local enclosed by rust-analyzer cargo main . func().",
-        );
-    }
-
-    // FIXME: This test represents current misbehavior.
-    #[test]
-    fn symbol_for_static_in_function() {
-        check_symbol(
-            r#"
-    //- /workspace/lib.rs crate:main
-    pub fn func() {
-       static SOME_STATIC$0: u32 = 1;
-    }
-    "#,
-            "rust-analyzer cargo main . SOME_STATIC.",
-            // FIXME: This should be a local:
-            // "local enclosed by rust-analyzer cargo main . func().",
-        );
-    }
-
     #[test]
     fn documentation_matches_doc_comment() {
         let s = "/// foo\nfn bar() {}";
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index f103f6cbe2..d2ed43e882 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -1826,7 +1826,6 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     let doc = TextDocumentIdentifier::new(item.uri);
     let frange = from_proto::file_range(&snap, &doc, item.selection_range)?;
     let fpos = FilePosition { file_id: frange.file_id, offset: frange.range.start() };
-    let line_index = snap.file_line_index(fpos.file_id)?;
 
     let config = snap.config.call_hierarchy();
     let call_items = match snap.analysis.outgoing_calls(config, fpos)? {
@@ -1837,6 +1836,8 @@ pub(crate) fn handle_call_hierarchy_outgoing(
     let mut res = vec![];
 
     for call_item in call_items.into_iter() {
+        let file_id = call_item.target.file_id;
+        let line_index = snap.file_line_index(file_id)?;
         let item = to_proto::call_hierarchy_item(&snap, call_item.target)?;
         res.push(CallHierarchyOutgoingCall {
             to: item,
diff --git a/crates/rust-analyzer/src/reload.rs b/crates/rust-analyzer/src/reload.rs
index 0add2cdf5a..1996c2b642 100644
--- a/crates/rust-analyzer/src/reload.rs
+++ b/crates/rust-analyzer/src/reload.rs
@@ -630,10 +630,13 @@ impl GlobalState {
                 };
 
                 let env: FxHashMap<_, _> = match &ws.kind {
-                    ProjectWorkspaceKind::Cargo { cargo, .. }
-                    | ProjectWorkspaceKind::DetachedFile { cargo: Some((cargo, ..)), .. } => cargo
-                        .env()
-                        .into_iter()
+                    ProjectWorkspaceKind::Cargo { cargo_config_extra_env, .. }
+                    | ProjectWorkspaceKind::DetachedFile {
+                        cargo: Some(_),
+                        cargo_config_extra_env,
+                        ..
+                    } => cargo_config_extra_env
+                        .iter()
                         .chain(self.config.extra_env(None))
                         .map(|(a, b)| (a.clone(), b.clone()))
                         .chain(


Test patch:
diff --git a/crates/hir-def/src/body/tests.rs b/crates/hir-def/src/body/tests.rs
index 7e15a9f2d6..13ba4db606 100644
--- a/crates/hir-def/src/body/tests.rs
+++ b/crates/hir-def/src/body/tests.rs
@@ -52,7 +52,6 @@ fn your_stack_belongs_to_me() {
     cov_mark::check!(your_stack_belongs_to_me);
     lower(
         r#"
-#![recursion_limit = "32"]
 macro_rules! n_nuple {
     ($e:tt) => ();
     ($($rest:tt)*) => {{
@@ -69,7 +68,6 @@ fn your_stack_belongs_to_me2() {
     cov_mark::check!(overflow_but_not_me);
     lower(
         r#"
-#![recursion_limit = "32"]
 macro_rules! foo {
     () => {{ foo!(); foo!(); }}
 }
@@ -80,6 +78,8 @@ fn main() { foo!(); }
 
 #[test]
 fn recursion_limit() {
+    cov_mark::check!(your_stack_belongs_to_me);
+
     lower(
         r#"
 #![recursion_limit = "2"]
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index aca7bd3751..fe7f0c79f5 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -2322,53 +2322,6 @@ fn foo(Foo { b$0ar }: &Foo) {}
     )
 }
 
-#[test]
-fn test_hover_show_type_def_for_subst() {
-    check_actions(
-        r#"
-fn f<T>(t: T) {
-
-}
-
-struct S;
-
-fn test() {
-    let a = S;
-    f$0(a);
-}
-"#,
-        expect![[r#"
-            [
-                Reference(
-                    FilePositionWrapper {
-                        file_id: FileId(
-                            0,
-                        ),
-                        offset: 3,
-                    },
-                ),
-                GoToType(
-                    [
-                        HoverGotoTypeData {
-                            mod_path: "ra_test_fixture::S",
-                            nav: NavigationTarget {
-                                file_id: FileId(
-                                    0,
-                                ),
-                                full_range: 20..29,
-                                focus_range: 27..28,
-                                name: "S",
-                                kind: Struct,
-                                description: "struct S",
-                            },
-                        },
-                    ],
-                ),
-            ]
-        "#]],
-    );
-}
-
 #[test]
 fn test_hover_non_ascii_space_doc() {
     check(
@@ -8204,7 +8157,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 🦀🦀\A `
+            value of literal: 🦀🦀\A
         "#]],
     );
     check(
@@ -8220,7 +8173,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 🦀\u{1f980}\\\x41 `
+            value of literal: 🦀\u{1f980}\\\x41
         "#]],
     );
     check(
@@ -8242,7 +8195,7 @@ fsdghs";
             ```
             ___
 
-            value of literal (truncated up to newline): ` 🦀\u{1f980}\\\x41 `
+            value of literal (truncated up to newline): 🦀\u{1f980}\\\x41
         "#]],
     );
 }
@@ -8262,41 +8215,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 🦀🦀\A `
-        "#]],
-    );
-}
-
-#[test]
-fn rawstring_literal() {
-    check(
-        r#"
-fn main() {
-    $0r"`[^`]*`";
-}"#,
-        expect![[r#"
-            *r"`[^`]*`"*
-            ```rust
-            &str
-            ```
-            ___
-
-            value of literal: ```` `[^`]*` ````
-        "#]],
-    );
-    check(
-        r#"
-fn main() {
-    $0r"`";
-}"#,
-        expect![[r#"
-            *r"`"*
-            ```rust
-            &str
-            ```
-            ___
-
-            value of literal: `` ` ``
+            value of literal: 🦀🦀\A
         "#]],
     );
 }
@@ -8316,7 +8235,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` [240, 159, 166, 128, 92] `
+            value of literal: [240, 159, 166, 128, 92]
         "#]],
     );
     check(
@@ -8332,7 +8251,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92] `
+            value of literal: [92, 120, 70, 48, 92, 120, 57, 70, 92, 120, 65, 54, 92, 120, 56, 48, 92, 92]
         "#]],
     );
 }
@@ -8352,7 +8271,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 0xF0 `
+            value of literal: 0xF0
         "#]],
     );
     check(
@@ -8368,7 +8287,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 0x5C `
+            value of literal: 0x5C
         "#]],
     );
 }
@@ -8388,7 +8307,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` A `
+            value of literal: A
         "#]],
     );
     check(
@@ -8404,7 +8323,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` \ `
+            value of literal: \
         "#]],
     );
     check(
@@ -8420,7 +8339,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 🦀 `
+            value of literal: 🦀
         "#]],
     );
 }
@@ -8440,7 +8359,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 1 (bits: 0x3FF0000000000000) `
+            value of literal: 1 (bits: 0x3FF0000000000000)
         "#]],
     );
     check(
@@ -8456,7 +8375,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 1 (bits: 0x3C00) `
+            value of literal: 1 (bits: 0x3C00)
         "#]],
     );
     check(
@@ -8472,7 +8391,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 1 (bits: 0x3F800000) `
+            value of literal: 1 (bits: 0x3F800000)
         "#]],
     );
     check(
@@ -8488,7 +8407,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 1 (bits: 0x3FFF0000000000000000000000000000) `
+            value of literal: 1 (bits: 0x3FFF0000000000000000000000000000)
         "#]],
     );
     check(
@@ -8504,7 +8423,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 134000000000000 (bits: 0x42DE77D399980000) `
+            value of literal: 134000000000000 (bits: 0x42DE77D399980000)
         "#]],
     );
     check(
@@ -8520,7 +8439,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 1523527134274733600000000 (bits: 0x44F429E9249F629B) `
+            value of literal: 1523527134274733600000000 (bits: 0x44F429E9249F629B)
         "#]],
     );
     check(
@@ -8556,7 +8475,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010) `
+            value of literal: 34325236457856836345234 (0x744C659178614489D92|0b111010001001100011001011001000101111000011000010100010010001001110110010010)
         "#]],
     );
     check(
@@ -8572,7 +8491,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 13412342421 (0x31F701A95|0b1100011111011100000001101010010101) `
+            value of literal: 13412342421 (0x31F701A95|0b1100011111011100000001101010010101)
         "#]],
     );
     check(
@@ -8588,7 +8507,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 306328611 (0x12423423|0b10010010000100011010000100011) `
+            value of literal: 306328611 (0x12423423|0b10010010000100011010000100011)
         "#]],
     );
     check(
@@ -8604,7 +8523,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 255 (0xFF|0b11111111) `
+            value of literal: 255 (0xFF|0b11111111)
         "#]],
     );
     check(
@@ -8620,7 +8539,7 @@ fn main() {
             ```
             ___
 
-            value of literal: ` 5349 (0x14E5|0b1010011100101) `
+            value of literal: 5349 (0x14E5|0b1010011100101)
         "#]],
     );
     check(
diff --git a/crates/project-model/src/tests.rs b/crates/project-model/src/tests.rs
index cf77b875d8..9fc2d6116a 100644
--- a/crates/project-model/src/tests.rs
+++ b/crates/project-model/src/tests.rs
@@ -28,12 +28,13 @@ fn load_cargo_with_overrides(
     let meta: Metadata = get_test_json_file(file);
     let manifest_path =
         ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
-    let cargo_workspace = CargoWorkspace::new(meta, manifest_path, Default::default());
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
     let project_workspace = ProjectWorkspace {
         kind: ProjectWorkspaceKind::Cargo {
             cargo: cargo_workspace,
             build_scripts: WorkspaceBuildScripts::default(),
             rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
             error: None,
             set_test: true,
         },
@@ -227,7 +228,7 @@ fn smoke_test_real_sysroot_cargo() {
     let meta: Metadata = get_test_json_file("hello-world-metadata.json");
     let manifest_path =
         ManifestPath::try_from(AbsPathBuf::try_from(meta.workspace_root.clone()).unwrap()).unwrap();
-    let cargo_workspace = CargoWorkspace::new(meta, manifest_path, Default::default());
+    let cargo_workspace = CargoWorkspace::new(meta, manifest_path);
     let sysroot = Sysroot::discover(
         AbsPath::assert(Utf8Path::new(env!("CARGO_MANIFEST_DIR"))),
         &Default::default(),
@@ -239,6 +240,7 @@ fn smoke_test_real_sysroot_cargo() {
             cargo: cargo_workspace,
             build_scripts: WorkspaceBuildScripts::default(),
             rustc: Err(None),
+            cargo_config_extra_env: Default::default(),
             error: None,
             set_test: true,
         },
diff --git a/crates/rust-analyzer/src/cli/rustc_tests.rs b/crates/rust-analyzer/src/cli/rustc_tests.rs
index e45492e17e..dabc71b1b9 100644
--- a/crates/rust-analyzer/src/cli/rustc_tests.rs
+++ b/crates/rust-analyzer/src/cli/rustc_tests.rs
@@ -89,6 +89,7 @@ impl Tester {
             kind: ProjectWorkspaceKind::DetachedFile {
                 file: ManifestPath::try_from(tmp_file).unwrap(),
                 cargo: None,
+                cargo_config_extra_env: Default::default(),
                 set_test: true,
             },
             sysroot,