Merge pull request #21011 from dfaure-kdab/wip/dfaure/smolstr_pretty_printer

Provide a gdb pretty printer for smol_str::SmolStr
diff --git a/Cargo.toml b/Cargo.toml
index a7f1e17..63223f8 100644
--- a/Cargo.toml
+++ b/Cargo.toml
@@ -156,7 +156,7 @@
 temp-dir = "0.1.16"
 text-size = "1.1.1"
 toml = "0.9.8"
-tracing = "0.1.41"
+tracing = { version = "0.1.41", default-features = false, features = ["std"] }
 tracing-tree = "0.4.0"
 tracing-subscriber = { version = "0.3.20", default-features = false, features = [
     "registry",
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index ffd82d5..5149d2d 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -460,6 +460,61 @@
     pub env: Env,
 }
 
+impl Crate {
+    /// Returns an iterator over all transitive dependencies of the given crate,
+    /// including the crate itself.
+    ///
+    /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
+    pub fn transitive_deps(self, db: &dyn salsa::Database) -> Box<[Crate]> {
+        // There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible
+        // and removing that is a bit difficult.
+        let mut worklist = vec![self];
+        let mut deps_seen = FxHashSet::default();
+        let mut deps = Vec::new();
+
+        while let Some(krate) = worklist.pop() {
+            if !deps_seen.insert(krate) {
+                continue;
+            }
+            deps.push(krate);
+
+            worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id));
+        }
+        deps.into_boxed_slice()
+    }
+
+    /// Returns all transitive reverse dependencies of the given crate,
+    /// including the crate itself.
+    ///
+    /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
+    pub fn transitive_rev_deps(self, db: &dyn RootQueryDb) -> Box<[Crate]> {
+        let mut worklist = vec![self];
+        let mut rev_deps = FxHashSet::default();
+        rev_deps.insert(self);
+
+        let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
+        db.all_crates().iter().for_each(|&krate| {
+            krate
+                .data(db)
+                .dependencies
+                .iter()
+                .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate))
+        });
+
+        while let Some(krate) = worklist.pop() {
+            if let Some(crate_rev_deps) = inverted_graph.get(&krate) {
+                crate_rev_deps
+                    .iter()
+                    .copied()
+                    .filter(|&rev_dep| rev_deps.insert(rev_dep))
+                    .for_each(|rev_dep| worklist.push(rev_dep));
+            }
+        }
+
+        rev_deps.into_iter().collect::<Box<_>>()
+    }
+}
+
 /// The mapping from [`UniqueCrateData`] to their [`Crate`] input.
 #[derive(Debug, Default)]
 pub struct CratesMap(DashMap<UniqueCrateData, Crate, BuildHasherDefault<FxHasher>>);
@@ -802,33 +857,6 @@
     }
 }
 
-pub(crate) fn transitive_rev_deps(db: &dyn RootQueryDb, of: Crate) -> FxHashSet<Crate> {
-    let mut worklist = vec![of];
-    let mut rev_deps = FxHashSet::default();
-    rev_deps.insert(of);
-
-    let mut inverted_graph = FxHashMap::<_, Vec<_>>::default();
-    db.all_crates().iter().for_each(|&krate| {
-        krate
-            .data(db)
-            .dependencies
-            .iter()
-            .for_each(|dep| inverted_graph.entry(dep.crate_id).or_default().push(krate))
-    });
-
-    while let Some(krate) = worklist.pop() {
-        if let Some(crate_rev_deps) = inverted_graph.get(&krate) {
-            crate_rev_deps
-                .iter()
-                .copied()
-                .filter(|&rev_dep| rev_deps.insert(rev_dep))
-                .for_each(|rev_dep| worklist.push(rev_dep));
-        }
-    }
-
-    rev_deps
-}
-
 impl BuiltCrateData {
     pub fn root_file_id(&self, db: &dyn salsa::Database) -> EditionedFileId {
         EditionedFileId::new(db, self.root_file_id, self.edition)
diff --git a/crates/base-db/src/lib.rs b/crates/base-db/src/lib.rs
index 90e0aa9..3629a00 100644
--- a/crates/base-db/src/lib.rs
+++ b/crates/base-db/src/lib.rs
@@ -26,7 +26,7 @@
 };
 use dashmap::{DashMap, mapref::entry::Entry};
 pub use query_group::{self};
-use rustc_hash::{FxHashSet, FxHasher};
+use rustc_hash::FxHasher;
 use salsa::{Durability, Setter};
 pub use semver::{BuildMetadata, Prerelease, Version, VersionReq};
 use span::Edition;
@@ -256,38 +256,6 @@
     /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
     #[salsa::input]
     fn all_crates(&self) -> Arc<Box<[Crate]>>;
-
-    /// Returns an iterator over all transitive dependencies of the given crate,
-    /// including the crate itself.
-    ///
-    /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
-    #[salsa::transparent]
-    fn transitive_deps(&self, crate_id: Crate) -> FxHashSet<Crate>;
-
-    /// Returns all transitive reverse dependencies of the given crate,
-    /// including the crate itself.
-    ///
-    /// **Warning**: do not use this query in `hir-*` crates! It kills incrementality across crate metadata modifications.
-    #[salsa::invoke(input::transitive_rev_deps)]
-    #[salsa::transparent]
-    fn transitive_rev_deps(&self, of: Crate) -> FxHashSet<Crate>;
-}
-
-fn transitive_deps(db: &dyn SourceDatabase, crate_id: Crate) -> FxHashSet<Crate> {
-    // There is a bit of duplication here and in `CrateGraphBuilder` in the same method, but it's not terrible
-    // and removing that is a bit difficult.
-    let mut worklist = vec![crate_id];
-    let mut deps = FxHashSet::default();
-
-    while let Some(krate) = worklist.pop() {
-        if !deps.insert(krate) {
-            continue;
-        }
-
-        worklist.extend(krate.data(db).dependencies.iter().map(|dep| dep.crate_id));
-    }
-
-    deps
 }
 
 #[salsa_macros::db]
diff --git a/crates/hir-def/Cargo.toml b/crates/hir-def/Cargo.toml
index abb4819..4add777 100644
--- a/crates/hir-def/Cargo.toml
+++ b/crates/hir-def/Cargo.toml
@@ -23,7 +23,7 @@
 itertools.workspace = true
 la-arena.workspace = true
 rustc-hash.workspace = true
-tracing.workspace = true
+tracing = { workspace = true, features = ["attributes"] }
 smallvec.workspace = true
 triomphe.workspace = true
 rustc_apfloat = "0.2.3"
