Repository: rust-lang/rust-analyzer
Pull request #17023 (2024-04-06 12:30:11)

internal: Some cleanup and perf 


Patch:
diff --git a/crates/base-db/src/input.rs b/crates/base-db/src/input.rs
index 27eb05cd4d..1924ce578a 100644
--- a/crates/base-db/src/input.rs
+++ b/crates/base-db/src/input.rs
@@ -285,9 +285,9 @@ pub struct CrateData {
     /// For purposes of analysis, crates are anonymous (only names in
     /// `Dependency` matters), this name should only be used for UI.
     pub display_name: Option<CrateDisplayName>,
-    pub cfg_options: CfgOptions,
+    pub cfg_options: Arc<CfgOptions>,
     /// The cfg options that could be used by the crate
-    pub potential_cfg_options: Option<CfgOptions>,
+    pub potential_cfg_options: Option<Arc<CfgOptions>>,
     pub env: Env,
     pub dependencies: Vec<Dependency>,
     pub origin: CrateOrigin,
@@ -328,8 +328,8 @@ impl CrateGraph {
         edition: Edition,
         display_name: Option<CrateDisplayName>,
         version: Option<String>,
-        cfg_options: CfgOptions,
-        potential_cfg_options: Option<CfgOptions>,
+        cfg_options: Arc<CfgOptions>,
+        potential_cfg_options: Option<Arc<CfgOptions>>,
         env: Env,
         is_proc_macro: bool,
         origin: CrateOrigin,
diff --git a/crates/flycheck/src/lib.rs b/crates/flycheck/src/lib.rs
index fe8e882bf6..4ee86954ac 100644
--- a/crates/flycheck/src/lib.rs
+++ b/crates/flycheck/src/lib.rs
@@ -41,50 +41,19 @@ pub enum InvocationLocation {
     Workspace,
 }
 
-#[derive(Clone, Debug, PartialEq, Eq)]
-pub struct CargoOptions {
-    pub target_triples: Vec<String>,
-    pub all_targets: bool,
-    pub no_default_features: bool,
-    pub all_features: bool,
-    pub features: Vec<String>,
-    pub extra_args: Vec<String>,
-    pub extra_env: FxHashMap<String, String>,
-    pub target_dir: Option<Utf8PathBuf>,
-}
-
-impl CargoOptions {
-    fn apply_on_command(&self, cmd: &mut Command) {
-        for target in &self.target_triples {
-            cmd.args(["--target", target.as_str()]);
-        }
-        if self.all_targets {
-            cmd.arg("--all-targets");
-        }
-        if self.all_features {
-            cmd.arg("--all-features");
-        } else {
-            if self.no_default_features {
-                cmd.arg("--no-default-features");
-            }
-            if !self.features.is_empty() {
-                cmd.arg("--features");
-                cmd.arg(self.features.join(" "));
-            }
-        }
-        if let Some(target_dir) = &self.target_dir {
-            cmd.arg("--target-dir").arg(target_dir);
-        }
-        cmd.envs(&self.extra_env);
-    }
-}
-
 #[derive(Clone, Debug, PartialEq, Eq)]
 pub enum FlycheckConfig {
     CargoCommand {
         command: String,
-        options: CargoOptions,
+        target_triples: Vec<String>,
+        all_targets: bool,
+        no_default_features: bool,
+        all_features: bool,
+        features: Vec<String>,
+        extra_args: Vec<String>,
+        extra_env: FxHashMap<String, String>,
         ansi_color_output: bool,
+        target_dir: Option<Utf8PathBuf>,
     },
     CustomCommand {
         command: String,
@@ -363,7 +332,18 @@ impl FlycheckActor {
         saved_file: Option<&AbsPath>,
     ) -> Option<Command> {
         let (mut cmd, args) = match &self.config {
-            FlycheckConfig::CargoCommand { command, options, ansi_color_output } => {
+            FlycheckConfig::CargoCommand {
+                command,
+                target_triples,
+                no_default_features,
+                all_targets,
+                all_features,
+                extra_args,
+                features,
+                extra_env,
+                ansi_color_output,
+                target_dir,
+            } => {
                 let mut cmd = Command::new(Tool::Cargo.path());
                 if let Some(sysroot_root) = &self.sysroot_root {
                     cmd.env("RUSTUP_TOOLCHAIN", AsRef::<std::path::Path>::as_ref(sysroot_root));
@@ -385,8 +365,28 @@ impl FlycheckActor {
                 cmd.arg("--manifest-path");
                 cmd.arg(self.root.join("Cargo.toml"));
 
-                options.apply_on_command(&mut cmd);
-                (cmd, options.extra_args.clone())
+                for target in target_triples {
+                    cmd.args(["--target", target.as_str()]);
+                }
+                if *all_targets {
+                    cmd.arg("--all-targets");
+                }
+                if *all_features {
+                    cmd.arg("--all-features");
+                } else {
+                    if *no_default_features {
+                        cmd.arg("--no-default-features");
+                    }
+                    if !features.is_empty() {
+                        cmd.arg("--features");
+                        cmd.arg(features.join(" "));
+                    }
+                }
+                if let Some(target_dir) = target_dir {
+                    cmd.arg("--target-dir").arg(target_dir);
+                }
+                cmd.envs(extra_env);
+                (cmd, extra_args.clone())
             }
             FlycheckConfig::CustomCommand {
                 command,
diff --git a/crates/hir-def/src/data.rs b/crates/hir-def/src/data.rs
index da790f1151..b5317be288 100644
--- a/crates/hir-def/src/data.rs
+++ b/crates/hir-def/src/data.rs
@@ -737,7 +737,7 @@ impl<'a> AssocItemCollector<'a> {
                     &AstIdWithPath::new(file_id, ast_id, Clone::clone(path)),
                     ctxt,
                     expand_to,
-                    self.expander.module.krate(),
+                    self.expander.krate(),
                     resolver,
                 ) {
                     Ok(Some(call_id)) => {
diff --git a/crates/hir-def/src/data/adt.rs b/crates/hir-def/src/data/adt.rs
index a7461b78af..5330db7c80 100644
--- a/crates/hir-def/src/data/adt.rs
+++ b/crates/hir-def/src/data/adt.rs
@@ -191,8 +191,6 @@ impl StructData {
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
-
         let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
 
         let mut flags = StructFlags::NO_FLAGS;
@@ -219,7 +217,7 @@ impl StructData {
             loc.id.file_id(),
             loc.container.local_id,
             &item_tree,
-            &cfg_options,
+            &db.crate_graph()[krate].cfg_options,
             &strukt.fields,
             None,
         );
@@ -248,8 +246,6 @@ impl StructData {
         let krate = loc.container.krate;
         let item_tree = loc.id.item_tree(db);
         let repr = repr_from_value(db, krate, &item_tree, ModItem::from(loc.id.value).into());
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
-
         let attrs = item_tree.attrs(db, krate, ModItem::from(loc.id.value).into());
         let mut flags = StructFlags::NO_FLAGS;
         if attrs.by_key("rustc_has_incoherent_inherent_impls").exists() {
@@ -266,7 +262,7 @@ impl StructData {
             loc.id.file_id(),
             loc.container.local_id,
             &item_tree,
-            &cfg_options,
+            &db.crate_graph()[krate].cfg_options,
             &union.fields,
             None,
         );
@@ -338,7 +334,6 @@ impl EnumVariantData {
         let container = loc.parent.lookup(db).container;
         let krate = container.krate;
         let item_tree = loc.id.item_tree(db);
-        let cfg_options = db.crate_graph()[krate].cfg_options.clone();
         let variant = &item_tree[loc.id.value];
 
         let (var_data, diagnostics) = lower_fields(
@@ -347,7 +342,7 @@ impl EnumVariantData {
             loc.id.file_id(),
             container.local_id,
             &item_tree,
-            &cfg_options,
+            &db.crate_graph()[krate].cfg_options,
             &variant.fields,
             Some(item_tree[loc.parent.lookup(db).id.value].visibility),
         );
diff --git a/crates/hir-def/src/expander.rs b/crates/hir-def/src/expander.rs
index b0872fcdc0..73ce942c58 100644
--- a/crates/hir-def/src/expander.rs
+++ b/crates/hir-def/src/expander.rs
@@ -11,6 +11,7 @@ use hir_expand::{
 };
 use limit::Limit;
 use syntax::{ast, Parse};
+use triomphe::Arc;
 
 use crate::{
     attr::Attrs, db::DefDatabase, lower::LowerCtx, path::Path, AsMacroCall, MacroId, ModuleId,
@@ -19,9 +20,8 @@ use crate::{
 
 #[derive(Debug)]
 pub struct Expander {
-    cfg_options: CfgOptions,
+    cfg_options: Arc<CfgOptions>,
     span_map: OnceCell<SpanMap>,
-    krate: CrateId,
     current_file_id: HirFileId,
     pub(crate) module: ModuleId,
     /// `recursion_depth == usize::MAX` indicates that the recursion limit has been reached.
@@ -45,10 +45,13 @@ impl Expander {
             recursion_limit,
             cfg_options: db.crate_graph()[module.krate].cfg_options.clone(),
             span_map: OnceCell::new(),
-            krate: module.krate,
         }
     }
 
+    pub fn krate(&self) -> CrateId {
+        self.module.krate
+    }
+
     pub fn enter_expand<T: ast::AstNode>(
         &mut self,
         db: &dyn DefDatabase,
@@ -112,7 +115,7 @@ impl Expander {
     pub(crate) fn parse_attrs(&self, db: &dyn DefDatabase, owner: &dyn ast::HasAttrs) -> Attrs {
         Attrs::filter(
             db,
-            self.krate,
+            self.krate(),
             RawAttrs::new(
                 db.upcast(),
                 owner,
diff --git a/crates/hir-def/src/generics.rs b/crates/hir-def/src/generics.rs
index 118055b605..acc60e1d9e 100644
--- a/crates/hir-def/src/generics.rs
+++ b/crates/hir-def/src/generics.rs
@@ -3,13 +3,15 @@
 //! generic parameters. See also the `Generics` type and the `generics_of` query
 //! in rustc.
 
+use std::ops;
+
 use either::Either;
 use hir_expand::{
     name::{AsName, Name},
     ExpandResult,
 };
 use intern::Interned;
-use la_arena::{Arena, Idx};
+use la_arena::Arena;
 use once_cell::unsync::Lazy;
 use stdx::impl_from;
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
@@ -23,7 +25,7 @@ use crate::{
     nameres::{DefMap, MacroSubNs},
     type_ref::{ConstRef, LifetimeRef, TypeBound, TypeRef},
     AdtId, ConstParamId, GenericDefId, HasModule, ItemTreeLoc, LifetimeParamId,
-    LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
+    LocalLifetimeParamId, LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
 };
 
 /// Data about a generic type parameter (to a function, struct, impl, ...).
@@ -158,6 +160,20 @@ pub struct GenericParams {
     pub where_predicates: Box<[WherePredicate]>,
 }
 
+impl ops::Index<LocalTypeOrConstParamId> for GenericParams {
+    type Output = TypeOrConstParamData;
+    fn index(&self, index: LocalTypeOrConstParamId) -> &TypeOrConstParamData {
+        &self.type_or_consts[index]
+    }
+}
+
+impl ops::Index<LocalLifetimeParamId> for GenericParams {
+    type Output = LifetimeParamData;
+    fn index(&self, index: LocalLifetimeParamId) -> &LifetimeParamData {
+        &self.lifetimes[index]
+    }
+}
+
 /// A single predicate from a where clause, i.e. `where Type: Trait`. Combined
 /// where clauses like `where T: Foo + Bar` are turned into multiple of these.
 /// It might still result in multiple actual predicates though, because of
@@ -199,7 +215,7 @@ impl GenericParamsCollector {
         lower_ctx: &LowerCtx<'_>,
         node: &dyn HasGenericParams,
         add_param_attrs: impl FnMut(
-            Either<Idx<TypeOrConstParamData>, Idx<LifetimeParamData>>,
+            Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
             ast::GenericParam,
         ),
     ) {
@@ -227,7 +243,7 @@ impl GenericParamsCollector {
         lower_ctx: &LowerCtx<'_>,
         params: ast::GenericParamList,
         mut add_param_attrs: impl FnMut(
-            Either<Idx<TypeOrConstParamData>, Idx<LifetimeParamData>>,
+            Either<LocalTypeOrConstParamId, LocalLifetimeParamId>,
             ast::GenericParam,
         ),
     ) {
@@ -416,16 +432,16 @@ impl GenericParams {
     }
 
     /// Iterator of type_or_consts field
-    pub fn iter(
+    pub fn iter_type_or_consts(
         &self,
-    ) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
+    ) -> impl DoubleEndedIterator<Item = (LocalTypeOrConstParamId, &TypeOrConstParamData)> {
         self.type_or_consts.iter()
     }
 
     /// Iterator of lifetimes field
     pub fn iter_lt(
         &self,
-    ) -> impl DoubleEndedIterator<Item = (Idx<LifetimeParamData>, &LifetimeParamData)> {
+    ) -> impl DoubleEndedIterator<Item = (LocalLifetimeParamId, &LifetimeParamData)> {
         self.lifetimes.iter()
     }
 
diff --git a/crates/hir-ty/src/consteval.rs b/crates/hir-ty/src/consteval.rs
index 705609ba68..f09277a92e 100644
--- a/crates/hir-ty/src/consteval.rs
+++ b/crates/hir-ty/src/consteval.rs
@@ -77,30 +77,32 @@ pub(crate) fn path_to_const(
     resolver: &Resolver,
     path: &Path,
     mode: ParamLoweringMode,
-    args_lazy: impl FnOnce() -> Generics,
+    args: impl FnOnce() -> Option<Generics>,
     debruijn: DebruijnIndex,
     expected_ty: Ty,
 ) -> Option<Const> {
     match resolver.resolve_path_in_value_ns_fully(db.upcast(), path) {
         Some(ValueNs::GenericParam(p)) => {
             let ty = db.const_param_ty(p);
-            let args = args_lazy();
             let value = match mode {
                 ParamLoweringMode::Placeholder => {
                     ConstValue::Placeholder(to_placeholder_idx(db, p.into()))
                 }
-                ParamLoweringMode::Variable => match args.param_idx(p.into()) {
-                    Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
-                    None => {
-                        never!(
-                            "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
-                            args,
-                            path,
-                            p
-                        );
-                        return None;
+                ParamLoweringMode::Variable => {
+                    let args = args();
+                    match args.as_ref().and_then(|args| args.type_or_const_param_idx(p.into())) {
+                        Some(it) => ConstValue::BoundVar(BoundVar::new(debruijn, it)),
+                        None => {
+                            never!(
+                                "Generic list doesn't contain this param: {:?}, {:?}, {:?}",
+                                args,
+                                path,
+                                p
+                            );
+                            return None;
+                        }
                     }
-                },
+                }
             };
             Some(ConstData { ty, value }.intern(Interner))
         }
@@ -285,7 +287,6 @@ pub(crate) fn eval_to_const(
     expr: ExprId,
     mode: ParamLoweringMode,
     ctx: &mut InferenceContext<'_>,
-    args: impl FnOnce() -> Generics,
     debruijn: DebruijnIndex,
 ) -> Const {
     let db = ctx.db;
@@ -304,7 +305,9 @@ pub(crate) fn eval_to_const(
     }
     if let Expr::Path(p) = &ctx.body.exprs[expr] {
         let resolver = &ctx.resolver;
-        if let Some(c) = path_to_const(db, resolver, p, mode, args, debruijn, infer[expr].clone()) {
+        if let Some(c) =
+            path_to_const(db, resolver, p, mode, || ctx.generics(), debruijn, infer[expr].clone())
+        {
             return c;
         }
     }
diff --git a/crates/hir-ty/src/display.rs b/crates/hir-ty/src/display.rs
index eb7f106cdf..22a52e6a23 100644
--- a/crates/hir-ty/src/display.rs
+++ b/crates/hir-ty/src/display.rs
@@ -453,7 +453,7 @@ impl HirDisplay for Const {
             ConstValue::Placeholder(idx) => {
                 let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params.type_or_consts[id.local_id];
+                let param_data = &generics.params[id.local_id];
                 write!(f, "{}", param_data.name().unwrap().display(f.db.upcast()))?;
                 Ok(())
             }
@@ -1176,7 +1176,7 @@ impl HirDisplay for Ty {
             TyKind::Placeholder(idx) => {
                 let id = from_placeholder_idx(db, *idx);
                 let generics = generics(db.upcast(), id.parent);
-                let param_data = &generics.params.type_or_consts[id.local_id];
+                let param_data = &generics.params[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
@@ -1724,7 +1724,7 @@ impl HirDisplay for LifetimeData {
             LifetimeData::Placeholder(idx) => {
                 let id = lt_from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params.lifetimes[id.local_id];
+                let param_data = &generics.params[id.local_id];
                 write!(f, "{}", param_data.name.display(f.db.upcast()))?;
                 Ok(())
             }
diff --git a/crates/hir-ty/src/infer.rs b/crates/hir-ty/src/infer.rs
index 3b644379fa..3aacf7d07f 100644
--- a/crates/hir-ty/src/infer.rs
+++ b/crates/hir-ty/src/infer.rs
@@ -60,7 +60,7 @@ use crate::{
     lower::ImplTraitLoweringMode,
     to_assoc_type_id,
     traits::FnTrait,
-    utils::{InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
+    utils::{Generics, InTypeConstIdMetadata, UnevaluatedConstEvaluatorFolder},
     AliasEq, AliasTy, Binders, ClosureId, Const, DomainGoal, GenericArg, Goal, ImplTraitId,
     ImplTraitIdx, InEnvironment, Interner, Lifetime, OpaqueTyId, ProjectionTy, Substitution,
     TraitEnvironment, Ty, TyBuilder, TyExt,
@@ -630,6 +630,10 @@ impl<'a> InferenceContext<'a> {
         }
     }
 
+    pub(crate) fn generics(&self) -> Option<Generics> {
+        Some(crate::utils::generics(self.db.upcast(), self.resolver.generic_def()?))
+    }
+
     // FIXME: This function should be private in module. It is currently only used in the consteval, since we need
     // `InferenceResult` in the middle of inference. See the fixme comment in `consteval::eval_to_const`. If you
     // used this function for another workaround, mention it here. If you really need this function and believe that
diff --git a/crates/hir-ty/src/infer/cast.rs b/crates/hir-ty/src/infer/cast.rs
index f8c03ee288..060b5f36f2 100644
--- a/crates/hir-ty/src/infer/cast.rs
+++ b/crates/hir-ty/src/infer/cast.rs
@@ -19,10 +19,6 @@ impl CastCheck {
         let expr_ty = table.resolve_ty_shallow(&self.expr_ty);
         let cast_ty = table.resolve_ty_shallow(&self.cast_ty);
 
-        if expr_ty.contains_unknown() || cast_ty.contains_unknown() {
-            return;
-        }
-
         if table.coerce(&expr_ty, &cast_ty).is_ok() {
             return;
         }
diff --git a/crates/hir-ty/src/infer/closure.rs b/crates/hir-ty/src/infer/closure.rs
index 20d24e6fe2..a25498eff3 100644
--- a/crates/hir-ty/src/infer/closure.rs
+++ b/crates/hir-ty/src/infer/closure.rs
@@ -26,7 +26,7 @@ use crate::{
     mir::{BorrowKind, MirSpan, MutBorrowKind, ProjectionElem},
     to_chalk_trait_id,
     traits::FnTrait,
-    utils::{self, elaborate_clause_supertraits, generics, Generics},
+    utils::{self, elaborate_clause_supertraits, Generics},
     Adjust, Adjustment, AliasEq, AliasTy, Binders, BindingMode, ChalkTraitId, ClosureId, DynTy,
     DynTyExt, FnAbi, FnPointer, FnSig, Interner, OpaqueTy, ProjectionTyExt, Substitution, Ty,
     TyExt, WhereClause,
@@ -331,14 +331,10 @@ impl CapturedItemWithoutTy {
             place: self.place,
             kind: self.kind,
             span: self.span,
-            ty: replace_placeholder_with_binder(ctx.db, ctx.owner, ty),
+            ty: replace_placeholder_with_binder(ctx, ty),
         };
 
-        fn replace_placeholder_with_binder(
-            db: &dyn HirDatabase,
-            owner: DefWithBodyId,
-            ty: Ty,
-        ) -> Binders<Ty> {
+        fn replace_placeholder_with_binder(ctx: &mut InferenceContext<'_>, ty: Ty) -> Binders<Ty> {
             struct Filler<'a> {
                 db: &'a dyn HirDatabase,
                 generics: Generics,
@@ -361,7 +357,7 @@ impl CapturedItemWithoutTy {
                     outer_binder: DebruijnIndex,
                 ) -> Result<chalk_ir::Const<Interner>, Self::Error> {
                     let x = from_placeholder_idx(self.db, idx);
-                    let Some(idx) = self.generics.param_idx(x) else {
+                    let Some(idx) = self.generics.type_or_const_param_idx(x) else {
                         return Err(());
                     };
                     Ok(BoundVar::new(outer_binder, idx).to_const(Interner, ty))
@@ -373,18 +369,18 @@ impl CapturedItemWithoutTy {
                     outer_binder: DebruijnIndex,
                 ) -> std::result::Result<Ty, Self::Error> {
                     let x = from_placeholder_idx(self.db, idx);
-                    let Some(idx) = self.generics.param_idx(x) else {
+                    let Some(idx) = self.generics.type_or_const_param_idx(x) else {
                         return Err(());
                     };
                     Ok(BoundVar::new(outer_binder, idx).to_ty(Interner))
                 }
             }
-            let Some(generic_def) = owner.as_generic_def_id() else {
+            let Some(generics) = ctx.generics() else {
                 return Binders::empty(Interner, ty);
             };
-            let filler = &mut Filler { db, generics: generics(db.upcast(), generic_def) };
+            let filler = &mut Filler { db: ctx.db, generics };
             let result = ty.clone().try_fold_with(filler, DebruijnIndex::INNERMOST).unwrap_or(ty);
-            make_binders(db, &filler.generics, result)
+            make_binders(ctx.db, &filler.generics, result)
         }
     }
 }
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 4d3d7376c4..d011a62e77 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -1040,18 +1040,12 @@ impl InferenceContext<'_> {
 
                 (
                     elem_ty,
-                    if let Some(g_def) = self.owner.as_generic_def_id() {
-                        let generics = generics(self.db.upcast(), g_def);
-                        consteval::eval_to_const(
-                            repeat,
-                            ParamLoweringMode::Placeholder,
-                            self,
-                            || generics,
-                            DebruijnIndex::INNERMOST,
-                        )
-                    } else {
-                        consteval::usize_const(self.db, None, krate)
-                    },
+                    consteval::eval_to_const(
+                        repeat,
+                        ParamLoweringMode::Placeholder,
+                        self,
+                        DebruijnIndex::INNERMOST,
+                    ),
                 )
             }
         };
@@ -1852,7 +1846,7 @@ impl InferenceContext<'_> {
                             ty,
                             c,
                             ParamLoweringMode::Placeholder,
-                            || generics(this.db.upcast(), this.resolver.generic_def().unwrap()),
+                            || this.generics(),
                             DebruijnIndex::INNERMOST,
                         )
                     },
diff --git a/crates/hir-ty/src/infer/pat.rs b/crates/hir-ty/src/infer/pat.rs
index 440ffa3357..1b354935a5 100644
--- a/crates/hir-ty/src/infer/pat.rs
+++ b/crates/hir-ty/src/infer/pat.rs
@@ -2,13 +2,13 @@
 
 use std::iter::repeat_with;
 
-use chalk_ir::Mutability;
 use hir_def::{
     body::Body,
     hir::{Binding, BindingAnnotation, BindingId, Expr, ExprId, ExprOrPatId, Literal, Pat, PatId},
     path::Path,
 };
 use hir_expand::name::Name;
+use stdx::TupleExt;
 
 use crate::{
     consteval::{try_const_usize, usize_const},
@@ -16,8 +16,8 @@ use crate::{
     infer::{BindingMode, Expectation, InferenceContext, TypeMismatch},
     lower::lower_to_chalk_mutability,
     primitive::UintTy,
-    static_lifetime, InferenceDiagnostic, Interner, Scalar, Substitution, Ty, TyBuilder, TyExt,
-    TyKind,
+    static_lifetime, InferenceDiagnostic, Interner, Mutability, Scalar, Substitution, Ty,
+    TyBuilder, TyExt, TyKind,
 };
 
 /// Used to generalize patterns and assignee expressions.
@@ -90,9 +90,6 @@ impl InferenceContext<'_> {
 
         self.unify(&ty, expected);
 
-        let substs =
-            ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
-
         match def {
             _ if subs.is_empty() => {}
             Some(def) => {
@@ -109,8 +106,10 @@ impl InferenceContext<'_> {
                 let pre_iter = pre.iter().enumerate();
                 let post_iter = (post_idx_offset..).zip(post.iter());
 
+                let substs = ty.as_adt().map(TupleExt::tail);
+
                 for (i, &subpat) in pre_iter.chain(post_iter) {
-                    let field_def = {
+                    let expected_ty = {
                         match variant_data.field(&Name::new_tuple_field(i)) {
                             Some(local_id) => {
                                 if !visibilities[local_id]
@@ -118,17 +117,17 @@ impl InferenceContext<'_> {
                                 {
                                     // FIXME(DIAGNOSE): private tuple field
                                 }
-                                Some(local_id)
+                                let f = field_types[local_id].clone();
+                                let expected_ty = match substs {
+                                    Some(substs) => f.substitute(Interner, substs),
+                                    None => f.substitute(Interner, &Substitution::empty(Interner)),
+                                };
+                                self.normalize_associated_types_in(expected_ty)
                             }
-                            None => None,
+                            None => self.err_ty(),
                         }
                     };
 
-                    let expected_ty = field_def.map_or(self.err_ty(), |f| {
-                        field_types[f].clone().substitute(Interner, &substs)
-                    });
-                    let expected_ty = self.normalize_associated_types_in(expected_ty);
-
                     T::infer(self, subpat, &expected_ty, default_bm);
                 }
             }
@@ -159,9 +158,6 @@ impl InferenceContext<'_> {
 
         self.unify(&ty, expected);
 
-        let substs =
-            ty.as_adt().map(|(_, s)| s.clone()).unwrap_or_else(|| Substitution::empty(Interner));
-
         match def {
             _ if subs.len() == 0 => {}
             Some(def) => {
@@ -169,8 +165,10 @@ impl InferenceContext<'_> {
                 let variant_data = def.variant_data(self.db.upcast());
                 let visibilities = self.db.field_visibilities(def);
 
+                let substs = ty.as_adt().map(TupleExt::tail);
+
                 for (name, inner) in subs {
-                    let field_def = {
+                    let expected_ty = {
                         match variant_data.field(&name) {
                             Some(local_id) => {
                                 if !visibilities[local_id]
@@ -181,23 +179,23 @@ impl InferenceContext<'_> {
                                         private: true,
                                     });
                                 }
-                                Some(local_id)
+                                let f = field_types[local_id].clone();
+                                let expected_ty = match substs {
+                                    Some(substs) => f.substitute(Interner, substs),
+                                    None => f.substitute(Interner, &Substitution::empty(Interner)),
+                                };
+                                self.normalize_associated_types_in(expected_ty)
                             }
                             None => {
                                 self.push_diagnostic(InferenceDiagnostic::NoSuchField {
                                     field: inner.into(),
                                     private: false,
                                 });
-                                None
+                                self.err_ty()
                             }
                         }
                     };
 
-                    let expected_ty = field_def.map_or(self.err_ty(), |f| {
-                        field_types[f].clone().substitute(Interner, &substs)
-                    });
-                    let expected_ty = self.normalize_associated_types_in(expected_ty);
-
                     T::infer(self, inner, &expected_ty, default_bm);
                 }
             }
diff --git a/crates/hir-ty/src/lib.rs b/crates/hir-ty/src/lib.rs
index ad8202d4d2..b12ccf7c83 100644
--- a/crates/hir-ty/src/lib.rs
+++ b/crates/hir-ty/src/lib.rs
@@ -288,7 +288,7 @@ impl Hash for ConstScalar {
 
 /// Return an index of a parameter in the generic type parameter list by it's id.
 pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
-    generics(db.upcast(), id.parent).param_idx(id)
+    generics(db.upcast(), id.parent).type_or_const_param_idx(id)
 }
 
 pub(crate) fn wrap_empty_binders<T>(value: T) -> Binders<T>
@@ -603,15 +603,17 @@ pub enum ImplTraitId {
 }
 impl_intern_value_trivial!(ImplTraitId);
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(PartialEq, Eq, Debug, Hash)]
 pub struct ImplTraits {
     pub(crate) impl_traits: Arena<ImplTrait>,
 }
 
 has_interner!(ImplTraits);
 
-#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+#[derive(PartialEq, Eq, Debug, Hash)]
 pub struct ImplTrait {
+    // FIXME: Should be Arc<[QuantifiedWhereClause]>, but the HasInterner impl for Arc is missing a
+    // ?Sized bound
     pub(crate) bounds: Binders<Vec<QuantifiedWhereClause>>,
 }
 
diff --git a/crates/hir-ty/src/lower.rs b/crates/hir-ty/src/lower.rs
index 9a468e2a23..bfc84ee5e3 100644
--- a/crates/hir-ty/src/lower.rs
+++ b/crates/hir-ty/src/lower.rs
@@ -62,8 +62,8 @@ use crate::{
     mapping::{from_chalk_trait_id, lt_to_placeholder_idx, ToChalk},
     static_lifetime, to_assoc_type_id, to_chalk_trait_id, to_placeholder_idx,
     utils::{
-        all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
-        InTypeConstIdMetadata,
+        self, all_super_trait_refs, associated_type_by_name_including_super_traits, generics,
+        Generics, InTypeConstIdMetadata,
     },
     AliasEq, AliasTy, Binders, BoundVar, CallableSig, Const, ConstScalar, DebruijnIndex, DynTy,
     FnAbi, FnPointer, FnSig, FnSubst, ImplTrait, ImplTraitId, ImplTraits, Interner, Lifetime,
@@ -245,13 +245,8 @@ impl<'a> TyLoweringContext<'a> {
         )
     }
 
-    fn generics(&self) -> Generics {
-        generics(
-            self.db.upcast(),
-            self.resolver
-                .generic_def()
-                .expect("there should be generics if there's a generic param"),
-        )
+    fn generics(&self) -> Option<Generics> {
+        Some(generics(self.db.upcast(), self.resolver.generic_def()?))
     }
 
     pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
@@ -321,7 +316,7 @@ impl<'a> TyLoweringContext<'a> {
                         // place even if we encounter more opaque types while
                         // lowering the bounds
                         let idx = opaque_type_data.borrow_mut().alloc(ImplTrait {
-                            bounds: crate::make_single_type_binders(Vec::new()),
+                            bounds: crate::make_single_type_binders(Vec::default()),
                         });
                         // We don't want to lower the bounds inside the binders
                         // we're currently in, because they don't end up inside
@@ -352,8 +347,7 @@ impl<'a> TyLoweringContext<'a> {
                         let idx = counter.get();
                         // FIXME we're probably doing something wrong here
                         counter.set(idx + count_impl_traits(type_ref) as u16);
-                        if let Some(def) = self.resolver.generic_def() {
-                            let generics = generics(self.db.upcast(), def);
+                        if let Some(generics) = self.generics() {
                             let param = generics
                                 .iter()
                                 .filter(|(_, data)| {
@@ -388,8 +382,7 @@ impl<'a> TyLoweringContext<'a> {
                             const_params,
                             _impl_trait_params,
                             _lifetime_params,
-                        ) = if let Some(def) = self.resolver.generic_def() {
-                            let generics = generics(self.db.upcast(), def);
+                        ) = if let Some(generics) = self.generics() {
                             generics.provenance_split()
                         } else {
                             (0, 0, 0, 0, 0, 0)
@@ -577,44 +570,40 @@ impl<'a> TyLoweringContext<'a> {
                 // FIXME(trait_alias): Implement trait alias.
                 return (TyKind::Error.intern(Interner), None);
             }
-            TypeNs::GenericParam(param_id) => {
-                let generics = generics(
-                    self.db.upcast(),
-                    self.resolver.generic_def().expect("generics in scope"),
-                );
-                match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
-                        TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
-                    }
-                    ParamLoweringMode::Variable => {
-                        let idx = match generics.param_idx(param_id.into()) {
-                            None => {
-                                never!("no matching generics");
-                                return (TyKind::Error.intern(Interner), None);
-                            }
-                            Some(idx) => idx,
-                        };
+            TypeNs::GenericParam(param_id) => match self.type_param_mode {
+                ParamLoweringMode::Placeholder => {
+                    TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
+                }
+                ParamLoweringMode::Variable => {
+                    let idx = match self
+                        .generics()
+                        .expect("generics in scope")
+                        .type_or_const_param_idx(param_id.into())
+                    {
+                        None => {
+                            never!("no matching generics");
+                            return (TyKind::Error.intern(Interner), None);
+                        }
+                        Some(idx) => idx,
+                    };
 
-                        TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
-                    }
+                    TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
                 }
-                .intern(Interner)
             }
+            .intern(Interner),
             TypeNs::SelfType(impl_id) => {
-                let def =
-                    self.resolver.generic_def().expect("impl should have generic param scope");
-                let generics = generics(self.db.upcast(), def);
+                let generics = self.generics().expect("impl should have generic param scope");
 
                 match self.type_param_mode {
                     ParamLoweringMode::Placeholder => {
                         // `def` can be either impl itself or item within, and we need impl itself
                         // now.
-                        let generics = generics.parent_generics().unwrap_or(&generics);
+                        let generics = generics.parent_or_self();
                         let subst = generics.placeholder_subst(self.db);
                         self.db.impl_self_ty(impl_id).substitute(Interner, &subst)
                     }
                     ParamLoweringMode::Variable => {
-                        let starting_from = match def {
+                        let starting_from = match generics.def() {
                             GenericDefId::ImplId(_) => 0,
                             // `def` is an item within impl. We need to substitute `BoundVar`s but
                             // remember that they are for parent (i.e. impl) generic params so they
@@ -682,12 +671,12 @@ impl<'a> TyLoweringContext<'a> {
     }
 
     fn select_associated_type(&self, res: Option<TypeNs>, segment: PathSegment<'_>) -> Ty {
-        let Some((def, res)) = self.resolver.generic_def().zip(res) else {
+        let Some((generics, res)) = self.generics().zip(res) else {
             return TyKind::Error.intern(Interner);
         };
         let ty = named_associated_type_shorthand_candidates(
             self.db,
-            def,
+            generics.def(),
             res,
             Some(segment.name.clone()),
             move |name, t, associated_ty| {
@@ -699,7 +688,6 @@ impl<'a> TyLoweringContext<'a> {
                 let parent_subst = match self.type_param_mode {
                     ParamLoweringMode::Placeholder => {
                         // if we're lowering to placeholders, we have to put them in now.
-                        let generics = generics(self.db.upcast(), def);
                         let s = generics.placeholder_subst(self.db);
                         s.apply(parent_subst, Interner)
                     }
@@ -721,7 +709,7 @@ impl<'a> TyLoweringContext<'a> {
                     None,
                 );
 
-                let len_self = generics(self.db.upcast(), associated_ty.into()).len_self();
+                let len_self = utils::generics(self.db.upcast(), associated_ty.into()).len_self();
 
                 let substs = Substitution::from_iter(
                     Interner,
@@ -1019,46 +1007,43 @@ impl<'a> TyLoweringContext<'a> {
         self.substs_from_path_segment(segment, Some(resolved.into()), false, explicit_self_ty)
     }
 
-    pub(crate) fn lower_where_predicate(
-        &self,
-        where_predicate: &WherePredicate,
+    pub(crate) fn lower_where_predicate<'b>(
+        &'b self,
+        where_predicate: &'b WherePredicate,
         ignore_bindings: bool,
-    ) -> impl Iterator<Item = QuantifiedWhereClause> {
+    ) -> impl Iterator<Item = QuantifiedWhereClause> + 'b {
         match where_predicate {
             WherePredicate::ForLifetime { target, bound, .. }
             | WherePredicate::TypeBound { target, bound } => {
                 let self_ty = match target {
                     WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
-                    WherePredicateTypeTarget::TypeOrConstParam(param_id) => {
-                        let generic_def = self.resolver.generic_def().expect("generics in scope");
-                        let generics = generics(self.db.upcast(), generic_def);
-                        let param_id = hir_def::TypeOrConstParamId {
-                            parent: generic_def,
-                            local_id: *param_id,
-                        };
-                        let placeholder = to_placeholder_idx(self.db, param_id);
+                    &WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
+                        let def = self.resolver.generic_def().expect("generics in scope");
+                        let param_id = hir_def::TypeOrConstParamId { parent: def, local_id };
                         match self.type_param_mode {
-                            ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
+                            ParamLoweringMode::Placeholder => {
+                                TyKind::Placeholder(to_placeholder_idx(self.db, param_id))
+                            }
                             ParamLoweringMode::Variable => {
-                                let idx = generics.param_idx(param_id).expect("matching generics");
+                                let idx = generics(self.db.upcast(), def)
+                                    .type_or_const_param_idx(param_id)
+                                    .expect("matching generics");
                                 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
                             }
                         }
                         .intern(Interner)
                     }
                 };
-                self.lower_type_bound(bound, self_ty, ignore_bindings)
-                    .collect::<Vec<_>>()
-                    .into_iter()
+                Either::Left(self.lower_type_bound(bound, self_ty, ignore_bindings))
             }
-            WherePredicate::Lifetime { bound, target } => {
-                vec![crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives {
+            WherePredicate::Lifetime { bound, target } => Either::Right(iter::once(
+                crate::wrap_empty_binders(WhereClause::LifetimeOutlives(LifetimeOutlives {
                     a: self.lower_lifetime(bound),
                     b: self.lower_lifetime(target),
-                }))]
-                .into_iter()
-            }
+                })),
+            )),
         }
+        .into_iter()
     }
 
     pub(crate) fn lower_type_bound(
@@ -1218,8 +1203,8 @@ impl<'a> TyLoweringContext<'a> {
                                     });
                                 if let Some(target_param_idx) = target_param_idx {
                                     let mut counter = 0;
-                                    for (idx, data) in self.generics().params.type_or_consts.iter()
-                                    {
+                                    let generics = self.generics().expect("generics in scope");
+                                    for (idx, data) in generics.params.type_or_consts.iter() {
                                         // Count the number of `impl Trait` things that appear before
                                         // the target of our `bound`.
                                         // Our counter within `impl_trait_mode` should be that number
@@ -1393,8 +1378,8 @@ impl<'a> TyLoweringContext<'a> {
                     crate::wrap_empty_binders(clause)
                 });
                 predicates.extend(sized_clause);
-                predicates.shrink_to_fit();
             }
+            predicates.shrink_to_fit();
             predicates
         });
         ImplTrait { bounds: crate::make_single_type_binders(predicates) }
@@ -1409,10 +1394,7 @@ impl<'a> TyLoweringContext<'a> {
                         LifetimeData::Placeholder(lt_to_placeholder_idx(self.db, id))
                     }
                     ParamLoweringMode::Variable => {
-                        let generics = generics(
-                            self.db.upcast(),
-                            self.resolver.generic_def().expect("generics in scope"),
-                        );
+                        let generics = self.generics().expect("generics in scope");
                         let idx = match generics.lifetime_idx(id) {
                             None => return error_lifetime(),
                             Some(idx) => idx,
@@ -1523,7 +1505,7 @@ fn named_associated_type_shorthand_candidates<R>(
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
                 let trait_generics = generics(db.upcast(), trait_id.into());
-                if trait_generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+                if trait_generics.params[param_id.local_id()].is_trait_self() {
                     let def_generics = generics(db.upcast(), def);
                     let starting_idx = match def {
                         GenericDefId::TraitId(_) => 0,
@@ -2258,7 +2240,7 @@ pub(crate) fn const_or_path_to_chalk(
     expected_ty: Ty,
     value: &ConstRef,
     mode: ParamLoweringMode,
-    args: impl FnOnce() -> Generics,
+    args: impl FnOnce() -> Option<Generics>,
     debruijn: DebruijnIndex,
 ) -> Const {
     match value {
@@ -2277,7 +2259,7 @@ pub(crate) fn const_or_path_to_chalk(
             .unwrap_or_else(|| unknown_const(expected_ty))
         }
         &ConstRef::Complex(it) => {
-            let crate_data = &db.crate_graph()[owner.module(db.upcast()).krate()];
+            let crate_data = &db.crate_graph()[resolver.krate()];
             if crate_data.env.get("__ra_is_test_fixture").is_none() && crate_data.origin.is_local()
             {
                 // FIXME: current `InTypeConstId` is very unstable, so we only use it in non local crate
diff --git a/crates/hir-ty/src/mir/lower.rs b/crates/hir-ty/src/mir/lower.rs
index ea311cadb7..c65dfd3285 100644
--- a/crates/hir-ty/src/mir/lower.rs
+++ b/crates/hir-ty/src/mir/lower.rs
@@ -495,9 +495,11 @@ impl<'ctx> MirLowerCtx<'ctx> {
                                     ty,
                                     value: chalk_ir::ConstValue::BoundVar(BoundVar::new(
                                         DebruijnIndex::INNERMOST,
-                                        gen.param_idx(p.into()).ok_or(MirLowerError::TypeError(
-                                            "fail to lower const generic param",
-                                        ))?,
+                                        gen.type_or_const_param_idx(p.into()).ok_or(
+                                            MirLowerError::TypeError(
+                                                "fail to lower const generic param",
+                                            ),
+                                        )?,
                                     )),
                                 }
                                 .intern(Interner),
diff --git a/crates/hir-ty/src/mir/monomorphization.rs b/crates/hir-ty/src/mir/monomorphization.rs
index d6557c3a81..a384c9306e 100644
--- a/crates/hir-ty/src/mir/monomorphization.rs
+++ b/crates/hir-ty/src/mir/monomorphization.rs
@@ -101,7 +101,7 @@ impl FallibleTypeFolder<Interner> for Filler<'_> {
         _outer_binder: DebruijnIndex,
     ) -> std::result::Result<chalk_ir::Const<Interner>, Self::Error> {
         let it = from_placeholder_idx(self.db, idx);
-        let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(it)) else {
+        let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else {
             not_supported!("missing idx in generics");
         };
         Ok(self
@@ -119,7 +119,7 @@ impl FallibleTypeFolder<Interner> for Filler<'_> {
         _outer_binder: DebruijnIndex,
     ) -> std::result::Result<Ty, Self::Error> {
         let it = from_placeholder_idx(self.db, idx);
-        let Some(idx) = self.generics.as_ref().and_then(|g| g.param_idx(it)) else {
+        let Some(idx) = self.generics.as_ref().and_then(|g| g.type_or_const_param_idx(it)) else {
             not_supported!("missing idx in generics");
         };
         Ok(self
diff --git a/crates/hir-ty/src/utils.rs b/crates/hir-ty/src/utils.rs
index afd4d1f271..42c7a84032 100644
--- a/crates/hir-ty/src/utils.rs
+++ b/crates/hir-ty/src/utils.rs
@@ -262,7 +262,7 @@ impl<'a> ClosureSubst<'a> {
     }
 }
 
-#[derive(Debug)]
+#[derive(Clone, Debug)]
 pub(crate) struct Generics {
     def: GenericDefId,
     pub(crate) params: Interned<GenericParams>,
@@ -274,6 +274,10 @@ impl Generics {
         self.iter().map(|(id, _)| id)
     }
 
+    pub(crate) fn def(&self) -> GenericDefId {
+        self.def
+    }
+
     /// Iterator over types and const params of self, then parent.
     pub(crate) fn iter<'a>(
         &'a self,
@@ -304,7 +308,11 @@ impl Generics {
         };
 
         let lt_iter = self.params.iter_lt().map(from_lt_id(self));
-        self.params.iter().map(from_toc_id(self)).chain(lt_iter).chain(self.iter_parent())
+        self.params
+            .iter_type_or_consts()
+            .map(from_toc_id(self))
+            .chain(lt_iter)
+            .chain(self.iter_parent())
     }
 
     /// Iterate over types and const params without parent params.
@@ -336,16 +344,19 @@ impl Generics {
             }
         };
 
-        self.params.iter().map(from_toc_id(self)).chain(self.params.iter_lt().map(from_lt_id(self)))
+        self.params
+            .iter_type_or_consts()
+            .map(from_toc_id(self))
+            .chain(self.params.iter_lt().map(from_lt_id(self)))
     }
 
     /// Iterator over types and const params of parent.
-    #[allow(clippy::needless_lifetimes)]
-    pub(crate) fn iter_parent<'a>(
-        &'a self,
-    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'a>)> + 'a {
+    pub(crate) fn iter_parent(
+        &self,
+    ) -> impl DoubleEndedIterator<Item = (GenericParamId, GenericParamDataRef<'_>)> + '_ {
         self.parent_generics().into_iter().flat_map(|it| {
-            let from_toc_id = move |(local_id, p): (_, &'a TypeOrConstParamData)| {
+            let from_toc_id = move |(local_id, p)| {
+                let p: &_ = p;
                 let id = TypeOrConstParamId { parent: it.def, local_id };
                 match p {
                     TypeOrConstParamData::TypeParamData(p) => (
@@ -359,14 +370,14 @@ impl Generics {
                 }
             };
 
-            let from_lt_id = move |(local_id, p): (_, &'a LifetimeParamData)| {
+            let from_lt_id = move |(local_id, p): (_, _)| {
                 (
                     GenericParamId::LifetimeParamId(LifetimeParamId { parent: it.def, local_id }),
                     GenericParamDataRef::LifetimeParamData(p),
                 )
             };
             let lt_iter = it.params.iter_lt().map(from_lt_id);
-            it.params.iter().map(from_toc_id).chain(lt_iter)
+            it.params.iter_type_or_consts().map(from_toc_id).chain(lt_iter)
         })
     }
 
@@ -383,7 +394,7 @@ impl Generics {
     }
 
     /// Returns number of generic parameter excluding those from parent
-    fn len_params(&self) -> usize {
+    fn len_type_and_const_params(&self) -> usize {
         self.params.type_or_consts.len()
     }
 
@@ -394,7 +405,7 @@ impl Generics {
         let mut impl_trait_params = 0;
         let mut const_params = 0;
         let mut lifetime_params = 0;
-        self.params.iter().for_each(|(_, data)| match data {
+        self.params.iter_type_or_consts().for_each(|(_, data)| match data {
             TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                 TypeParamProvenance::TypeParamList => type_params += 1,
                 TypeParamProvenance::TraitSelf => self_params += 1,
@@ -409,18 +420,23 @@ impl Generics {
         (parent_len, self_params, type_params, const_params, impl_trait_params, lifetime_params)
     }
 
-    pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
-        Some(self.find_param(param)?.0)
+    pub(crate) fn type_or_const_param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
+        Some(self.find_type_or_const_param(param)?.0)
     }
 
-    fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
+    fn find_type_or_const_param(
+        &self,
+        param: TypeOrConstParamId,
+    ) -> Option<(usize, &TypeOrConstParamData)> {
         if param.parent == self.def {
-            let (idx, (_local_id, data)) =
-                self.params.iter().enumerate().find(|(_, (idx, _))| *idx == param.local_id)?;
-            Some((idx, data))
+            let idx = param.local_id.into_raw().into_u32() as usize;
+            if idx >= self.params.type_or_consts.len() {
+                return None;
+            }
+            Some((idx, &self.params.type_or_consts[param.local_id]))
         } else {
             self.parent_generics()
-                .and_then(|g| g.find_param(param))
+                .and_then(|g| g.find_type_or_const_param(param))
                 // Remember that parent parameters come after parameters for self.
                 .map(|(idx, data)| (self.len_self() + idx, data))
         }
@@ -432,13 +448,14 @@ impl Generics {
 
     fn find_lifetime(&self, lifetime: LifetimeParamId) -> Option<(usize, &LifetimeParamData)> {
         if lifetime.parent == self.def {
-            let (idx, (_local_id, data)) = self
-                .params
-                .iter_lt()
-                .enumerate()
-                .find(|(_, (idx, _))| *idx == lifetime.local_id)?;
-
-            Some((self.len_params() + idx, data))
+            let idx = lifetime.local_id.into_raw().into_u32() as usize;
+            if idx >= self.params.lifetimes.len() {
+                return None;
+            }
+            Some((
+                self.len_type_and_const_params() + idx,
+                &self.params.lifetimes[lifetime.local_id],
+            ))
         } else {
             self.parent_generics()
                 .and_then(|g| g.find_lifetime(lifetime))
@@ -450,6 +467,10 @@ impl Generics {
         self.parent_generics.as_deref()
     }
 
+    pub(crate) fn parent_or_self(&self) -> &Generics {
+        self.parent_generics.as_deref().unwrap_or(self)
+    }
+
     /// Returns a Substitution that replaces each parameter by a bound variable.
     pub(crate) fn bound_vars_subst(
         &self,
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index 9b9f710d9a..8556d35a43 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -260,11 +260,11 @@ impl Crate {
         doc_url.map(|s| s.trim_matches('"').trim_end_matches('/').to_owned() + "/")
     }
 
-    pub fn cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
+    pub fn cfg(&self, db: &dyn HirDatabase) -> Arc<CfgOptions> {
         db.crate_graph()[self.id].cfg_options.clone()
     }
 
-    pub fn potential_cfg(&self, db: &dyn HirDatabase) -> CfgOptions {
+    pub fn potential_cfg(&self, db: &dyn HirDatabase) -> Arc<CfgOptions> {
         let data = &db.crate_graph()[self.id];
         data.potential_cfg_options.clone().unwrap_or_else(|| data.cfg_options.clone())
     }
@@ -653,7 +653,7 @@ impl Module {
                     GenericParamId::LifetimeParamId(LifetimeParamId { parent, local_id })
                 });
                 let type_params = generic_params
-                    .iter()
+                    .iter_type_or_consts()
                     .filter(|(_, it)| it.type_param().is_some())
                     .map(|(local_id, _)| {
                         GenericParamId::TypeParamId(TypeParamId::from_unchecked(
diff --git a/crates/ide/src/lib.rs b/crates/ide/src/lib.rs
index ad48d80389..e13060e4d7 100644
--- a/crates/ide/src/lib.rs
+++ b/crates/ide/src/lib.rs
@@ -252,7 +252,7 @@ impl Analysis {
             Edition::CURRENT,
             None,
             None,
-            cfg_options.clone(),
+            Arc::new(cfg_options),
             None,
             Env::default(),
             false,
diff --git a/crates/limit/Cargo.toml b/crates/limit/Cargo.toml
index c89722cc40..c1a768833b 100644
--- a/crates/limit/Cargo.toml
+++ b/crates/limit/Cargo.toml
@@ -10,7 +10,6 @@ rust-version.workspace = true
 
 [features]
 tracking = []
-default = ["tracking"]
 
 [lints]
-workspace = true
\ No newline at end of file
+workspace = true
diff --git a/crates/project-model/src/workspace.rs b/crates/project-model/src/workspace.rs
index b59c0d59e4..00e9c12988 100644
--- a/crates/project-model/src/workspace.rs
+++ b/crates/project-model/src/workspace.rs
@@ -913,12 +913,14 @@ fn project_json_to_crate_graph(
                     *edition,
                     display_name.clone(),
                     version.clone(),
-                    target_cfgs
-                        .iter()
-                        .chain(cfg.iter())
-                        .chain(iter::once(&r_a_cfg_flag))
-                        .cloned()
-                        .collect(),
+                    Arc::new(
+                        target_cfgs
+                            .iter()
+                            .chain(cfg.iter())
+                            .chain(iter::once(&r_a_cfg_flag))
+                            .cloned()
+                            .collect(),
+                    ),
                     None,
                     env,
                     *is_proc_macro,
@@ -1179,6 +1181,7 @@ fn detached_files_to_crate_graph(
 
     let mut cfg_options = create_cfg_options(rustc_cfg);
     cfg_options.insert_atom("rust_analyzer".into());
+    let cfg_options = Arc::new(cfg_options);
 
     for detached_file in detached_files {
         let file_id = match load(detached_file) {
@@ -1380,8 +1383,8 @@ fn add_target_crate_root(
         edition,
         Some(display_name),
         Some(pkg.version.to_string()),
-        cfg_options,
-        potential_cfg_options,
+        Arc::new(cfg_options),
+        potential_cfg_options.map(Arc::new),
         env,
         matches!(kind, TargetKind::Lib { is_proc_macro: true }),
         origin,
@@ -1437,7 +1440,7 @@ fn sysroot_to_crate_graph(
             let diff = CfgDiff::new(vec![], vec![CfgAtom::Flag("test".into())]).unwrap();
             for (cid, c) in cg.iter_mut() {
                 // uninject `test` flag so `core` keeps working.
-                c.cfg_options.apply_diff(diff.clone());
+                Arc::make_mut(&mut c.cfg_options).apply_diff(diff.clone());
                 // patch the origin
                 if c.origin.is_local() {
                     let lang_crate = LangCrateOrigin::from(
@@ -1486,7 +1489,7 @@ fn sysroot_to_crate_graph(
             (SysrootPublicDeps { deps: pub_deps }, libproc_macro)
         }
         SysrootMode::Stitched(stitched) => {
-            let cfg_options = create_cfg_options(rustc_cfg);
+            let cfg_options = Arc::new(create_cfg_options(rustc_cfg));
             let sysroot_crates: FxHashMap<SysrootCrate, CrateId> = stitched
                 .crates()
                 .filter_map(|krate| {
diff --git a/crates/rust-analyzer/src/cli/analysis_stats.rs b/crates/rust-analyzer/src/cli/analysis_stats.rs
index fdd77199aa..a1eea8839e 100644
--- a/crates/rust-analyzer/src/cli/analysis_stats.rs
+++ b/crates/rust-analyzer/src/cli/analysis_stats.rs
@@ -280,7 +280,9 @@ impl flags::AnalysisStats {
         let mut fail = 0;
         for &a in adts {
             let generic_params = db.generic_params(a.into());
-            if generic_params.iter().next().is_some() || generic_params.iter_lt().next().is_some() {
+            if generic_params.iter_type_or_consts().next().is_some()
+                || generic_params.iter_lt().next().is_some()
+            {
                 // Data types with generics don't have layout.
                 continue;
             }
diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs
index 5890af17eb..80f024184a 100644
--- a/crates/rust-analyzer/src/config.rs
+++ b/crates/rust-analyzer/src/config.rs
@@ -10,7 +10,7 @@
 use std::{fmt, iter, ops::Not};
 
 use cfg::{CfgAtom, CfgDiff};
-use flycheck::{CargoOptions, FlycheckConfig};
+use flycheck::FlycheckConfig;
 use ide::{
     AssistConfig, CallableSnippets, CompletionConfig, DiagnosticsConfig, ExprFillDefaultMode,
     HighlightConfig, HighlightRelatedConfig, HoverConfig, HoverDocFormat, InlayFieldsToResolve,
@@ -1364,22 +1364,6 @@ impl Config {
         self.data.check_workspace
     }
 
-    pub fn cargo_test_options(&self) -> CargoOptions {
-        CargoOptions {
-            target_triples: self.data.cargo_target.clone().into_iter().collect(),
-            all_targets: false,
-            no_default_features: self.data.cargo_noDefaultFeatures,
-            all_features: matches!(self.data.cargo_features, CargoFeaturesDef::All),
-            features: match self.data.cargo_features.clone() {
-                CargoFeaturesDef::All => vec![],
-                CargoFeaturesDef::Selected(it) => it,
-            },
-            extra_args: self.extra_args().clone(),
-            extra_env: self.extra_env().clone(),
-            target_dir: self.target_dir_from_config(),
-        }
-    }
-
     pub fn flycheck(&self) -> FlycheckConfig {
         match &self.data.check_overrideCommand {
             Some(args) if !args.is_empty() => {
@@ -1405,39 +1389,37 @@ impl Config {
             }
             Some(_) | None => FlycheckConfig::CargoCommand {
                 command: self.data.check_command.clone(),
-                options: CargoOptions {
-                    target_triples: self
-                        .data
-                        .check_targets
-                        .clone()
-                        .and_then(|targets| match &targets.0[..] {
-                            [] => None,
-                            targets => Some(targets.into()),
-                        })
-                        .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()),
-                    all_targets: self.data.check_allTargets.unwrap_or(self.data.cargo_allTargets),
-                    no_default_features: self
-                        .data
-                        .check_noDefaultFeatures
-                        .unwrap_or(self.data.cargo_noDefaultFeatures),
-                    all_features: matches!(
-                        self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features),
-                        CargoFeaturesDef::All
-                    ),
-                    features: match self
-                        .data
-                        .check_features
-                        .clone()
-                        .unwrap_or_else(|| self.data.cargo_features.clone())
-                    {
-                        CargoFeaturesDef::All => vec![],
-                        CargoFeaturesDef::Selected(it) => it,
-                    },
-                    extra_args: self.check_extra_args(),
-                    extra_env: self.check_extra_env(),
-                    target_dir: self.target_dir_from_config(),
+                target_triples: self
+                    .data
+                    .check_targets
+                    .clone()
+                    .and_then(|targets| match &targets.0[..] {
+                        [] => None,
+                        targets => Some(targets.into()),
+                    })
+                    .unwrap_or_else(|| self.data.cargo_target.clone().into_iter().collect()),
+                all_targets: self.data.check_allTargets.unwrap_or(self.data.cargo_allTargets),
+                no_default_features: self
+                    .data
+                    .check_noDefaultFeatures
+                    .unwrap_or(self.data.cargo_noDefaultFeatures),
+                all_features: matches!(
+                    self.data.check_features.as_ref().unwrap_or(&self.data.cargo_features),
+                    CargoFeaturesDef::All
+                ),
+                features: match self
+                    .data
+                    .check_features
+                    .clone()
+                    .unwrap_or_else(|| self.data.cargo_features.clone())
+                {
+                    CargoFeaturesDef::All => vec![],
+                    CargoFeaturesDef::Selected(it) => it,
                 },
+                extra_args: self.check_extra_args(),
+                extra_env: self.check_extra_env(),
                 ansi_color_output: self.color_diagnostic_output(),
+                target_dir: self.target_dir_from_config(),
             },
         }
     }
@@ -2790,7 +2772,7 @@ mod tests {
             .unwrap();
         assert_eq!(config.data.cargo_targetDir, None);
         assert!(
-            matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir.is_none())
+            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir.is_none())
         );
     }
 
@@ -2809,7 +2791,7 @@ mod tests {
             .unwrap();
         assert_eq!(config.data.cargo_targetDir, Some(TargetDirectory::UseSubdirectory(true)));
         assert!(
-            matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
+            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(Utf8PathBuf::from("target/rust-analyzer")))
         );
     }
 
@@ -2831,7 +2813,7 @@ mod tests {
             Some(TargetDirectory::Directory(Utf8PathBuf::from("other_folder")))
         );
         assert!(
-            matches!(config.flycheck(), FlycheckConfig::CargoCommand { options, .. } if options.target_dir == Some(Utf8PathBuf::from("other_folder")))
+            matches!(config.flycheck(), FlycheckConfig::CargoCommand { target_dir, .. } if target_dir == Some(Utf8PathBuf::from("other_folder")))
         );
     }
 }
diff --git a/crates/rust-analyzer/src/handlers/request.rs b/crates/rust-analyzer/src/handlers/request.rs
index 77c4ad32cc..77692ed3ae 100644
--- a/crates/rust-analyzer/src/handlers/request.rs
+++ b/crates/rust-analyzer/src/handlers/request.rs
@@ -220,11 +220,11 @@ pub(crate) fn handle_run_test(
         None => "".to_owned(),
     };
     let handle = if lca.is_empty() {
-        flycheck::CargoTestHandle::new(None, state.config.cargo_test_options())
+        flycheck::CargoTestHandle::new(None)
     } else if let Some((_, path)) = lca.split_once("::") {
-        flycheck::CargoTestHandle::new(Some(path), state.config.cargo_test_options())
+        flycheck::CargoTestHandle::new(Some(path))
     } else {
-        flycheck::CargoTestHandle::new(None, state.config.cargo_test_options())
+        flycheck::CargoTestHandle::new(None)
     };
     state.test_run_session = Some(handle?);
     Ok(())


Test patch:
diff --git a/crates/flycheck/src/test_runner.rs b/crates/flycheck/src/test_runner.rs
index 94c05ebc74..9f761c9ead 100644
--- a/crates/flycheck/src/test_runner.rs
+++ b/crates/flycheck/src/test_runner.rs
@@ -7,10 +7,7 @@ use crossbeam_channel::Receiver;
 use serde::Deserialize;
 use toolchain::Tool;
 
-use crate::{
-    command::{CommandHandle, ParseFromLine},
-    CargoOptions,
-};
+use crate::command::{CommandHandle, ParseFromLine};
 
 #[derive(Debug, Deserialize)]
 #[serde(tag = "event", rename_all = "camelCase")]
@@ -61,14 +58,13 @@ pub struct CargoTestHandle {
 // cargo test --workspace --no-fail-fast -- module::func -Z unstable-options --format=json
 
 impl CargoTestHandle {
-    pub fn new(path: Option<&str>, options: CargoOptions) -> std::io::Result<Self> {
+    pub fn new(path: Option<&str>) -> std::io::Result<Self> {
         let mut cmd = Command::new(Tool::Cargo.path());
         cmd.env("RUSTC_BOOTSTRAP", "1");
         cmd.arg("test");
         cmd.arg("--workspace");
         // --no-fail-fast is needed to ensure that all requested tests will run
         cmd.arg("--no-fail-fast");
-        options.apply_on_command(&mut cmd);
         cmd.arg("--");
         if let Some(path) = path {
             cmd.arg(path);
diff --git a/crates/test-fixture/src/lib.rs b/crates/test-fixture/src/lib.rs
index c8d785f83e..7ce83078cb 100644
--- a/crates/test-fixture/src/lib.rs
+++ b/crates/test-fixture/src/lib.rs
@@ -189,8 +189,8 @@ impl ChangeFixture {
                     meta.edition,
                     Some(crate_name.clone().into()),
                     version,
-                    meta.cfg.clone(),
-                    Some(meta.cfg),
+                    From::from(meta.cfg.clone()),
+                    Some(From::from(meta.cfg)),
                     meta.env,
                     false,
                     origin,
@@ -227,8 +227,8 @@ impl ChangeFixture {
                 Edition::CURRENT,
                 Some(CrateName::new("test").unwrap().into()),
                 None,
-                default_cfg.clone(),
-                Some(default_cfg),
+                From::from(default_cfg.clone()),
+                Some(From::from(default_cfg)),
                 default_env,
                 false,
                 CrateOrigin::Local { repo: None, name: None },