about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2025-05-28 23:05:24 +0000
committerbors <bors@rust-lang.org>2025-05-28 23:05:24 +0000
commitebe9b0060240953d721508ceb4d02a745efda88f (patch)
tree2ec1f66016d81a2667c186bed37897a8d7fc4cfe
parent6f69710780d579b180ab38da4c1384d630f7bd31 (diff)
parentd08ab512dd8f7ccecbc3a18718ca828b2a80fc6a (diff)
downloadrust-ebe9b0060240953d721508ceb4d02a745efda88f.tar.gz
rust-ebe9b0060240953d721508ceb4d02a745efda88f.zip
Auto merge of #141693 - lnicola:sync-from-ra, r=lnicola
Subtree update of `rust-analyzer`

r? `@ghost`
-rw-r--r--src/tools/rust-analyzer/Cargo.lock241
-rw-r--r--src/tools/rust-analyzer/Cargo.toml7
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/input.rs12
-rw-r--r--src/tools/rust-analyzer/crates/base-db/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs18
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres.rs8
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs4
-rw-r--r--src/tools/rust-analyzer/crates/hir-def/src/test_db.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs25
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs13
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/display.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs56
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs23
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs2
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs22
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs27
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/traits.rs5
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/lib.rs53
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics.rs150
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs19
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs24
-rw-r--r--src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs36
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs281
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs94
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs137
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs148
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs62
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context.rs6
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs33
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs50
-rw-r--r--src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs38
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/lib.rs4
-rw-r--r--src/tools/rust-analyzer/crates/ide-db/src/search.rs34
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs43
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs25
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs14
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs181
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide-ssr/src/search.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/expand_macro.rs116
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/highlight_related.rs2
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/render.rs76
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/hover/tests.rs128
-rw-r--r--src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs1
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs4
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs3
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs11
-rw-r--r--src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs2
-rw-r--r--src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs40
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs2
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs5
-rw-r--r--src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs20
-rw-r--r--src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs12
-rw-r--r--src/tools/rust-analyzer/docs/book/src/configuration_generated.md9
-rw-r--r--src/tools/rust-analyzer/docs/book/src/other_editors.md24
-rw-r--r--src/tools/rust-analyzer/editors/code/package.json29
62 files changed, 1513 insertions, 956 deletions
diff --git a/src/tools/rust-analyzer/Cargo.lock b/src/tools/rust-analyzer/Cargo.lock
index bd8146defae..01de430925d 100644
--- a/src/tools/rust-analyzer/Cargo.lock
+++ b/src/tools/rust-analyzer/Cargo.lock
@@ -18,15 +18,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "512761e0bb2578dd7380c6baaa0f4ce03e84f95e960231d1dec8bf4d7d6e2627"
 
 [[package]]