diff --git a/crates/hir-def/src/db.rs b/crates/hir-def/src/db.rs
index 4e1d598..925a078 100644
--- a/crates/hir-def/src/db.rs
+++ b/crates/hir-def/src/db.rs
@@ -273,10 +273,9 @@
 
     // endregion:visibilities
 
-    #[salsa::invoke(crate::lang_item::notable_traits_in_deps)]
-    fn notable_traits_in_deps(&self, krate: Crate) -> Arc<[Arc<[TraitId]>]>;
     #[salsa::invoke(crate::lang_item::crate_notable_traits)]
-    fn crate_notable_traits(&self, krate: Crate) -> Option<Arc<[TraitId]>>;
+    #[salsa::transparent]
+    fn crate_notable_traits(&self, krate: Crate) -> Option<&[TraitId]>;
 
     #[salsa::invoke(crate_supports_no_std)]
     fn crate_supports_no_std(&self, crate_id: Crate) -> bool;
diff --git a/crates/hir-def/src/lang_item.rs b/crates/hir-def/src/lang_item.rs
index df0705b..91a90f6 100644
--- a/crates/hir-def/src/lang_item.rs
+++ b/crates/hir-def/src/lang_item.rs
@@ -5,7 +5,6 @@
 use hir_expand::name::Name;
 use intern::{Symbol, sym};
 use rustc_hash::FxHashMap;
-use triomphe::Arc;
 
 use crate::{
     AdtId, AssocItemId, AttrDefId, Crate, EnumId, EnumVariantId, FunctionId, ImplId, ModuleDefId,
@@ -223,16 +222,8 @@
     db.attrs(item).lang_item()
 }
 
-pub(crate) fn notable_traits_in_deps(db: &dyn DefDatabase, krate: Crate) -> Arc<[Arc<[TraitId]>]> {
-    let _p = tracing::info_span!("notable_traits_in_deps", ?krate).entered();
-    Arc::from_iter(
-        db.transitive_deps(krate).into_iter().filter_map(|krate| db.crate_notable_traits(krate)),
-    )
-}
-
-pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Arc<[TraitId]>> {
-    let _p = tracing::info_span!("crate_notable_traits", ?krate).entered();
-
+#[salsa::tracked(returns(as_deref))]
+pub(crate) fn crate_notable_traits(db: &dyn DefDatabase, krate: Crate) -> Option<Box<[TraitId]>> {
     let mut traits = Vec::new();
 
     let crate_def_map = crate_def_map(db, krate);
diff --git a/crates/hir-ty/Cargo.toml b/crates/hir-ty/Cargo.toml
index 378a0f0..902fcd9 100644
--- a/crates/hir-ty/Cargo.toml
+++ b/crates/hir-ty/Cargo.toml
@@ -21,7 +21,7 @@
 ena = "0.14.3"
 either.workspace = true
 oorandom = "11.1.5"
-tracing.workspace = true
+tracing = { workspace = true, features = ["attributes"] }
 rustc-hash.workspace = true
 scoped-tls = "1.0.1"
 la-arena.workspace = true
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 18ebe7d..621ebc7 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -5,7 +5,7 @@
 
 use base_db::Crate;
 use hir_def::{
-    EnumVariantId, GeneralConstId, HasModule, StaticId,
+    ConstId, EnumVariantId, StaticId,
     expr_store::Body,
     hir::{Expr, ExprId},
     type_ref::LiteralConstRef,
@@ -139,16 +139,18 @@
         ConstKind::Infer(_) => None,
         ConstKind::Bound(_, _) => None,
         ConstKind::Placeholder(_) => None,
-        ConstKind::Unevaluated(unevaluated_const) => {
-            let c = match unevaluated_const.def {
-                SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
-                SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
-                _ => unreachable!(),
-            };
-            let subst = unevaluated_const.args;
-            let ec = db.const_eval(c, subst, None).ok()?;
-            try_const_usize(db, ec)
-        }
+        ConstKind::Unevaluated(unevaluated_const) => match unevaluated_const.def {
+            SolverDefId::ConstId(id) => {
+                let subst = unevaluated_const.args;
+                let ec = db.const_eval(id, subst, None).ok()?;
+                try_const_usize(db, ec)
+            }
+            SolverDefId::StaticId(id) => {
+                let ec = db.const_eval_static(id).ok()?;
+                try_const_usize(db, ec)
+            }
+            _ => unreachable!(),
+        },
         ConstKind::Value(val) => Some(u128::from_le_bytes(pad16(&val.value.inner().memory, false))),
         ConstKind::Error(_) => None,
         ConstKind::Expr(_) => None,
@@ -161,16 +163,18 @@
         ConstKind::Infer(_) => None,
         ConstKind::Bound(_, _) => None,
         ConstKind::Placeholder(_) => None,
-        ConstKind::Unevaluated(unevaluated_const) => {
-            let c = match unevaluated_const.def {
-                SolverDefId::ConstId(id) => GeneralConstId::ConstId(id),
-                SolverDefId::StaticId(id) => GeneralConstId::StaticId(id),
-                _ => unreachable!(),
-            };
-            let subst = unevaluated_const.args;
-            let ec = db.const_eval(c, subst, None).ok()?;
-            try_const_isize(db, &ec)
-        }
+        ConstKind::Unevaluated(unevaluated_const) => match unevaluated_const.def {
+            SolverDefId::ConstId(id) => {
+                let subst = unevaluated_const.args;
+                let ec = db.const_eval(id, subst, None).ok()?;
+                try_const_isize(db, &ec)
+            }
+            SolverDefId::StaticId(id) => {
+                let ec = db.const_eval_static(id).ok()?;
+                try_const_isize(db, &ec)
+            }
+            _ => unreachable!(),
+        },
         ConstKind::Value(val) => Some(i128::from_le_bytes(pad16(&val.value.inner().memory, true))),
         ConstKind::Error(_) => None,
         ConstKind::Expr(_) => None,
@@ -254,7 +258,7 @@
 
 pub(crate) fn const_eval_cycle_result<'db>(
     _: &'db dyn HirDatabase,
-    _: GeneralConstId,
+    _: ConstId,
     _: GenericArgs<'db>,
     _: Option<Arc<TraitEnvironment<'db>>>,
 ) -> Result<Const<'db>, ConstEvalError<'db>> {
@@ -277,19 +281,11 @@
 
 pub(crate) fn const_eval_query<'db>(
     db: &'db dyn HirDatabase,
-    def: GeneralConstId,
+    def: ConstId,
     subst: GenericArgs<'db>,
     trait_env: Option<Arc<TraitEnvironment<'db>>>,
 ) -> Result<Const<'db>, ConstEvalError<'db>> {
-    let body = match def {
-        GeneralConstId::ConstId(c) => {
-            db.monomorphized_mir_body(c.into(), subst, db.trait_environment(c.into()))?
-        }
-        GeneralConstId::StaticId(s) => {
-            let krate = s.module(db).krate();
-            db.monomorphized_mir_body(s.into(), subst, TraitEnvironment::empty(krate))?
-        }
-    };
+    let body = db.monomorphized_mir_body(def.into(), subst, db.trait_environment(def.into()))?;
     let c = interpret_mir(db, body, false, trait_env)?.0?;
     Ok(c)
 }
diff --git a/crates/hir-ty/src/consteval/tests.rs b/crates/hir-ty/src/consteval/tests.rs
index 70185bb..6095250 100644
--- a/crates/hir-ty/src/consteval/tests.rs
+++ b/crates/hir-ty/src/consteval/tests.rs
@@ -142,7 +142,7 @@
             _ => None,
         })
         .expect("No const named GOAL found in the test");
