Repository: rust-analyzer/rust-analyzer
Pull request #11774 (2022-03-20 18:08:44)

feat: Tag macro calls as unsafe if they expand to unsafe expressions
as long as they aren't inside an unsafe block inside the macro that is.


Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 5351da334a..fab0edfe30 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -37,9 +37,9 @@ dependencies = [
 
 [[package]]
 name = "anyhow"
-version = "1.0.56"
+version = "1.0.53"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4361135be9122e0870de935d7c439aef945b9f9ddd4199a553b5270b49c82a27"
+checksum = "94a45b455c14666b85fc40a019e8ab9eb75e3a124e05494f5397122bc9eb06e0"
 
 [[package]]
 name = "anymap"
@@ -132,9 +132,9 @@ dependencies = [
 
 [[package]]
 name = "cargo_metadata"
-version = "0.14.2"
+version = "0.14.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4acbb09d9ee8e23699b9634375c72795d095bf268439da88562cf9b501f181fa"
+checksum = "ba2ae6de944143141f6155a473a6b02f66c7c3f9f47316f802f80204ebfe6e12"
 dependencies = [
  "camino",
  "cargo-platform",
@@ -145,9 +145,9 @@ dependencies = [
 
 [[package]]
 name = "cc"
-version = "1.0.73"
+version = "1.0.72"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2fff2a6927b3bb87f9595d67196a70493f627687a71d87a0d692242c33f58c11"
+checksum = "22a9137b95ea06864e018375b72adfb7db6e6f68cfc8df5a04d00288050485ee"
 
 [[package]]
 name = "cfg"
@@ -223,11 +223,11 @@ dependencies = [
 
 [[package]]
 name = "countme"
-version = "3.0.1"
+version = "3.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7704b5fdd17b18ae31c4c1da5a2e0305a2bf17b5249300a9ee9ed7b72114c636"
+checksum = "03746e0c6dd9b5d2d9132ffe0bede35fb5f815604fd371bb42599fd37bc8e483"
 dependencies = [
- "dashmap",
+ "dashmap 4.0.2",
  "once_cell",
  "rustc-hash",
 ]
@@ -249,9 +249,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-channel"
-version = "0.5.3"
+version = "0.5.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "fdbfe11fe19ff083c48923cf179540e8cd0535903dc35e178a1fdeeb59aef51f"
+checksum = "e54ea8bc3fb1ee042f5aace6e3c6e025d3874866da222930f70ce62aceba0bfa"
 dependencies = [
  "cfg-if",
  "crossbeam-utils",
@@ -270,11 +270,10 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-epoch"
-version = "0.9.8"
+version = "0.9.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1145cf131a2c6ba0615079ab6a638f7e1973ac9c2634fcbeaaad6114246efe8c"
+checksum = "c00d6d2ea26e8b151d99093005cb442fb9a37aeaca582a03ec70946f49ab5ed9"
 dependencies = [
- "autocfg",
  "cfg-if",
  "crossbeam-utils",
  "lazy_static",
@@ -284,9 +283,9 @@ dependencies = [
 
 [[package]]
 name = "crossbeam-utils"
-version = "0.8.8"
+version = "0.8.7"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0bf124c720b7686e3c2663cf54062ab0f68a88af2fb6a030e87e30bf721fcb38"
+checksum = "b5e5bed1f1c269533fa816a0a5492b3545209a205ca1a54842be180eb63a16a6"
 dependencies = [
  "cfg-if",
  "lazy_static",
@@ -294,9 +293,19 @@ dependencies = [
 
 [[package]]
 name = "dashmap"
-version = "5.2.0"
+version = "4.0.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4c8858831f7781322e539ea39e72449c46b059638250c14344fec8d0aa6e539c"
+checksum = "e77a43b28d0668df09411cb0bc9a8c2adc40f9a048afe863e05fd43251e8e39c"
+dependencies = [
+ "cfg-if",
+ "num_cpus",
+]
+
+[[package]]
+name = "dashmap"
+version = "5.1.0"
+source = "registry+https://github.com/rust-lang/crates.io-index"
+checksum = "c0834a35a3fce649144119e18da2a4d8ed12ef3862f47183fd46f625d072d96c"
 dependencies = [
  "cfg-if",
  "num_cpus",
@@ -499,7 +508,7 @@ dependencies = [
  "base_db",
  "cfg",
  "cov-mark",
- "dashmap",
+ "dashmap 5.1.0",
  "drop_bomb",
  "either",
  "expect-test",
@@ -821,9 +830,9 @@ checksum = "e2abad23fbc42b3700f2f279844dc832adb2b2eb069b2df918f455c4e18cc646"
 
 [[package]]
 name = "libc"
-version = "0.2.120"
+version = "0.2.117"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ad5c14e80759d0939d013e6ca49930e59fc53dd8e5009132f76240c179380c09"
+checksum = "e74d72e0f9b65b5b4ca49a346af3976df0f9c61d550727f349ecd559f251a26c"
 
 [[package]]
 name = "libloading"
@@ -837,9 +846,9 @@ dependencies = [
 
 [[package]]
 name = "libmimalloc-sys"
-version = "0.1.24"
+version = "0.1.23"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7705fc40f6ed493f73584abbb324e74f96b358ff60dfe5659a0f8fc12c590a69"
+checksum = "9636c194f9db483f4d0adf2f99a65011a99f904bd222bbd67fb4df4f37863c30"
 dependencies = [
  "cc",
 ]
@@ -947,9 +956,9 @@ dependencies = [
 
 [[package]]
 name = "mimalloc"
-version = "0.1.28"
+version = "0.1.27"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "b0dfa131390c2f6bdb3242f65ff271fcdaca5ff7b6c08f28398be7f2280e3926"
+checksum = "cf5f78c1d9892fb5677a8b2f543f967ab891ac0f71feecd961435b74f877283a"
 dependencies = [
  "libmimalloc-sys",
 ]
@@ -966,15 +975,14 @@ dependencies = [
 
 [[package]]
 name = "mio"
-version = "0.8.1"
+version = "0.7.14"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "7ba42135c6a5917b9db9cd7b293e5409e1c6b041e6f9825e92e55a894c63b6f8"
+checksum = "8067b404fe97c70829f082dec8bcf4f71225d7eaea1d8645349cb76fa06205cc"
 dependencies = [
  "libc",
  "log",
  "miow 0.3.7",
  "ntapi",
- "wasi",
  "winapi",
 ]
 
@@ -998,9 +1006,9 @@ dependencies = [
 
 [[package]]
 name = "notify"
-version = "5.0.0-pre.14"
+version = "5.0.0-pre.13"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "d13c22db70a63592e098fb51735bab36646821e6389a0ba171f3549facdf0b74"
+checksum = "245d358380e2352c2d020e8ee62baac09b3420f1f6c012a31326cfced4ad487d"
 dependencies = [
  "bitflags",
  "crossbeam-channel",
@@ -1053,9 +1061,9 @@ dependencies = [
 
 [[package]]
 name = "once_cell"
-version = "1.10.0"
+version = "1.9.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "87f3e037eac156d1775da914196f0f37741a274155e34a0b7e427c35d2a2ecb9"
+checksum = "da32515d9f6e6e489d7bc9d84c71b060db7247dc035bbe44eac88cf87486d8d5"
 
 [[package]]
 name = "oorandom"
@@ -1274,9 +1282,9 @@ dependencies = [
 
 [[package]]
 name = "pulldown-cmark-to-cmark"
-version = "10.0.1"
+version = "10.0.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3eafb76310f7dc895b5d83d24f2a00e244fc8a68ef94f4257eb4060984d0385f"
+checksum = "d1dd19382cbbcee6ce498f65d5acaa6016e41ec701c9b0aef29a689bd7062f88"
 dependencies = [
  "pulldown-cmark",
 ]
@@ -1317,18 +1325,18 @@ dependencies = [
 
 [[package]]
 name = "redox_syscall"
-version = "0.2.11"
+version = "0.2.10"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "8380fe0152551244f0747b1bf41737e0f8a74f97a14ccefd1148187271634f3c"
+checksum = "8383f39639269cde97d255a32bdb68c047337295414940c68bdd30c2e13203ff"
 dependencies = [
  "bitflags",
 ]
 
 [[package]]
 name = "regex"
-version = "1.5.5"
+version = "1.5.4"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "1a11647b6b25ff05a515cb92c365cec08801e83423a235b51e231e1808747286"
+checksum = "d07a8629359eb56f1e2fb1652bb04212c072a87ba68546a04065d525673ac461"
 dependencies = [
  "regex-syntax",
 ]
@@ -1350,9 +1358,9 @@ checksum = "f497285884f3fcff424ffc933e56d7cbca511def0c9831a7f9b5f6153e3cc89b"
 
 [[package]]
 name = "rowan"
-version = "0.15.4"
+version = "0.15.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4c1112d7b23c800be3a0dae244886b71d96b1461b57b31b56e4c679acbe614f"
+checksum = "c72a0c863fef62cfd9ca7b72a35b422d7672dbffac4ac8003dcc3be7837d871d"
 dependencies = [
  "countme",
  "hashbrown 0.12.0",
@@ -1493,9 +1501,9 @@ checksum = "d29ab0c6d3fc0ee92fe66e2d99f700eab17a8d57d1c1d3b748380fb20baa78cd"
 
 [[package]]
 name = "semver"
-version = "1.0.6"
+version = "1.0.5"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a4a3381e03edd24287172047536f20cabde766e2cd3e65e6b00fb3af51c4f38d"
+checksum = "0486718e92ec9a68fbed73bb5ef687d71103b142595b406835649bebd33f72c7"
 dependencies = [
  "serde",
 ]
@@ -1593,9 +1601,9 @@ dependencies = [
 
 [[package]]
 name = "syn"
-version = "1.0.89"
+version = "1.0.86"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "ea297be220d52398dcc07ce15a209fce436d361735ac1db700cab3b6cdfb9f54"
+checksum = "8a65b3f4ffa0092e9887669db0eae07941f023991ab58ea44da8fe8e2d511c6b"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1695,9 +1703,9 @@ dependencies = [
 
 [[package]]
 name = "tikv-jemalloc-sys"
-version = "0.4.3+5.2.1-patched.2"
+version = "0.4.2+5.2.1-patched.2"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a1792ccb507d955b46af42c123ea8863668fae24d03721e40cad6a41773dbb49"
+checksum = "5844e429d797c62945a566f8da4e24c7fe3fbd5d6617fd8bf7a0b7dc1ee0f22e"
 dependencies = [
  "cc",
  "fs_extra",
@@ -1706,9 +1714,9 @@ dependencies = [
 
 [[package]]
 name = "tikv-jemallocator"
-version = "0.4.3"
+version = "0.4.1"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "a5b7bcecfafe4998587d636f9ae9d55eb9d0499877b88757767c346875067098"
+checksum = "3c14a5a604eb8715bc5785018a37d00739b180bcf609916ddf4393d33d49ccdf"
 dependencies = [
  "libc",
  "tikv-jemalloc-sys",
@@ -1738,9 +1746,9 @@ dependencies = [
 
 [[package]]
 name = "tracing"
-version = "0.1.32"
+version = "0.1.30"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4a1bdf54a7c28a2bbf701e1d2233f6c77f473486b94bee4f9678da5a148dca7f"
+checksum = "2d8d93354fe2a8e50d5953f5ae2e47a3fc2ef03292e7ea46e3cc38f549525fb9"
 dependencies = [
  "cfg-if",
  "pin-project-lite",
@@ -1750,9 +1758,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-attributes"
-version = "0.1.20"
+version = "0.1.19"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "2e65ce065b4b5c53e73bb28912318cb8c9e9ad3921f1d669eb0e68b4c8143a2b"
+checksum = "8276d9a4a3a558d7b7ad5303ad50b53d58264641b82914b7ada36bd762e7a716"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -1761,9 +1769,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-core"
-version = "0.1.23"
+version = "0.1.22"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "aa31669fa42c09c34d94d8165dd2012e8ff3c66aca50f3bb226b68f216f2706c"
+checksum = "03cfcb51380632a72d3111cb8d3447a8d908e577d31beeac006f836383d29a23"
 dependencies = [
  "lazy_static",
  "valuable",
@@ -1782,9 +1790,9 @@ dependencies = [
 
 [[package]]
 name = "tracing-subscriber"
-version = "0.3.9"
+version = "0.3.8"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e0ab7bdc962035a87fba73f3acca9b8a8d0034c2e6f60b84aeaaddddc155dce"
+checksum = "74786ce43333fcf51efe947aed9718fbe46d5c7328ec3f1029e818083966d9aa"
 dependencies = [
  "lazy_static",
  "matchers",
@@ -1924,12 +1932,6 @@ dependencies = [
  "winapi-util",
 ]
 
-[[package]]
-name = "wasi"
-version = "0.11.0+wasi-snapshot-preview1"
-source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9c8d87e72b64a3b4db28d11ce29237c246188f4f51057d65a7eab63b7987e423"
-
 [[package]]
 name = "winapi"
 version = "0.3.9"
@@ -2055,33 +2057,33 @@ checksum = "06069a848f95fceae3e5e03c0ddc8cb78452b56654ee0c8e68f938cf790fb9e3"
 
 [[package]]
 name = "xflags"
-version = "0.2.4"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "3f14fe1ed41a5a2b5ef3f565586c4a8a559ee55d3953faab360a771135bdee00"
+checksum = "2c2854f07e689d7388420d1c73512073630df31ec5ddf18554f64aea0ae73775"
 dependencies = [
  "xflags-macros",
 ]
 
 [[package]]
 name = "xflags-macros"
-version = "0.2.4"
+version = "0.2.3"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "45d11d5fc2a97287eded8b170ca80533b3c42646dd7fa386a5eb045817921022"
+checksum = "da260301476ad19a4733a0e930db8227a48ea04561e235a5102978145ec69fcc"
 
 [[package]]
 name = "xshell"
-version = "0.2.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4884417669886d3abff14feec797179526ade713f212e54ec08b19bc6bdc86aa"
+checksum = "3332cab90be2998a2aacb6494db45344bd16dfcc43ff36c42255018c6bcc96be"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.2.1"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "37d92065701c3611323f96eac5475b995421fc7eb2bcba1336cdd80b9b2fb68f"
+checksum = "f47e54cffa76000b7641328ab3bb1e146f93a1690ab86c5909c656f49d91019c"
 
 [[package]]
 name = "xtask"
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 3c12907b82..9207614c68 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -1547,7 +1547,9 @@ impl SelfParam {
 
 impl HasVisibility for Function {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.function_visibility(self.id)
+        let function_data = db.function_data(self.id);
+        let visibility = &function_data.visibility;
+        visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
     }
 }
 
@@ -1598,7 +1600,9 @@ impl Const {
 
 impl HasVisibility for Const {
     fn visibility(&self, db: &dyn HirDatabase) -> Visibility {
-        db.const_visibility(self.id)
+        let function_data = db.const_data(self.id);
+        let visibility = &function_data.visibility;
+        visibility.resolve(db.upcast(), &self.id.resolver(db.upcast()))
     }
 }
 
@@ -2075,7 +2079,7 @@ impl GenericDef {
                 id: LifetimeParamId { parent: self.into(), local_id },
             })
             .map(GenericParam::LifetimeParam);
-        lt_params.chain(ty_params).collect()
+        ty_params.chain(lt_params).collect()
     }
 
     pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
@@ -2336,18 +2340,6 @@ impl TypeParam {
         self.id.parent().module(db.upcast()).into()
     }
 
-    /// Is this type parameter implicitly introduced (eg. `Self` in a trait or an `impl Trait`
-    /// argument)?
-    pub fn is_implicit(self, db: &dyn HirDatabase) -> bool {
-        let params = db.generic_params(self.id.parent());
-        let data = &params.type_or_consts[self.id.local_id()];
-        match data.type_param().unwrap().provenance {
-            hir_def::generics::TypeParamProvenance::TypeParamList => false,
-            hir_def::generics::TypeParamProvenance::TraitSelf
-            | hir_def::generics::TypeParamProvenance::ArgumentImplTrait => true,
-        }
-    }
-
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
         let resolver = self.id.parent().resolver(db.upcast());
         let krate = self.id.parent().module(db.upcast()).krate();
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index c2b7e9bb52..4afdde6494 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -358,6 +358,10 @@ impl<'db, DB: HirDatabase> Semantics<'db, DB> {
         self.imp.resolve_macro_call(macro_call)
     }
 
+    pub fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
+        self.imp.is_unsafe_macro_call(macro_call)
+    }
+
     pub fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
         self.imp.resolve_attr_macro_call(item)
     }
@@ -961,6 +965,12 @@ impl<'db> SemanticsImpl<'db> {
         sa.resolve_macro_call(self.db, macro_call)
     }
 
+    fn is_unsafe_macro_call(&self, macro_call: &ast::MacroCall) -> bool {
+        let sa = self.analyze(macro_call.syntax());
+        let macro_call = self.find_file(macro_call.syntax()).with_value(macro_call);
+        sa.is_unsafe_macro_call(self.db, macro_call)
+    }
+
     fn resolve_attr_macro_call(&self, item: &ast::Item) -> Option<Macro> {
         let item_in_file = self.wrap_node_infile(item.clone());
         let id = self.with_ctx(|ctx| {
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 576d063c43..6b2120b253 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -25,7 +25,10 @@ use hir_def::{
 };
 use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
 use hir_ty::{
-    diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
+    diagnostics::{
+        record_literal_missing_fields, record_pattern_missing_fields, unsafe_expressions,
+        UnsafeExpr,
+    },
     Adjust, Adjustment, AutoBorrow, InferenceResult, Interner, Substitution, TyExt,
     TyLoweringContext,
 };
@@ -46,8 +49,7 @@ use base_db::CrateId;
 pub(crate) struct SourceAnalyzer {
     pub(crate) file_id: HirFileId,
     pub(crate) resolver: Resolver,
-    body: Option<Arc<Body>>,
-    body_source_map: Option<Arc<BodySourceMap>>,
+    def: Option<(DefWithBodyId, Arc<Body>, Arc<BodySourceMap>)>,
     infer: Option<Arc<InferenceResult>>,
 }
 
@@ -67,8 +69,7 @@ impl SourceAnalyzer {
         let resolver = resolver_for_scope(db.upcast(), def, scope);
         SourceAnalyzer {
             resolver,
-            body: Some(body),
-            body_source_map: Some(source_map),
+            def: Some((def, body, source_map)),
             infer: Some(db.infer(def)),
             file_id,
         }
@@ -87,26 +88,21 @@ impl SourceAnalyzer {
             Some(offset) => scope_for_offset(db, &scopes, &source_map, node.with_value(offset)),
         };
         let resolver = resolver_for_scope(db.upcast(), def, scope);
-        SourceAnalyzer {
-            resolver,
-            body: Some(body),
-            body_source_map: Some(source_map),
-            infer: None,
-            file_id,
-        }
+        SourceAnalyzer { resolver, def: Some((def, body, source_map)), infer: None, file_id }
     }
 
     pub(crate) fn new_for_resolver(
         resolver: Resolver,
         node: InFile<&SyntaxNode>,
     ) -> SourceAnalyzer {
-        SourceAnalyzer {
-            resolver,
-            body: None,
-            body_source_map: None,
-            infer: None,
-            file_id: node.file_id,
-        }
+        SourceAnalyzer { resolver, def: None, infer: None, file_id: node.file_id }
+    }
+
+    fn body_source_map(&self) -> Option<&BodySourceMap> {
+        self.def.as_ref().map(|(.., source_map)| &**source_map)
+    }
+    fn body(&self) -> Option<&Body> {
+        self.def.as_ref().map(|(_, body, _)| &**body)
     }
 
     fn expr_id(&self, db: &dyn HirDatabase, expr: &ast::Expr) -> Option<ExprId> {
@@ -116,14 +112,14 @@ impl SourceAnalyzer {
             }
             _ => InFile::new(self.file_id, expr.clone()),
         };
-        let sm = self.body_source_map.as_ref()?;
+        let sm = self.body_source_map()?;
         sm.node_expr(src.as_ref())
     }
 
     fn pat_id(&self, pat: &ast::Pat) -> Option<PatId> {
         // FIXME: macros, see `expr_id`
         let src = InFile { file_id: self.file_id, value: pat };
-        self.body_source_map.as_ref()?.node_pat(src)
+        self.body_source_map()?.node_pat(src)
     }
 
     fn expand_expr(
@@ -131,7 +127,7 @@ impl SourceAnalyzer {
         db: &dyn HirDatabase,
         expr: InFile<ast::MacroCall>,
     ) -> Option<InFile<ast::Expr>> {
-        let macro_file = self.body_source_map.as_ref()?.node_macro_file(expr.as_ref())?;
+        let macro_file = self.body_source_map()?.node_macro_file(expr.as_ref())?;
         let expanded = db.parse_or_expand(macro_file)?;
 
         let res = match ast::MacroCall::cast(expanded.clone()) {
@@ -196,7 +192,7 @@ impl SourceAnalyzer {
         param: &ast::SelfParam,
     ) -> Option<Type> {
         let src = InFile { file_id: self.file_id, value: param };
-        let pat_id = self.body_source_map.as_ref()?.node_self_param(src)?;
+        let pat_id = self.body_source_map()?.node_self_param(src)?;
         let ty = self.infer.as_ref()?[pat_id].clone();
         Type::new_with_resolver(db, &self.resolver, ty)
     }
@@ -226,7 +222,7 @@ impl SourceAnalyzer {
     ) -> Option<(Field, Option<Local>, Type)> {
         let record_expr = ast::RecordExpr::cast(field.syntax().parent().and_then(|p| p.parent())?)?;
         let expr = ast::Expr::from(record_expr);
-        let expr_id = self.body_source_map.as_ref()?.node_expr(InFile::new(self.file_id, &expr))?;
+        let expr_id = self.body_source_map()?.node_expr(InFile::new(self.file_id, &expr))?;
 
         let local_name = field.field_name()?.as_name();
         let local = if field.name_ref().is_some() {
@@ -279,7 +275,7 @@ impl SourceAnalyzer {
         pat: &ast::IdentPat,
     ) -> Option<ModuleDef> {
         let pat_id = self.pat_id(&pat.clone().into())?;
-        let body = self.body.as_ref()?;
+        let body = self.body()?;
         let path = match &body[pat_id] {
             Pat::Path(path) => path,
             _ => return None,
@@ -415,7 +411,7 @@ impl SourceAnalyzer {
         literal: &ast::RecordExpr,
     ) -> Option<Vec<(Field, Type)>> {
         let krate = self.resolver.krate()?;
-        let body = self.body.as_ref()?;
+        let body = self.body()?;
         let infer = self.infer.as_ref()?;
 
         let expr_id = self.expr_id(db, &literal.clone().into())?;
@@ -433,7 +429,7 @@ impl SourceAnalyzer {
         pattern: &ast::RecordPat,
     ) -> Option<Vec<(Field, Type)>> {
         let krate = self.resolver.krate()?;
-        let body = self.body.as_ref()?;
+        let body = self.body()?;
         let infer = self.infer.as_ref()?;
 
         let pat_id = self.pat_id(&pattern.clone().into())?;
@@ -488,6 +484,34 @@ impl SourceAnalyzer {
         let expr_id = self.expr_id(db, &record_lit.into())?;
         infer.variant_resolution_for_expr(expr_id)
     }
+
+    pub(crate) fn is_unsafe_macro_call(
+        &self,
+        db: &dyn HirDatabase,
+        macro_call: InFile<&ast::MacroCall>,
+    ) -> bool {
+        if let (Some((def, body, sm)), Some(infer)) = (&self.def, &self.infer) {
+            if let Some(expr_ids) = sm.macro_expansion_expr(macro_call) {
+                let mut is_unsafe = false;
+                for &expr_id in expr_ids {
+                    unsafe_expressions(
+                        db,
+                        infer,
+                        *def,
+                        body,
+                        expr_id,
+                        &mut |UnsafeExpr { inside_unsafe_block, .. }| {
+                            is_unsafe |= !inside_unsafe_block
+                        },
+                    );
+                    if is_unsafe {
+                        return true;
+                    }
+                }
+            }
+        }
+        false
+    }
 }
 
 fn scope_for(
diff --git a/crates/hir_def/src/body.rs b/crates/hir_def/src/body.rs
index ebb15e20cb..57dd3a3502 100644
--- a/crates/hir_def/src/body.rs
+++ b/crates/hir_def/src/body.rs
@@ -19,6 +19,7 @@ use la_arena::{Arena, ArenaMap};
 use limit::Limit;
 use profile::Count;
 use rustc_hash::FxHashMap;
+use smallvec::SmallVec;
 use syntax::{ast, AstNode, AstPtr, SyntaxNodePtr};
 
 use crate::{
@@ -293,6 +294,10 @@ pub struct BodySourceMap {
     field_map: FxHashMap<InFile<AstPtr<ast::RecordExprField>>, ExprId>,
     field_map_back: FxHashMap<ExprId, InFile<AstPtr<ast::RecordExprField>>>,
 
+    /// Maps a macro call to its lowered expressions, a single one if it expands to an expression,
+    /// or multiple if it expands to MacroStmts.
+    macro_call_to_exprs: FxHashMap<InFile<AstPtr<ast::MacroCall>>, SmallVec<[ExprId; 1]>>,
+
     expansions: FxHashMap<InFile<AstPtr<ast::MacroCall>>, HirFileId>,
 
     /// Diagnostics accumulated during body lowering. These contain `AstPtr`s and so are stored in
@@ -461,6 +466,11 @@ impl BodySourceMap {
         self.field_map.get(&src).cloned()
     }
 
+    pub fn macro_expansion_expr(&self, node: InFile<&ast::MacroCall>) -> Option<&[ExprId]> {
+        let src = node.map(AstPtr::new);
+        self.macro_call_to_exprs.get(&src).map(|it| &**it)
+    }
+
     /// Get a reference to the body source map's diagnostics.
     pub fn diagnostics(&self) -> &[BodyDiagnostic] {
         &self.diagnostics
diff --git a/crates/hir_def/src/body/lower.rs b/crates/hir_def/src/body/lower.rs
index 512a9312a7..d1cfc501e5 100644
--- a/crates/hir_def/src/body/lower.rs
+++ b/crates/hir_def/src/body/lower.rs
@@ -13,6 +13,7 @@ use hir_expand::{
 use la_arena::Arena;
 use profile::Count;
 use rustc_hash::FxHashMap;
+use smallvec::smallvec;
 use syntax::{
     ast::{
         self, ArrayExprKind, AstChildren, HasArgList, HasLoopBody, HasName, LiteralKind,
@@ -507,14 +508,18 @@ impl ExprCollector<'_> {
             }
             ast::Expr::MacroCall(e) => {
                 let macro_ptr = AstPtr::new(&e);
-                let mut ids = None;
-                self.collect_macro_call(e, macro_ptr, true, |this, expansion| {
-                    ids.get_or_insert(match expansion {
-                        Some(it) => this.collect_expr(it),
-                        None => this.alloc_expr(Expr::Missing, syntax_ptr.clone()),
-                    });
+                let id = self.collect_macro_call(e, macro_ptr.clone(), true, |this, expansion| {
+                    expansion.map(|it| this.collect_expr(it))
                 });
-                ids.unwrap_or_else(|| self.alloc_expr(Expr::Missing, syntax_ptr.clone()))
+                match id {
+                    Some(id) => {
+                        self.source_map
+                            .macro_call_to_exprs
+                            .insert(self.expander.to_source(macro_ptr), smallvec![id]);
+                        id
+                    }
+                    None => self.alloc_expr(Expr::Missing, syntax_ptr.clone()),
+                }
             }
             ast::Expr::MacroStmts(e) => {
                 e.statements().for_each(|s| self.collect_stmt(s));
@@ -529,13 +534,17 @@ impl ExprCollector<'_> {
         })
     }
 
-    fn collect_macro_call<F: FnMut(&mut Self, Option<T>), T: ast::AstNode>(
+    fn collect_macro_call<F, T, U>(
         &mut self,
         mcall: ast::MacroCall,
         syntax_ptr: AstPtr<ast::MacroCall>,
         record_diagnostics: bool,
-        mut collector: F,
-    ) {
+        collector: F,
+    ) -> U
+    where
+        F: FnOnce(&mut Self, Option<T>) -> U,
+        T: ast::AstNode,
+    {
         // File containing the macro call. Expansion errors will be attached here.
         let outer_file = self.expander.current_file_id;
 
@@ -551,8 +560,7 @@ impl ExprCollector<'_> {
                         path,
                     });
                 }
-                collector(self, None);
-                return;
+                return collector(self, None);
             }
         };
 
@@ -625,11 +633,9 @@ impl ExprCollector<'_> {
                     let macro_ptr = AstPtr::new(&m);
                     let syntax_ptr = AstPtr::new(&stmt.expr().unwrap());
 
-                    self.collect_macro_call(
-                        m,
-                        macro_ptr,
-                        false,
-                        |this, expansion| match expansion {
+                    let prev_stmt = self.statements_in_scope.len();
+                    self.collect_macro_call(m, macro_ptr.clone(), false, |this, expansion| {
+                        match expansion {
                             Some(expansion) => {
                                 let statements: ast::MacroStmts = expansion;
 
@@ -644,8 +650,24 @@ impl ExprCollector<'_> {
                                 let expr = this.alloc_expr(Expr::Missing, syntax_ptr.clone());
                                 this.statements_in_scope.push(Statement::Expr { expr, has_semi });
                             }
-                        },
-                    );
+                        }
+                    });
+
+                    let mut macro_exprs = smallvec![];
+                    for stmt in &self.statements_in_scope[prev_stmt..] {
+                        match *stmt {
+                            Statement::Let { initializer, else_branch, .. } => {
+                                macro_exprs.extend(initializer);
+                                macro_exprs.extend(else_branch);
+                            }
+                            Statement::Expr { expr, .. } => macro_exprs.push(expr),
+                        }
+                    }
+                    if !macro_exprs.is_empty() {
+                        self.source_map
+                            .macro_call_to_exprs
+                            .insert(self.expander.to_source(macro_ptr), macro_exprs);
+                    }
                 } else {
                     let expr = self.collect_expr_opt(stmt.expr());
                     self.statements_in_scope.push(Statement::Expr { expr, has_semi });
@@ -870,15 +892,11 @@ impl ExprCollector<'_> {
             ast::Pat::MacroPat(mac) => match mac.macro_call() {
                 Some(call) => {
                     let macro_ptr = AstPtr::new(&call);
-                    let mut pat = None;
-                    self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
-                        pat = Some(this.collect_pat_opt_(expanded_pat));
-                    });
-
-                    match pat {
-                        Some(pat) => return pat,
-                        None => Pat::Missing,
-                    }
+                    let pat =
+                        self.collect_macro_call(call, macro_ptr, true, |this, expanded_pat| {
+                            this.collect_pat_opt_(expanded_pat)
+                        });
+                    return pat;
                 }
                 None => Pat::Missing,
             },
diff --git a/crates/hir_def/src/db.rs b/crates/hir_def/src/db.rs
index 74bb7472d5..934d13c067 100644
--- a/crates/hir_def/src/db.rs
+++ b/crates/hir_def/src/db.rs
@@ -175,13 +175,9 @@ pub trait DefDatabase: InternDatabase + AstDatabase + Upcast<dyn AstDatabase> {
     #[salsa::invoke(visibility::field_visibilities_query)]
     fn field_visibilities(&self, var: VariantId) -> Arc<ArenaMap<LocalFieldId, Visibility>>;
 
-    // FIXME: unify function_visibility and const_visibility?
     #[salsa::invoke(visibility::function_visibility_query)]
     fn function_visibility(&self, def: FunctionId) -> Visibility;
 
-    #[salsa::invoke(visibility::const_visibility_query)]
-    fn const_visibility(&self, def: ConstId) -> Visibility;
-
     #[salsa::transparent]
     fn crate_limits(&self, crate_id: CrateId) -> CrateLimits;
 }
diff --git a/crates/hir_def/src/visibility.rs b/crates/hir_def/src/visibility.rs
index 6e22a877a9..f76034a3e2 100644
--- a/crates/hir_def/src/visibility.rs
+++ b/crates/hir_def/src/visibility.rs
@@ -11,7 +11,7 @@ use crate::{
     nameres::DefMap,
     path::{ModPath, PathKind},
     resolver::HasResolver,
-    ConstId, FunctionId, HasModule, LocalFieldId, ModuleId, VariantId,
+    FunctionId, HasModule, LocalFieldId, ModuleId, VariantId,
 };
 
 /// Visibility of an item, not yet resolved.
@@ -234,9 +234,3 @@ pub(crate) fn function_visibility_query(db: &dyn DefDatabase, def: FunctionId) -
     let resolver = def.resolver(db);
     db.function_data(def).visibility.resolve(db, &resolver)
 }
-
-/// Resolve visibility of a const.
-pub(crate) fn const_visibility_query(db: &dyn DefDatabase, def: ConstId) -> Visibility {
-    let resolver = def.resolver(db);
-    db.const_data(def).visibility.resolve(db, &resolver)
-}
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index 5c77c0cdf8..c507c42f5b 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -15,10 +15,10 @@ use hir_def::{
 use smallvec::SmallVec;
 
 use crate::{
-    consteval::unknown_const_as_generic, db::HirDatabase, infer::unify::InferenceTable, primitive,
-    to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData,
-    ConstValue, GenericArg, GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty,
-    TyDefId, TyExt, TyKind, ValueTyDefId,
+    consteval::unknown_const_as_generic, db::HirDatabase, primitive, to_assoc_type_id,
+    to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, ConstValue, GenericArg,
+    GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
+    ValueTyDefId,
 };
 
 #[derive(Debug, Clone, PartialEq, Eq)]
@@ -111,15 +111,6 @@ impl<D> TyBuilder<D> {
         this
     }
 
-    pub(crate) fn fill_with_inference_vars(self, table: &mut InferenceTable) -> Self {
-        self.fill(|x| match x {
-            ParamKind::Type => GenericArgData::Ty(table.new_type_var()).intern(Interner),
-            ParamKind::Const(ty) => {
-                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
-            }
-        })
-    }
-
     pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
         self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
         assert_eq!(self.remaining(), 0);
diff --git a/crates/hir_ty/src/diagnostics.rs b/crates/hir_ty/src/diagnostics.rs
index a4702715e5..37eb06be1d 100644
--- a/crates/hir_ty/src/diagnostics.rs
+++ b/crates/hir_ty/src/diagnostics.rs
@@ -9,5 +9,5 @@ pub use crate::diagnostics::{
     expr::{
         record_literal_missing_fields, record_pattern_missing_fields, BodyValidationDiagnostic,
     },
-    unsafe_check::missing_unsafe,
+    unsafe_check::{missing_unsafe, unsafe_expressions, UnsafeExpr},
 };
diff --git a/crates/hir_ty/src/diagnostics/unsafe_check.rs b/crates/hir_ty/src/diagnostics/unsafe_check.rs
index 2a18df253e..b0fc49fc61 100644
--- a/crates/hir_ty/src/diagnostics/unsafe_check.rs
+++ b/crates/hir_ty/src/diagnostics/unsafe_check.rs
@@ -12,54 +12,58 @@ use crate::{db::HirDatabase, InferenceResult, Interner, TyExt, TyKind};
 
 pub fn missing_unsafe(db: &dyn HirDatabase, def: DefWithBodyId) -> Vec<ExprId> {
     let infer = db.infer(def);
+    let mut res = Vec::new();
 
     let is_unsafe = match def {
         DefWithBodyId::FunctionId(it) => db.function_data(it).is_unsafe(),
         DefWithBodyId::StaticId(_) | DefWithBodyId::ConstId(_) => false,
     };
     if is_unsafe {
-        return Vec::new();
+        return res;
     }
 
-    unsafe_expressions(db, &infer, def)
-        .into_iter()
-        .filter(|it| !it.inside_unsafe_block)
-        .map(|it| it.expr)
-        .collect()
+    let body = db.body(def);
+    unsafe_expressions(db, &infer, def, &body, body.body_expr, &mut |expr| {
+        if !expr.inside_unsafe_block {
+            res.push(expr.expr);
+        }
+    });
+
+    res
 }
 
-struct UnsafeExpr {
-    pub(crate) expr: ExprId,
-    pub(crate) inside_unsafe_block: bool,
+pub struct UnsafeExpr {
+    pub expr: ExprId,
+    pub inside_unsafe_block: bool,
 }
 
-fn unsafe_expressions(
+// FIXME: Move this out, its not a diagnostic only thing anymore, and handle unsafe pattern accesses as well
+pub fn unsafe_expressions(
     db: &dyn HirDatabase,
     infer: &InferenceResult,
     def: DefWithBodyId,
-) -> Vec<UnsafeExpr> {
-    let mut unsafe_exprs = vec![];
-    let body = db.body(def);
-    walk_unsafe(&mut unsafe_exprs, db, infer, def, &body, body.body_expr, false);
-
-    unsafe_exprs
+    body: &Body,
+    current: ExprId,
+    unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
+) {
+    walk_unsafe(db, infer, def, body, current, false, unsafe_expr_cb)
 }
 
 fn walk_unsafe(
-    unsafe_exprs: &mut Vec<UnsafeExpr>,
     db: &dyn HirDatabase,
     infer: &InferenceResult,
     def: DefWithBodyId,
     body: &Body,
     current: ExprId,
     inside_unsafe_block: bool,
+    unsafe_expr_cb: &mut dyn FnMut(UnsafeExpr),
 ) {
     let expr = &body.exprs[current];
     match expr {
         &Expr::Call { callee, .. } => {
             if let Some(func) = infer[callee].as_fn_def(db) {
                 if db.function_data(func).is_unsafe() {
-                    unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
+                    unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
                 }
             }
         }
@@ -68,7 +72,7 @@ fn walk_unsafe(
             let value_or_partial = resolver.resolve_path_in_value_ns(db.upcast(), path.mod_path());
             if let Some(ResolveValueResult::ValueNs(ValueNs::StaticId(id))) = value_or_partial {
                 if db.static_data(id).mutable {
-                    unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
+                    unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
                 }
             }
         }
@@ -78,21 +82,21 @@ fn walk_unsafe(
                 .map(|(func, _)| db.function_data(func).is_unsafe())
                 .unwrap_or(false)
             {
-                unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
+                unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
             }
         }
         Expr::UnaryOp { expr, op: UnaryOp::Deref } => {
             if let TyKind::Raw(..) = &infer[*expr].kind(Interner) {
-                unsafe_exprs.push(UnsafeExpr { expr: current, inside_unsafe_block });
+                unsafe_expr_cb(UnsafeExpr { expr: current, inside_unsafe_block });
             }
         }
         Expr::Unsafe { body: child } => {
-            return walk_unsafe(unsafe_exprs, db, infer, def, body, *child, true);
+            return walk_unsafe(db, infer, def, body, *child, true, unsafe_expr_cb);
         }
         _ => {}
     }
 
     expr.walk_child_exprs(|child| {
-        walk_unsafe(unsafe_exprs, db, infer, def, body, child, inside_unsafe_block);
+        walk_unsafe(db, infer, def, body, child, inside_unsafe_block, unsafe_expr_cb);
     });
 }
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 442774d0be..4ee5391057 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -35,9 +35,10 @@ use rustc_hash::FxHashMap;
 use stdx::impl_from;
 
 use crate::{
-    db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
-    to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal, GenericArg, Goal, InEnvironment,
-    Interner, ProjectionTy, Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+    builder::ParamKind, db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany,
+    lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
+    GenericArg, GenericArgData, Goal, InEnvironment, Interner, ProjectionTy, Substitution,
+    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -45,6 +46,7 @@ use crate::{
 // https://github.com/rust-lang/rust/issues/57411
 #[allow(unreachable_pub)]
 pub use unify::could_unify;
+pub(crate) use unify::unify;
 
 pub(crate) mod unify;
 mod path;
@@ -655,7 +657,15 @@ impl<'a> InferenceContext<'a> {
             }
             TypeNs::TypeAliasId(it) => {
                 let ty = TyBuilder::def_ty(self.db, it.into())
-                    .fill_with_inference_vars(&mut self.table)
+                    .fill(|x| match x {
+                        ParamKind::Type => {
+                            GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
+                        }
+                        ParamKind::Const(ty) => {
+                            GenericArgData::Const(self.table.new_const_var(ty.clone()))
+                                .intern(Interner)
+                        }
+                    })
                     .build();
                 self.resolve_variant_on_alias(ty, unresolved, path)
             }
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 53fe2131a3..1d23654576 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -104,7 +104,9 @@ impl<'a> InferenceContext<'a> {
                     ParamKind::Type => {
                         GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
                     }
-                    ParamKind::Const(ty) => consteval::unknown_const_as_generic(ty.clone()),
+                    ParamKind::Const(_) => {
+                        GenericArgData::Const(consteval::usize_const(None)).intern(Interner)
+                    }
                 })
             })
             .build();
@@ -247,7 +249,15 @@ impl<'a> InferenceContext<'a> {
                 let substs = match container {
                     ItemContainerId::ImplId(impl_id) => {
                         let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
-                            .fill_with_inference_vars(&mut self.table)
+                            .fill(|x| match x {
+                                ParamKind::Type => {
+                                    GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
+                                }
+                                ParamKind::Const(ty) => {
+                                    GenericArgData::Const(self.table.new_const_var(ty.clone()))
+                                        .intern(Interner)
+                                }
+                            })
                             .build();
                         let impl_self_ty =
                             self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
@@ -258,7 +268,15 @@ impl<'a> InferenceContext<'a> {
                         // we're picking this method
                         let trait_ref = TyBuilder::trait_ref(self.db, trait_)
                             .push(ty.clone())
-                            .fill_with_inference_vars(&mut self.table)
+                            .fill(|x| match x {
+                                ParamKind::Type => {
+                                    GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
+                                }
+                                ParamKind::Const(ty) => {
+                                    GenericArgData::Const(self.table.new_const_var(ty.clone()))
+                                        .intern(Interner)
+                                }
+                            })
                             .build();
                         self.push_obligation(trait_ref.clone().cast(Interner));
                         Some(trait_ref.substitution)
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index ef0675d59f..deb536e511 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -146,7 +146,7 @@ pub(crate) struct InferenceTable<'a> {
 
 pub(crate) struct InferenceTableSnapshot {
     var_table_snapshot: chalk_solve::infer::InferenceSnapshot<Interner>,
-    pending_obligations: Vec<Canonicalized<InEnvironment<Goal>>>,
+    // FIXME: snapshot pending_obligations?
     type_variable_table_snapshot: Vec<TypeVariableData>,
 }
 
@@ -365,25 +365,12 @@ impl<'a> InferenceTable<'a> {
     pub(crate) fn snapshot(&mut self) -> InferenceTableSnapshot {
         let var_table_snapshot = self.var_unification_table.snapshot();
         let type_variable_table_snapshot = self.type_variable_table.clone();
-        let pending_obligations = self.pending_obligations.clone();
-        InferenceTableSnapshot {
-            var_table_snapshot,
-            pending_obligations,
-            type_variable_table_snapshot,
-        }
+        InferenceTableSnapshot { var_table_snapshot, type_variable_table_snapshot }
     }
 
     pub(crate) fn rollback_to(&mut self, snapshot: InferenceTableSnapshot) {
         self.var_unification_table.rollback_to(snapshot.var_table_snapshot);
         self.type_variable_table = snapshot.type_variable_table_snapshot;
-        self.pending_obligations = snapshot.pending_obligations;
-    }
-
-    pub(crate) fn run_in_snapshot<T>(&mut self, f: impl FnOnce(&mut InferenceTable) -> T) -> T {
-        let snapshot = self.snapshot();
-        let result = f(self);
-        self.rollback_to(snapshot);
-        result
     }
 
     /// Checks an obligation without registering it. Useful mostly to check
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 41bb94c5d5..9e69785ac2 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -9,8 +9,6 @@ use std::cell::{Cell, RefCell};
 use std::{iter, sync::Arc};
 
 use base_db::CrateId;
-use chalk_ir::fold::Fold;
-use chalk_ir::interner::HasInterner;
 use chalk_ir::{cast::Cast, fold::Shift, Mutability, Safety};
 use hir_def::generics::TypeOrConstParamData;
 use hir_def::intern::Interned;
@@ -38,6 +36,7 @@ use stdx::{impl_from, never};
 use syntax::{ast, SmolStr};
 
 use crate::consteval::{path_to_const, unknown_const_as_generic, unknown_const_usize, usize_const};
+use crate::method_resolution::fallback_bound_vars;
 use crate::utils::Generics;
 use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
 use crate::{
@@ -713,7 +712,7 @@ impl<'a> TyLoweringContext<'a> {
                 .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
                 .skip(skip)
                 .take(expected_num)
-                .zip(def_generics.iter_id().skip(parent_params + skip))
+                .zip(def_generics.iter_id().skip(skip))
             {
                 if let Some(x) = generic_arg_to_chalk(
                     self.db,
@@ -1702,28 +1701,3 @@ pub(crate) fn const_or_path_to_chalk(
         }
     }
 }
-
-/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
-/// num_vars_to_keep) by `TyKind::Unknown`.
-fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
-    s: T,
-    num_vars_to_keep: usize,
-) -> T::Result {
-    crate::fold_free_vars(
-        s,
-        |bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                TyKind::Error.intern(Interner)
-            } else {
-                bound.shifted_in_from(binders).to_ty(Interner)
-            }
-        },
-        |ty, bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                consteval::unknown_const(ty.clone())
-            } else {
-                bound.shifted_in_from(binders).to_const(Interner, ty)
-            }
-        },
-    )
-}
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 1c939f3d8a..06c834fbc8 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -6,7 +6,7 @@ use std::{iter, ops::ControlFlow, sync::Arc};
 
 use arrayvec::ArrayVec;
 use base_db::{CrateId, Edition};
-use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
+use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, Mutability, UniverseIndex};
 use hir_def::{
     item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
     ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
@@ -18,14 +18,16 @@ use stdx::never;
 
 use crate::{
     autoderef::{self, AutoderefKind},
+    consteval::{self, ConstExt},
     db::HirDatabase,
     from_foreign_def_id,
     infer::{unify::InferenceTable, Adjust, Adjustment, AutoBorrow, OverloadedDeref, PointerCast},
     primitive::{self, FloatTy, IntTy, UintTy},
     static_lifetime,
     utils::all_super_traits,
-    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
-    Scalar, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, GenericArgData,
+    InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
+    TyExt, TyKind,
 };
 
 /// This is used as a key for indexing impls.
@@ -641,10 +643,11 @@ pub fn iterate_method_candidates_dyn(
             let mut table = InferenceTable::new(db, env.clone());
             let ty = table.instantiate_canonical(ty.clone());
             let (deref_chain, adj) = autoderef_method_receiver(&mut table, ty);
+            let deref_chains = stdx::slice_tails(&deref_chain);
 
-            let result = deref_chain.into_iter().zip(adj).try_for_each(|(receiver_ty, adj)| {
+            let result = deref_chains.zip(adj).try_for_each(|(deref_chain, adj)| {
                 iterate_method_candidates_with_autoref(
-                    &receiver_ty,
+                    deref_chain,
                     adj,
                     db,
                     env.clone(),
@@ -672,7 +675,7 @@ pub fn iterate_method_candidates_dyn(
 }
 
 fn iterate_method_candidates_with_autoref(
-    receiver_ty: &Canonical<Ty>,
+    deref_chain: &[Canonical<Ty>],
     first_adjustment: ReceiverAdjustments,
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
@@ -681,9 +684,17 @@ fn iterate_method_candidates_with_autoref(
     name: Option<&Name>,
     mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
+    let (receiver_ty, rest) = match deref_chain.split_first() {
+        Some((rec, rest)) => (rec, rest),
+        None => {
+            never!("received empty deref-chain");
+            return ControlFlow::Break(());
+        }
+    };
     iterate_method_candidates_by_receiver(
         receiver_ty,
         first_adjustment.clone(),
+        rest,
         db,
         env.clone(),
         traits_in_scope,
@@ -701,6 +712,7 @@ fn iterate_method_candidates_with_autoref(
     iterate_method_candidates_by_receiver(
         &refed,
         first_adjustment.with_autoref(Mutability::Not),
+        deref_chain,
         db,
         env.clone(),
         traits_in_scope,
@@ -718,6 +730,7 @@ fn iterate_method_candidates_with_autoref(
     iterate_method_candidates_by_receiver(
         &ref_muted,
         first_adjustment.with_autoref(Mutability::Mut),
+        deref_chain,
         db,
         env,
         traits_in_scope,
@@ -730,6 +743,7 @@ fn iterate_method_candidates_with_autoref(
 fn iterate_method_candidates_by_receiver(
     receiver_ty: &Canonical<Ty>,
     receiver_adjustments: ReceiverAdjustments,
+    rest_of_deref_chain: &[Canonical<Ty>],
     db: &dyn HirDatabase,
     env: Arc<TraitEnvironment>,
     traits_in_scope: &FxHashSet<TraitId>,
@@ -737,35 +751,30 @@ fn iterate_method_candidates_by_receiver(
     name: Option<&Name>,
     mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let mut table = InferenceTable::new(db, env);
-    let receiver_ty = table.instantiate_canonical(receiver_ty.clone());
-    let snapshot = table.snapshot();
     // We're looking for methods with *receiver* type receiver_ty. These could
     // be found in any of the derefs of receiver_ty, so we have to go through
     // that.
-    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
-    while let Some((self_ty, _)) = autoderef.next() {
+    for self_ty in iter::once(receiver_ty).chain(rest_of_deref_chain) {
         iterate_inherent_methods(
-            &self_ty,
-            &mut autoderef.table,
+            self_ty,
+            db,
+            env.clone(),
             name,
-            Some(&receiver_ty),
+            Some(receiver_ty),
             Some(receiver_adjustments.clone()),
             visible_from_module,
             &mut callback,
         )?
     }
 
-    table.rollback_to(snapshot);
-
-    let mut autoderef = autoderef::Autoderef::new(&mut table, receiver_ty.clone());
-    while let Some((self_ty, _)) = autoderef.next() {
+    for self_ty in iter::once(receiver_ty).chain(rest_of_deref_chain) {
         iterate_trait_method_candidates(
-            &self_ty,
-            &mut autoderef.table,
+            self_ty,
+            db,
+            env.clone(),
             traits_in_scope,
             name,
-            Some(&receiver_ty),
+            Some(receiver_ty),
             Some(receiver_adjustments.clone()),
             &mut callback,
         )?
@@ -783,55 +792,43 @@ fn iterate_method_candidates_for_self_ty(
     name: Option<&Name>,
     mut callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let mut table = InferenceTable::new(db, env);
-    let self_ty = table.instantiate_canonical(self_ty.clone());
     iterate_inherent_methods(
-        &self_ty,
-        &mut table,
+        self_ty,
+        db,
+        env.clone(),
         name,
         None,
         None,
         visible_from_module,
         &mut callback,
     )?;
-    iterate_trait_method_candidates(
-        &self_ty,
-        &mut table,
-        traits_in_scope,
-        name,
-        None,
-        None,
-        callback,
-    )
+    iterate_trait_method_candidates(self_ty, db, env, traits_in_scope, name, None, None, callback)
 }
 
 fn iterate_trait_method_candidates(
-    self_ty: &Ty,
-    table: &mut InferenceTable,
+    self_ty: &Canonical<Ty>,
+    db: &dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
     traits_in_scope: &FxHashSet<TraitId>,
     name: Option<&Name>,
-    receiver_ty: Option<&Ty>,
+    receiver_ty: Option<&Canonical<Ty>>,
     receiver_adjustments: Option<ReceiverAdjustments>,
     callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let db = table.db;
-    let env = table.trait_env.clone();
-    let self_is_array = matches!(self_ty.kind(Interner), chalk_ir::TyKind::Array(..));
+    let self_is_array = matches!(self_ty.value.kind(Interner), chalk_ir::TyKind::Array(..));
     // if ty is `dyn Trait`, the trait doesn't need to be in scope
     let inherent_trait =
-        self_ty.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
-    let env_traits = matches!(self_ty.kind(Interner), TyKind::Placeholder(_))
+        self_ty.value.dyn_trait().into_iter().flat_map(|t| all_super_traits(db.upcast(), t));
+    let env_traits = matches!(self_ty.value.kind(Interner), TyKind::Placeholder(_))
         // if we have `T: Trait` in the param env, the trait doesn't need to be in scope
         .then(|| {
-            env.traits_in_scope_from_clauses(self_ty.clone())
+            env.traits_in_scope_from_clauses(self_ty.value.clone())
                 .flat_map(|t| all_super_traits(db.upcast(), t))
         })
         .into_iter()
         .flatten();
     let traits = inherent_trait.chain(env_traits).chain(traits_in_scope.iter().copied());
 
-    let canonical_self_ty = table.canonicalize(self_ty.clone()).value;
-
     'traits: for t in traits {
         let data = db.trait_data(t);
 
@@ -855,11 +852,11 @@ fn iterate_trait_method_candidates(
         for &(_, item) in data.items.iter() {
             // Don't pass a `visible_from_module` down to `is_valid_candidate`,
             // since only inherent methods should be included into visibility checking.
-            if !is_valid_candidate(table, name, receiver_ty, item, self_ty, None) {
+            if !is_valid_candidate(db, env.clone(), name, receiver_ty, item, self_ty, None) {
                 continue;
             }
             if !known_implemented {
-                let goal = generic_implements_goal(db, env.clone(), t, &canonical_self_ty);
+                let goal = generic_implements_goal(db, env.clone(), t, self_ty);
                 if db.trait_solve(env.krate, goal.cast(Interner)).is_none() {
                     continue 'traits;
                 }
@@ -871,18 +868,40 @@ fn iterate_trait_method_candidates(
     ControlFlow::Continue(())
 }
 
-fn iterate_inherent_methods(
+fn filter_inherent_impls_for_self_ty<'i>(
+    impls: &'i InherentImpls,
     self_ty: &Ty,
-    table: &mut InferenceTable,
+) -> impl Iterator<Item = &'i ImplId> {
+    // inherent methods on arrays are fingerprinted as [T; {unknown}], so we must also consider them when
+    // resolving a method call on an array with a known len
+    let array_impls = {
+        match self_ty.kind(Interner) {
+            TyKind::Array(parameters, array_len) if !array_len.is_unknown() => {
+                let unknown_array_len_ty =
+                    TyKind::Array(parameters.clone(), consteval::usize_const(None));
+
+                Some(impls.for_self_ty(&unknown_array_len_ty.intern(Interner)))
+            }
+            _ => None,
+        }
+    }
+    .into_iter()
+    .flatten();
+
+    impls.for_self_ty(self_ty).iter().chain(array_impls)
+}
+
+fn iterate_inherent_methods(
+    self_ty: &Canonical<Ty>,
+    db: &dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
     name: Option<&Name>,
-    receiver_ty: Option<&Ty>,
+    receiver_ty: Option<&Canonical<Ty>>,
     receiver_adjustments: Option<ReceiverAdjustments>,
     visible_from_module: VisibleFromModule,
     callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
 ) -> ControlFlow<()> {
-    let db = table.db;
-    let env = table.trait_env.clone();
-    let def_crates = match def_crates(db, self_ty, env.krate) {
+    let def_crates = match def_crates(db, &self_ty.value, env.krate) {
         Some(k) => k,
         None => return ControlFlow::Continue(()),
     };
@@ -898,7 +917,8 @@ fn iterate_inherent_methods(
             impls_for_self_ty(
                 &impls,
                 self_ty,
-                table,
+                db,
+                env.clone(),
                 name,
                 receiver_ty,
                 receiver_adjustments.clone(),
@@ -913,7 +933,8 @@ fn iterate_inherent_methods(
         impls_for_self_ty(
             &impls,
             self_ty,
-            table,
+            db,
+            env.clone(),
             name,
             receiver_ty,
             receiver_adjustments.clone(),
@@ -925,20 +946,37 @@ fn iterate_inherent_methods(
 
     fn impls_for_self_ty(
         impls: &InherentImpls,
-        self_ty: &Ty,
-        table: &mut InferenceTable,
+        self_ty: &Canonical<Ty>,
+        db: &dyn HirDatabase,
+        env: Arc<TraitEnvironment>,
         name: Option<&Name>,
-        receiver_ty: Option<&Ty>,
+        receiver_ty: Option<&Canonical<Ty>>,
         receiver_adjustments: Option<ReceiverAdjustments>,
         visible_from_module: Option<ModuleId>,
         callback: &mut dyn FnMut(ReceiverAdjustments, AssocItemId) -> ControlFlow<()>,
     ) -> ControlFlow<()> {
-        let db = table.db;
-        let impls_for_self_ty = impls.for_self_ty(self_ty);
+        let impls_for_self_ty = filter_inherent_impls_for_self_ty(impls, &self_ty.value);
         for &impl_def in impls_for_self_ty {
             for &item in &db.impl_data(impl_def).items {
-                if !is_valid_candidate(table, name, receiver_ty, item, self_ty, visible_from_module)
+                if !is_valid_candidate(
+                    db,
+                    env.clone(),
+                    name,
+                    receiver_ty,
+                    item,
+                    self_ty,
+                    visible_from_module,
+                ) {
+                    continue;
+                }
+                // we have to check whether the self type unifies with the type
+                // that the impl is for. If we have a receiver type, this
+                // already happens in `is_valid_candidate` above; if not, we
+                // check it here
+                if receiver_ty.is_none()
+                    && inherent_impl_substs(db, env.clone(), impl_def, self_ty).is_none()
                 {
+                    cov_mark::hit!(impl_self_type_match_without_receiver);
                     continue;
                 }
                 callback(receiver_adjustments.clone().unwrap_or_default(), item)?;
@@ -967,15 +1005,37 @@ pub fn resolve_indexing_op(
     None
 }
 
+fn is_transformed_receiver_ty_equal(transformed_receiver_ty: &Ty, receiver_ty: &Ty) -> bool {
+    if transformed_receiver_ty == receiver_ty {
+        return true;
+    }
+
+    // a transformed receiver may be considered equal (and a valid method call candidate) if it is an array
+    // with an unknown (i.e. generic) length, and the receiver is an array with the same item type but a known len,
+    // this allows inherent methods on arrays to be considered valid resolution candidates
+    match (transformed_receiver_ty.kind(Interner), receiver_ty.kind(Interner)) {
+        (
+            TyKind::Array(transformed_array_ty, transformed_array_len),
+            TyKind::Array(receiver_array_ty, receiver_array_len),
+        ) if transformed_array_ty == receiver_array_ty
+            && transformed_array_len.is_unknown()
+            && !receiver_array_len.is_unknown() =>
+        {
+            true
+        }
+        _ => false,
+    }
+}
+
 fn is_valid_candidate(
-    table: &mut InferenceTable,
+    db: &dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
     name: Option<&Name>,
-    receiver_ty: Option<&Ty>,
+    receiver_ty: Option<&Canonical<Ty>>,
     item: AssocItemId,
-    self_ty: &Ty,
+    self_ty: &Canonical<Ty>,
     visible_from_module: Option<ModuleId>,
 ) -> bool {
-    let db = table.db;
     match item {
         AssocItemId::FunctionId(m) => {
             let data = db.function_data(m);
@@ -984,82 +1044,123 @@ fn is_valid_candidate(
                     return false;
                 }
             }
-            table.run_in_snapshot(|table| {
-                let subst = TyBuilder::subst_for_def(db, m).fill_with_inference_vars(table).build();
-                let expected_self_ty = match m.lookup(db.upcast()).container {
-                    ItemContainerId::TraitId(_) => {
-                        subst.at(Interner, 0).assert_ty_ref(Interner).clone()
-                    }
-                    ItemContainerId::ImplId(impl_id) => {
-                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner)
-                    }
-                    // We should only get called for associated items (impl/trait)
-                    ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => {
-                        unreachable!()
-                    }
-                };
-                if !table.unify(&expected_self_ty, &self_ty) {
+            if let Some(receiver_ty) = receiver_ty {
+                if !data.has_self_param() {
                     return false;
                 }
-                if let Some(receiver_ty) = receiver_ty {
-                    if !data.has_self_param() {
-                        return false;
-                    }
-
-                    let sig = db.callable_item_signature(m.into());
-                    let expected_receiver =
-                        sig.map(|s| s.params()[0].clone()).substitute(Interner, &subst);
-                    let receiver_matches = table.unify(&receiver_ty, &expected_receiver);
-
-                    if !receiver_matches {
-                        return false;
-                    }
-                }
-                if let Some(from_module) = visible_from_module {
-                    if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
-                        cov_mark::hit!(autoderef_candidate_not_visible);
-                        return false;
-                    }
-                }
+                let transformed_receiver_ty = match transform_receiver_ty(db, env, m, self_ty) {
+                    Some(ty) => ty,
+                    None => return false,
+                };
 
-                true
-            })
-        }
-        AssocItemId::ConstId(c) => {
-            let data = db.const_data(c);
-            if receiver_ty.is_some() {
-                return false;
-            }
-            if let Some(name) = name {
-                if data.name.as_ref() != Some(name) {
+                if !is_transformed_receiver_ty_equal(&transformed_receiver_ty, &receiver_ty.value) {
                     return false;
                 }
             }
             if let Some(from_module) = visible_from_module {
-                if !db.const_visibility(c).is_visible_from(db.upcast(), from_module) {
-                    cov_mark::hit!(const_candidate_not_visible);
-                    return false;
-                }
-            }
-            if let ItemContainerId::ImplId(impl_id) = c.lookup(db.upcast()).container {
-                let self_ty_matches = table.run_in_snapshot(|table| {
-                    let subst =
-                        TyBuilder::subst_for_def(db, c).fill_with_inference_vars(table).build();
-                    let expected_self_ty =
-                        subst.apply(db.impl_self_ty(impl_id).skip_binders().clone(), Interner);
-                    table.unify(&expected_self_ty, &self_ty)
-                });
-                if !self_ty_matches {
-                    cov_mark::hit!(const_candidate_self_type_mismatch);
+                if !db.function_visibility(m).is_visible_from(db.upcast(), from_module) {
+                    cov_mark::hit!(autoderef_candidate_not_visible);
                     return false;
                 }
             }
+
             true
         }
+        AssocItemId::ConstId(c) => {
+            let data = db.const_data(c);
+            name.map_or(true, |name| data.name.as_ref() == Some(name)) && receiver_ty.is_none()
+        }
         _ => false,
     }
 }
 
+pub(crate) fn inherent_impl_substs(
+    db: &dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
+    impl_id: ImplId,
+    self_ty: &Canonical<Ty>,
+) -> Option<Substitution> {
+    // we create a var for each type parameter of the impl; we need to keep in
+    // mind here that `self_ty` might have vars of its own
+    let self_ty_vars = self_ty.binders.len(Interner);
+    let vars = TyBuilder::subst_for_def(db, impl_id)
+        .fill_with_bound_vars(DebruijnIndex::INNERMOST, self_ty_vars)
+        .build();
+    let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(Interner, &vars);
+    let mut kinds = self_ty.binders.interned().to_vec();
+    kinds.extend(vars.iter(Interner).map(|x| {
+        let kind = match x.data(Interner) {
+            GenericArgData::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+            GenericArgData::Const(c) => chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()),
+            GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
+        };
+        chalk_ir::WithKind::new(kind, UniverseIndex::ROOT)
+    }));
+    let tys = Canonical {
+        binders: CanonicalVarKinds::from_iter(Interner, kinds),
+        value: (self_ty_with_vars, self_ty.value.clone()),
+    };
+    let substs = super::infer::unify(db, env, &tys)?;
+    // We only want the substs for the vars we added, not the ones from self_ty.
+    // Also, if any of the vars we added are still in there, we replace them by
+    // Unknown. I think this can only really happen if self_ty contained
+    // Unknown, and in that case we want the result to contain Unknown in those
+    // places again.
+    let suffix =
+        Substitution::from_iter(Interner, substs.iter(Interner).skip(self_ty_vars).cloned());
+    Some(fallback_bound_vars(suffix, self_ty_vars))
+}
+
+/// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
+/// num_vars_to_keep) by `TyKind::Unknown`.
+pub(crate) fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
+    s: T,
+    num_vars_to_keep: usize,
+) -> T::Result {
+    crate::fold_free_vars(
+        s,
+        |bound, binders| {
+            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
+                TyKind::Error.intern(Interner)
+            } else {
+                bound.shifted_in_from(binders).to_ty(Interner)
+            }
+        },
+        |ty, bound, binders| {
+            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
+                consteval::usize_const(None)
+            } else {
+                bound.shifted_in_from(binders).to_const(Interner, ty)
+            }
+        },
+    )
+}
+
+fn transform_receiver_ty(
+    db: &dyn HirDatabase,
+    env: Arc<TraitEnvironment>,
+    function_id: FunctionId,
+    self_ty: &Canonical<Ty>,
+) -> Option<Ty> {
+    let substs = match function_id.lookup(db.upcast()).container {
+        ItemContainerId::TraitId(_) => TyBuilder::subst_for_def(db, function_id)
+            .push(self_ty.value.clone())
+            .fill_with_unknown()
+            .build(),
+        ItemContainerId::ImplId(impl_id) => {
+            let impl_substs = inherent_impl_substs(db, env, impl_id, self_ty)?;
+            TyBuilder::subst_for_def(db, function_id)
+                .use_parent_substs(&impl_substs)
+                .fill_with_unknown()
+                .build()
+        }
+        // No receiver
+        ItemContainerId::ModuleId(_) | ItemContainerId::ExternBlockId(_) => unreachable!(),
+    };
+    let sig = db.callable_item_signature(function_id.into());
+    Some(sig.map(|s| s.params()[0].clone()).substitute(Interner, &substs))
+}
+
 pub fn implements_trait(
     ty: &Canonical<Ty>,
     db: &dyn HirDatabase,
diff --git a/crates/ide/src/signature_help.rs b/crates/ide/src/call_info.rs
similarity index 68%
rename from crates/ide/src/signature_help.rs
rename to crates/ide/src/call_info.rs
index e13abe2d87..7568faa6bd 100644
--- a/crates/ide/src/signature_help.rs
+++ b/crates/ide/src/call_info.rs
@@ -1,30 +1,24 @@
-//! This module provides primitives for showing type and function parameter information when editing
-//! a call or use-site.
+//! This module provides primitives for tracking the information about a call site.
 
 use either::Either;
 use hir::{HasAttrs, HirDisplay, Semantics};
-use ide_db::{
-    active_parameter::{callable_for_token, generics_for_token},
-    base_db::FilePosition,
-};
+use ide_db::{active_parameter::callable_for_token, base_db::FilePosition};
 use stdx::format_to;
 use syntax::{algo, AstNode, Direction, TextRange, TextSize};
 
 use crate::RootDatabase;
 
-/// Contains information about an item signature as seen from a use site.
-///
-/// This includes the "active parameter", which is the parameter whose value is currently being
-/// edited.
+/// Contains information about a call site. Specifically the
+/// `FunctionSignature`and current parameter.
 #[derive(Debug)]
-pub struct SignatureHelp {
+pub struct CallInfo {
     pub doc: Option<String>,
     pub signature: String,
     pub active_parameter: Option<usize>,
     parameters: Vec<TextRange>,
 }
 
-impl SignatureHelp {
+impl CallInfo {
     pub fn parameter_labels(&self) -> impl Iterator<Item = &str> + '_ {
         self.parameters.iter().map(move |&it| &self.signature[it])
     }
@@ -33,16 +27,8 @@ impl SignatureHelp {
         &self.parameters
     }
 
-    fn push_call_param(&mut self, param: &str) {
-        self.push_param('(', param);
-    }
-
-    fn push_generic_param(&mut self, param: &str) {
-        self.push_param('<', param);
-    }
-
-    fn push_param(&mut self, opening_delim: char, param: &str) {
-        if !self.signature.ends_with(opening_delim) {
+    fn push_param(&mut self, param: &str) {
+        if !self.signature.ends_with('(') {
             self.signature.push_str(", ");
         }
         let start = TextSize::of(&self.signature);
@@ -52,8 +38,8 @@ impl SignatureHelp {
     }
 }
 
-/// Computes parameter information for the given position.
-pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Option<SignatureHelp> {
+/// Computes parameter information for the given call expression.
+pub(crate) fn call_info(db: &RootDatabase, position: FilePosition) -> Option<CallInfo> {
     let sema = Semantics::new(db);
     let file = sema.parse(position.file_id);
     let file = file.syntax();
@@ -65,24 +51,10 @@ pub(crate) fn signature_help(db: &RootDatabase, position: FilePosition) -> Optio
         .and_then(|tok| algo::skip_trivia_token(tok, Direction::Prev))?;
     let token = sema.descend_into_macros_single(token);
 
-    if let Some((callable, active_parameter)) = callable_for_token(&sema, token.clone()) {
-        return Some(signature_help_for_callable(db, callable, active_parameter));
-    }
-
-    if let Some((generic_def, active_parameter)) = generics_for_token(&sema, token.clone()) {
-        return signature_help_for_generics(db, generic_def, active_parameter);
-    }
-
-    None
-}
+    let (callable, active_parameter) = callable_for_token(&sema, token)?;
 
-fn signature_help_for_callable(
-    db: &RootDatabase,
-    callable: hir::Callable,
-    active_parameter: Option<usize>,
-) -> SignatureHelp {
     let mut res =
-        SignatureHelp { doc: None, signature: String::new(), parameters: vec![], active_parameter };
+        CallInfo { doc: None, signature: String::new(), parameters: vec![], active_parameter };
 
     match callable.kind() {
         hir::CallableKind::Function(func) => {
@@ -120,7 +92,7 @@ fn signature_help_for_callable(
                 }
             }
             format_to!(buf, "{}", ty.display(db));
-            res.push_call_param(&buf);
+            res.push_param(&buf);
         }
     }
     res.signature.push(')');
@@ -134,75 +106,6 @@ fn signature_help_for_callable(
         }
         hir::CallableKind::TupleStruct(_) | hir::CallableKind::TupleEnumVariant(_) => {}
     }
-    res
-}
-
-fn signature_help_for_generics(
-    db: &RootDatabase,
-    mut generics_def: hir::GenericDef,
-    active_parameter: usize,
-) -> Option<SignatureHelp> {
-    let mut res = SignatureHelp {
-        doc: None,
-        signature: String::new(),
-        parameters: vec![],
-        active_parameter: Some(active_parameter),
-    };
-
-    match generics_def {
-        hir::GenericDef::Function(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
-            format_to!(res.signature, "fn {}", it.name(db));
-        }
-        hir::GenericDef::Adt(hir::Adt::Enum(it)) => {
-            res.doc = it.docs(db).map(|it| it.into());
-            format_to!(res.signature, "enum {}", it.name(db));
-        }
-        hir::GenericDef::Adt(hir::Adt::Struct(it)) => {
-            res.doc = it.docs(db).map(|it| it.into());
-            format_to!(res.signature, "struct {}", it.name(db));
-        }
-        hir::GenericDef::Adt(hir::Adt::Union(it)) => {
-            res.doc = it.docs(db).map(|it| it.into());
-            format_to!(res.signature, "union {}", it.name(db));
-        }
-        hir::GenericDef::Trait(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
-            format_to!(res.signature, "trait {}", it.name(db));
-        }
-        hir::GenericDef::TypeAlias(it) => {
-            res.doc = it.docs(db).map(|it| it.into());
-            format_to!(res.signature, "type {}", it.name(db));
-        }
-        hir::GenericDef::Variant(it) => {
-            // In paths, generics of an enum can be specified *after* one of its variants.
-            // eg. `None::<u8>`
-            // We'll use the signature of the enum, but include the docs of the variant.
-            res.doc = it.docs(db).map(|it| it.into());
-            let it = it.parent_enum(db);
-            format_to!(res.signature, "enum {}", it.name(db));
-            generics_def = it.into();
-        }
-        // These don't have generic args that can be specified
-        hir::GenericDef::Impl(_) | hir::GenericDef::Const(_) => return None,
-    }
-
-    res.signature.push('<');
-    let params = generics_def.params(db);
-    let mut buf = String::new();
-    for param in params {
-        if let hir::GenericParam::TypeParam(ty) = param {
-            if ty.is_implicit(db) {
-                continue;
-            }
-        }
-
-        buf.clear();
-        format_to!(buf, "{}", param.display(db));
-        res.push_generic_param(&buf);
-    }
-    res.signature.push('>');
-
     Some(res)
 }
 
@@ -225,15 +128,8 @@ mod tests {
     }
 
     fn check(ra_fixture: &str, expect: Expect) {
-        // Implicitly add `Sized` to avoid noisy `T: ?Sized` in the results.
-        let fixture = format!(
-            r#"
-#[lang = "sized"] trait Sized {{}}
-{ra_fixture}
-            "#
-        );
-        let (db, position) = position(&fixture);
-        let call_info = crate::signature_help::signature_help(&db, position);
+        let (db, position) = position(ra_fixture);
+        let call_info = crate::call_info::call_info(&db, position);
         let actual = match call_info {
             Some(call_info) => {
                 let docs = match &call_info.doc {
@@ -780,138 +676,4 @@ fn main() {
         "#]],
         )
     }
-
-    #[test]
-    fn test_generics_simple() {
-        check(
-            r#"
-/// Option docs.
-enum Option<T> {
-    Some(T),
-    None,
-}
-
-fn f() {
-    let opt: Option<$0
-}
-        "#,
-            expect![[r#"
-                Option docs.
-                ------
-                enum Option<T>
-                (<T>)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_generics_on_variant() {
-        check(
-            r#"
-/// Option docs.
-enum Option<T> {
-    /// Some docs.
-    Some(T),
-    /// None docs.
-    None,
-}
-
-use Option::*;
-
-fn f() {
-    None::<$0
-}
-        "#,
-            expect![[r#"
-                None docs.
-                ------
-                enum Option<T>
-                (<T>)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_lots_of_generics() {
-        check(
-            r#"
-trait Tr<T> {}
-
-struct S<T>(T);
-
-impl<T> S<T> {
-    fn f<G, H>(g: G, h: impl Tr<G>) where G: Tr<()> {}
-}
-
-fn f() {
-    S::<u8>::f::<(), $0
-}
-        "#,
-            expect![[r#"
-                fn f<G: Tr<()>, H>
-                (G: Tr<()>, <H>)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_generics_in_trait_ufcs() {
-        check(
-            r#"
-trait Tr {
-    fn f<T: Tr, U>() {}
-}
-
-struct S;
-
-impl Tr for S {}
-
-fn f() {
-    <S as Tr>::f::<$0
-}
-        "#,
-            expect![[r#"
-                fn f<T: Tr, U>
-                (<T: Tr>, U)
-            "#]],
-        );
-    }
-
-    #[test]
-    fn test_generics_in_method_call() {
-        check(
-            r#"
-struct S;
-
-impl S {
-    fn f<T>(&self) {}
-}
-
-fn f() {
-    S.f::<$0
-}
-        "#,
-            expect![[r#"
-            fn f<T>
-            (<T>)
-        "#]],
-        );
-    }
-
-    #[test]
-    fn test_generic_kinds() {
-        check(
-            r#"
-fn callee<'a, const A: (), T, const C: u8>() {}
-
-fn f() {
-    callee::<'static, $0
-}
-        "#,
-            expect![[r#"
-            fn callee<'a, const A: (), T, const C: u8>
-            ('a, <const A: ()>, T, const C: u8)
-        "#]],
-        );
-    }
 }
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 7fcb09b5e2..ff20d98f1f 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -24,7 +24,7 @@ mod navigation_target;
 
 mod annotations;
 mod call_hierarchy;
-mod signature_help;
+mod call_info;
 mod doc_links;
 mod highlight_related;
 mod expand_macro;
@@ -75,6 +75,7 @@ use crate::navigation_target::{ToNav, TryToNav};
 pub use crate::{
     annotations::{Annotation, AnnotationConfig, AnnotationKind},
     call_hierarchy::CallItem,
+    call_info::CallInfo,
     expand_macro::ExpandedMacro,
     file_structure::{StructureNode, StructureNodeKind},
     folding_ranges::{Fold, FoldKind},
@@ -90,7 +91,6 @@ pub use crate::{
     references::ReferenceSearchResult,
     rename::RenameError,
     runnables::{Runnable, RunnableKind, TestId},
-    signature_help::SignatureHelp,
     static_index::{StaticIndex, StaticIndexedFile, TokenId, TokenStaticData},
     syntax_highlighting::{
         tags::{Highlight, HlMod, HlMods, HlOperator, HlPunct, HlTag},
@@ -450,9 +450,9 @@ impl Analysis {
         self.with_db(|db| doc_links::external_docs(db, &position))
     }
 
-    /// Computes parameter information at the given position.
-    pub fn signature_help(&self, position: FilePosition) -> Cancellable<Option<SignatureHelp>> {
-        self.with_db(|db| signature_help::signature_help(db, position))
+    /// Computes parameter information for the given call expression.
+    pub fn call_info(&self, position: FilePosition) -> Cancellable<Option<CallInfo>> {
+        self.with_db(|db| call_info::call_info(db, position))
     }
 
     /// Computes call hierarchy candidates for the given file position.
diff --git a/crates/ide/src/syntax_highlighting/highlight.rs b/crates/ide/src/syntax_highlighting/highlight.rs
index e7aa83dd9e..7ac6775685 100644
--- a/crates/ide/src/syntax_highlighting/highlight.rs
+++ b/crates/ide/src/syntax_highlighting/highlight.rs
@@ -248,6 +248,16 @@ fn highlight_name_ref(
                         }
                     }
                 }
+                Definition::Macro(_) => {
+                    if let Some(macro_call) =
+                        ide_db::syntax_helpers::node_ext::full_path_of_name_ref(&name_ref)
+                            .and_then(|it| it.syntax().parent().and_then(ast::MacroCall::cast))
+                    {
+                        if sema.is_unsafe_macro_call(&macro_call) {
+                            h |= HlMod::Unsafe;
+                        }
+                    }
+                }
                 _ => (),
             }
 
diff --git a/crates/ide/src/syntax_highlighting/html.rs b/crates/ide/src/syntax_highlighting/html.rs
index 0491ce3635..9777c014c7 100644
--- a/crates/ide/src/syntax_highlighting/html.rs
+++ b/crates/ide/src/syntax_highlighting/html.rs
@@ -71,6 +71,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide_assists/src/handlers/convert_to_guarded_return.rs b/crates/ide_assists/src/handlers/convert_to_guarded_return.rs
index 445567b7f9..a7c43413d2 100644
--- a/crates/ide_assists/src/handlers/convert_to_guarded_return.rs
+++ b/crates/ide_assists/src/handlers/convert_to_guarded_return.rs
@@ -97,7 +97,7 @@ pub(crate) fn convert_to_guarded_return(acc: &mut Assists, ctx: &AssistContext)
     let parent_container = parent_block.syntax().parent()?;
 
     let early_expression: ast::Expr = match parent_container.kind() {
-        WHILE_EXPR | LOOP_EXPR => make::expr_continue(None),
+        WHILE_EXPR | LOOP_EXPR => make::expr_continue(),
         FN => make::expr_return(None),
         _ => return None,
     };
diff --git a/crates/ide_assists/src/handlers/convert_while_to_loop.rs b/crates/ide_assists/src/handlers/convert_while_to_loop.rs
index 739097067d..345d0c2063 100644
--- a/crates/ide_assists/src/handlers/convert_while_to_loop.rs
+++ b/crates/ide_assists/src/handlers/convert_while_to_loop.rs
@@ -53,7 +53,7 @@ pub(crate) fn convert_while_to_loop(acc: &mut Assists, ctx: &AssistContext) -> O
             let while_indent_level = IndentLevel::from_node(while_expr.syntax());
 
             let break_block =
-                make::block_expr(once(make::expr_stmt(make::expr_break(None, None)).into()), None)
+                make::block_expr(once(make::expr_stmt(make::expr_break(None)).into()), None)
                     .indent(while_indent_level);
             let block_expr = if is_pattern_cond(while_cond.clone()) {
                 let if_expr = make::expr_if(while_cond, while_body, Some(break_block.into()));
diff --git a/crates/ide_assists/src/handlers/extract_function.rs b/crates/ide_assists/src/handlers/extract_function.rs
index 8352774be4..e48a1cd9ef 100644
--- a/crates/ide_assists/src/handlers/extract_function.rs
+++ b/crates/ide_assists/src/handlers/extract_function.rs
@@ -287,10 +287,10 @@ enum FlowKind {
     Try {
         kind: TryKind,
     },
-    /// Break with label and value (`break 'label $expr;`)
-    Break(Option<ast::Lifetime>, Option<ast::Expr>),
-    /// Continue with label (`continue 'label;`)
-    Continue(Option<ast::Lifetime>),
+    /// Break with value (`break $expr;`)
+    Break(Option<ast::Expr>),
+    /// Continue
+    Continue,
 }
 
 #[derive(Debug, Clone)]
@@ -433,21 +433,21 @@ impl FlowKind {
     fn make_result_handler(&self, expr: Option<ast::Expr>) -> ast::Expr {
         match self {
             FlowKind::Return(_) => make::expr_return(expr),
-            FlowKind::Break(label, _) => make::expr_break(label.clone(), expr),
+            FlowKind::Break(_) => make::expr_break(expr),
             FlowKind::Try { .. } => {
                 stdx::never!("cannot have result handler with try");
                 expr.unwrap_or_else(|| make::expr_return(None))
             }
-            FlowKind::Continue(label) => {
+            FlowKind::Continue => {
                 stdx::always!(expr.is_none(), "continue with value is not possible");
-                make::expr_continue(label.clone())
+                make::expr_continue()
             }
         }
     }
 
     fn expr_ty(&self, ctx: &AssistContext) -> Option<hir::Type> {
         match self {
-            FlowKind::Return(Some(expr)) | FlowKind::Break(_, Some(expr)) => {
+            FlowKind::Return(Some(expr)) | FlowKind::Break(Some(expr)) => {
                 ctx.sema.type_of_expr(expr).map(TypeInfo::adjusted)
             }
             FlowKind::Try { .. } => {
@@ -839,8 +839,8 @@ impl FunctionBody {
                 cov_mark::hit!(external_control_flow_break_and_continue);
                 return None;
             }
-            (None, None, Some(b), None) => Some(FlowKind::Break(b.lifetime(), b.expr())),
-            (None, None, None, Some(c)) => Some(FlowKind::Continue(c.lifetime())),
+            (None, None, Some(b), None) => Some(FlowKind::Break(b.expr())),
+            (None, None, None, Some(_)) => Some(FlowKind::Continue),
             (None, None, None, None) => None,
         };
 
@@ -1185,20 +1185,20 @@ impl FlowHandler {
                 let action = flow_kind.clone();
                 if *ret_ty == FunType::Unit {
                     match flow_kind {
-                        FlowKind::Return(None)
-                        | FlowKind::Break(_, None)
-                        | FlowKind::Continue(_) => FlowHandler::If { action },
-                        FlowKind::Return(_) | FlowKind::Break(_, _) => {
+                        FlowKind::Return(None) | FlowKind::Break(None) | FlowKind::Continue => {
+                            FlowHandler::If { action }
+                        }
+                        FlowKind::Return(_) | FlowKind::Break(_) => {
                             FlowHandler::IfOption { action }
                         }
                         FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() },
                     }
                 } else {
                     match flow_kind {
-                        FlowKind::Return(None)
-                        | FlowKind::Break(_, None)
-                        | FlowKind::Continue(_) => FlowHandler::MatchOption { none: action },
-                        FlowKind::Return(_) | FlowKind::Break(_, _) => {
+                        FlowKind::Return(None) | FlowKind::Break(None) | FlowKind::Continue => {
+                            FlowHandler::MatchOption { none: action }
+                        }
+                        FlowKind::Return(_) | FlowKind::Break(_) => {
                             FlowHandler::MatchResult { err: action }
                         }
                         FlowKind::Try { kind } => FlowHandler::Try { kind: kind.clone() },
@@ -3404,76 +3404,6 @@ fn $0fun_name(n: i32) -> ControlFlow<()> {
         );
     }
 
-    #[test]
-    fn break_loop_nested_labeled() {
-        check_assist(
-            extract_function,
-            r#"
-//- minicore: try
-fn foo() {
-    'bar: loop {
-        loop {
-            $0break 'bar;$0
-        }
-    }
-}
-"#,
-            r#"
-use core::ops::ControlFlow;
-
-fn foo() {
-    'bar: loop {
-        loop {
-            if let ControlFlow::Break(_) = fun_name() {
-                break 'bar;
-            }
-        }
-    }
-}
-
-fn $0fun_name() -> ControlFlow<()> {
-    return ControlFlow::Break(());
-    ControlFlow::Continue(())
-}
-"#,
-        );
-    }
-
-    #[test]
-    fn continue_loop_nested_labeled() {
-        check_assist(
-            extract_function,
-            r#"
-//- minicore: try
-fn foo() {
-    'bar: loop {
-        loop {
-            $0continue 'bar;$0
-        }
-    }
-}
-"#,
-            r#"
-use core::ops::ControlFlow;
-
-fn foo() {
-    'bar: loop {
-        loop {
-            if let ControlFlow::Break(_) = fun_name() {
-                continue 'bar;
-            }
-        }
-    }
-}
-
-fn $0fun_name() -> ControlFlow<()> {
-    return ControlFlow::Break(());
-    ControlFlow::Continue(())
-}
-"#,
-        );
-    }
-
     #[test]
     fn return_from_nested_loop() {
         check_assist(
@@ -3678,46 +3608,6 @@ fn $0fun_name() -> Option<i32> {
         );
     }
 
-    #[test]
-    fn break_with_value_and_label() {
-        check_assist(
-            extract_function,
-            r#"
-fn foo() -> i32 {
-    'bar: loop {
-        let n = 1;
-        $0let k = 1;
-        if k == 42 {
-            break 'bar 4;
-        }
-        let m = k + 1;$0
-        let h = 1;
-    }
-}
-"#,
-            r#"
-fn foo() -> i32 {
-    'bar: loop {
-        let n = 1;
-        if let Some(value) = fun_name() {
-            break 'bar value;
-        }
-        let h = 1;
-    }
-}
-
-fn $0fun_name() -> Option<i32> {
-    let k = 1;
-    if k == 42 {
-        return Some(4);
-    }
-    let m = k + 1;
-    None
-}
-"#,
-        );
-    }
-
     #[test]
     fn break_with_value_and_return() {
         check_assist(
diff --git a/crates/ide_assists/src/handlers/generate_enum_is_method.rs b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
index 863ada79ba..c2a6e438b1 100644
--- a/crates/ide_assists/src/handlers/generate_enum_is_method.rs
+++ b/crates/ide_assists/src/handlers/generate_enum_is_method.rs
@@ -30,7 +30,6 @@ use crate::{
 //     /// Returns `true` if the version is [`Minor`].
 //     ///
 //     /// [`Minor`]: Version::Minor
-//     #[must_use]
 //     fn is_minor(&self) -> bool {
 //         matches!(self, Self::Minor)
 //     }
@@ -64,7 +63,6 @@ pub(crate) fn generate_enum_is_method(acc: &mut Assists, ctx: &AssistContext) ->
                 "    /// Returns `true` if the {} is [`{variant}`].
     ///
     /// [`{variant}`]: {}::{variant}
-    #[must_use]
     {}fn {}(&self) -> bool {{
         matches!(self, Self::{variant}{})
     }}",
@@ -107,7 +105,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Minor`].
     ///
     /// [`Minor`]: Variant::Minor
-    #[must_use]
     fn is_minor(&self) -> bool {
         matches!(self, Self::Minor)
     }
@@ -154,7 +151,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Minor`].
     ///
     /// [`Minor`]: Variant::Minor
-    #[must_use]
     fn is_minor(&self) -> bool {
         matches!(self, Self::Minor(..))
     }
@@ -182,7 +178,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Minor`].
     ///
     /// [`Minor`]: Variant::Minor
-    #[must_use]
     fn is_minor(&self) -> bool {
         matches!(self, Self::Minor { .. })
     }
@@ -202,7 +197,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Undefined`].
     ///
     /// [`Undefined`]: Variant::Undefined
-    #[must_use]
     fn is_undefined(&self) -> bool {
         matches!(self, Self::Undefined)
     }
@@ -230,7 +224,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Minor`].
     ///
     /// [`Minor`]: Variant::Minor
-    #[must_use]
     pub(crate) fn is_minor(&self) -> bool {
         matches!(self, Self::Minor)
     }
@@ -253,7 +246,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Minor`].
     ///
     /// [`Minor`]: Variant::Minor
-    #[must_use]
     fn is_minor(&self) -> bool {
         matches!(self, Self::Minor)
     }
@@ -268,7 +260,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Minor`].
     ///
     /// [`Minor`]: Variant::Minor
-    #[must_use]
     fn is_minor(&self) -> bool {
         matches!(self, Self::Minor)
     }
@@ -276,7 +267,6 @@ impl Variant {
     /// Returns `true` if the variant is [`Major`].
     ///
     /// [`Major`]: Variant::Major
-    #[must_use]
     fn is_major(&self) -> bool {
         matches!(self, Self::Major)
     }
@@ -304,7 +294,6 @@ impl GeneratorState {
     /// Returns `true` if the generator state is [`Complete`].
     ///
     /// [`Complete`]: GeneratorState::Complete
-    #[must_use]
     fn is_complete(&self) -> bool {
         matches!(self, Self::Complete)
     }
diff --git a/crates/ide_assists/src/handlers/generate_getter.rs b/crates/ide_assists/src/handlers/generate_getter.rs
index 2e81dd13f4..c6e979c072 100644
--- a/crates/ide_assists/src/handlers/generate_getter.rs
+++ b/crates/ide_assists/src/handlers/generate_getter.rs
@@ -39,7 +39,6 @@ use crate::{
 //
 // impl Person {
 //     /// Get a reference to the person's name.
-//     #[must_use]
 //     fn $0name(&self) -> &str {
 //         self.name.as_ref()
 //     }
@@ -66,7 +65,6 @@ pub(crate) fn generate_getter(acc: &mut Assists, ctx: &AssistContext) -> Option<
 //
 // impl Person {
 //     /// Get a mutable reference to the person's name.
-//     #[must_use]
 //     fn $0name_mut(&mut self) -> &mut String {
 //         &mut self.name
 //     }
@@ -145,7 +143,6 @@ pub(crate) fn generate_getter_impl(
             format_to!(
                 buf,
                 "    /// Get {}the {}'s {}.
-    #[must_use]
     {}fn {}(&{}self) -> {} {{
         {}
     }}",
@@ -198,7 +195,6 @@ struct Context {
 
 impl Context {
     /// Get a reference to the context's data.
-    #[must_use]
     fn $0data(&self) -> &Data {
         &self.data
     }
@@ -220,7 +216,6 @@ struct Context {
 
 impl Context {
     /// Get a mutable reference to the context's data.
-    #[must_use]
     fn $0data_mut(&mut self) -> &mut Data {
         &mut self.data
     }
@@ -254,7 +249,6 @@ struct Context {
 }
 
 impl Context {
-    #[must_use]
     fn data_mut(&mut self) -> &mut Data {
         &mut self.data
     }
@@ -279,7 +273,6 @@ pub(crate) struct Context {
 
 impl Context {
     /// Get a reference to the context's data.
-    #[must_use]
     pub(crate) fn $0data(&self) -> &Data {
         &self.data
     }
@@ -300,7 +293,6 @@ struct Context {
 
 impl Context {
     /// Get a reference to the context's data.
-    #[must_use]
     fn data(&self) -> &Data {
         &self.data
     }
@@ -314,13 +306,11 @@ struct Context {
 
 impl Context {
     /// Get a reference to the context's data.
-    #[must_use]
     fn data(&self) -> &Data {
         &self.data
     }
 
     /// Get a reference to the context's count.
-    #[must_use]
     fn $0count(&self) -> &usize {
         &self.count
     }
@@ -347,7 +337,6 @@ struct S { foo: String }
 
 impl S {
     /// Get a reference to the s's foo.
-    #[must_use]
     fn $0foo(&self) -> &String {
         &self.foo
     }
@@ -372,7 +361,6 @@ struct S { foo: bool }
 
 impl S {
     /// Get the s's foo.
-    #[must_use]
     fn $0foo(&self) -> bool {
         self.foo
     }
@@ -406,7 +394,6 @@ struct S { foo: String }
 
 impl S {
     /// Get a reference to the s's foo.
-    #[must_use]
     fn $0foo(&self) -> &str {
         self.foo.as_ref()
     }
@@ -444,7 +431,6 @@ struct S { foo: Box<Sweets> }
 
 impl S {
     /// Get a reference to the s's foo.
-    #[must_use]
     fn $0foo(&self) -> &Sweets {
         self.foo.as_ref()
     }
@@ -478,7 +464,6 @@ struct S { foo: Vec<()> }
 
 impl S {
     /// Get a reference to the s's foo.
-    #[must_use]
     fn $0foo(&self) -> &[()] {
         self.foo.as_ref()
     }
@@ -502,7 +487,6 @@ struct S { foo: Option<Failure> }
 
 impl S {
     /// Get a reference to the s's foo.
-    #[must_use]
     fn $0foo(&self) -> Option<&Failure> {
         self.foo.as_ref()
     }
@@ -526,7 +510,6 @@ struct Context {
 
 impl Context {
     /// Get a reference to the context's data.
-    #[must_use]
     fn $0data(&self) -> Result<&bool, &i32> {
         self.data.as_ref()
     }
diff --git a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
index bd7c85c443..db0cfbe2ec 100644
--- a/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
+++ b/crates/ide_assists/src/handlers/generate_is_empty_from_len.rs
@@ -17,7 +17,6 @@ use crate::{
 // struct MyStruct { data: Vec<String> }
 //
 // impl MyStruct {
-//     #[must_use]
 //     p$0ub fn len(&self) -> usize {
 //         self.data.len()
 //     }
@@ -28,12 +27,10 @@ use crate::{
 // struct MyStruct { data: Vec<String> }
 //
 // impl MyStruct {
-//     #[must_use]
 //     pub fn len(&self) -> usize {
 //         self.data.len()
 //     }
 //
-//     #[must_use]
 //     pub fn is_empty(&self) -> bool {
 //         self.len() == 0
 //     }
@@ -75,7 +72,6 @@ pub(crate) fn generate_is_empty_from_len(acc: &mut Assists, ctx: &AssistContext)
         |builder| {
             let code = r#"
 
-    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }"#
@@ -133,7 +129,6 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     p$0ub fn len(&self, _i: bool) -> usize {
         self.data.len()
     }
@@ -151,12 +146,10 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     p$0ub fn len(&self) -> usize {
         self.data.len()
     }
 
-    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -174,7 +167,6 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     p$0ub fn len(&self) -> u32 {
         self.data.len()
     }
@@ -191,7 +183,6 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     p$0ub fn len(&self) -> usize {
         self.data.len()
     }
@@ -201,12 +192,10 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     pub fn len(&self) -> usize {
         self.data.len()
     }
 
-    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -223,12 +212,10 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     pub fn new() -> Self {
         Self { data: 0 }
     }
 
-    #[must_use]
     p$0ub fn len(&self) -> usize {
         self.data.len()
     }
@@ -242,17 +229,14 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     pub fn new() -> Self {
         Self { data: 0 }
     }
 
-    #[must_use]
     pub fn len(&self) -> usize {
         self.data.len()
     }
 
-    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -273,14 +257,12 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     p$0ub fn len(&self) -> usize {
         self.data.len()
     }
 }
 
 impl MyStruct {
-    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
diff --git a/crates/ide_assists/src/handlers/generate_new.rs b/crates/ide_assists/src/handlers/generate_new.rs
index eb9f1d04e1..6a1f710f6d 100644
--- a/crates/ide_assists/src/handlers/generate_new.rs
+++ b/crates/ide_assists/src/handlers/generate_new.rs
@@ -23,7 +23,6 @@ use crate::{
 // }
 //
 // impl<T: Clone> Ctx<T> {
-//     #[must_use]
 //     fn $0new(data: T) -> Self { Self { data } }
 // }
 // ```
@@ -55,13 +54,7 @@ pub(crate) fn generate_new(acc: &mut Assists, ctx: &AssistContext) -> Option<()>
             .format(", ");
         let fields = field_list.fields().filter_map(|f| f.name()).format(", ");
 
-        format_to!(
-            buf,
-            "    #[must_use]\n    {}fn new({}) -> Self {{ Self {{ {} }} }}",
-            vis,
-            params,
-            fields
-        );
+        format_to!(buf, "    {}fn new({}) -> Self {{ Self {{ {} }} }}", vis, params, fields);
 
         let start_offset = impl_def
             .and_then(|impl_def| find_impl_block_start(impl_def, &mut buf))
@@ -97,7 +90,6 @@ struct Foo {$0}
 struct Foo {}
 
 impl Foo {
-    #[must_use]
     fn $0new() -> Self { Self {  } }
 }
 "#,
@@ -111,7 +103,6 @@ struct Foo<T: Clone> {$0}
 struct Foo<T: Clone> {}
 
 impl<T: Clone> Foo<T> {
-    #[must_use]
     fn $0new() -> Self { Self {  } }
 }
 "#,
@@ -125,7 +116,6 @@ struct Foo<'a, T: Foo<'a>> {$0}
 struct Foo<'a, T: Foo<'a>> {}
 
 impl<'a, T: Foo<'a>> Foo<'a, T> {
-    #[must_use]
     fn $0new() -> Self { Self {  } }
 }
 "#,
@@ -139,7 +129,6 @@ struct Foo { baz: String $0}
 struct Foo { baz: String }
 
 impl Foo {
-    #[must_use]
     fn $0new(baz: String) -> Self { Self { baz } }
 }
 "#,
@@ -153,7 +142,6 @@ struct Foo { baz: String, qux: Vec<i32> $0}
 struct Foo { baz: String, qux: Vec<i32> }
 
 impl Foo {
-    #[must_use]
     fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
 }
 "#,
@@ -171,7 +159,6 @@ struct Foo { pub baz: String, pub qux: Vec<i32> $0}
 struct Foo { pub baz: String, pub qux: Vec<i32> }
 
 impl Foo {
-    #[must_use]
     fn $0new(baz: String, qux: Vec<i32>) -> Self { Self { baz, qux } }
 }
 "#,
@@ -191,7 +178,6 @@ impl Foo {}
 struct Foo {}
 
 impl Foo {
-    #[must_use]
     fn $0new() -> Self { Self {  } }
 }
 "#,
@@ -209,7 +195,6 @@ impl Foo {
 struct Foo {}
 
 impl Foo {
-    #[must_use]
     fn $0new() -> Self { Self {  } }
 
     fn qux(&self) {}
@@ -233,7 +218,6 @@ impl Foo {
 struct Foo {}
 
 impl Foo {
-    #[must_use]
     fn $0new() -> Self { Self {  } }
 
     fn qux(&self) {}
@@ -256,7 +240,6 @@ pub struct Foo {$0}
 pub struct Foo {}
 
 impl Foo {
-    #[must_use]
     pub fn $0new() -> Self { Self {  } }
 }
 "#,
@@ -270,7 +253,6 @@ pub(crate) struct Foo {$0}
 pub(crate) struct Foo {}
 
 impl Foo {
-    #[must_use]
     pub(crate) fn $0new() -> Self { Self {  } }
 }
 "#,
@@ -366,7 +348,6 @@ pub struct Source<T> {
 }
 
 impl<T> Source<T> {
-    #[must_use]
     pub fn $0new(file_id: HirFileId, ast: T) -> Self { Self { file_id, ast } }
 
     pub fn map<F: FnOnce(T) -> U, U>(self, f: F) -> Source<U> {
diff --git a/crates/ide_completion/src/completions/pattern.rs b/crates/ide_completion/src/completions/pattern.rs
index 0d3a49c668..6c17da07d6 100644
--- a/crates/ide_completion/src/completions/pattern.rs
+++ b/crates/ide_completion/src/completions/pattern.rs
@@ -137,38 +137,25 @@ fn pattern_path_completion(
                         }
                     }
                 }
-                res @ (hir::PathResolution::TypeParam(_)
-                | hir::PathResolution::SelfType(_)
-                | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(_)))
-                | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(_)))
-                | hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(_)))
-                | hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))) => {
+                hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
+                    cov_mark::hit!(enum_plain_qualified_use_tree);
+                    e.variants(ctx.db)
+                        .into_iter()
+                        .for_each(|variant| acc.add_enum_variant(ctx, variant, None));
+                }
+                res @ (hir::PathResolution::TypeParam(_) | hir::PathResolution::SelfType(_)) => {
                     let ty = match res {
                         hir::PathResolution::TypeParam(param) => param.ty(ctx.db),
                         hir::PathResolution::SelfType(impl_def) => impl_def.self_ty(ctx.db),
-                        hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Struct(s))) => {
-                            s.ty(ctx.db)
-                        }
-                        hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Enum(e))) => {
-                            cov_mark::hit!(enum_plain_qualified_use_tree);
-                            e.variants(ctx.db)
-                                .into_iter()
-                                .for_each(|variant| acc.add_enum_variant(ctx, variant, None));
-                            e.ty(ctx.db)
-                        }
-                        hir::PathResolution::Def(hir::ModuleDef::Adt(hir::Adt::Union(u))) => {
-                            u.ty(ctx.db)
-                        }
-                        hir::PathResolution::Def(hir::ModuleDef::BuiltinType(ty)) => {
-                            let module = match ctx.module {
-                                Some(m) => m,
-                                None => return,
-                            };
-                            ty.ty(ctx.db, module)
-                        }
                         _ => return,
                     };
 
+                    if let Some(hir::Adt::Enum(e)) = ty.as_adt() {
+                        e.variants(ctx.db)
+                            .into_iter()
+                            .for_each(|variant| acc.add_enum_variant(ctx, variant, None));
+                    }
+
                     let traits_in_scope = ctx.scope.visible_traits();
                     let mut seen = FxHashSet::default();
                     ty.iterate_path_candidates(
@@ -178,19 +165,12 @@ fn pattern_path_completion(
                         ctx.module,
                         None,
                         |item| {
-                            match item {
-                                AssocItem::TypeAlias(ta) => {
-                                    // We might iterate candidates of a trait multiple times here, so deduplicate them.
-                                    if seen.insert(item) {
-                                        acc.add_type_alias(ctx, ta);
-                                    }
-                                }
-                                AssocItem::Const(c) => {
-                                    if seen.insert(item) {
-                                        acc.add_const(ctx, c);
-                                    }
+                            // Note associated consts cannot be referenced in patterns
+                            if let AssocItem::TypeAlias(ta) = item {
+                                // We might iterate candidates of a trait multiple times here, so deduplicate them.
+                                if seen.insert(item) {
+                                    acc.add_type_alias(ctx, ta);
                                 }
-                                _ => {}
                             }
                             None::<()>
                         },
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index 26b51739cf..c71a213c40 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -35,5 +35,5 @@ limit = { path = "../limit", version = "0.0.0" }
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
-xshell = "0.2.1"
+xshell = "0.2.0"
 expect-test = "1.2.0-pre.1"
diff --git a/crates/ide_db/src/active_parameter.rs b/crates/ide_db/src/active_parameter.rs
index 67b819c5a5..47bd7aa979 100644
--- a/crates/ide_db/src/active_parameter.rs
+++ b/crates/ide_db/src/active_parameter.rs
@@ -68,53 +68,3 @@ pub fn callable_for_token(
     };
     Some((callable, active_param))
 }
-
-pub fn generics_for_token(
-    sema: &Semantics<RootDatabase>,
-    token: SyntaxToken,
-) -> Option<(hir::GenericDef, usize)> {
-    let parent = token.parent()?;
-    let arg_list = parent
-        .ancestors()
-        .filter_map(ast::GenericArgList::cast)
-        .find(|list| list.syntax().text_range().contains(token.text_range().start()))?;
-
-    let active_param = arg_list
-        .generic_args()
-        .take_while(|arg| arg.syntax().text_range().end() <= token.text_range().start())
-        .count();
-
-    if let Some(path) = arg_list.syntax().ancestors().find_map(ast::Path::cast) {
-        let res = sema.resolve_path(&path)?;
-        let generic_def: hir::GenericDef = match res {
-            hir::PathResolution::Def(hir::ModuleDef::Adt(it)) => it.into(),
-            hir::PathResolution::Def(hir::ModuleDef::Function(it)) => it.into(),
-            hir::PathResolution::Def(hir::ModuleDef::Trait(it)) => it.into(),
-            hir::PathResolution::Def(hir::ModuleDef::TypeAlias(it)) => it.into(),
-            hir::PathResolution::Def(hir::ModuleDef::Variant(it)) => it.into(),
-            hir::PathResolution::Def(hir::ModuleDef::BuiltinType(_))
-            | hir::PathResolution::Def(hir::ModuleDef::Const(_))
-            | hir::PathResolution::Def(hir::ModuleDef::Macro(_))
-            | hir::PathResolution::Def(hir::ModuleDef::Module(_))
-            | hir::PathResolution::Def(hir::ModuleDef::Static(_)) => return None,
-            hir::PathResolution::AssocItem(hir::AssocItem::Function(it)) => it.into(),
-            hir::PathResolution::AssocItem(hir::AssocItem::TypeAlias(it)) => it.into(),
-            hir::PathResolution::AssocItem(hir::AssocItem::Const(_)) => return None,
-            hir::PathResolution::BuiltinAttr(_)
-            | hir::PathResolution::ToolModule(_)
-            | hir::PathResolution::Local(_)
-            | hir::PathResolution::TypeParam(_)
-            | hir::PathResolution::ConstParam(_)
-            | hir::PathResolution::SelfType(_) => return None,
-        };
-
-        Some((generic_def, active_param))
-    } else if let Some(method_call) = arg_list.syntax().parent().and_then(ast::MethodCallExpr::cast)
-    {
-        // recv.method::<$0>()
-        let method = sema.resolve_method_call(&method_call)?;
-        Some((method.into(), active_param))
-    } else {
-        None
-    }
-}
diff --git a/crates/ide_db/src/syntax_helpers/node_ext.rs b/crates/ide_db/src/syntax_helpers/node_ext.rs
index c0f0529966..3d72045838 100644
--- a/crates/ide_db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide_db/src/syntax_helpers/node_ext.rs
@@ -15,6 +15,13 @@ pub fn expr_as_name_ref(expr: &ast::Expr) -> Option<ast::NameRef> {
     }
 }
 
+pub fn full_path_of_name_ref(name_ref: &ast::NameRef) -> Option<ast::Path> {
+    let mut ancestors = name_ref.syntax().ancestors();
+    let _ = ancestors.next()?; // skip self
+    let _ = ancestors.next().filter(|it| ast::PathSegment::can_cast(it.kind()))?; // skip self
+    ancestors.take_while(|it| ast::Path::can_cast(it.kind())).last().and_then(ast::Path::cast)
+}
+
 pub fn block_as_lone_tail(block: &ast::BlockExpr) -> Option<ast::Expr> {
     block.statements().next().is_none().then(|| block.tail_expr()).flatten()
 }
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 079e56c9fa..68d728b41f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -75,7 +75,7 @@ jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = tr
 [dev-dependencies]
 expect-test = "1.2.0-pre.1"
 jod-thread = "0.1.0"
-xshell = "0.2.1"
+xshell = "0.2.0"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/rust-analyzer/src/caps.rs b/crates/rust-analyzer/src/caps.rs
index d83af2a48a..dc6cf61f79 100644
--- a/crates/rust-analyzer/src/caps.rs
+++ b/crates/rust-analyzer/src/caps.rs
@@ -34,7 +34,7 @@ pub fn server_capabilities(config: &Config) -> ServerCapabilities {
             work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         }),
         signature_help_provider: Some(SignatureHelpOptions {
-            trigger_characters: Some(vec!["(".to_string(), ",".to_string(), "<".to_string()]),
+            trigger_characters: Some(vec!["(".to_string(), ",".to_string()]),
             retrigger_characters: None,
             work_done_progress_options: WorkDoneProgressOptions { work_done_progress: None },
         }),
diff --git a/crates/rust-analyzer/src/handlers.rs b/crates/rust-analyzer/src/handlers.rs
index 8f91f64a69..e63b6f490b 100644
--- a/crates/rust-analyzer/src/handlers.rs
+++ b/crates/rust-analyzer/src/handlers.rs
@@ -895,12 +895,13 @@ pub(crate) fn handle_signature_help(
 ) -> Result<Option<lsp_types::SignatureHelp>> {
     let _p = profile::span("handle_signature_help");
     let position = from_proto::file_position(&snap, params.text_document_position_params)?;
-    let help = match snap.analysis.signature_help(position)? {
+    let call_info = match snap.analysis.call_info(position)? {
         Some(it) => it,
         None => return Ok(None),
     };
     let concise = !snap.config.call_info_full();
-    let res = to_proto::signature_help(help, concise, snap.config.signature_help_label_offsets());
+    let res =
+        to_proto::signature_help(call_info, concise, snap.config.signature_help_label_offsets());
     Ok(Some(res))
 }
 
diff --git a/crates/rust-analyzer/src/to_proto.rs b/crates/rust-analyzer/src/to_proto.rs
index 7c5785bfb8..b9182c4bc1 100644
--- a/crates/rust-analyzer/src/to_proto.rs
+++ b/crates/rust-analyzer/src/to_proto.rs
@@ -6,11 +6,11 @@ use std::{
 };
 
 use ide::{
-    Annotation, AnnotationKind, Assist, AssistKind, Cancellable, CompletionItem,
+    Annotation, AnnotationKind, Assist, AssistKind, CallInfo, Cancellable, CompletionItem,
     CompletionItemKind, CompletionRelevance, Documentation, FileId, FileRange, FileSystemEdit,
     Fold, FoldKind, Highlight, HlMod, HlOperator, HlPunct, HlRange, HlTag, Indel, InlayHint,
     InlayKind, Markup, NavigationTarget, ReferenceCategory, RenameError, Runnable, Severity,
-    SignatureHelp, SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
+    SourceChange, StructureNodeKind, SymbolKind, TextEdit, TextRange, TextSize,
 };
 use itertools::Itertools;
 use serde_json::to_value;
@@ -336,7 +336,7 @@ fn completion_item(
 }
 
 pub(crate) fn signature_help(
-    call_info: SignatureHelp,
+    call_info: CallInfo,
     concise: bool,
     label_offsets: bool,
 ) -> lsp_types::SignatureHelp {
diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml
index 57e183af3f..10587d913d 100644
--- a/crates/sourcegen/Cargo.toml
+++ b/crates/sourcegen/Cargo.toml
@@ -10,4 +10,4 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-xshell = "0.2.1"
+xshell = "0.2.0"
diff --git a/crates/syntax/src/ast/make.rs b/crates/syntax/src/ast/make.rs
index d11d658a27..a69a77c7ee 100644
--- a/crates/syntax/src/ast/make.rs
+++ b/crates/syntax/src/ast/make.rs
@@ -368,28 +368,18 @@ pub fn expr_empty_block() -> ast::Expr {
 pub fn expr_path(path: ast::Path) -> ast::Expr {
     expr_from_text(&path.to_string())
 }
-pub fn expr_continue(label: Option<ast::Lifetime>) -> ast::Expr {
-    match label {
-        Some(label) => expr_from_text(&format!("continue {}", label)),
-        None => expr_from_text("continue"),
-    }
+pub fn expr_continue() -> ast::Expr {
+    expr_from_text("continue")
 }
 // Consider `op: SyntaxKind` instead for nicer syntax at the call-site?
 pub fn expr_bin_op(lhs: ast::Expr, op: ast::BinaryOp, rhs: ast::Expr) -> ast::Expr {
     expr_from_text(&format!("{} {} {}", lhs, op, rhs))
 }
-pub fn expr_break(label: Option<ast::Lifetime>, expr: Option<ast::Expr>) -> ast::Expr {
-    let mut s = String::from("break");
-
-    if let Some(label) = label {
-        format_to!(s, " {}", label);
-    }
-
-    if let Some(expr) = expr {
-        format_to!(s, " {}", expr);
+pub fn expr_break(expr: Option<ast::Expr>) -> ast::Expr {
+    match expr {
+        Some(expr) => expr_from_text(&format!("break {}", expr)),
+        None => expr_from_text("break"),
     }
-
-    expr_from_text(&s)
 }
 pub fn expr_return(expr: Option<ast::Expr>) -> ast::Expr {
     match expr {
diff --git a/crates/vfs-notify/Cargo.toml b/crates/vfs-notify/Cargo.toml
index 10addab1e4..a670852d63 100644
--- a/crates/vfs-notify/Cargo.toml
+++ b/crates/vfs-notify/Cargo.toml
@@ -14,7 +14,7 @@ tracing = "0.1"
 jod-thread = "0.1.0"
 walkdir = "2.3.1"
 crossbeam-channel = "0.5.0"
-notify = "=5.0.0-pre.14"
+notify = "=5.0.0-pre.13"
 
 vfs = { path = "../vfs", version = "0.0.0" }
 paths = { path = "../paths", version = "0.0.0" }
diff --git a/editors/code/package.json b/editors/code/package.json
index 911fa2bd76..18d4b39b83 100644
--- a/editors/code/package.json
+++ b/editors/code/package.json
@@ -184,6 +184,11 @@
                 "title": "Restart server",
                 "category": "Rust Analyzer"
             },
+            {
+                "command": "rust-analyzer.updateGithubToken",
+                "title": "Update Github API token",
+                "category": "Rust Analyzer"
+            },
             {
                 "command": "rust-analyzer.onEnter",
                 "title": "Enhanced enter key",
@@ -1452,6 +1457,10 @@
                     "command": "rust-analyzer.reload",
                     "when": "inRustProject"
                 },
+                {
+                    "command": "rust-analyzer.updateGithubToken",
+                    "when": "inRustProject"
+                },
                 {
                     "command": "rust-analyzer.onEnter",
                     "when": "inRustProject"
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index de6a102427..d9adf88c02 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -10,6 +10,6 @@ rust-version = "1.57"
 anyhow = "1.0.26"
 flate2 = "1.0"
 write-json = "0.1.0"
-xshell = "0.2.1"
+xshell = "0.2.0"
 xflags = "0.2.1"
 # Avoid adding more dependencies to this crate
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
index 3da7419582..aa700d715d 100644
--- a/xtask/src/metrics.rs
+++ b/xtask/src/metrics.rs
@@ -17,7 +17,7 @@ impl flags::Metrics {
     pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
         let mut metrics = Metrics::new(sh)?;
         if !self.dry_run {
-            sh.remove_path("./target/release")?;
+            let _ = sh.remove_path("./target/release");
         }
         if !Path::new("./target/rustc-perf").exists() {
             sh.create_dir("./target/rustc-perf")?;
@@ -51,14 +51,10 @@ impl flags::Metrics {
                 "git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git"
             )
             .run()?;
-
-            {
-                let mut file =
-                    fs::File::options().append(true).open("target/metrics/metrics.json")?;
-                writeln!(file, "{}", metrics.json())?;
-            }
-
             let _d = sh.push_dir("metrics");
+
+            let mut file = fs::File::options().append(true).open("metrics.json")?;
+            writeln!(file, "{}", metrics.json())?;
             cmd!(sh, "git add .").run()?;
             cmd!(sh, "git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
                 .run()?;


Test patch:
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 56b8db1319..9700b388aa 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -925,6 +925,7 @@ fn test() { S2.into(); }
 
 #[test]
 fn method_resolution_overloaded_method() {
+    cov_mark::check!(impl_self_type_match_without_receiver);
     check_types(
         r#"
 struct Wrapper<T>(T);
@@ -953,33 +954,6 @@ fn main() {
     );
 }
 
-#[test]
-fn method_resolution_overloaded_const() {
-    cov_mark::check!(const_candidate_self_type_mismatch);
-    check_types(
-        r#"
-struct Wrapper<T>(T);
-struct Foo<T>(T);
-struct Bar<T>(T);
-
-impl<T> Wrapper<Foo<T>> {
-    pub const VALUE: Foo<T>;
-}
-
-impl<T> Wrapper<Bar<T>> {
-    pub const VALUE: Bar<T>;
-}
-
-fn main() {
-    let a = Wrapper::<Foo<f32>>::VALUE;
-    let b = Wrapper::<Bar<f32>>::VALUE;
-    (a, b);
-  //^^^^^^ (Foo<f32>, Bar<f32>)
-}
-"#,
-    );
-}
-
 #[test]
 fn method_resolution_encountering_fn_type() {
     check_types(
@@ -1283,37 +1257,6 @@ mod b {
     )
 }
 
-#[test]
-fn trait_vs_private_inherent_const() {
-    cov_mark::check!(const_candidate_not_visible);
-    check(
-        r#"
-mod a {
-    pub struct Foo;
-    impl Foo {
-        const VALUE: u32 = 2;
-    }
-    pub trait Trait {
-        const VALUE: usize;
-    }
-    impl Trait for Foo {
-        const VALUE: usize = 3;
-    }
-
-    fn foo() {
-        let x = Foo::VALUE;
-            //  ^^^^^^^^^^ type: u32
-    }
-}
-use a::Trait;
-fn foo() {
-    let x = a::Foo::VALUE;
-         // ^^^^^^^^^^^^^ type: usize
-}
-"#,
-    )
-}
-
 #[test]
 fn trait_impl_in_unnamed_const() {
     check_types(
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 7a7470fd35..63faecbfaf 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1454,26 +1454,3 @@ fn regression_11688_1() {
         "#,
     );
 }
-
-#[test]
-fn regression_11688_2() {
-    check_types(
-        r#"
-        union MaybeUninit<T> {
-            uninit: (),
-            value: T,
-        }
-
-        impl<T> MaybeUninit<T> {
-            fn uninit_array<const LEN: usize>() -> [Self; LEN] {
-                loop {}
-            }
-        }
-
-        fn main() {
-            let x = MaybeUninit::<i32>::uninit_array::<1>();
-              //^ [MaybeUninit<i32>; 1]
-        }
-        "#,
-    );
-}
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index a82b8cb466..5daffb2c5e 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3609,40 +3609,3 @@ fn f<F: Foo>() {
         "#]],
     );
 }
-
-#[test]
-fn dyn_map() {
-    check_types(
-        r#"
-pub struct Key<K, V, P = (K, V)> {}
-
-pub trait Policy {
-    type K;
-    type V;
-}
-
-impl<K, V> Policy for (K, V) {
-    type K = K;
-    type V = V;
-}
-
-pub struct KeyMap<KEY> {}
-
-impl<P: Policy> KeyMap<Key<P::K, P::V, P>> {
-    pub fn get(&self, key: &P::K) -> P::V {
-        loop {}
-    }
-}
-
-struct Fn {}
-struct FunctionId {}
-
-fn test() {
-    let key_map: &KeyMap<Key<Fn, FunctionId>> = loop {};
-    let key;
-    let result = key_map.get(key);
-      //^^^^^^ FunctionId
-}
-"#,
-    )
-}
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
index b035e786d3..e07fd3925c 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_assoc_functions.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
index 9fe2b50cde..1a43988147 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_attributes.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html b/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
index 37c8b56682..6704e5e8d5 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_crate_root.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
index 3e20b2f351..5d66f832da 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_default_library.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index 96044751b8..d9126421cd 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
index 3208770d7f..87b9da46e2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_extern_crate.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
index 86ed8dbd77..d5c930e049 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_general.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
index 023e791f8b..ced7d22f03 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_injection.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
index 145bba2a06..278e0d84ee 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_keywords.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
index 9e36b56d28..2d85fc8c92 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_lifetimes.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
index c3f71d443f..71add7e495 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_macros.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
index 46220993e6..2369071ae2 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_operators.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html b/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
index e0287f1185..bff35c897e 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_rainbow.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
index 3715164bbf..e26c017f95 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_strings.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
index 25bfcb6482..113463aa7a 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_unsafe.html
@@ -19,6 +19,7 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 .operator.unsafe    { color: #BC8383; }
 .mutable.unsafe     { color: #BC8383; text-decoration: underline; }
 .keyword.unsafe     { color: #BC8383; font-weight: bold; }
+.macro.unsafe       { color: #BC8383; }
 .parameter          { color: #94BFF3; }
 .text               { color: #DCDCCC; }
 .type               { color: #7CB8BB; }
@@ -41,7 +42,17 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 
 .unresolved_reference { color: #FC5555; text-decoration: wavy underline; }
 </style>
-<pre><code><span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
+<pre><code><span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">id</span> <span class="brace">{</span>
+    <span class="parenthesis">(</span><span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="colon">:</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
+        <span class="punctuation">$</span><span class="parenthesis">(</span><span class="punctuation">$</span>tt<span class="parenthesis">)</span><span class="punctuation">*</span>
+    <span class="brace">}</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+<span class="keyword">macro_rules</span><span class="punctuation">!</span> <span class="macro declaration">unsafe_deref</span> <span class="brace">{</span>
+    <span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="operator">=</span><span class="angle">&gt;</span> <span class="brace">{</span>
+        <span class="punctuation">*</span><span class="parenthesis">(</span><span class="operator">&</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="keyword">as</span> <span class="punctuation">*</span><span class="keyword">const</span> <span class="parenthesis">(</span><span class="parenthesis">)</span><span class="parenthesis">)</span>
+    <span class="brace">}</span><span class="semicolon">;</span>
+<span class="brace">}</span>
+<span class="keyword">static</span> <span class="keyword">mut</span> <span class="static declaration mutable unsafe">MUT_GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
 <span class="keyword">static</span> <span class="static declaration">GLOBAL</span><span class="colon">:</span> <span class="struct">Struct</span> <span class="operator">=</span> <span class="struct">Struct</span> <span class="brace">{</span> <span class="field">field</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
 <span class="keyword unsafe">unsafe</span> <span class="keyword">fn</span> <span class="function declaration unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span><span class="brace">}</span>
 
@@ -77,7 +88,15 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
 <span class="keyword">fn</span> <span class="function declaration">main</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">{</span>
     <span class="keyword">let</span> <span class="variable declaration">x</span> <span class="operator">=</span> <span class="operator">&</span><span class="numeric_literal">5</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="punctuation">_</span> <span class="keyword">as</span> <span class="keyword">*</span><span class="keyword">const</span> <span class="builtin_type">usize</span><span class="semicolon">;</span>
     <span class="keyword">let</span> <span class="variable declaration">u</span> <span class="operator">=</span> <span class="union">Union</span> <span class="brace">{</span> <span class="field">b</span><span class="colon">:</span> <span class="numeric_literal">0</span> <span class="brace">}</span><span class="semicolon">;</span>
+
+    <span class="macro">id</span><span class="macro_bang">!</span> <span class="brace">{</span>
+        <span class="keyword unsafe">unsafe</span> <span class="brace">{</span> <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">}</span>
+    <span class="brace">}</span><span class="semicolon">;</span>
+
     <span class="keyword unsafe">unsafe</span> <span class="brace">{</span>
+        <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
+        <span class="macro unsafe">id</span><span class="macro_bang">!</span> <span class="brace">{</span> <span class="macro unsafe">unsafe_deref</span><span class="macro_bang">!</span><span class="parenthesis">(</span><span class="parenthesis">)</span> <span class="brace">}</span><span class="semicolon">;</span>
+
         <span class="comment">// unsafe fn and method calls</span>
         <span class="function unsafe">unsafe_fn</span><span class="parenthesis">(</span><span class="parenthesis">)</span><span class="semicolon">;</span>
         <span class="keyword">let</span> <span class="variable declaration">b</span> <span class="operator">=</span> <span class="variable">u</span><span class="operator">.</span><span class="field unsafe">b</span><span class="semicolon">;</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index a8c69875e0..c74bced637 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -483,6 +483,16 @@ fn main() {
 fn test_unsafe_highlighting() {
     check_highlighting(
         r#"
+macro_rules! id {
+    ($($tt:tt)*) => {
+        $($tt)*
+    };
+}
+macro_rules! unsafe_deref {
+    () => {
+        *(&() as *const ())
+    };
+}
 static mut MUT_GLOBAL: Struct = Struct { field: 0 };
 static GLOBAL: Struct = Struct { field: 0 };
 unsafe fn unsafe_fn() {}
@@ -519,7 +529,15 @@ impl DoTheAutoref for u16 {
 fn main() {
     let x = &5 as *const _ as *const usize;
     let u = Union { b: 0 };
+
+    id! {
+        unsafe { unsafe_deref!() }
+    };
+
     unsafe {
+        unsafe_deref!();
+        id! { unsafe_deref!() };
+
         // unsafe fn and method calls
         unsafe_fn();
         let b = u.b;
diff --git a/crates/ide_assists/src/tests/generated.rs b/crates/ide_assists/src/tests/generated.rs
index bf69a94c27..485b807d05 100644
--- a/crates/ide_assists/src/tests/generated.rs
+++ b/crates/ide_assists/src/tests/generated.rs
@@ -922,7 +922,6 @@ impl Version {
     /// Returns `true` if the version is [`Minor`].
     ///
     /// [`Minor`]: Version::Minor
-    #[must_use]
     fn is_minor(&self) -> bool {
         matches!(self, Self::Minor)
     }
@@ -1037,7 +1036,6 @@ struct Person {
 
 impl Person {
     /// Get a reference to the person's name.
-    #[must_use]
     fn $0name(&self) -> &str {
         self.name.as_ref()
     }
@@ -1062,7 +1060,6 @@ struct Person {
 
 impl Person {
     /// Get a mutable reference to the person's name.
-    #[must_use]
     fn $0name_mut(&mut self) -> &mut String {
         &mut self.name
     }
@@ -1100,7 +1097,6 @@ fn doctest_generate_is_empty_from_len() {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     p$0ub fn len(&self) -> usize {
         self.data.len()
     }
@@ -1110,12 +1106,10 @@ impl MyStruct {
 struct MyStruct { data: Vec<String> }
 
 impl MyStruct {
-    #[must_use]
     pub fn len(&self) -> usize {
         self.data.len()
     }
 
-    #[must_use]
     pub fn is_empty(&self) -> bool {
         self.len() == 0
     }
@@ -1139,7 +1133,6 @@ struct Ctx<T: Clone> {
 }
 
 impl<T: Clone> Ctx<T> {
-    #[must_use]
     fn $0new(data: T) -> Self { Self { data } }
 }
 "#####,
diff --git a/crates/ide_completion/src/tests/pattern.rs b/crates/ide_completion/src/tests/pattern.rs
index 405a128b7e..50d5e01979 100644
--- a/crates/ide_completion/src/tests/pattern.rs
+++ b/crates/ide_completion/src/tests/pattern.rs
@@ -306,7 +306,6 @@ fn func() {
             ev TupleV(…)   TupleV(u32)
             ev RecordV {…} RecordV { field: u32 }
             ev UnitV       UnitV
-            ct ASSOC_CONST const ASSOC_CONST: ()
         "#]],
     );
 }
@@ -445,92 +444,3 @@ fn foo() {
         expect![[r#""#]],
     );
 }
-
-#[test]
-fn completes_associated_const() {
-    check_empty(
-        r#"
-#[derive(PartialEq, Eq)]
-struct Ty(u8);
-
-impl Ty {
-    const ABC: Self = Self(0);
-}
-
-fn f(t: Ty) {
-    match t {
-        Ty::$0 => {}
-        _ => {}
-    }
-}
-"#,
-        expect![[r#"
-            ct ABC const ABC: Self
-        "#]],
-    );
-
-    check_empty(
-        r#"
-enum MyEnum {}
-
-impl MyEnum {
-    pub const A: i32 = 123;
-    pub const B: i32 = 456;
-}
-
-fn f(e: MyEnum) {
-    match e {
-        MyEnum::$0 => {}
-        _ => {}
-    }
-}
-"#,
-        expect![[r#"
-            ct A pub const A: i32
-            ct B pub const B: i32
-        "#]],
-    );
-
-    check_empty(
-        r#"
-union U {
-    i: i32,
-    f: f32,
-}
-
-impl U {
-    pub const C: i32 = 123;
-    pub const D: i32 = 456;
-}
-
-fn f(u: U) {
-    match u {
-        U::$0 => {}
-        _ => {}
-    }
-}
-"#,
-        expect![[r#"
-            ct C pub const C: i32
-            ct D pub const D: i32
-        "#]],
-    );
-
-    check_empty(
-        r#"
-#[lang = "u32"]
-impl u32 {
-    pub const MIN: Self = 0;
-}
-
-fn f(v: u32) {
-    match v {
-        u32::$0
-    }
-}
-        "#,
-        expect![[r#"
-            ct MIN pub const MIN: Self
-        "#]],
-    );
-}
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 1d04caa28a..9e53aa847d 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -227,7 +227,6 @@ fn check_licenses() {
 Apache-2.0
 Apache-2.0 OR BSL-1.0
 Apache-2.0 OR MIT
-Apache-2.0 WITH LLVM-exception OR Apache-2.0 OR MIT
 Apache-2.0/MIT
 BSD-3-Clause
 CC0-1.0 OR Artistic-2.0