-name = "aho-corasick"
-version = "1.1.3"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8e60d3430d3a69478ad0993f19238d2df97c507009a52b3c10addcd7f6bcb916"
-dependencies = [
- "memchr",
-]
-
-[[package]]
 name = "allocator-api2"
 version = "0.2.21"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -124,12 +115,9 @@ dependencies = [
 
 [[package]]
 name = "boxcar"
-version = "0.2.11"
+version = "0.2.12"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6740c6e2fc6360fa57c35214c7493826aee95993926092606f27c983b40837be"
-dependencies = [
- "loom",
-]
+checksum = "66bb12751a83493ef4b8da1120451a262554e216a247f14b48cb5e8fe7ed8bdf"
 
 [[package]]
 name = "camino"
@@ -512,19 +500,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7ab85b9b05e3978cc9a9cf8fea7f01b494e1a09ed3037e16ba39edc7a29eb61a"
 
 [[package]]
-name = "generator"
-version = "0.8.4"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cc6bd114ceda131d3b1d665eba35788690ad37f5916457286b32ab6fd3c438dd"
-dependencies = [
- "cfg-if",
- "libc",
- "log",
- "rustversion",
- "windows 0.58.0",
-]
-
-[[package]]
 name = "getrandom"
 version = "0.2.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1214,19 +1189,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "30bde2b3dc3671ae49d8e2e9f044c7c005836e7a023ee57cffa25ab82764bb9e"
 
 [[package]]
-name = "loom"
-version = "0.7.2"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "419e0dc8046cb947daa77eb95ae174acfbddb7673b4151f56d1eed8e93fbfaca"
-dependencies = [
- "cfg-if",
- "generator",
- "scoped-tls",
- "tracing",
- "tracing-subscriber",
-]
-
-[[package]]
 name = "lsp-server"
 version = "0.7.8"
 dependencies = [
@@ -1266,15 +1228,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "matchers"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8263075bb86c5a1b1427b5ae862e8889656f126e9f77c484496e8b47cf5c5558"
-dependencies = [
- "regex-automata 0.1.10",
-]
-
-[[package]]
 name = "mbe"
 version = "0.0.0"
 dependencies = [
@@ -1402,16 +1355,6 @@ checksum = "5e0826a989adedc2a244799e823aece04662b66609d96af8dff7ac6df9a8925d"
 
 [[package]]
 name = "nu-ansi-term"
-version = "0.46.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "77a8165726e8236064dbb45459242600304b42a5ea24ee2948e18e023bf7ba84"
-dependencies = [
- "overload",
- "winapi",
-]
-
-[[package]]
-name = "nu-ansi-term"
 version = "0.50.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "d4a28e057d01f97e61255210fcff094d74ed0466038633e95017f5beb68e4399"
@@ -1472,12 +1415,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "04744f49eae99ab78e0d5c0b603ab218f515ea8cfe5a456d7629ad883a3b6e7d"
 
 [[package]]
-name = "overload"
-version = "0.1.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b15813163c1d831bf4a13c3610c05c0d03b39feb07f7e09fa234dac9b15aaf39"
-
-[[package]]
 name = "parking_lot"
 version = "0.12.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -1648,7 +1585,7 @@ dependencies = [
  "indexmap",
  "nix",
  "tracing",
- "windows 0.61.1",
+ "windows",
 ]
 
 [[package]]
@@ -1865,50 +1802,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "regex"
-version = "1.11.1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b544ef1b4eac5dc2db33ea63606ae9ffcfac26c1416a2806ae0bf5f56b201191"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-automata 0.4.9",
- "regex-syntax 0.8.5",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.1.10"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6c230d73fb8d8c1b9c0b3135c5142a8acee3a0558fb8db5cf1cb65f8d7862132"
-dependencies = [
- "regex-syntax 0.6.29",
-]
-
-[[package]]
-name = "regex-automata"
-version = "0.4.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "809e8dc61f6de73b46c85f4c96486310fe304c434cfa43669d7b40f711150908"
-dependencies = [
- "aho-corasick",
- "memchr",
- "regex-syntax 0.8.5",
-]
-
-[[package]]
-name = "regex-syntax"
-version = "0.6.29"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "f162c6dd7b008981e4d40210aca20b4bd0f9b60ca9271061b07f78537722f2e1"
-
-[[package]]
-name = "regex-syntax"
-version = "0.8.5"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2b15c43186be67a4fd63bee50d0303afffcef381492ebe2c5d87f324e1b8815c"
-
-[[package]]
 name = "rowan"
 version = "0.15.15"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2027,12 +1920,6 @@ dependencies = [
 ]
 
 [[package]]
-name = "rustversion"
-version = "1.0.20"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eded382c5f5f786b989652c49544c4877d9f015cc22e145a5ea8ea66c2921cd2"
-
-[[package]]
 name = "ryu"
 version = "1.0.20"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2040,9 +1927,9 @@ checksum = "28d3b2b1366ec20994f1fd18c3c594f05c5dd4bc44d8bb0c1c632c8d6829481f"
 
 [[package]]
 name = "salsa"
-version = "0.21.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6f80d5cf3c3fcab2cef898012f242a670477a1baa609267376af9cb4409026c5"
+checksum = "c8fff508e3d6ef42a32607f7538e17171a877a12015e32036f46e99d00c95781"
 dependencies = [
  "boxcar",
  "crossbeam-queue",
@@ -2063,15 +1950,15 @@ dependencies = [
 
 [[package]]
 name = "salsa-macro-rules"
-version = "0.21.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "05303d72606fbf2b9c9523cda2039bb8ecb00304027a3cd7e52b02a65c7d9185"
+checksum = "8ea72b3c06f2ce6350fe3a0eeb7aaaf842d1d8352b706973c19c4f02e298a87c"
 
 [[package]]
 name = "salsa-macros"
-version = "0.21.1"
+version = "0.22.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eb2f0e2a30c65cb3cd63440c491dde68d9af7e1be2b77832ac7057141107db50"
+checksum = "0ce92025bc160b27814a207cb78d680973af17f863c7f4fc56cf3a535e22f378"
 dependencies = [
  "heck",
  "proc-macro2",
@@ -2556,15 +2443,9 @@ version = "0.3.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "e8189decb5ac0fa7bc8b96b7cb9b2701d60d48805aca84a238004d665fcc4008"
 dependencies = [
- "matchers",
- "nu-ansi-term 0.46.0",
- "once_cell",
- "regex",
  "sharded-slab",
- "smallvec",
  "thread_local",
  "time",
- "tracing",
  "tracing-core",
  "tracing-log",
 ]
@@ -2575,7 +2456,7 @@ version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "f459ca79f1b0d5f71c54ddfde6debfc59c8b6eeb46808ae492077f739dc7b49c"
 dependencies = [
- "nu-ansi-term 0.50.1",
+ "nu-ansi-term",
  "tracing-core",
  "tracing-log",
  "tracing-subscriber",
@@ -2710,22 +2591,6 @@ source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
 
 [[package]]
-name = "winapi"
-version = "0.3.9"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "5c839a674fcd7a98952e593242ea400abe93992746761e38641405d28b00f419"
-dependencies = [
- "winapi-i686-pc-windows-gnu",
- "winapi-x86_64-pc-windows-gnu",
-]
-
-[[package]]
-name = "winapi-i686-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ac3b87c63620426dd9b991e5ce0329eff545bccbbb34f3be09ff6fb6ab51b7b6"
-
-[[package]]
 name = "winapi-util"
 version = "0.1.9"
 source = "registry+https://github.com/rust-lang/crates.io-index"
@@ -2735,29 +2600,13 @@ dependencies = [
 ]
 
 [[package]]
-name = "winapi-x86_64-pc-windows-gnu"
-version = "0.4.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "712e227841d057c1ee1cd2fb22fa7e5a5461ae8e48fa2ca79ec42cfc1931183f"
-
-[[package]]
-name = "windows"
-version = "0.58.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "dd04d41d93c4992d421894c18c8b43496aa748dd4c081bac0dc93eb0489272b6"
-dependencies = [
- "windows-core 0.58.0",
- "windows-targets 0.52.6",
-]
-
-[[package]]
 name = "windows"
 version = "0.61.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c5ee8f3d025738cb02bad7868bbb5f8a6327501e870bf51f1b455b0a2454a419"
 dependencies = [
  "windows-collections",
- "windows-core 0.61.0",
+ "windows-core",
  "windows-future",
  "windows-link",
  "windows-numerics",
@@ -2769,20 +2618,7 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "3beeceb5e5cfd9eb1d76b381630e82c4241ccd0d27f1a39ed41b2760b255c5e8"
 dependencies = [
- "windows-core 0.61.0",
-]
-
-[[package]]
-name = "windows-core"
-version = "0.58.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "6ba6d44ec8c2591c134257ce647b7ea6b20335bf6379a27dac5f1641fcf59f99"
-dependencies = [
- "windows-implement 0.58.0",
- "windows-interface 0.58.0",
- "windows-result 0.2.0",
- "windows-strings 0.1.0",
- "windows-targets 0.52.6",
+ "windows-core",
 ]
 
 [[package]]
@@ -2791,11 +2627,11 @@ version = "0.61.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "4763c1de310c86d75a878046489e2e5ba02c649d185f21c67d4cf8a56d098980"
 dependencies = [
- "windows-implement 0.60.0",
- "windows-interface 0.59.1",
+ "windows-implement",
+ "windows-interface",
  "windows-link",
- "windows-result 0.3.2",
- "windows-strings 0.4.0",
+ "windows-result",
+ "windows-strings",
 ]
 
 [[package]]
@@ -2804,23 +2640,12 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a1d6bbefcb7b60acd19828e1bc965da6fcf18a7e39490c5f8be71e54a19ba32"
 dependencies = [
- "windows-core 0.61.0",
+ "windows-core",
  "windows-link",
 ]
 
 [[package]]
 name = "windows-implement"
-version = "0.58.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2bbd5b46c938e506ecbce286b6628a02171d56153ba733b6c741fc627ec9579b"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "windows-implement"
 version = "0.60.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "a47fddd13af08290e67f4acabf4b459f647552718f683a7b415d290ac744a836"
@@ -2832,17 +2657,6 @@ dependencies = [
 
 [[package]]
 name = "windows-interface"
-version = "0.58.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "053c4c462dc91d3b1504c6fe5a726dd15e216ba718e84a0e46a88fbe5ded3515"
-dependencies = [
- "proc-macro2",
- "quote",
- "syn",
-]
-
-[[package]]
-name = "windows-interface"
 version = "0.59.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "bd9211b69f8dcdfa817bfd14bf1c97c9188afa36f4750130fcdf3f400eca9fa8"
@@ -2864,21 +2678,12 @@ version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "9150af68066c4c5c07ddc0ce30421554771e528bde427614c61038bc2c92c2b1"
 dependencies = [
- "windows-core 0.61.0",
+ "windows-core",
  "windows-link",
 ]
 
 [[package]]
 name = "windows-result"
-version = "0.2.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1d1043d8214f791817bab27572aaa8af63732e11bf84aa21a45a78d6c317ae0e"
-dependencies = [
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-result"
 version = "0.3.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "c64fd11a4fd95df68efcfee5f44a294fe71b8bc6a91993e2791938abcc712252"
@@ -2888,16 +2693,6 @@ dependencies = [
 
 [[package]]
 name = "windows-strings"
-version = "0.1.0"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4cd9b125c486025df0eabcb585e62173c6c9eddcec5d117d3b6e8c30e2ee4d10"
-dependencies = [
- "windows-result 0.2.0",
- "windows-targets 0.52.6",
-]
-
-[[package]]
-name = "windows-strings"
 version = "0.4.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
 checksum = "7a2ba9642430ee452d5a7aa78d72907ebe8cfda358e8cb7918a2050581322f97"
diff --git a/src/tools/rust-analyzer/Cargo.toml b/src/tools/rust-analyzer/Cargo.toml
index 07731bae3f3..8c507189846 100644
--- a/src/tools/rust-analyzer/Cargo.toml
+++ b/src/tools/rust-analyzer/Cargo.toml
@@ -132,11 +132,8 @@ pulldown-cmark-to-cmark = "10.0.4"
 pulldown-cmark = { version = "0.9.6", default-features = false }
 rayon = "1.10.0"
 rowan = "=0.15.15"
-salsa = { version = "0.21.1", default-features = false, features = [
-  "rayon",
-  "salsa_unstable",
-] }
-salsa-macros = "0.21.1"
+salsa = { version = "0.22.0", default-features = false, features = ["rayon","salsa_unstable"] }
+salsa-macros = "0.22.0"
 semver = "1.0.26"
 serde = { version = "1.0.219" }
 serde_derive = { version = "1.0.219" }
diff --git a/src/tools/rust-analyzer/crates/base-db/src/input.rs b/src/tools/rust-analyzer/crates/base-db/src/input.rs
index d42d7e5707d..745238167bc 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/input.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/input.rs
@@ -395,21 +395,21 @@ impl BuiltDependency {
 pub type CratesIdMap = FxHashMap<CrateBuilderId, Crate>;
 
 #[salsa_macros::input]
-#[derive(Debug)]
+#[derive(Debug, PartialOrd, Ord)]
 pub struct Crate {
-    #[return_ref]
+    #[returns(ref)]
     pub data: BuiltCrateData,
     /// Crate data that is not needed for analysis.
     ///
     /// This is split into a separate field to increase incrementality.
-    #[return_ref]
+    #[returns(ref)]
     pub extra_data: ExtraCrateData,
     // This is in `Arc` because it is shared for all crates in a workspace.
-    #[return_ref]
+    #[returns(ref)]
     pub workspace_data: Arc<CrateWorkspaceData>,
-    #[return_ref]
+    #[returns(ref)]
     pub cfg_options: CfgOptions,
-    #[return_ref]
+    #[returns(ref)]
     pub env: Env,
 }
 
diff --git a/src/tools/rust-analyzer/crates/base-db/src/lib.rs b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
index a67fbf75c02..4d4e6cae037 100644
--- a/src/tools/rust-analyzer/crates/base-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/base-db/src/lib.rs
@@ -32,6 +32,7 @@ pub use vfs::{AnchoredPath, AnchoredPathBuf, FileId, VfsPath, file_set::FileSet}
 macro_rules! impl_intern_key {
     ($id:ident, $loc:ident) => {
         #[salsa_macros::interned(no_lifetime)]
+        #[derive(PartialOrd, Ord)]
         pub struct $id {
             pub loc: $loc,
         }
@@ -165,6 +166,7 @@ impl Files {
 }
 
 #[salsa_macros::interned(no_lifetime, debug, constructor=from_span)]
+#[derive(PartialOrd, Ord)]
 pub struct EditionedFileId {
     pub editioned_file_id: span::EditionedFileId,
 }
@@ -356,7 +358,7 @@ fn parse(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Parse<ast::SourceFil
 }
 
 fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<&[SyntaxError]> {
-    #[salsa_macros::tracked(return_ref)]
+    #[salsa_macros::tracked(returns(ref))]
     fn parse_errors(db: &dyn RootQueryDb, file_id: EditionedFileId) -> Option<Box<[SyntaxError]>> {
         let errors = db.parse(file_id).errors();
         match &*errors {
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
index 59344641f47..4ad44775ea1 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/lang_item.rs
@@ -85,7 +85,7 @@ impl LangItemTarget {
 }
 
 /// Salsa query. This will look for lang items in a specific crate.
-#[salsa_macros::tracked(return_ref)]
+#[salsa_macros::tracked(returns(ref))]
 pub fn crate_lang_items(db: &dyn DefDatabase, krate: Crate) -> Option<Box<LangItems>> {
     let _p = tracing::info_span!("crate_lang_items_query").entered();
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
index 3027aff3163..293868df613 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/macro_expansion_tests/builtin_fn_macro.rs
@@ -510,24 +510,6 @@ fn main() { "s"; }
 }
 
 #[test]
-fn test_concat_idents_expand() {
-    check(
-        r##"
-#[rustc_builtin_macro]
-macro_rules! concat_idents {}
-
-fn main() { concat_idents!(foo, bar); }
-"##,
-        expect![[r##"
-#[rustc_builtin_macro]
-macro_rules! concat_idents {}
-
-fn main() { foobar; }
-"##]],
-    );
-}
-
-#[test]
 fn test_quote_string() {
     check(
         r##"
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
index d4b30a1d3e6..f337f83156a 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres.rs
@@ -381,15 +381,15 @@ mod __ {
     #[salsa_macros::tracked]
     pub(crate) struct DefMapPair<'db> {
         #[tracked]
-        #[return_ref]
+        #[returns(ref)]
         pub(crate) def_map: DefMap,
-        #[return_ref]
+        #[returns(ref)]
         pub(crate) local: LocalDefMap,
     }
 }
 pub(crate) use __::DefMapPair;
 
-#[salsa_macros::tracked(return_ref)]
+#[salsa_macros::tracked(returns(ref))]
 pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefMapPair<'_> {
     let krate = crate_id.data(db);
     let _p = tracing::info_span!(
@@ -420,7 +420,7 @@ pub(crate) fn crate_local_def_map(db: &dyn DefDatabase, crate_id: Crate) -> DefM
     DefMapPair::new(db, def_map, local_def_map)
 }
 
-#[salsa_macros::tracked(return_ref)]
+#[salsa_macros::tracked(returns(ref))]
 pub fn block_def_map(db: &dyn DefDatabase, block_id: BlockId) -> DefMap {
     let BlockLoc { ast_id, module } = block_id.lookup(db);
 
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
index d45709b8b90..86225d33b4e 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/nameres/assoc.rs
@@ -75,7 +75,7 @@ impl TraitItems {
         })
     }
 
-    pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
+    pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
         self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
 }
@@ -109,7 +109,7 @@ impl ImplItems {
         (Arc::new(ImplItems { items, macro_calls }), DefDiagnostics::new(diagnostics))
     }
 
-    pub fn attribute_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
+    pub fn macro_calls(&self) -> impl Iterator<Item = (AstId<ast::Item>, MacroCallId)> + '_ {
         self.macro_calls.iter().flat_map(|it| it.iter()).copied()
     }
 }
diff --git a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
index 6c995ab6c23..e30a5b65a1f 100644
--- a/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-def/src/test_db.rs
@@ -30,9 +30,18 @@ pub(crate) struct TestDB {
 
 impl Default for TestDB {
     fn default() -> Self {
+        let events = <Arc<Mutex<Option<Vec<salsa::Event>>>>>::default();
         let mut this = Self {
-            storage: Default::default(),
-            events: Default::default(),
+            storage: salsa::Storage::new(Some(Box::new({
+                let events = events.clone();
+                move |event| {
+                    let mut events = events.lock().unwrap();
+                    if let Some(events) = &mut *events {
+                        events.push(event);
+                    }
+                }
+            }))),
+            events,
             files: Default::default(),
             crates_map: Default::default(),
         };
@@ -45,15 +54,7 @@ impl Default for TestDB {
 }
 
 #[salsa_macros::db]
-impl salsa::Database for TestDB {
-    fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) {
-        let mut events = self.events.lock().unwrap();
-        if let Some(events) = &mut *events {
-            let event = event();
-            events.push(event);
-        }
-    }
-}
+impl salsa::Database for TestDB {}
 
 impl fmt::Debug for TestDB {
     fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
diff --git a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
index 539c7277284..3180b8dae10 100644
--- a/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
+++ b/src/tools/rust-analyzer/crates/hir-expand/src/builtin/fn_macro.rs
@@ -140,7 +140,6 @@ register_builtin! {
     EagerExpander:
     (compile_error, CompileError) => compile_error_expand,
     (concat, Concat) => concat_expand,
-    (concat_idents, ConcatIdents) => concat_idents_expand,
     (concat_bytes, ConcatBytes) => concat_bytes_expand,
     (include, Include) => include_expand,
     (include_bytes, IncludeBytes) => include_bytes_expand,
@@ -660,30 +659,6 @@ fn concat_bytes_expand_subtree(
     Ok(())
 }
 
-fn concat_idents_expand(
-    _db: &dyn ExpandDatabase,
-    _arg_id: MacroCallId,
-    tt: &tt::TopSubtree,
-    span: Span,
-) -> ExpandResult<tt::TopSubtree> {
-    let mut err = None;
-    let mut ident = String::new();
-    for (i, t) in tt.iter().enumerate() {
-        match t {
-            TtElement::Leaf(tt::Leaf::Ident(id)) => {
-                ident.push_str(id.sym.as_str());
-            }
-            TtElement::Leaf(tt::Leaf::Punct(punct)) if i % 2 == 1 && punct.char == ',' => (),
-            _ => {
-                err.get_or_insert(ExpandError::other(span, "unexpected token"));
-            }
-        }
-    }
-    // FIXME merge spans
-    let ident = tt::Ident { sym: Symbol::intern(&ident), span, is_raw: tt::IdentIsRaw::No };
-    ExpandResult { value: quote!(span =>#ident), err }
-}
-
 fn relative_file(
     db: &dyn ExpandDatabase,
     call_id: MacroCallId,
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
index cd799c03ddf..22b96b55cbb 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/chalk_db.rs
@@ -259,7 +259,7 @@ impl chalk_solve::RustIrDatabase<Interner> for ChalkContext<'_> {
     }
     fn well_known_trait_id(
         &self,
-        well_known_trait: rust_ir::WellKnownTrait,
+        well_known_trait: WellKnownTrait,
     ) -> Option<chalk_ir::TraitId<Interner>> {
         let lang_attr = lang_item_from_well_known_trait(well_known_trait);
         let trait_ = lang_attr.resolve_trait(self.db, self.krate)?;
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
index e4a23cbbacf..9eb7ffe1c71 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/expr.rs
@@ -25,7 +25,7 @@ use triomphe::Arc;
 use typed_arena::Arena;
 
 use crate::{
-    Adjust, InferenceResult, Interner, Ty, TyExt, TyKind,
+    Adjust, InferenceResult, Interner, TraitEnvironment, Ty, TyExt, TyKind,
     db::HirDatabase,
     diagnostics::match_check::{
         self,
@@ -74,8 +74,9 @@ impl BodyValidationDiagnostic {
         let _p = tracing::info_span!("BodyValidationDiagnostic::collect").entered();
         let infer = db.infer(owner);
         let body = db.body(owner);
+        let env = db.trait_environment_for_body(owner);
         let mut validator =
-            ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints };
+            ExprValidator { owner, body, infer, diagnostics: Vec::new(), validate_lints, env };
         validator.validate_body(db);
         validator.diagnostics
     }
@@ -85,6 +86,7 @@ struct ExprValidator {
     owner: DefWithBodyId,
     body: Arc<Body>,
     infer: Arc<InferenceResult>,
+    env: Arc<TraitEnvironment>,
     diagnostics: Vec<BodyValidationDiagnostic>,
     validate_lints: bool,
 }
@@ -190,7 +192,7 @@ impl ExprValidator {
             return;
         }
 
-        let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db);
+        let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
 
         let pattern_arena = Arena::new();
         let mut m_arms = Vec::with_capacity(arms.len());
@@ -317,11 +319,14 @@ impl ExprValidator {
             return;
         };
         let pattern_arena = Arena::new();
-        let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db);
+        let cx = MatchCheckCtx::new(self.owner.module(db), self.owner, db, self.env.clone());
         for stmt in &**statements {
             let &Statement::Let { pat, initializer, else_branch: None, .. } = stmt else {
                 continue;
             };
+            if self.infer.type_mismatch_for_pat(pat).is_some() {
+                continue;
+            }
             let Some(initializer) = initializer else { continue };
             let ty = &self.infer[initializer];
             if ty.contains_unknown() {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
index 785277d70c6..dd82a0f45ca 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/diagnostics/match_check/pat_analysis.rs
@@ -12,9 +12,10 @@ use rustc_pattern_analysis::{
 };
 use smallvec::{SmallVec, smallvec};
 use stdx::never;
+use triomphe::Arc;
 
 use crate::{
-    AdtId, Interner, Scalar, Ty, TyExt, TyKind,
+    AdtId, Interner, Scalar, TraitEnvironment, Ty, TyExt, TyKind,
     db::HirDatabase,
     infer::normalize,
     inhabitedness::{is_enum_variant_uninhabited_from, is_ty_uninhabited_from},
@@ -69,13 +70,19 @@ pub(crate) struct MatchCheckCtx<'db> {
     body: DefWithBodyId,
     pub(crate) db: &'db dyn HirDatabase,
     exhaustive_patterns: bool,
+    env: Arc<TraitEnvironment>,
 }
 
 impl<'db> MatchCheckCtx<'db> {
-    pub(crate) fn new(module: ModuleId, body: DefWithBodyId, db: &'db dyn HirDatabase) -> Self {
+    pub(crate) fn new(
+        module: ModuleId,
+        body: DefWithBodyId,
+        db: &'db dyn HirDatabase,
+        env: Arc<TraitEnvironment>,
+    ) -> Self {
         let def_map = module.crate_def_map(db);
         let exhaustive_patterns = def_map.is_unstable_feature_enabled(&sym::exhaustive_patterns);
-        Self { module, body, db, exhaustive_patterns }
+        Self { module, body, db, exhaustive_patterns, env }
     }
 
     pub(crate) fn compute_match_usefulness(
@@ -100,7 +107,7 @@ impl<'db> MatchCheckCtx<'db> {
     }
 
     fn is_uninhabited(&self, ty: &Ty) -> bool {
-        is_ty_uninhabited_from(self.db, ty, self.module)
+        is_ty_uninhabited_from(self.db, ty, self.module, self.env.clone())
     }
 
     /// Returns whether the given ADT is from another crate declared `#[non_exhaustive]`.
@@ -459,8 +466,13 @@ impl PatCx for MatchCheckCtx<'_> {
                 } else {
                     let mut variants = IndexVec::with_capacity(enum_data.variants.len());
                     for &(variant, _) in enum_data.variants.iter() {
-                        let is_uninhabited =
-                            is_enum_variant_uninhabited_from(cx.db, variant, subst, cx.module);
+                        let is_uninhabited = is_enum_variant_uninhabited_from(
+                            cx.db,
+                            variant,
+                            subst,
+                            cx.module,
+                            self.env.clone(),
+                        );
                         let visibility = if is_uninhabited {
                             VariantVisibility::Empty
                         } else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
index f0989d9de91..f210dd8799f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/display.rs
@@ -1463,6 +1463,8 @@ impl HirDisplay for Ty {
                     }
                     if f.closure_style == ClosureStyle::RANotation || !sig.ret().is_unit() {
                         write!(f, " -> ")?;
+                        // FIXME: We display `AsyncFn` as `-> impl Future`, but this is hard to fix because
+                        // we don't have a trait environment here, required to normalize `<Ret as Future>::Output`.
                         sig.ret().hir_fmt(f)?;
                     }
                 } else {
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
index 800897c6fc3..bd57ca89162 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/closure.rs
@@ -38,7 +38,7 @@ use crate::{
     infer::{BreakableKind, CoerceMany, Diverges, coerce::CoerceNever},
     make_binders,
     mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
-    to_chalk_trait_id,
+    to_assoc_type_id, to_chalk_trait_id,
     traits::FnTrait,
     utils::{self, elaborate_clause_supertraits},
 };
@@ -245,7 +245,7 @@ impl InferenceContext<'_> {
     }
 
     fn deduce_closure_kind_from_predicate_clauses(
-        &self,
+        &mut self,
         expected_ty: &Ty,
         clauses: impl DoubleEndedIterator<Item = WhereClause>,
         closure_kind: ClosureKind,
@@ -378,7 +378,7 @@ impl InferenceContext<'_> {
     }
 
     fn deduce_sig_from_projection(
-        &self,
+        &mut self,
         closure_kind: ClosureKind,
         projection_ty: &ProjectionTy,
         projected_ty: &Ty,
@@ -392,13 +392,16 @@ impl InferenceContext<'_> {
 
         // For now, we only do signature deduction based off of the `Fn` and `AsyncFn` traits,
         // for closures and async closures, respectively.
-        match closure_kind {
-            ClosureKind::Closure | ClosureKind::Async
-                if self.fn_trait_kind_from_trait_id(trait_).is_some() =>
-            {
-                self.extract_sig_from_projection(projection_ty, projected_ty)
-            }
-            _ => None,
+        let fn_trait_kind = self.fn_trait_kind_from_trait_id(trait_)?;
+        if !matches!(closure_kind, ClosureKind::Closure | ClosureKind::Async) {
+            return None;
+        }
+        if fn_trait_kind.is_async() {
+            // If the expected trait is `AsyncFn(...) -> X`, we don't know what the return type is,
+            // but we do know it must implement `Future<Output = X>`.
+            self.extract_async_fn_sig_from_projection(projection_ty, projected_ty)
+        } else {
+            self.extract_sig_from_projection(projection_ty, projected_ty)
         }
     }
 
@@ -424,6 +427,39 @@ impl InferenceContext<'_> {
         )))
     }
 
+    fn extract_async_fn_sig_from_projection(
+        &mut self,
+        projection_ty: &ProjectionTy,
+        projected_ty: &Ty,
+    ) -> Option<FnSubst<Interner>> {
+        let arg_param_ty = projection_ty.substitution.as_slice(Interner)[1].assert_ty_ref(Interner);
+
+        let TyKind::Tuple(_, input_tys) = arg_param_ty.kind(Interner) else {
+            return None;
+        };
+
+        let ret_param_future_output = projected_ty;
+        let ret_param_future = self.table.new_type_var();
+        let future_output =
+            LangItem::FutureOutput.resolve_type_alias(self.db, self.resolver.krate())?;
+        let future_projection = crate::AliasTy::Projection(crate::ProjectionTy {
+            associated_ty_id: to_assoc_type_id(future_output),
+            substitution: Substitution::from1(Interner, ret_param_future.clone()),
+        });
+        self.table.register_obligation(
+            crate::AliasEq { alias: future_projection, ty: ret_param_future_output.clone() }
+                .cast(Interner),
+        );
+
+        Some(FnSubst(Substitution::from_iter(
+            Interner,
+            input_tys.iter(Interner).map(|t| t.cast(Interner)).chain(Some(GenericArg::new(
+                Interner,
+                chalk_ir::GenericArgData::Ty(ret_param_future),
+            ))),
+        )))
+    }
+
     fn fn_trait_kind_from_trait_id(&self, trait_id: hir_def::TraitId) -> Option<FnTrait> {
         FnTrait::from_lang_item(self.db.lang_attr(trait_id.into())?)
     }
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
index e0c3279d3fb..e81a5e3c311 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/inhabitedness.rs
@@ -7,17 +7,24 @@ use chalk_ir::{
 };
 use hir_def::{AdtId, EnumVariantId, ModuleId, VariantId, visibility::Visibility};
 use rustc_hash::FxHashSet;
+use triomphe::Arc;
 
 use crate::{
-    Binders, Interner, Substitution, Ty, TyKind, consteval::try_const_usize, db::HirDatabase,
+    AliasTy, Binders, Interner, Substitution, TraitEnvironment, Ty, TyKind,
+    consteval::try_const_usize, db::HirDatabase,
 };
 
 // FIXME: Turn this into a query, it can be quite slow
 /// Checks whether a type is visibly uninhabited from a particular module.
-pub(crate) fn is_ty_uninhabited_from(db: &dyn HirDatabase, ty: &Ty, target_mod: ModuleId) -> bool {
+pub(crate) fn is_ty_uninhabited_from(
+    db: &dyn HirDatabase,
+    ty: &Ty,
+    target_mod: ModuleId,
+    env: Arc<TraitEnvironment>,
+) -> bool {
     let _p = tracing::info_span!("is_ty_uninhabited_from", ?ty).entered();
     let mut uninhabited_from =
-        UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
+        UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
     let inhabitedness = ty.visit_with(&mut uninhabited_from, DebruijnIndex::INNERMOST);
     inhabitedness == BREAK_VISIBLY_UNINHABITED
 }
@@ -29,11 +36,12 @@ pub(crate) fn is_enum_variant_uninhabited_from(
     variant: EnumVariantId,
     subst: &Substitution,
     target_mod: ModuleId,
+    env: Arc<TraitEnvironment>,
 ) -> bool {
     let _p = tracing::info_span!("is_enum_variant_uninhabited_from").entered();
 
     let mut uninhabited_from =
-        UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default() };
+        UninhabitedFrom { target_mod, db, max_depth: 500, recursive_ty: FxHashSet::default(), env };
     let inhabitedness = uninhabited_from.visit_variant(variant.into(), subst);
     inhabitedness == BREAK_VISIBLY_UNINHABITED
 }
@@ -44,6 +52,7 @@ struct UninhabitedFrom<'a> {
     // guard for preventing stack overflow in non trivial non terminating types
     max_depth: usize,
     db: &'a dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
 }
 
 const CONTINUE_OPAQUELY_INHABITED: ControlFlow<VisiblyUninhabited> = Continue(());
@@ -78,6 +87,12 @@ impl TypeVisitor<Interner> for UninhabitedFrom<'_> {
                 Some(0) | None => CONTINUE_OPAQUELY_INHABITED,
                 Some(1..) => item_ty.super_visit_with(self, outer_binder),
             },
+            TyKind::Alias(AliasTy::Projection(projection)) => {
+                // FIXME: I think this currently isn't used for monomorphized bodies, so there is no need to handle
+                // `TyKind::AssociatedType`, but perhaps in the future it will.
+                let normalized = self.db.normalize_projection(projection.clone(), self.env.clone());
+                self.visit_ty(&normalized, outer_binder)
+            }
             _ => CONTINUE_OPAQUELY_INHABITED,
         };
         self.recursive_ty.remove(ty);
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
index 7cf948b178e..90c52ee96f1 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/eval/shim.rs
@@ -1121,7 +1121,7 @@ impl Evaluator<'_> {
                 // We don't call any drop glue yet, so there is nothing here
                 Ok(())
             }
-            "transmute" => {
+            "transmute" | "transmute_unchecked" => {
                 let [arg] = args else {
                     return Err(MirEvalError::InternalError(
                         "transmute arg is not provided".into(),
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
index 7fcc89e5183..e6caf2d8d97 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/mir/lower.rs
@@ -25,7 +25,7 @@ use syntax::TextRange;
 use triomphe::Arc;
 
 use crate::{
-    Adjust, Adjustment, AutoBorrow, CallableDefId, TyBuilder, TyExt,
+    Adjust, Adjustment, AutoBorrow, CallableDefId, TraitEnvironment, TyBuilder, TyExt,
     consteval::ConstEvalError,
     db::{HirDatabase, InternedClosure, InternedClosureId},
     display::{DisplayTarget, HirDisplay, hir_display_with_store},
@@ -79,6 +79,7 @@ struct MirLowerCtx<'db> {
     infer: &'db InferenceResult,
     resolver: Resolver<'db>,
     drop_scopes: Vec<DropScope>,
+    env: Arc<TraitEnvironment>,
 }
 
 // FIXME: Make this smaller, its stored in database queries
@@ -288,6 +289,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             closures: vec![],
         };
         let resolver = owner.resolver(db);
+        let env = db.trait_environment_for_body(owner);
 
         MirLowerCtx {
             result: mir,
@@ -300,6 +302,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
             labeled_loop_blocks: Default::default(),
             discr_temp: None,
             drop_scopes: vec![DropScope::default()],
+            env,
         }
     }
 
@@ -944,10 +947,7 @@ impl<'ctx> MirLowerCtx<'ctx> {
                     let cast_kind = if source_ty.as_reference().is_some() {
                         CastKind::PointerCoercion(PointerCast::ArrayToPointer)
                     } else {
-                        let mut table = InferenceTable::new(
-                            self.db,
-                            self.db.trait_environment_for_body(self.owner),
-                        );
+                        let mut table = InferenceTable::new(self.db, self.env.clone());
                         cast_kind(&mut table, &source_ty, &target_ty)?
                     };
 
@@ -1412,11 +1412,8 @@ impl<'ctx> MirLowerCtx<'ctx> {
     }
 
     fn lower_literal_to_operand(&mut self, ty: Ty, l: &Literal) -> Result<Operand> {
-        let size = || {
-            self.db
-                .layout_of_ty(ty.clone(), self.db.trait_environment_for_body(self.owner))
-                .map(|it| it.size.bytes_usize())
-        };
+        let size =
+            || self.db.layout_of_ty(ty.clone(), self.env.clone()).map(|it| it.size.bytes_usize());
         const USIZE_SIZE: usize = size_of::<usize>();
         let bytes: Box<[_]> = match l {
             hir_def::hir::Literal::String(b) => {
@@ -1723,7 +1720,12 @@ impl<'ctx> MirLowerCtx<'ctx> {
     }
 
     fn is_uninhabited(&self, expr_id: ExprId) -> bool {
-        is_ty_uninhabited_from(self.db, &self.infer[expr_id], self.owner.module(self.db))
+        is_ty_uninhabited_from(
+            self.db,
+            &self.infer[expr_id],
+            self.owner.module(self.db),
+            self.env.clone(),
+        )
     }
 
     /// This function push `StorageLive` statement for the binding, and applies changes to add `StorageDead` and
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
index 8f0d17c9dc4..d049c678e2d 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/test_db.rs
@@ -27,9 +27,18 @@ pub(crate) struct TestDB {
 
 impl Default for TestDB {
     fn default() -> Self {
+        let events = <Arc<Mutex<Option<Vec<salsa::Event>>>>>::default();
         let mut this = Self {
-            storage: Default::default(),
-            events: Default::default(),
+            storage: salsa::Storage::new(Some(Box::new({
+                let events = events.clone();
+                move |event| {
+                    let mut events = events.lock().unwrap();
+                    if let Some(events) = &mut *events {
+                        events.push(event);
+                    }
+                }
+            }))),
+            events,
             files: Default::default(),
             crates_map: Default::default(),
         };
@@ -103,14 +112,7 @@ impl SourceDatabase for TestDB {
 }
 
 #[salsa_macros::db]
-impl salsa::Database for TestDB {
-    fn salsa_event(&self, event: &dyn std::ops::Fn() -> salsa::Event) {
-        let mut events = self.events.lock().unwrap();
-        if let Some(events) = &mut *events {
-            events.push(event());
-        }
-    }
-}
+impl salsa::Database for TestDB {}
 
 impl panic::RefUnwindSafe for TestDB {}
 
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
index 2b527a4ae12..e5d1fbe9def 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/tests/traits.rs
@@ -4903,3 +4903,30 @@ fn main() {
         "#]],
     );
 }
+
+#[test]
+fn async_fn_return_type() {
+    check_infer(
+        r#"
+//- minicore: async_fn
+fn foo<F: AsyncFn() -> R, R>(_: F) -> R {
+    loop {}
+}
+
+fn main() {
+    foo(async move || ());
+}
+    "#,
+        expect![[r#"
+            29..30 '_': F
+            40..55 '{     loop {} }': R
+            46..53 'loop {}': !
+            51..53 '{}': ()
+            67..97 '{     ...()); }': ()
+            73..76 'foo': fn foo<impl AsyncFn() -> impl Future<Output = ()>, ()>(impl AsyncFn() -> impl Future<Output = ()>)
+            73..94 'foo(as...|| ())': ()
+            77..93 'async ... || ()': impl AsyncFn() -> impl Future<Output = ()>
+            91..93 '()': ()
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
index f9f8776cff7..7414b4fc607 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/traits.rs
@@ -291,4 +291,9 @@ impl FnTrait {
     pub fn get_id(self, db: &dyn HirDatabase, krate: Crate) -> Option<TraitId> {
         self.lang_item().resolve_trait(db, krate)
     }
+
+    #[inline]
+    pub(crate) fn is_async(self) -> bool {
+        matches!(self, FnTrait::AsyncFn | FnTrait::AsyncFnMut | FnTrait::AsyncFnOnce)
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/hir/src/lib.rs b/src/tools/rust-analyzer/crates/hir/src/lib.rs
index 3a91050d15f..e8218cf8611 100644
--- a/src/tools/rust-analyzer/crates/hir/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/lib.rs
@@ -5972,6 +5972,59 @@ impl Layout {
         }
     }
 
+    pub fn tail_padding(&self, field_size: &mut impl FnMut(usize) -> Option<u64>) -> Option<u64> {
+        match self.0.fields {
+            layout::FieldsShape::Primitive => None,
+            layout::FieldsShape::Union(_) => None,
+            layout::FieldsShape::Array { stride, count } => count.checked_sub(1).and_then(|tail| {
+                let tail_field_size = field_size(tail as usize)?;
+                let offset = stride.bytes() * tail;
+                self.0.size.bytes().checked_sub(offset)?.checked_sub(tail_field_size)
+            }),
+            layout::FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
+                let tail = memory_index.last_index()?;
+                let tail_field_size = field_size(tail.0.into_raw().into_u32() as usize)?;
+                let offset = offsets.get(tail)?.bytes();
+                self.0.size.bytes().checked_sub(offset)?.checked_sub(tail_field_size)
+            }
+        }
+    }
+
+    pub fn largest_padding(
+        &self,
+        field_size: &mut impl FnMut(usize) -> Option<u64>,
+    ) -> Option<u64> {
+        match self.0.fields {
+            layout::FieldsShape::Primitive => None,
+            layout::FieldsShape::Union(_) => None,
+            layout::FieldsShape::Array { stride: _, count: 0 } => None,
+            layout::FieldsShape::Array { stride, .. } => {
+                let size = field_size(0)?;
+                stride.bytes().checked_sub(size)
+            }
+            layout::FieldsShape::Arbitrary { ref offsets, ref memory_index } => {
+                let mut reverse_index = vec![None; memory_index.len()];
+                for (src, (mem, offset)) in memory_index.iter().zip(offsets.iter()).enumerate() {
+                    reverse_index[*mem as usize] = Some((src, offset.bytes()));
+                }
+                if reverse_index.iter().any(|it| it.is_none()) {
+                    stdx::never!();
+                    return None;
+                }
+                reverse_index
+                    .into_iter()
+                    .flatten()
+                    .chain(std::iter::once((0, self.0.size.bytes())))
+                    .tuple_windows()
+                    .filter_map(|((i, start), (_, end))| {
+                        let size = field_size(i)?;
+                        end.checked_sub(start)?.checked_sub(size)
+                    })
+                    .max()
+            }
+        }
+    }
+
     pub fn enum_tag_size(&self) -> Option<usize> {
         let tag_size =
             if let layout::Variants::Multiple { tag, tag_encoding, .. } = &self.0.variants {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics.rs b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
index caa6700de9f..aea22545ed5 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics.rs
@@ -147,7 +147,7 @@ impl TypeInfo {
 }
 
 /// Primary API to get semantic information, like types, from syntax trees.
-pub struct Semantics<'db, DB> {
+pub struct Semantics<'db, DB: ?Sized> {
     pub db: &'db DB,
     imp: SemanticsImpl<'db>,
 }
@@ -407,14 +407,10 @@ impl<'db> SemanticsImpl<'db> {
         res
     }
 
-    pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option<SyntaxNode> {
-        let sa = self.analyze_no_infer(macro_call.syntax())?;
-
-        let macro_call = InFile::new(sa.file_id, macro_call);
-        let file_id = sa.expand(self.db, macro_call)?;
-
+    pub fn expand_macro_call(&self, macro_call: &ast::MacroCall) -> Option<InFile<SyntaxNode>> {
+        let file_id = self.to_def(macro_call)?;
         let node = self.parse_or_expand(file_id.into());
-        Some(node)
+        Some(InFile::new(file_id.into(), node))
     }
 
     pub fn check_cfg_attr(&self, attr: &ast::TokenTree) -> Option<bool> {
@@ -434,10 +430,7 @@ impl<'db> SemanticsImpl<'db> {
         &self,
         macro_call: &ast::MacroCall,
     ) -> Option<ExpandResult<SyntaxNode>> {
-        let sa = self.analyze_no_infer(macro_call.syntax())?;
-
-        let macro_call = InFile::new(sa.file_id, macro_call);
-        let file_id = sa.expand(self.db, macro_call)?;
+        let file_id = self.to_def(macro_call)?;
         let macro_call = self.db.lookup_intern_macro_call(file_id);
 
         let skip = matches!(
@@ -468,10 +461,10 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     /// If `item` has an attribute macro attached to it, expands it.
-    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<ExpandResult<SyntaxNode>> {
+    pub fn expand_attr_macro(&self, item: &ast::Item) -> Option<ExpandResult<InFile<SyntaxNode>>> {
         let src = self.wrap_node_infile(item.clone());
         let macro_call_id = self.with_ctx(|ctx| ctx.item_to_macro_call(src.as_ref()))?;
-        Some(self.expand(macro_call_id))
+        Some(self.expand(macro_call_id).map(|it| InFile::new(macro_call_id.into(), it)))
     }
 
     pub fn expand_derive_as_pseudo_attr_macro(&self, attr: &ast::Attr) -> Option<SyntaxNode> {
@@ -574,9 +567,7 @@ impl<'db> SemanticsImpl<'db> {
         speculative_args: &ast::TokenTree,
         token_to_map: SyntaxToken,
     ) -> Option<(SyntaxNode, Vec<(SyntaxToken, u8)>)> {
-        let analyzer = self.analyze_no_infer(actual_macro_call.syntax())?;
-        let macro_call = InFile::new(analyzer.file_id, actual_macro_call);
-        let macro_file = analyzer.expansion(macro_call)?;
+        let macro_file = self.to_def(actual_macro_call)?;
         hir_expand::db::expand_speculative(
             self.db,
             macro_file,
@@ -778,6 +769,31 @@ impl<'db> SemanticsImpl<'db> {
         })
     }
 
+    /// Descends the token into the include expansion, if its file is an included file.
+    pub fn descend_token_into_include_expansion(
+        &self,
+        tok: InRealFile<SyntaxToken>,
+    ) -> InFile<SyntaxToken> {
+        let Some(include) =
+            self.s2d_cache.borrow_mut().get_or_insert_include_for(self.db, tok.file_id)
+        else {
+            return tok.into();
+        };
+        let span = self.db.real_span_map(tok.file_id).span_for_range(tok.value.text_range());
+        let Some(InMacroFile { file_id, value: mut mapped_tokens }) = self.with_ctx(|ctx| {
+            Some(
+                ctx.cache
+                    .get_or_insert_expansion(ctx.db, include)
+                    .map_range_down(span)?
+                    .map(SmallVec::<[_; 2]>::from_iter),
+            )
+        }) else {
+            return tok.into();
+        };
+        // We should only get one result at most
+        mapped_tokens.pop().map_or_else(|| tok.into(), |(tok, _)| InFile::new(file_id.into(), tok))
+    }
+
     /// Maps a node down by mapping its first and last token down.
     pub fn descend_node_into_attributes<N: AstNode>(&self, node: N) -> SmallVec<[N; 1]> {
         // This might not be the correct way to do this, but it works for now
@@ -846,49 +862,35 @@ impl<'db> SemanticsImpl<'db> {
         res
     }
 
-    // FIXME: This isn't quite right wrt to inner attributes
-    /// Does a syntactic traversal to check whether this token might be inside a macro call
-    pub fn might_be_inside_macro_call(&self, token: &SyntaxToken) -> bool {
-        token.parent_ancestors().any(|ancestor| {
+    pub fn is_inside_macro_call(&self, token: InFile<&SyntaxToken>) -> bool {
+        // FIXME: Maybe `ancestors_with_macros()` is more suitable here? Currently
+        // this is only used on real (not macro) files so this is not a problem.
+        token.value.parent_ancestors().any(|ancestor| {
             if ast::MacroCall::can_cast(ancestor.kind()) {
                 return true;
             }
-            // Check if it is an item (only items can have macro attributes) that has a non-builtin attribute.
-            let Some(item) = ast::Item::cast(ancestor) else { return false };
-            item.attrs().any(|attr| {
-                let Some(meta) = attr.meta() else { return false };
-                let Some(path) = meta.path() else { return false };
-                if let Some(attr_name) = path.as_single_name_ref() {
-                    let attr_name = attr_name.text();
-                    let attr_name = Symbol::intern(attr_name.as_str());
-                    if attr_name == sym::derive {
-                        return true;
-                    }
-                    // We ignore `#[test]` and friends in the def map, so we cannot expand them.
-                    // FIXME: We match by text. This is both hacky and incorrect (people can, and do, create
-                    // other macros named `test`). We cannot fix that unfortunately because we use this method
-                    // for speculative expansion in completion, which we cannot analyze. Fortunately, most macros
-                    // named `test` are test-like, meaning their expansion is not terribly important for IDE.
-                    if attr_name == sym::test
-                        || attr_name == sym::bench
-                        || attr_name == sym::test_case
-                        || find_builtin_attr_idx(&attr_name).is_some()
-                    {
-                        return false;
-                    }
-                }
-                let mut segments = path.segments();
-                let mut next_segment_text = || segments.next().and_then(|it| it.name_ref());
-                // `#[core::prelude::rust_2024::test]` or `#[std::prelude::rust_2024::test]`.
-                if next_segment_text().is_some_and(|it| matches!(&*it.text(), "core" | "std"))
-                    && next_segment_text().is_some_and(|it| it.text() == "prelude")
-                    && next_segment_text().is_some()
-                    && next_segment_text()
-                        .is_some_and(|it| matches!(&*it.text(), "test" | "bench" | "test_case"))
-                {
-                    return false;
+
+            let Some(item) = ast::Item::cast(ancestor) else {
+                return false;
+            };
+            // Optimization to skip the semantic check.
+            if item.attrs().all(|attr| {
+                attr.simple_name()
+                    .is_some_and(|attr| find_builtin_attr_idx(&Symbol::intern(&attr)).is_some())
+            }) {
+                return false;
+            }
+            self.with_ctx(|ctx| {
+                if ctx.item_to_macro_call(token.with_value(&item)).is_some() {
+                    return true;
                 }
-                true
+                let adt = match item {
+                    ast::Item::Struct(it) => it.into(),
+                    ast::Item::Enum(it) => it.into(),
+                    ast::Item::Union(it) => it.into(),
+                    _ => return false,
+                };
+                ctx.has_derives(token.with_value(&adt))
             })
         })
     }
@@ -1111,16 +1113,7 @@ impl<'db> SemanticsImpl<'db> {
                             let file_id = match m_cache.get(&mcall) {
                                 Some(&it) => it,
                                 None => {
-                                    let it = token
-                                        .parent()
-                                        .and_then(|parent| {
-                                            self.analyze_impl(
-                                                InFile::new(expansion, &parent),
-                                                None,
-                                                false,
-                                            )
-                                        })?
-                                        .expand(self.db, mcall.as_ref())?;
+                                    let it = ast::MacroCall::to_def(self, mcall.as_ref())?;
                                     m_cache.insert(mcall, it);
                                     it
                                 }
@@ -1560,14 +1553,9 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub fn resolve_macro_call2(&self, macro_call: InFile<&ast::MacroCall>) -> Option<Macro> {
-        self.with_ctx(|ctx| {
-            ctx.macro_call_to_macro_call(macro_call)
-                .and_then(|call| macro_call_to_macro_id(ctx, call))
-                .map(Into::into)
-        })
-        .or_else(|| {
-            self.analyze(macro_call.value.syntax())?.resolve_macro_call(self.db, macro_call)
-        })
+        self.to_def2(macro_call)
+            .and_then(|call| self.with_ctx(|ctx| macro_call_to_macro_id(ctx, call)))
+            .map(Into::into)
     }
 
     pub fn is_proc_macro_call(&self, macro_call: InFile<&ast::MacroCall>) -> bool {
@@ -1576,14 +1564,8 @@ impl<'db> SemanticsImpl<'db> {
     }
 
     pub fn resolve_macro_call_arm(&self, macro_call: &ast::MacroCall) -> Option<u32> {
-        let sa = self.analyze(macro_call.syntax())?;
-        self.db
-            .parse_macro_expansion(
-                sa.expand(self.db, self.wrap_node_infile(macro_call.clone()).as_ref())?,
-            )
-            .value
-            .1
-            .matched_arm
+        let file_id = self.to_def(macro_call)?;
+        self.db.parse_macro_expansion(file_id).value.1.matched_arm
     }
 
     pub fn get_unsafe_ops(&self, def: DefWithBody) -> FxHashSet<ExprOrPatSource> {
@@ -1688,6 +1670,10 @@ impl<'db> SemanticsImpl<'db> {
         T::to_def(self, src)
     }
 
+    pub fn to_def2<T: ToDef>(&self, src: InFile<&T>) -> Option<T::Def> {
+        T::to_def(self, src)
+    }
+
     fn file_to_module_defs(&self, file: FileId) -> impl Iterator<Item = Module> {
         self.with_ctx(|ctx| ctx.file_to_def(file).to_owned()).into_iter().map(Module::from)
     }
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
index 9393d08ad3f..6accf9b2e9c 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/child_by_source.rs
@@ -36,9 +36,14 @@ impl ChildBySource for TraitId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let data = db.trait_items(*self);
 
-        data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
+        data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
-                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db), call_id);
+                let ptr = ast_id.to_ptr(db);
+                if let Some(ptr) = ptr.cast::<ast::MacroCall>() {
+                    res[keys::MACRO_CALL].insert(ptr, call_id);
+                } else {
+                    res[keys::ATTR_MACRO_CALL].insert(ptr, call_id);
+                }
             },
         );
         data.items.iter().for_each(|&(_, item)| {
@@ -50,10 +55,14 @@ impl ChildBySource for TraitId {
 impl ChildBySource for ImplId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let data = db.impl_items(*self);
-        // FIXME: Macro calls
-        data.attribute_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
+        data.macro_calls().filter(|(ast_id, _)| ast_id.file_id == file_id).for_each(
             |(ast_id, call_id)| {
-                res[keys::ATTR_MACRO_CALL].insert(ast_id.to_ptr(db), call_id);
+                let ptr = ast_id.to_ptr(db);
+                if let Some(ptr) = ptr.cast::<ast::MacroCall>() {
+                    res[keys::MACRO_CALL].insert(ptr, call_id);
+                } else {
+                    res[keys::ATTR_MACRO_CALL].insert(ptr, call_id);
+                }
             },
         );
         data.items.iter().for_each(|&(_, item)| {
diff --git a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
index 172af456d92..7f6c9af4740 100644
--- a/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/semantics/source_to_def.rs
@@ -399,19 +399,6 @@ impl SourceToDefCtx<'_, '_> {
         Some((container, label?))
     }
 
-    pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> {
-        let map = self.dyn_map(src)?;
-        map[keys::ATTR_MACRO_CALL].get(&AstPtr::new(src.value)).copied()
-    }
-
-    pub(super) fn macro_call_to_macro_call(
-        &mut self,
-        src: InFile<&ast::MacroCall>,
-    ) -> Option<MacroCallId> {
-        let map = self.dyn_map(src)?;
-        map[keys::MACRO_CALL].get(&AstPtr::new(src.value)).copied()
-    }
-
     /// (AttrId, derive attribute call id, derive call ids)
     pub(super) fn attr_to_derive_macro_call(
         &mut self,
@@ -449,6 +436,17 @@ impl SourceToDefCtx<'_, '_> {
             .or_insert_with(|| container.child_by_source(db, file_id))
     }
 
+    pub(super) fn item_to_macro_call(&mut self, src: InFile<&ast::Item>) -> Option<MacroCallId> {
+        self.to_def(src, keys::ATTR_MACRO_CALL)
+    }
+
+    pub(super) fn macro_call_to_macro_call(
+        &mut self,
+        src: InFile<&ast::MacroCall>,
+    ) -> Option<MacroCallId> {
+        self.to_def(src, keys::MACRO_CALL)
+    }
+
     pub(super) fn type_param_to_def(
         &mut self,
         src: InFile<&ast::TypeParam>,
diff --git a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
index ea21546f9d7..d22812d3c69 100644
--- a/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
+++ b/src/tools/rust-analyzer/crates/hir/src/source_analyzer.rs
@@ -26,12 +26,12 @@ use hir_def::{
     },
     hir::{BindingId, Expr, ExprId, ExprOrPatId, Pat},
     lang_item::LangItem,
-    nameres::{MacroSubNs, crate_def_map},
+    nameres::MacroSubNs,
     resolver::{HasResolver, Resolver, TypeNs, ValueNs, resolver_for_scope},
     type_ref::{Mutability, TypeRefId},
 };
 use hir_expand::{
-    HirFileId, InFile, MacroCallId,
+    HirFileId, InFile,
     mod_path::{ModPath, PathKind, path},
     name::{AsName, Name},
 };
@@ -218,10 +218,6 @@ impl<'db> SourceAnalyzer<'db> {
         })
     }
 
-    pub(crate) fn expansion(&self, node: InFile<&ast::MacroCall>) -> Option<MacroCallId> {
-        self.store_sm()?.expansion(node)
-    }
-
     fn trait_environment(&self, db: &'db dyn HirDatabase) -> Arc<TraitEnvironment> {
         self.body_().map(|(def, ..)| def).map_or_else(
             || TraitEnvironment::empty(self.resolver.krate()),
@@ -745,22 +741,6 @@ impl<'db> SourceAnalyzer<'db> {
         ))
     }
 
-    pub(crate) fn resolve_macro_call(
-        &self,
-        db: &'db dyn HirDatabase,
-        macro_call: InFile<&ast::MacroCall>,
-    ) -> Option<Macro> {
-        let bs = self.store_sm()?;
-        bs.expansion(macro_call).and_then(|it| {
-            // FIXME: Block def maps
-            let def = it.lookup(db).def;
-            crate_def_map(db, def.krate)
-                .macro_def_to_macro_id
-                .get(&def.kind.erased_ast_id())
-                .map(|it| (*it).into())
-        })
-    }
-
     pub(crate) fn resolve_bind_pat_to_const(
         &self,
         db: &'db dyn HirDatabase,
@@ -1292,18 +1272,6 @@ impl<'db> SourceAnalyzer<'db> {
             .collect()
     }
 
-    pub(crate) fn expand(
-        &self,
-        db: &'db dyn HirDatabase,
-        macro_call: InFile<&ast::MacroCall>,
-    ) -> Option<MacroCallId> {
-        self.store_sm().and_then(|bs| bs.expansion(macro_call)).or_else(|| {
-            self.resolver.item_scope().macro_invoc(
-                macro_call.with_value(db.ast_id_map(macro_call.file_id).ast_id(macro_call.value)),
-            )
-        })
-    }
-
     pub(crate) fn resolve_variant(&self, record_lit: ast::RecordExpr) -> Option<VariantId> {
         let infer = self.infer()?;
         let expr_id = self.expr_id(record_lit.into())?;
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs
new file mode 100644
index 00000000000..efadde9e364
--- /dev/null
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/desugar_try_expr.rs
@@ -0,0 +1,281 @@
+use std::iter;
+
+use ide_db::{
+    assists::{AssistId, ExprFillDefaultMode},
+    ty_filter::TryEnum,
+};
+use syntax::{
+    AstNode, T,
+    ast::{
+        self,
+        edit::{AstNodeEdit, IndentLevel},
+        make,
+        syntax_factory::SyntaxFactory,
+    },
+};
+
+use crate::assist_context::{AssistContext, Assists};
+
+// Assist: desugar_try_expr_match
+//
+// Replaces a `try` expression with a `match` expression.
+//
+// ```
+// # //- minicore: try, option
+// fn handle() {
+//     let pat = Some(true)$0?;
+// }
+// ```
+// ->
+// ```
+// fn handle() {
+//     let pat = match Some(true) {
+//         Some(it) => it,
+//         None => return None,
+//     };
+// }
+// ```
+
+// Assist: desugar_try_expr_let_else
+//
+// Replaces a `try` expression with a `let else` statement.
+//
+// ```
+// # //- minicore: try, option
+// fn handle() {
+//     let pat = Some(true)$0?;
+// }
+// ```
+// ->
+// ```
+// fn handle() {
+//     let Some(pat) = Some(true) else {
+//         return None;
+//     };
+// }
+// ```
+pub(crate) fn desugar_try_expr(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    let question_tok = ctx.find_token_syntax_at_offset(T![?])?;
+    let try_expr = question_tok.parent().and_then(ast::TryExpr::cast)?;
+
+    let expr = try_expr.expr()?;
+    let expr_type_info = ctx.sema.type_of_expr(&expr)?;
+
+    let try_enum = TryEnum::from_ty(&ctx.sema, &expr_type_info.original)?;
+
+    let target = try_expr.syntax().text_range();
+    acc.add(
+        AssistId::refactor_rewrite("desugar_try_expr_match"),
+        "Replace try expression with match",
+        target,
+        |edit| {
+            let sad_pat = match try_enum {
+                TryEnum::Option => make::path_pat(make::ext::ident_path("None")),
+                TryEnum::Result => make::tuple_struct_pat(
+                    make::ext::ident_path("Err"),
+                    iter::once(make::path_pat(make::ext::ident_path("err"))),
+                )
+                .into(),
+            };
+            let sad_expr = match try_enum {
+                TryEnum::Option => {
+                    make::expr_return(Some(make::expr_path(make::ext::ident_path("None"))))
+                }
+                TryEnum::Result => make::expr_return(Some(
+                    make::expr_call(
+                        make::expr_path(make::ext::ident_path("Err")),
+                        make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))),
+                    )
+                    .into(),
+                )),
+            };
+
+            let happy_arm = make::match_arm(
+                try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
+                None,
+                make::expr_path(make::ext::ident_path("it")),
+            );
+            let sad_arm = make::match_arm(sad_pat, None, sad_expr);
+
+            let match_arm_list = make::match_arm_list([happy_arm, sad_arm]);
+
+            let expr_match = make::expr_match(expr.clone(), match_arm_list)
+                .indent(IndentLevel::from_node(try_expr.syntax()));
+
+            edit.replace_ast::<ast::Expr>(try_expr.clone().into(), expr_match.into());
+        },
+    );
+
+    if let Some(let_stmt) = try_expr.syntax().parent().and_then(ast::LetStmt::cast) {
+        if let_stmt.let_else().is_none() {
+            let pat = let_stmt.pat()?;
+            acc.add(
+                AssistId::refactor_rewrite("desugar_try_expr_let_else"),
+                "Replace try expression with let else",
+                target,
+                |builder| {
+                    let make = SyntaxFactory::with_mappings();
+                    let mut editor = builder.make_editor(let_stmt.syntax());
+
+                    let indent_level = IndentLevel::from_node(let_stmt.syntax());
+                    let new_let_stmt = make.let_else_stmt(
+                        try_enum.happy_pattern(pat),
+                        let_stmt.ty(),
+                        expr,
+                        make.block_expr(
+                            iter::once(
+                                make.expr_stmt(
+                                    make.expr_return(Some(match try_enum {
+                                        TryEnum::Option => make.expr_path(make.ident_path("None")),
+                                        TryEnum::Result => make
+                                            .expr_call(
+                                                make.expr_path(make.ident_path("Err")),
+                                                make.arg_list(iter::once(
+                                                    match ctx.config.expr_fill_default {
+                                                        ExprFillDefaultMode::Todo => make
+                                                            .expr_macro(
+                                                                make.ident_path("todo"),
+                                                                make.token_tree(
+                                                                    syntax::SyntaxKind::L_PAREN,
+                                                                    [],
+                                                                ),
+                                                            )
+                                                            .into(),
+                                                        ExprFillDefaultMode::Underscore => {
+                                                            make.expr_underscore().into()
+                                                        }
+                                                        ExprFillDefaultMode::Default => make
+                                                            .expr_macro(
+                                                                make.ident_path("todo"),
+                                                                make.token_tree(
+                                                                    syntax::SyntaxKind::L_PAREN,
+                                                                    [],
+                                                                ),
+                                                            )
+                                                            .into(),
+                                                    },
+                                                )),
+                                            )
+                                            .into(),
+                                    }))
+                                    .indent(indent_level + 1)
+                                    .into(),
+                                )
+                                .into(),
+                            ),
+                            None,
+                        )
+                        .indent(indent_level),
+                    );
+                    editor.replace(let_stmt.syntax(), new_let_stmt.syntax());
+                    editor.add_mappings(make.finish_with_mappings());
+                    builder.add_file_edits(ctx.vfs_file_id(), editor);
+                },
+            );
+        }
+    }
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use super::*;
+
+    use crate::tests::{check_assist, check_assist_by_label, check_assist_not_applicable};
+
+    #[test]
+    fn test_desugar_try_expr_not_applicable() {
+        check_assist_not_applicable(
+            desugar_try_expr,
+            r#"
+                fn test() {
+                    let pat: u32 = 25$0;
+                }
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_desugar_try_expr_option() {
+        check_assist(
+            desugar_try_expr,
+            r#"
+//- minicore: try, option
+fn test() {
+    let pat = Some(true)$0?;
+}
+            "#,
+            r#"
+fn test() {
+    let pat = match Some(true) {
+        Some(it) => it,
+        None => return None,
+    };
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_desugar_try_expr_result() {
+        check_assist(
+            desugar_try_expr,
+            r#"
+//- minicore: try, from, result
+fn test() {
+    let pat = Ok(true)$0?;
+}
+            "#,
+            r#"
+fn test() {
+    let pat = match Ok(true) {
+        Ok(it) => it,
+        Err(err) => return Err(err),
+    };
+}
+            "#,
+        );
+    }
+
+    #[test]
+    fn test_desugar_try_expr_option_let_else() {
+        check_assist_by_label(
+            desugar_try_expr,
+            r#"
+//- minicore: try, option
+fn test() {
+    let pat = Some(true)$0?;
+}
+            "#,
+            r#"
+fn test() {
+    let Some(pat) = Some(true) else {
+        return None;
+    };
+}
+            "#,
+            "Replace try expression with let else",
+        );
+    }
+
+    #[test]
+    fn test_desugar_try_expr_result_let_else() {
+        check_assist_by_label(
+            desugar_try_expr,
+            r#"
+//- minicore: try, from, result
+fn test() {
+    let pat = Ok(true)$0?;
+}
+            "#,
+            r#"
+fn test() {
+    let Ok(pat) = Ok(true) else {
+        return Err(todo!());
+    };
+}
+            "#,
+            "Replace try expression with let else",
+        );
+    }
+}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
index 2ac960ed7e1..bab2ccf3f33 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_mut_trait_impl.rs
@@ -1,7 +1,7 @@
 use ide_db::famous_defs::FamousDefs;
 use syntax::{
     AstNode,
-    ast::{self, make},
+    ast::{self, edit_in_place::Indent, make},
     ted,
 };
 
@@ -46,6 +46,7 @@ use crate::{AssistContext, AssistId, Assists};
 // ```
 pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
     let impl_def = ctx.find_node_at_offset::<ast::Impl>()?.clone_for_update();
+    let indent = impl_def.indent_level();
 
     let trait_ = impl_def.trait_()?;
     if let ast::Type::PathType(trait_path) = trait_ {
@@ -97,8 +98,8 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
     })?;
 
     let assoc_list = make::assoc_item_list().clone_for_update();
-    assoc_list.add_item(syntax::ast::AssocItem::Fn(fn_));
     ted::replace(impl_def.assoc_item_list()?.syntax(), assoc_list.syntax());
+    impl_def.get_or_create_assoc_item_list().add_item(syntax::ast::AssocItem::Fn(fn_));
 
     let target = impl_def.syntax().text_range();
     acc.add(
@@ -106,7 +107,7 @@ pub(crate) fn generate_mut_trait_impl(acc: &mut Assists, ctx: &AssistContext<'_>
         "Generate `IndexMut` impl from this `Index` trait",
         target,
         |edit| {
-            edit.insert(target.start(), format!("$0{impl_def}\n\n"));
+            edit.insert(target.start(), format!("$0{impl_def}\n\n{indent}"));
         },
     )
 }
@@ -190,6 +191,93 @@ impl<T> core::ops::Index<Axis> for [T; 3] where T: Copy {
     }
 
     #[test]
+    fn test_generate_mut_trait_impl_non_zero_indent() {
+        check_assist(
+            generate_mut_trait_impl,
+            r#"
+//- minicore: index
+mod foo {
+    pub enum Axis { X = 0, Y = 1, Z = 2 }
+
+    impl<T> core::ops::Index$0<Axis> for [T; 3] where T: Copy {
+        type Output = T;
+
+        fn index(&self, index: Axis) -> &Self::Output {
+            let var_name = &self[index as usize];
+            var_name
+        }
+    }
+}
+"#,
+            r#"
+mod foo {
+    pub enum Axis { X = 0, Y = 1, Z = 2 }
+
+    $0impl<T> core::ops::IndexMut<Axis> for [T; 3] where T: Copy {
+        fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
+            let var_name = &self[index as usize];
+            var_name
+        }
+    }
+
+    impl<T> core::ops::Index<Axis> for [T; 3] where T: Copy {
+        type Output = T;
+
+        fn index(&self, index: Axis) -> &Self::Output {
+            let var_name = &self[index as usize];
+            var_name
+        }
+    }
+}
+"#,
+        );
+
+        check_assist(
+            generate_mut_trait_impl,
+            r#"
+//- minicore: index
+mod foo {
+    mod bar {
+        pub enum Axis { X = 0, Y = 1, Z = 2 }
+
+        impl<T> core::ops::Index$0<Axis> for [T; 3] where T: Copy {
+            type Output = T;
+
+            fn index(&self, index: Axis) -> &Self::Output {
+                let var_name = &self[index as usize];
+                var_name
+            }
+        }
+    }
+}
+"#,
+            r#"
+mod foo {
+    mod bar {
+        pub enum Axis { X = 0, Y = 1, Z = 2 }
+
+        $0impl<T> core::ops::IndexMut<Axis> for [T; 3] where T: Copy {
+            fn index_mut(&mut self, index: Axis) -> &mut Self::Output {
+                let var_name = &self[index as usize];
+                var_name
+            }
+        }
+
+        impl<T> core::ops::Index<Axis> for [T; 3] where T: Copy {
+            type Output = T;
+
+            fn index(&self, index: Axis) -> &Self::Output {
+                let var_name = &self[index as usize];
+                var_name
+            }
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn test_generate_mut_trait_impl_not_applicable() {
         check_assist_not_applicable(
             generate_mut_trait_impl,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
index f963f48d62a..4837f92f934 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/generate_new.rs
@@ -129,17 +129,23 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option
 
         // Get the mutable version of the impl to modify
         let impl_def = if let Some(impl_def) = impl_def {
+            fn_.indent(impl_def.indent_level());
             builder.make_mut(impl_def)
         } else {
             // Generate a new impl to add the method to
             let impl_def = generate_impl(&ast::Adt::Struct(strukt.clone()));
+            let indent_level = strukt.indent_level();
+            fn_.indent(indent_level);
 
             // Insert it after the adt
             let strukt = builder.make_mut(strukt.clone());
 
             ted::insert_all_raw(
                 ted::Position::after(strukt.syntax()),
-                vec![make::tokens::blank_line().into(), impl_def.syntax().clone().into()],
+                vec![
+                    make::tokens::whitespace(&format!("\n\n{indent_level}")).into(),
+                    impl_def.syntax().clone().into(),
+                ],
             );
 
             impl_def
@@ -426,6 +432,135 @@ impl Foo {
     }
 
     #[test]
+    fn non_zero_indent() {
+        check_assist(
+            generate_new,
+            r#"
+mod foo {
+    struct $0Foo {}
+}
+"#,
+            r#"
+mod foo {
+    struct Foo {}
+
+    impl Foo {
+        fn $0new() -> Self {
+            Self {  }
+        }
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+mod foo {
+    mod bar {
+        struct $0Foo {}
+    }
+}
+"#,
+            r#"
+mod foo {
+    mod bar {
+        struct Foo {}
+
+        impl Foo {
+            fn $0new() -> Self {
+                Self {  }
+            }
+        }
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+mod foo {
+    struct $0Foo {}
+
+    impl Foo {
+        fn some() {}
+    }
+}
+"#,
+            r#"
+mod foo {
+    struct Foo {}
+
+    impl Foo {
+        fn $0new() -> Self {
+            Self {  }
+        }
+
+        fn some() {}
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+mod foo {
+    mod bar {
+        struct $0Foo {}
+
+        impl Foo {
+            fn some() {}
+        }
+    }
+}
+"#,
+            r#"
+mod foo {
+    mod bar {
+        struct Foo {}
+
+        impl Foo {
+            fn $0new() -> Self {
+                Self {  }
+            }
+
+            fn some() {}
+        }
+    }
+}
+"#,
+        );
+        check_assist(
+            generate_new,
+            r#"
+mod foo {
+    mod bar {
+struct $0Foo {}
+
+        impl Foo {
+            fn some() {}
+        }
+    }
+}
+"#,
+            r#"
+mod foo {
+    mod bar {
+struct Foo {}
+
+        impl Foo {
+            fn $0new() -> Self {
+                Self {  }
+            }
+
+            fn some() {}
+        }
+    }
+}
+"#,
+        );
+    }
+
+    #[test]
     fn check_visibility_of_new_fn_based_on_struct() {
         check_assist(
             generate_new,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs b/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
deleted file mode 100644
index c6e864fcfdb..00000000000
--- a/src/tools/rust-analyzer/crates/ide-assists/src/handlers/replace_try_expr_with_match.rs
+++ /dev/null
@@ -1,148 +0,0 @@
-use std::iter;
-
-use ide_db::{assists::AssistId, ty_filter::TryEnum};
-use syntax::{
-    AstNode, T,
-    ast::{
-        self,
-        edit::{AstNodeEdit, IndentLevel},
-        make,
-    },
-};
-
-use crate::assist_context::{AssistContext, Assists};
-
-// Assist: replace_try_expr_with_match
-//
-// Replaces a `try` expression with a `match` expression.
-//
-// ```
-// # //- minicore: try, option
-// fn handle() {
-//     let pat = Some(true)$0?;
-// }
-// ```
-// ->
-// ```
-// fn handle() {
-//     let pat = match Some(true) {
-//         Some(it) => it,
-//         None => return None,
-//     };
-// }
-// ```
-pub(crate) fn replace_try_expr_with_match(
-    acc: &mut Assists,
-    ctx: &AssistContext<'_>,
-) -> Option<()> {
-    let qm_kw = ctx.find_token_syntax_at_offset(T![?])?;
-    let qm_kw_parent = qm_kw.parent().and_then(ast::TryExpr::cast)?;
-
-    let expr = qm_kw_parent.expr()?;
-    let expr_type_info = ctx.sema.type_of_expr(&expr)?;
-
-    let try_enum = TryEnum::from_ty(&ctx.sema, &expr_type_info.original)?;
-
-    let target = qm_kw_parent.syntax().text_range();
-    acc.add(
-        AssistId::refactor_rewrite("replace_try_expr_with_match"),
-        "Replace try expression with match",
-        target,
-        |edit| {
-            let sad_pat = match try_enum {
-                TryEnum::Option => make::path_pat(make::ext::ident_path("None")),
-                TryEnum::Result => make::tuple_struct_pat(
-                    make::ext::ident_path("Err"),
-                    iter::once(make::path_pat(make::ext::ident_path("err"))),
-                )
-                .into(),
-            };
-            let sad_expr = match try_enum {
-                TryEnum::Option => {
-                    make::expr_return(Some(make::expr_path(make::ext::ident_path("None"))))
-                }
-                TryEnum::Result => make::expr_return(Some(
-                    make::expr_call(
-                        make::expr_path(make::ext::ident_path("Err")),
-                        make::arg_list(iter::once(make::expr_path(make::ext::ident_path("err")))),
-                    )
-                    .into(),
-                )),
-            };
-
-            let happy_arm = make::match_arm(
-                try_enum.happy_pattern(make::ident_pat(false, false, make::name("it")).into()),
-                None,
-                make::expr_path(make::ext::ident_path("it")),
-            );
-            let sad_arm = make::match_arm(sad_pat, None, sad_expr);
-
-            let match_arm_list = make::match_arm_list([happy_arm, sad_arm]);
-
-            let expr_match = make::expr_match(expr, match_arm_list)
-                .indent(IndentLevel::from_node(qm_kw_parent.syntax()));
-            edit.replace_ast::<ast::Expr>(qm_kw_parent.into(), expr_match.into());
-        },
-    )
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-
-    use crate::tests::{check_assist, check_assist_not_applicable};
-
-    #[test]
-    fn test_replace_try_expr_with_match_not_applicable() {
-        check_assist_not_applicable(
-            replace_try_expr_with_match,
-            r#"
-                fn test() {
-                    let pat: u32 = 25$0;
-                }
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_replace_try_expr_with_match_option() {
-        check_assist(
-            replace_try_expr_with_match,
-            r#"
-//- minicore: try, option
-fn test() {
-    let pat = Some(true)$0?;
-}
-            "#,
-            r#"
-fn test() {
-    let pat = match Some(true) {
-        Some(it) => it,
-        None => return None,
-    };
-}
-            "#,
-        );
-    }
-
-    #[test]
-    fn test_replace_try_expr_with_match_result() {
-        check_assist(
-            replace_try_expr_with_match,
-            r#"
-//- minicore: try, from, result
-fn test() {
-    let pat = Ok(true)$0?;
-}
-            "#,
-            r#"
-fn test() {
-    let pat = match Ok(true) {
-        Ok(it) => it,
-        Err(err) => return Err(err),
-    };
-}
-            "#,
-        );
-    }
-}
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
index 2395091b6f2..c2604432032 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/lib.rs
@@ -139,6 +139,7 @@ mod handlers {
     mod destructure_struct_binding;
     mod destructure_tuple_binding;
     mod desugar_doc_comment;
+    mod desugar_try_expr;
     mod expand_glob_import;
     mod expand_rest_pattern;
     mod extract_expressions_from_format_string;
@@ -214,7 +215,6 @@ mod handlers {
     mod replace_named_generic_with_impl;
     mod replace_qualified_name_with_use;
     mod replace_string_with_char;
-    mod replace_try_expr_with_match;
     mod replace_turbofish_with_explicit_type;
     mod sort_items;
     mod split_import;
@@ -273,6 +273,7 @@ mod handlers {
             destructure_struct_binding::destructure_struct_binding,
             destructure_tuple_binding::destructure_tuple_binding,
             desugar_doc_comment::desugar_doc_comment,
+            desugar_try_expr::desugar_try_expr,
             expand_glob_import::expand_glob_import,
             expand_glob_import::expand_glob_reexport,
             expand_rest_pattern::expand_rest_pattern,
@@ -354,7 +355,6 @@ mod handlers {
             replace_method_eager_lazy::replace_with_lazy_method,
             replace_named_generic_with_impl::replace_named_generic_with_impl,
             replace_qualified_name_with_use::replace_qualified_name_with_use,
-            replace_try_expr_with_match::replace_try_expr_with_match,
             replace_turbofish_with_explicit_type::replace_turbofish_with_explicit_type,
             sort_items::sort_items,
             split_import::split_import,
diff --git a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
index 76134acb36e..72f7195cbd7 100644
--- a/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
+++ b/src/tools/rust-analyzer/crates/ide-assists/src/tests/generated.rs
@@ -930,6 +930,47 @@ comment"]
 }
 
 #[test]
+fn doctest_desugar_try_expr_let_else() {
+    check_doc_test(
+        "desugar_try_expr_let_else",
+        r#####"
+//- minicore: try, option
+fn handle() {
+    let pat = Some(true)$0?;
+}
+"#####,
+        r#####"
+fn handle() {
+    let Some(pat) = Some(true) else {
+        return None;
+    };
+}
+"#####,
+    )
+}
+
+#[test]
+fn doctest_desugar_try_expr_match() {
+    check_doc_test(
+        "desugar_try_expr_match",
+        r#####"
+//- minicore: try, option
+fn handle() {
+    let pat = Some(true)$0?;
+}
+"#####,
+        r#####"
+fn handle() {
+    let pat = match Some(true) {
+        Some(it) => it,
+        None => return None,
+    };
+}
+"#####,
+    )
+}
+
+#[test]
 fn doctest_expand_glob_import() {
     check_doc_test(
         "expand_glob_import",
@@ -3097,27 +3138,6 @@ fn main() {
 }
 
 #[test]
-fn doctest_replace_try_expr_with_match() {
-    check_doc_test(
-        "replace_try_expr_with_match",
-        r#####"
-//- minicore: try, option
-fn handle() {
-    let pat = Some(true)$0?;
-}
-"#####,
-        r#####"
-fn handle() {
-    let pat = match Some(true) {
-        Some(it) => it,
-        None => return None,
-    };
-}
-"#####,
-    )
-}
-
-#[test]
 fn doctest_replace_turbofish_with_explicit_type() {
     check_doc_test(
         "replace_turbofish_with_explicit_type",
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
index 3baf1f3de61..5287627790a 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context.rs
@@ -8,8 +8,8 @@ use std::{iter, ops::ControlFlow};
 
 use base_db::RootQueryDb as _;
 use hir::{
-    DisplayTarget, HasAttrs, Local, ModuleDef, ModuleSource, Name, PathResolution, ScopeDef,
-    Semantics, SemanticsScope, Symbol, Type, TypeInfo,
+    DisplayTarget, HasAttrs, InFile, Local, ModuleDef, ModuleSource, Name, PathResolution,
+    ScopeDef, Semantics, SemanticsScope, Symbol, Type, TypeInfo,
 };
 use ide_db::{
     FilePosition, FxHashMap, FxHashSet, RootDatabase, famous_defs::FamousDefs,
@@ -751,7 +751,7 @@ impl<'a> CompletionContext<'a> {
             original_offset,
         } = expand_and_analyze(
             &sema,
-            original_file.syntax().clone(),
+            InFile::new(editioned_file_id.into(), original_file.syntax().clone()),
             file_with_fake_ident.syntax().clone(),
             offset,
             &original_token,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
index 284876ffc88..7a2230b3e36 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/context/analysis.rs
@@ -1,7 +1,7 @@
 //! Module responsible for analyzing the code surrounding the cursor for completion.
 use std::iter;
 
-use hir::{ExpandResult, Semantics, Type, TypeInfo, Variant};
+use hir::{ExpandResult, InFile, Semantics, Type, TypeInfo, Variant};
 use ide_db::{RootDatabase, active_parameter::ActiveParameter};
 use itertools::Either;
 use syntax::{
@@ -50,7 +50,7 @@ pub(super) struct AnalysisResult {
 
 pub(super) fn expand_and_analyze(
     sema: &Semantics<'_, RootDatabase>,
-    original_file: SyntaxNode,
+    original_file: InFile<SyntaxNode>,
     speculative_file: SyntaxNode,
     offset: TextSize,
     original_token: &SyntaxToken,
@@ -72,7 +72,7 @@ pub(super) fn expand_and_analyze(
         relative_offset,
     )
     .unwrap_or(ExpansionResult {
-        original_file,
+        original_file: original_file.value,
         speculative_file,
         original_offset: offset,
         speculative_offset: fake_ident_token.text_range().start(),
@@ -125,7 +125,7 @@ fn token_at_offset_ignore_whitespace(file: &SyntaxNode, offset: TextSize) -> Opt
 /// the best we can do.
 fn expand_maybe_stop(
     sema: &Semantics<'_, RootDatabase>,
-    original_file: SyntaxNode,
+    original_file: InFile<SyntaxNode>,
     speculative_file: SyntaxNode,
     original_offset: TextSize,
     fake_ident_token: SyntaxToken,
@@ -142,17 +142,16 @@ fn expand_maybe_stop(
         return result;
     }
 
-    // This needs to come after the recursive call, because our "inside macro" detection is subtly wrong
-    // with regard to attribute macros named `test` that are not std's test. So hopefully we will expand
-    // them successfully above and be able to analyze.
-    // Left biased since there may already be an identifier token there, and we appended to it.
-    if !sema.might_be_inside_macro_call(&fake_ident_token)
-        && token_at_offset_ignore_whitespace(&original_file, original_offset + relative_offset)
-            .is_some_and(|original_token| !sema.might_be_inside_macro_call(&original_token))
+    // We can't check whether the fake expansion is inside macro call, because that requires semantic info.
+    // But hopefully checking just the real one should be enough.
+    if token_at_offset_ignore_whitespace(&original_file.value, original_offset + relative_offset)
+        .is_some_and(|original_token| {
+            !sema.is_inside_macro_call(original_file.with_value(&original_token))
+        })
     {
         // Recursion base case.
         Some(ExpansionResult {
-            original_file,
+            original_file: original_file.value,
             speculative_file,
             original_offset,
             speculative_offset: fake_ident_token.text_range().start(),
@@ -166,7 +165,7 @@ fn expand_maybe_stop(
 
 fn expand(
     sema: &Semantics<'_, RootDatabase>,
-    original_file: SyntaxNode,
+    original_file: InFile<SyntaxNode>,
     speculative_file: SyntaxNode,
     original_offset: TextSize,
     fake_ident_token: SyntaxToken,
@@ -176,7 +175,7 @@ fn expand(
 
     let parent_item =
         |item: &ast::Item| item.syntax().ancestors().skip(1).find_map(ast::Item::cast);
-    let original_node = token_at_offset_ignore_whitespace(&original_file, original_offset)
+    let original_node = token_at_offset_ignore_whitespace(&original_file.value, original_offset)
         .and_then(|token| token.parent_ancestors().find_map(ast::Item::cast));
     let ancestor_items = iter::successors(
         Option::zip(
@@ -249,7 +248,7 @@ fn expand(
     }
 
     // No attributes have been expanded, so look for macro_call! token trees or derive token trees
-    let orig_tt = ancestors_at_offset(&original_file, original_offset)
+    let orig_tt = ancestors_at_offset(&original_file.value, original_offset)
         .map_while(Either::<ast::TokenTree, ast::Meta>::cast)
         .last()?;
     let spec_tt = ancestors_at_offset(&speculative_file, fake_ident_token.text_range().start())
@@ -292,7 +291,7 @@ fn expand(
                 fake_mapped_tokens.into_iter().min_by_key(|(_, rank)| *rank)
             {
                 return Some(ExpansionResult {
-                    original_file,
+                    original_file: original_file.value,
                     speculative_file,
                     original_offset,
                     speculative_offset: fake_ident_token.text_range().start(),
@@ -349,7 +348,7 @@ fn expand(
                                 }
                                 let result = expand_maybe_stop(
                                     sema,
-                                    actual_expansion.clone(),
+                                    InFile::new(file.into(), actual_expansion.clone()),
                                     fake_expansion.clone(),
                                     new_offset,
                                     fake_mapped_token,
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
index e5467767d42..b46e4c32061 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/expression.rs
@@ -2112,6 +2112,56 @@ fn foo() {
 }
 
 #[test]
+fn cfg_attr_attr_macro() {
+    check(
+        r#"
+//- proc_macros: identity
+#[cfg_attr(test, proc_macros::identity)]
+fn foo() {
+    $0
+}
+    "#,
+        expect![[r#"
+            fn foo()  fn()
+            md proc_macros
+            bt u32     u32
+            kw async
+            kw const
+            kw crate::
+            kw enum
+            kw extern
+            kw false
+            kw fn
+            kw for
+            kw if
+            kw if let
+            kw impl
+            kw impl for
+            kw let
+            kw letm
+            kw loop
+            kw match
+            kw mod
+            kw return
+            kw self::
+            kw static
+            kw struct
+            kw trait
+            kw true
+            kw type
+            kw union
+            kw unsafe
+            kw use
+            kw while
+            kw while let
+            sn macro_rules
+            sn pd
+            sn ppd
+        "#]],
+    );
+}
+
+#[test]
 fn escaped_label() {
     check(
         r#"
diff --git a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
index 55689034fb4..ed87b339fed 100644
--- a/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
+++ b/src/tools/rust-analyzer/crates/ide-completion/src/tests/item.rs
@@ -4,7 +4,7 @@
 //! in [crate::completions::mod_].
 use expect_test::expect;
 
-use crate::tests::{check_edit, check_with_base_items};
+use crate::tests::{check, check_edit, check_with_base_items};
 
 #[test]
 fn target_type_or_trait_in_impl_block() {
@@ -308,3 +308,39 @@ fn bar() {
         "#]],
     );
 }
+
+#[test]
+fn expression_in_item_macro() {
+    check(
+        r#"
+fn foo() -> u8 { 0 }
+
+macro_rules! foo {
+    ($expr:expr) => {
+        const BAR: u8 = $expr;
+    };
+}
+
+foo!(f$0);
+    "#,
+        expect![[r#"
+            ct BAR                   u8
+            fn foo()         fn() -> u8
+            ma foo!(…) macro_rules! foo
+            bt u32                  u32
+            kw const
+            kw crate::
+            kw false
+            kw for
+            kw if
+            kw if let
+            kw loop
+            kw match
+            kw self::
+            kw true
+            kw unsafe
+            kw while
+            kw while let
+        "#]],
+    );
+}
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
index 63cc7cde280..c94be7e164e 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/lib.rs
@@ -92,9 +92,7 @@ pub struct RootDatabase {
 impl std::panic::RefUnwindSafe for RootDatabase {}
 
 #[salsa_macros::db]
-impl salsa::Database for RootDatabase {
-    fn salsa_event(&self, _event: &dyn Fn() -> salsa::Event) {}
-}
+impl salsa::Database for RootDatabase {}
 
 impl Drop for RootDatabase {
     fn drop(&mut self) {
diff --git a/src/tools/rust-analyzer/crates/ide-db/src/search.rs b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
index 30be5bc21b4..d4ab7592927 100644
--- a/src/tools/rust-analyzer/crates/ide-db/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-db/src/search.rs
@@ -524,6 +524,7 @@ impl<'a> FindUsages<'a> {
     fn find_nodes<'b>(
         sema: &'b Semantics<'_, RootDatabase>,
         name: &str,
+        file_id: EditionedFileId,
         node: &syntax::SyntaxNode,
         offset: TextSize,
     ) -> impl Iterator<Item = SyntaxNode> + 'b {
@@ -534,7 +535,7 @@ impl<'a> FindUsages<'a> {
             })
             .into_iter()
             .flat_map(move |token| {
-                if sema.might_be_inside_macro_call(&token) {
+                if sema.is_inside_macro_call(InFile::new(file_id.into(), &token)) {
                     sema.descend_into_macros_exact(token)
                 } else {
                     <_>::from([token])
@@ -654,11 +655,14 @@ impl<'a> FindUsages<'a> {
                     let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone());
 
                     for offset in FindUsages::match_indices(&file_text, &finder, search_range) {
-                        let usages =
-                            FindUsages::find_nodes(sema, &current_to_process, &tree, offset)
-                                .filter(|it| {
-                                    matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF)
-                                });
+                        let usages = FindUsages::find_nodes(
+                            sema,
+                            &current_to_process,
+                            file_id,
+                            &tree,
+                            offset,
+                        )
+                        .filter(|it| matches!(it.kind(), SyntaxKind::NAME | SyntaxKind::NAME_REF));
                         for usage in usages {
                             if let Some(alias) = usage.parent().and_then(|it| {
                                 let path = ast::PathSegment::cast(it)?.parent_path();
@@ -813,7 +817,7 @@ impl<'a> FindUsages<'a> {
                 let tree = LazyCell::new(move || this.sema.parse(file_id).syntax().clone());
 
                 for offset in FindUsages::match_indices(&file_text, finder, search_range) {
-                    let usages = FindUsages::find_nodes(this.sema, name, &tree, offset)
+                    let usages = FindUsages::find_nodes(this.sema, name, file_id, &tree, offset)
                         .filter_map(ast::NameRef::cast);
                     for usage in usages {
                         let found_usage = usage
@@ -970,8 +974,8 @@ impl<'a> FindUsages<'a> {
                     return;
                 }
 
-                for name in
-                    Self::find_nodes(sema, name, &tree, offset).filter_map(ast::NameLike::cast)
+                for name in Self::find_nodes(sema, name, file_id, &tree, offset)
+                    .filter_map(ast::NameLike::cast)
                 {
                     if match name {
                         ast::NameLike::NameRef(name_ref) => self.found_name_ref(&name_ref, sink),
@@ -985,8 +989,8 @@ impl<'a> FindUsages<'a> {
             // Search for occurrences of the `Self` referring to our type
             if let Some((self_ty, finder)) = &include_self_kw_refs {
                 for offset in Self::match_indices(&text, finder, search_range) {
-                    for name_ref in
-                        Self::find_nodes(sema, "Self", &tree, offset).filter_map(ast::NameRef::cast)
+                    for name_ref in Self::find_nodes(sema, "Self", file_id, &tree, offset)
+                        .filter_map(ast::NameRef::cast)
                     {
                         if self.found_self_ty_name_ref(self_ty, &name_ref, sink) {
                             return;
@@ -1010,7 +1014,7 @@ impl<'a> FindUsages<'a> {
                 let tree = LazyCell::new(move || sema.parse(file_id).syntax().clone());
 
                 for offset in Self::match_indices(&text, finder, search_range) {
-                    for name_ref in Self::find_nodes(sema, "super", &tree, offset)
+                    for name_ref in Self::find_nodes(sema, "super", file_id, &tree, offset)
                         .filter_map(ast::NameRef::cast)
                     {
                         if self.found_name_ref(&name_ref, sink) {
@@ -1020,7 +1024,7 @@ impl<'a> FindUsages<'a> {
                 }
                 if let Some(finder) = &is_crate_root {
                     for offset in Self::match_indices(&text, finder, search_range) {
-                        for name_ref in Self::find_nodes(sema, "crate", &tree, offset)
+                        for name_ref in Self::find_nodes(sema, "crate", file_id, &tree, offset)
                             .filter_map(ast::NameRef::cast)
                         {
                             if self.found_name_ref(&name_ref, sink) {
@@ -1064,8 +1068,8 @@ impl<'a> FindUsages<'a> {
                 let finder = &Finder::new("self");
 
                 for offset in Self::match_indices(&text, finder, search_range) {
-                    for name_ref in
-                        Self::find_nodes(sema, "self", &tree, offset).filter_map(ast::NameRef::cast)
+                    for name_ref in Self::find_nodes(sema, "self", file_id, &tree, offset)
+                        .filter_map(ast::NameRef::cast)
                     {
                         if self.found_self_module_name_ref(&name_ref, sink) {
                             return;
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
index 364bead34ef..6bd5417b25d 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/missing_unsafe.rs
@@ -915,4 +915,47 @@ fn foo() {
             "#,
         );
     }
+
+    #[test]
+    fn regression_19823() {
+        check_diagnostics(
+            r#"
+pub trait FooTrait {
+    unsafe fn method1();
+    unsafe fn method2();
+}
+
+unsafe fn some_unsafe_fn() {}
+
+macro_rules! impl_foo {
+    () => {
+        unsafe fn method1() {
+            some_unsafe_fn();
+        }
+        unsafe fn method2() {
+            some_unsafe_fn();
+        }
+    };
+}
+
+pub struct S1;
+#[allow(unsafe_op_in_unsafe_fn)]
+impl FooTrait for S1 {
+    unsafe fn method1() {
+        some_unsafe_fn();
+    }
+
+    unsafe fn method2() {
+        some_unsafe_fn();
+    }
+}
+
+pub struct S2;
+#[allow(unsafe_op_in_unsafe_fn)]
+impl FooTrait for S2 {
+    impl_foo!();
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
index 35cefd23975..f20b6dea122 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/non_exhaustive_let.rs
@@ -106,4 +106,29 @@ fn test(x: Result<i32, &'static !>) {
 "#,
         );
     }
+
+    #[test]
+    fn empty_patterns_normalize() {
+        check_diagnostics(
+            r#"
+enum Infallible {}
+
+trait Foo {
+    type Assoc;
+}
+enum Enum<T: Foo> {
+    A,
+    B(T::Assoc),
+}
+
+impl Foo for () {
+    type Assoc = Infallible;
+}
+
+fn foo(v: Enum<()>) {
+    let Enum::A = v;
+}
+        "#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 5253734867e..076df1ab0f8 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -1243,4 +1243,18 @@ fn foo(v: &Enum) {
     "#,
         );
     }
+
+    #[test]
+    fn regression_19844() {
+        check_diagnostics(
+            r#"
+fn main() {
+    struct S {}
+    enum E { V() }
+    let E::V() = &S {};
+     // ^^^^^^ error: expected S, found E
+}
+"#,
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
index 2af14ca949b..72bd66d1c8b 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/lib.rs
@@ -83,12 +83,11 @@ mod handlers {
 #[cfg(test)]
 mod tests;
 
-use std::{collections::hash_map, iter, sync::LazyLock};
+use std::{iter, sync::LazyLock};
 
 use either::Either;
 use hir::{
-    Crate, DisplayTarget, HirFileId, InFile, Semantics, db::ExpandDatabase,
-    diagnostics::AnyDiagnostic,
+    Crate, DisplayTarget, InFile, Semantics, db::ExpandDatabase, diagnostics::AnyDiagnostic,
 };
 use ide_db::{
     EditionedFileId, FileId, FileRange, FxHashMap, FxHashSet, RootDatabase, Severity, SnippetCap,
@@ -513,13 +512,7 @@ pub fn semantic_diagnostics(
 
     // The edition isn't accurate (each diagnostics may have its own edition due to macros),
     // but it's okay as it's only being used for error recovery.
-    handle_lints(
-        &ctx.sema,
-        &mut FxHashMap::default(),
-        &mut lints,
-        &mut Vec::new(),
-        editioned_file_id.edition(db),
-    );
+    handle_lints(&ctx.sema, &mut lints, editioned_file_id.edition(db));
 
     res.retain(|d| d.severity != Severity::Allow);
 
@@ -584,8 +577,6 @@ fn handle_diag_from_macros(
     true
 }
 
-// `__RA_EVERY_LINT` is a fake lint group to allow every lint in proc macros
-
 struct BuiltLint {
     lint: &'static Lint,
     groups: Vec<&'static str>,
@@ -629,9 +620,7 @@ fn build_lints_map(
 
 fn handle_lints(
     sema: &Semantics<'_, RootDatabase>,
-    cache: &mut FxHashMap<HirFileId, FxHashMap<SmolStr, SeverityAttr>>,
     diagnostics: &mut [(InFile<SyntaxNode>, &mut Diagnostic)],
-    cache_stack: &mut Vec<HirFileId>,
     edition: Edition,
 ) {
     for (node, diag) in diagnostics {
@@ -645,7 +634,8 @@ fn handle_lints(
             diag.severity = default_severity;
         }
 
-        let mut diag_severity = fill_lint_attrs(sema, node, cache, cache_stack, diag, edition);
+        let mut diag_severity =
+            lint_severity_at(sema, node, &lint_groups(&diag.code, edition), edition);
 
         if let outline_diag_severity @ Some(_) =
             find_outline_mod_lint_severity(sema, node, diag, edition)
@@ -698,155 +688,22 @@ fn find_outline_mod_lint_severity(
     result
 }
 
-#[derive(Debug, Clone, Copy)]
-struct SeverityAttr {
-    severity: Severity,
-    /// This field counts how far we are from the main node. Bigger values mean more far.
-    ///
-    /// Note this isn't accurate: there can be gaps between values (created when merging severity maps).
-    /// The important thing is that if an attr is closer to the main node, it will have smaller value.
-    ///
-    /// This is necessary even though we take care to never overwrite a value from deeper nesting
-    /// because of lint groups. For example, in the following code:
-    /// ```
-    /// #[warn(non_snake_case)]
-    /// mod foo {
-    ///     #[allow(nonstandard_style)]
-    ///     mod bar {}
-    /// }
-    /// ```
-    /// We want to not warn on non snake case inside `bar`. If we are traversing this for the first
-    /// time, everything will be fine, because we will set `diag_severity` on the first matching group
-    /// and never overwrite it since then. But if `bar` is cached, the cache will contain both
-    /// `#[warn(non_snake_case)]` and `#[allow(nonstandard_style)]`, and without this field, we have
-    /// no way of differentiating between the two.
-    depth: u32,
-}
-
-fn fill_lint_attrs(
+fn lint_severity_at(
     sema: &Semantics<'_, RootDatabase>,
     node: &InFile<SyntaxNode>,
-    cache: &mut FxHashMap<HirFileId, FxHashMap<SmolStr, SeverityAttr>>,
-    cache_stack: &mut Vec<HirFileId>,
-    diag: &Diagnostic,
+    lint_groups: &LintGroups,
     edition: Edition,
 ) -> Option<Severity> {
-    let mut collected_lint_attrs = FxHashMap::<SmolStr, SeverityAttr>::default();
-    let mut diag_severity = None;
-
-    let mut ancestors = node.value.ancestors().peekable();
-    let mut depth = 0;
-    loop {
-        let ancestor = ancestors.next().expect("we always return from top-level nodes");
-        depth += 1;
-
-        if ancestors.peek().is_none() {
-            // We don't want to insert too many nodes into cache, but top level nodes (aka. outline modules
-            // or macro expansions) need to touch the database so they seem like a good fit to cache.
-
-            if let Some(cached) = cache.get_mut(&node.file_id) {
-                // This node (and everything above it) is already cached; the attribute is either here or nowhere.
-
-                // Workaround for the borrow checker.
-                let cached = std::mem::take(cached);
-
-                cached.iter().for_each(|(lint, severity)| {
-                    for item in &*cache_stack {
-                        let node_cache_entry = cache
-                            .get_mut(item)
-                            .expect("we always insert cached nodes into the cache map");
-                        let lint_cache_entry = node_cache_entry.entry(lint.clone());
-                        if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
-                            // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
-                            // overwrite top attrs.
-                            lint_cache_entry.insert(SeverityAttr {
-                                severity: severity.severity,
-                                depth: severity.depth + depth,
-                            });
-                        }
-                    }
-                });
-
-                let lints = lint_groups(&diag.code, edition);
-                let all_matching_groups =
-                    lints.iter().filter_map(|lint_group| cached.get(lint_group));
-                let cached_severity =
-                    all_matching_groups.min_by_key(|it| it.depth).map(|it| it.severity);
-
-                cache.insert(node.file_id, cached);
-
-                return diag_severity.or(cached_severity);
-            }
-
-            // Insert this node's descendants' attributes into any outline descendant, but not including this node.
-            // This must come before inserting this node's own attributes to preserve order.
-            collected_lint_attrs.drain().for_each(|(lint, severity)| {
-                if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
-                    diag_severity = Some(severity.severity);
-                }
-
-                for item in &*cache_stack {
-                    let node_cache_entry = cache
-                        .get_mut(item)
-                        .expect("we always insert cached nodes into the cache map");
-                    let lint_cache_entry = node_cache_entry.entry(lint.clone());
-                    if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
-                        // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
-                        // overwrite top attrs.
-                        lint_cache_entry.insert(severity);
-                    }
-                }
-            });
-
-            cache_stack.push(node.file_id);
-            cache.insert(node.file_id, FxHashMap::default());
-
-            if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
-                // Insert this node's attributes into any outline descendant, including this node.
-                lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
-                    if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
-                        diag_severity = Some(severity);
-                    }
-
-                    for item in &*cache_stack {
-                        let node_cache_entry = cache
-                            .get_mut(item)
-                            .expect("we always insert cached nodes into the cache map");
-                        let lint_cache_entry = node_cache_entry.entry(lint.clone());
-                        if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
-                            // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
-                            // overwrite top attrs.
-                            lint_cache_entry.insert(SeverityAttr { severity, depth });
-                        }
-                    }
-                });
-            }
-
-            let parent_node = sema.find_parent_file(node.file_id);
-            if let Some(parent_node) = parent_node {
-                let parent_severity =
-                    fill_lint_attrs(sema, &parent_node, cache, cache_stack, diag, edition);
-                if diag_severity.is_none() {
-                    diag_severity = parent_severity;
-                }
-            }
-            cache_stack.pop();
-            return diag_severity;
-        } else if let Some(ancestor) = ast::AnyHasAttrs::cast(ancestor) {
-            lint_attrs(sema, ancestor, edition).for_each(|(lint, severity)| {
-                if diag_severity.is_none() && lint_groups(&diag.code, edition).contains(&lint) {
-                    diag_severity = Some(severity);
-                }
-
-                let lint_cache_entry = collected_lint_attrs.entry(lint);
-                if let hash_map::Entry::Vacant(lint_cache_entry) = lint_cache_entry {
-                    // Do not overwrite existing lint attributes, as we go bottom to top and bottom attrs
-                    // overwrite top attrs.
-                    lint_cache_entry.insert(SeverityAttr { severity, depth });
-                }
-            });
-        }
-    }
+    node.value
+        .ancestors()
+        .filter_map(ast::AnyHasAttrs::cast)
+        .find_map(|ancestor| {
+            lint_attrs(sema, ancestor, edition)
+                .find_map(|(lint, severity)| lint_groups.contains(&lint).then_some(severity))
+        })
+        .or_else(|| {
+            lint_severity_at(sema, &sema.find_parent_file(node.file_id)?, lint_groups, edition)
+        })
 }
 
 fn lint_attrs<'a>(
@@ -945,10 +802,6 @@ impl LintGroups {
     fn contains(&self, group: &str) -> bool {
         self.groups.contains(&group) || (self.inside_warnings && group == "warnings")
     }
-
-    fn iter(&self) -> impl Iterator<Item = &'static str> {
-        self.groups.iter().copied().chain(self.inside_warnings.then_some("warnings"))
-    }
 }
 
 fn lint_groups(lint: &DiagnosticCode, edition: Edition) -> LintGroups {
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
index 339c199ec29..43c56ac8bec 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/lib.rs
@@ -287,7 +287,7 @@ impl<'db> MatchFinder<'db> {
                 if let Some(expanded) = self.sema.expand_macro_call(&macro_call) {
                     if let Some(tt) = macro_call.token_tree() {
                         self.output_debug_for_nodes_at_range(
-                            &expanded,
+                            &expanded.value,
                             range,
                             &Some(self.sema.original_range(tt.syntax())),
                             out,
diff --git a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
index d89911fca40..9afbedbb1ab 100644
--- a/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
+++ b/src/tools/rust-analyzer/crates/ide-ssr/src/search.rs
@@ -194,7 +194,7 @@ impl MatchFinder<'_> {
                     // nodes that originated entirely from within the token tree of the macro call.
                     // i.e. we don't want to match something that came from the macro itself.
                     if let Some(range) = self.sema.original_range_opt(tt.syntax()) {
-                        self.slow_scan_node(&expanded, rule, &Some(range), matches_out);
+                        self.slow_scan_node(&expanded.value, rule, &Some(range), matches_out);
                     }
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
index 241a702038d..7c396339c14 100644
--- a/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/expand_macro.rs
@@ -1,10 +1,10 @@
 use hir::db::ExpandDatabase;
-use hir::{ExpandResult, InFile, Semantics};
+use hir::{ExpandResult, InFile, InRealFile, Semantics};
 use ide_db::{
     FileId, RootDatabase, base_db::Crate, helpers::pick_best_token,
     syntax_helpers::prettify_macro_expansion,
 };
-use span::{Edition, SpanMap, SyntaxContext, TextRange, TextSize};
+use span::{SpanMap, SyntaxContext, TextRange, TextSize};
 use stdx::format_to;
 use syntax::{AstNode, NodeOrToken, SyntaxKind, SyntaxNode, T, ast, ted};
 
@@ -26,8 +26,9 @@ pub struct ExpandedMacro {
 // ![Expand Macro Recursively](https://user-images.githubusercontent.com/48062697/113020648-b3973180-917a-11eb-84a9-ecb921293dc5.gif)
 pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<ExpandedMacro> {
     let sema = Semantics::new(db);
-    let file = sema.parse_guess_edition(position.file_id);
-    let krate = sema.file_to_module_def(position.file_id)?.krate().into();
+    let file_id = sema.attach_first_edition(position.file_id)?;
+    let file = sema.parse(file_id);
+    let krate = sema.file_to_module_def(file_id.file_id(db))?.krate().into();
 
     let tok = pick_best_token(file.syntax().token_at_offset(position.offset), |kind| match kind {
         SyntaxKind::IDENT => 1,
@@ -86,7 +87,10 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
         return derive;
     }
 
-    let mut anc = tok.parent_ancestors();
+    let mut anc = sema
+        .descend_token_into_include_expansion(InRealFile::new(file_id, tok))
+        .value
+        .parent_ancestors();
     let mut span_map = SpanMap::empty();
     let mut error = String::new();
     let (name, expanded, kind) = loop {
@@ -95,14 +99,7 @@ pub(crate) fn expand_macro(db: &RootDatabase, position: FilePosition) -> Option<
         if let Some(item) = ast::Item::cast(node.clone()) {
             if let Some(def) = sema.resolve_attr_macro_call(&item) {
                 break (
-                    def.name(db)
-                        .display(
-                            db,
-                            sema.attach_first_edition(position.file_id)
-                                .map(|it| it.edition(db))
-                                .unwrap_or(Edition::CURRENT),
-                        )
-                        .to_string(),
+                    def.name(db).display(db, file_id.edition(db)).to_string(),
                     expand_macro_recur(&sema, &item, &mut error, &mut span_map, TextSize::new(0))?,
                     SyntaxKind::MACRO_ITEMS,
                 );
@@ -146,10 +143,11 @@ fn expand_macro_recur(
     offset_in_original_node: TextSize,
 ) -> Option<SyntaxNode> {
     let ExpandResult { value: expanded, err } = match macro_call {
-        item @ ast::Item::MacroCall(macro_call) => {
-            sema.expand_attr_macro(item).or_else(|| sema.expand_allowed_builtins(macro_call))?
-        }
-        item => sema.expand_attr_macro(item)?,
+        item @ ast::Item::MacroCall(macro_call) => sema
+            .expand_attr_macro(item)
+            .map(|it| it.map(|it| it.value))
+            .or_else(|| sema.expand_allowed_builtins(macro_call))?,
+        item => sema.expand_attr_macro(item)?.map(|it| it.value),
     };
     let expanded = expanded.clone_for_update();
     if let Some(err) = err {
@@ -718,4 +716,88 @@ __log!(written:%; "Test"$0);
             "#]],
         );
     }
+
+    #[test]
+    fn assoc_call() {
+        check(
+            r#"
+macro_rules! mac {
+    () => { fn assoc() {} }
+}
+impl () {
+    mac$0!();
+}
+    "#,
+            expect![[r#"
+                mac!
+                fn assoc(){}"#]],
+        );
+    }
+
+    #[test]
+    fn eager() {
+        check(
+            r#"
+//- minicore: concat
+macro_rules! my_concat {
+    ($head:expr, $($tail:tt)*) => { concat!($head, $($tail)*) };
+}
+
+
+fn test() {
+    _ = my_concat!(
+        conc$0at!("<", ">"),
+        "hi",
+    );
+}
+    "#,
+            expect![[r#"
+                my_concat!
+                "<>hi""#]],
+        );
+    }
+
+    #[test]
+    fn in_included() {
+        check(
+            r#"
+//- minicore: include
+//- /main.rs crate:main
+include!("./included.rs");
+//- /included.rs
+macro_rules! foo {
+    () => { fn item() {} };
+}
+foo$0!();
+"#,
+            expect![[r#"
+                foo!
+                fn item(){}"#]],
+        );
+    }
+
+    #[test]
+    fn include() {
+        check(
+            r#"
+//- minicore: include
+//- /main.rs crate:main
+include$0!("./included.rs");
+//- /included.rs
+macro_rules! foo {
+    () => { fn item() {} };
+}
+foo();
+"#,
+            expect![[r#"
+                include!
+                macro_rules! foo {
+                    () => {
+                        fn item(){}
+
+                    };
+                }
+                foo();"#]],
+        );
+    }
 }
diff --git a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
index fb8dbcfc735..520ba39a238 100644
--- a/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/highlight_related.rs
@@ -653,7 +653,7 @@ impl<'a> WalkExpandedExprCtx<'a> {
                             expr.macro_call().and_then(|call| self.sema.expand_macro_call(&call))
                         {
                             match_ast! {
-                                match expanded {
+                                match (expanded.value) {
                                     ast::MacroStmts(it) => {
                                         self.handle_expanded(it, cb);
                                     },
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover.rs b/src/tools/rust-analyzer/crates/ide/src/hover.rs
index 873e31b4a33..8bb1c708e25 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover.rs
@@ -58,6 +58,7 @@ pub struct MemoryLayoutHoverConfig {
     pub size: Option<MemoryLayoutHoverRenderKind>,
     pub offset: Option<MemoryLayoutHoverRenderKind>,
     pub alignment: Option<MemoryLayoutHoverRenderKind>,
+    pub padding: Option<MemoryLayoutHoverRenderKind>,
     pub niches: bool,
 }
 
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
index ad720c8a627..c24864a18bd 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/render.rs
@@ -630,27 +630,57 @@ pub(super) fn definition(
                 }
             },
             |_| None,
+            |_| None,
+        ),
+        Definition::Adt(it @ Adt::Struct(strukt)) => render_memory_layout(
+            config.memory_layout,
+            || it.layout(db),
+            |_| None,
+            |layout| {
+                let mut field_size =
+                    |i: usize| Some(strukt.fields(db).get(i)?.layout(db).ok()?.size());
+                if strukt.repr(db).is_some_and(|it| it.inhibit_struct_field_reordering()) {
+                    Some(("tail padding", layout.tail_padding(&mut field_size)?))
+                } else {
+                    Some(("largest padding", layout.largest_padding(&mut field_size)?))
+                }
+            },
+            |_| None,
+        ),
+        Definition::Adt(it) => render_memory_layout(
+            config.memory_layout,
+            || it.layout(db),
+            |_| None,
+            |_| None,
+            |_| None,
         ),
-        Definition::Adt(it) => {
-            render_memory_layout(config.memory_layout, || it.layout(db), |_| None, |_| None)
-        }
         Definition::Variant(it) => render_memory_layout(
             config.memory_layout,
             || it.layout(db),
             |_| None,
+            |_| None,
             |layout| layout.enum_tag_size(),
         ),
-        Definition::TypeAlias(it) => {
-            render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
-        }
-        Definition::Local(it) => {
-            render_memory_layout(config.memory_layout, || it.ty(db).layout(db), |_| None, |_| None)
-        }
+        Definition::TypeAlias(it) => render_memory_layout(
+            config.memory_layout,
+            || it.ty(db).layout(db),
+            |_| None,
+            |_| None,
+            |_| None,
+        ),
+        Definition::Local(it) => render_memory_layout(
+            config.memory_layout,
+            || it.ty(db).layout(db),
+            |_| None,
+            |_| None,
+            |_| None,
+        ),
         Definition::SelfType(it) => render_memory_layout(
             config.memory_layout,
             || it.self_ty(db).layout(db),
             |_| None,
             |_| None,
+            |_| None,
         ),
         _ => None,
     };
@@ -1055,9 +1085,13 @@ fn closure_ty(
     if let Some(trait_) = c.fn_trait(sema.db).get_id(sema.db, original.krate(sema.db).into()) {
         push_new_def(hir::Trait::from(trait_).into())
     }
-    if let Some(layout) =
-        render_memory_layout(config.memory_layout, || original.layout(sema.db), |_| None, |_| None)
-    {
+    if let Some(layout) = render_memory_layout(
+        config.memory_layout,
+        || original.layout(sema.db),
+        |_| None,
+        |_| None,
+        |_| None,
+    ) {
         format_to!(markup, "\n___\n{layout}");
     }
     format_to!(markup, "{adjusted}\n\n## Captures\n{}", captures_rendered,);
@@ -1142,6 +1176,7 @@ fn render_memory_layout(
     config: Option<MemoryLayoutHoverConfig>,
     layout: impl FnOnce() -> Result<Layout, LayoutError>,
     offset: impl FnOnce(&Layout) -> Option<u64>,
+    padding: impl FnOnce(&Layout) -> Option<(&str, u64)>,
     tag: impl FnOnce(&Layout) -> Option<usize>,
 ) -> Option<String> {
     let config = config?;
@@ -1199,6 +1234,23 @@ fn render_memory_layout(
         }
     }
 
+    if let Some(render) = config.padding {
+        if let Some((padding_name, padding)) = padding(&layout) {
+            format_to!(label, "{padding_name} = ");
+            match render {
+                MemoryLayoutHoverRenderKind::Decimal => format_to!(label, "{padding}"),
+                MemoryLayoutHoverRenderKind::Hexadecimal => format_to!(label, "{padding:#X}"),
+                MemoryLayoutHoverRenderKind::Both if padding >= 10 => {
+                    format_to!(label, "{padding} ({padding:#X})")
+                }
+                MemoryLayoutHoverRenderKind::Both => {
+                    format_to!(label, "{padding}")
+                }
+            }
+            format_to!(label, ", ");
+        }
+    }
+
     if config.niches {
         if let Some(niches) = layout.niches() {
             if niches > 1024 {
diff --git a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
index 06ca24c3ec3..a281a491525 100644
--- a/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
+++ b/src/tools/rust-analyzer/crates/ide/src/hover/tests.rs
@@ -12,6 +12,7 @@ const HOVER_BASE_CONFIG: HoverConfig = HoverConfig {
         size: Some(MemoryLayoutHoverRenderKind::Both),
         offset: Some(MemoryLayoutHoverRenderKind::Both),
         alignment: Some(MemoryLayoutHoverRenderKind::Both),
+        padding: Some(MemoryLayoutHoverRenderKind::Both),
         niches: true,
     }),
     documentation: true,
@@ -933,7 +934,7 @@ struct Foo$0(pub u32) where u32: Copy;
 
             ---
 
-            size = 4, align = 4, no Drop
+            size = 4, align = 4, largest padding = 0, no Drop
         "#]],
     );
 }
@@ -959,7 +960,7 @@ struct Foo$0 { field: u32 }
 
             ---
 
-            size = 4, align = 4, no Drop
+            size = 4, align = 4, largest padding = 0, no Drop
         "#]],
     );
     check(
@@ -984,7 +985,7 @@ struct Foo$0 where u32: Copy { field: u32 }
 
             ---
 
-            size = 4, align = 4, no Drop
+            size = 4, align = 4, largest padding = 0, no Drop
         "#]],
     );
 }
@@ -1013,7 +1014,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4, no Drop
+            size = 12 (0xC), align = 4, largest padding = 0, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1036,7 +1037,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 4, align = 4, no Drop
+            size = 4, align = 4, largest padding = 0, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1062,7 +1063,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 16 (0x10), align = 4, no Drop
+            size = 16 (0x10), align = 4, largest padding = 0, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1083,7 +1084,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4, no Drop
+            size = 12 (0xC), align = 4, largest padding = 0, no Drop
         "#]],
     );
     check_hover_fields_limit(
@@ -1104,7 +1105,7 @@ fn hover_record_struct_limit() {
 
             ---
 
-            size = 12 (0xC), align = 4, no Drop
+            size = 12 (0xC), align = 4, largest padding = 0, no Drop
         "#]],
     );
 
@@ -3114,7 +3115,7 @@ struct S$0<T>(core::marker::PhantomData<T>);
 
             ---
 
-            size = 0, align = 1, no Drop
+            size = 0, align = 1, largest padding = 0, no Drop
         "#]],
     );
 }
@@ -3148,6 +3149,111 @@ fn test_hover_layout_of_enum() {
 }
 
 #[test]
+fn test_hover_layout_padding_info() {
+    check(
+        r#"struct $0Foo {
+            x: bool,
+            y: i64,
+            z: u32,
+        }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Foo {
+                x: bool,
+                y: i64,
+                z: u32,
+            }
+            ```
+
+            ---
+
+            size = 16 (0x10), align = 8, largest padding = 3, niches = 254, no Drop
+        "#]],
+    );
+
+    check(
+        r#"#[repr(align(32))]
+        struct $0Foo {
+            x: bool,
+            y: i64,
+            z: u32,
+        }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Foo {
+                x: bool,
+                y: i64,
+                z: u32,
+            }
+            ```
+
+            ---
+
+            size = 32 (0x20), align = 32 (0x20), largest padding = 19 (0x13), niches = 254, no Drop
+        "#]],
+    );
+
+    check(
+        r#"#[repr(C)]
+        struct $0Foo {
+            x: bool,
+            y: i64,
+            z: u32,
+        }"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Foo {
+                x: bool,
+                y: i64,
+                z: u32,
+            }
+            ```
+
+            ---
+
+            size = 24 (0x18), align = 8, tail padding = 4, niches = 254, no Drop
+        "#]],
+    );
+
+    check(
+        r#"struct $0Foo(i16, u128, u64)"#,
+        expect![[r#"
+            *Foo*
+
+            ```rust
+            ra_test_fixture
+            ```
+
+            ```rust
+            struct Foo(i16, u128, u64)
+            ```
+
+            ---
+
+            size = 32 (0x20), align = 8, largest padding = 6, no Drop
+        "#]],
+    );
+}
+
+#[test]
 fn test_hover_no_memory_layout() {
     check_hover_no_memory_layout(
         r#"struct Foo { fiel$0d_a: u8, field_b: i32, field_c: i16 }"#,
@@ -9198,7 +9304,7 @@ struct Pedro$0<'a> {
 
             ---
 
-            size = 16 (0x10), align = 8, niches = 1, no Drop
+            size = 16 (0x10), align = 8, largest padding = 0, niches = 1, no Drop
         "#]],
     )
 }
@@ -10559,7 +10665,7 @@ struct DropField$0 {
 
             ---
 
-            size = 4, align = 4, needs Drop
+            size = 4, align = 4, largest padding = 0, needs Drop
         "#]],
     );
     check(
diff --git a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
index abde48d1512..fc922dd849f 100644
--- a/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
+++ b/src/tools/rust-analyzer/crates/intern/src/symbol/symbols.rs
@@ -164,7 +164,6 @@ define_symbols! {
     completion,
     compile_error,
     concat_bytes,
-    concat_idents,
     concat,
     const_format_args,
     const_panic_fmt,
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
index 64b40e7b943..e0c6e68f803 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/rust_analyzer_span.rs
@@ -258,7 +258,9 @@ impl server::TokenStream for RaSpanServer {
         &mut self,
         stream: Self::TokenStream,
     ) -> Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
-        stream.into_bridge()
+        stream.into_bridge(&mut |first, second| {
+            server::Span::join(self, first, second).unwrap_or(first)
+        })
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
index 24a67bf45c8..d55b269f868 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_id.rs
@@ -238,7 +238,8 @@ impl server::TokenStream for TokenIdServer {
         &mut self,
         stream: Self::TokenStream,
     ) -> Vec<bridge::TokenTree<Self::TokenStream, Self::Span, Self::Symbol>> {
-        stream.into_bridge()
+        // Can't join with `TokenId`.
+        stream.into_bridge(&mut |first, _second| first)
     }
 }
 
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
index 072557913c2..c5019a59172 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/server_impl/token_stream.rs
@@ -56,7 +56,10 @@ impl<S: Copy> TokenStream<S> {
         self.token_trees.is_empty()
     }
 
-    pub(crate) fn into_bridge(self) -> Vec<bridge::TokenTree<Self, S, intern::Symbol>> {
+    pub(crate) fn into_bridge(
+        self,
+        join_spans: &mut dyn FnMut(S, S) -> S,
+    ) -> Vec<bridge::TokenTree<Self, S, intern::Symbol>> {
         let mut result = Vec::new();
         let mut iter = self.token_trees.into_iter();
         while let Some(tree) = iter.next() {
@@ -98,7 +101,11 @@ impl<S: Copy> TokenStream<S> {
                                 token_trees: iter.by_ref().take(subtree.usize_len()).collect(),
                             })
                         },
-                        span: bridge::DelimSpan::from_single(subtree.delimiter.open),
+                        span: bridge::DelimSpan {
+                            open: subtree.delimiter.open,
+                            close: subtree.delimiter.close,
+                            entire: join_spans(subtree.delimiter.open, subtree.delimiter.close),
+                        },
                     }))
                 }
             }
diff --git a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
index 3868fee40fb..3a6ce639d13 100644
--- a/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
+++ b/src/tools/rust-analyzer/crates/proc-macro-srv/src/tests/mod.rs
@@ -144,7 +144,7 @@ fn test_fn_like_macro_clone_ident_subtree() {
             SUBTREE $$ 42:2@0..100#ROOT2024 42:2@0..100#ROOT2024
               IDENT   ident 42:2@0..5#ROOT2024
               PUNCH   , [alone] 42:2@5..6#ROOT2024
-              SUBTREE [] 42:2@7..8#ROOT2024 42:2@7..8#ROOT2024"#]],
+              SUBTREE [] 42:2@7..9#ROOT2024 42:2@7..9#ROOT2024"#]],
     );
 }
 
diff --git a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs
index bade0c2cd6f..71af63a0d3b 100644
--- a/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs
+++ b/src/tools/rust-analyzer/crates/query-group-macro/tests/logger_db.rs
@@ -1,33 +1,41 @@
 use std::sync::{Arc, Mutex};
 
 #[salsa_macros::db]
-#[derive(Default, Clone)]
+#[derive(Clone)]
 pub(crate) struct LoggerDb {
     storage: salsa::Storage<Self>,
     logger: Logger,
 }
 
+impl Default for LoggerDb {
+    fn default() -> Self {
+        let logger = Logger::default();
+        Self {
+            storage: salsa::Storage::new(Some(Box::new({
+                let logger = logger.clone();
+                move |event| match event.kind {
+                    salsa::EventKind::WillExecute { .. }
+                    | salsa::EventKind::WillCheckCancellation
+                    | salsa::EventKind::DidValidateMemoizedValue { .. }
+                    | salsa::EventKind::WillDiscardStaleOutput { .. }
+                    | salsa::EventKind::DidDiscard { .. } => {
+                        logger.logs.lock().unwrap().push(format!("salsa_event({:?})", event.kind));
+                    }
+                    _ => {}
+                }
+            }))),
+            logger,
+        }
+    }
+}
+
 #[derive(Default, Clone)]
 struct Logger {
     logs: Arc<Mutex<Vec<String>>>,
 }
 
 #[salsa_macros::db]
-impl salsa::Database for LoggerDb {
-    fn salsa_event(&self, event: &dyn Fn() -> salsa::Event) {
-        let event = event();
-        match event.kind {
-            salsa::EventKind::WillExecute { .. }
-            | salsa::EventKind::WillCheckCancellation
-            | salsa::EventKind::DidValidateMemoizedValue { .. }
-            | salsa::EventKind::WillDiscardStaleOutput { .. }
-            | salsa::EventKind::DidDiscard { .. } => {
-                self.push_log(format!("salsa_event({:?})", event.kind));
-            }
-            _ => {}
-        }
-    }
-}
+impl salsa::Database for LoggerDb {}
 
 impl LoggerDb {
     /// Log an event from inside a tracked function.
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
index 671e838421f..12b393b80c0 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -1023,7 +1023,7 @@ impl flags::AnalysisStats {
             percentage(num_pats_partially_unknown, num_pats),
             num_pat_type_mismatches
         );
-        eprintln!("  panics: {}", panics);
+        eprintln!("  panics: {panics}");
         eprintln!("{:<20} {}", "Inference:", inference_time);
         report_metric("unknown type", num_exprs_unknown, "#");
         report_metric("type mismatches", num_expr_type_mismatches, "#");
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
index 03e5b1f6f4b..d1ca8c1a91a 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/config.rs
@@ -149,6 +149,8 @@ config_data! {
         hover_memoryLayout_niches: Option<bool> = Some(false),
         /// How to render the offset information in a memory layout hover.
         hover_memoryLayout_offset: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Hexadecimal),
+        /// How to render the padding information in a memory layout hover.
+        hover_memoryLayout_padding: Option<MemoryLayoutHoverRenderKindDef> = None,
         /// How to render the size information in a memory layout hover.
         hover_memoryLayout_size: Option<MemoryLayoutHoverRenderKindDef> = Some(MemoryLayoutHoverRenderKindDef::Both),
 
@@ -544,7 +546,7 @@ config_data! {
          /// Whether to prefer import paths containing a `prelude` module.
         imports_preferPrelude: bool                       = false,
         /// The path structure for newly inserted paths to use.
-        imports_prefix: ImportPrefixDef               = ImportPrefixDef::Plain,
+        imports_prefix: ImportPrefixDef               = ImportPrefixDef::ByCrate,
         /// Whether to prefix external (including std, core) crate imports with `::`. e.g. "use ::std::io::Read;".
         imports_prefixExternPrelude: bool = false,
     }
@@ -1635,6 +1637,7 @@ impl Config {
                 size: self.hover_memoryLayout_size().map(mem_kind),
                 offset: self.hover_memoryLayout_offset().map(mem_kind),
                 alignment: self.hover_memoryLayout_alignment().map(mem_kind),
+                padding: self.hover_memoryLayout_padding().map(mem_kind),
                 niches: self.hover_memoryLayout_niches().unwrap_or_default(),
             }),
             documentation: self.hover_documentation_enable().to_owned(),
diff --git a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
index 49ebffa909a..84b7888258f 100644
--- a/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
+++ b/src/tools/rust-analyzer/crates/rust-analyzer/src/integrated_benchmarks.rs
@@ -147,7 +147,7 @@ fn integrated_completion_benchmark() {
         let _it = stdx::timeit("change");
         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
         let completion_offset =
-            patch(&mut text, "db.struct_data(self.id)", "sel;\ndb.struct_data(self.id)")
+            patch(&mut text, "db.struct_signature(self.id)", "sel;\ndb.struct_signature(self.id)")
                 + "sel".len();
         let mut change = ChangeWithProcMacros::default();
         change.change_file(file_id, Some(text));
@@ -197,9 +197,11 @@ fn integrated_completion_benchmark() {
     let completion_offset = {
         let _it = stdx::timeit("change");
         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
-        let completion_offset =
-            patch(&mut text, "sel;\ndb.struct_data(self.id)", ";sel;\ndb.struct_data(self.id)")
-                + ";sel".len();
+        let completion_offset = patch(
+            &mut text,
+            "sel;\ndb.struct_signature(self.id)",
+            ";sel;\ndb.struct_signature(self.id)",
+        ) + ";sel".len();
         let mut change = ChangeWithProcMacros::default();
         change.change_file(file_id, Some(text));
         host.apply_change(change);
@@ -247,9 +249,11 @@ fn integrated_completion_benchmark() {
     let completion_offset = {
         let _it = stdx::timeit("change");
         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
-        let completion_offset =
-            patch(&mut text, "sel;\ndb.struct_data(self.id)", "self.;\ndb.struct_data(self.id)")
-                + "self.".len();
+        let completion_offset = patch(
+            &mut text,
+            "sel;\ndb.struct_signature(self.id)",
+            "self.;\ndb.struct_signature(self.id)",
+        ) + "self.".len();
         let mut change = ChangeWithProcMacros::default();
         change.change_file(file_id, Some(text));
         host.apply_change(change);
@@ -366,7 +370,7 @@ fn integrated_diagnostics_benchmark() {
     {
         let _it = stdx::timeit("change");
         let mut text = host.analysis().file_text(file_id).unwrap().to_string();
-        patch(&mut text, "db.struct_data(self.id)", "();\ndb.struct_data(self.id)");
+        patch(&mut text, "db.struct_signature(self.id)", "();\ndb.struct_signature(self.id)");
         let mut change = ChangeWithProcMacros::default();
         change.change_file(file_id, Some(text));
         host.apply_change(change);
diff --git a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
index 8dee3964d44..429e51ba362 100644
--- a/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
+++ b/src/tools/rust-analyzer/crates/syntax/src/ast/syntax_factory/constructors.rs
@@ -585,6 +585,18 @@ impl SyntaxFactory {
         ast
     }
 
+    pub fn expr_underscore(&self) -> ast::UnderscoreExpr {
+        let ast::Expr::UnderscoreExpr(ast) = make::ext::expr_underscore().clone_for_update() else {
+            unreachable!()
+        };
+
+        if let Some(mut mapping) = self.mappings() {
+            SyntaxMappingBuilder::new(ast.syntax().clone()).finish(&mut mapping);
+        }
+
+        ast
+    }
+
     pub fn expr_if(
         &self,
         condition: ast::Expr,
diff --git a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
index 2ae73df61d0..0e07dadfb7c 100644
--- a/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
+++ b/src/tools/rust-analyzer/docs/book/src/configuration_generated.md
@@ -763,6 +763,13 @@ Default: `"hexadecimal"`
 How to render the offset information in a memory layout hover.
 
 
+## rust-analyzer.hover.memoryLayout.padding {#hover.memoryLayout.padding}
+
+Default: `null`
+
+How to render the padding information in a memory layout hover.
+
+
 ## rust-analyzer.hover.memoryLayout.size {#hover.memoryLayout.size}
 
 Default: `"both"`
@@ -835,7 +842,7 @@ Whether to prefer import paths containing a `prelude` module.
 
 ## rust-analyzer.imports.prefix {#imports.prefix}
 
-Default: `"plain"`
+Default: `"crate"`
 
 The path structure for newly inserted paths to use.
 
diff --git a/src/tools/rust-analyzer/docs/book/src/other_editors.md b/src/tools/rust-analyzer/docs/book/src/other_editors.md
index 1eac7dd2c25..896df52af5f 100644
--- a/src/tools/rust-analyzer/docs/book/src/other_editors.md
+++ b/src/tools/rust-analyzer/docs/book/src/other_editors.md
@@ -364,30 +364,6 @@ binary](./rust_analyzer_binary.html).
 There are multiple rust-analyzer extensions for Visual Studio 2022 on
 Windows:
 
-### rust-analyzer.vs
-
-(License: Creative Commons Attribution-NonCommercial-ShareAlike 4.0
-International)
-
-[Visual Studio
-Marketplace](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer)
-
-[GitHub](https://github.com/kitamstudios/rust-analyzer/)
-
-Support for Rust development in the Visual Studio IDE is enabled by the
-[rust-analyzer](https://marketplace.visualstudio.com/items?itemName=kitamstudios.RustAnalyzer)
-package. Either click on the download link or install from IDE’s
-extension manager. For now [Visual Studio
-2022](https://visualstudio.microsoft.com/downloads/) is required. All
-editions are supported viz. Community, Professional & Enterprise. The
-package aims to provide 0-friction installation and therefore comes
-loaded with most things required including rust-analyzer binary. If
-anything it needs is missing, appropriate errors / warnings will guide
-the user. E.g. cargo.exe needs to be in path and the package will tell
-you as much. This package is under rapid active development. So if you
-encounter any issues please file it at
-[rust-analyzer.vs](https://github.com/kitamstudios/rust-analyzer/).
-
 ### VS RustAnalyzer
 
 (License: GPL)
diff --git a/src/tools/rust-analyzer/editors/code/package.json b/src/tools/rust-analyzer/editors/code/package.json
index a282eea9997..c8c36cd85c8 100644
--- a/src/tools/rust-analyzer/editors/code/package.json
+++ b/src/tools/rust-analyzer/editors/code/package.json
@@ -1782,6 +1782,33 @@
             {
                 "title": "hover",
                 "properties": {
+                    "rust-analyzer.hover.memoryLayout.padding": {
+                        "markdownDescription": "How to render the padding information in a memory layout hover.",
+                        "default": null,
+                        "anyOf": [
+                            {
+                                "type": "null"
+                            },
+                            {
+                                "type": "string",
+                                "enum": [
+                                    "both",
+                                    "decimal",
+                                    "hexadecimal"
+                                ],
+                                "enumDescriptions": [
+                                    "Render as 12 (0xC)",
+                                    "Render as 12",
+                                    "Render as 0xC"
+                                ]
+                            }
+                        ]
+                    }
+                }
+            },
+            {
+                "title": "hover",
+                "properties": {
                     "rust-analyzer.hover.memoryLayout.size": {
                         "markdownDescription": "How to render the size information in a memory layout hover.",
                         "default": "both",
@@ -1927,7 +1954,7 @@
                 "properties": {
                     "rust-analyzer.imports.prefix": {
                         "markdownDescription": "The path structure for newly inserted paths to use.",
-                        "default": "plain",
+                        "default": "crate",
                         "type": "string",
                         "enum": [
                             "plain",