-    db.const_eval(const_id.into(), GenericArgs::new_from_iter(interner, []), None)
+    db.const_eval(const_id, GenericArgs::new_from_iter(interner, []), None)
 }
 
 #[test]
diff --git a/crates/hir-ty/src/db.rs b/crates/hir-ty/src/db.rs
index 98f4209..40e58aa 100644
--- a/crates/hir-ty/src/db.rs
+++ b/crates/hir-ty/src/db.rs
@@ -3,9 +3,9 @@
 
 use base_db::{Crate, target::TargetLoadError};
 use hir_def::{
-    AdtId, CallableDefId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId, GeneralConstId,
-    GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId,
-    TypeOrConstParamId, VariantId, db::DefDatabase, hir::ExprId, layout::TargetDataLayout,
+    AdtId, CallableDefId, ConstId, ConstParamId, DefWithBodyId, EnumVariantId, FunctionId,
+    GenericDefId, ImplId, LifetimeParamId, LocalFieldId, StaticId, TraitId, TypeAliasId, VariantId,
+    db::DefDatabase, hir::ExprId, layout::TargetDataLayout,
 };
 use la_arena::ArenaMap;
 use salsa::plumbing::AsId;
@@ -29,6 +29,8 @@
 
     // region:mir
 
+    // FXME: Collapse `mir_body_for_closure` into `mir_body`
+    // and `monomorphized_mir_body_for_closure` into `monomorphized_mir_body`
     #[salsa::invoke(crate::mir::mir_body_query)]
     #[salsa::cycle(cycle_result = crate::mir::mir_body_cycle_result)]
     fn mir_body<'db>(
@@ -70,7 +72,7 @@
     #[salsa::cycle(cycle_result = crate::consteval::const_eval_cycle_result)]
     fn const_eval<'db>(
         &'db self,
-        def: GeneralConstId,
+        def: ConstId,
         subst: GenericArgs<'db>,
         trait_env: Option<Arc<TraitEnvironment<'db>>>,
     ) -> Result<Const<'db>, ConstEvalError<'db>>;
@@ -234,13 +236,6 @@
 
 #[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
 #[derive(PartialOrd, Ord)]
-pub struct InternedTypeOrConstParamId {
-    /// This stores the param and its index.
-    pub loc: (TypeOrConstParamId, u32),
-}
-
-#[salsa_macros::interned(no_lifetime, debug, revisions = usize::MAX)]
-#[derive(PartialOrd, Ord)]
 pub struct InternedLifetimeParamId {
     /// This stores the param and its index.
     pub loc: (LifetimeParamId, u32),
diff --git a/crates/hir-ty/src/drop.rs b/crates/hir-ty/src/drop.rs
index 522d12d..aebb6de 100644
--- a/crates/hir-ty/src/drop.rs
+++ b/crates/hir-ty/src/drop.rs
@@ -28,10 +28,10 @@
     };
     let impls = match module.containing_block() {
         Some(block) => match TraitImpls::for_block(db, block) {
-            Some(it) => it,
+            Some(it) => &**it,
             None => return false,
         },
-        None => &**TraitImpls::for_crate(db, module.krate()),
+        None => TraitImpls::for_crate(db, module.krate()),
     };
     !impls.for_trait_and_self_ty(drop_trait, &SimplifiedType::Adt(adt.into())).is_empty()
 }
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index d8b02de..ece2bdc 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -11,7 +11,6 @@
 use rustc_ast_ir::Mutability;
 use rustc_type_ir::inherent::{GenericArg as _, GenericArgs as _, IntoKind, SliceLike, Ty as _};
 use stdx::TupleExt;
-use syntax::ast::RangeOp;
 
 use crate::{
     DeclContext, DeclOrigin, InferenceDiagnostic,
@@ -350,51 +349,16 @@
                 self.infer_slice_pat(expected, prefix, *slice, suffix, default_bm, decl)
             }
             Pat::Wild => expected,
