Repository: rust-analyzer/rust-analyzer
Pull request #11700 (2022-03-13 21:23:28)

:arrow_up: xshell

matklad: Would be prudent to merge this *after* tomorrow's release :-)
matklad: bors r+
bors[bot]: Canceled.

Patch:
diff --git a/Cargo.lock b/Cargo.lock
index 5d084bcf1c..1d298353f7 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -171,9 +171,9 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd"
 
 [[package]]
 name = "chalk-derive"
-version = "0.79.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "0b14364774396379d5c488e73d88e0a6d2b51acd0dac9c8359e2f84c58cf3a16"
+checksum = "58c24b8052ea1e3adbb6f9ab7ba5fcc18b9d12591c042de4c833f709ce81e0e0"
 dependencies = [
  "proc-macro2",
  "quote",
@@ -183,9 +183,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-ir"
-version = "0.79.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "cd571e8931d3075f562a2d460bfe3028a9c7b343876765cce95b6143a76b882e"
+checksum = "f3cad5c3f1edd4b4a2c9bda24ae558ceb4f88336f88f944c2e35d0bfeb13c818"
 dependencies = [
  "bitflags",
  "chalk-derive",
@@ -194,9 +194,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-recursive"
-version = "0.79.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "54ceedab35607f4680d02de80f8be005af0ad5c1dcfec56cfd849d33da5fe736"
+checksum = "e68ba0c7219f34738b66c0c992438c644ca33f4d8a29da3d41604299c7eaf419"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -207,9 +207,9 @@ dependencies = [
 
 [[package]]
 name = "chalk-solve"
-version = "0.79.0"
+version = "0.76.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "9e31bb853cf921365759346db05d833f969e330462432bf38c9c2be1e78a9abd"
+checksum = "94533188d3452bc72cbd5618d166f45fc7646b674ad3fe9667d557bc25236dee"
 dependencies = [
  "chalk-derive",
  "chalk-ir",
@@ -2072,18 +2072,18 @@ checksum = "da260301476ad19a4733a0e930db8227a48ea04561e235a5102978145ec69fcc"
 
 [[package]]
 name = "xshell"
-version = "0.1.17"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "eaad2035244c56da05573d4d7fda5f903c60a5f35b9110e157a14a1df45a9f14"
+checksum = "3332cab90be2998a2aacb6494db45344bd16dfcc43ff36c42255018c6bcc96be"
 dependencies = [
  "xshell-macros",
 ]
 
 [[package]]
 name = "xshell-macros"
-version = "0.1.17"
+version = "0.2.0"
 source = "registry+https://github.com/rust-lang/crates.io-index"
-checksum = "4916a4a3cad759e499a3620523bf9545cc162d7a06163727dde97ce9aaa4cf39"
+checksum = "f47e54cffa76000b7641328ab3bb1e146f93a1690ab86c5909c656f49d91019c"
 
 [[package]]
 name = "xtask"
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 9edb6de9df..6e3285fd4f 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -256,7 +256,7 @@ impl HirDisplay for TypeParam {
         }
 
         let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None);
-        let substs = TyBuilder::placeholder_subst(f.db, self.id.parent());
+        let substs = TyBuilder::type_params_subst(f.db, self.id.parent());
         let predicates: Vec<_> =
             bounds.iter().cloned().map(|b| b.substitute(Interner, &substs)).collect();
         let krate = self.id.parent().krate(f.db).id;
@@ -292,9 +292,8 @@ impl HirDisplay for ConstParam {
 fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
     let params = f.db.generic_params(def);
     if params.lifetimes.is_empty()
-        && params.type_or_consts.iter().all(|x| x.1.const_param().is_none())
         && params
-            .type_or_consts
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
@@ -316,7 +315,7 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
         delim(f)?;
         write!(f, "{}", lifetime.name)?;
     }
-    for (_, ty) in params.type_or_consts.iter() {
+    for (_, ty) in params.tocs.iter() {
         if let Some(name) = &ty.name() {
             match ty {
                 TypeOrConstParamData::TypeParamData(ty) => {
@@ -349,9 +348,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
     // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
     let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
         WherePredicateTypeTarget::TypeRef(_) => false,
-        WherePredicateTypeTarget::TypeOrConstParam(id) => {
-            params.type_or_consts[*id].name().is_none()
-        }
+        WherePredicateTypeTarget::TypeOrConstParam(id) => params.tocs[*id].name().is_none(),
     };
 
     let has_displayable_predicate = params
@@ -367,12 +364,10 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
 
     let write_target = |target: &WherePredicateTypeTarget, f: &mut HirFormatter| match target {
         WherePredicateTypeTarget::TypeRef(ty) => ty.hir_fmt(f),
-        WherePredicateTypeTarget::TypeOrConstParam(id) => {
-            match &params.type_or_consts[*id].name() {
-                Some(name) => write!(f, "{}", name),
-                None => write!(f, "{{unnamed}}"),
-            }
-        }
+        WherePredicateTypeTarget::TypeOrConstParam(id) => match &params.tocs[*id].name() {
+            Some(name) => write!(f, "{}", name),
+            None => write!(f, "{{unnamed}}"),
+        },
     };
 
     write!(f, "\nwhere")?;
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index ee4ff0aebb..b45689ec37 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -55,9 +55,7 @@ use hir_def::{
 use hir_expand::{name::name, MacroCallKind};
 use hir_ty::{
     autoderef,
-    consteval::{
-        eval_const, unknown_const_as_generic, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt,
-    },
+    consteval::{eval_const, ComputedExpr, ConstEvalCtx, ConstEvalError, ConstExt},
     could_unify,
     diagnostics::BodyValidationDiagnostic,
     method_resolution::{self, TyFingerprint},
@@ -65,9 +63,9 @@ use hir_ty::{
     subst_prefix,
     traits::FnTrait,
     AliasEq, AliasTy, BoundVar, CallableDefId, CallableSig, Canonical, CanonicalVarKinds, Cast,
-    DebruijnIndex, GenericArgData, InEnvironment, Interner, ParamKind, QuantifiedWhereClause,
-    Scalar, Solution, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt,
-    TyKind, TyVariableKind, WhereClause,
+    DebruijnIndex, InEnvironment, Interner, QuantifiedWhereClause, Scalar, Solution, Substitution,
+    TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyDefId, TyExt, TyKind, TyVariableKind,
+    WhereClause,
 };
 use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
@@ -798,7 +796,7 @@ impl Field {
             VariantDef::Union(it) => it.id.into(),
             VariantDef::Variant(it) => it.parent.id.into(),
         };
-        let substs = TyBuilder::placeholder_subst(db, generic_def_id);
+        let substs = TyBuilder::type_params_subst(db, generic_def_id);
         let ty = db.field_types(var_id)[self.id].clone().substitute(Interner, &substs);
         Type::new(db, self.parent.module(db).id.krate(), var_id, ty)
     }
@@ -985,10 +983,7 @@ impl_from!(Struct, Union, Enum for Adt);
 impl Adt {
     pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
         let subst = db.generic_defaults(self.into());
-        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
-            GenericArgData::Ty(x) => x.is_unknown(),
-            _ => false,
-        })
+        subst.iter().any(|ty| ty.skip_binders().is_unknown())
     }
 
     /// Turns this ADT into a type. Any type parameters of the ADT will be
@@ -1685,10 +1680,7 @@ pub struct TypeAlias {
 impl TypeAlias {
     pub fn has_non_default_type_params(self, db: &dyn HirDatabase) -> bool {
         let subst = db.generic_defaults(self.id.into());
-        subst.iter().any(|ty| match ty.skip_binders().data(Interner) {
-            GenericArgData::Ty(x) => x.is_unknown(),
-            _ => false,
-        })
+        subst.iter().any(|ty| ty.skip_binders().is_unknown())
     }
 
     pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -2055,7 +2047,7 @@ impl_from!(
 impl GenericDef {
     pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
         let generics = db.generic_params(self.into());
-        let ty_params = generics.type_or_consts.iter().map(|(local_id, _)| {
+        let ty_params = generics.tocs.iter().map(|(local_id, _)| {
             let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
             match toc.split(db) {
                 Either::Left(x) => GenericParam::ConstParam(x),
@@ -2075,7 +2067,7 @@ impl GenericDef {
     pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
         let generics = db.generic_params(self.into());
         generics
-            .type_or_consts
+            .tocs
             .iter()
             .map(|(local_id, _)| TypeOrConstParam {
                 id: TypeOrConstParamId { parent: self.into(), local_id },
@@ -2359,14 +2351,9 @@ impl TypeParam {
         let resolver = self.id.parent().resolver(db.upcast());
         let krate = self.id.parent().module(db.upcast()).krate();
         let ty = params.get(local_idx)?.clone();
-        let subst = TyBuilder::placeholder_subst(db, self.id.parent());
+        let subst = TyBuilder::type_params_subst(db, self.id.parent());
         let ty = ty.substitute(Interner, &subst_prefix(&subst, local_idx));
-        match ty.data(Interner) {
-            GenericArgData::Ty(x) => {
-                Some(Type::new_with_resolver_inner(db, krate, &resolver, x.clone()))
-            }
-            _ => None,
-        }
+        Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
     }
 }
 
@@ -2402,7 +2389,7 @@ impl ConstParam {
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let params = db.generic_params(self.id.parent());
-        match params.type_or_consts[self.id.local_id()].name() {
+        match params.tocs[self.id.local_id()].name() {
             Some(x) => x.clone(),
             None => {
                 never!();
@@ -2434,7 +2421,7 @@ pub struct TypeOrConstParam {
 impl TypeOrConstParam {
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let params = db.generic_params(self.id.parent);
-        match params.type_or_consts[self.id.local_id].name() {
+        match params.tocs[self.id.local_id].name() {
             Some(n) => n.clone(),
             _ => Name::missing(),
         }
@@ -2450,12 +2437,12 @@ impl TypeOrConstParam {
 
     pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
         let params = db.generic_params(self.id.parent);
-        match &params.type_or_consts[self.id.local_id] {
+        match &params.tocs[self.id.local_id] {
             hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
-                Either::Right(TypeParam { id: TypeParamId::from_unchecked(self.id) })
+                Either::Right(TypeParam { id: self.id.into() })
             }
             hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
-                Either::Left(ConstParam { id: ConstParamId::from_unchecked(self.id) })
+                Either::Left(ConstParam { id: self.id.into() })
             }
         }
     }
@@ -2701,19 +2688,9 @@ impl Type {
     }
 
     pub fn impls_trait(&self, db: &dyn HirDatabase, trait_: Trait, args: &[Type]) -> bool {
-        let mut it = args.iter().map(|t| t.ty.clone());
         let trait_ref = TyBuilder::trait_ref(db, trait_.id)
             .push(self.ty.clone())
-            .fill(|x| {
-                let r = it.next().unwrap();
-                match x {
-                    ParamKind::Type => GenericArgData::Ty(r).intern(Interner),
-                    ParamKind::Const(ty) => {
-                        // FIXME: this code is not covered in tests.
-                        unknown_const_as_generic(ty.clone())
-                    }
-                }
-            })
+            .fill(args.iter().map(|t| t.ty.clone()))
             .build();
 
         let goal = Canonical {
@@ -2730,18 +2707,9 @@ impl Type {
         args: &[Type],
         alias: TypeAlias,
     ) -> Option<Type> {
-        let mut args = args.iter();
         let projection = TyBuilder::assoc_type_projection(db, alias.id)
             .push(self.ty.clone())
-            .fill(|x| {
-                // FIXME: this code is not covered in tests.
-                match x {
-                    ParamKind::Type => {
-                        GenericArgData::Ty(args.next().unwrap().ty.clone()).intern(Interner)
-                    }
-                    ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
-                }
-            })
+            .fill(args.iter().map(|t| t.ty.clone()))
             .build();
         let goal = hir_ty::make_canonical(
             InEnvironment::new(
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index 4672e7db40..986ea0cf2a 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -279,7 +279,7 @@ impl SourceToDefCtx<'_, '_> {
     pub(super) fn type_param_to_def(&mut self, src: InFile<ast::TypeParam>) -> Option<TypeParamId> {
         let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
         let dyn_map = self.cache_for(container, src.file_id);
-        dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| TypeParamId::from_unchecked(x))
+        dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| x.into())
     }
 
     pub(super) fn lifetime_param_to_def(
@@ -297,7 +297,7 @@ impl SourceToDefCtx<'_, '_> {
     ) -> Option<ConstParamId> {
         let container: ChildContainer = self.find_generic_param_container(src.syntax())?.into();
         let dyn_map = self.cache_for(container, src.file_id);
-        dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| ConstParamId::from_unchecked(x))
+        dyn_map[keys::CONST_PARAM].get(&src.value).copied().map(|x| x.into())
     }
 
     pub(super) fn generic_param_to_def(
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 04b77894ae..6d7b98f3b1 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -24,8 +24,8 @@ use crate::{
     keys,
     src::{HasChildSource, HasSource},
     type_ref::{LifetimeRef, TypeBound, TypeRef},
-    AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId,
-    LocalTypeOrConstParamId, Lookup, TypeOrConstParamId, TypeParamId,
+    AdtId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId,
+    Lookup, TypeOrConstParamId,
 };
 
 /// Data about a generic type parameter (to a function, struct, impl, ...).
@@ -99,7 +99,7 @@ impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
 /// Data about the generic parameters of a function, struct, impl, etc.
 #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
 pub struct GenericParams {
-    pub type_or_consts: Arena<TypeOrConstParamData>,
+    pub tocs: Arena<TypeOrConstParamData>,
     pub lifetimes: Arena<LifetimeParamData>,
     pub where_predicates: Vec<WherePredicate>,
 }
@@ -138,14 +138,13 @@ impl GenericParams {
     pub fn type_iter<'a>(
         &'a self,
     ) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeParamData)> {
-        self.type_or_consts.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
+        self.tocs.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
     }
 
-    /// Iterator of type_or_consts field
-    pub fn iter<'a>(
+    pub fn toc_iter<'a>(
         &'a self,
-    ) -> impl DoubleEndedIterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
-        self.type_or_consts.iter()
+    ) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
+        self.tocs.iter()
     }
 
     pub(crate) fn generic_params_query(
@@ -252,7 +251,7 @@ impl GenericParams {
                         default,
                         provenance: TypeParamProvenance::TypeParamList,
                     };
-                    self.type_or_consts.alloc(param.into());
+                    self.tocs.alloc(param.into());
                     let type_ref = TypeRef::Path(name.into());
                     self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
                 }
@@ -262,7 +261,7 @@ impl GenericParams {
                         .ty()
                         .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
                     let param = ConstParamData { name, ty: Interned::new(ty) };
-                    self.type_or_consts.alloc(param.into());
+                    self.tocs.alloc(param.into());
                 }
             }
         }
@@ -349,7 +348,7 @@ impl GenericParams {
                     default: None,
                     provenance: TypeParamProvenance::ArgumentImplTrait,
                 };
-                let param_id = self.type_or_consts.alloc(param.into());
+                let param_id = self.tocs.alloc(param.into());
                 for bound in bounds {
                     self.where_predicates.push(WherePredicate::TypeBound {
                         target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
@@ -373,34 +372,27 @@ impl GenericParams {
     }
 
     pub(crate) fn shrink_to_fit(&mut self) {
-        let Self { lifetimes, type_or_consts: types, where_predicates } = self;
+        let Self { lifetimes, tocs: types, where_predicates } = self;
         lifetimes.shrink_to_fit();
         types.shrink_to_fit();
         where_predicates.shrink_to_fit();
     }
 
-    pub fn find_type_by_name(&self, name: &Name, parent: GenericDefId) -> Option<TypeParamId> {
-        self.type_or_consts.iter().find_map(|(id, p)| {
-            if p.name().as_ref() == Some(&name) && p.type_param().is_some() {
-                Some(TypeParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
-            } else {
-                None
-            }
-        })
+    pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
+        self.tocs
+            .iter()
+            .filter(|x| matches!(x.1, TypeOrConstParamData::TypeParamData(_)))
+            .find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
     }
 
-    pub fn find_const_by_name(&self, name: &Name, parent: GenericDefId) -> Option<ConstParamId> {
-        self.type_or_consts.iter().find_map(|(id, p)| {
-            if p.name().as_ref() == Some(&name) && p.const_param().is_some() {
-                Some(ConstParamId::from_unchecked(TypeOrConstParamId { local_id: id, parent }))
-            } else {
-                None
-            }
-        })
+    pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
+        self.tocs
+            .iter()
+            .find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
     }
 
     pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
-        self.type_or_consts.iter().find_map(|(id, p)| {
+        self.tocs.iter().find_map(|(id, p)| {
             if let TypeOrConstParamData::TypeParamData(p) = p {
                 if p.provenance == TypeParamProvenance::TraitSelf {
                     Some(id)
@@ -459,7 +451,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
         let generic_params = db.generic_params(*self);
-        let mut idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
+        let mut idx_iter = generic_params.tocs.iter().map(|(idx, _)| idx);
 
         let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
 
@@ -513,7 +505,7 @@ impl ChildBySource for GenericDefId {
         }
 
         let generic_params = db.generic_params(*self);
-        let mut toc_idx_iter = generic_params.type_or_consts.iter().map(|(idx, _)| idx);
+        let mut toc_idx_iter = generic_params.tocs.iter().map(|(idx, _)| idx);
         let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
 
         // For traits the first type index is `Self`, skip it.
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 379e03504b..516a16bcf0 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -582,7 +582,7 @@ impl<'a> Ctx<'a> {
             }
             GenericsOwner::Trait(trait_def) => {
                 // traits get the Self type as an implicit first type parameter
-                generics.type_or_consts.alloc(
+                generics.tocs.alloc(
                     TypeParamData {
                         name: Some(name![Self]),
                         default: None,
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index b24ba61ea0..34bea5bd45 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -621,13 +621,12 @@ impl<'a> Printer<'a> {
     fn print_generic_arg(&mut self, arg: &GenericArg) {
         match arg {
             GenericArg::Type(ty) => self.print_type_ref(ty),
-            GenericArg::Const(c) => w!(self, "{}", c),
             GenericArg::Lifetime(lt) => w!(self, "{}", lt.name),
         }
     }
 
     fn print_generic_params(&mut self, params: &GenericParams) {
-        if params.type_or_consts.is_empty() && params.lifetimes.is_empty() {
+        if params.tocs.is_empty() && params.lifetimes.is_empty() {
             return;
         }
 
@@ -640,7 +639,7 @@ impl<'a> Printer<'a> {
             first = false;
             w!(self, "{}", lt.name);
         }
-        for (idx, x) in params.type_or_consts.iter() {
+        for (idx, x) in params.tocs.iter() {
             if !first {
                 w!(self, ", ");
             }
@@ -702,7 +701,7 @@ impl<'a> Printer<'a> {
                 match target {
                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
                     WherePredicateTypeTarget::TypeOrConstParam(id) => {
-                        match &params.type_or_consts[*id].name() {
+                        match &params.tocs[*id].name() {
                             Some(name) => w!(this, "{}", name),
                             None => w!(this, "_anon_{}", id.into_raw()),
                         }
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index 974a2ab8f2..d7292b0063 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -343,13 +343,11 @@ impl TypeParamId {
     }
 }
 
-impl TypeParamId {
-    /// Caller should check if this toc id really belongs to a type
-    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
+impl From<TypeOrConstParamId> for TypeParamId {
+    fn from(x: TypeOrConstParamId) -> Self {
         Self(x)
     }
 }
-
 impl From<TypeParamId> for TypeOrConstParamId {
     fn from(x: TypeParamId) -> Self {
         x.0
@@ -369,13 +367,11 @@ impl ConstParamId {
     }
 }
 
-impl ConstParamId {
-    /// Caller should check if this toc id really belongs to a const
-    pub fn from_unchecked(x: TypeOrConstParamId) -> Self {
+impl From<TypeOrConstParamId> for ConstParamId {
+    fn from(x: TypeOrConstParamId) -> Self {
         Self(x)
     }
 }
-
 impl From<ConstParamId> for TypeOrConstParamId {
     fn from(x: ConstParamId) -> Self {
         x.0
diff --git a/crates/hir_def/src/path.rs b/crates/hir_def/src/path.rs
index 37c09a0984..aea1e3ec34 100644
--- a/crates/hir_def/src/path.rs
+++ b/crates/hir_def/src/path.rs
@@ -6,11 +6,7 @@ use std::{
     iter,
 };
 
-use crate::{
-    body::LowerCtx,
-    intern::Interned,
-    type_ref::{ConstScalarOrPath, LifetimeRef},
-};
+use crate::{body::LowerCtx, intern::Interned, type_ref::LifetimeRef};
 use hir_expand::name::{name, Name};
 use syntax::ast;
 
@@ -82,7 +78,6 @@ pub struct AssociatedTypeBinding {
 pub enum GenericArg {
     Type(TypeRef),
     Lifetime(LifetimeRef),
-    Const(ConstScalarOrPath),
 }
 
 impl Path {
diff --git a/crates/hir_def/src/path/lower.rs b/crates/hir_def/src/path/lower.rs
index b6a24cd4ab..550f12dabd 100644
--- a/crates/hir_def/src/path/lower.rs
+++ b/crates/hir_def/src/path/lower.rs
@@ -1,6 +1,6 @@
 //! Transforms syntax into `Path` objects, ideally with accounting for hygiene
 
-use crate::{intern::Interned, type_ref::ConstScalarOrPath};
+use crate::intern::Interned;
 
 use either::Either;
 use hir_expand::name::{name, AsName};
@@ -180,10 +180,8 @@ pub(super) fn lower_generic_args(
                     args.push(GenericArg::Lifetime(lifetime_ref))
                 }
             }
-            ast::GenericArg::ConstArg(arg) => {
-                let arg = ConstScalarOrPath::from_expr_opt(arg.expr());
-                args.push(GenericArg::Const(arg))
-            }
+            // constants are ignored for now.
+            ast::GenericArg::ConstArg(_) => (),
         }
     }
 
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 72856a1bfe..3d47064e4f 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -189,9 +189,14 @@ impl Resolver {
                 Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
 
                 Scope::GenericParams { params, def } => {
-                    if let Some(id) = params.find_type_by_name(first_name, *def) {
+                    if let Some(local_id) = params.find_type_by_name(first_name) {
                         let idx = if path.segments().len() == 1 { None } else { Some(1) };
-                        return Some((TypeNs::GenericParam(id), idx));
+                        return Some((
+                            TypeNs::GenericParam(
+                                TypeOrConstParamId { local_id, parent: *def }.into(),
+                            ),
+                            idx,
+                        ));
                     }
                 }
                 Scope::ImplDefScope(impl_) => {
@@ -279,14 +284,18 @@ impl Resolver {
                 Scope::ExprScope(_) => continue,
 
                 Scope::GenericParams { params, def } if n_segments > 1 => {
-                    if let Some(id) = params.find_type_by_name(first_name, *def) {
-                        let ty = TypeNs::GenericParam(id);
+                    if let Some(local_id) = params.find_type_or_const_by_name(first_name) {
+                        let ty = TypeNs::GenericParam(
+                            TypeOrConstParamId { local_id, parent: *def }.into(),
+                        );
                         return Some(ResolveValueResult::Partial(ty, 1));
                     }
                 }
                 Scope::GenericParams { params, def } if n_segments == 1 => {
-                    if let Some(id) = params.find_const_by_name(first_name, *def) {
-                        let val = ValueNs::GenericParam(id);
+                    if let Some(local_id) = params.find_type_or_const_by_name(first_name) {
+                        let val = ValueNs::GenericParam(
+                            TypeOrConstParamId { local_id, parent: *def }.into(),
+                        );
                         return Some(ResolveValueResult::ValueNs(val));
                     }
                 }
@@ -509,18 +518,18 @@ impl Scope {
             }
             Scope::GenericParams { params, def: parent } => {
                 let parent = *parent;
-                for (local_id, param) in params.type_or_consts.iter() {
+                for (local_id, param) in params.tocs.iter() {
                     if let Some(name) = &param.name() {
                         let id = TypeOrConstParamId { parent, local_id };
-                        let data = &db.generic_params(parent).type_or_consts[local_id];
+                        let data = &db.generic_params(parent).tocs[local_id];
                         acc.add(
                             name,
                             ScopeDef::GenericParam(match data {
                                 TypeOrConstParamData::TypeParamData(_) => {
-                                    GenericParamId::TypeParamId(TypeParamId::from_unchecked(id))
+                                    GenericParamId::TypeParamId(id.into())
                                 }
                                 TypeOrConstParamData::ConstParamData(_) => {
-                                    GenericParamId::ConstParamId(ConstParamId::from_unchecked(id))
+                                    GenericParamId::ConstParamId(id.into())
                                 }
                             }),
                         );
diff --git a/crates/hir_def/src/type_ref.rs b/crates/hir_def/src/type_ref.rs
index b9fadcfa8d..027c410cdf 100644
--- a/crates/hir_def/src/type_ref.rs
+++ b/crates/hir_def/src/type_ref.rs
@@ -89,7 +89,7 @@ pub enum TypeRef {
     Reference(Box<TypeRef>, Option<LifetimeRef>, Mutability),
     // FIXME: for full const generics, the latter element (length) here is going to have to be an
     // expression that is further lowered later in hir_ty.
-    Array(Box<TypeRef>, ConstScalarOrPath),
+    Array(Box<TypeRef>, ConstScalar),
     Slice(Box<TypeRef>),
     /// A fn pointer. Last element of the vector is the return type.
     Fn(Vec<(Option<Name>, TypeRef)>, bool /*varargs*/),
@@ -162,7 +162,10 @@ impl TypeRef {
                 // `hir_def::body::lower` to lower this into an `Expr` and then evaluate it at the
                 // `hir_ty` level, which would allow knowing the type of:
                 // let v: [u8; 2 + 2] = [0u8; 4];
-                let len = ConstScalarOrPath::from_expr_opt(inner.expr());
+                let len = inner
+                    .expr()
+                    .map(ConstScalar::usize_from_literal_expr)
+                    .unwrap_or(ConstScalar::Unknown);
 
                 TypeRef::Array(Box::new(TypeRef::from_ast_opt(ctx, inner.ty())), len)
             }
@@ -275,8 +278,7 @@ impl TypeRef {
                             crate::path::GenericArg::Type(type_ref) => {
                                 go(type_ref, f);
                             }
-                            crate::path::GenericArg::Const(_)
-                            | crate::path::GenericArg::Lifetime(_) => {}
+                            crate::path::GenericArg::Lifetime(_) => {}
                         }
                     }
                     for binding in &args_and_bindings.bindings {
@@ -355,60 +357,6 @@ impl TypeBound {
     }
 }
 
-#[derive(Debug, Clone, PartialEq, Eq, Hash)]
-pub enum ConstScalarOrPath {
-    Scalar(ConstScalar),
-    Path(Name),
-}
-
-impl std::fmt::Display for ConstScalarOrPath {
-    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
-        match self {
-            ConstScalarOrPath::Scalar(s) => write!(f, "{}", s),
-            ConstScalarOrPath::Path(n) => write!(f, "{}", n),
-        }
-    }
-}
-
-impl ConstScalarOrPath {
-    pub(crate) fn from_expr_opt(expr: Option<ast::Expr>) -> Self {
-        match expr {
-            Some(x) => Self::from_expr(x),
-            None => Self::Scalar(ConstScalar::Unknown),
-        }
-    }
-
-    // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
-    // parse stage.
-    fn from_expr(expr: ast::Expr) -> Self {
-        match expr {
-            ast::Expr::PathExpr(p) => {
-                match p.path().and_then(|x| x.segment()).and_then(|x| x.name_ref()) {
-                    Some(x) => Self::Path(x.as_name()),
-                    None => Self::Scalar(ConstScalar::Unknown),
-                }
-            }
-            ast::Expr::Literal(lit) => {
-                let lkind = lit.kind();
-                match lkind {
-                    ast::LiteralKind::IntNumber(num)
-                        if num.suffix() == None || num.suffix() == Some("usize") =>
-                    {
-                        Self::Scalar(
-                            num.value()
-                                .and_then(|v| v.try_into().ok())
-                                .map(ConstScalar::Usize)
-                                .unwrap_or(ConstScalar::Unknown),
-                        )
-                    }
-                    _ => Self::Scalar(ConstScalar::Unknown),
-                }
-            }
-            _ => Self::Scalar(ConstScalar::Unknown),
-        }
-    }
-}
-
 /// A concrete constant value
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ConstScalar {
@@ -441,4 +389,25 @@ impl ConstScalar {
             _ => None,
         }
     }
+
+    // FIXME: as per the comments on `TypeRef::Array`, this evaluation should not happen at this
+    // parse stage.
+    fn usize_from_literal_expr(expr: ast::Expr) -> ConstScalar {
+        match expr {
+            ast::Expr::Literal(lit) => {
+                let lkind = lit.kind();
+                match lkind {
+                    ast::LiteralKind::IntNumber(num)
+                        if num.suffix() == None || num.suffix() == Some("usize") =>
+                    {
+                        num.value().and_then(|v| v.try_into().ok())
+                    }
+                    _ => None,
+                }
+            }
+            _ => None,
+        }
+        .map(ConstScalar::Usize)
+        .unwrap_or(ConstScalar::Unknown)
+    }
 }
diff --git a/crates/hir_ty/Cargo.toml b/crates/hir_ty/Cargo.toml
index d2bfca53ad..850aaaa5a9 100644
--- a/crates/hir_ty/Cargo.toml
+++ b/crates/hir_ty/Cargo.toml
@@ -18,9 +18,9 @@ ena = "0.14.0"
 tracing = "0.1"
 rustc-hash = "1.1.0"
 scoped-tls = "1"
-chalk-solve = { version = "0.79", default-features = false }
-chalk-ir = "0.79"
-chalk-recursive = { version = "0.79", default-features = false }
+chalk-solve = { version = "0.76", default-features = false }
+chalk-ir = "0.76"
+chalk-recursive = { version = "0.76", default-features = false }
 la-arena = { version = "0.3.0", path = "../../lib/arena" }
 once_cell = { version = "1.5.0" }
 typed-arena = "2.0.1"
diff --git a/crates/hir_ty/src/builder.rs b/crates/hir_ty/src/builder.rs
index c507c42f5b..76e5efc052 100644
--- a/crates/hir_ty/src/builder.rs
+++ b/crates/hir_ty/src/builder.rs
@@ -8,136 +8,67 @@ use chalk_ir::{
     interner::HasInterner,
     AdtId, BoundVar, DebruijnIndex, Scalar,
 };
-use hir_def::{
-    builtin_type::BuiltinType, generics::TypeOrConstParamData, ConstParamId, GenericDefId, TraitId,
-    TypeAliasId,
-};
+use hir_def::{builtin_type::BuiltinType, GenericDefId, TraitId, TypeAliasId};
 use smallvec::SmallVec;
 
 use crate::{
-    consteval::unknown_const_as_generic, db::HirDatabase, primitive, to_assoc_type_id,
-    to_chalk_trait_id, utils::generics, Binders, CallableSig, ConstData, ConstValue, GenericArg,
-    GenericArgData, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt, TyKind,
-    ValueTyDefId,
+    db::HirDatabase, primitive, to_assoc_type_id, to_chalk_trait_id, utils::generics, Binders,
+    CallableSig, GenericArg, Interner, ProjectionTy, Substitution, TraitRef, Ty, TyDefId, TyExt,
+    TyKind, ValueTyDefId,
 };
 
-#[derive(Debug, Clone, PartialEq, Eq)]
-pub enum ParamKind {
-    Type,
-    Const(Ty),
-}
-
 /// This is a builder for `Ty` or anything that needs a `Substitution`.
 pub struct TyBuilder<D> {
     /// The `data` field is used to keep track of what we're building (e.g. an
     /// ADT, a `TraitRef`, ...).
     data: D,
     vec: SmallVec<[GenericArg; 2]>,
-    param_kinds: SmallVec<[ParamKind; 2]>,
-}
-
-impl<A> TyBuilder<A> {
-    fn with_data<B>(self, data: B) -> TyBuilder<B> {
-        TyBuilder { data, param_kinds: self.param_kinds, vec: self.vec }
-    }
+    param_count: usize,
 }
 
 impl<D> TyBuilder<D> {
-    fn new(data: D, param_kinds: SmallVec<[ParamKind; 2]>) -> TyBuilder<D> {
-        TyBuilder { data, vec: SmallVec::with_capacity(param_kinds.len()), param_kinds }
+    fn new(data: D, param_count: usize) -> TyBuilder<D> {
+        TyBuilder { data, param_count, vec: SmallVec::with_capacity(param_count) }
     }
 
     fn build_internal(self) -> (D, Substitution) {
-        assert_eq!(self.vec.len(), self.param_kinds.len());
-        for (a, e) in self.vec.iter().zip(self.param_kinds.iter()) {
-            self.assert_match_kind(a, e);
-        }
+        assert_eq!(self.vec.len(), self.param_count);
         let subst = Substitution::from_iter(Interner, self.vec);
         (self.data, subst)
     }
 
     pub fn push(mut self, arg: impl CastTo<GenericArg>) -> Self {
-        let arg = arg.cast(Interner);
-        let expected_kind = &self.param_kinds[self.vec.len()];
-        let arg_kind = match arg.data(Interner) {
-            chalk_ir::GenericArgData::Ty(_) => ParamKind::Type,
-            chalk_ir::GenericArgData::Lifetime(_) => panic!("Got lifetime in TyBuilder::push"),
-            chalk_ir::GenericArgData::Const(c) => {
-                let c = c.data(Interner);
-                ParamKind::Const(c.ty.clone())
-            }
-        };
-        assert_eq!(*expected_kind, arg_kind);
-        self.vec.push(arg);
+        self.vec.push(arg.cast(Interner));
         self
     }
 
     pub fn remaining(&self) -> usize {
-        self.param_kinds.len() - self.vec.len()
+        self.param_count - self.vec.len()
     }
 
     pub fn fill_with_bound_vars(self, debruijn: DebruijnIndex, starting_from: usize) -> Self {
-        // self.fill is inlined to make borrow checker happy
-        let mut this = self;
-        let other = this.param_kinds.iter().skip(this.vec.len());
-        let filler = (starting_from..).zip(other).map(|(idx, kind)| match kind {
-            ParamKind::Type => {
-                GenericArgData::Ty(TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner))
-                    .intern(Interner)
-            }
-            ParamKind::Const(ty) => GenericArgData::Const(
-                ConstData {
-                    value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
-                    ty: ty.clone(),
-                }
-                .intern(Interner),
-            )
-            .intern(Interner),
-        });
-        this.vec.extend(filler.take(this.remaining()).casted(Interner));
-        assert_eq!(this.remaining(), 0);
-        this
+        self.fill(
+            (starting_from..)
+                .map(|idx| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
+        )
     }
 
     pub fn fill_with_unknown(self) -> Self {
-        // self.fill is inlined to make borrow checker happy
-        let mut this = self;
-        let filler = this.param_kinds.iter().skip(this.vec.len()).map(|x| match x {
-            ParamKind::Type => GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner),
-            ParamKind::Const(ty) => unknown_const_as_generic(ty.clone()),
-        });
-        this.vec.extend(filler.casted(Interner));
-        assert_eq!(this.remaining(), 0);
-        this
+        self.fill(iter::repeat(TyKind::Error.intern(Interner)))
     }
 
-    pub fn fill(mut self, filler: impl FnMut(&ParamKind) -> GenericArg) -> Self {
-        self.vec.extend(self.param_kinds.iter().skip(self.vec.len()).map(filler));
+    pub fn fill(mut self, filler: impl Iterator<Item = impl CastTo<GenericArg>>) -> Self {
+        self.vec.extend(filler.take(self.remaining()).casted(Interner));
         assert_eq!(self.remaining(), 0);
         self
     }
 
     pub fn use_parent_substs(mut self, parent_substs: &Substitution) -> Self {
         assert!(self.vec.is_empty());
-        assert!(parent_substs.len(Interner) <= self.param_kinds.len());
-        self.extend(parent_substs.iter(Interner).cloned());
+        assert!(parent_substs.len(Interner) <= self.param_count);
+        self.vec.extend(parent_substs.iter(Interner).cloned());
         self
     }
-
-    fn extend(&mut self, it: impl Iterator<Item = GenericArg> + Clone) {
-        for x in it.clone().zip(self.param_kinds.iter().skip(self.vec.len())) {
-            self.assert_match_kind(&x.0, &x.1);
-        }
-        self.vec.extend(it);
-    }
-
-    fn assert_match_kind(&self, a: &chalk_ir::GenericArg<Interner>, e: &ParamKind) {
-        match (a.data(Interner), e) {
-            (chalk_ir::GenericArgData::Ty(_), ParamKind::Type)
-            | (chalk_ir::GenericArgData::Const(_), ParamKind::Const(_)) => (),
-            _ => panic!("Mismatched kinds: {:?}, {:?}, {:?}", a, self.vec, self.param_kinds),
-        }
-    }
 }
 
 impl TyBuilder<()> {
@@ -170,26 +101,16 @@ impl TyBuilder<()> {
         TyKind::Slice(argument).intern(Interner)
     }
 
-    pub fn placeholder_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
+    pub fn type_params_subst(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> Substitution {
         let params = generics(db.upcast(), def.into());
-        params.placeholder_subst(db)
+        params.type_params_subst(db)
     }
 
     pub fn subst_for_def(db: &dyn HirDatabase, def: impl Into<GenericDefId>) -> TyBuilder<()> {
         let def = def.into();
         let params = generics(db.upcast(), def);
-        TyBuilder::new(
-            (),
-            params
-                .iter()
-                .map(|(id, data)| match data {
-                    TypeOrConstParamData::TypeParamData(_) => ParamKind::Type,
-                    TypeOrConstParamData::ConstParamData(_) => {
-                        ParamKind::Const(db.const_param_ty(ConstParamId::from_unchecked(id)))
-                    }
-                })
-                .collect(),
-        )
+        let param_count = params.len();
+        TyBuilder::new((), param_count)
     }
 
     pub fn build(self) -> Substitution {
@@ -199,8 +120,10 @@ impl TyBuilder<()> {
 }
 
 impl TyBuilder<hir_def::AdtId> {
-    pub fn adt(db: &dyn HirDatabase, def: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
-        TyBuilder::subst_for_def(db, def).with_data(def)
+    pub fn adt(db: &dyn HirDatabase, adt: hir_def::AdtId) -> TyBuilder<hir_def::AdtId> {
+        let generics = generics(db.upcast(), adt.into());
+        let param_count = generics.len();
+        TyBuilder::new(adt, param_count)
     }
 
     pub fn fill_with_defaults(
@@ -210,15 +133,14 @@ impl TyBuilder<hir_def::AdtId> {
     ) -> Self {
         let defaults = db.generic_defaults(self.data.into());
         for default_ty in defaults.iter().skip(self.vec.len()) {
-            if let GenericArgData::Ty(x) = default_ty.skip_binders().data(Interner) {
-                if x.is_unknown() {
-                    self.vec.push(fallback().cast(Interner));
-                    continue;
-                }
-            };
-            // each default can depend on the previous parameters
-            let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
-            self.vec.push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
+            if default_ty.skip_binders().is_unknown() {
+                self.vec.push(fallback().cast(Interner));
+            } else {
+                // each default can depend on the previous parameters
+                let subst_so_far = Substitution::from_iter(Interner, self.vec.clone());
+                self.vec
+                    .push(default_ty.clone().substitute(Interner, &subst_so_far).cast(Interner));
+            }
         }
         self
     }
@@ -232,7 +154,7 @@ impl TyBuilder<hir_def::AdtId> {
 pub struct Tuple(usize);
 impl TyBuilder<Tuple> {
     pub fn tuple(size: usize) -> TyBuilder<Tuple> {
-        TyBuilder::new(Tuple(size), iter::repeat(ParamKind::Type).take(size).collect())
+        TyBuilder::new(Tuple(size), size)
     }
 
     pub fn build(self) -> Ty {
@@ -242,8 +164,10 @@ impl TyBuilder<Tuple> {
 }
 
 impl TyBuilder<TraitId> {
-    pub fn trait_ref(db: &dyn HirDatabase, def: TraitId) -> TyBuilder<TraitId> {
-        TyBuilder::subst_for_def(db, def).with_data(def)
+    pub fn trait_ref(db: &dyn HirDatabase, trait_id: TraitId) -> TyBuilder<TraitId> {
+        let generics = generics(db.upcast(), trait_id.into());
+        let param_count = generics.len();
+        TyBuilder::new(trait_id, param_count)
     }
 
     pub fn build(self) -> TraitRef {
@@ -253,8 +177,13 @@ impl TyBuilder<TraitId> {
 }
 
 impl TyBuilder<TypeAliasId> {
-    pub fn assoc_type_projection(db: &dyn HirDatabase, def: TypeAliasId) -> TyBuilder<TypeAliasId> {
-        TyBuilder::subst_for_def(db, def).with_data(def)
+    pub fn assoc_type_projection(
+        db: &dyn HirDatabase,
+        type_alias: TypeAliasId,
+    ) -> TyBuilder<TypeAliasId> {
+        let generics = generics(db.upcast(), type_alias.into());
+        let param_count = generics.len();
+        TyBuilder::new(type_alias, param_count)
     }
 
     pub fn build(self) -> ProjectionTy {
@@ -265,16 +194,8 @@ impl TyBuilder<TypeAliasId> {
 
 impl<T: HasInterner<Interner = Interner> + Fold<Interner>> TyBuilder<Binders<T>> {
     fn subst_binders(b: Binders<T>) -> Self {
-        let param_kinds = b
-            .binders
-            .iter(Interner)
-            .map(|x| match x {
-                chalk_ir::VariableKind::Ty(_) => ParamKind::Type,
-                chalk_ir::VariableKind::Lifetime => panic!("Got lifetime parameter"),
-                chalk_ir::VariableKind::Const(ty) => ParamKind::Const(ty.clone()),
-            })
-            .collect();
-        TyBuilder::new(b, param_kinds)
+        let param_count = b.binders.len(Interner);
+        TyBuilder::new(b, param_count)
     }
 
     pub fn build(self) -> <T as Fold<Interner>>::Result {
diff --git a/crates/hir_ty/src/chalk_db.rs b/crates/hir_ty/src/chalk_db.rs
index 1b67e5a86b..0a46aea950 100644
--- a/crates/hir_ty/src/chalk_db.rs
+++ b/crates/hir_ty/src/chalk_db.rs
@@ -19,8 +19,7 @@ use hir_expand::name::name;
 use crate::{
     db::HirDatabase,
     display::HirDisplay,
-    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_binders,
-    make_single_type_binders,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, make_only_type_binders,
     mapping::{from_chalk, ToChalk, TypeAliasAsValue},
     method_resolution::{TraitImpls, TyFingerprint, ALL_FLOAT_FPS, ALL_INT_FPS},
     to_assoc_type_id, to_chalk_trait_id,
@@ -207,8 +206,8 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
                 let (datas, binders) = (*datas).as_ref().into_value_and_skipped_binders();
                 let data = &datas.impl_traits[idx as usize];
                 let bound = OpaqueTyDatumBound {
-                    bounds: make_single_type_binders(data.bounds.skip_binders().to_vec()),
-                    where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
+                    bounds: make_only_type_binders(1, data.bounds.skip_binders().to_vec()),
+                    where_clauses: make_only_type_binders(0, vec![]),
                 };
                 chalk_ir::Binders::new(binders, bound)
             }
@@ -256,22 +255,25 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
                             .intern(Interner),
                     });
                     let bound = OpaqueTyDatumBound {
-                        bounds: make_single_type_binders(vec![
-                            crate::wrap_empty_binders(impl_bound),
-                            crate::wrap_empty_binders(proj_bound),
-                        ]),
-                        where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
+                        bounds: make_only_type_binders(
+                            1,
+                            vec![
+                                crate::wrap_empty_binders(impl_bound),
+                                crate::wrap_empty_binders(proj_bound),
+                            ],
+                        ),
+                        where_clauses: make_only_type_binders(0, vec![]),
                     };
                     // The opaque type has 1 parameter.
-                    make_single_type_binders(bound)
+                    make_only_type_binders(1, bound)
                 } else {
                     // If failed to find Symbol’s value as variable is void: Future::Output, return empty bounds as fallback.
                     let bound = OpaqueTyDatumBound {
-                        bounds: chalk_ir::Binders::empty(Interner, vec![]),
-                        where_clauses: chalk_ir::Binders::empty(Interner, vec![]),
+                        bounds: make_only_type_binders(0, vec![]),
+                        where_clauses: make_only_type_binders(0, vec![]),
                     };
                     // The opaque type has 1 parameter.
-                    make_single_type_binders(bound)
+                    make_only_type_binders(1, bound)
                 }
             }
         };
@@ -308,7 +310,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
             argument_types: sig.params().to_vec(),
             return_type: sig.ret().clone(),
         };
-        chalk_ir::Binders::empty(Interner, io.shifted_in(Interner))
+        make_only_type_binders(0, io.shifted_in(Interner))
     }
     fn closure_upvars(
         &self,
@@ -316,7 +318,7 @@ impl<'a> chalk_solve::RustIrDatabase<Interner> for ChalkContext<'a> {
         _substs: &chalk_ir::Substitution<Interner>,
     ) -> chalk_ir::Binders<chalk_ir::Ty<Interner>> {
         let ty = TyBuilder::unit();
-        chalk_ir::Binders::empty(Interner, ty)
+        make_only_type_binders(0, ty)
     }
     fn closure_fn_substitution(
         &self,
@@ -405,7 +407,7 @@ pub(crate) fn associated_ty_data_query(
     // let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let resolver = hir_def::resolver::HasResolver::resolver(type_alias, db.upcast());
     let ctx = crate::TyLoweringContext::new(db, &resolver)
-        .with_type_param_mode(crate::lower::ParamLoweringMode::Variable);
+        .with_type_param_mode(crate::lower::TypeParamLoweringMode::Variable);
     let self_ty =
         TyKind::BoundVar(BoundVar::new(crate::DebruijnIndex::INNERMOST, 0)).intern(Interner);
     let mut bounds: Vec<_> = type_alias_data
@@ -438,7 +440,7 @@ pub(crate) fn associated_ty_data_query(
         trait_id: to_chalk_trait_id(trait_),
         id,
         name: type_alias,
-        binders: make_binders(db, &generic_params, bound_data),
+        binders: make_only_type_binders(generic_params.len(), bound_data),
     };
     Arc::new(datum)
 }
@@ -453,7 +455,7 @@ pub(crate) fn trait_datum_query(
     let trait_data = db.trait_data(trait_);
     debug!("trait {:?} = {:?}", trait_id, trait_data.name);
     let generic_params = generics(db.upcast(), trait_.into());
-    let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let flags = rust_ir::TraitFlags {
         auto: trait_data.is_auto,
         upstream: trait_.lookup(db.upcast()).container.krate() != krate,
@@ -470,7 +472,7 @@ pub(crate) fn trait_datum_query(
         lang_attr(db.upcast(), trait_).and_then(|name| well_known_trait_from_lang_attr(&name));
     let trait_datum = TraitDatum {
         id: trait_id,
-        binders: make_binders(db, &generic_params, trait_datum_bound),
+        binders: make_only_type_binders(bound_vars.len(Interner), trait_datum_bound),
         flags,
         associated_ty_ids,
         well_known,
@@ -518,11 +520,11 @@ pub(crate) fn struct_datum_query(
 ) -> Arc<StructDatum> {
     debug!("struct_datum {:?}", struct_id);
     let chalk_ir::AdtId(adt_id) = struct_id;
-    let generic_params = generics(db.upcast(), adt_id.into());
+    let num_params = generics(db.upcast(), adt_id.into()).len();
     let upstream = adt_id.module(db.upcast()).krate() != krate;
     let where_clauses = {
         let generic_params = generics(db.upcast(), adt_id.into());
-        let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+        let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
         convert_where_clauses(db, adt_id.into(), &bound_vars)
     };
     let flags = rust_ir::AdtFlags {
@@ -540,7 +542,7 @@ pub(crate) fn struct_datum_query(
         // FIXME set ADT kind
         kind: rust_ir::AdtKind::Struct,
         id: struct_id,
-        binders: make_binders(db, &generic_params, struct_datum_bound),
+        binders: make_only_type_binders(num_params, struct_datum_bound),
         flags,
     };
     Arc::new(struct_datum)
@@ -572,7 +574,7 @@ fn impl_def_datum(
     let impl_data = db.impl_data(impl_id);
 
     let generic_params = generics(db.upcast(), impl_id.into());
-    let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let trait_ = trait_ref.hir_trait_id();
     let impl_type = if impl_id.lookup(db.upcast()).container.krate() == krate {
         rust_ir::ImplType::Local
@@ -609,7 +611,7 @@ fn impl_def_datum(
         .collect();
     debug!("impl_datum: {:?}", impl_datum_bound);
     let impl_datum = ImplDatum {
-        binders: make_binders(db, &generic_params, impl_datum_bound),
+        binders: make_only_type_binders(bound_vars.len(Interner), impl_datum_bound),
         impl_type,
         polarity,
         associated_ty_value_ids,
@@ -665,12 +667,12 @@ pub(crate) fn fn_def_datum_query(
     let callable_def: CallableDefId = from_chalk(db, fn_def_id);
     let generic_params = generics(db.upcast(), callable_def.into());
     let (sig, binders) = db.callable_item_signature(callable_def).into_value_and_skipped_binders();
-    let bound_vars = generic_params.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let bound_vars = generic_params.bound_vars_subst(DebruijnIndex::INNERMOST);
     let where_clauses = convert_where_clauses(db, callable_def.into(), &bound_vars);
     let bound = rust_ir::FnDefDatumBound {
         // Note: Chalk doesn't actually use this information yet as far as I am aware, but we provide it anyway
-        inputs_and_output: chalk_ir::Binders::empty(
-            Interner,
+        inputs_and_output: make_only_type_binders(
+            0,
             rust_ir::FnDefInputsAndOutputDatum {
                 argument_types: sig.params().to_vec(),
                 return_type: sig.ret().clone(),
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index b0885ab003..8758f38bfc 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -237,11 +237,11 @@ impl TyExt for Ty {
             TyKind::Placeholder(idx) => {
                 let id = from_placeholder_idx(db, *idx);
                 let generic_params = db.generic_params(id.parent);
-                let param_data = &generic_params.type_or_consts[id.local_id];
+                let param_data = &generic_params.tocs[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
-                            let substs = TyBuilder::placeholder_subst(db, id.parent);
+                            let substs = TyBuilder::type_params_subst(db, id.parent);
                             let predicates = db
                                 .generic_predicates(id.parent)
                                 .iter()
diff --git a/crates/hir_ty/src/consteval.rs b/crates/hir_ty/src/consteval.rs
index 24296c6b7b..5cc474aca6 100644
--- a/crates/hir_ty/src/consteval.rs
+++ b/crates/hir_ty/src/consteval.rs
@@ -2,25 +2,15 @@
 
 use std::{collections::HashMap, convert::TryInto, fmt::Display};
 
-use chalk_ir::{BoundVar, DebruijnIndex, GenericArgData, IntTy, Scalar};
+use chalk_ir::{IntTy, Scalar};
 use hir_def::{
     expr::{ArithOp, BinaryOp, Expr, Literal, Pat},
-    path::ModPath,
-    resolver::{Resolver, ValueNs},
     type_ref::ConstScalar,
 };
 use hir_expand::name::Name;
 use la_arena::{Arena, Idx};
-use stdx::never;
 
-use crate::{
-    db::HirDatabase,
-    infer::{Expectation, InferenceContext},
-    lower::ParamLoweringMode,
-    to_placeholder_idx,
-    utils::Generics,
-    Const, ConstData, ConstValue, GenericArg, Interner, Ty, TyKind,
-};
+use crate::{Const, ConstData, ConstValue, Interner, Ty, TyKind};
 
 /// Extension trait for [`Const`]
 pub trait ConstExt {
@@ -313,57 +303,6 @@ pub fn eval_usize(expr: Idx<Expr>, mut ctx: ConstEvalCtx<'_>) -> Option<u64> {
     None
 }
 
-pub(crate) fn path_to_const(
-    db: &dyn HirDatabase,
-    resolver: &Resolver,
-    path: &ModPath,
-    mode: ParamLoweringMode,
-    args_lazy: impl FnOnce() -> Generics,
-    debruijn: DebruijnIndex,
-) -> 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(x) => ConstValue::BoundVar(BoundVar::new(debruijn, x)),
-                    None => {
-                        never!(
-                            "Generic list doesn't contain this param: {:?}, {}, {:?}",
-                            args,
-                            path,
-                            p
-                        );
-                        return None;
-                    }
-                },
-            };
-            Some(ConstData { ty, value }.intern(Interner))
-        }
-        _ => None,
-    }
-}
-
-pub fn unknown_const(ty: Ty) -> Const {
-    ConstData {
-        ty,
-        value: ConstValue::Concrete(chalk_ir::ConcreteConst { interned: ConstScalar::Unknown }),
-    }
-    .intern(Interner)
-}
-
-pub fn unknown_const_usize() -> Const {
-    unknown_const(TyKind::Scalar(chalk_ir::Scalar::Uint(chalk_ir::UintTy::Usize)).intern(Interner))
-}
-
-pub fn unknown_const_as_generic(ty: Ty) -> GenericArg {
-    GenericArgData::Const(unknown_const(ty)).intern(Interner)
-}
-
 /// Interns a possibly-unknown target usize
 pub fn usize_const(value: Option<u64>) -> Const {
     ConstData {
@@ -374,27 +313,3 @@ pub fn usize_const(value: Option<u64>) -> Const {
     }
     .intern(Interner)
 }
-
-pub(crate) fn eval_to_const(
-    expr: Idx<Expr>,
-    mode: ParamLoweringMode,
-    ctx: &mut InferenceContext,
-    args: impl FnOnce() -> Generics,
-    debruijn: DebruijnIndex,
-) -> Const {
-    if let Expr::Path(p) = &ctx.body.exprs[expr] {
-        let db = ctx.db;
-        let resolver = &ctx.resolver;
-        if let Some(c) = path_to_const(db, resolver, p.mod_path(), mode, args, debruijn) {
-            return c;
-        }
-    }
-    let body = ctx.body.clone();
-    let ctx = ConstEvalCtx {
-        exprs: &body.exprs,
-        pats: &body.pats,
-        local_data: HashMap::default(),
-        infer: &mut |x| ctx.infer_expr(x, &Expectation::None),
-    };
-    usize_const(eval_usize(expr, ctx))
-}
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index 599fd16dd0..e144dd43f4 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -13,7 +13,7 @@ use la_arena::ArenaMap;
 use crate::{
     chalk_db,
     method_resolution::{InherentImpls, TraitImpls},
-    Binders, CallableDefId, FnDefId, GenericArg, ImplTraitId, InferenceResult, Interner, PolyFnSig,
+    Binders, CallableDefId, FnDefId, ImplTraitId, InferenceResult, Interner, PolyFnSig,
     QuantifiedWhereClause, ReturnTypeImplTraits, TraitRef, Ty, TyDefId, ValueTyDefId,
 };
 use hir_expand::name::Name;
@@ -73,7 +73,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
 
     #[salsa::invoke(crate::lower::generic_defaults_query)]
     #[salsa::cycle(crate::lower::generic_defaults_recover)]
-    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<GenericArg>]>;
+    fn generic_defaults(&self, def: GenericDefId) -> Arc<[Binders<Ty>]>;
 
     #[salsa::invoke(InherentImpls::inherent_impls_in_crate_query)]
     fn inherent_impls_in_crate(&self, krate: CrateId) -> Arc<InherentImpls>;
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index eb74809bfe..d81aa34824 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -14,7 +14,7 @@ use hir_def::{
     intern::{Internable, Interned},
     item_scope::ItemInNs,
     path::{Path, PathKind},
-    type_ref::{ConstScalar, TraitBoundModifier, TypeBound, TypeRef},
+    type_ref::{TraitBoundModifier, TypeBound, TypeRef},
     visibility::Visibility,
     HasModule, ItemContainerId, Lookup, ModuleId, TraitId,
 };
@@ -28,10 +28,10 @@ use crate::{
     mapping::from_chalk,
     primitive, subst_prefix, to_assoc_type_id,
     utils::{self, generics},
-    AdtId, AliasEq, AliasTy, Binders, CallableDefId, CallableSig, Const, ConstValue, DomainGoal,
-    GenericArg, ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability,
-    OpaqueTy, ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, Substitution, TraitRef,
-    TraitRefExt, Ty, TyExt, TyKind, WhereClause,
+    AdtId, AliasEq, AliasTy, CallableDefId, CallableSig, Const, ConstValue, DomainGoal, GenericArg,
+    ImplTraitId, Interner, Lifetime, LifetimeData, LifetimeOutlives, Mutability, OpaqueTy,
+    ProjectionTy, ProjectionTyExt, QuantifiedWhereClause, Scalar, TraitRef, TraitRefExt, Ty, TyExt,
+    TyKind, WhereClause,
 };
 
 pub struct HirFormatter<'a> {
@@ -316,11 +316,11 @@ impl HirDisplay for Const {
         let data = self.interned();
         match data.value {
             ConstValue::BoundVar(idx) => idx.hir_fmt(f),
-            ConstValue::InferenceVar(..) => write!(f, "#c#"),
+            ConstValue::InferenceVar(..) => write!(f, "_"),
             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.tocs[id.local_id];
                 write!(f, "{}", param_data.name().unwrap())
             }
             ConstValue::Concrete(c) => write!(f, "{}", c.interned),
@@ -544,37 +544,24 @@ impl HirDisplay for Ty {
                         {
                             None => parameters.as_slice(Interner),
                             Some(default_parameters) => {
-                                fn should_show(
-                                    parameter: &GenericArg,
-                                    default_parameters: &[Binders<GenericArg>],
-                                    i: usize,
-                                    parameters: &Substitution,
-                                ) -> bool {
-                                    if parameter.ty(Interner).map(|x| x.kind(Interner))
-                                        == Some(&TyKind::Error)
-                                    {
-                                        return true;
-                                    }
-                                    if let Some(ConstValue::Concrete(c)) =
-                                        parameter.constant(Interner).map(|x| x.data(Interner).value)
-                                    {
-                                        if c.interned == ConstScalar::Unknown {
-                                            return true;
-                                        }
-                                    }
-                                    let default_parameter = match default_parameters.get(i) {
-                                        Some(x) => x,
-                                        None => return true,
-                                    };
-                                    let actual_default = default_parameter
-                                        .clone()
-                                        .substitute(Interner, &subst_prefix(parameters, i));
-                                    parameter != &actual_default
-                                }
                                 let mut default_from = 0;
                                 for (i, parameter) in parameters.iter(Interner).enumerate() {
-                                    if should_show(parameter, &default_parameters, i, parameters) {
-                                        default_from = i + 1;
+                                    match (
+                                        parameter.assert_ty_ref(Interner).kind(Interner),
+                                        default_parameters.get(i),
+                                    ) {
+                                        (&TyKind::Error, _) | (_, None) => {
+                                            default_from = i + 1;
+                                        }
+                                        (_, Some(default_parameter)) => {
+                                            let actual_default = default_parameter
+                                                .clone()
+                                                .substitute(Interner, &subst_prefix(parameters, i));
+                                            if parameter.assert_ty_ref(Interner) != &actual_default
+                                            {
+                                                default_from = i + 1;
+                                            }
+                                        }
                                     }
                                 }
                                 &parameters.as_slice(Interner)[0..default_from]
@@ -693,14 +680,14 @@ impl HirDisplay for Ty {
             TyKind::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.tocs[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
                             write!(f, "{}", p.name.clone().unwrap_or_else(Name::missing))?
                         }
                         TypeParamProvenance::ArgumentImplTrait => {
-                            let substs = generics.placeholder_subst(f.db);
+                            let substs = generics.type_params_subst(f.db);
                             let bounds =
                                 f.db.generic_predicates(id.parent)
                                     .iter()
@@ -1294,7 +1281,6 @@ impl HirDisplay for hir_def::path::GenericArg {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         match self {
             hir_def::path::GenericArg::Type(ty) => ty.hir_fmt(f),
-            hir_def::path::GenericArg::Const(c) => write!(f, "{}", c),
             hir_def::path::GenericArg::Lifetime(lifetime) => write!(f, "{}", lifetime.name),
         }
     }
diff --git a/crates/hir_ty/src/infer.rs b/crates/hir_ty/src/infer.rs
index 4ee5391057..0c62f58940 100644
--- a/crates/hir_ty/src/infer.rs
+++ b/crates/hir_ty/src/infer.rs
@@ -16,7 +16,7 @@
 use std::ops::Index;
 use std::sync::Arc;
 
-use chalk_ir::{cast::Cast, ConstValue, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
+use chalk_ir::{cast::Cast, DebruijnIndex, Mutability, Safety, Scalar, TypeFlags};
 use hir_def::{
     body::Body,
     data::{ConstData, FunctionData, StaticData},
@@ -29,16 +29,14 @@ use hir_def::{
     TraitId, TypeAliasId, VariantId,
 };
 use hir_expand::name::{name, Name};
-use itertools::Either;
 use la_arena::ArenaMap;
 use rustc_hash::FxHashMap;
 use stdx::impl_from;
 
 use crate::{
-    builder::ParamKind, db::HirDatabase, fold_tys_and_consts, infer::coerce::CoerceMany,
-    lower::ImplTraitLoweringMode, to_assoc_type_id, AliasEq, AliasTy, Const, DomainGoal,
-    GenericArg, GenericArgData, Goal, InEnvironment, Interner, ProjectionTy, Substitution,
-    TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
+    db::HirDatabase, fold_tys, infer::coerce::CoerceMany, lower::ImplTraitLoweringMode,
+    to_assoc_type_id, AliasEq, AliasTy, DomainGoal, Goal, InEnvironment, Interner, ProjectionTy,
+    Substitution, TraitEnvironment, TraitRef, Ty, TyBuilder, TyExt, TyKind,
 };
 
 // This lint has a false positive here. See the link below for details.
@@ -356,11 +354,11 @@ impl Index<PatId> for InferenceResult {
 
 /// The inference context contains all information needed during type inference.
 #[derive(Clone, Debug)]
-pub(crate) struct InferenceContext<'a> {
-    pub(crate) db: &'a dyn HirDatabase,
+struct InferenceContext<'a> {
+    db: &'a dyn HirDatabase,
     owner: DefWithBodyId,
-    pub(crate) body: Arc<Body>,
-    pub(crate) resolver: Resolver,
+    body: Arc<Body>,
+    resolver: Resolver,
     table: unify::InferenceTable<'a>,
     trait_env: Arc<TraitEnvironment>,
     result: InferenceResult,
@@ -490,20 +488,6 @@ impl<'a> InferenceContext<'a> {
         self.make_ty_with_mode(type_ref, ImplTraitLoweringMode::Disallowed)
     }
 
-    /// Replaces ConstScalar::Unknown by a new type var, so we can maybe still infer it.
-    fn insert_const_vars_shallow(&mut self, c: Const) -> Const {
-        let data = c.data(Interner);
-        match data.value {
-            ConstValue::Concrete(cc) => match cc.interned {
-                hir_def::type_ref::ConstScalar::Usize(_) => c,
-                hir_def::type_ref::ConstScalar::Unknown => {
-                    self.table.new_const_var(data.ty.clone())
-                }
-            },
-            _ => c,
-        }
-    }
-
     /// Replaces Ty::Unknown by a new type var, so we can maybe still infer it.
     fn insert_type_vars_shallow(&mut self, ty: Ty) -> Ty {
         match ty.kind(Interner) {
@@ -521,14 +505,7 @@ impl<'a> InferenceContext<'a> {
     }
 
     fn insert_type_vars(&mut self, ty: Ty) -> Ty {
-        fold_tys_and_consts(
-            ty,
-            |x, _| match x {
-                Either::Left(ty) => Either::Left(self.insert_type_vars_shallow(ty)),
-                Either::Right(c) => Either::Right(self.insert_const_vars_shallow(c)),
-            },
-            DebruijnIndex::INNERMOST,
-        )
+        fold_tys(ty, |ty, _| self.insert_type_vars_shallow(ty), DebruijnIndex::INNERMOST)
     }
 
     fn resolve_obligations_as_possible(&mut self) {
@@ -556,7 +533,7 @@ impl<'a> InferenceContext<'a> {
         &mut self,
         inner_ty: Ty,
         assoc_ty: Option<TypeAliasId>,
-        params: &[GenericArg],
+        params: &[Ty],
     ) -> Ty {
         match assoc_ty {
             Some(res_assoc_ty) => {
@@ -565,10 +542,9 @@ impl<'a> InferenceContext<'a> {
                     _ => panic!("resolve_associated_type called with non-associated type"),
                 };
                 let ty = self.table.new_type_var();
-                let mut param_iter = params.iter().cloned();
                 let trait_ref = TyBuilder::trait_ref(self.db, trait_)
                     .push(inner_ty)
-                    .fill(|_| param_iter.next().unwrap())
+                    .fill(params.iter().cloned())
                     .build();
                 let alias_eq = AliasEq {
                     alias: AliasTy::Projection(ProjectionTy {
@@ -651,21 +627,13 @@ impl<'a> InferenceContext<'a> {
             }
             TypeNs::SelfType(impl_id) => {
                 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
-                let substs = generics.placeholder_subst(self.db);
+                let substs = generics.type_params_subst(self.db);
                 let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
                 self.resolve_variant_on_alias(ty, unresolved, path)
             }
             TypeNs::TypeAliasId(it) => {
                 let ty = TyBuilder::def_ty(self.db, it.into())
-                    .fill(|x| match x {
-                        ParamKind::Type => {
-                            GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
-                        }
-                        ParamKind::Const(ty) => {
-                            GenericArgData::Const(self.table.new_const_var(ty.clone()))
-                                .intern(Interner)
-                        }
-                    })
+                    .fill(std::iter::repeat_with(|| self.table.new_type_var()))
                     .build();
                 self.resolve_variant_on_alias(ty, unresolved, path)
             }
@@ -859,7 +827,7 @@ impl<'a> InferenceContext<'a> {
 /// When inferring an expression, we propagate downward whatever type hint we
 /// are able in the form of an `Expectation`.
 #[derive(Clone, PartialEq, Eq, Debug)]
-pub(crate) enum Expectation {
+enum Expectation {
     None,
     HasType(Ty),
     // Castable(Ty), // rustc has this, we currently just don't propagate an expectation for casts
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index e78a6377e5..c093f0e4b2 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -7,15 +7,13 @@ use std::{
     sync::Arc,
 };
 
-use chalk_ir::{
-    cast::Cast, fold::Shift, DebruijnIndex, GenericArgData, Mutability, TyVariableKind,
-};
+use chalk_ir::{cast::Cast, fold::Shift, Mutability, TyVariableKind};
 use hir_def::{
     expr::{ArithOp, Array, BinaryOp, CmpOp, Expr, ExprId, Literal, Ordering, Statement, UnaryOp},
     generics::TypeOrConstParamData,
     path::{GenericArg, GenericArgs},
     resolver::resolver_for_expr,
-    ConstParamId, FieldId, FunctionId, ItemContainerId, Lookup,
+    FieldId, FunctionId, ItemContainerId, Lookup,
 };
 use hir_expand::name::{name, Name};
 use stdx::always;
@@ -25,9 +23,7 @@ use crate::{
     autoderef::{self, Autoderef},
     consteval,
     infer::coerce::CoerceMany,
-    lower::{
-        const_or_path_to_chalk, generic_arg_to_chalk, lower_to_chalk_mutability, ParamLoweringMode,
-    },
+    lower::lower_to_chalk_mutability,
     mapping::from_chalk,
     method_resolution,
     primitive::{self, UintTy},
@@ -43,7 +39,7 @@ use super::{
 };
 
 impl<'a> InferenceContext<'a> {
-    pub(crate) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
+    pub(super) fn infer_expr(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
         let ty = self.infer_expr_inner(tgt_expr, expected);
         if self.resolve_ty_shallow(&ty).is_never() {
             // Any expression that produces a value of type `!` must have diverged
@@ -666,7 +662,7 @@ impl<'a> InferenceContext<'a> {
                     self.resolve_associated_type_with_params(
                         self_ty,
                         self.resolve_ops_index_output(),
-                        &[GenericArgData::Ty(index_ty).intern(Interner)],
+                        &[index_ty],
                     )
                 } else {
                     self.err_ty()
@@ -708,7 +704,7 @@ impl<'a> InferenceContext<'a> {
                             let cur_elem_ty = self.infer_expr_inner(expr, &expected);
                             coerce.coerce(self, Some(expr), &cur_elem_ty);
                         }
-                        consteval::usize_const(Some(items.len() as u64))
+                        Some(items.len() as u64)
                     }
                     &Array::Repeat { initializer, repeat } => {
                         self.infer_expr_coerce(initializer, &Expectation::has_type(elem_ty));
@@ -719,22 +715,19 @@ impl<'a> InferenceContext<'a> {
                             ),
                         );
 
-                        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(None)
-                        }
+                        consteval::eval_usize(
+                            repeat,
+                            consteval::ConstEvalCtx {
+                                exprs: &body.exprs,
+                                pats: &body.pats,
+                                local_data: Default::default(),
+                                infer: &mut |x| self.infer_expr(x, &expected),
+                            },
+                        )
                     }
                 };
 
-                TyKind::Array(coerce.complete(), len).intern(Interner)
+                TyKind::Array(coerce.complete(), consteval::usize_const(len)).intern(Interner)
             }
             Expr::Literal(lit) => match lit {
                 Literal::Bool(..) => TyKind::Scalar(Scalar::Bool).intern(Interner),
@@ -1045,52 +1038,38 @@ impl<'a> InferenceContext<'a> {
         let total_len = parent_params + type_params + const_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
         // Parent arguments are unknown
-        for (id, param) in def_generics.iter_parent() {
+        for (_id, param) in def_generics.iter_parent() {
             match param {
                 TypeOrConstParamData::TypeParamData(_) => {
-                    substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
+                    substs.push(self.table.new_type_var());
                 }
                 TypeOrConstParamData::ConstParamData(_) => {
-                    let ty = self.db.const_param_ty(ConstParamId::from_unchecked(id));
-                    substs
-                        .push(GenericArgData::Const(self.table.new_const_var(ty)).intern(Interner));
+                    // FIXME: here we should do something else
+                    substs.push(self.table.new_type_var());
                 }
             }
         }
-        // handle provided arguments
+        // handle provided type arguments
         if let Some(generic_args) = generic_args {
             // if args are provided, it should be all of them, but we can't rely on that
-            for (arg, kind_id) in generic_args
+            for arg in generic_args
                 .args
                 .iter()
-                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
-                .take(type_params + const_params)
-                .zip(def_generics.iter_id().skip(parent_params))
+                .filter(|arg| matches!(arg, GenericArg::Type(_)))
+                .take(type_params)
             {
-                if let Some(g) = generic_arg_to_chalk(
-                    self.db,
-                    kind_id,
-                    arg,
-                    self,
-                    |this, type_ref| this.make_ty(type_ref),
-                    |this, c| {
-                        const_or_path_to_chalk(
-                            this.db,
-                            &this.resolver,
-                            c,
-                            ParamLoweringMode::Placeholder,
-                            || generics(this.db.upcast(), (&this.resolver).generic_def().unwrap()),
-                            DebruijnIndex::INNERMOST,
-                        )
-                    },
-                ) {
-                    substs.push(g);
+                match arg {
+                    GenericArg::Type(type_ref) => {
+                        let ty = self.make_ty(type_ref);
+                        substs.push(ty);
+                    }
+                    GenericArg::Lifetime(_) => {}
                 }
             }
         };
         let supplied_params = substs.len();
         for _ in supplied_params..total_len {
-            substs.push(GenericArgData::Ty(self.table.new_type_var()).intern(Interner));
+            substs.push(self.table.new_type_var());
         }
         assert_eq!(substs.len(), total_len);
         Substitution::from_iter(Interner, substs)
diff --git a/crates/hir_ty/src/infer/path.rs b/crates/hir_ty/src/infer/path.rs
index 1d23654576..0d6c8f12d2 100644
--- a/crates/hir_ty/src/infer/path.rs
+++ b/crates/hir_ty/src/infer/path.rs
@@ -1,5 +1,7 @@
 //! Path expression resolution.
 
+use std::iter;
+
 use chalk_ir::cast::Cast;
 use hir_def::{
     path::{Path, PathSegment},
@@ -9,8 +11,8 @@ use hir_def::{
 use hir_expand::name::Name;
 
 use crate::{
-    builder::ParamKind, consteval, method_resolution, GenericArgData, Interner, Substitution,
-    TraitRefExt, Ty, TyBuilder, TyExt, TyKind, ValueTyDefId,
+    method_resolution, Interner, Substitution, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
+    ValueTyDefId,
 };
 
 use super::{ExprOrPatId, InferenceContext, TraitRef};
@@ -80,7 +82,7 @@ impl<'a> InferenceContext<'a> {
             }
             ValueNs::ImplSelf(impl_id) => {
                 let generics = crate::utils::generics(self.db.upcast(), impl_id.into());
-                let substs = generics.placeholder_subst(self.db);
+                let substs = generics.type_params_subst(self.db);
                 let ty = self.db.impl_self_ty(impl_id).substitute(Interner, &substs);
                 if let Some((AdtId::StructId(struct_id), substs)) = ty.as_adt() {
                     let ty = self.db.value_ty(struct_id.into()).substitute(Interner, &substs);
@@ -96,19 +98,9 @@ impl<'a> InferenceContext<'a> {
         let parent_substs = self_subst.unwrap_or_else(|| Substitution::empty(Interner));
         let ctx = crate::lower::TyLoweringContext::new(self.db, &self.resolver);
         let substs = ctx.substs_from_path(path, typable, true);
-        let mut it = substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned();
         let ty = TyBuilder::value_ty(self.db, typable)
             .use_parent_substs(&parent_substs)
-            .fill(|x| {
-                it.next().unwrap_or_else(|| match x {
-                    ParamKind::Type => {
-                        GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
-                    }
-                    ParamKind::Const(_) => {
-                        GenericArgData::Const(consteval::usize_const(None)).intern(Interner)
-                    }
-                })
-            })
+            .fill(substs.as_slice(Interner)[parent_substs.len(Interner)..].iter().cloned())
             .build();
         Some(ty)
     }
@@ -249,15 +241,7 @@ impl<'a> InferenceContext<'a> {
                 let substs = match container {
                     ItemContainerId::ImplId(impl_id) => {
                         let impl_substs = TyBuilder::subst_for_def(self.db, impl_id)
-                            .fill(|x| match x {
-                                ParamKind::Type => {
-                                    GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
-                                }
-                                ParamKind::Const(ty) => {
-                                    GenericArgData::Const(self.table.new_const_var(ty.clone()))
-                                        .intern(Interner)
-                                }
-                            })
+                            .fill(iter::repeat_with(|| self.table.new_type_var()))
                             .build();
                         let impl_self_ty =
                             self.db.impl_self_ty(impl_id).substitute(Interner, &impl_substs);
@@ -268,15 +252,7 @@ impl<'a> InferenceContext<'a> {
                         // we're picking this method
                         let trait_ref = TyBuilder::trait_ref(self.db, trait_)
                             .push(ty.clone())
-                            .fill(|x| match x {
-                                ParamKind::Type => {
-                                    GenericArgData::Ty(self.table.new_type_var()).intern(Interner)
-                                }
-                                ParamKind::Const(ty) => {
-                                    GenericArgData::Const(self.table.new_const_var(ty.clone()))
-                                        .intern(Interner)
-                                }
-                            })
+                            .fill(std::iter::repeat_with(|| self.table.new_type_var()))
                             .build();
                         self.push_obligation(trait_ref.clone().cast(Interner));
                         Some(trait_ref.substitution)
diff --git a/crates/hir_ty/src/infer/unify.rs b/crates/hir_ty/src/infer/unify.rs
index deb536e511..8a6c34b493 100644
--- a/crates/hir_ty/src/infer/unify.rs
+++ b/crates/hir_ty/src/infer/unify.rs
@@ -1,6 +1,6 @@
 //! Unification and canonicalization logic.
 
-use std::{fmt, mem, sync::Arc};
+use std::{fmt, iter, mem, sync::Arc};
 
 use chalk_ir::{
     cast::Cast, fold::Fold, interner::HasInterner, zip::Zip, FloatTy, IntTy, NoSolution,
@@ -9,14 +9,13 @@ use chalk_ir::{
 use chalk_solve::infer::ParameterEnaVariableExt;
 use ena::unify::UnifyKey;
 use hir_expand::name;
-use stdx::never;
 
 use super::{InferOk, InferResult, InferenceContext, TypeError};
 use crate::{
     db::HirDatabase, fold_tys, static_lifetime, traits::FnTrait, AliasEq, AliasTy, BoundVar,
-    Canonical, Const, DebruijnIndex, GenericArg, GenericArgData, Goal, Guidance, InEnvironment,
-    InferenceVar, Interner, Lifetime, ParamKind, ProjectionTy, ProjectionTyExt, Scalar, Solution,
-    Substitution, TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
+    Canonical, Const, DebruijnIndex, GenericArg, Goal, Guidance, InEnvironment, InferenceVar,
+    Interner, Lifetime, ProjectionTy, ProjectionTyExt, Scalar, Solution, Substitution,
+    TraitEnvironment, Ty, TyBuilder, TyExt, TyKind, VariableKind,
 };
 
 impl<'a> InferenceContext<'a> {
@@ -49,13 +48,13 @@ impl<T: HasInterner<Interner = Interner>> Canonicalized<T> {
         // the solution may contain new variables, which we need to convert to new inference vars
         let new_vars = Substitution::from_iter(
             Interner,
-            solution.binders.iter(Interner).map(|k| match &k.kind {
+            solution.binders.iter(Interner).map(|k| match k.kind {
                 VariableKind::Ty(TyVariableKind::General) => ctx.new_type_var().cast(Interner),
                 VariableKind::Ty(TyVariableKind::Integer) => ctx.new_integer_var().cast(Interner),
                 VariableKind::Ty(TyVariableKind::Float) => ctx.new_float_var().cast(Interner),
                 // Chalk can sometimes return new lifetime variables. We just use the static lifetime everywhere
                 VariableKind::Lifetime => static_lifetime().cast(Interner),
-                VariableKind::Const(ty) => ctx.new_const_var(ty.clone()).cast(Interner),
+                _ => panic!("const variable in solution"),
             }),
         );
         for (i, v) in solution.value.iter(Interner).enumerate() {
@@ -88,17 +87,11 @@ pub(crate) fn unify(
     let mut table = InferenceTable::new(db, env);
     let vars = Substitution::from_iter(
         Interner,
-        tys.binders.iter(Interner).map(|x| match &x.kind {
-            chalk_ir::VariableKind::Ty(_) => {
-                GenericArgData::Ty(table.new_type_var()).intern(Interner)
-            }
-            chalk_ir::VariableKind::Lifetime => {
-                GenericArgData::Ty(table.new_type_var()).intern(Interner)
-            } // FIXME: maybe wrong?
-            chalk_ir::VariableKind::Const(ty) => {
-                GenericArgData::Const(table.new_const_var(ty.clone())).intern(Interner)
-            }
-        }),
+        tys.binders
+            .iter(Interner)
+            // we always use type vars here because we want everything to
+            // fallback to Unknown in the end (kind of hacky, as below)
+            .map(|_| table.new_type_var()),
     );
     let ty1_with_vars = vars.apply(tys.value.0.clone(), Interner);
     let ty2_with_vars = vars.apply(tys.value.1.clone(), Interner);
@@ -124,7 +117,8 @@ pub(crate) fn unify(
     };
     Some(Substitution::from_iter(
         Interner,
-        vars.iter(Interner).map(|v| table.resolve_with_fallback(v.clone(), &fallback)),
+        vars.iter(Interner)
+            .map(|v| table.resolve_with_fallback(v.assert_ty_ref(Interner).clone(), &fallback)),
     ))
 }
 
@@ -558,18 +552,11 @@ impl<'a> InferenceTable<'a> {
 
         let mut arg_tys = vec![];
         let arg_ty = TyBuilder::tuple(num_args)
-            .fill(|x| {
-                let arg = match x {
-                    ParamKind::Type => self.new_type_var(),
-                    ParamKind::Const(ty) => {
-                        never!("Tuple with const parameter");
-                        return GenericArgData::Const(self.new_const_var(ty.clone()))
-                            .intern(Interner);
-                    }
-                };
+            .fill(iter::repeat_with(|| {
+                let arg = self.new_type_var();
                 arg_tys.push(arg.clone());
-                GenericArgData::Ty(arg).intern(Interner)
-            })
+                arg
+            }))
             .build();
 
         let projection = {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index d6a524d593..b57ad62068 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -42,13 +42,11 @@ use hir_def::{
     type_ref::{ConstScalar, Rawness},
     TypeOrConstParamId,
 };
-use itertools::Either;
-use utils::Generics;
 
 use crate::{db::HirDatabase, utils::generics};
 
 pub use autoderef::autoderef;
-pub use builder::{ParamKind, TyBuilder};
+pub use builder::TyBuilder;
 pub use chalk_ext::*;
 pub use infer::{could_unify, InferenceDiagnostic, InferenceResult};
 pub use interner::Interner;
@@ -142,58 +140,20 @@ where
     Binders::empty(Interner, value.shifted_in_from(Interner, DebruijnIndex::ONE))
 }
 
-pub(crate) fn make_type_and_const_binders<T: HasInterner<Interner = Interner>>(
-    which_is_const: impl Iterator<Item = Option<Ty>>,
+pub(crate) fn make_only_type_binders<T: HasInterner<Interner = Interner>>(
+    num_vars: usize,
     value: T,
 ) -> Binders<T> {
     Binders::new(
         VariableKinds::from_iter(
             Interner,
-            which_is_const.map(|x| {
-                if let Some(ty) = x {
-                    chalk_ir::VariableKind::Const(ty)
-                } else {
-                    chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
-                }
-            }),
+            std::iter::repeat(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General))
+                .take(num_vars),
         ),
         value,
     )
 }
 
-pub(crate) fn make_single_type_binders<T: HasInterner<Interner = Interner>>(
-    value: T,
-) -> Binders<T> {
-    Binders::new(
-        VariableKinds::from_iter(
-            Interner,
-            std::iter::once(chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)),
-        ),
-        value,
-    )
-}
-
-pub(crate) fn make_binders_with_count<T: HasInterner<Interner = Interner>>(
-    db: &dyn HirDatabase,
-    count: usize,
-    generics: &Generics,
-    value: T,
-) -> Binders<T> {
-    let it = generics.iter_id().take(count).map(|id| match id {
-        Either::Left(_) => None,
-        Either::Right(id) => Some(db.const_param_ty(id)),
-    });
-    crate::make_type_and_const_binders(it, value)
-}
-
-pub(crate) fn make_binders<T: HasInterner<Interner = Interner>>(
-    db: &dyn HirDatabase,
-    generics: &Generics,
-    value: T,
-) -> Binders<T> {
-    make_binders_with_count(db, usize::MAX, generics, value)
-}
-
 // FIXME: get rid of this
 pub fn make_canonical<T: HasInterner<Interner = Interner>>(
     value: T,
@@ -328,17 +288,11 @@ pub fn dummy_usize_const() -> Const {
 
 pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner>>(
     t: T,
-    for_ty: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
-    for_const: impl FnMut(Ty, BoundVar, DebruijnIndex) -> Const,
+    f: impl FnMut(BoundVar, DebruijnIndex) -> Ty,
 ) -> T::Result {
     use chalk_ir::{fold::Folder, Fallible};
-    struct FreeVarFolder<F1, F2>(F1, F2);
-    impl<
-            'i,
-            F1: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i,
-            F2: FnMut(Ty, BoundVar, DebruijnIndex) -> Const + 'i,
-        > Folder<Interner> for FreeVarFolder<F1, F2>
-    {
+    struct FreeVarFolder<F>(F);
+    impl<'i, F: FnMut(BoundVar, DebruijnIndex) -> Ty + 'i> Folder<Interner> for FreeVarFolder<F> {
         type Error = NoSolution;
 
         fn as_dyn(&mut self) -> &mut dyn Folder<Interner, Error = Self::Error> {
@@ -356,38 +310,13 @@ pub(crate) fn fold_free_vars<T: HasInterner<Interner = Interner> + Fold<Interner
         ) -> Fallible<Ty> {
             Ok(self.0(bound_var, outer_binder))
         }
-
-        fn fold_free_var_const(
-            &mut self,
-            ty: Ty,
-            bound_var: BoundVar,
-            outer_binder: DebruijnIndex,
-        ) -> Fallible<Const> {
-            Ok(self.1(ty, bound_var, outer_binder))
-        }
     }
-    t.fold_with(&mut FreeVarFolder(for_ty, for_const), DebruijnIndex::INNERMOST)
-        .expect("fold failed unexpectedly")
+    t.fold_with(&mut FreeVarFolder(f), DebruijnIndex::INNERMOST).expect("fold failed unexpectedly")
 }
 
 pub(crate) fn fold_tys<T: HasInterner<Interner = Interner> + Fold<Interner>>(
     t: T,
-    mut for_ty: impl FnMut(Ty, DebruijnIndex) -> Ty,
-    binders: DebruijnIndex,
-) -> T::Result {
-    fold_tys_and_consts(
-        t,
-        |x, d| match x {
-            Either::Left(x) => Either::Left(for_ty(x, d)),
-            Either::Right(x) => Either::Right(x),
-        },
-        binders,
-    )
-}
-
-pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + Fold<Interner>>(
-    t: T,
-    f: impl FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const>,
+    f: impl FnMut(Ty, DebruijnIndex) -> Ty,
     binders: DebruijnIndex,
 ) -> T::Result {
     use chalk_ir::{
@@ -395,9 +324,7 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + Fold<Int
         Fallible,
     };
     struct TyFolder<F>(F);
-    impl<'i, F: FnMut(Either<Ty, Const>, DebruijnIndex) -> Either<Ty, Const> + 'i> Folder<Interner>
-        for TyFolder<F>
-    {
+    impl<'i, F: FnMut(Ty, DebruijnIndex) -> Ty + 'i> Folder<Interner> for TyFolder<F> {
         type Error = NoSolution;
 
         fn as_dyn(&mut self) -> &mut dyn Folder<Interner, Error = Self::Error> {
@@ -410,11 +337,7 @@ pub(crate) fn fold_tys_and_consts<T: HasInterner<Interner = Interner> + Fold<Int
 
         fn fold_ty(&mut self, ty: Ty, outer_binder: DebruijnIndex) -> Fallible<Ty> {
             let ty = ty.super_fold_with(self.as_dyn(), outer_binder)?;
-            Ok(self.0(Either::Left(ty), outer_binder).left().unwrap())
-        }
-
-        fn fold_const(&mut self, c: Const, outer_binder: DebruijnIndex) -> Fallible<Const> {
-            Ok(self.0(Either::Right(c), outer_binder).right().unwrap())
+            Ok(self.0(ty, outer_binder))
         }
     }
     t.fold_with(&mut TyFolder(f), binders).expect("fold failed unexpectedly")
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 9e69785ac2..1d6affe9c7 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -9,11 +9,9 @@ use std::cell::{Cell, RefCell};
 use std::{iter, sync::Arc};
 
 use base_db::CrateId;
-use chalk_ir::{cast::Cast, fold::Shift, Mutability, Safety};
+use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
 use hir_def::generics::TypeOrConstParamData;
 use hir_def::intern::Interned;
-use hir_def::path::{ModPath, PathKind};
-use hir_def::type_ref::ConstScalarOrPath;
 use hir_def::{
     adt::StructKind,
     body::{Expander, LowerCtx},
@@ -26,25 +24,23 @@ use hir_def::{
     ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId,
     UnionId, VariantId,
 };
-use hir_def::{ConstParamId, TypeOrConstParamId, TypeParamId};
+use hir_def::{ConstParamId, TypeOrConstParamId};
 use hir_expand::{name::Name, ExpandResult};
-use itertools::Either;
 use la_arena::ArenaMap;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
 use stdx::{impl_from, never};
 use syntax::{ast, SmolStr};
 
-use crate::consteval::{path_to_const, unknown_const_as_generic, unknown_const_usize, usize_const};
-use crate::method_resolution::fallback_bound_vars;
-use crate::utils::Generics;
-use crate::{all_super_traits, make_binders, Const, GenericArgData, ParamKind};
+use crate::all_super_traits;
 use crate::{
     consteval,
     db::HirDatabase,
     mapping::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},
+    utils::{
+        all_super_trait_refs, associated_type_by_name_including_super_traits, generics, Generics,
+    },
     AliasEq, AliasTy, Binders, BoundVar, CallableSig, DebruijnIndex, DynTy, FnPointer, FnSig,
     FnSubst, ImplTraitId, Interner, PolyFnSig, ProjectionTy, QuantifiedWhereClause,
     QuantifiedWhereClauses, ReturnTypeImplTrait, ReturnTypeImplTraits, Substitution,
@@ -60,7 +56,7 @@ pub struct TyLoweringContext<'a> {
     /// some type params should be represented as placeholders, and others
     /// should be converted to variables. I think in practice, this isn't
     /// possible currently, so this should be fine for now.
-    pub type_param_mode: ParamLoweringMode,
+    pub type_param_mode: TypeParamLoweringMode,
     pub impl_trait_mode: ImplTraitLoweringMode,
     impl_trait_counter: Cell<u16>,
     /// When turning `impl Trait` into opaque types, we have to collect the
@@ -81,7 +77,7 @@ impl<'a> TyLoweringContext<'a> {
     pub fn new(db: &'a dyn HirDatabase, resolver: &'a Resolver) -> Self {
         let impl_trait_counter = Cell::new(0);
         let impl_trait_mode = ImplTraitLoweringMode::Disallowed;
-        let type_param_mode = ParamLoweringMode::Placeholder;
+        let type_param_mode = TypeParamLoweringMode::Placeholder;
         let in_binders = DebruijnIndex::INNERMOST;
         let opaque_type_data = RefCell::new(Vec::new());
         Self {
@@ -133,7 +129,7 @@ impl<'a> TyLoweringContext<'a> {
         Self { impl_trait_mode, ..self }
     }
 
-    pub fn with_type_param_mode(self, type_param_mode: ParamLoweringMode) -> Self {
+    pub fn with_type_param_mode(self, type_param_mode: TypeParamLoweringMode) -> Self {
         Self { type_param_mode, ..self }
     }
 }
@@ -159,7 +155,7 @@ pub enum ImplTraitLoweringMode {
 }
 
 #[derive(Copy, Clone, Debug, PartialEq, Eq)]
-pub enum ParamLoweringMode {
+pub enum TypeParamLoweringMode {
     Placeholder,
     Variable,
 }
@@ -169,15 +165,6 @@ impl<'a> TyLoweringContext<'a> {
         self.lower_ty_ext(type_ref).0
     }
 
-    fn generics(&self) -> Generics {
-        generics(
-            self.db.upcast(),
-            self.resolver
-                .generic_def()
-                .expect("there should be generics if there's a generic param"),
-        )
-    }
-
     pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
         let mut res = None;
         let ty = match type_ref {
@@ -198,14 +185,8 @@ impl<'a> TyLoweringContext<'a> {
             }
             TypeRef::Array(inner, len) => {
                 let inner_ty = self.lower_ty(inner);
-                let const_len = const_or_path_to_chalk(
-                    self.db,
-                    self.resolver,
-                    len,
-                    self.type_param_mode,
-                    || self.generics(),
-                    DebruijnIndex::INNERMOST,
-                );
+
+                let const_len = consteval::usize_const(len.as_usize());
 
                 TyKind::Array(inner_ty, const_len).intern(Interner)
             }
@@ -240,7 +221,7 @@ impl<'a> TyLoweringContext<'a> {
                         bounds.iter().flat_map(|b| ctx.lower_type_bound(b, self_ty.clone(), false)),
                     )
                 });
-                let bounds = crate::make_single_type_binders(bounds);
+                let bounds = crate::make_only_type_binders(1, bounds);
                 TyKind::Dyn(DynTy { bounds, lifetime: static_lifetime() }).intern(Interner)
             }
             TypeRef::ImplTrait(bounds) => {
@@ -258,7 +239,7 @@ impl<'a> TyLoweringContext<'a> {
                         // place even if we encounter more opaque types while
                         // lowering the bounds
                         self.opaque_type_data.borrow_mut().push(ReturnTypeImplTrait {
-                            bounds: crate::make_single_type_binders(Vec::new()),
+                            bounds: crate::make_only_type_binders(1, Vec::new()),
                         });
                         // We don't want to lower the bounds inside the binders
                         // we're currently in, because they don't end up inside
@@ -278,7 +259,7 @@ impl<'a> TyLoweringContext<'a> {
                         let impl_trait_id = ImplTraitId::ReturnTypeImplTrait(func, idx);
                         let opaque_ty_id = self.db.intern_impl_trait_id(impl_trait_id).into();
                         let generics = generics(self.db.upcast(), func.into());
-                        let parameters = generics.bound_vars_subst(self.db, self.in_binders);
+                        let parameters = generics.bound_vars_subst(self.in_binders);
                         TyKind::OpaqueType(opaque_ty_id, parameters).intern(Interner)
                     }
                     ImplTraitLoweringMode::Param => {
@@ -468,7 +449,8 @@ impl<'a> TyLoweringContext<'a> {
                             )
                         });
                         let dyn_ty = DynTy {
-                            bounds: crate::make_single_type_binders(
+                            bounds: crate::make_only_type_binders(
+                                1,
                                 QuantifiedWhereClauses::from_iter(
                                     Interner,
                                     Some(crate::wrap_empty_binders(WhereClause::Implemented(
@@ -493,10 +475,10 @@ impl<'a> TyLoweringContext<'a> {
                     self.resolver.generic_def().expect("generics in scope"),
                 );
                 match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => {
+                    TypeParamLoweringMode::Placeholder => {
                         TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
                     }
-                    ParamLoweringMode::Variable => {
+                    TypeParamLoweringMode::Variable => {
                         let idx = generics.param_idx(param_id.into()).expect("matching generics");
                         TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
                     }
@@ -506,20 +488,16 @@ impl<'a> TyLoweringContext<'a> {
             TypeNs::SelfType(impl_id) => {
                 let generics = generics(self.db.upcast(), impl_id.into());
                 let substs = match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
-                    ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.db, self.in_binders)
-                    }
+                    TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
+                    TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
                 };
                 self.db.impl_self_ty(impl_id).substitute(Interner, &substs)
             }
             TypeNs::AdtSelfType(adt) => {
                 let generics = generics(self.db.upcast(), adt.into());
                 let substs = match self.type_param_mode {
-                    ParamLoweringMode::Placeholder => generics.placeholder_subst(self.db),
-                    ParamLoweringMode::Variable => {
-                        generics.bound_vars_subst(self.db, self.in_binders)
-                    }
+                    TypeParamLoweringMode::Placeholder => generics.type_params_subst(self.db),
+                    TypeParamLoweringMode::Variable => generics.bound_vars_subst(self.in_binders),
                 };
                 self.db.ty(adt.into()).substitute(Interner, &substs)
             }
@@ -571,7 +549,7 @@ impl<'a> TyLoweringContext<'a> {
             move |name, t, associated_ty| {
                 if name == segment.name {
                     let substs = match self.type_param_mode {
-                        ParamLoweringMode::Placeholder => {
+                        TypeParamLoweringMode::Placeholder => {
                             // if we're lowering to placeholders, we have to put
                             // them in now
                             let generics = generics(
@@ -580,10 +558,10 @@ impl<'a> TyLoweringContext<'a> {
                                     .generic_def()
                                     .expect("there should be generics if there's a generic param"),
                             );
-                            let s = generics.placeholder_subst(self.db);
+                            let s = generics.type_params_subst(self.db);
                             s.apply(t.substitution.clone(), Interner)
                         }
-                        ParamLoweringMode::Variable => t.substitution.clone(),
+                        TypeParamLoweringMode::Variable => t.substitution.clone(),
                     };
                     // We need to shift in the bound vars, since
                     // associated_type_shorthand_candidates does not do that
@@ -664,75 +642,47 @@ impl<'a> TyLoweringContext<'a> {
         explicit_self_ty: Option<Ty>,
     ) -> Substitution {
         let mut substs = Vec::new();
-        let def_generics = if let Some(def) = def_generic {
-            generics(self.db.upcast(), def)
-        } else {
-            return Substitution::empty(Interner);
-        };
+        let def_generics = def_generic.map(|def| generics(self.db.upcast(), def));
+
         let (parent_params, self_params, type_params, const_params, impl_trait_params) =
-            def_generics.provenance_split();
+            def_generics.map_or((0, 0, 0, 0, 0), |g| g.provenance_split());
         let total_len =
             parent_params + self_params + type_params + const_params + impl_trait_params;
 
-        let ty_error = GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner);
-        let const_error = GenericArgData::Const(consteval::usize_const(None)).intern(Interner);
-
-        for (_, data) in def_generics.iter().take(parent_params) {
-            match data {
-                TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
-                TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
-            }
-        }
+        substs.extend(iter::repeat(TyKind::Error.intern(Interner)).take(parent_params));
 
         let fill_self_params = || {
             substs.extend(
                 explicit_self_ty
                     .into_iter()
-                    .map(|x| GenericArgData::Ty(x).intern(Interner))
-                    .chain(iter::repeat(ty_error.clone()))
+                    .chain(iter::repeat(TyKind::Error.intern(Interner)))
                     .take(self_params),
             )
         };
-        let mut had_explicit_args = false;
+        let mut had_explicit_type_args = false;
 
         if let Some(generic_args) = &segment.args_and_bindings {
             if !generic_args.has_self_type {
                 fill_self_params();
             }
-            let expected_num = if generic_args.has_self_type {
-                self_params + type_params + const_params
-            } else {
-                type_params + const_params
-            };
+            let expected_num =
+                if generic_args.has_self_type { self_params + type_params } else { type_params };
             let skip = if generic_args.has_self_type && self_params == 0 { 1 } else { 0 };
             // if args are provided, it should be all of them, but we can't rely on that
-            for (arg, id) in generic_args
+            for arg in generic_args
                 .args
                 .iter()
-                .filter(|arg| !matches!(arg, GenericArg::Lifetime(_)))
+                .filter(|arg| matches!(arg, GenericArg::Type(_)))
                 .skip(skip)
                 .take(expected_num)
-                .zip(def_generics.iter_id().skip(skip))
             {
-                if let Some(x) = generic_arg_to_chalk(
-                    self.db,
-                    id,
-                    arg,
-                    &mut (),
-                    |_, type_ref| self.lower_ty(type_ref),
-                    |_, c| {
-                        const_or_path_to_chalk(
-                            self.db,
-                            &self.resolver,
-                            c,
-                            self.type_param_mode,
-                            || self.generics(),
-                            DebruijnIndex::INNERMOST,
-                        )
-                    },
-                ) {
-                    had_explicit_args = true;
-                    substs.push(x);
+                match arg {
+                    GenericArg::Type(type_ref) => {
+                        had_explicit_type_args = true;
+                        let ty = self.lower_ty(type_ref);
+                        substs.push(ty);
+                    }
+                    GenericArg::Lifetime(_) => {}
                 }
             }
         } else {
@@ -742,7 +692,7 @@ impl<'a> TyLoweringContext<'a> {
         // handle defaults. In expression or pattern path segments without
         // explicitly specified type arguments, missing type arguments are inferred
         // (i.e. defaults aren't used).
-        if !infer_args || had_explicit_args {
+        if !infer_args || had_explicit_type_args {
             if let Some(def_generic) = def_generic {
                 let defaults = self.db.generic_defaults(def_generic);
                 assert_eq!(total_len, defaults.len());
@@ -757,11 +707,8 @@ impl<'a> TyLoweringContext<'a> {
 
         // add placeholders for args that were not provided
         // FIXME: emit diagnostics in contexts where this is not allowed
-        for (_, data) in def_generics.iter().skip(substs.len()) {
-            match data {
-                TypeOrConstParamData::TypeParamData(_) => substs.push(ty_error.clone()),
-                TypeOrConstParamData::ConstParamData(_) => substs.push(const_error.clone()),
-            }
+        for _ in substs.len()..total_len {
+            substs.push(TyKind::Error.intern(Interner));
         }
         assert_eq!(substs.len(), total_len);
 
@@ -828,8 +775,8 @@ impl<'a> TyLoweringContext<'a> {
                         };
                         let placeholder = to_placeholder_idx(self.db, param_id);
                         match self.type_param_mode {
-                            ParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
-                            ParamLoweringMode::Variable => {
+                            TypeParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
+                            TypeParamLoweringMode::Variable => {
                                 let idx = generics.param_idx(param_id).expect("matching generics");
                                 TyKind::BoundVar(BoundVar::new(DebruijnIndex::INNERMOST, idx))
                             }
@@ -972,7 +919,8 @@ impl<'a> TyLoweringContext<'a> {
             }
             predicates
         });
-        ReturnTypeImplTrait { bounds: crate::make_single_type_binders(predicates) }
+
+        ReturnTypeImplTrait { bounds: crate::make_only_type_binders(1, predicates) }
     }
 }
 
@@ -1051,7 +999,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 generics = generics(db.upcast(), trait_id.into());
-                if generics.params.type_or_consts[param_id.local_id()].is_trait_self() {
+                if generics.params.tocs[param_id.local_id()].is_trait_self() {
                     let trait_ref = TyBuilder::trait_ref(db, trait_id)
                         .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
                         .build();
@@ -1078,9 +1026,9 @@ pub(crate) fn field_types_query(
     let generics = generics(db.upcast(), def);
     let mut res = ArenaMap::default();
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     for (field_id, field_data) in var_data.fields().iter() {
-        res.insert(field_id, make_binders(db, &generics, ctx.lower_ty(&field_data.type_ref)))
+        res.insert(field_id, make_binders(&generics, ctx.lower_ty(&field_data.type_ref)))
     }
     Arc::new(res)
 }
@@ -1101,7 +1049,7 @@ pub(crate) fn generic_predicates_for_param_query(
 ) -> Arc<[Binders<QuantifiedWhereClause>]> {
     let resolver = def.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let generics = generics(db.upcast(), def);
     let mut predicates: Vec<_> = resolver
         .where_predicates_in_scope()
@@ -1149,16 +1097,14 @@ pub(crate) fn generic_predicates_for_param_query(
             }
             WherePredicate::Lifetime { .. } => false,
         })
-        .flat_map(|pred| {
-            ctx.lower_where_predicate(pred, true).map(|p| make_binders(db, &generics, p))
-        })
+        .flat_map(|pred| ctx.lower_where_predicate(pred, true).map(|p| make_binders(&generics, p)))
         .collect();
 
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
     let explicitly_unsized_tys = ctx.unsized_types.into_inner();
     let implicitly_sized_predicates =
         implicitly_sized_clauses(db, param_id.parent, &explicitly_unsized_tys, &subst, &resolver)
-            .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
+            .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
     predicates.extend(implicitly_sized_predicates);
     predicates.into()
 }
@@ -1178,8 +1124,8 @@ pub(crate) fn trait_environment_query(
     def: GenericDefId,
 ) -> Arc<TraitEnvironment> {
     let resolver = def.resolver(db.upcast());
-    let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Placeholder);
+    let ctx = TyLoweringContext::new(db, &resolver)
+        .with_type_param_mode(TypeParamLoweringMode::Placeholder);
     let mut traits_in_scope = Vec::new();
     let mut clauses = Vec::new();
     for pred in resolver.where_predicates_in_scope() {
@@ -1207,14 +1153,14 @@ pub(crate) fn trait_environment_query(
         // function default implementations (and speculative code
         // inside consts or type aliases)
         cov_mark::hit!(trait_self_implements_self);
-        let substs = TyBuilder::placeholder_subst(db, trait_id);
+        let substs = TyBuilder::type_params_subst(db, trait_id);
         let trait_ref = TraitRef { trait_id: to_chalk_trait_id(trait_id), substitution: substs };
         let pred = WhereClause::Implemented(trait_ref);
         let program_clause: chalk_ir::ProgramClause<Interner> = pred.cast(Interner);
         clauses.push(program_clause.into_from_env_clause(Interner));
     }
 
-    let subst = generics(db.upcast(), def).placeholder_subst(db);
+    let subst = generics(db.upcast(), def).type_params_subst(db);
     let explicitly_unsized_tys = ctx.unsized_types.into_inner();
     let implicitly_sized_clauses =
         implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver).map(|pred| {
@@ -1237,21 +1183,19 @@ pub(crate) fn generic_predicates_query(
 ) -> Arc<[Binders<QuantifiedWhereClause>]> {
     let resolver = def.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let generics = generics(db.upcast(), def);
 
     let mut predicates = resolver
         .where_predicates_in_scope()
-        .flat_map(|pred| {
-            ctx.lower_where_predicate(pred, false).map(|p| make_binders(db, &generics, p))
-        })
+        .flat_map(|pred| ctx.lower_where_predicate(pred, false).map(|p| make_binders(&generics, p)))
         .collect::<Vec<_>>();
 
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let subst = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
     let explicitly_unsized_tys = ctx.unsized_types.into_inner();
     let implicitly_sized_predicates =
         implicitly_sized_clauses(db, def, &explicitly_unsized_tys, &subst, &resolver)
-            .map(|p| make_binders(db, &generics, crate::wrap_empty_binders(p)));
+            .map(|p| make_binders(&generics, crate::wrap_empty_binders(p)));
     predicates.extend(implicitly_sized_predicates);
     predicates.into()
 }
@@ -1290,36 +1234,40 @@ fn implicitly_sized_clauses<'a>(
 pub(crate) fn generic_defaults_query(
     db: &dyn HirDatabase,
     def: GenericDefId,
-) -> Arc<[Binders<chalk_ir::GenericArg<Interner>>]> {
+) -> Arc<[Binders<Ty>]> {
     let resolver = def.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let generic_params = generics(db.upcast(), def);
 
     let defaults = generic_params
-        .iter()
+        .toc_iter()
         .enumerate()
-        .map(|(idx, (id, p))| {
+        .map(|(idx, (_, p))| {
             let p = match p {
                 TypeOrConstParamData::TypeParamData(p) => p,
                 TypeOrConstParamData::ConstParamData(_) => {
-                    // FIXME: implement const generic defaults
-                    let val = unknown_const_as_generic(
-                        db.const_param_ty(ConstParamId::from_unchecked(id)),
-                    );
-                    return crate::make_binders_with_count(db, idx, &generic_params, val);
+                    // FIXME: here we should add const generic parameters
+                    let ty = TyKind::Error.intern(Interner);
+                    return crate::make_only_type_binders(idx, ty);
                 }
             };
             let mut ty =
                 p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 
             // Each default can only refer to previous parameters.
-            // type variable default referring to parameter coming
-            // after it. This is forbidden (FIXME: report
-            // diagnostic)
-            ty = fallback_bound_vars(ty, idx);
-            let val = GenericArgData::Ty(ty).intern(Interner);
-            crate::make_binders_with_count(db, idx, &generic_params, val)
+            ty = crate::fold_free_vars(ty, |bound, binders| {
+                if bound.index >= idx && bound.debruijn == DebruijnIndex::INNERMOST {
+                    // type variable default referring to parameter coming
+                    // after it. This is forbidden (FIXME: report
+                    // diagnostic)
+                    TyKind::Error.intern(Interner)
+                } else {
+                    bound.shifted_in_from(binders).to_ty(Interner)
+                }
+            });
+
+            crate::make_only_type_binders(idx, ty)
         })
         .collect();
 
@@ -1330,21 +1278,17 @@ pub(crate) fn generic_defaults_recover(
     db: &dyn HirDatabase,
     _cycle: &[String],
     def: &GenericDefId,
-) -> Arc<[Binders<crate::GenericArg>]> {
+) -> Arc<[Binders<Ty>]> {
     let generic_params = generics(db.upcast(), *def);
-    // FIXME: this code is not covered in tests.
+
     // we still need one default per parameter
     let defaults = generic_params
-        .iter_id()
+        .toc_iter()
         .enumerate()
-        .map(|(count, id)| {
-            let val = match id {
-                itertools::Either::Left(_) => {
-                    GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
-                }
-                itertools::Either::Right(id) => unknown_const_as_generic(db.const_param_ty(id)),
-            };
-            crate::make_binders_with_count(db, count, &generic_params, val)
+        .map(|(idx, _)| {
+            let ty = TyKind::Error.intern(Interner);
+
+            crate::make_only_type_binders(idx, ty)
         })
         .collect();
 
@@ -1356,27 +1300,26 @@ fn fn_sig_for_fn(db: &dyn HirDatabase, def: FunctionId) -> PolyFnSig {
     let resolver = def.resolver(db.upcast());
     let ctx_params = TyLoweringContext::new(db, &resolver)
         .with_impl_trait_mode(ImplTraitLoweringMode::Variable)
-        .with_type_param_mode(ParamLoweringMode::Variable);
+        .with_type_param_mode(TypeParamLoweringMode::Variable);
     let params = data.params.iter().map(|(_, tr)| ctx_params.lower_ty(tr)).collect::<Vec<_>>();
     let ctx_ret = TyLoweringContext::new(db, &resolver)
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-        .with_type_param_mode(ParamLoweringMode::Variable);
+        .with_type_param_mode(TypeParamLoweringMode::Variable);
     let ret = ctx_ret.lower_ty(&data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let mut sig = CallableSig::from_params_and_return(params, ret, data.is_varargs());
     if !data.legacy_const_generics_indices.is_empty() {
         sig.set_legacy_const_generics_indices(&data.legacy_const_generics_indices);
     }
-    make_binders(db, &generics, sig)
+    make_binders(&generics, sig)
 }
 
 /// Build the declared type of a function. This should not need to look at the
 /// function body.
 fn type_for_fn(db: &dyn HirDatabase, def: FunctionId) -> Binders<Ty> {
     let generics = generics(db.upcast(), def.into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
     make_binders(
-        db,
         &generics,
         TyKind::FnDef(CallableDefId::FunctionId(def).to_chalk(db), substs).intern(Interner),
     )
@@ -1388,9 +1331,9 @@ fn type_for_const(db: &dyn HirDatabase, def: ConstId) -> Binders<Ty> {
     let generics = generics(db.upcast(), def.into());
     let resolver = def.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
 
-    make_binders(db, &generics, ctx.lower_ty(&data.type_ref))
+    make_binders(&generics, ctx.lower_ty(&data.type_ref))
 }
 
 /// Build the declared type of a static.
@@ -1407,7 +1350,7 @@ fn fn_sig_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> PolyFnS
     let fields = struct_data.variant_data.fields();
     let resolver = def.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
     let (ret, binders) = type_for_adt(db, def.into()).into_value_and_skipped_binders();
     Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
@@ -1420,9 +1363,8 @@ fn type_for_struct_constructor(db: &dyn HirDatabase, def: StructId) -> Binders<T
         return type_for_adt(db, def.into());
     }
     let generics = generics(db.upcast(), def.into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
     make_binders(
-        db,
         &generics,
         TyKind::FnDef(CallableDefId::StructId(def).to_chalk(db), substs).intern(Interner),
     )
@@ -1434,7 +1376,7 @@ fn fn_sig_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId)
     let fields = var_data.variant_data.fields();
     let resolver = def.parent.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let params = fields.iter().map(|(_, field)| ctx.lower_ty(&field.type_ref)).collect::<Vec<_>>();
     let (ret, binders) = type_for_adt(db, def.parent.into()).into_value_and_skipped_binders();
     Binders::new(binders, CallableSig::from_params_and_return(params, ret, false))
@@ -1448,9 +1390,8 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
         return type_for_adt(db, def.parent.into());
     }
     let generics = generics(db.upcast(), def.parent.into());
-    let substs = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
+    let substs = generics.bound_vars_subst(DebruijnIndex::INNERMOST);
     make_binders(
-        db,
         &generics,
         TyKind::FnDef(CallableDefId::EnumVariantId(def).to_chalk(db), substs).intern(Interner),
     )
@@ -1458,22 +1399,22 @@ fn type_for_enum_variant_constructor(db: &dyn HirDatabase, def: EnumVariantId) -
 
 fn type_for_adt(db: &dyn HirDatabase, adt: AdtId) -> Binders<Ty> {
     let generics = generics(db.upcast(), adt.into());
-    let subst = generics.bound_vars_subst(db, DebruijnIndex::INNERMOST);
-    let ty = TyKind::Adt(crate::AdtId(adt), subst).intern(Interner);
-    make_binders(db, &generics, ty)
+    let b = TyBuilder::adt(db, adt);
+    let ty = b.fill_with_bound_vars(DebruijnIndex::INNERMOST, 0).build();
+    make_binders(&generics, ty)
 }
 
 fn type_for_type_alias(db: &dyn HirDatabase, t: TypeAliasId) -> Binders<Ty> {
     let generics = generics(db.upcast(), t.into());
     let resolver = t.resolver(db.upcast());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     if db.type_alias_data(t).is_extern {
         Binders::empty(Interner, TyKind::Foreign(crate::to_foreign_def_id(t)).intern(Interner))
     } else {
         let type_ref = &db.type_alias_data(t).type_ref;
         let inner = ctx.lower_ty(type_ref.as_deref().unwrap_or(&TypeRef::Error));
-        make_binders(db, &generics, inner)
+        make_binders(&generics, inner)
     }
 }
 
@@ -1544,7 +1485,7 @@ pub(crate) fn ty_recover(db: &dyn HirDatabase, _cycle: &[String], def: &TyDefId)
         TyDefId::AdtId(it) => generics(db.upcast(), it.into()),
         TyDefId::TypeAliasId(it) => generics(db.upcast(), it.into()),
     };
-    make_binders(db, &generics, TyKind::Error.intern(Interner))
+    make_binders(&generics, TyKind::Error.intern(Interner))
 }
 
 pub(crate) fn value_ty_query(db: &dyn HirDatabase, def: ValueTyDefId) -> Binders<Ty> {
@@ -1568,14 +1509,14 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
     ));
     let generics = generics(db.upcast(), impl_id.into());
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
-    make_binders(db, &generics, ctx.lower_ty(&impl_data.self_ty))
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
+    make_binders(&generics, ctx.lower_ty(&impl_data.self_ty))
 }
 
 // returns None if def is a type arg
 pub(crate) fn const_param_ty_query(db: &dyn HirDatabase, def: ConstParamId) -> Ty {
     let parent_data = db.generic_params(def.parent());
-    let data = &parent_data.type_or_consts[def.local_id()];
+    let data = &parent_data.tocs[def.local_id()];
     let resolver = def.parent().resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver);
     match data {
@@ -1593,7 +1534,7 @@ pub(crate) fn impl_self_ty_recover(
     impl_id: &ImplId,
 ) -> Binders<Ty> {
     let generics = generics(db.upcast(), (*impl_id).into());
-    make_binders(db, &generics, TyKind::Error.intern(Interner))
+    make_binders(&generics, TyKind::Error.intern(Interner))
 }
 
 pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<Binders<TraitRef>> {
@@ -1605,7 +1546,7 @@ pub(crate) fn impl_trait_query(db: &dyn HirDatabase, impl_id: ImplId) -> Option<
         impl_id, impl_loc, impl_data
     ));
     let ctx =
-        TyLoweringContext::new(db, &resolver).with_type_param_mode(ParamLoweringMode::Variable);
+        TyLoweringContext::new(db, &resolver).with_type_param_mode(TypeParamLoweringMode::Variable);
     let (self_ty, binders) = db.impl_self_ty(impl_id).into_value_and_skipped_binders();
     let target_trait = impl_data.target_trait.as_ref()?;
     Some(Binders::new(binders, ctx.lower_trait_ref(target_trait, Some(self_ty))?))
@@ -1620,7 +1561,7 @@ pub(crate) fn return_type_impl_traits(
     let resolver = def.resolver(db.upcast());
     let ctx_ret = TyLoweringContext::new(db, &resolver)
         .with_impl_trait_mode(ImplTraitLoweringMode::Opaque)
-        .with_type_param_mode(ParamLoweringMode::Variable);
+        .with_type_param_mode(TypeParamLoweringMode::Variable);
     let _ret = (&ctx_ret).lower_ty(&data.ret_type);
     let generics = generics(db.upcast(), def.into());
     let return_type_impl_traits =
@@ -1628,7 +1569,7 @@ pub(crate) fn return_type_impl_traits(
     if return_type_impl_traits.impl_traits.is_empty() {
         None
     } else {
-        Some(Arc::new(make_binders(db, &generics, return_type_impl_traits)))
+        Some(Arc::new(make_binders(&generics, return_type_impl_traits)))
     }
 }
 
@@ -1639,65 +1580,6 @@ pub(crate) fn lower_to_chalk_mutability(m: hir_def::type_ref::Mutability) -> Mut
     }
 }
 
-pub(crate) fn generic_arg_to_chalk<'a, T>(
-    db: &dyn HirDatabase,
-    kind_id: Either<TypeParamId, ConstParamId>,
-    arg: &'a GenericArg,
-    this: &mut T,
-    for_type: impl FnOnce(&mut T, &TypeRef) -> Ty + 'a,
-    for_const: impl FnOnce(&mut T, &ConstScalarOrPath) -> Const + 'a,
-) -> Option<crate::GenericArg> {
-    let kind = match kind_id {
-        Either::Left(_) => ParamKind::Type,
-        Either::Right(id) => {
-            let ty = db.const_param_ty(id);
-            ParamKind::Const(ty)
-        }
-    };
-    Some(match (arg, kind) {
-        (GenericArg::Type(type_ref), ParamKind::Type) => {
-            let ty = for_type(this, type_ref);
-            GenericArgData::Ty(ty).intern(Interner)
-        }
-        (GenericArg::Const(c), ParamKind::Const(_)) => {
-            GenericArgData::Const(for_const(this, c)).intern(Interner)
-        }
-        (GenericArg::Const(_), ParamKind::Type) => {
-            GenericArgData::Ty(TyKind::Error.intern(Interner)).intern(Interner)
-        }
-        (GenericArg::Type(t), ParamKind::Const(ty)) => {
-            // We want to recover simple idents, which parser detects them
-            // as types. Maybe here is not the best place to do it, but
-            // it works.
-            if let TypeRef::Path(p) = t {
-                let p = p.mod_path();
-                if p.kind == PathKind::Plain {
-                    if let [n] = p.segments() {
-                        let c = ConstScalarOrPath::Path(n.clone());
-                        return Some(GenericArgData::Const(for_const(this, &c)).intern(Interner));
-                    }
-                }
-            }
-            unknown_const_as_generic(ty)
-        }
-        (GenericArg::Lifetime(_), _) => return None,
-    })
-}
-
-pub(crate) fn const_or_path_to_chalk(
-    db: &dyn HirDatabase,
-    resolver: &Resolver,
-    value: &ConstScalarOrPath,
-    mode: ParamLoweringMode,
-    args: impl FnOnce() -> Generics,
-    debruijn: DebruijnIndex,
-) -> Const {
-    match value {
-        ConstScalarOrPath::Scalar(s) => usize_const(s.as_usize()),
-        ConstScalarOrPath::Path(n) => {
-            let path = ModPath::from_segments(PathKind::Plain, Some(n.clone()));
-            path_to_const(db, resolver, &path, mode, args, debruijn)
-                .unwrap_or_else(|| unknown_const_usize())
-        }
-    }
+fn make_binders<T: HasInterner<Interner = Interner>>(generics: &Generics, value: T) -> Binders<T> {
+    crate::make_only_type_binders(generics.len(), value)
 }
diff --git a/crates/hir_ty/src/method_resolution.rs b/crates/hir_ty/src/method_resolution.rs
index 06c834fbc8..6564a3f4c7 100644
--- a/crates/hir_ty/src/method_resolution.rs
+++ b/crates/hir_ty/src/method_resolution.rs
@@ -6,7 +6,7 @@ use std::{iter, ops::ControlFlow, sync::Arc};
 
 use arrayvec::ArrayVec;
 use base_db::{CrateId, Edition};
-use chalk_ir::{cast::Cast, fold::Fold, interner::HasInterner, Mutability, UniverseIndex};
+use chalk_ir::{cast::Cast, Mutability, UniverseIndex};
 use hir_def::{
     item_scope::ItemScope, lang_item::LangItemTarget, nameres::DefMap, AssocItemId, BlockId,
     ConstId, FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, Lookup, ModuleDefId,
@@ -25,9 +25,8 @@ use crate::{
     primitive::{self, FloatTy, IntTy, UintTy},
     static_lifetime,
     utils::all_super_traits,
-    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, GenericArgData,
-    InEnvironment, Interner, Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder,
-    TyExt, TyKind,
+    AdtId, Canonical, CanonicalVarKinds, DebruijnIndex, ForeignDefId, InEnvironment, Interner,
+    Scalar, Substitution, TraitEnvironment, TraitRefExt, Ty, TyBuilder, TyExt, TyKind,
 };
 
 /// This is used as a key for indexing impls.
@@ -1088,14 +1087,13 @@ pub(crate) fn inherent_impl_substs(
         .build();
     let self_ty_with_vars = db.impl_self_ty(impl_id).substitute(Interner, &vars);
     let mut kinds = self_ty.binders.interned().to_vec();
-    kinds.extend(vars.iter(Interner).map(|x| {
-        let kind = match x.data(Interner) {
-            GenericArgData::Ty(_) => chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
-            GenericArgData::Const(c) => chalk_ir::VariableKind::Const(c.data(Interner).ty.clone()),
-            GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
-        };
-        chalk_ir::WithKind::new(kind, UniverseIndex::ROOT)
-    }));
+    kinds.extend(
+        iter::repeat(chalk_ir::WithKind::new(
+            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+            UniverseIndex::ROOT,
+        ))
+        .take(vars.len(Interner)),
+    );
     let tys = Canonical {
         binders: CanonicalVarKinds::from_iter(Interner, kinds),
         value: (self_ty_with_vars, self_ty.value.clone()),
@@ -1113,27 +1111,14 @@ pub(crate) fn inherent_impl_substs(
 
 /// This replaces any 'free' Bound vars in `s` (i.e. those with indices past
 /// num_vars_to_keep) by `TyKind::Unknown`.
-pub(crate) fn fallback_bound_vars<T: Fold<Interner> + HasInterner<Interner = Interner>>(
-    s: T,
-    num_vars_to_keep: usize,
-) -> T::Result {
-    crate::fold_free_vars(
-        s,
-        |bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                TyKind::Error.intern(Interner)
-            } else {
-                bound.shifted_in_from(binders).to_ty(Interner)
-            }
-        },
-        |ty, bound, binders| {
-            if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
-                consteval::usize_const(None)
-            } else {
-                bound.shifted_in_from(binders).to_const(Interner, ty)
-            }
-        },
-    )
+fn fallback_bound_vars(s: Substitution, num_vars_to_keep: usize) -> Substitution {
+    crate::fold_free_vars(s, |bound, binders| {
+        if bound.index >= num_vars_to_keep && bound.debruijn == DebruijnIndex::INNERMOST {
+            TyKind::Error.intern(Interner)
+        } else {
+            bound.shifted_in_from(binders).to_ty(Interner)
+        }
+    })
 }
 
 fn transform_receiver_ty(
@@ -1198,18 +1183,13 @@ fn generic_implements_goal(
         .push(self_ty.value.clone())
         .fill_with_bound_vars(DebruijnIndex::INNERMOST, kinds.len())
         .build();
-    kinds.extend(trait_ref.substitution.iter(Interner).skip(1).map(|x| {
-        let vk = match x.data(Interner) {
-            chalk_ir::GenericArgData::Ty(_) => {
-                chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General)
-            }
-            chalk_ir::GenericArgData::Lifetime(_) => chalk_ir::VariableKind::Lifetime,
-            chalk_ir::GenericArgData::Const(c) => {
-                chalk_ir::VariableKind::Const(c.data(Interner).ty.clone())
-            }
-        };
-        chalk_ir::WithKind::new(vk, UniverseIndex::ROOT)
-    }));
+    kinds.extend(
+        iter::repeat(chalk_ir::WithKind::new(
+            chalk_ir::VariableKind::Ty(chalk_ir::TyVariableKind::General),
+            UniverseIndex::ROOT,
+        ))
+        .take(trait_ref.substitution.len(Interner) - 1),
+    );
     let obligation = trait_ref.cast(Interner);
     Canonical {
         binders: CanonicalVarKinds::from_iter(Interner, kinds),
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index 343e89eb9b..a6706aa81d 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -15,18 +15,16 @@ use hir_def::{
     path::Path,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    ConstParamId, GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
-    TypeParamId,
+    GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
 };
 use hir_expand::name::{name, Name};
-use itertools::Either;
 use rustc_hash::FxHashSet;
 use smallvec::{smallvec, SmallVec};
 use syntax::SmolStr;
 
 use crate::{
-    db::HirDatabase, ChalkTraitId, ConstData, ConstValue, GenericArgData, Interner, Substitution,
-    TraitRef, TraitRefExt, TyKind, WhereClause,
+    db::HirDatabase, ChalkTraitId, Interner, Substitution, TraitRef, TraitRefExt, TyKind,
+    WhereClause,
 };
 
 pub(crate) fn fn_traits(db: &dyn DefDatabase, krate: CrateId) -> impl Iterator<Item = TraitId> {
@@ -205,43 +203,30 @@ impl Generics {
             )
     }
 
-    pub(crate) fn iter_id<'a>(
+    pub(crate) fn toc_iter<'a>(
         &'a self,
-    ) -> impl Iterator<Item = Either<TypeParamId, ConstParamId>> + 'a {
-        self.iter().map(|(id, data)| match data {
-            TypeOrConstParamData::TypeParamData(_) => Either::Left(TypeParamId::from_unchecked(id)),
-            TypeOrConstParamData::ConstParamData(_) => {
-                Either::Right(ConstParamId::from_unchecked(id))
-            }
-        })
-    }
-
-    /// Iterator over types and const params of parent, then self.
-    pub(crate) fn iter<'a>(
-        &'a self,
-    ) -> impl DoubleEndedIterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
+    ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
         self.parent_generics
             .as_ref()
             .into_iter()
             .flat_map(|it| {
                 it.params
-                    .iter()
+                    .toc_iter()
                     .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
             })
             .chain(
-                self.params.iter().map(move |(local_id, p)| {
+                self.params.toc_iter().map(move |(local_id, p)| {
                     (TypeOrConstParamId { parent: self.def, local_id }, p)
                 }),
             )
     }
 
-    /// Iterator over types and const params of parent.
     pub(crate) fn iter_parent<'a>(
         &'a self,
     ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
         self.parent_generics.as_ref().into_iter().flat_map(|it| {
             it.params
-                .type_or_consts
+                .tocs
                 .iter()
                 .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
         })
@@ -254,7 +239,7 @@ impl Generics {
     /// (total, parents, child)
     pub(crate) fn len_split(&self) -> (usize, usize, usize) {
         let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
-        let child = self.params.type_or_consts.len();
+        let child = self.params.tocs.len();
         (parent + child, parent, child)
     }
 
@@ -263,20 +248,22 @@ impl Generics {
         let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
         let self_params = self
             .params
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .filter(|p| p.provenance == TypeParamProvenance::TraitSelf)
             .count();
         let type_params = self
             .params
-            .type_or_consts
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .filter(|p| p.provenance == TypeParamProvenance::TypeParamList)
             .count();
-        let const_params = self.params.iter().filter_map(|x| x.1.const_param()).count();
+        let const_params = self.params.tocs.iter().filter_map(|x| x.1.const_param()).count();
         let impl_trait_params = self
             .params
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait)
@@ -292,7 +279,7 @@ impl Generics {
         if param.parent == self.def {
             let (idx, (_local_id, data)) = self
                 .params
-                .type_or_consts
+                .tocs
                 .iter()
                 .enumerate()
                 .find(|(_, (idx, _))| *idx == param.local_id)
@@ -305,47 +292,21 @@ impl Generics {
     }
 
     /// Returns a Substitution that replaces each parameter by a bound variable.
-    pub(crate) fn bound_vars_subst(
-        &self,
-        db: &dyn HirDatabase,
-        debruijn: DebruijnIndex,
-    ) -> Substitution {
+    pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution {
         Substitution::from_iter(
             Interner,
-            self.iter_id().enumerate().map(|(idx, id)| match id {
-                Either::Left(_) => GenericArgData::Ty(
-                    TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner),
-                )
-                .intern(Interner),
-                Either::Right(id) => GenericArgData::Const(
-                    ConstData {
-                        value: ConstValue::BoundVar(BoundVar::new(debruijn, idx)),
-                        ty: db.const_param_ty(id),
-                    }
-                    .intern(Interner),
-                )
-                .intern(Interner),
-            }),
+            self.toc_iter()
+                .enumerate()
+                .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
         )
     }
 
     /// Returns a Substitution that replaces each parameter by itself (i.e. `Ty::Param`).
-    pub(crate) fn placeholder_subst(&self, db: &dyn HirDatabase) -> Substitution {
+    pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution {
         Substitution::from_iter(
             Interner,
-            self.iter_id().map(|id| match id {
-                Either::Left(id) => GenericArgData::Ty(
-                    TyKind::Placeholder(crate::to_placeholder_idx(db, id.into())).intern(Interner),
-                )
-                .intern(Interner),
-                Either::Right(id) => GenericArgData::Const(
-                    ConstData {
-                        value: ConstValue::Placeholder(crate::to_placeholder_idx(db, id.into())),
-                        ty: db.const_param_ty(id),
-                    }
-                    .intern(Interner),
-                )
-                .intern(Interner),
+            self.toc_iter().map(|(id, _)| {
+                TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(Interner)
             }),
         )
     }
diff --git a/crates/ide_db/Cargo.toml b/crates/ide_db/Cargo.toml
index e00803708b..c71a213c40 100644
--- a/crates/ide_db/Cargo.toml
+++ b/crates/ide_db/Cargo.toml
@@ -35,5 +35,5 @@ limit = { path = "../limit", version = "0.0.0" }
 [dev-dependencies]
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
-xshell = "0.1"
+xshell = "0.2.0"
 expect-test = "1.2.0-pre.1"
diff --git a/crates/rust-analyzer/Cargo.toml b/crates/rust-analyzer/Cargo.toml
index 87b6cd7186..68d728b41f 100644
--- a/crates/rust-analyzer/Cargo.toml
+++ b/crates/rust-analyzer/Cargo.toml
@@ -75,7 +75,7 @@ jemallocator = { version = "0.4.1", package = "tikv-jemallocator", optional = tr
 [dev-dependencies]
 expect-test = "1.2.0-pre.1"
 jod-thread = "0.1.0"
-xshell = "0.1"
+xshell = "0.2.0"
 
 test_utils = { path = "../test_utils" }
 sourcegen = { path = "../sourcegen" }
diff --git a/crates/sourcegen/Cargo.toml b/crates/sourcegen/Cargo.toml
index 9cfe181c2e..10587d913d 100644
--- a/crates/sourcegen/Cargo.toml
+++ b/crates/sourcegen/Cargo.toml
@@ -10,4 +10,4 @@ rust-version = "1.57"
 doctest = false
 
 [dependencies]
-xshell = "0.1"
+xshell = "0.2.0"
diff --git a/crates/sourcegen/src/lib.rs b/crates/sourcegen/src/lib.rs
index 398e846a14..719b35b630 100644
--- a/crates/sourcegen/src/lib.rs
+++ b/crates/sourcegen/src/lib.rs
@@ -11,7 +11,7 @@ use std::{
     path::{Path, PathBuf},
 };
 
-use xshell::{cmd, pushenv};
+use xshell::{cmd, Shell};
 
 pub fn list_rust_files(dir: &Path) -> Vec<PathBuf> {
     let mut res = list_files(dir);
@@ -133,8 +133,8 @@ impl fmt::Display for Location {
     }
 }
 
-fn ensure_rustfmt() {
-    let version = cmd!("rustfmt --version").read().unwrap_or_default();
+fn ensure_rustfmt(sh: &Shell) {
+    let version = cmd!(sh, "rustfmt --version").read().unwrap_or_default();
     if !version.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -144,10 +144,11 @@ fn ensure_rustfmt() {
 }
 
 pub fn reformat(text: String) -> String {
-    let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
-    ensure_rustfmt();
+    let sh = Shell::new().unwrap();
+    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
+    ensure_rustfmt(&sh);
     let rustfmt_toml = project_root().join("rustfmt.toml");
-    let mut stdout = cmd!("rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
+    let mut stdout = cmd!(sh, "rustfmt --config-path {rustfmt_toml} --config fn_single_line=true")
         .stdin(text)
         .read()
         .unwrap();
diff --git a/xtask/Cargo.toml b/xtask/Cargo.toml
index 0acbaf8176..d9adf88c02 100644
--- a/xtask/Cargo.toml
+++ b/xtask/Cargo.toml
@@ -10,6 +10,6 @@ rust-version = "1.57"
 anyhow = "1.0.26"
 flate2 = "1.0"
 write-json = "0.1.0"
-xshell = "0.1"
+xshell = "0.2.0"
 xflags = "0.2.1"
 # Avoid adding more dependencies to this crate
diff --git a/xtask/src/dist.rs b/xtask/src/dist.rs
index 985829880c..3c58fbb76d 100644
--- a/xtask/src/dist.rs
+++ b/xtask/src/dist.rs
@@ -5,25 +5,23 @@ use std::{
     path::{Path, PathBuf},
 };
 
-use anyhow::Result;
 use flate2::{write::GzEncoder, Compression};
-use xshell::{cmd, cp, mkdir_p, pushd, pushenv, read_file, rm_rf, write_file};
+use xshell::{cmd, Shell};
 
 use crate::{date_iso, flags, project_root};
 
 impl flags::Dist {
-    pub(crate) fn run(self) -> Result<()> {
-        let stable =
-            std::env::var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";
+    pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
+        let stable = sh.var("GITHUB_REF").unwrap_or_default().as_str() == "refs/heads/release";
 
         let project_root = project_root();
         let target = Target::get(&project_root);
         let dist = project_root.join("dist");
-        rm_rf(&dist)?;
-        mkdir_p(&dist)?;
+        sh.remove_path(&dist)?;
+        sh.create_dir(&dist)?;
 
         let release_channel = if stable { "stable" } else { "nightly" };
-        dist_server(release_channel, &target)?;
+        dist_server(sh, release_channel, &target)?;
 
         if let Some(patch_version) = self.client_patch_version {
             let version = if stable {
@@ -32,50 +30,55 @@ impl flags::Dist {
                 // A hack to make VS Code prefer nightly over stable.
                 format!("0.3.{}", patch_version)
             };
-            let release_tag = if stable { date_iso()? } else { "nightly".to_string() };
-            dist_client(&version, &release_tag, &target)?;
+            let release_tag = if stable { date_iso(sh)? } else { "nightly".to_string() };
+            dist_client(sh, &version, &release_tag, &target)?;
         }
         Ok(())
     }
 }
 
-fn dist_client(version: &str, release_tag: &str, target: &Target) -> Result<()> {
+fn dist_client(
+    sh: &Shell,
+    version: &str,
+    release_tag: &str,
+    target: &Target,
+) -> anyhow::Result<()> {
     let bundle_path = Path::new("editors").join("code").join("server");
-    mkdir_p(&bundle_path)?;
-    cp(&target.server_path, &bundle_path)?;
+    sh.create_dir(&bundle_path)?;
+    sh.copy_file(&target.server_path, &bundle_path)?;
     if let Some(symbols_path) = &target.symbols_path {
-        cp(symbols_path, &bundle_path)?;
+        sh.copy_file(symbols_path, &bundle_path)?;
     }
 
-    let _d = pushd("./editors/code")?;
+    let _d = sh.push_dir("./editors/code");
 
-    let mut patch = Patch::new("./package.json")?;
+    let mut patch = Patch::new(sh, "./package.json")?;
     patch
         .replace(r#""version": "0.4.0-dev""#, &format!(r#""version": "{}""#, version))
         .replace(r#""releaseTag": null"#, &format!(r#""releaseTag": "{}""#, release_tag))
         .replace(r#""$generated-start": {},"#, "")
         .replace(",\n                \"$generated-end\": {}", "")
         .replace(r#""enabledApiProposals": [],"#, r#""#);
-    patch.commit()?;
+    patch.commit(sh)?;
 
     Ok(())
 }
 
-fn dist_server(release_channel: &str, target: &Target) -> Result<()> {
-    let _e = pushenv("RUST_ANALYZER_CHANNEL", release_channel);
-    let _e = pushenv("CARGO_PROFILE_RELEASE_LTO", "thin");
+fn dist_server(sh: &Shell, release_channel: &str, target: &Target) -> anyhow::Result<()> {
+    let _e = sh.push_env("RUST_ANALYZER_CHANNEL", release_channel);
+    let _e = sh.push_env("CARGO_PROFILE_RELEASE_LTO", "thin");
 
     // Uncomment to enable debug info for releases. Note that:
     //   * debug info is split on windows and macs, so it does nothing for those platforms,
     //   * on Linux, this blows up the binary size from 8MB to 43MB, which is unreasonable.
-    // let _e = pushenv("CARGO_PROFILE_RELEASE_DEBUG", "1");
+    // let _e = sh.push_env("CARGO_PROFILE_RELEASE_DEBUG", "1");
 
     if target.name.contains("-linux-") {
         env::set_var("CC", "clang");
     }
 
     let target_name = &target.name;
-    cmd!("cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;
+    cmd!(sh, "cargo build --manifest-path ./crates/rust-analyzer/Cargo.toml --bin rust-analyzer --target {target_name} --release").run()?;
 
     let dst = Path::new("dist").join(&target.artifact_name);
     gzip(&target.server_path, &dst.with_extension("gz"))?;
@@ -83,7 +86,7 @@ fn dist_server(release_channel: &str, target: &Target) -> Result<()> {
     Ok(())
 }
 
-fn gzip(src_path: &Path, dest_path: &Path) -> Result<()> {
+fn gzip(src_path: &Path, dest_path: &Path) -> anyhow::Result<()> {
     let mut encoder = GzEncoder::new(File::create(dest_path)?, Compression::best());
     let mut input = io::BufReader::new(File::open(src_path)?);
     io::copy(&mut input, &mut encoder)?;
@@ -133,9 +136,9 @@ struct Patch {
 }
 
 impl Patch {
-    fn new(path: impl Into<PathBuf>) -> Result<Patch> {
+    fn new(sh: &Shell, path: impl Into<PathBuf>) -> anyhow::Result<Patch> {
         let path = path.into();
-        let contents = read_file(&path)?;
+        let contents = sh.read_file(&path)?;
         Ok(Patch { path, original_contents: contents.clone(), contents })
     }
 
@@ -145,8 +148,8 @@ impl Patch {
         self
     }
 
-    fn commit(&self) -> Result<()> {
-        write_file(&self.path, &self.contents)?;
+    fn commit(&self, sh: &Shell) -> anyhow::Result<()> {
+        sh.write_file(&self.path, &self.contents)?;
         Ok(())
     }
 }
diff --git a/xtask/src/install.rs b/xtask/src/install.rs
index 58f386be85..ae978d5512 100644
--- a/xtask/src/install.rs
+++ b/xtask/src/install.rs
@@ -3,20 +3,20 @@
 use std::{env, path::PathBuf, str};
 
 use anyhow::{bail, format_err, Context, Result};
-use xshell::{cmd, pushd};
+use xshell::{cmd, Shell};
 
 use crate::flags;
 
 impl flags::Install {
-    pub(crate) fn run(self) -> Result<()> {
+    pub(crate) fn run(self, sh: &Shell) -> Result<()> {
         if cfg!(target_os = "macos") {
-            fix_path_for_mac().context("Fix path for mac")?;
+            fix_path_for_mac(sh).context("Fix path for mac")?;
         }
         if let Some(server) = self.server() {
-            install_server(server).context("install server")?;
+            install_server(sh, server).context("install server")?;
         }
         if let Some(client) = self.client() {
-            install_client(client).context("install client")?;
+            install_client(sh, client).context("install client")?;
         }
         Ok(())
     }
@@ -39,15 +39,14 @@ pub(crate) enum Malloc {
     Jemalloc,
 }
 
-fn fix_path_for_mac() -> Result<()> {
+fn fix_path_for_mac(sh: &Shell) -> Result<()> {
     let mut vscode_path: Vec<PathBuf> = {
         const COMMON_APP_PATH: &str =
             r"/Applications/Visual Studio Code.app/Contents/Resources/app/bin";
         const ROOT_DIR: &str = "";
-        let home_dir = match env::var("HOME") {
-            Ok(home) => home,
-            Err(e) => bail!("Failed getting HOME from environment with error: {}.", e),
-        };
+        let home_dir = sh.var("HOME").map_err(|err| {
+            format_err!("Failed getting HOME from environment with error: {}.", err)
+        })?;
 
         [ROOT_DIR, &home_dir]
             .into_iter()
@@ -58,36 +57,33 @@ fn fix_path_for_mac() -> Result<()> {
     };
 
     if !vscode_path.is_empty() {
-        let vars = match env::var_os("PATH") {
-            Some(path) => path,
-            None => bail!("Could not get PATH variable from env."),
-        };
+        let vars = sh.var_os("PATH").context("Could not get PATH variable from env.")?;
 
         let mut paths = env::split_paths(&vars).collect::<Vec<_>>();
         paths.append(&mut vscode_path);
         let new_paths = env::join_paths(paths).context("build env PATH")?;
-        env::set_var("PATH", &new_paths);
+        sh.set_var("PATH", &new_paths);
     }
 
     Ok(())
 }
 
-fn install_client(client_opt: ClientOpt) -> Result<()> {
-    let _dir = pushd("./editors/code");
+fn install_client(sh: &Shell, client_opt: ClientOpt) -> Result<()> {
+    let _dir = sh.push_dir("./editors/code");
 
     // Package extension.
     if cfg!(unix) {
-        cmd!("npm --version").run().context("`npm` is required to build the VS Code plugin")?;
-        cmd!("npm ci").run()?;
+        cmd!(sh, "npm --version").run().context("`npm` is required to build the VS Code plugin")?;
+        cmd!(sh, "npm ci").run()?;
 
-        cmd!("npm run package --scripts-prepend-node-path").run()?;
+        cmd!(sh, "npm run package --scripts-prepend-node-path").run()?;
     } else {
-        cmd!("cmd.exe /c npm --version")
+        cmd!(sh, "cmd.exe /c npm --version")
             .run()
             .context("`npm` is required to build the VS Code plugin")?;
-        cmd!("cmd.exe /c npm ci").run()?;
+        cmd!(sh, "cmd.exe /c npm ci").run()?;
 
-        cmd!("cmd.exe /c npm run package").run()?;
+        cmd!(sh, "cmd.exe /c npm run package").run()?;
     };
 
     // Find the appropriate VS Code binary.
@@ -104,9 +100,9 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
         .copied()
         .find(|&bin| {
             if cfg!(unix) {
-                cmd!("{bin} --version").read().is_ok()
+                cmd!(sh, "{bin} --version").read().is_ok()
             } else {
-                cmd!("cmd.exe /c {bin}.cmd --version").read().is_ok()
+                cmd!(sh, "cmd.exe /c {bin}.cmd --version").read().is_ok()
             }
         })
         .ok_or_else(|| {
@@ -115,11 +111,11 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
 
     // Install & verify.
     let installed_extensions = if cfg!(unix) {
-        cmd!("{code} --install-extension rust-analyzer.vsix --force").run()?;
-        cmd!("{code} --list-extensions").read()?
+        cmd!(sh, "{code} --install-extension rust-analyzer.vsix --force").run()?;
+        cmd!(sh, "{code} --list-extensions").read()?
     } else {
-        cmd!("cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
-        cmd!("cmd.exe /c {code}.cmd --list-extensions").read()?
+        cmd!(sh, "cmd.exe /c {code}.cmd --install-extension rust-analyzer.vsix --force").run()?;
+        cmd!(sh, "cmd.exe /c {code}.cmd --list-extensions").read()?
     };
 
     if !installed_extensions.contains("rust-analyzer") {
@@ -133,14 +129,14 @@ fn install_client(client_opt: ClientOpt) -> Result<()> {
     Ok(())
 }
 
-fn install_server(opts: ServerOpt) -> Result<()> {
+fn install_server(sh: &Shell, opts: ServerOpt) -> Result<()> {
     let features = match opts.malloc {
         Malloc::System => &[][..],
         Malloc::Mimalloc => &["--features", "mimalloc"],
         Malloc::Jemalloc => &["--features", "jemalloc"],
     };
 
-    let cmd = cmd!("cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
+    let cmd = cmd!(sh, "cargo install --path crates/rust-analyzer --locked --force --features force-always-assert {features...}");
     cmd.run()?;
     Ok(())
 }
diff --git a/xtask/src/main.rs b/xtask/src/main.rs
index 5e5401ce28..df726dc23c 100644
--- a/xtask/src/main.rs
+++ b/xtask/src/main.rs
@@ -14,15 +14,16 @@ mod release;
 mod dist;
 mod metrics;
 
-use anyhow::{bail, Result};
+use anyhow::bail;
 use std::{
     env,
     path::{Path, PathBuf},
 };
-use xshell::{cmd, cp, pushd, pushenv};
+use xshell::{cmd, Shell};
 
-fn main() -> Result<()> {
-    let _d = pushd(project_root())?;
+fn main() -> anyhow::Result<()> {
+    let sh = &Shell::new()?;
+    sh.change_dir(project_root());
 
     let flags = flags::Xtask::from_env()?;
     match flags.subcommand {
@@ -30,18 +31,21 @@ fn main() -> Result<()> {
             println!("{}", flags::Xtask::HELP);
             Ok(())
         }
-        flags::XtaskCmd::Install(cmd) => cmd.run(),
-        flags::XtaskCmd::FuzzTests(_) => run_fuzzer(),
-        flags::XtaskCmd::Release(cmd) => cmd.run(),
-        flags::XtaskCmd::Promote(cmd) => cmd.run(),
-        flags::XtaskCmd::Dist(cmd) => cmd.run(),
-        flags::XtaskCmd::Metrics(cmd) => cmd.run(),
+        flags::XtaskCmd::Install(cmd) => cmd.run(sh),
+        flags::XtaskCmd::FuzzTests(_) => run_fuzzer(sh),
+        flags::XtaskCmd::Release(cmd) => cmd.run(sh),
+        flags::XtaskCmd::Promote(cmd) => cmd.run(sh),
+        flags::XtaskCmd::Dist(cmd) => cmd.run(sh),
+        flags::XtaskCmd::Metrics(cmd) => cmd.run(sh),
         flags::XtaskCmd::Bb(cmd) => {
             {
-                let _d = pushd("./crates/rust-analyzer")?;
-                cmd!("cargo build --release --features jemalloc").run()?;
+                let _d = sh.push_dir("./crates/rust-analyzer");
+                cmd!(sh, "cargo build --release --features jemalloc").run()?;
             }
-            cp("./target/release/rust-analyzer", format!("./target/rust-analyzer-{}", cmd.suffix))?;
+            sh.copy_file(
+                "./target/release/rust-analyzer",
+                format!("./target/rust-analyzer-{}", cmd.suffix),
+            )?;
             Ok(())
         }
     }
@@ -57,25 +61,25 @@ fn project_root() -> PathBuf {
     .to_path_buf()
 }
 
-fn run_fuzzer() -> Result<()> {
-    let _d = pushd("./crates/syntax")?;
-    let _e = pushenv("RUSTUP_TOOLCHAIN", "nightly");
-    if cmd!("cargo fuzz --help").read().is_err() {
-        cmd!("cargo install cargo-fuzz").run()?;
+fn run_fuzzer(sh: &Shell) -> anyhow::Result<()> {
+    let _d = sh.push_dir("./crates/syntax");
+    let _e = sh.push_env("RUSTUP_TOOLCHAIN", "nightly");
+    if cmd!(sh, "cargo fuzz --help").read().is_err() {
+        cmd!(sh, "cargo install cargo-fuzz").run()?;
     };
 
     // Expecting nightly rustc
-    let out = cmd!("rustc --version").read()?;
+    let out = cmd!(sh, "rustc --version").read()?;
     if !out.contains("nightly") {
         bail!("fuzz tests require nightly rustc")
     }
 
-    cmd!("cargo fuzz run parser").run()?;
+    cmd!(sh, "cargo fuzz run parser").run()?;
     Ok(())
 }
 
-fn date_iso() -> Result<String> {
-    let res = cmd!("date -u +%Y-%m-%d").read()?;
+fn date_iso(sh: &Shell) -> anyhow::Result<String> {
+    let res = cmd!(sh, "date -u +%Y-%m-%d").read()?;
     Ok(res)
 }
 
diff --git a/xtask/src/metrics.rs b/xtask/src/metrics.rs
index e4d3e981af..b683b32e6d 100644
--- a/xtask/src/metrics.rs
+++ b/xtask/src/metrics.rs
@@ -1,95 +1,103 @@
 use std::{
     collections::BTreeMap,
-    env,
+    env, fs,
     io::Write as _,
     path::Path,
     time::{Instant, SystemTime, UNIX_EPOCH},
 };
 
-use anyhow::{bail, format_err, Result};
-use xshell::{cmd, mkdir_p, pushd, pushenv, read_file, rm_rf};
+use anyhow::{bail, format_err};
+use xshell::{cmd, Shell};
 
 use crate::flags;
 
 type Unit = String;
 
 impl flags::Metrics {
-    pub(crate) fn run(self) -> Result<()> {
-        let mut metrics = Metrics::new()?;
+    pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
+        let mut metrics = Metrics::new(sh)?;
         if !self.dry_run {
-            rm_rf("./target/release")?;
+            sh.remove_path("./target/release")?;
         }
         if !Path::new("./target/rustc-perf").exists() {
-            mkdir_p("./target/rustc-perf")?;
-            cmd!("git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")
+            sh.create_dir("./target/rustc-perf")?;
+            cmd!(sh, "git clone https://github.com/rust-lang/rustc-perf.git ./target/rustc-perf")
                 .run()?;
         }
         {
-            let _d = pushd("./target/rustc-perf")?;
+            let _d = sh.push_dir("./target/rustc-perf");
             let revision = &metrics.perf_revision;
-            cmd!("git reset --hard {revision}").run()?;
+            cmd!(sh, "git reset --hard {revision}").run()?;
         }
 
-        let _env = pushenv("RA_METRICS", "1");
+        let _env = sh.push_env("RA_METRICS", "1");
 
         {
             // https://github.com/rust-analyzer/rust-analyzer/issues/9997
-            let _d = pushd("target/rustc-perf/collector/benchmarks/webrender")?;
-            cmd!("cargo update -p url --precise 1.6.1").run()?;
+            let _d = sh.push_dir("target/rustc-perf/collector/benchmarks/webrender");
+            cmd!(sh, "cargo update -p url --precise 1.6.1").run()?;
         }
-        metrics.measure_build()?;
-        metrics.measure_analysis_stats_self()?;
-        metrics.measure_analysis_stats("ripgrep")?;
-        metrics.measure_analysis_stats("webrender")?;
-        metrics.measure_analysis_stats("diesel/diesel")?;
+        metrics.measure_build(sh)?;
+        metrics.measure_analysis_stats_self(sh)?;
+        metrics.measure_analysis_stats(sh, "ripgrep")?;
+        metrics.measure_analysis_stats(sh, "webrender")?;
+        metrics.measure_analysis_stats(sh, "diesel/diesel")?;
 
         if !self.dry_run {
-            let _d = pushd("target")?;
+            let _d = sh.push_dir("target");
             let metrics_token = env::var("METRICS_TOKEN").unwrap();
             cmd!(
+                sh,
                 "git clone --depth 1 https://{metrics_token}@github.com/rust-analyzer/metrics.git"
             )
             .run()?;
-            let _d = pushd("metrics")?;
+            let _d = sh.push_dir("metrics");
 
-            let mut file = std::fs::OpenOptions::new().append(true).open("metrics.json")?;
+            let mut file = fs::File::options().append(true).open("metrics.json")?;
             writeln!(file, "{}", metrics.json())?;
-            cmd!("git add .").run()?;
-            cmd!("git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
+            cmd!(sh, "git add .").run()?;
+            cmd!(sh, "git -c user.name=Bot -c user.email=dummy@example.com commit --message 📈")
                 .run()?;
-            cmd!("git push origin master").run()?;
+            cmd!(sh, "git push origin master").run()?;
         }
-        eprintln!("{:#?}", metrics);
+        eprintln!("{metrics:#?}");
         Ok(())
     }
 }
 
 impl Metrics {
-    fn measure_build(&mut self) -> Result<()> {
+    fn measure_build(&mut self, sh: &Shell) -> anyhow::Result<()> {
         eprintln!("\nMeasuring build");
-        cmd!("cargo fetch").run()?;
+        cmd!(sh, "cargo fetch").run()?;
 
         let time = Instant::now();
-        cmd!("cargo build --release --package rust-analyzer --bin rust-analyzer").run()?;
+        cmd!(sh, "cargo build --release --package rust-analyzer --bin rust-analyzer").run()?;
         let time = time.elapsed();
         self.report("build", time.as_millis() as u64, "ms".into());
         Ok(())
     }
-    fn measure_analysis_stats_self(&mut self) -> Result<()> {
-        self.measure_analysis_stats_path("self", ".")
+    fn measure_analysis_stats_self(&mut self, sh: &Shell) -> anyhow::Result<()> {
+        self.measure_analysis_stats_path(sh, "self", ".")
     }
-    fn measure_analysis_stats(&mut self, bench: &str) -> Result<()> {
+    fn measure_analysis_stats(&mut self, sh: &Shell, bench: &str) -> anyhow::Result<()> {
         self.measure_analysis_stats_path(
+            sh,
             bench,
             &format!("./target/rustc-perf/collector/benchmarks/{}", bench),
         )
     }
-    fn measure_analysis_stats_path(&mut self, name: &str, path: &str) -> Result<()> {
-        eprintln!("\nMeasuring analysis-stats/{}", name);
-        let output = cmd!("./target/release/rust-analyzer -q analysis-stats --memory-usage {path}")
-            .read()?;
+    fn measure_analysis_stats_path(
+        &mut self,
+        sh: &Shell,
+        name: &str,
+        path: &str,
+    ) -> anyhow::Result<()> {
+        eprintln!("\nMeasuring analysis-stats/{name}");
+        let output =
+            cmd!(sh, "./target/release/rust-analyzer -q analysis-stats --memory-usage {path}")
+                .read()?;
         for (metric, value, unit) in parse_metrics(&output) {
-            self.report(&format!("analysis-stats/{}/{}", name, metric), value, unit.into());
+            self.report(&format!("analysis-stats/{name}/{metric}"), value, unit.into());
         }
         Ok(())
     }
@@ -125,10 +133,10 @@ struct Host {
 }
 
 impl Metrics {
-    fn new() -> Result<Metrics> {
-        let host = Host::new()?;
+    fn new(sh: &Shell) -> anyhow::Result<Metrics> {
+        let host = Host::new(sh)?;
         let timestamp = SystemTime::now();
-        let revision = cmd!("git rev-parse HEAD").read()?;
+        let revision = cmd!(sh, "git rev-parse HEAD").read()?;
         let perf_revision = "c52ee623e231e7690a93be88d943016968c1036b".into();
         Ok(Metrics { host, timestamp, revision, perf_revision, metrics: BTreeMap::new() })
     }
@@ -157,28 +165,29 @@ impl Metrics {
 }
 
 impl Host {
-    fn new() -> Result<Host> {
+    fn new(sh: &Shell) -> anyhow::Result<Host> {
         if cfg!(not(target_os = "linux")) {
             bail!("can only collect metrics on Linux ");
         }
 
-        let os = read_field("/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
+        let os = read_field(sh, "/etc/os-release", "PRETTY_NAME=")?.trim_matches('"').to_string();
 
-        let cpu =
-            read_field("/proc/cpuinfo", "model name")?.trim_start_matches(':').trim().to_string();
+        let cpu = read_field(sh, "/proc/cpuinfo", "model name")?
+            .trim_start_matches(':')
+            .trim()
+            .to_string();
 
-        let mem = read_field("/proc/meminfo", "MemTotal:")?;
+        let mem = read_field(sh, "/proc/meminfo", "MemTotal:")?;
 
         return Ok(Host { os, cpu, mem });
 
-        fn read_field(path: &str, field: &str) -> Result<String> {
-            let text = read_file(path)?;
+        fn read_field(sh: &Shell, path: &str, field: &str) -> anyhow::Result<String> {
+            let text = sh.read_file(path)?;
 
-            let line = text
-                .lines()
-                .find(|it| it.starts_with(field))
-                .ok_or_else(|| format_err!("can't parse {}", path))?;
-            Ok(line[field.len()..].trim().to_string())
+            text.lines()
+                .find_map(|it| it.strip_prefix(field))
+                .map(|it| it.trim().to_string())
+                .ok_or_else(|| format_err!("can't parse {}", path))
         }
     }
     fn to_json(&self, mut obj: write_json::Object<'_>) {
diff --git a/xtask/src/release.rs b/xtask/src/release.rs
index acb13282f6..9bd5d9d310 100644
--- a/xtask/src/release.rs
+++ b/xtask/src/release.rs
@@ -1,15 +1,15 @@
 mod changelog;
 
-use xshell::{cmd, pushd, read_dir, read_file, write_file};
+use xshell::{cmd, Shell};
 
-use crate::{date_iso, flags, is_release_tag, project_root, Result};
+use crate::{date_iso, flags, is_release_tag, project_root};
 
 impl flags::Release {
-    pub(crate) fn run(self) -> Result<()> {
+    pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
         if !self.dry_run {
-            cmd!("git switch release").run()?;
-            cmd!("git fetch upstream --tags --force").run()?;
-            cmd!("git reset --hard tags/nightly").run()?;
+            cmd!(sh, "git switch release").run()?;
+            cmd!(sh, "git fetch upstream --tags --force").run()?;
+            cmd!(sh, "git reset --hard tags/nightly").run()?;
             // The `release` branch sometimes has a couple of cherry-picked
             // commits for patch releases. If that's the case, just overwrite
             // it. As we are setting `release` branch to an up-to-date `nightly`
@@ -19,24 +19,24 @@ impl flags::Release {
             // commits -- they'll be kept alive by the tag. More generally, we
             // don't care about historic releases all that much, it's fine even
             // to delete old tags.
-            cmd!("git push --force").run()?;
+            cmd!(sh, "git push --force").run()?;
         }
 
         // Generates bits of manual.adoc.
-        cmd!("cargo test -p ide_assists -p ide_diagnostics -p rust-analyzer -- sourcegen_")
+        cmd!(sh, "cargo test -p ide_assists -p ide_diagnostics -p rust-analyzer -- sourcegen_")
             .run()?;
 
         let website_root = project_root().join("../rust-analyzer.github.io");
         {
-            let _dir = pushd(&website_root)?;
-            cmd!("git switch src").run()?;
-            cmd!("git pull").run()?;
+            let _dir = sh.push_dir(&website_root);
+            cmd!(sh, "git switch src").run()?;
+            cmd!(sh, "git pull").run()?;
         }
         let changelog_dir = website_root.join("./thisweek/_posts");
 
-        let today = date_iso()?;
-        let commit = cmd!("git rev-parse HEAD").read()?;
-        let changelog_n = read_dir(changelog_dir.as_path())?.len();
+        let today = date_iso(sh)?;
+        let commit = cmd!(sh, "git rev-parse HEAD").read()?;
+        let changelog_n = sh.read_dir(changelog_dir.as_path())?.len();
 
         for adoc in [
             "manual.adoc",
@@ -48,42 +48,46 @@ impl flags::Release {
             let src = project_root().join("./docs/user/").join(adoc);
             let dst = website_root.join(adoc);
 
-            let contents = read_file(src)?;
-            write_file(dst, contents)?;
+            let contents = sh.read_file(src)?;
+            sh.write_file(dst, contents)?;
         }
 
-        let tags = cmd!("git tag --list").read()?;
+        let tags = cmd!(sh, "git tag --list").read()?;
         let prev_tag = tags.lines().filter(|line| is_release_tag(line)).last().unwrap();
 
-        let contents = changelog::get_changelog(changelog_n, &commit, prev_tag, &today)?;
+        let contents = changelog::get_changelog(sh, changelog_n, &commit, prev_tag, &today)?;
         let path = changelog_dir.join(format!("{}-changelog-{}.adoc", today, changelog_n));
-        write_file(&path, &contents)?;
+        sh.write_file(&path, &contents)?;
 
         Ok(())
     }
 }
 
 impl flags::Promote {
-    pub(crate) fn run(self) -> Result<()> {
-        let _dir = pushd("../rust-rust-analyzer")?;
-        cmd!("git switch master").run()?;
-        cmd!("git fetch upstream").run()?;
-        cmd!("git reset --hard upstream/master").run()?;
-        cmd!("git submodule update --recursive").run()?;
+    pub(crate) fn run(self, sh: &Shell) -> anyhow::Result<()> {
+        let _dir = sh.push_dir("../rust-rust-analyzer");
+        cmd!(sh, "git switch master").run()?;
+        cmd!(sh, "git fetch upstream").run()?;
+        cmd!(sh, "git reset --hard upstream/master").run()?;
+        cmd!(sh, "git submodule update --recursive").run()?;
 
-        let branch = format!("rust-analyzer-{}", date_iso()?);
-        cmd!("git switch -c {branch}").run()?;
+        let date = date_iso(sh)?;
+        let branch = format!("rust-analyzer-{date}");
+        cmd!(sh, "git switch -c {branch}").run()?;
         {
-            let _dir = pushd("src/tools/rust-analyzer")?;
-            cmd!("git fetch origin").run()?;
-            cmd!("git reset --hard origin/release").run()?;
+            let _dir = sh.push_dir("src/tools/rust-analyzer");
+            cmd!(sh, "git fetch origin").run()?;
+            cmd!(sh, "git reset --hard origin/release").run()?;
         }
-        cmd!("git add src/tools/rust-analyzer").run()?;
-        cmd!("git commit -m':arrow_up: rust-analyzer'").run()?;
+        cmd!(sh, "git add src/tools/rust-analyzer").run()?;
+        cmd!(sh, "git commit -m':arrow_up: rust-analyzer'").run()?;
         if !self.dry_run {
-            cmd!("git push -u origin {branch}").run()?;
-            cmd!("xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost")
-                .run()?;
+            cmd!(sh, "git push -u origin {branch}").run()?;
+            cmd!(
+                sh,
+                "xdg-open https://github.com/matklad/rust/pull/new/{branch}?body=r%3F%20%40ghost"
+            )
+            .run()?;
         }
         Ok(())
     }
diff --git a/xtask/src/release/changelog.rs b/xtask/src/release/changelog.rs
index 2384a746f3..ceef9fac2d 100644
--- a/xtask/src/release/changelog.rs
+++ b/xtask/src/release/changelog.rs
@@ -1,16 +1,17 @@
 use std::fmt::Write;
 use std::{env, iter};
 
-use anyhow::{bail, Result};
-use xshell::cmd;
+use anyhow::bail;
+use xshell::{cmd, Shell};
 
 pub(crate) fn get_changelog(
+    sh: &Shell,
     changelog_n: usize,
     commit: &str,
     prev_tag: &str,
     today: &str,
-) -> Result<String> {
-    let git_log = cmd!("git log {prev_tag}..HEAD --merges --reverse").read()?;
+) -> anyhow::Result<String> {
+    let git_log = cmd!(sh, "git log {prev_tag}..HEAD --merges --reverse").read()?;
     let mut features = String::new();
     let mut fixes = String::new();
     let mut internal = String::new();
@@ -30,14 +31,15 @@ pub(crate) fn get_changelog(
 
                 // we don't use an HTTPS client or JSON parser to keep the build times low
                 let pr_json =
-                    cmd!("curl -s -H {accept} -H {authorization} {pr_url}/{pr}").read()?;
-                let pr_title = cmd!("jq .title").stdin(&pr_json).read()?;
+                    cmd!(sh, "curl -s -H {accept} -H {authorization} {pr_url}/{pr}").read()?;
+                let pr_title = cmd!(sh, "jq .title").stdin(&pr_json).read()?;
                 let pr_title = unescape(&pr_title[1..pr_title.len() - 1]);
-                let pr_comment = cmd!("jq .body").stdin(pr_json).read()?;
+                let pr_comment = cmd!(sh, "jq .body").stdin(pr_json).read()?;
 
                 let comments_json =
-                    cmd!("curl -s -H {accept} -H {authorization} {pr_url}/{pr}/comments").read()?;
-                let pr_comments = cmd!("jq .[].body").stdin(comments_json).read()?;
+                    cmd!(sh, "curl -s -H {accept} -H {authorization} {pr_url}/{pr}/comments")
+                        .read()?;
+                let pr_comments = cmd!(sh, "jq .[].body").stdin(comments_json).read()?;
 
                 let l = iter::once(pr_comment.as_str())
                     .chain(pr_comments.lines())


Test patch:
diff --git a/crates/hir_ty/src/tests/method_resolution.rs b/crates/hir_ty/src/tests/method_resolution.rs
index 9700b388aa..c118ae24cf 100644
--- a/crates/hir_ty/src/tests/method_resolution.rs
+++ b/crates/hir_ty/src/tests/method_resolution.rs
@@ -1359,69 +1359,7 @@ impl<T> [T] {
 fn f() {
     let v = [1, 2].map::<_, usize>(|x| -> x * 2);
     v;
-  //^ [usize; 2]
-}
-    "#,
-    );
-}
-
-#[test]
-fn resolve_const_generic_method() {
-    check_types(
-        r#"
-struct Const<const N: usize>;
-
-#[lang = "array"]
-impl<T, const N: usize> [T; N] {
-    pub fn my_map<F, U, const X: usize>(self, f: F, c: Const<X>) -> [U; X]
-    where
-        F: FnMut(T) -> U,
-    { loop {} }
-}
-
-#[lang = "slice"]
-impl<T> [T] {
-    pub fn my_map<F, const X: usize, U>(self, f: F, c: Const<X>) -> &[U]
-    where
-        F: FnMut(T) -> U,
-    { loop {} }
-}
-
-fn f<const C: usize, P>() {
-    let v = [1, 2].my_map::<_, (), 12>(|x| -> x * 2, Const::<12>);
-    v;
-  //^ [(); 12]
-    let v = [1, 2].my_map::<_, P, C>(|x| -> x * 2, Const::<C>);
-    v;
-  //^ [P; C]
-}
-    "#,
-    );
-}
-
-#[test]
-fn const_generic_type_alias() {
-    check_types(
-        r#"
-struct Const<const N: usize>;
-type U2 = Const<2>;
-type U5 = Const<5>;
-
-impl U2 {
-    fn f(self) -> Const<12> {
-        loop {}
-    }
-}
-
-impl U5 {
-    fn f(self) -> Const<15> {
-        loop {}
-    }
-}
-
-fn f(x: U2) {
-    let y = x.f();
-      //^ Const<12>
+  //^ [usize; _]
 }
     "#,
     );
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index 4a65b927ba..020c5da680 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1301,7 +1301,7 @@ impl<I: Iterator> IntoIterator for I {
 
 #[test]
 fn bug_11659() {
-    check_no_mismatches(
+    check_infer(
         r#"
 struct LinkArray<const N: usize, LD>(LD);
 fn f<const N: usize, LD>(x: LD) -> LinkArray<N, LD> {
@@ -1314,8 +1314,26 @@ fn test() {
     let y = LinkArray::<52, LinkArray<2, i32>>(x);
 }
         "#,
+        expect![[r#"
+        67..68 'x': LD
+        94..138 '{     ...   r }': LinkArray<{unknown}, LD>
+        104..105 'r': LinkArray<{unknown}, LD>
+        108..126 'LinkAr...N, LD>': LinkArray<{unknown}, LD>(LD) -> LinkArray<{unknown}, LD>
+        108..129 'LinkAr...LD>(x)': LinkArray<{unknown}, LD>
+        127..128 'x': LD
+        135..136 'r': LinkArray<{unknown}, LD>
+        150..232 '{     ...(x); }': ()
+        160..161 'x': LinkArray<{unknown}, {unknown}>
+        164..175 'f::<2, i32>': fn f<i32, i32>(i32) -> LinkArray<{unknown}, {unknown}>
+        164..178 'f::<2, i32>(5)': LinkArray<{unknown}, {unknown}>
+        176..177 '5': i32
+        188..189 'y': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
+        192..226 'LinkAr... i32>>': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>(LinkArray<{unknown}, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
+        192..229 'LinkAr...2>>(x)': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
+        227..228 'x': LinkArray<{unknown}, {unknown}>
+        "#]],
     );
-    check_no_mismatches(
+    check_infer(
         r#"
 struct LinkArray<LD, const N: usize>(LD);
 fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> {
@@ -1328,106 +1346,23 @@ fn test() {
     let y = LinkArray::<LinkArray<i32, 2>, 52>(x);
 }
         "#,
+        expect![[r#"
+        67..68 'x': LD
+        94..138 '{     ...   r }': LinkArray<LD, {unknown}>
+        104..105 'r': LinkArray<LD, {unknown}>
+        108..126 'LinkAr...LD, N>': LinkArray<LD, {unknown}>(LD) -> LinkArray<LD, {unknown}>
+        108..129 'LinkAr... N>(x)': LinkArray<LD, {unknown}>
+        127..128 'x': LD
+        135..136 'r': LinkArray<LD, {unknown}>
+        150..232 '{     ...(x); }': ()
+        160..161 'x': LinkArray<i32, {unknown}>
+        164..175 'f::<i32, 2>': fn f<i32, i32>(i32) -> LinkArray<i32, {unknown}>
+        164..178 'f::<i32, 2>(5)': LinkArray<i32, {unknown}>
+        176..177 '5': i32
+        188..189 'y': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
+        192..226 'LinkAr...>, 52>': LinkArray<LinkArray<i32, {unknown}>, {unknown}>(LinkArray<i32, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, {unknown}>
+        192..229 'LinkAr...52>(x)': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
+        227..228 'x': LinkArray<i32, {unknown}>
+        "#]],
     );
 }
-
-#[test]
-fn const_generic_error_tolerance() {
-    check_no_mismatches(
-        r#"
-#[lang = "sized"]
-pub trait Sized {}
-
-struct CT<const N: usize, T>(T);
-struct TC<T, const N: usize>(T);
-fn f<const N: usize, T>(x: T) -> (CT<N, T>, TC<T, N>) {
-    let l = CT::<N, T>(x);
-    let r = TC::<N, T>(x);
-    (l, r)
-}
-
-trait TR1<const N: usize>;
-trait TR2<const N: usize>;
-
-impl<const N: usize, T> TR1<N> for CT<N, T>;
-impl<const N: usize, T> TR1<5> for TC<T, N>;
-impl<const N: usize, T> TR2<N> for CT<T, N>;
-
-trait TR3<const N: usize> {
-    fn tr3(&self) -> &Self;
-}
-
-impl<const N: usize, T> TR3<5> for TC<T, N> {
-    fn tr3(&self) -> &Self {
-        self
-    }
-}
-
-impl<const N: usize, T> TR3<Item = 5> for TC<T, N> {}
-impl<const N: usize, T> TR3<T> for TC<T, N> {}
-
-fn impl_trait<const N: usize>(inp: impl TR1<N>) {}
-fn dyn_trait<const N: usize>(inp: &dyn TR2<N>) {}
-fn impl_trait_bad<'a, const N: usize>(inp: impl TR1<i32>) -> impl TR1<'a, i32> {}
-fn impl_trait_very_bad<const N: usize>(inp: impl TR1<Item = i32>) -> impl TR1<'a, Item = i32, 5, Foo = N> {}
-
-fn test() {
-    f::<2, i32>(5);
-    f::<2, 2>(5);
-    f(5);
-    f::<i32>(5);
-    CT::<52, CT<2, i32>>(x);
-    CT::<CT<2, i32>>(x);
-    impl_trait_bad(5);
-    impl_trait_bad(12);
-    TR3<5>::tr3();
-    TR3<{ 2+3 }>::tr3();
-    TC::<i32, 10>(5).tr3();
-    TC::<i32, 20>(5).tr3();
-    TC::<i32, i32>(5).tr3();
-    TC::<i32, { 7 + 3 }>(5).tr3();
-}
-        "#,
-    );
-}
-
-#[test]
-fn const_generic_impl_trait() {
-    check_no_mismatches(
-        r#"
-        //- minicore: from
-
-        struct Foo<T, const M: usize>;
-
-        trait Tr<T> {
-            fn f(T) -> Self;
-        }
-
-        impl<T, const M: usize> Tr<[T; M]> for Foo<T, M> {
-            fn f(_: [T; M]) -> Self {
-                Self
-            }
-        }
-
-        fn test() {
-            Foo::f([1, 2, 7, 10]);
-        }
-        "#,
-    );
-}
-
-#[test]
-fn nalgebra_factorial() {
-    check_no_mismatches(
-        r#"
-        const FACTORIAL: [u128; 4] = [1, 1, 2, 6];
-
-        fn factorial(n: usize) -> u128 {
-            match FACTORIAL.get(n) {
-                Some(f) => *f,
-                None => panic!("{}! is greater than u128::MAX", n),
-            }
-        }
-        "#,
-    )
-}
diff --git a/crates/hir_ty/src/tests/simple.rs b/crates/hir_ty/src/tests/simple.rs
index 0d050f7461..c11a70fa66 100644
--- a/crates/hir_ty/src/tests/simple.rs
+++ b/crates/hir_ty/src/tests/simple.rs
@@ -1202,13 +1202,14 @@ fn infer_array() {
 
             let b = [a, ["b"]];
             let x: [u8; 0] = [];
+            // FIXME: requires const evaluation/taking type from rhs somehow
             let y: [u8; 2+2] = [1,2,3,4];
         }
         "#,
         expect![[r#"
             8..9 'x': &str
             17..18 'y': isize
-            27..326 '{     ...,4]; }': ()
+            27..395 '{     ...,4]; }': ()
             37..38 'a': [&str; 1]
             41..44 '[x]': [&str; 1]
             42..43 'x': &str
@@ -1258,12 +1259,12 @@ fn infer_array() {
             259..262 '"b"': &str
             274..275 'x': [u8; 0]
             287..289 '[]': [u8; 0]
-            299..300 'y': [u8; 4]
-            314..323 '[1,2,3,4]': [u8; 4]
-            315..316 '1': u8
-            317..318 '2': u8
-            319..320 '3': u8
-            321..322 '4': u8
+            368..369 'y': [u8; _]
+            383..392 '[1,2,3,4]': [u8; 4]
+            384..385 '1': u8
+            386..387 '2': u8
+            388..389 '3': u8
+            390..391 '4': u8
         "#]],
     );
 }
diff --git a/crates/hir_ty/src/tests/traits.rs b/crates/hir_ty/src/tests/traits.rs
index 5daffb2c5e..04d8b91e35 100644
--- a/crates/hir_ty/src/tests/traits.rs
+++ b/crates/hir_ty/src/tests/traits.rs
@@ -3394,6 +3394,7 @@ fn main() {
     )
 }
 
+// FIXME: We should infer the length of the returned array :)
 #[test]
 fn const_generics() {
     check_infer(
@@ -3417,18 +3418,18 @@ fn main() {
 "#,
         expect![[r#"
             44..48 'self': &Self
-            151..155 'self': &[u8; L]
-            173..194 '{     ...     }': [u8; L]
-            183..188 '*self': [u8; L]
-            184..188 'self': &[u8; L]
+            151..155 'self': &[u8; _]
+            173..194 '{     ...     }': [u8; _]
+            183..188 '*self': [u8; _]
+            184..188 'self': &[u8; _]
             208..260 '{     ...g(); }': ()
             218..219 'v': [u8; 2]
             222..230 '[0u8; 2]': [u8; 2]
             223..226 '0u8': u8
             228..229 '2': usize
-            240..242 'v2': [u8; 2]
+            240..242 'v2': [u8; _]
             245..246 'v': [u8; 2]
-            245..257 'v.do_thing()': [u8; 2]
+            245..257 'v.do_thing()': [u8; _]
         "#]],
     )
 }
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index 96cd83b924..df27f935c8 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -3361,27 +3361,6 @@ fn foo<T$0: Sized + ?Sized + Sized + Trait>() {}
     }
 }
 
-#[test]
-fn hover_const_generic_type_alias() {
-    check(
-        r#"
-struct Foo<const LEN: usize>;
-type Fo$0o2 = Foo<2>;
-"#,
-        expect![[r#"
-                *Foo2*
-
-                ```rust
-                test
-                ```
-
-                ```rust
-                type Foo2 = Foo<2>
-                ```
-            "#]],
-    );
-}
-
 #[test]
 fn hover_const_param() {
     check(
diff --git a/crates/ide_db/src/tests/sourcegen_lints.rs b/crates/ide_db/src/tests/sourcegen_lints.rs
index 61c05c7ffd..b7db1dd8db 100644
--- a/crates/ide_db/src/tests/sourcegen_lints.rs
+++ b/crates/ide_db/src/tests/sourcegen_lints.rs
@@ -4,16 +4,20 @@ use std::{borrow::Cow, fs, path::Path};
 use itertools::Itertools;
 use stdx::format_to;
 use test_utils::project_root;
-use xshell::cmd;
+use xshell::{cmd, Shell};
 
 /// This clones rustc repo, and so is not worth to keep up-to-date. We update
 /// manually by un-ignoring the test from time to time.
 #[test]
 #[ignore]
 fn sourcegen_lint_completions() {
+    let sh = &Shell::new().unwrap();
+
     let rust_repo = project_root().join("./target/rust");
     if !rust_repo.exists() {
-        cmd!("git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}").run().unwrap();
+        cmd!(sh, "git clone --depth=1 https://github.com/rust-lang/rust {rust_repo}")
+            .run()
+            .unwrap();
     }
 
     let mut contents = String::from(
@@ -30,16 +34,19 @@ pub struct LintGroup {
 ",
     );
 
-    generate_lint_descriptor(&mut contents);
+    generate_lint_descriptor(sh, &mut contents);
     contents.push('\n');
 
     generate_feature_descriptor(&mut contents, &rust_repo.join("src/doc/unstable-book/src"));
     contents.push('\n');
 
     let lints_json = project_root().join("./target/clippy_lints.json");
-    cmd!("curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}")
-        .run()
-        .unwrap();
+    cmd!(
+        sh,
+        "curl https://rust-lang.github.io/rust-clippy/master/lints.json --output {lints_json}"
+    )
+    .run()
+    .unwrap();
     generate_descriptor_clippy(&mut contents, &lints_json);
 
     let contents = sourcegen::add_preamble("sourcegen_lints", sourcegen::reformat(contents));
@@ -48,10 +55,10 @@ pub struct LintGroup {
     sourcegen::ensure_file_contents(destination.as_path(), &contents);
 }
 
-fn generate_lint_descriptor(buf: &mut String) {
+fn generate_lint_descriptor(sh: &Shell, buf: &mut String) {
     // FIXME: rustdoc currently requires an input file for -Whelp cc https://github.com/rust-lang/rust/pull/88831
     let file = project_root().join(file!());
-    let stdout = cmd!("rustdoc -W help {file}").read().unwrap();
+    let stdout = cmd!(sh, "rustdoc -W help {file}").read().unwrap();
     let start_lints = stdout.find("----  -------  -------").unwrap();
     let start_lint_groups = stdout.find("----  ---------").unwrap();
     let start_lints_rustdoc =
diff --git a/crates/rust-analyzer/tests/slow-tests/tidy.rs b/crates/rust-analyzer/tests/slow-tests/tidy.rs
index 2b51e7fecb..9e53aa847d 100644
--- a/crates/rust-analyzer/tests/slow-tests/tidy.rs
+++ b/crates/rust-analyzer/tests/slow-tests/tidy.rs
@@ -3,14 +3,15 @@ use std::{
     path::{Path, PathBuf},
 };
 
-use xshell::{cmd, pushd, pushenv, read_file};
+use xshell::{cmd, Shell};
 
 #[test]
 fn check_code_formatting() {
-    let _dir = pushd(sourcegen::project_root()).unwrap();
-    let _e = pushenv("RUSTUP_TOOLCHAIN", "stable");
+    let sh = &Shell::new().unwrap();
+    sh.change_dir(sourcegen::project_root());
+    sh.set_var("RUSTUP_TOOLCHAIN", "stable");
 
-    let out = cmd!("rustfmt --version").read().unwrap();
+    let out = cmd!(sh, "rustfmt --version").read().unwrap();
     if !out.contains("stable") {
         panic!(
             "Failed to run rustfmt from toolchain 'stable'. \
@@ -18,25 +19,27 @@ fn check_code_formatting() {
         )
     }
 
-    let res = cmd!("cargo fmt -- --check").run();
+    let res = cmd!(sh, "cargo fmt -- --check").run();
     if res.is_err() {
-        let _ = cmd!("cargo fmt").run();
+        let _ = cmd!(sh, "cargo fmt").run();
     }
     res.unwrap()
 }
 
 #[test]
 fn check_lsp_extensions_docs() {
+    let sh = &Shell::new().unwrap();
+
     let expected_hash = {
-        let lsp_ext_rs =
-            read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs"))
-                .unwrap();
+        let lsp_ext_rs = sh
+            .read_file(sourcegen::project_root().join("crates/rust-analyzer/src/lsp_ext.rs"))
+            .unwrap();
         stable_hash(lsp_ext_rs.as_str())
     };
 
     let actual_hash = {
         let lsp_extensions_md =
-            read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap();
+            sh.read_file(sourcegen::project_root().join("docs/dev/lsp-extensions.md")).unwrap();
         let text = lsp_extensions_md
             .lines()
             .find_map(|line| line.strip_prefix("lsp_ext.rs hash:"))
@@ -62,6 +65,8 @@ Please adjust docs/dev/lsp-extensions.md.
 
 #[test]
 fn files_are_tidy() {
+    let sh = &Shell::new().unwrap();
+
     let files = sourcegen::list_files(&sourcegen::project_root().join("crates"));
 
     let mut tidy_docs = TidyDocs::default();
@@ -70,7 +75,7 @@ fn files_are_tidy() {
         let extension = path.extension().unwrap_or_default().to_str().unwrap_or_default();
         match extension {
             "rs" => {
-                let text = read_file(&path).unwrap();
+                let text = sh.read_file(&path).unwrap();
                 check_todo(&path, &text);
                 check_dbg(&path, &text);
                 check_test_attrs(&path, &text);
@@ -80,7 +85,7 @@ fn files_are_tidy() {
                 tidy_marks.visit(&path, &text);
             }
             "toml" => {
-                let text = read_file(&path).unwrap();
+                let text = sh.read_file(&path).unwrap();
                 check_cargo_toml(&path, text);
             }
             _ => (),
@@ -139,8 +144,10 @@ fn check_cargo_toml(path: &Path, text: String) {
 
 #[test]
 fn check_merge_commits() {
-    let bors = cmd!("git rev-list --merges --author 'bors\\[bot\\]' HEAD~19..").read().unwrap();
-    let all = cmd!("git rev-list --merges HEAD~19..").read().unwrap();
+    let sh = &Shell::new().unwrap();
+
+    let bors = cmd!(sh, "git rev-list --merges --author 'bors\\[bot\\]' HEAD~19..").read().unwrap();
+    let all = cmd!(sh, "git rev-list --merges HEAD~19..").read().unwrap();
     if bors != all {
         panic!(
             "
@@ -213,6 +220,8 @@ See https://github.com/rust-lang/rust-clippy/issues/5537 for discussion.
 
 #[test]
 fn check_licenses() {
+    let sh = &Shell::new().unwrap();
+
     let expected = "
 0BSD OR MIT OR Apache-2.0
 Apache-2.0
@@ -235,7 +244,7 @@ Zlib OR Apache-2.0 OR MIT
     .filter(|it| !it.is_empty())
     .collect::<Vec<_>>();
 
-    let meta = cmd!("cargo metadata --format-version 1").read().unwrap();
+    let meta = cmd!(sh, "cargo metadata --format-version 1").read().unwrap();
     let mut licenses = meta
         .split(|c| c == ',' || c == '{' || c == '}')
         .filter(|it| it.contains(r#""license""#))