-            Pat::Range { start, end, range_type } => {
-                // FIXME: Expectation
-                let lhs_expectation = Expectation::none();
-                let lhs_ty =
-                    start.map(|start| self.infer_expr(start, &lhs_expectation, ExprIsRead::Yes));
-                let rhs_expectation = lhs_ty.map_or_else(Expectation::none, Expectation::HasType);
-                let rhs_ty = end.map(|end| self.infer_expr(end, &rhs_expectation, ExprIsRead::Yes));
-                let single_arg_adt = |adt, ty: Ty<'db>| {
-                    Ty::new_adt(
-                        self.interner(),
-                        adt,
-                        GenericArgs::new_from_iter(self.interner(), [ty.into()]),
-                    )
-                };
-                match (range_type, lhs_ty, rhs_ty) {
-                    (RangeOp::Exclusive, None, None) => match self.resolve_range_full() {
-                        Some(adt) => Ty::new_adt(self.interner(), adt, self.types.empty_args),
-                        None => self.err_ty(),
-                    },
-                    (RangeOp::Exclusive, None, Some(ty)) => match self.resolve_range_to() {
-                        Some(adt) => single_arg_adt(adt, ty),
-                        None => self.err_ty(),
-                    },
-                    (RangeOp::Inclusive, None, Some(ty)) => {
-                        match self.resolve_range_to_inclusive() {
-                            Some(adt) => single_arg_adt(adt, ty),
-                            None => self.err_ty(),
-                        }
-                    }
-                    (RangeOp::Exclusive, Some(_), Some(ty)) => match self.resolve_range() {
-                        Some(adt) => single_arg_adt(adt, ty),
-                        None => self.err_ty(),
-                    },
-                    (RangeOp::Inclusive, Some(_), Some(ty)) => {
-                        match self.resolve_range_inclusive() {
-                            Some(adt) => single_arg_adt(adt, ty),
-                            None => self.err_ty(),
-                        }
-                    }
-                    (RangeOp::Exclusive, Some(ty), None) => match self.resolve_range_from() {
-                        Some(adt) => single_arg_adt(adt, ty),
-                        None => self.err_ty(),
-                    },
-                    (RangeOp::Inclusive, _, None) => self.err_ty(),
+            Pat::Range { start, end, range_type: _ } => {
+                if let Some(start) = *start {
+                    let start_ty = self.infer_expr(start, &Expectation::None, ExprIsRead::Yes);
+                    _ = self.demand_eqtype(start.into(), expected, start_ty);
                 }
+                if let Some(end) = *end {
+                    let end_ty = self.infer_expr(end, &Expectation::None, ExprIsRead::Yes);
+                    _ = self.demand_eqtype(end.into(), expected, end_ty);
+                }
+                expected
             }
             &Pat::Lit(expr) => {
                 // Don't emit type mismatches again, the expression lowering already did that.
diff --git a/crates/hir-ty/src/method_resolution.rs b/crates/hir-ty/src/method_resolution.rs
index 799bfb3..59299f2 100644
--- a/crates/hir-ty/src/method_resolution.rs
+++ b/crates/hir-ty/src/method_resolution.rs
@@ -687,7 +687,7 @@
 
     #[salsa::tracked(returns(ref))]
     pub fn for_crate_and_deps(db: &dyn HirDatabase, krate: Crate) -> Box<[Arc<Self>]> {
-        db.transitive_deps(krate).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
+        krate.transitive_deps(db).iter().map(|&dep| Self::for_crate(db, dep).clone()).collect()
     }
 }
 
diff --git a/crates/hir-ty/src/mir/eval.rs b/crates/hir-ty/src/mir/eval.rs
index 6e62bcb..08f4241 100644
--- a/crates/hir-ty/src/mir/eval.rs
+++ b/crates/hir-ty/src/mir/eval.rs
@@ -1917,24 +1917,32 @@
         let value = match konst.kind() {
             ConstKind::Value(value) => value,
             ConstKind::Unevaluated(UnevaluatedConst { def: const_id, args: subst }) => 'b: {
-                let mut const_id = match const_id {
+                let mut id = match const_id {
                     SolverDefId::ConstId(it) => GeneralConstId::from(it),
                     SolverDefId::StaticId(it) => it.into(),
                     _ => unreachable!("unevaluated consts should be consts or statics"),
                 };
                 let mut subst = subst;
-                if let hir_def::GeneralConstId::ConstId(c) = const_id {
+                if let hir_def::GeneralConstId::ConstId(c) = id {
                     let (c, s) = lookup_impl_const(&self.infcx, self.trait_env.clone(), c, subst);
-                    const_id = hir_def::GeneralConstId::ConstId(c);
+                    id = hir_def::GeneralConstId::ConstId(c);
                     subst = s;
                 }
-                result_owner = self
-                    .db
-                    .const_eval(const_id, subst, Some(self.trait_env.clone()))
-                    .map_err(|e| {
-                        let name = const_id.name(self.db);
-                        MirEvalError::ConstEvalError(name, Box::new(e))
-                    })?;
+                result_owner = match id {
+                    GeneralConstId::ConstId(const_id) => self
+                        .db
+                        .const_eval(const_id, subst, Some(self.trait_env.clone()))
+                        .map_err(|e| {
+                            let name = id.name(self.db);
+                            MirEvalError::ConstEvalError(name, Box::new(e))
+                        })?,
+                    GeneralConstId::StaticId(static_id) => {
+                        self.db.const_eval_static(static_id).map_err(|e| {
+                            let name = id.name(self.db);
+                            MirEvalError::ConstEvalError(name, Box::new(e))
+                        })?
+                    }
+                };
                 if let ConstKind::Value(value) = result_owner.kind() {
                     break 'b value;
                 }
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index 6704012..7f457ca 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -1532,10 +1532,20 @@
                 UnevaluatedConst { def: const_id.into(), args: subst },
             )
         } else {
-            let name = const_id.name(self.db);
-            self.db
-                .const_eval(const_id, subst, None)
-                .map_err(|e| MirLowerError::ConstEvalError(name.into(), Box::new(e)))?
+            match const_id {
+                id @ GeneralConstId::ConstId(const_id) => {
+                    self.db.const_eval(const_id, subst, None).map_err(|e| {
+                        let name = id.name(self.db);
+                        MirLowerError::ConstEvalError(name.into(), Box::new(e))
+                    })?
+                }
+                GeneralConstId::StaticId(static_id) => {
+                    self.db.const_eval_static(static_id).map_err(|e| {
+                        let name = const_id.name(self.db);
+                        MirLowerError::ConstEvalError(name.into(), Box::new(e))
+                    })?
+                }
+            }
         };
         let ty = self
             .db
diff --git a/crates/hir-ty/src/next_solver/generic_arg.rs b/crates/hir-ty/src/next_solver/generic_arg.rs
index dedd6a1..2205cba 100644
--- a/crates/hir-ty/src/next_solver/generic_arg.rs
+++ b/crates/hir-ty/src/next_solver/generic_arg.rs
@@ -17,7 +17,7 @@
     generics::Generics,
 };
 
-#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable)]
+#[derive(Copy, Clone, PartialEq, Eq, Hash, TypeVisitable, TypeFoldable, salsa::Supertype)]
 pub enum GenericArg<'db> {
     Ty(Ty<'db>),
     Lifetime(Region<'db>),
@@ -196,6 +196,11 @@
     {
         let defs = interner.generics_of(def_id);
         let count = defs.count();
+
+        if count == 0 {
+            return Default::default();
+        }
+
         let mut args = SmallVec::with_capacity(count);
         Self::fill_item(&mut args, interner, defs, &mut mk_kind);
         interner.mk_args(&args)
diff --git a/crates/hir-ty/src/next_solver/interner.rs b/crates/hir-ty/src/next_solver/interner.rs
index 39de17e..b77b305 100644
--- a/crates/hir-ty/src/next_solver/interner.rs
+++ b/crates/hir-ty/src/next_solver/interner.rs
@@ -214,6 +214,10 @@
         }
 
         impl<'db> $name<'db> {
+            pub fn empty(interner: DbInterner<'db>) -> Self {
+                $name::new_(interner.db(), smallvec::SmallVec::new())
+            }
+
             pub fn new_from_iter(
                 interner: DbInterner<'db>,
                 data: impl IntoIterator<Item = $ty<'db>>,
diff --git a/crates/hir-ty/src/next_solver/solver.rs b/crates/hir-ty/src/next_solver/solver.rs
index 8fae340..68b6ebf 100644
--- a/crates/hir-ty/src/next_solver/solver.rs
+++ b/crates/hir-ty/src/next_solver/solver.rs
@@ -1,6 +1,6 @@
 //! Defining `SolverContext` for next-trait-solver.
 
-use hir_def::{AssocItemId, GeneralConstId};
+use hir_def::AssocItemId;
 use rustc_next_trait_solver::delegate::SolverDelegate;
 use rustc_type_ir::{
     AliasTyKind, GenericArgKind, InferCtxtLike, Interner, PredicatePolarity, TypeFlags,
@@ -233,14 +233,18 @@
         _param_env: ParamEnv<'db>,
         uv: rustc_type_ir::UnevaluatedConst<Self::Interner>,
     ) -> Option<<Self::Interner as rustc_type_ir::Interner>::Const> {
-        let c = match uv.def {
-            SolverDefId::ConstId(c) => GeneralConstId::ConstId(c),
-            SolverDefId::StaticId(c) => GeneralConstId::StaticId(c),
+        match uv.def {
+            SolverDefId::ConstId(c) => {
+                let subst = uv.args;
+                let ec = self.cx().db.const_eval(c, subst, None).ok()?;
+                Some(ec)
+            }
+            SolverDefId::StaticId(c) => {
+                let ec = self.cx().db.const_eval_static(c).ok()?;
+                Some(ec)
+            }
             _ => unreachable!(),
-        };
-        let subst = uv.args;
-        let ec = self.cx().db.const_eval(c, subst, None).ok()?;
-        Some(ec)
+        }
     }
 
     fn compute_goal_fast_path(
diff --git a/crates/hir-ty/src/tests/patterns.rs b/crates/hir-ty/src/tests/patterns.rs
index 5e150e2..c312b16 100644
--- a/crates/hir-ty/src/tests/patterns.rs
+++ b/crates/hir-ty/src/tests/patterns.rs
@@ -196,28 +196,38 @@
 }
         "#,
         expect![[r#"
-            8..9 'x': u32
+            8..9 'x': Range<u32>
             8..12 'x..y': Range<u32>
-            11..12 'y': u32
+            11..12 'y': Range<u32>
             38..96 '{     ...2 {} }': ()
             44..66 'if let...u32 {}': ()
             47..63 'let 1....= 2u32': bool
-            51..52 '1': i32
-            51..56 '1..76': Range<i32>
-            54..56 '76': i32
+            51..52 '1': u32
+            51..56 '1..76': u32
+            54..56 '76': u32
             59..63 '2u32': u32
             64..66 '{}': ()
             71..94 'if let...u32 {}': ()
             74..91 'let 1....= 2u32': bool
-            78..79 '1': i32
-            78..84 '1..=76': RangeInclusive<i32>
-            82..84 '76': i32
+            78..79 '1': u32
+            78..84 '1..=76': u32
+            82..84 '76': u32
             87..91 '2u32': u32
             92..94 '{}': ()
-            51..56: expected u32, got Range<i32>
-            78..84: expected u32, got RangeInclusive<i32>
         "#]],
     );
+    check_no_mismatches(
+        r#"
+//- minicore: range
+fn main() {
+    let byte: u8 = 0u8;
+    let b = match byte {
+        b'0'..=b'9' => true,
+        _ => false,
+    };
+}
+    "#,
+    );
 }
 
 #[test]
diff --git a/crates/hir/Cargo.toml b/crates/hir/Cargo.toml
index dfa3938..a839975 100644
--- a/crates/hir/Cargo.toml
+++ b/crates/hir/Cargo.toml
@@ -18,7 +18,7 @@
 arrayvec.workspace = true
 itertools.workspace = true
 smallvec.workspace = true
-tracing.workspace = true
+tracing = { workspace = true, features = ["attributes"] }
 triomphe.workspace = true
 indexmap.workspace = true
 
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 82c6cf7..5400003 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -247,7 +247,15 @@
         self,
         db: &dyn HirDatabase,
     ) -> impl Iterator<Item = Crate> {
-        db.transitive_rev_deps(self.id).into_iter().map(|id| Crate { id })
+        self.id.transitive_rev_deps(db).into_iter().map(|id| Crate { id })
+    }
+
+    pub fn notable_traits_in_deps(self, db: &dyn HirDatabase) -> impl Iterator<Item = &TraitId> {
+        self.id
+            .transitive_deps(db)
+            .into_iter()
+            .filter_map(|krate| db.crate_notable_traits(krate))
+            .flatten()
     }
 
     pub fn root_module(self) -> Module {
@@ -2798,7 +2806,7 @@
     pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError<'_>> {
         let interner = DbInterner::new_with(db, None, None);
         let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity();
-        db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None)
+        db.const_eval(self.id, GenericArgs::new_from_iter(interner, []), None)
             .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty })
     }
 }
@@ -2877,10 +2885,12 @@
 
     /// Evaluate the static initializer.
     pub fn eval(self, db: &dyn HirDatabase) -> Result<EvaluatedConst<'_>, ConstEvalError<'_>> {
-        let interner = DbInterner::new_with(db, None, None);
         let ty = db.value_ty(self.id.into()).unwrap().instantiate_identity();
-        db.const_eval(self.id.into(), GenericArgs::new_from_iter(interner, []), None)
-            .map(|it| EvaluatedConst { const_: it, def: self.id.into(), ty })
+        db.const_eval_static(self.id).map(|it| EvaluatedConst {
+            const_: it,
+            def: self.id.into(),
+            ty,
+        })
     }
 }
 
@@ -4444,7 +4454,7 @@
         let mut handle_impls = |impls: &TraitImpls| {
             impls.for_trait(trait_.id, |impls| all.extend(impls.iter().copied().map(Impl::from)));
         };
-        for krate in db.transitive_rev_deps(module.krate()) {
+        for krate in module.krate().transitive_rev_deps(db) {
             handle_impls(TraitImpls::for_crate(db, krate));
         }
         if let Some(block) = module.containing_block()
diff --git a/crates/ide-assists/Cargo.toml b/crates/ide-assists/Cargo.toml
index 385b0e1..dcccf13f 100644
--- a/crates/ide-assists/Cargo.toml
+++ b/crates/ide-assists/Cargo.toml
@@ -18,7 +18,7 @@
 itertools.workspace = true
 either.workspace = true
 smallvec.workspace = true
-tracing.workspace = true
+tracing = { workspace = true, features = ["attributes"] }
 
 # local deps
 stdx.workspace = true
diff --git a/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs b/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
index 10b0879..7960373 100644
--- a/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
+++ b/crates/ide-assists/src/handlers/add_explicit_enum_discriminant.rs
@@ -1,8 +1,11 @@
 use hir::Semantics;
 use ide_db::{RootDatabase, assists::AssistId, source_change::SourceChangeBuilder};
-use syntax::{AstNode, ast};
+use syntax::{
+    AstNode,
+    ast::{self, Radix},
+};
 
-use crate::{AssistContext, Assists};
+use crate::{AssistContext, Assists, utils::add_group_separators};
 
 // Assist: add_explicit_enum_discriminant
 //
@@ -53,8 +56,9 @@
         "Add explicit enum discriminants",
         enum_node.syntax().text_range(),
         |builder| {
+            let mut radix = Radix::Decimal;
             for variant_node in variant_list.variants() {
-                add_variant_discriminant(&ctx.sema, builder, &variant_node);
+                add_variant_discriminant(&ctx.sema, builder, &variant_node, &mut radix);
             }
         },
     );
@@ -66,8 +70,10 @@
     sema: &Semantics<'_, RootDatabase>,
     builder: &mut SourceChangeBuilder,
     variant_node: &ast::Variant,
+    radix: &mut Radix,
 ) {
-    if variant_node.expr().is_some() {
+    if let Some(expr) = variant_node.expr() {
+        *radix = expr_radix(&expr).unwrap_or(*radix);
         return;
     }
 
@@ -80,7 +86,24 @@
 
     let variant_range = variant_node.syntax().text_range();
 
-    builder.insert(variant_range.end(), format!(" = {discriminant}"));
+    let (group_size, prefix, text) = match radix {
+        Radix::Binary => (4, "0b", format!("{discriminant:b}")),
+        Radix::Octal => (3, "0o", format!("{discriminant:o}")),
+        Radix::Decimal => (6, "", discriminant.to_string()),
+        Radix::Hexadecimal => (4, "0x", format!("{discriminant:x}")),
+    };
+    let pretty_num = add_group_separators(&text, group_size);
+    builder.insert(variant_range.end(), format!(" = {prefix}{pretty_num}"));
+}
+
+fn expr_radix(expr: &ast::Expr) -> Option<Radix> {
+    if let ast::Expr::Literal(lit) = expr
+        && let ast::LiteralKind::IntNumber(num) = lit.kind()
+    {
+        Some(num.radix())
+    } else {
+        None
+    }
 }
 
 #[cfg(test)]
@@ -172,9 +195,9 @@
 #[repr(i64)]
 enum TheEnum {
     Foo = 1 << 63,
-    Bar = -9223372036854775807,
+    Bar = -9_223372_036854_775807,
     Baz = 0x7fff_ffff_ffff_fffe,
-    Quux = 9223372036854775807,
+    Quux = 0x7fff_ffff_ffff_ffff,
 }
 "#,
         );
diff --git a/crates/ide-assists/src/handlers/add_missing_match_arms.rs b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
index 7843ab9..3eeff2a 100644
--- a/crates/ide-assists/src/handlers/add_missing_match_arms.rs
+++ b/crates/ide-assists/src/handlers/add_missing_match_arms.rs
@@ -67,9 +67,9 @@
             }
             .map(move |pat| (pat, has_guard))
         })
-        .map(|(pat, has_guard)| {
+        .filter_map(|(pat, has_guard)| {
             has_catch_all_arm |= !has_guard && matches!(pat, Pat::WildcardPat(_));
-            pat
+            (!has_guard).then_some(pat)
         })
         // Exclude top level wildcards so that they are expanded by this assist, retains status quo in #8129.
         .filter(|pat| !matches!(pat, Pat::WildcardPat(_)))
@@ -998,7 +998,8 @@
         A::Ds(_value) => { let x = 1; }
         A::Es(B::Xs) => (),
         A::As => ${1:todo!()},
-        A::Cs => ${2:todo!()},$0
+        A::Bs => ${2:todo!()},
+        A::Cs => ${3:todo!()},$0
     }
 }
 "#,
diff --git a/crates/ide-assists/src/handlers/convert_char_literal.rs b/crates/ide-assists/src/handlers/convert_char_literal.rs
new file mode 100644
index 0000000..0a50ba8
--- /dev/null
+++ b/crates/ide-assists/src/handlers/convert_char_literal.rs
@@ -0,0 +1,97 @@
+use syntax::{AstToken, ast};
+
+use crate::{AssistContext, AssistId, Assists, GroupLabel};
+
+// Assist: convert_char_literal
+//
+// Converts character literals between different representations. Currently supports normal character -> ASCII / Unicode escape.
+// ```
+// const _: char = 'a'$0;
+// ```
+// ->
+// ```
+// const _: char = '\x61';
+// ```
+pub(crate) fn convert_char_literal(acc: &mut Assists, ctx: &AssistContext<'_>) -> Option<()> {
+    if !ctx.has_empty_selection() {
+        return None;
+    }
+
+    let literal = ctx.find_node_at_offset::<ast::Literal>()?;
+    let literal = match literal.kind() {
+        ast::LiteralKind::Char(it) => it,
+        _ => return None,
+    };
+
+    let value = literal.value().ok()?;
+    let text = literal.syntax().text().to_owned();
+    let range = literal.syntax().text_range();
+    let group_id = GroupLabel("Convert char representation".into());
+
+    let mut add_assist = |converted: String| {
+        // Skip no-op assists (e.g. `'const C: char = '\\x61';'` already matches the ASCII form).
+        if converted == text {
+            return;
+        }
+        let label = format!("Convert {text} to {converted}");
+        acc.add_group(
+            &group_id,
+            AssistId::refactor_rewrite("convert_char_literal"),
+            label,
+            range,
+            |builder| builder.replace(range, converted),
+        );
+    };
+
+    if value.is_ascii() {
+        add_assist(format!("'\\x{:02x}'", value as u32));
+    }
+
+    add_assist(format!("'\\u{{{:x}}}'", value as u32));
+
+    Some(())
+}
+
+#[cfg(test)]
+mod tests {
+    use crate::tests::check_assist_by_label;
+
+    use super::convert_char_literal;
+
+    #[test]
+    fn ascii_char_to_ascii_and_unicode() {
+        let before = "const _: char = 'a'$0;";
+        check_assist_by_label(
+            convert_char_literal,
+            before,
+            "const _: char = '\\x61';",
+            "Convert 'a' to '\\x61'",
+        );
+        check_assist_by_label(
+            convert_char_literal,
+            before,
+            "const _: char = '\\u{61}';",
+            "Convert 'a' to '\\u{61}'",
+        );
+    }
+
+    #[test]
+    fn non_ascii_char_only_unicode() {
+        check_assist_by_label(
+            convert_char_literal,
+            "const _: char = '😀'$0;",
+            "const _: char = '\\u{1f600}';",
+            "Convert '😀' to '\\u{1f600}'",
+        );
+    }
+
+    #[test]
+    fn ascii_escape_can_convert_to_unicode() {
+        check_assist_by_label(
+            convert_char_literal,
+            "const _: char = '\\x61'$0;",
+            "const _: char = '\\u{61}';",
+            "Convert '\\x61' to '\\u{61}'",
+        );
+    }
+}
diff --git a/crates/ide-assists/src/handlers/number_representation.rs b/crates/ide-assists/src/handlers/number_representation.rs
index 1fe40f8..fac81ae 100644
--- a/crates/ide-assists/src/handlers/number_representation.rs
+++ b/crates/ide-assists/src/handlers/number_representation.rs
@@ -1,6 +1,6 @@
 use syntax::{AstToken, ast, ast::Radix};
 
-use crate::{AssistContext, AssistId, Assists, GroupLabel};
+use crate::{AssistContext, AssistId, Assists, GroupLabel, utils::add_group_separators};
 
 const MIN_NUMBER_OF_DIGITS_TO_FORMAT: usize = 5;
 
@@ -70,18 +70,6 @@
     }
 }
 
-fn add_group_separators(s: &str, group_size: usize) -> String {
-    let mut chars = Vec::new();
-    for (i, ch) in s.chars().filter(|&ch| ch != '_').rev().enumerate() {
-        if i > 0 && i % group_size == 0 {
-            chars.push('_');
-        }
-        chars.push(ch);
-    }
-
-    chars.into_iter().rev().collect()
-}
-
 #[cfg(test)]
 mod tests {
     use crate::tests::{check_assist_by_label, check_assist_not_applicable, check_assist_target};
diff --git a/crates/ide-assists/src/lib.rs b/crates/ide-assists/src/lib.rs
index 4b4aa94..ca46890 100644
--- a/crates/ide-assists/src/lib.rs
+++ b/crates/ide-assists/src/lib.rs
@@ -119,6 +119,7 @@
     mod change_visibility;
     mod convert_bool_then;
     mod convert_bool_to_enum;
+    mod convert_char_literal;
     mod convert_closure_to_fn;
     mod convert_comment_block;
     mod convert_comment_from_or_to_doc;
@@ -256,6 +257,7 @@
             convert_bool_then::convert_bool_then_to_if,
             convert_bool_then::convert_if_to_bool_then,
             convert_bool_to_enum::convert_bool_to_enum,
+            convert_char_literal::convert_char_literal,
             convert_closure_to_fn::convert_closure_to_fn,
             convert_comment_block::convert_comment_block,
             convert_comment_from_or_to_doc::convert_comment_from_or_to_doc,
diff --git a/crates/ide-assists/src/tests/generated.rs b/crates/ide-assists/src/tests/generated.rs
index 160b31a..7eef257 100644
--- a/crates/ide-assists/src/tests/generated.rs
+++ b/crates/ide-assists/src/tests/generated.rs
@@ -425,6 +425,19 @@
 }
 
 #[test]
+fn doctest_convert_char_literal() {
+    check_doc_test(
+        "convert_char_literal",
+        r#####"
+const _: char = 'a'$0;
+"#####,
+        r#####"
+const _: char = '\x61';
+"#####,
+    )
+}
+
+#[test]
 fn doctest_convert_closure_to_fn() {
     check_doc_test(
         "convert_closure_to_fn",
diff --git a/crates/ide-assists/src/utils.rs b/crates/ide-assists/src/utils.rs
index 4350749..a00af92 100644
--- a/crates/ide-assists/src/utils.rs
+++ b/crates/ide-assists/src/utils.rs
@@ -1080,6 +1080,18 @@
     assert_eq!(Some("r"), string_prefix(r##"r#""#"##));
 }
 
+pub(crate) fn add_group_separators(s: &str, group_size: usize) -> String {
+    let mut chars = Vec::new();
+    for (i, ch) in s.chars().filter(|&ch| ch != '_').rev().enumerate() {
+        if i > 0 && i % group_size == 0 && ch != '-' {
+            chars.push('_');
+        }
+        chars.push(ch);
+    }
+
+    chars.into_iter().rev().collect()
+}
+
 /// Replaces the record expression, handling field shorthands including inside macros.
 pub(crate) fn replace_record_field_expr(
     ctx: &AssistContext<'_>,
diff --git a/crates/ide-completion/src/completions/attribute/cfg.rs b/crates/ide-completion/src/completions/attribute/cfg.rs
index b6739c9..1350e58 100644
--- a/crates/ide-completion/src/completions/attribute/cfg.rs
+++ b/crates/ide-completion/src/completions/attribute/cfg.rs
@@ -2,7 +2,7 @@
 
 use ide_db::SymbolKind;
 use itertools::Itertools;
-use syntax::{AstToken, Direction, NodeOrToken, SyntaxKind, algo, ast::Ident};
+use syntax::{AstToken, Direction, NodeOrToken, SmolStr, SyntaxKind, algo, ast::Ident};
 
 use crate::{CompletionItem, completions::Completions, context::CompletionContext};
 
@@ -56,10 +56,15 @@
         None => ctx
             .krate
             .potential_cfg(ctx.db)
-            .get_cfg_keys()
-            .unique()
-            .map(|s| (s.as_str(), ""))
-            .chain(CFG_CONDITION.iter().copied())
+            .into_iter()
+            .map(|x| match x {
+                hir::CfgAtom::Flag(key) => (key.as_str(), "".into()),
+                hir::CfgAtom::KeyValue { key, .. } => {
+                    (key.as_str(), SmolStr::from_iter([key.as_str(), " = $0"]))
+                }
+            })
+            .chain(CFG_CONDITION.iter().map(|&(k, snip)| (k, SmolStr::new_static(snip))))
+            .unique_by(|&(s, _)| s)
             .for_each(|(s, snippet)| {
                 let mut item = CompletionItem::new(
                     SymbolKind::BuiltinAttr,
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index d6d3978..e4076fc 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -1679,12 +1679,16 @@
     let mut param_ctx = None;
 
     let mut missing_variants = vec![];
+    let is_pat_like = |kind| {
+        ast::Pat::can_cast(kind)
+            || ast::RecordPatField::can_cast(kind)
+            || ast::RecordPatFieldList::can_cast(kind)
+    };
 
-    let (refutability, has_type_ascription) =
-    pat
+    let (refutability, has_type_ascription) = pat
         .syntax()
         .ancestors()
-        .find(|it| !ast::Pat::can_cast(it.kind()))
+        .find(|it| !is_pat_like(it.kind()))
         .map_or((PatternRefutability::Irrefutable, false), |node| {
             let refutability = match_ast! {
                 match node {
diff --git a/crates/ide-completion/src/tests/attribute.rs b/crates/ide-completion/src/tests/attribute.rs
index 3538dac..9ff490f 100644
--- a/crates/ide-completion/src/tests/attribute.rs
+++ b/crates/ide-completion/src/tests/attribute.rs
@@ -983,6 +983,34 @@
     }
 
     #[test]
+    fn complete_key_attr() {
+        check_edit(
+            "test",
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg($0)]
+"#,
+            r#"
+#[cfg(test)]
+"#,
+        );
+    }
+
+    #[test]
+    fn complete_key_value_attr() {
+        check_edit(
+            "opt_level",
+            r#"
+//- /main.rs cfg:test,dbg=false,opt_level=2
+#[cfg($0)]
+"#,
+            r#"
+#[cfg(opt_level = $0)]
+"#,
+        );
+    }
+
+    #[test]
     fn cfg_target_endian() {
         check(
             r#"#[cfg(target_endian = $0"#,
diff --git a/crates/ide-completion/src/tests/pattern.rs b/crates/ide-completion/src/tests/pattern.rs
index df0c4e5..a765fd12 100644
--- a/crates/ide-completion/src/tests/pattern.rs
+++ b/crates/ide-completion/src/tests/pattern.rs
@@ -133,6 +133,44 @@
 }
 
 #[test]
+fn refutable_in_record_pat_field() {
+    check(
+        r#"
+enum Bar { Value, Nil }
+struct Foo { x: Bar }
+fn foo(foo: Foo) { match foo { Foo { x: $0 } } }
+"#,
+        expect![[r#"
+            en Bar
+            st Foo
+            bn Foo {…} Foo { x$1 }$0
+            kw mut
+            kw ref
+        "#]],
+    );
+
+    check(
+        r#"
+enum Bar { Value, Nil }
+use Bar::*;
+struct Foo { x: Bar }
+fn foo(foo: Foo) { match foo { Foo { x: $0 } } }
+"#,
+        expect![[r#"
+            en Bar
+            st Foo
+            ev Nil
+            ev Value
+            bn Foo {…} Foo { x$1 }$0
+            bn Nil             Nil$0
+            bn Value         Value$0
+            kw mut
+            kw ref
+        "#]],
+    );
+}
+
+#[test]
 fn irrefutable() {
     check_with_base_items(
         r#"
diff --git a/crates/ide-db/Cargo.toml b/crates/ide-db/Cargo.toml
index b714816..ac28e32 100644
--- a/crates/ide-db/Cargo.toml
+++ b/crates/ide-db/Cargo.toml
@@ -15,7 +15,7 @@
 [dependencies]
 cov-mark = "2.0.0"
 crossbeam-channel.workspace = true
-tracing.workspace = true
+tracing = { workspace = true, features = ["attributes"] }
 rayon.workspace = true
 fst = { version = "0.4.7", default-features = false }
 rustc-hash.workspace = true
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index e1d18b0..fa4b4b6 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -8,7 +8,6 @@
 use either::Either;
 use hir::{
     DisplayTarget, GenericDef, GenericSubstitution, HasCrate, HasSource, LangItem, Semantics,
-    db::DefDatabase,
 };
 use ide_db::{
     FileRange, FxIndexSet, MiniCore, Ranker, RootDatabase,
@@ -522,9 +521,8 @@
         return Vec::new();
     }
 
-    db.notable_traits_in_deps(ty.krate(db).into())
-        .iter()
-        .flat_map(|it| &**it)
+    ty.krate(db)
+        .notable_traits_in_deps(db)
         .filter_map(move |&trait_| {
             let trait_ = trait_.into();
             ty.impls_trait(db, trait_, &[]).then(|| {
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index 2609457..113cb83 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -642,7 +642,7 @@
 
     /// Returns crates that this file belongs to.
     pub fn transitive_rev_deps(&self, crate_id: Crate) -> Cancellable<Vec<Crate>> {
-        self.with_db(|db| Vec::from_iter(db.transitive_rev_deps(crate_id)))
+        self.with_db(|db| Vec::from_iter(crate_id.transitive_rev_deps(db)))
     }
 
     /// Returns crates that this file *might* belong to.
diff --git a/crates/parser/Cargo.toml b/crates/parser/Cargo.toml
index 8384d5b..2bdf8d7 100644
--- a/crates/parser/Cargo.toml
+++ b/crates/parser/Cargo.toml
@@ -16,7 +16,7 @@
 drop_bomb = "0.1.5"
 ra-ap-rustc_lexer.workspace = true
 rustc-literal-escaper.workspace = true
-tracing = { workspace = true, optional = true }
+tracing.workspace = true
 
 edition.workspace = true
 winnow = { version = "0.7.13", default-features = false }
@@ -27,7 +27,7 @@
 stdx.workspace = true
 
 [features]
-default = ["tracing"]
+default = []
 in-rust-tree = []
 
 [lints]
diff --git a/crates/project-model/Cargo.toml b/crates/project-model/Cargo.toml
index ec44369..7e0b1f7 100644
--- a/crates/project-model/Cargo.toml
+++ b/crates/project-model/Cargo.toml
@@ -22,7 +22,7 @@
 serde_derive.workspace = true
 temp-dir.workspace = true
 toml.workspace = true
-tracing.workspace = true
+tracing = { workspace = true, features = ["attributes"] }
 triomphe.workspace = true
 la-arena.workspace = true
 itertools.workspace = true