Repository: rust-analyzer/rust-analyzer
Pull request #11140 (2021-12-29 15:27:13)

Preserve order of generic args
https://github.com/rust-lang/rust/pull/90207 removed order restriction of generic args, i.e. const generics can now become before of type generics. We need to preserve this order to analyze correctly, and this PR does that.

It also simplifies implementation of const generics a bit IMO.

Implementing default generics the same problem of #7434, we need lower them to body and then evaluate them.


lnicola: @HKalbasi can you please rebase?
HKalbasi: @flodiebold Can you please review this PR? It touches too many files so it conflicts with master frequently.

Patch:
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 46e9c54dad..7e83819a4f 100644
--- a/crates/hir/src/attrs.rs
+++ b/crates/hir/src/attrs.rs
@@ -139,9 +139,9 @@ fn resolve_doc_path(
         AttrDefId::ImplId(it) => it.resolver(db.upcast()),
         AttrDefId::ExternBlockId(it) => it.resolver(db.upcast()),
         AttrDefId::GenericParamId(it) => match it {
-            GenericParamId::TypeParamId(it) => it.parent,
+            GenericParamId::TypeParamId(it) => it.parent(),
+            GenericParamId::ConstParamId(it) => it.parent(),
             GenericParamId::LifetimeParamId(it) => it.parent,
-            GenericParamId::ConstParamId(it) => it.parent,
         }
         .resolver(db.upcast()),
         // FIXME
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index 1e949771ea..d411b9d71b 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -1,7 +1,9 @@
 //! HirDisplay implementations for various hir types.
 use hir_def::{
     adt::VariantData,
-    generics::{TypeParamProvenance, WherePredicate, WherePredicateTypeTarget},
+    generics::{
+        TypeOrConstParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+    },
     type_ref::{TypeBound, TypeRef},
     AdtId, GenericDefId,
 };
@@ -16,8 +18,8 @@ use syntax::SmolStr;
 
 use crate::{
     Adt, Const, ConstParam, Enum, Field, Function, GenericParam, HasCrate, HasVisibility,
-    LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeParam, Union,
-    Variant,
+    LifetimeParam, Module, Static, Struct, Trait, TyBuilder, Type, TypeAlias, TypeOrConstParam,
+    TypeParam, Union, Variant,
 };
 
 impl HirDisplay for Function {
@@ -226,8 +228,17 @@ impl HirDisplay for GenericParam {
     fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
         match self {
             GenericParam::TypeParam(it) => it.hir_fmt(f),
-            GenericParam::LifetimeParam(it) => it.hir_fmt(f),
             GenericParam::ConstParam(it) => it.hir_fmt(f),
+            GenericParam::LifetimeParam(it) => it.hir_fmt(f),
+        }
+    }
+}
+
+impl HirDisplay for TypeOrConstParam {
+    fn hir_fmt(&self, f: &mut HirFormatter) -> Result<(), HirDisplayError> {
+        match self.split(f.db) {
+            either::Either::Left(x) => x.hir_fmt(f),
+            either::Either::Right(x) => x.hir_fmt(f),
         }
     }
 }
@@ -239,11 +250,11 @@ impl HirDisplay for TypeParam {
             return Ok(());
         }
 
-        let bounds = f.db.generic_predicates_for_param(self.id.parent, self.id, None);
-        let substs = TyBuilder::type_params_subst(f.db, self.id.parent);
+        let bounds = f.db.generic_predicates_for_param(self.id.parent(), self.id.into(), None);
+        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;
+        let krate = self.id.parent().krate(f.db).id;
         let sized_trait =
             f.db.lang_item(krate, SmolStr::new_inline("sized"))
                 .and_then(|lang_item| lang_item.as_trait());
@@ -276,11 +287,11 @@ 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.consts.is_empty()
         && params
             .types
             .iter()
-            .all(|(_, param)| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
+            .filter_map(|x| x.1.type_param())
+            .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
     {
         return Ok(());
     }
@@ -300,23 +311,27 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
         write!(f, "{}", lifetime.name)?;
     }
     for (_, ty) in params.types.iter() {
-        if ty.provenance != TypeParamProvenance::TypeParamList {
-            continue;
-        }
-        if let Some(name) = &ty.name {
-            delim(f)?;
-            write!(f, "{}", name)?;
-            if let Some(default) = &ty.default {
-                write!(f, " = ")?;
-                default.hir_fmt(f)?;
+        if let Some(name) = &ty.name() {
+            match ty {
+                TypeOrConstParamData::TypeParamData(ty) => {
+                    if ty.provenance != TypeParamProvenance::TypeParamList {
+                        continue;
+                    }
+                    delim(f)?;
+                    write!(f, "{}", name)?;
+                    if let Some(default) = &ty.default {
+                        write!(f, " = ")?;
+                        default.hir_fmt(f)?;
+                    }
+                }
+                TypeOrConstParamData::ConstParamData(c) => {
+                    delim(f)?;
+                    write!(f, "const {}: ", name)?;
+                    c.ty.hir_fmt(f)?;
+                }
             }
         }
     }
-    for (_, konst) in params.consts.iter() {
-        delim(f)?;
-        write!(f, "const {}: ", konst.name)?;
-        konst.ty.hir_fmt(f)?;
-    }
 
     write!(f, ">")?;
     Ok(())
@@ -328,7 +343,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::TypeParam(id) => params.types[*id].name.is_none(),
+        WherePredicateTypeTarget::TypeOrConstParam(id) => params.types[*id].name().is_none(),
     };
 
     let has_displayable_predicate = params
@@ -344,7 +359,7 @@ 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::TypeParam(id) => match &params.types[*id].name {
+        WherePredicateTypeTarget::TypeOrConstParam(id) => match &params.types[*id].name() {
             Some(name) => write!(f, "{}", name),
             None => write!(f, "{{unnamed}}"),
         },
diff --git a/crates/hir/src/from_id.rs b/crates/hir/src/from_id.rs
index 98c51652d9..a0b7aa3da2 100644
--- a/crates/hir/src/from_id.rs
+++ b/crates/hir/src/from_id.rs
@@ -41,9 +41,10 @@ from_id![
     (hir_def::ConstId, crate::Const),
     (hir_def::FunctionId, crate::Function),
     (hir_def::ImplId, crate::Impl),
+    (hir_def::TypeOrConstParamId, crate::TypeOrConstParam),
     (hir_def::TypeParamId, crate::TypeParam),
-    (hir_def::LifetimeParamId, crate::LifetimeParam),
     (hir_def::ConstParamId, crate::ConstParam),
+    (hir_def::LifetimeParamId, crate::LifetimeParam),
     (hir_expand::MacroDefId, crate::MacroDef)
 ];
 
@@ -71,8 +72,8 @@ impl From<GenericParamId> for GenericParam {
     fn from(id: GenericParamId) -> Self {
         match id {
             GenericParamId::TypeParamId(it) => GenericParam::TypeParam(it.into()),
-            GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()),
             GenericParamId::ConstParamId(it) => GenericParam::ConstParam(it.into()),
+            GenericParamId::LifetimeParamId(it) => GenericParam::LifetimeParam(it.into()),
         }
     }
 }
@@ -80,9 +81,9 @@ impl From<GenericParamId> for GenericParam {
 impl From<GenericParam> for GenericParamId {
     fn from(id: GenericParam) -> Self {
         match id {
-            GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id),
             GenericParam::LifetimeParam(it) => GenericParamId::LifetimeParamId(it.id),
-            GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id),
+            GenericParam::ConstParam(it) => GenericParamId::ConstParamId(it.id.into()),
+            GenericParam::TypeParam(it) => GenericParamId::TypeParamId(it.id.into()),
         }
     }
 }
diff --git a/crates/hir/src/has_source.rs b/crates/hir/src/has_source.rs
index 8669b00ca1..8683e14f2a 100644
--- a/crates/hir/src/has_source.rs
+++ b/crates/hir/src/has_source.rs
@@ -10,8 +10,8 @@ use hir_expand::InFile;
 use syntax::ast;
 
 use crate::{
-    db::HirDatabase, Adt, Const, ConstParam, Enum, Field, FieldSource, Function, Impl,
-    LifetimeParam, MacroDef, Module, Static, Struct, Trait, TypeAlias, TypeParam, Union, Variant,
+    db::HirDatabase, Adt, Const, Enum, Field, FieldSource, Function, Impl, LifetimeParam, MacroDef,
+    Module, Static, Struct, Trait, TypeAlias, TypeOrConstParam, Union, Variant,
 };
 
 pub trait HasSource {
@@ -139,8 +139,8 @@ impl HasSource for Impl {
     }
 }
 
-impl HasSource for TypeParam {
-    type Ast = Either<ast::TypeParam, ast::Trait>;
+impl HasSource for TypeOrConstParam {
+    type Ast = Either<ast::TypeOrConstParam, ast::Trait>;
     fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
         let child_source = self.id.parent.child_source(db.upcast());
         Some(child_source.map(|it| it[self.id.local_id].clone()))
@@ -154,11 +154,3 @@ impl HasSource for LifetimeParam {
         Some(child_source.map(|it| it[self.id.local_id].clone()))
     }
 }
-
-impl HasSource for ConstParam {
-    type Ast = ast::ConstParam;
-    fn source(self, db: &dyn HirDatabase) -> Option<InFile<Self::Ast>> {
-        let child_source = self.id.parent.child_source(db.upcast());
-        Some(child_source.map(|it| it[self.id.local_id].clone()))
-    }
-}
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index e02ba2e7c8..45a4c6a50e 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -50,7 +50,7 @@ use hir_def::{
     AdtId, AssocItemId, AssocItemLoc, AttrDefId, ConstId, ConstParamId, DefWithBodyId, EnumId,
     FunctionId, GenericDefId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
     LocalEnumVariantId, LocalFieldId, Lookup, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
-    TypeParamId, UnionId,
+    TypeOrConstParamId, TypeParamId, UnionId,
 };
 use hir_expand::{name::name, MacroCallKind, MacroDefId, MacroDefKind};
 use hir_ty::{
@@ -71,7 +71,7 @@ use itertools::Itertools;
 use nameres::diagnostics::DefDiagnosticKind;
 use once_cell::unsync::Lazy;
 use rustc_hash::FxHashSet;
-use stdx::{format_to, impl_from};
+use stdx::{format_to, impl_from, never};
 use syntax::{
     ast::{self, HasAttrs as _, HasDocComments, HasName},
     AstNode, AstPtr, SmolStr, SyntaxNodePtr, T,
@@ -2007,11 +2007,13 @@ impl_from!(
 impl GenericDef {
     pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
         let generics = db.generic_params(self.into());
-        let ty_params = generics
-            .types
-            .iter()
-            .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
-            .map(GenericParam::TypeParam);
+        let ty_params = generics.types.iter().map(|(local_id, _)| {
+            let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
+            match toc.split(db) {
+                Either::Left(x) => GenericParam::ConstParam(x),
+                Either::Right(x) => GenericParam::TypeParam(x),
+            }
+        });
         let lt_params = generics
             .lifetimes
             .iter()
@@ -2019,20 +2021,17 @@ impl GenericDef {
                 id: LifetimeParamId { parent: self.into(), local_id },
             })
             .map(GenericParam::LifetimeParam);
-        let const_params = generics
-            .consts
-            .iter()
-            .map(|(local_id, _)| ConstParam { id: ConstParamId { parent: self.into(), local_id } })
-            .map(GenericParam::ConstParam);
-        ty_params.chain(lt_params).chain(const_params).collect()
+        ty_params.chain(lt_params).collect()
     }
 
-    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeParam> {
+    pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
         let generics = db.generic_params(self.into());
         generics
             .types
             .iter()
-            .map(|(local_id, _)| TypeParam { id: TypeParamId { parent: self.into(), local_id } })
+            .map(|(local_id, _)| TypeOrConstParam {
+                id: TypeOrConstParamId { parent: self.into(), local_id },
+            })
             .collect()
     }
 }
@@ -2221,25 +2220,25 @@ impl Label {
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum GenericParam {
     TypeParam(TypeParam),
-    LifetimeParam(LifetimeParam),
     ConstParam(ConstParam),
+    LifetimeParam(LifetimeParam),
 }
-impl_from!(TypeParam, LifetimeParam, ConstParam for GenericParam);
+impl_from!(TypeParam, ConstParam, LifetimeParam for GenericParam);
 
 impl GenericParam {
     pub fn module(self, db: &dyn HirDatabase) -> Module {
         match self {
             GenericParam::TypeParam(it) => it.module(db),
-            GenericParam::LifetimeParam(it) => it.module(db),
             GenericParam::ConstParam(it) => it.module(db),
+            GenericParam::LifetimeParam(it) => it.module(db),
         }
     }
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         match self {
             GenericParam::TypeParam(it) => it.name(db),
-            GenericParam::LifetimeParam(it) => it.name(db),
             GenericParam::ConstParam(it) => it.name(db),
+            GenericParam::LifetimeParam(it) => it.name(db),
         }
     }
 }
@@ -2250,19 +2249,23 @@ pub struct TypeParam {
 }
 
 impl TypeParam {
+    pub fn merge(self) -> TypeOrConstParam {
+        TypeOrConstParam { id: self.id.into() }
+    }
+
     pub fn name(self, db: &dyn HirDatabase) -> Name {
-        let params = db.generic_params(self.id.parent);
-        params.types[self.id.local_id].name.clone().unwrap_or_else(Name::missing)
+        self.merge().name(db)
     }
 
     pub fn module(self, db: &dyn HirDatabase) -> Module {
-        self.id.parent.module(db.upcast()).into()
+        self.id.parent().module(db.upcast()).into()
     }
 
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
-        let resolver = self.id.parent.resolver(db.upcast());
-        let krate = self.id.parent.module(db.upcast()).krate();
-        let ty = TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id)).intern(Interner);
+        let resolver = self.id.parent().resolver(db.upcast());
+        let krate = self.id.parent().module(db.upcast()).krate();
+        let ty =
+            TyKind::Placeholder(hir_ty::to_placeholder_idx(db, self.id.into())).intern(Interner);
         Type::new_with_resolver_inner(db, krate, &resolver, ty)
     }
 
@@ -2270,7 +2273,7 @@ impl TypeParam {
     /// parameter, not additional bounds that might be added e.g. by a method if
     /// the parameter comes from an impl!
     pub fn trait_bounds(self, db: &dyn HirDatabase) -> Vec<Trait> {
-        db.generic_predicates_for_param(self.id.parent, self.id, None)
+        db.generic_predicates_for_param(self.id.parent(), self.id.into(), None)
             .iter()
             .filter_map(|pred| match &pred.skip_binders().skip_binders() {
                 hir_ty::WhereClause::Implemented(trait_ref) => {
@@ -2282,12 +2285,12 @@ impl TypeParam {
     }
 
     pub fn default(self, db: &dyn HirDatabase) -> Option<Type> {
-        let params = db.generic_defaults(self.id.parent);
-        let local_idx = hir_ty::param_idx(db, self.id)?;
-        let resolver = self.id.parent.resolver(db.upcast());
-        let krate = self.id.parent.module(db.upcast()).krate();
+        let params = db.generic_defaults(self.id.parent());
+        let local_idx = hir_ty::param_idx(db, self.id.into())?;
+        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::type_params_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));
         Some(Type::new_with_resolver_inner(db, krate, &resolver, ty))
     }
@@ -2319,9 +2322,48 @@ pub struct ConstParam {
 }
 
 impl ConstParam {
+    pub fn merge(self) -> TypeOrConstParam {
+        TypeOrConstParam { id: self.id.into() }
+    }
+
+    pub fn name(self, db: &dyn HirDatabase) -> Name {
+        let params = db.generic_params(self.id.parent());
+        match params.types[self.id.local_id()].name() {
+            Some(x) => x.clone(),
+            None => {
+                never!();
+                Name::missing()
+            }
+        }
+    }
+
+    pub fn module(self, db: &dyn HirDatabase) -> Module {
+        self.id.parent().module(db.upcast()).into()
+    }
+
+    pub fn parent(self, _db: &dyn HirDatabase) -> GenericDef {
+        self.id.parent().into()
+    }
+
+    pub fn ty(self, db: &dyn HirDatabase) -> Type {
+        let def = self.id.parent();
+        let krate = def.module(db.upcast()).krate();
+        Type::new(db, krate, def, db.const_param_ty(self.id))
+    }
+}
+
+#[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
+pub struct TypeOrConstParam {
+    pub(crate) id: TypeOrConstParamId,
+}
+
+impl TypeOrConstParam {
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let params = db.generic_params(self.id.parent);
-        params.consts[self.id.local_id].name.clone()
+        match params.types[self.id.local_id].name() {
+            Some(n) => n.clone(),
+            _ => Name::missing(),
+        }
     }
 
     pub fn module(self, db: &dyn HirDatabase) -> Module {
@@ -2332,10 +2374,23 @@ impl ConstParam {
         self.id.parent.into()
     }
 
+    pub fn split(self, db: &dyn HirDatabase) -> Either<ConstParam, TypeParam> {
+        let params = db.generic_params(self.id.parent);
+        match &params.types[self.id.local_id] {
+            hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
+                Either::Right(TypeParam { id: self.id.into() })
+            }
+            hir_def::generics::TypeOrConstParamData::ConstParamData(_) => {
+                Either::Left(ConstParam { id: self.id.into() })
+            }
+        }
+    }
+
     pub fn ty(self, db: &dyn HirDatabase) -> Type {
-        let def = self.id.parent;
-        let krate = def.module(db.upcast()).krate();
-        Type::new(db, krate, def, db.const_param_ty(self.id))
+        match self.split(db) {
+            Either::Left(x) => x.ty(db),
+            Either::Right(x) => x.ty(db),
+        }
     }
 }
 
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index dddb8e33dc..6f93f8ac94 100644
--- a/crates/hir/src/semantics/source_to_def.rs
+++ b/crates/hir/src/semantics/source_to_def.rs
@@ -282,7 +282,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()
+        dyn_map[keys::TYPE_PARAM].get(&src.value).copied().map(|x| x.into())
     }
 
     pub(super) fn lifetime_param_to_def(
@@ -300,7 +300,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()
+        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/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index ef32a5891c..c6462a2c78 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -34,7 +34,7 @@ use syntax::{
 use crate::{
     db::HirDatabase, semantics::PathResolution, Adt, BuiltinAttr, BuiltinType, Const, Field,
     Function, Local, MacroDef, ModuleDef, Static, Struct, ToolModule, Trait, Type, TypeAlias,
-    TypeParam, Variant,
+    Variant,
 };
 use base_db::CrateId;
 
@@ -609,7 +609,7 @@ fn resolve_hir_path_(
 
         let res = match ty {
             TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
-            TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
+            TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
             TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
                 PathResolution::Def(Adt::from(it).into())
             }
@@ -650,7 +650,7 @@ fn resolve_hir_path_(
                 ValueNs::StructId(it) => PathResolution::Def(Struct::from(it).into()),
                 ValueNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
                 ValueNs::ImplSelf(impl_id) => PathResolution::SelfType(impl_id.into()),
-                ValueNs::GenericParam(it) => PathResolution::ConstParam(it.into()),
+                ValueNs::GenericParam(id) => PathResolution::ConstParam(id.into()),
             };
             Some(res)
         })
@@ -703,7 +703,7 @@ fn resolve_hir_path_qualifier(
 
     resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
         TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
-        TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
+        TypeNs::GenericParam(id) => PathResolution::TypeParam(id.into()),
         TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => PathResolution::Def(Adt::from(it).into()),
         TypeNs::EnumVariantId(it) => PathResolution::Def(Variant::from(it).into()),
         TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
diff --git a/crates/hir_def/src/attr.rs b/crates/hir_def/src/attr.rs
index 3ff2d7b915..694c24a4fe 100644
--- a/crates/hir_def/src/attr.rs
+++ b/crates/hir_def/src/attr.rs
@@ -367,23 +367,36 @@ impl AttrsWithOwner {
             AttrDefId::FunctionId(it) => attrs_from_item_tree(it.lookup(db).id, db),
             AttrDefId::TypeAliasId(it) => attrs_from_item_tree(it.lookup(db).id, db),
             AttrDefId::GenericParamId(it) => match it {
+                GenericParamId::ConstParamId(it) => {
+                    let src = it.parent().child_source(db);
+                    RawAttrs::from_attrs_owner(
+                        db,
+                        src.with_value(src.value[it.local_id()].as_ref().either(
+                            |it| match it {
+                                ast::TypeOrConstParam::Type(it) => it as _,
+                                ast::TypeOrConstParam::Const(it) => it as _,
+                            },
+                            |it| it as _,
+                        )),
+                    )
+                }
                 GenericParamId::TypeParamId(it) => {
-                    let src = it.parent.child_source(db);
+                    let src = it.parent().child_source(db);
                     RawAttrs::from_attrs_owner(
                         db,
-                        src.with_value(
-                            src.value[it.local_id].as_ref().either(|it| it as _, |it| it as _),
-                        ),
+                        src.with_value(src.value[it.local_id()].as_ref().either(
+                            |it| match it {
+                                ast::TypeOrConstParam::Type(it) => it as _,
+                                ast::TypeOrConstParam::Const(it) => it as _,
+                            },
+                            |it| it as _,
+                        )),
                     )
                 }
                 GenericParamId::LifetimeParamId(it) => {
                     let src = it.parent.child_source(db);
                     RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
                 }
-                GenericParamId::ConstParamId(it) => {
-                    let src = it.parent.child_source(db);
-                    RawAttrs::from_attrs_owner(db, src.with_value(&src.value[it.local_id]))
-                }
             },
             AttrDefId::ExternBlockId(it) => attrs_from_item_tree(it.lookup(db).id, db),
         };
@@ -454,9 +467,25 @@ impl AttrsWithOwner {
             ),
             AttrDefId::ImplId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
             AttrDefId::GenericParamId(id) => match id {
+                GenericParamId::ConstParamId(id) => {
+                    id.parent().child_source(db).map(|source| match &source[id.local_id()] {
+                        Either::Left(ast::TypeOrConstParam::Type(id)) => {
+                            ast::AnyHasAttrs::new(id.clone())
+                        }
+                        Either::Left(ast::TypeOrConstParam::Const(id)) => {
+                            ast::AnyHasAttrs::new(id.clone())
+                        }
+                        Either::Right(id) => ast::AnyHasAttrs::new(id.clone()),
+                    })
+                }
                 GenericParamId::TypeParamId(id) => {
-                    id.parent.child_source(db).map(|source| match &source[id.local_id] {
-                        Either::Left(id) => ast::AnyHasAttrs::new(id.clone()),
+                    id.parent().child_source(db).map(|source| match &source[id.local_id()] {
+                        Either::Left(ast::TypeOrConstParam::Type(id)) => {
+                            ast::AnyHasAttrs::new(id.clone())
+                        }
+                        Either::Left(ast::TypeOrConstParam::Const(id)) => {
+                            ast::AnyHasAttrs::new(id.clone())
+                        }
                         Either::Right(id) => ast::AnyHasAttrs::new(id.clone()),
                     })
                 }
@@ -464,10 +493,6 @@ impl AttrsWithOwner {
                     .parent
                     .child_source(db)
                     .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
-                GenericParamId::ConstParamId(id) => id
-                    .parent
-                    .child_source(db)
-                    .map(|source| ast::AnyHasAttrs::new(source[id.local_id].clone())),
             },
             AttrDefId::ExternBlockId(id) => id.lookup(db).source(db).map(ast::AnyHasAttrs::new),
         };
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index 7febf1b5e8..b5a11a1ba5 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -9,9 +9,10 @@ use hir_expand::{
     name::{AsName, Name},
     ExpandResult, HirFileId, InFile,
 };
-use la_arena::{Arena, ArenaMap};
+use la_arena::{Arena, ArenaMap, Idx};
 use once_cell::unsync::Lazy;
 use std::ops::DerefMut;
+use stdx::impl_from;
 use syntax::ast::{self, HasGenericParams, HasName, HasTypeBounds};
 
 use crate::{
@@ -23,8 +24,8 @@ use crate::{
     keys,
     src::{HasChildSource, HasSource},
     type_ref::{LifetimeRef, TypeBound, TypeRef},
-    AdtId, ConstParamId, GenericDefId, HasModule, LifetimeParamId, LocalConstParamId,
-    LocalLifetimeParamId, LocalTypeParamId, Lookup, TypeParamId,
+    AdtId, GenericDefId, HasModule, LifetimeParamId, LocalLifetimeParamId, LocalTypeOrConstParamId,
+    Lookup, TypeOrConstParamId,
 };
 
 /// Data about a generic type parameter (to a function, struct, impl, ...).
@@ -55,12 +56,44 @@ pub enum TypeParamProvenance {
     ArgumentImplTrait,
 }
 
+#[derive(Clone, PartialEq, Eq, Debug, Hash)]
+pub enum TypeOrConstParamData {
+    TypeParamData(TypeParamData),
+    ConstParamData(ConstParamData),
+}
+
+impl TypeOrConstParamData {
+    pub fn name(&self) -> Option<&Name> {
+        match self {
+            TypeOrConstParamData::TypeParamData(x) => x.name.as_ref(),
+            TypeOrConstParamData::ConstParamData(x) => Some(&x.name),
+        }
+    }
+
+    pub fn type_param(&self) -> Option<&TypeParamData> {
+        match self {
+            TypeOrConstParamData::TypeParamData(x) => Some(&x),
+            TypeOrConstParamData::ConstParamData(_) => None,
+        }
+    }
+
+    pub fn is_trait_self(&self) -> bool {
+        match self {
+            TypeOrConstParamData::TypeParamData(x) => {
+                x.provenance == TypeParamProvenance::TraitSelf
+            }
+            TypeOrConstParamData::ConstParamData(_) => false,
+        }
+    }
+}
+
+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 types: Arena<TypeParamData>,
+    pub types: Arena<TypeOrConstParamData>,
     pub lifetimes: Arena<LifetimeParamData>,
-    pub consts: Arena<ConstParamData>,
     pub where_predicates: Vec<WherePredicate>,
 }
 
@@ -89,10 +122,18 @@ pub enum WherePredicate {
 pub enum WherePredicateTypeTarget {
     TypeRef(Interned<TypeRef>),
     /// For desugared where predicates that can directly refer to a type param.
-    TypeParam(LocalTypeParamId),
+    TypeOrConstParam(LocalTypeOrConstParamId),
 }
 
 impl GenericParams {
+    // FIXME: almost every usecase of this function is wrong. every one should check
+    // const generics
+    pub fn type_iter<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeParamData)> {
+        self.types.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
+    }
+
     pub(crate) fn generic_params_query(
         db: &dyn DefDatabase,
         def: GenericDefId,
@@ -184,19 +225,32 @@ impl GenericParams {
     }
 
     fn fill_params(&mut self, lower_ctx: &LowerCtx, params: ast::GenericParamList) {
-        for type_param in params.type_params() {
-            let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
-            // FIXME: Use `Path::from_src`
-            let default =
-                type_param.default_type().map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
-            let param = TypeParamData {
-                name: Some(name.clone()),
-                default,
-                provenance: TypeParamProvenance::TypeParamList,
-            };
-            self.types.alloc(param);
-            let type_ref = TypeRef::Path(name.into());
-            self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
+        for type_or_const_param in params.type_or_const_params() {
+            match type_or_const_param {
+                ast::TypeOrConstParam::Type(type_param) => {
+                    let name = type_param.name().map_or_else(Name::missing, |it| it.as_name());
+                    // FIXME: Use `Path::from_src`
+                    let default = type_param
+                        .default_type()
+                        .map(|it| Interned::new(TypeRef::from_ast(lower_ctx, it)));
+                    let param = TypeParamData {
+                        name: Some(name.clone()),
+                        default,
+                        provenance: TypeParamProvenance::TypeParamList,
+                    };
+                    self.types.alloc(param.into());
+                    let type_ref = TypeRef::Path(name.into());
+                    self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
+                }
+                ast::TypeOrConstParam::Const(const_param) => {
+                    let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
+                    let ty = const_param
+                        .ty()
+                        .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
+                    let param = ConstParamData { name, ty: Interned::new(ty) };
+                    self.types.alloc(param.into());
+                }
+            }
         }
         for lifetime_param in params.lifetime_params() {
             let name =
@@ -206,12 +260,6 @@ impl GenericParams {
             let lifetime_ref = LifetimeRef::new_name(name);
             self.fill_bounds(lower_ctx, &lifetime_param, Either::Right(lifetime_ref));
         }
-        for const_param in params.const_params() {
-            let name = const_param.name().map_or_else(Name::missing, |it| it.as_name());
-            let ty = const_param.ty().map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
-            let param = ConstParamData { name, ty: Interned::new(ty) };
-            self.consts.alloc(param);
-        }
     }
 
     fn fill_where_predicates(&mut self, lower_ctx: &LowerCtx, where_clause: ast::WhereClause) {
@@ -287,10 +335,10 @@ impl GenericParams {
                     default: None,
                     provenance: TypeParamProvenance::ArgumentImplTrait,
                 };
-                let param_id = self.types.alloc(param);
+                let param_id = self.types.alloc(param.into());
                 for bound in bounds {
                     self.where_predicates.push(WherePredicate::TypeBound {
-                        target: WherePredicateTypeTarget::TypeParam(param_id),
+                        target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
                         bound: bound.clone(),
                     });
                 }
@@ -311,27 +359,33 @@ impl GenericParams {
     }
 
     pub(crate) fn shrink_to_fit(&mut self) {
-        let Self { consts, lifetimes, types, where_predicates } = self;
-        consts.shrink_to_fit();
+        let Self { lifetimes, 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) -> Option<LocalTypeParamId> {
+    pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
         self.types
             .iter()
-            .find_map(|(id, p)| if p.name.as_ref() == Some(name) { Some(id) } else { None })
+            .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) -> Option<LocalConstParamId> {
-        self.consts.iter().find_map(|(id, p)| if p.name == *name { Some(id) } else { None })
+    pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
+        self.types
+            .iter()
+            .find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
     }
 
-    pub fn find_trait_self_param(&self) -> Option<LocalTypeParamId> {
+    pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
         self.types.iter().find_map(|(id, p)| {
-            if p.provenance == TypeParamProvenance::TraitSelf {
-                Some(id)
+            if let TypeOrConstParamData::TypeParamData(p) = p {
+                if p.provenance == TypeParamProvenance::TraitSelf {
+                    Some(id)
+                } else {
+                    None
+                }
             } else {
                 None
             }
@@ -377,12 +431,12 @@ fn file_id_and_params_of(
     }
 }
 
-impl HasChildSource<LocalTypeParamId> for GenericDefId {
-    type Value = Either<ast::TypeParam, ast::Trait>;
+impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
+    type Value = Either<ast::TypeOrConstParam, ast::Trait>;
     fn child_source(
         &self,
         db: &dyn DefDatabase,
-    ) -> InFile<ArenaMap<LocalTypeParamId, Self::Value>> {
+    ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
         let generic_params = db.generic_params(*self);
         let mut idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
 
@@ -398,7 +452,7 @@ impl HasChildSource<LocalTypeParamId> for GenericDefId {
         }
 
         if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.type_params()) {
+            for (idx, ast_param) in idx_iter.zip(generic_params_list.type_or_const_params()) {
                 params.insert(idx, Either::Left(ast_param));
             }
         }
@@ -430,29 +484,6 @@ impl HasChildSource<LocalLifetimeParamId> for GenericDefId {
     }
 }
 
-impl HasChildSource<LocalConstParamId> for GenericDefId {
-    type Value = ast::ConstParam;
-    fn child_source(
-        &self,
-        db: &dyn DefDatabase,
-    ) -> InFile<ArenaMap<LocalConstParamId, Self::Value>> {
-        let generic_params = db.generic_params(*self);
-        let idx_iter = generic_params.consts.iter().map(|(idx, _)| idx);
-
-        let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
-
-        let mut params = ArenaMap::default();
-
-        if let Some(generic_params_list) = generic_params_list {
-            for (idx, ast_param) in idx_iter.zip(generic_params_list.const_params()) {
-                params.insert(idx, ast_param);
-            }
-        }
-
-        InFile::new(file_id, params)
-    }
-}
-
 impl ChildBySource for GenericDefId {
     fn child_by_source_to(&self, db: &dyn DefDatabase, res: &mut DynMap, file_id: HirFileId) {
         let (gfile_id, generic_params_list) = file_id_and_params_of(*self, db);
@@ -461,28 +492,28 @@ impl ChildBySource for GenericDefId {
         }
 
         let generic_params = db.generic_params(*self);
-        let mut types_idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
+        let mut toc_idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
         let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
-        let consts_idx_iter = generic_params.consts.iter().map(|(idx, _)| idx);
 
         // For traits the first type index is `Self`, skip it.
         if let GenericDefId::TraitId(_) = *self {
-            types_idx_iter.next().unwrap(); // advance_by(1);
+            toc_idx_iter.next().unwrap(); // advance_by(1);
         }
 
         if let Some(generic_params_list) = generic_params_list {
-            for (local_id, ast_param) in types_idx_iter.zip(generic_params_list.type_params()) {
-                let id = TypeParamId { parent: *self, local_id };
-                res[keys::TYPE_PARAM].insert(ast_param, id);
+            for (local_id, ast_param) in
+                toc_idx_iter.zip(generic_params_list.type_or_const_params())
+            {
+                let id = TypeOrConstParamId { parent: *self, local_id };
+                match ast_param {
+                    ast::TypeOrConstParam::Type(a) => res[keys::TYPE_PARAM].insert(a, id),
+                    ast::TypeOrConstParam::Const(a) => res[keys::CONST_PARAM].insert(a, id),
+                }
             }
             for (local_id, ast_param) in lts_idx_iter.zip(generic_params_list.lifetime_params()) {
                 let id = LifetimeParamId { parent: *self, local_id };
                 res[keys::LIFETIME_PARAM].insert(ast_param, id);
             }
-            for (local_id, ast_param) in consts_idx_iter.zip(generic_params_list.const_params()) {
-                let id = ConstParamId { parent: *self, local_id };
-                res[keys::CONST_PARAM].insert(ast_param, id);
-            }
         }
     }
 }
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index f1b378a3be..d215ce101f 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -582,11 +582,14 @@ impl<'a> Ctx<'a> {
             }
             GenericsOwner::Trait(trait_def) => {
                 // traits get the Self type as an implicit first type parameter
-                generics.types.alloc(TypeParamData {
-                    name: Some(name![Self]),
-                    default: None,
-                    provenance: TypeParamProvenance::TraitSelf,
-                });
+                generics.types.alloc(
+                    TypeParamData {
+                        name: Some(name![Self]),
+                        default: None,
+                        provenance: TypeParamProvenance::TraitSelf,
+                    }
+                    .into(),
+                );
                 // add super traits as bounds on Self
                 // i.e., trait Foo: Bar is equivalent to trait Foo where Self: Bar
                 let self_param = TypeRef::Path(name![Self].into());
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 0df6e97dd4..5b211a142a 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -6,7 +6,7 @@ use itertools::Itertools;
 
 use crate::{
     attr::RawAttrs,
-    generics::{WherePredicate, WherePredicateTypeTarget},
+    generics::{TypeOrConstParamData, WherePredicate, WherePredicateTypeTarget},
     path::GenericArg,
     type_ref::TraitBoundModifier,
     visibility::RawVisibility,
@@ -626,7 +626,7 @@ impl<'a> Printer<'a> {
     }
 
     fn print_generic_params(&mut self, params: &GenericParams) {
-        if params.types.is_empty() && params.lifetimes.is_empty() && params.consts.is_empty() {
+        if params.types.is_empty() && params.lifetimes.is_empty() {
             return;
         }
 
@@ -639,23 +639,21 @@ impl<'a> Printer<'a> {
             first = false;
             w!(self, "{}", lt.name);
         }
-        for (idx, ty) in params.types.iter() {
+        for (idx, x) in params.types.iter() {
             if !first {
                 w!(self, ", ");
             }
             first = false;
-            match &ty.name {
-                Some(name) => w!(self, "{}", name),
-                None => w!(self, "_anon_{}", idx.into_raw()),
-            }
-        }
-        for (_, konst) in params.consts.iter() {
-            if !first {
-                w!(self, ", ");
+            match x {
+                TypeOrConstParamData::TypeParamData(ty) => match &ty.name {
+                    Some(name) => w!(self, "{}", name),
+                    None => w!(self, "_anon_{}", idx.into_raw()),
+                },
+                TypeOrConstParamData::ConstParamData(konst) => {
+                    w!(self, "const {}: ", konst.name);
+                    self.print_type_ref(&konst.ty);
+                }
             }
-            first = false;
-            w!(self, "const {}: ", konst.name);
-            self.print_type_ref(&konst.ty);
         }
         w!(self, ">");
     }
@@ -702,10 +700,12 @@ impl<'a> Printer<'a> {
 
                 match target {
                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
-                    WherePredicateTypeTarget::TypeParam(id) => match &params.types[*id].name {
-                        Some(name) => w!(this, "{}", name),
-                        None => w!(this, "_anon_{}", id.into_raw()),
-                    },
+                    WherePredicateTypeTarget::TypeOrConstParam(id) => {
+                        match &params.types[*id].name() {
+                            Some(name) => w!(this, "{}", name),
+                            None => w!(this, "_anon_{}", id.into_raw()),
+                        }
+                    }
                 }
                 w!(this, ": ");
                 this.print_type_bounds(std::slice::from_ref(bound));
diff --git a/crates/hir_def/src/keys.rs b/crates/hir_def/src/keys.rs
index 8cd2d77172..5f21914305 100644
--- a/crates/hir_def/src/keys.rs
+++ b/crates/hir_def/src/keys.rs
@@ -9,8 +9,8 @@ use syntax::{ast, AstNode, AstPtr};
 use crate::{
     attr::AttrId,
     dyn_map::{DynMap, Policy},
-    ConstId, ConstParamId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId,
-    StaticId, StructId, TraitId, TypeAliasId, TypeParamId, UnionId,
+    ConstId, EnumId, EnumVariantId, FieldId, FunctionId, ImplId, LifetimeParamId, StaticId,
+    StructId, TraitId, TypeAliasId, TypeOrConstParamId, UnionId,
 };
 
 pub type Key<K, V> = crate::dyn_map::Key<K, V, AstPtrPolicy<K, V>>;
@@ -28,9 +28,9 @@ pub const ENUM: Key<ast::Enum, EnumId> = Key::new();
 pub const VARIANT: Key<ast::Variant, EnumVariantId> = Key::new();
 pub const TUPLE_FIELD: Key<ast::TupleField, FieldId> = Key::new();
 pub const RECORD_FIELD: Key<ast::RecordField, FieldId> = Key::new();
-pub const TYPE_PARAM: Key<ast::TypeParam, TypeParamId> = Key::new();
+pub const TYPE_PARAM: Key<ast::TypeParam, TypeOrConstParamId> = Key::new();
+pub const CONST_PARAM: Key<ast::ConstParam, TypeOrConstParamId> = Key::new();
 pub const LIFETIME_PARAM: Key<ast::LifetimeParam, LifetimeParamId> = Key::new();
-pub const CONST_PARAM: Key<ast::ConstParam, ConstParamId> = Key::new();
 
 pub const MACRO: Key<ast::Macro, MacroDefId> = Key::new();
 pub const ATTR_MACRO_CALL: Key<ast::Item, MacroCallId> = Key::new();
diff --git a/crates/hir_def/src/lib.rs b/crates/hir_def/src/lib.rs
index bb65d1dec8..21096166d7 100644
--- a/crates/hir_def/src/lib.rs
+++ b/crates/hir_def/src/lib.rs
@@ -279,26 +279,67 @@ pub struct BlockLoc {
 impl_intern!(BlockId, BlockLoc, intern_block, lookup_intern_block);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct TypeParamId {
+pub struct TypeOrConstParamId {
     pub parent: GenericDefId,
-    pub local_id: LocalTypeParamId,
+    pub local_id: LocalTypeOrConstParamId,
 }
 
-pub type LocalTypeParamId = Idx<generics::TypeParamData>;
+#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
+/// A TypeOrConstParamId with an invariant that it actually belongs to a type
+pub struct TypeParamId(TypeOrConstParamId);
+
+impl TypeParamId {
+    pub fn parent(&self) -> GenericDefId {
+        self.0.parent
+    }
+    pub fn local_id(&self) -> LocalTypeOrConstParamId {
+        self.0.local_id
+    }
+}
+
+impl From<TypeOrConstParamId> for TypeParamId {
+    fn from(x: TypeOrConstParamId) -> Self {
+        Self(x)
+    }
+}
+impl From<TypeParamId> for TypeOrConstParamId {
+    fn from(x: TypeParamId) -> Self {
+        x.0
+    }
+}
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct LifetimeParamId {
-    pub parent: GenericDefId,
-    pub local_id: LocalLifetimeParamId,
+/// A TypeOrConstParamId with an invariant that it actually belongs to a const
+pub struct ConstParamId(TypeOrConstParamId);
+
+impl ConstParamId {
+    pub fn parent(&self) -> GenericDefId {
+        self.0.parent
+    }
+    pub fn local_id(&self) -> LocalTypeOrConstParamId {
+        self.0.local_id
+    }
 }
-pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
+
+impl From<TypeOrConstParamId> for ConstParamId {
+    fn from(x: TypeOrConstParamId) -> Self {
+        Self(x)
+    }
+}
+impl From<ConstParamId> for TypeOrConstParamId {
+    fn from(x: ConstParamId) -> Self {
+        x.0
+    }
+}
+
+pub type LocalTypeOrConstParamId = Idx<generics::TypeOrConstParamData>;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct ConstParamId {
+pub struct LifetimeParamId {
     pub parent: GenericDefId,
-    pub local_id: LocalConstParamId,
+    pub local_id: LocalLifetimeParamId,
 }
-pub type LocalConstParamId = Idx<generics::ConstParamData>;
+pub type LocalLifetimeParamId = Idx<generics::LifetimeParamData>;
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub enum ItemContainerId {
@@ -322,8 +363,8 @@ impl_from!(StructId, UnionId, EnumId for AdtId);
 #[derive(Clone, Copy, Debug, PartialEq, Eq, Hash)]
 pub enum GenericParamId {
     TypeParamId(TypeParamId),
-    LifetimeParamId(LifetimeParamId),
     ConstParamId(ConstParamId),
+    LifetimeParamId(LifetimeParamId),
 }
 impl_from!(TypeParamId, LifetimeParamId, ConstParamId for GenericParamId);
 
@@ -632,9 +673,9 @@ impl AttrDefId {
             AttrDefId::ExternBlockId(it) => it.lookup(db).container.krate,
             AttrDefId::GenericParamId(it) => {
                 match it {
-                    GenericParamId::TypeParamId(it) => it.parent,
+                    GenericParamId::TypeParamId(it) => it.parent(),
+                    GenericParamId::ConstParamId(it) => it.parent(),
                     GenericParamId::LifetimeParamId(it) => it.parent,
-                    GenericParamId::ConstParamId(it) => it.parent,
                 }
                 .module(db)
                 .krate
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 9f68b800a5..d5e62f226a 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -15,7 +15,7 @@ use crate::{
     builtin_type::BuiltinType,
     db::DefDatabase,
     expr::{ExprId, LabelId, PatId},
-    generics::GenericParams,
+    generics::{GenericParams, TypeOrConstParamData},
     intern::Interned,
     item_scope::{BuiltinShadowMode, BUILTIN_SCOPE},
     nameres::DefMap,
@@ -25,7 +25,7 @@ use crate::{
     AdtId, AssocItemId, ConstId, ConstParamId, DefWithBodyId, EnumId, EnumVariantId, ExternBlockId,
     FunctionId, GenericDefId, GenericParamId, HasModule, ImplId, ItemContainerId, LifetimeParamId,
     LocalModuleId, Lookup, ModuleDefId, ModuleId, StaticId, StructId, TraitId, TypeAliasId,
-    TypeParamId, VariantId,
+    TypeOrConstParamId, TypeParamId, VariantId,
 };
 
 #[derive(Debug, Clone, Default)]
@@ -195,7 +195,9 @@ impl Resolver {
                     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(TypeParamId { local_id, parent: *def }),
+                            TypeNs::GenericParam(
+                                TypeOrConstParamId { local_id, parent: *def }.into(),
+                            ),
                             idx,
                         ));
                     }
@@ -285,14 +287,18 @@ impl Resolver {
                 Scope::ExprScope(_) => continue,
 
                 Scope::GenericParams { params, def } if n_segments > 1 => {
-                    if let Some(local_id) = params.find_type_by_name(first_name) {
-                        let ty = TypeNs::GenericParam(TypeParamId { local_id, parent: *def });
+                    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(local_id) = params.find_const_by_name(first_name) {
-                        let val = ValueNs::GenericParam(ConstParamId { local_id, parent: *def });
+                    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));
                     }
                 }
@@ -521,15 +527,22 @@ impl Scope {
             Scope::GenericParams { params, def: parent } => {
                 let parent = *parent;
                 for (local_id, param) in params.types.iter() {
-                    if let Some(name) = &param.name {
-                        let id = TypeParamId { parent, local_id };
-                        acc.add(name, ScopeDef::GenericParam(id.into()))
+                    if let Some(name) = &param.name() {
+                        let id = TypeOrConstParamId { parent, local_id };
+                        let data = &db.generic_params(parent).types[local_id];
+                        acc.add(
+                            name,
+                            ScopeDef::GenericParam(match data {
+                                TypeOrConstParamData::TypeParamData(_) => {
+                                    GenericParamId::TypeParamId(id.into())
+                                }
+                                TypeOrConstParamData::ConstParamData(_) => {
+                                    GenericParamId::ConstParamId(id.into())
+                                }
+                            }),
+                        );
                     }
                 }
-                for (local_id, param) in params.consts.iter() {
-                    let id = ConstParamId { parent, local_id };
-                    acc.add(&param.name, ScopeDef::GenericParam(id.into()))
-                }
                 for (local_id, param) in params.lifetimes.iter() {
                     let id = LifetimeParamId { parent, local_id };
                     acc.add(&param.name, ScopeDef::GenericParam(id.into()))
diff --git a/crates/hir_expand/src/builtin_derive_macro.rs b/crates/hir_expand/src/builtin_derive_macro.rs
index dd7d249efa..d56cd99269 100644
--- a/crates/hir_expand/src/builtin_derive_macro.rs
+++ b/crates/hir_expand/src/builtin_derive_macro.rs
@@ -71,7 +71,7 @@ pub fn find_builtin_derive(
 
 struct BasicAdtInfo {
     name: tt::Ident,
-    type_params: usize,
+    type_or_const_params: usize,
 }
 
 fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
@@ -104,8 +104,9 @@ fn parse_adt(tt: &tt::Subtree) -> Result<BasicAdtInfo, ExpandError> {
         .token_by_range(name.syntax().text_range())
         .unwrap_or_else(|| TokenId::unspecified());
     let name_token = tt::Ident { id: name_token_id, text: name.text().into() };
-    let type_params = params.map_or(0, |type_param_list| type_param_list.type_params().count());
-    Ok(BasicAdtInfo { name: name_token, type_params })
+    let type_or_const_params =
+        params.map_or(0, |type_param_list| type_param_list.type_or_const_params().count());
+    Ok(BasicAdtInfo { name: name_token, type_or_const_params })
 }
 
 fn make_type_args(n: usize, bound: Vec<tt::TokenTree>) -> Vec<tt::TokenTree> {
@@ -157,8 +158,8 @@ fn expand_simple_derive(tt: &tt::Subtree, trait_path: tt::Subtree) -> ExpandResu
     let name = info.name;
     let trait_path_clone = trait_path.token_trees.clone();
     let bound = (quote! { : ##trait_path_clone }).token_trees;
-    let type_params = make_type_args(info.type_params, bound);
-    let type_args = make_type_args(info.type_params, Vec::new());
+    let type_params = make_type_args(info.type_or_const_params, bound);
+    let type_args = make_type_args(info.type_or_const_params, Vec::new());
     let trait_path = trait_path.token_trees;
     let expanded = quote! {
         impl ##type_params ##trait_path for #name ##type_args {}
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index bd5aab1b3d..d34257f118 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -3,6 +3,7 @@
 use chalk_ir::{FloatTy, IntTy, Mutability, Scalar, UintTy};
 use hir_def::{
     builtin_type::{BuiltinFloat, BuiltinInt, BuiltinType, BuiltinUint},
+    generics::TypeOrConstParamData,
     type_ref::Rawness,
     FunctionId, GenericDefId, HasModule, ItemContainerId, Lookup, TraitId,
 };
@@ -237,27 +238,30 @@ impl TyExt for Ty {
                 let id = from_placeholder_idx(db, *idx);
                 let generic_params = db.generic_params(id.parent);
                 let param_data = &generic_params.types[id.local_id];
-                match param_data.provenance {
-                    hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
-                        let substs = TyBuilder::type_params_subst(db, id.parent);
-                        let predicates = db
-                            .generic_predicates(id.parent)
-                            .iter()
-                            .map(|pred| pred.clone().substitute(Interner, &substs))
-                            .filter(|wc| match &wc.skip_binders() {
-                                WhereClause::Implemented(tr) => {
-                                    &tr.self_type_parameter(Interner) == self
-                                }
-                                WhereClause::AliasEq(AliasEq {
-                                    alias: AliasTy::Projection(proj),
-                                    ty: _,
-                                }) => &proj.self_type_parameter(Interner) == self,
-                                _ => false,
-                            })
-                            .collect::<Vec<_>>();
-
-                        Some(predicates)
-                    }
+                match param_data {
+                    TypeOrConstParamData::TypeParamData(p) => match p.provenance {
+                        hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
+                            let substs = TyBuilder::type_params_subst(db, id.parent);
+                            let predicates = db
+                                .generic_predicates(id.parent)
+                                .iter()
+                                .map(|pred| pred.clone().substitute(Interner, &substs))
+                                .filter(|wc| match &wc.skip_binders() {
+                                    WhereClause::Implemented(tr) => {
+                                        &tr.self_type_parameter(Interner) == self
+                                    }
+                                    WhereClause::AliasEq(AliasEq {
+                                        alias: AliasTy::Projection(proj),
+                                        ty: _,
+                                    }) => &proj.self_type_parameter(Interner) == self,
+                                    _ => false,
+                                })
+                                .collect::<Vec<_>>();
+
+                            Some(predicates)
+                        }
+                        _ => None,
+                    },
                     _ => None,
                 }
             }
diff --git a/crates/hir_ty/src/db.rs b/crates/hir_ty/src/db.rs
index c3b9255baf..e144dd43f4 100644
--- a/crates/hir_ty/src/db.rs
+++ b/crates/hir_ty/src/db.rs
@@ -6,7 +6,7 @@ use std::sync::Arc;
 use base_db::{impl_intern_key, salsa, CrateId, Upcast};
 use hir_def::{
     db::DefDatabase, expr::ExprId, BlockId, ConstParamId, DefWithBodyId, FunctionId, GenericDefId,
-    ImplId, LifetimeParamId, LocalFieldId, TypeParamId, VariantId,
+    ImplId, LifetimeParamId, LocalFieldId, TypeOrConstParamId, VariantId,
 };
 use la_arena::ArenaMap;
 
@@ -61,7 +61,7 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     fn generic_predicates_for_param(
         &self,
         def: GenericDefId,
-        param_id: TypeParamId,
+        param_id: TypeOrConstParamId,
         assoc_name: Option<Name>,
     ) -> Arc<[Binders<QuantifiedWhereClause>]>;
 
@@ -94,12 +94,13 @@ pub trait HirDatabase: DefDatabase + Upcast<dyn DefDatabase> {
     #[salsa::interned]
     fn intern_callable_def(&self, callable_def: CallableDefId) -> InternedCallableDefId;
     #[salsa::interned]
-    fn intern_type_param_id(&self, param_id: TypeParamId) -> InternedTypeParamId;
+    fn intern_type_or_const_param_id(
+        &self,
+        param_id: TypeOrConstParamId,
+    ) -> InternedTypeOrConstParamId;
     #[salsa::interned]
     fn intern_lifetime_param_id(&self, param_id: LifetimeParamId) -> InternedLifetimeParamId;
     #[salsa::interned]
-    fn intern_const_param_id(&self, param_id: ConstParamId) -> InternedConstParamId;
-    #[salsa::interned]
     fn intern_impl_trait_id(&self, id: ImplTraitId) -> InternedOpaqueTyId;
     #[salsa::interned]
     fn intern_closure(&self, id: (DefWithBodyId, ExprId)) -> InternedClosureId;
@@ -186,8 +187,8 @@ fn hir_database_is_object_safe() {
 }
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
-pub struct InternedTypeParamId(salsa::InternId);
-impl_intern_key!(InternedTypeParamId);
+pub struct InternedTypeOrConstParamId(salsa::InternId);
+impl_intern_key!(InternedTypeOrConstParamId);
 
 #[derive(Debug, Clone, Copy, PartialEq, Eq, Hash)]
 pub struct InternedLifetimeParamId(salsa::InternId);
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index 2020834fbc..a2644e74b8 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -10,7 +10,7 @@ use hir_def::{
     body,
     db::DefDatabase,
     find_path,
-    generics::TypeParamProvenance,
+    generics::{TypeOrConstParamData, TypeParamProvenance},
     intern::{Internable, Interned},
     item_scope::ItemInNs,
     path::{Path, PathKind},
@@ -23,7 +23,6 @@ use itertools::Itertools;
 use syntax::SmolStr;
 
 use crate::{
-    const_from_placeholder_idx,
     db::HirDatabase,
     from_assoc_type_id, from_foreign_def_id, from_placeholder_idx, lt_from_placeholder_idx,
     mapping::from_chalk,
@@ -319,10 +318,10 @@ impl HirDisplay for Const {
             ConstValue::BoundVar(idx) => idx.hir_fmt(f),
             ConstValue::InferenceVar(..) => write!(f, "_"),
             ConstValue::Placeholder(idx) => {
-                let id = const_from_placeholder_idx(f.db, idx);
+                let id = from_placeholder_idx(f.db, idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params.consts[id.local_id];
-                write!(f, "{}", param_data.name)
+                let param_data = &generics.params.types[id.local_id];
+                write!(f, "{}", param_data.name().unwrap())
             }
             ConstValue::Concrete(c) => write!(f, "{}", c.interned),
         }
@@ -682,34 +681,39 @@ impl HirDisplay for Ty {
                 let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
                 let param_data = &generics.params.types[id.local_id];
-                match param_data.provenance {
-                    TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
-                        write!(f, "{}", param_data.name.clone().unwrap_or_else(Name::missing))?
-                    }
-                    TypeParamProvenance::ArgumentImplTrait => {
-                        let substs = generics.type_params_subst(f.db);
-                        let bounds =
-                            f.db.generic_predicates(id.parent)
-                                .iter()
-                                .map(|pred| pred.clone().substitute(Interner, &substs))
-                                .filter(|wc| match &wc.skip_binders() {
-                                    WhereClause::Implemented(tr) => {
-                                        &tr.self_type_parameter(Interner) == self
-                                    }
-                                    WhereClause::AliasEq(AliasEq {
-                                        alias: AliasTy::Projection(proj),
-                                        ty: _,
-                                    }) => &proj.self_type_parameter(Interner) == self,
-                                    _ => false,
-                                })
-                                .collect::<Vec<_>>();
-                        let krate = id.parent.module(f.db.upcast()).krate();
-                        write_bounds_like_dyn_trait_with_prefix(
-                            "impl",
-                            &bounds,
-                            SizedByDefault::Sized { anchor: krate },
-                            f,
-                        )?;
+                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.type_params_subst(f.db);
+                            let bounds =
+                                f.db.generic_predicates(id.parent)
+                                    .iter()
+                                    .map(|pred| pred.clone().substitute(Interner, &substs))
+                                    .filter(|wc| match &wc.skip_binders() {
+                                        WhereClause::Implemented(tr) => {
+                                            &tr.self_type_parameter(Interner) == self
+                                        }
+                                        WhereClause::AliasEq(AliasEq {
+                                            alias: AliasTy::Projection(proj),
+                                            ty: _,
+                                        }) => &proj.self_type_parameter(Interner) == self,
+                                        _ => false,
+                                    })
+                                    .collect::<Vec<_>>();
+                            let krate = id.parent.module(f.db.upcast()).krate();
+                            write_bounds_like_dyn_trait_with_prefix(
+                                "impl",
+                                &bounds,
+                                SizedByDefault::Sized { anchor: krate },
+                                f,
+                            )?;
+                        }
+                    },
+                    TypeOrConstParamData::ConstParamData(p) => {
+                        write!(f, "{}", p.name)?;
                     }
                 }
             }
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index ad54b72b4b..c52dd3e8ed 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -10,6 +10,7 @@ use std::{
 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,
     FieldId, FunctionId, ItemContainerId, Lookup,
@@ -1037,8 +1038,15 @@ impl<'a> InferenceContext<'a> {
         let total_len = parent_params + type_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
         // Parent arguments are unknown
-        for _ in def_generics.iter_parent() {
-            substs.push(self.table.new_type_var());
+        for (_id, param) in def_generics.iter_parent() {
+            match param {
+                TypeOrConstParamData::TypeParamData(_) => {
+                    substs.push(self.table.new_type_var());
+                }
+                TypeOrConstParamData::ConstParamData(_) => {
+                    // FIXME: here we should do something
+                }
+            }
         }
         // handle provided type arguments
         if let Some(generic_args) = generic_args {
diff --git a/crates/hir_ty/src/lib.rs b/crates/hir_ty/src/lib.rs
index f1280fcc10..b57ad62068 100644
--- a/crates/hir_ty/src/lib.rs
+++ b/crates/hir_ty/src/lib.rs
@@ -40,7 +40,7 @@ use chalk_ir::{
 use hir_def::{
     expr::ExprId,
     type_ref::{ConstScalar, Rawness},
-    TypeParamId,
+    TypeOrConstParamId,
 };
 
 use crate::{db::HirDatabase, utils::generics};
@@ -55,9 +55,9 @@ pub use lower::{
     TyDefId, TyLoweringContext, ValueTyDefId,
 };
 pub use mapping::{
-    const_from_placeholder_idx, from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id,
-    from_placeholder_idx, lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id,
-    to_foreign_def_id, to_placeholder_idx,
+    from_assoc_type_id, from_chalk_trait_id, from_foreign_def_id, from_placeholder_idx,
+    lt_from_placeholder_idx, to_assoc_type_id, to_chalk_trait_id, to_foreign_def_id,
+    to_placeholder_idx,
 };
 pub use traits::TraitEnvironment;
 pub use utils::all_super_traits;
@@ -129,7 +129,7 @@ pub fn subst_prefix(s: &Substitution, n: usize) -> Substitution {
 }
 
 /// Return an index of a parameter in the generic type parameter list by it's id.
-pub fn param_idx(db: &dyn HirDatabase, id: TypeParamId) -> Option<usize> {
+pub fn param_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> Option<usize> {
     generics(db.upcast(), id.parent).param_idx(id)
 }
 
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index a140dd4057..3147b6f330 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -10,6 +10,7 @@ use std::{iter, sync::Arc};
 
 use base_db::CrateId;
 use chalk_ir::{cast::Cast, fold::Shift, interner::HasInterner, Mutability, Safety};
+use hir_def::generics::TypeOrConstParamData;
 use hir_def::intern::Interned;
 use hir_def::{
     adt::StructKind,
@@ -19,15 +20,16 @@ use hir_def::{
     path::{GenericArg, Path, PathSegment, PathSegments},
     resolver::{HasResolver, Resolver, TypeNs},
     type_ref::{TraitBoundModifier, TraitRef as HirTraitRef, TypeBound, TypeRef},
-    AdtId, AssocItemId, ConstId, ConstParamId, EnumId, EnumVariantId, FunctionId, GenericDefId,
-    HasModule, ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId,
-    TypeAliasId, TypeParamId, UnionId, VariantId,
+    AdtId, AssocItemId, ConstId, EnumId, EnumVariantId, FunctionId, GenericDefId, HasModule,
+    ImplId, ItemContainerId, LocalFieldId, Lookup, StaticId, StructId, TraitId, TypeAliasId,
+    UnionId, VariantId,
 };
+use hir_def::{ConstParamId, TypeOrConstParamId};
 use hir_expand::{name::Name, ExpandResult};
 use la_arena::ArenaMap;
 use rustc_hash::FxHashSet;
 use smallvec::SmallVec;
-use stdx::impl_from;
+use stdx::{impl_from, never};
 use syntax::{ast, SmolStr};
 
 use crate::all_super_traits;
@@ -267,7 +269,7 @@ impl<'a> TyLoweringContext<'a> {
                         if let Some(def) = self.resolver.generic_def() {
                             let generics = generics(self.db.upcast(), def);
                             let param = generics
-                                .iter()
+                                .type_iter()
                                 .filter(|(_, data)| {
                                     data.provenance == TypeParamProvenance::ArgumentImplTrait
                                 })
@@ -353,7 +355,7 @@ impl<'a> TyLoweringContext<'a> {
     /// This is only for `generic_predicates_for_param`, where we can't just
     /// lower the self types of the predicates since that could lead to cycles.
     /// So we just check here if the `type_ref` resolves to a generic param, and which.
-    fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeParamId> {
+    fn lower_ty_only_param(&self, type_ref: &TypeRef) -> Option<TypeOrConstParamId> {
         let path = match type_ref {
             TypeRef::Path(path) => path,
             _ => return None,
@@ -370,7 +372,7 @@ impl<'a> TyLoweringContext<'a> {
                 _ => return None,
             };
         match resolution {
-            TypeNs::GenericParam(param_id) => Some(param_id),
+            TypeNs::GenericParam(param_id) => Some(param_id.into()),
             _ => None,
         }
     }
@@ -469,10 +471,10 @@ impl<'a> TyLoweringContext<'a> {
                 );
                 match self.type_param_mode {
                     TypeParamLoweringMode::Placeholder => {
-                        TyKind::Placeholder(to_placeholder_idx(self.db, param_id))
+                        TyKind::Placeholder(to_placeholder_idx(self.db, param_id.into()))
                     }
                     TypeParamLoweringMode::Variable => {
-                        let idx = generics.param_idx(param_id).expect("matching generics");
+                        let idx = generics.param_idx(param_id.into()).expect("matching generics");
                         TyKind::BoundVar(BoundVar::new(self.in_binders, idx))
                     }
                 }
@@ -758,11 +760,13 @@ impl<'a> TyLoweringContext<'a> {
             | WherePredicate::TypeBound { target, bound } => {
                 let self_ty = match target {
                     WherePredicateTypeTarget::TypeRef(type_ref) => self.lower_ty(type_ref),
-                    WherePredicateTypeTarget::TypeParam(param_id) => {
+                    WherePredicateTypeTarget::TypeOrConstParam(param_id) => {
                         let generic_def = self.resolver.generic_def().expect("generics in scope");
                         let generics = generics(self.db.upcast(), generic_def);
-                        let param_id =
-                            hir_def::TypeParamId { parent: generic_def, local_id: *param_id };
+                        let param_id = hir_def::TypeOrConstParamId {
+                            parent: generic_def,
+                            local_id: *param_id,
+                        };
                         let placeholder = to_placeholder_idx(self.db, param_id);
                         match self.type_param_mode {
                             TypeParamLoweringMode::Placeholder => TyKind::Placeholder(placeholder),
@@ -973,7 +977,7 @@ fn named_associated_type_shorthand_candidates<R>(
             db.impl_trait(impl_id)?.into_value_and_skipped_binders().0,
         ),
         TypeNs::GenericParam(param_id) => {
-            let predicates = db.generic_predicates_for_param(def, param_id, assoc_name);
+            let predicates = db.generic_predicates_for_param(def, param_id.into(), assoc_name);
             let res = predicates.iter().find_map(|pred| match pred.skip_binders().skip_binders() {
                 // FIXME: how to correctly handle higher-ranked bounds here?
                 WhereClause::Implemented(tr) => search(
@@ -987,11 +991,9 @@ fn named_associated_type_shorthand_candidates<R>(
                 return res;
             }
             // Handle `Self::Type` referring to own associated type in trait definitions
-            if let GenericDefId::TraitId(trait_id) = param_id.parent {
+            if let GenericDefId::TraitId(trait_id) = param_id.parent() {
                 let generics = generics(db.upcast(), trait_id.into());
-                if generics.params.types[param_id.local_id].provenance
-                    == TypeParamProvenance::TraitSelf
-                {
+                if generics.params.types[param_id.local_id()].is_trait_self() {
                     let trait_ref = TyBuilder::trait_ref(db, trait_id)
                         .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
                         .build();
@@ -1036,7 +1038,7 @@ pub(crate) fn field_types_query(
 pub(crate) fn generic_predicates_for_param_query(
     db: &dyn HirDatabase,
     def: GenericDefId,
-    param_id: TypeParamId,
+    param_id: TypeOrConstParamId,
     assoc_name: Option<Name>,
 ) -> Arc<[Binders<QuantifiedWhereClause>]> {
     let resolver = def.resolver(db.upcast());
@@ -1051,11 +1053,11 @@ pub(crate) fn generic_predicates_for_param_query(
             | WherePredicate::TypeBound { target, bound, .. } => {
                 match target {
                     WherePredicateTypeTarget::TypeRef(type_ref) => {
-                        if ctx.lower_ty_only_param(type_ref) != Some(param_id) {
+                        if ctx.lower_ty_only_param(type_ref) != Some(param_id.into()) {
                             return false;
                         }
                     }
-                    WherePredicateTypeTarget::TypeParam(local_id) => {
+                    WherePredicateTypeTarget::TypeOrConstParam(local_id) => {
                         if *local_id != param_id.local_id {
                             return false;
                         }
@@ -1105,7 +1107,7 @@ pub(crate) fn generic_predicates_for_param_recover(
     _db: &dyn HirDatabase,
     _cycle: &[String],
     _def: &GenericDefId,
-    _param_id: &TypeParamId,
+    _param_id: &TypeOrConstParamId,
     _assoc_name: &Option<Name>,
 ) -> Arc<[Binders<QuantifiedWhereClause>]> {
     Arc::new([])
@@ -1233,7 +1235,7 @@ pub(crate) fn generic_defaults_query(
     let generic_params = generics(db.upcast(), def);
 
     let defaults = generic_params
-        .iter()
+        .type_iter()
         .enumerate()
         .map(|(idx, (_, p))| {
             let mut ty =
@@ -1267,7 +1269,7 @@ pub(crate) fn generic_defaults_recover(
 
     // we still need one default per parameter
     let defaults = generic_params
-        .iter()
+        .type_iter()
         .enumerate()
         .map(|(idx, _)| {
             let ty = TyKind::Error.intern(Interner);
@@ -1497,13 +1499,19 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
     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.consts[def.local_id];
-    let resolver = def.parent.resolver(db.upcast());
+    let parent_data = db.generic_params(def.parent());
+    let data = &parent_data.types[def.local_id()];
+    let resolver = def.parent().resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver);
-
-    ctx.lower_ty(&data.ty)
+    match data {
+        TypeOrConstParamData::TypeParamData(_) => {
+            never!();
+            Ty::new(Interner, TyKind::Error)
+        }
+        TypeOrConstParamData::ConstParamData(d) => ctx.lower_ty(&d.ty),
+    }
 }
 
 pub(crate) fn impl_self_ty_recover(
diff --git a/crates/hir_ty/src/mapping.rs b/crates/hir_ty/src/mapping.rs
index 5e86fafe5d..d765fee0e1 100644
--- a/crates/hir_ty/src/mapping.rs
+++ b/crates/hir_ty/src/mapping.rs
@@ -6,7 +6,7 @@
 use chalk_solve::rust_ir;
 
 use base_db::salsa::{self, InternKey};
-use hir_def::{ConstParamId, LifetimeParamId, TraitId, TypeAliasId, TypeParamId};
+use hir_def::{LifetimeParamId, TraitId, TypeAliasId, TypeOrConstParamId};
 
 use crate::{
     chalk_db, db::HirDatabase, AssocTypeId, CallableDefId, ChalkTraitId, FnDefId, ForeignDefId,
@@ -119,14 +119,14 @@ pub fn from_assoc_type_id(id: AssocTypeId) -> TypeAliasId {
     salsa::InternKey::from_intern_id(id.0)
 }
 
-pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeParamId {
+pub fn from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> TypeOrConstParamId {
     assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
     let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
-    db.lookup_intern_type_param_id(interned_id)
+    db.lookup_intern_type_or_const_param_id(interned_id)
 }
 
-pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeParamId) -> PlaceholderIndex {
-    let interned_id = db.intern_type_param_id(id);
+pub fn to_placeholder_idx(db: &dyn HirDatabase, id: TypeOrConstParamId) -> PlaceholderIndex {
+    let interned_id = db.intern_type_or_const_param_id(id);
     PlaceholderIndex {
         ui: chalk_ir::UniverseIndex::ROOT,
         idx: salsa::InternKey::as_intern_id(&interned_id).as_usize(),
@@ -139,12 +139,6 @@ pub fn lt_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> L
     db.lookup_intern_lifetime_param_id(interned_id)
 }
 
-pub fn const_from_placeholder_idx(db: &dyn HirDatabase, idx: PlaceholderIndex) -> ConstParamId {
-    assert_eq!(idx.ui, chalk_ir::UniverseIndex::ROOT);
-    let interned_id = salsa::InternKey::from_intern_id(salsa::InternId::from(idx.idx));
-    db.lookup_intern_const_param_id(interned_id)
-}
-
 pub fn to_chalk_trait_id(id: TraitId) -> ChalkTraitId {
     chalk_ir::TraitId(salsa::InternKey::as_intern_id(&id))
 }
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index c5646e08e6..cf8e284c62 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -8,13 +8,14 @@ use chalk_ir::{fold::Shift, BoundVar, DebruijnIndex};
 use hir_def::{
     db::DefDatabase,
     generics::{
-        GenericParams, TypeParamData, TypeParamProvenance, WherePredicate, WherePredicateTypeTarget,
+        GenericParams, TypeOrConstParamData, TypeParamData, TypeParamProvenance, WherePredicate,
+        WherePredicateTypeTarget,
     },
     intern::Interned,
     path::Path,
     resolver::{HasResolver, TypeNs},
     type_ref::{TraitBoundModifier, TypeRef},
-    GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeParamId,
+    GenericDefId, ItemContainerId, Lookup, TraitId, TypeAliasId, TypeOrConstParamId,
 };
 use hir_expand::name::{name, Name};
 use rustc_hash::FxHashSet;
@@ -55,7 +56,9 @@ fn direct_super_traits(db: &dyn DefDatabase, trait_: TraitId) -> SmallVec<[Trait
                     TypeRef::Path(p) if p == &Path::from(name![Self]) => bound.as_path(),
                     _ => None,
                 },
-                WherePredicateTypeTarget::TypeParam(local_id) if Some(*local_id) == trait_self => {
+                WherePredicateTypeTarget::TypeOrConstParam(local_id)
+                    if Some(*local_id) == trait_self =>
+                {
                     bound.as_path()
                 }
                 _ => None,
@@ -80,7 +83,7 @@ fn direct_super_trait_refs(db: &dyn HirDatabase, trait_ref: &TraitRef) -> Vec<Tr
     // SmallVec if performance is a concern)
     let generic_params = db.generic_params(trait_ref.hir_trait_id().into());
     let trait_self = match generic_params.find_trait_self_param() {
-        Some(p) => TypeParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
+        Some(p) => TypeOrConstParamId { parent: trait_ref.hir_trait_id().into(), local_id: p },
         None => return Vec::new(),
     };
     db.generic_predicates_for_param(trait_self.parent, trait_self, None)
@@ -181,34 +184,33 @@ pub(crate) struct Generics {
 }
 
 impl Generics {
-    pub(crate) fn iter<'a>(
+    // FIXME: we should drop this and handle const and type generics at the same time
+    pub(crate) fn type_iter<'a>(
         &'a self,
-    ) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a {
+    ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeParamData)> + 'a {
         self.parent_generics
             .as_ref()
             .into_iter()
             .flat_map(|it| {
                 it.params
-                    .types
-                    .iter()
-                    .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))
+                    .type_iter()
+                    .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
             })
             .chain(
-                self.params
-                    .types
-                    .iter()
-                    .map(move |(local_id, p)| (TypeParamId { parent: self.def, local_id }, p)),
+                self.params.type_iter().map(move |(local_id, p)| {
+                    (TypeOrConstParamId { parent: self.def, local_id }, p)
+                }),
             )
     }
 
     pub(crate) fn iter_parent<'a>(
         &'a self,
-    ) -> impl Iterator<Item = (TypeParamId, &'a TypeParamData)> + 'a {
+    ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
         self.parent_generics.as_ref().into_iter().flat_map(|it| {
             it.params
                 .types
                 .iter()
-                .map(move |(local_id, p)| (TypeParamId { parent: it.def, local_id }, p))
+                .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
         })
     }
 
@@ -219,7 +221,8 @@ 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.types.len();
+        // FIXME: we should not filter const generics here, but at now it breaks tests
+        let child = self.params.types.iter().filter_map(|x| x.1.type_param()).count();
         (parent + child, parent, child)
     }
 
@@ -230,28 +233,31 @@ impl Generics {
             .params
             .types
             .iter()
-            .filter(|(_, p)| p.provenance == TypeParamProvenance::TraitSelf)
+            .filter_map(|x| x.1.type_param())
+            .filter(|p| p.provenance == TypeParamProvenance::TraitSelf)
             .count();
         let list_params = self
             .params
             .types
             .iter()
-            .filter(|(_, p)| p.provenance == TypeParamProvenance::TypeParamList)
+            .filter_map(|x| x.1.type_param())
+            .filter(|p| p.provenance == TypeParamProvenance::TypeParamList)
             .count();
         let impl_trait_params = self
             .params
             .types
             .iter()
-            .filter(|(_, p)| p.provenance == TypeParamProvenance::ArgumentImplTrait)
+            .filter_map(|x| x.1.type_param())
+            .filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait)
             .count();
         (parent, self_params, list_params, impl_trait_params)
     }
 
-    pub(crate) fn param_idx(&self, param: TypeParamId) -> Option<usize> {
+    pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
         Some(self.find_param(param)?.0)
     }
 
-    fn find_param(&self, param: TypeParamId) -> Option<(usize, &TypeParamData)> {
+    fn find_param(&self, param: TypeOrConstParamId) -> Option<(usize, &TypeOrConstParamData)> {
         if param.parent == self.def {
             let (idx, (_local_id, data)) = self
                 .params
@@ -271,7 +277,7 @@ impl Generics {
     pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution {
         Substitution::from_iter(
             Interner,
-            self.iter()
+            self.type_iter()
                 .enumerate()
                 .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
         )
@@ -281,7 +287,7 @@ impl Generics {
     pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution {
         Substitution::from_iter(
             Interner,
-            self.iter().map(|(id, _)| {
+            self.type_iter().map(|(id, _)| {
                 TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(Interner)
             }),
         )
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 834668960f..97545bd20d 100644
--- a/crates/ide/src/navigation_target.rs
+++ b/crates/ide/src/navigation_target.rs
@@ -12,6 +12,7 @@ use ide_db::{
     SymbolKind,
 };
 use ide_db::{defs::Definition, RootDatabase};
+use stdx::never;
 use syntax::{
     ast::{self, HasName},
     match_ast, AstNode, SmolStr, SyntaxNode, TextRange,
@@ -435,9 +436,18 @@ impl ToNav for hir::Label {
 
 impl TryToNav for hir::TypeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
+        let InFile { file_id, value } = self.merge().source(db)?;
         let name = self.name(db).to_smol_str();
 
+        let value = match value {
+            Either::Left(ast::TypeOrConstParam::Type(x)) => Either::Left(x),
+            Either::Left(ast::TypeOrConstParam::Const(_)) => {
+                never!();
+                return None;
+            }
+            Either::Right(x) => Either::Right(x),
+        };
+
         let range = |syntax: &_| InFile::new(file_id, syntax).original_file_range(db);
         let focus_range = |syntax: &_| InFile::new(file_id, syntax).original_file_range_opt(db);
         let FileRange { file_id, range: full_range } = match &value {
@@ -464,6 +474,12 @@ impl TryToNav for hir::TypeParam {
     }
 }
 
+impl TryToNav for hir::TypeOrConstParam {
+    fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
+        self.split(db).try_to_nav(db)
+    }
+}
+
 impl TryToNav for hir::LifetimeParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
         let InFile { file_id, value } = self.source(db)?;
@@ -486,9 +502,17 @@ impl TryToNav for hir::LifetimeParam {
 
 impl TryToNav for hir::ConstParam {
     fn try_to_nav(&self, db: &RootDatabase) -> Option<NavigationTarget> {
-        let InFile { file_id, value } = self.source(db)?;
+        let InFile { file_id, value } = self.merge().source(db)?;
         let name = self.name(db).to_smol_str();
 
+        let value = match value {
+            Either::Left(ast::TypeOrConstParam::Const(x)) => x,
+            _ => {
+                never!();
+                return None;
+            }
+        };
+
         let focus_range = value.name().and_then(|it| orig_focus_range(db, file_id, it.syntax()));
         let FileRange { file_id, range: full_range } =
             InFile::new(file_id, value.syntax()).original_file_range(db);
diff --git a/crates/ide/src/syntax_highlighting/inject.rs b/crates/ide/src/syntax_highlighting/inject.rs
index a3b05ee263..ec1df6d1de 100644
--- a/crates/ide/src/syntax_highlighting/inject.rs
+++ b/crates/ide/src/syntax_highlighting/inject.rs
@@ -259,8 +259,8 @@ fn module_def_to_hl_tag(def: Definition) -> HlTag {
         Definition::Local(_) => SymbolKind::Local,
         Definition::GenericParam(gp) => match gp {
             hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
-            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
             hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
+            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
         },
         Definition::Label(_) => SymbolKind::Label,
         Definition::BuiltinAttr(_) => SymbolKind::BuiltinAttr,
diff --git a/crates/ide_assists/src/handlers/generate_default_from_new.rs b/crates/ide_assists/src/handlers/generate_default_from_new.rs
index 680ec0d1cd..6f158ceb99 100644
--- a/crates/ide_assists/src/handlers/generate_default_from_new.rs
+++ b/crates/ide_assists/src/handlers/generate_default_from_new.rs
@@ -85,21 +85,23 @@ fn generate_trait_impl_text_from_impl(impl_: &ast::Impl, trait_text: &str, code:
 
     if let Some(generic_params) = &generic_params {
         let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
-        let type_params = generic_params.type_params().map(|type_param| {
-            let mut buf = String::new();
-            if let Some(it) = type_param.name() {
-                format_to!(buf, "{}", it.syntax());
+        let toc_params = generic_params.type_or_const_params().map(|toc_param| match toc_param {
+            ast::TypeOrConstParam::Type(type_param) => {
+                let mut buf = String::new();
+                if let Some(it) = type_param.name() {
+                    format_to!(buf, "{}", it.syntax());
+                }
+                if let Some(it) = type_param.colon_token() {
+                    format_to!(buf, "{} ", it);
+                }
+                if let Some(it) = type_param.type_bound_list() {
+                    format_to!(buf, "{}", it.syntax());
+                }
+                buf
             }
-            if let Some(it) = type_param.colon_token() {
-                format_to!(buf, "{} ", it);
-            }
-            if let Some(it) = type_param.type_bound_list() {
-                format_to!(buf, "{}", it.syntax());
-            }
-            buf
+            ast::TypeOrConstParam::Const(const_param) => const_param.syntax().to_string(),
         });
-        let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
-        let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
+        let generics = lifetimes.chain(toc_params).format(", ");
         format_to!(buf, "<{}>", generics);
     }
 
diff --git a/crates/ide_assists/src/handlers/move_bounds.rs b/crates/ide_assists/src/handlers/move_bounds.rs
index 01c6eea225..425dba1a75 100644
--- a/crates/ide_assists/src/handlers/move_bounds.rs
+++ b/crates/ide_assists/src/handlers/move_bounds.rs
@@ -23,8 +23,11 @@ use crate::{AssistContext, AssistId, AssistKind, Assists};
 pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext) -> Option<()> {
     let type_param_list = ctx.find_node_at_offset::<ast::GenericParamList>()?;
 
-    let mut type_params = type_param_list.type_params();
-    if type_params.all(|p| p.type_bound_list().is_none()) {
+    let mut type_params = type_param_list.type_or_const_params();
+    if type_params.all(|p| match p {
+        ast::TypeOrConstParam::Type(t) => t.type_bound_list().is_none(),
+        ast::TypeOrConstParam::Const(_) => true,
+    }) {
         return None;
     }
 
@@ -50,7 +53,11 @@ pub(crate) fn move_bounds_to_where_clause(acc: &mut Assists, ctx: &AssistContext
                 }
             };
 
-            for type_param in type_param_list.type_params() {
+            for toc_param in type_param_list.type_or_const_params() {
+                let type_param = match toc_param {
+                    ast::TypeOrConstParam::Type(x) => x,
+                    ast::TypeOrConstParam::Const(_) => continue,
+                };
                 if let Some(tbl) = type_param.type_bound_list() {
                     if let Some(predicate) = build_predicate(type_param) {
                         where_clause.add_predicate(predicate)
diff --git a/crates/ide_assists/src/utils.rs b/crates/ide_assists/src/utils.rs
index e1ee3f3ad4..116f150ef2 100644
--- a/crates/ide_assists/src/utils.rs
+++ b/crates/ide_assists/src/utils.rs
@@ -435,7 +435,11 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
     buf.push_str("impl");
     if let Some(generic_params) = &generic_params {
         let lifetimes = generic_params.lifetime_params().map(|lt| format!("{}", lt.syntax()));
-        let type_params = generic_params.type_params().map(|type_param| {
+        let toc_params = generic_params.type_or_const_params().map(|toc_param| {
+            let type_param = match toc_param {
+                ast::TypeOrConstParam::Type(x) => x,
+                ast::TypeOrConstParam::Const(x) => return x.syntax().to_string(),
+            };
             let mut buf = String::new();
             if let Some(it) = type_param.name() {
                 format_to!(buf, "{}", it.syntax());
@@ -448,8 +452,7 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
             }
             buf
         });
-        let const_params = generic_params.const_params().map(|t| t.syntax().to_string());
-        let generics = lifetimes.chain(type_params).chain(const_params).format(", ");
+        let generics = lifetimes.chain(toc_params).format(", ");
         format_to!(buf, "<{}>", generics);
     }
     buf.push(' ');
@@ -463,15 +466,11 @@ fn generate_impl_text_inner(adt: &ast::Adt, trait_text: Option<&str>, code: &str
             .lifetime_params()
             .filter_map(|it| it.lifetime())
             .map(|it| SmolStr::from(it.text()));
-        let type_params = generic_params
-            .type_params()
-            .filter_map(|it| it.name())
-            .map(|it| SmolStr::from(it.text()));
-        let const_params = generic_params
-            .const_params()
+        let toc_params = generic_params
+            .type_or_const_params()
             .filter_map(|it| it.name())
             .map(|it| SmolStr::from(it.text()));
-        format_to!(buf, "<{}>", lifetime_params.chain(type_params).chain(const_params).format(", "))
+        format_to!(buf, "<{}>", lifetime_params.chain(toc_params).format(", "))
     }
 
     match adt.where_clause() {
diff --git a/crates/ide_completion/src/render.rs b/crates/ide_completion/src/render.rs
index 027fb53527..d5618f1474 100644
--- a/crates/ide_completion/src/render.rs
+++ b/crates/ide_completion/src/render.rs
@@ -201,8 +201,8 @@ fn render_resolution_(
         ScopeDef::ModuleDef(BuiltinType(..)) => CompletionItemKind::BuiltinType,
         ScopeDef::GenericParam(param) => CompletionItemKind::SymbolKind(match param {
             hir::GenericParam::TypeParam(_) => SymbolKind::TypeParam,
-            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
             hir::GenericParam::ConstParam(_) => SymbolKind::ConstParam,
+            hir::GenericParam::LifetimeParam(_) => SymbolKind::LifetimeParam,
         }),
         ScopeDef::Local(..) => CompletionItemKind::SymbolKind(SymbolKind::Local),
         ScopeDef::Label(..) => CompletionItemKind::SymbolKind(SymbolKind::Label),
diff --git a/crates/ide_db/src/apply_change.rs b/crates/ide_db/src/apply_change.rs
index 6c085ffc97..98b0e9c947 100644
--- a/crates/ide_db/src/apply_change.rs
+++ b/crates/ide_db/src/apply_change.rs
@@ -129,12 +129,12 @@ impl RootDatabase {
             hir::db::FnDefDatumQuery
             hir::db::ReturnTypeImplTraitsQuery
             hir::db::InternCallableDefQuery
-            hir::db::InternTypeParamIdQuery
+            hir::db::InternTypeOrConstParamIdQuery
             hir::db::InternImplTraitIdQuery
             hir::db::InternClosureQuery
             hir::db::AssociatedTyValueQuery
             hir::db::TraitSolveQueryQuery
-            hir::db::InternTypeParamIdQuery
+            hir::db::InternTypeOrConstParamIdQuery
 
             // SymbolsDatabase
             crate::symbol_index::ModuleSymbolsQuery
diff --git a/crates/ide_db/src/defs.rs b/crates/ide_db/src/defs.rs
index e41c97ea95..80988986ce 100644
--- a/crates/ide_db/src/defs.rs
+++ b/crates/ide_db/src/defs.rs
@@ -482,9 +482,9 @@ impl From<PathResolution> for Definition {
             }
             PathResolution::Local(local) => Definition::Local(local),
             PathResolution::TypeParam(par) => Definition::GenericParam(par.into()),
+            PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
             PathResolution::Macro(def) => Definition::Macro(def),
             PathResolution::SelfType(impl_def) => Definition::SelfType(impl_def),
-            PathResolution::ConstParam(par) => Definition::GenericParam(par.into()),
             PathResolution::BuiltinAttr(attr) => Definition::BuiltinAttr(attr),
             PathResolution::ToolModule(tool) => Definition::ToolModule(tool),
         }
diff --git a/crates/ide_db/src/path_transform.rs b/crates/ide_db/src/path_transform.rs
index 524af7fe8f..a293713026 100644
--- a/crates/ide_db/src/path_transform.rs
+++ b/crates/ide_db/src/path_transform.rs
@@ -1,6 +1,7 @@
 //! See [`PathTransform`].
 
 use crate::helpers::mod_path_to_ast;
+use either::Either;
 use hir::{HirDisplay, SemanticsScope};
 use rustc_hash::FxHashMap;
 use syntax::{
@@ -94,15 +95,20 @@ impl<'a> PathTransform<'a> {
             // a default type. If they do, go for that type from `hir` to `ast` so
             // the resulting change can be applied correctly.
             .zip(self.substs.iter().map(Some).chain(std::iter::repeat(None)))
-            .filter_map(|(k, v)| match v {
-                Some(v) => Some((k, v.clone())),
-                None => {
-                    let default = k.default(db)?;
-                    Some((
-                        k,
-                        ast::make::ty(&default.display_source_code(db, source_module.into()).ok()?),
-                    ))
-                }
+            .filter_map(|(k, v)| match k.split(db) {
+                Either::Left(_) => None,
+                Either::Right(t) => match v {
+                    Some(v) => Some((k, v.clone())),
+                    None => {
+                        let default = t.default(db)?;
+                        Some((
+                            k,
+                            ast::make::ty(
+                                &default.display_source_code(db, source_module.into()).ok()?,
+                            ),
+                        ))
+                    }
+                },
             })
             .collect();
         let res = Ctx { substs: substs_by_param, target_module, source_scope: self.source_scope };
@@ -111,7 +117,7 @@ impl<'a> PathTransform<'a> {
 }
 
 struct Ctx<'a> {
-    substs: FxHashMap<hir::TypeParam, ast::Type>,
+    substs: FxHashMap<hir::TypeOrConstParam, ast::Type>,
     target_module: hir::Module,
     source_scope: &'a SemanticsScope<'a>,
 }
@@ -150,7 +156,7 @@ impl<'a> Ctx<'a> {
 
         match resolution {
             hir::PathResolution::TypeParam(tp) => {
-                if let Some(subst) = self.substs.get(&tp) {
+                if let Some(subst) = self.substs.get(&tp.merge()) {
                     let parent = path.syntax().parent()?;
                     if let Some(parent) = ast::Path::cast(parent.clone()) {
                         // Path inside path means that there is an associated
diff --git a/crates/ide_db/src/rename.rs b/crates/ide_db/src/rename.rs
index 404e17c022..970ca2b6d7 100644
--- a/crates/ide_db/src/rename.rs
+++ b/crates/ide_db/src/rename.rs
@@ -124,20 +124,23 @@ impl Definition {
                 src.with_value(name.syntax()).original_file_range_opt(sema.db)
             }
             Definition::GenericParam(generic_param) => match generic_param {
-                hir::GenericParam::TypeParam(type_param) => {
-                    let src = type_param.source(sema.db)?;
+                hir::GenericParam::LifetimeParam(lifetime_param) => {
+                    let src = lifetime_param.source(sema.db)?;
+                    src.with_value(src.value.lifetime()?.syntax()).original_file_range_opt(sema.db)
+                }
+                _ => {
+                    let x = match generic_param {
+                        hir::GenericParam::TypeParam(it) => it.merge(),
+                        hir::GenericParam::ConstParam(it) => it.merge(),
+                        hir::GenericParam::LifetimeParam(_) => return None,
+                    };
+                    let src = x.source(sema.db)?;
                     let name = match &src.value {
-                        Either::Left(type_param) => type_param.name()?,
-                        Either::Right(_trait) => return None,
+                        Either::Left(x) => x.name()?,
+                        Either::Right(_) => return None,
                     };
                     src.with_value(name.syntax()).original_file_range_opt(sema.db)
                 }
-                hir::GenericParam::LifetimeParam(lifetime_param) => {
-                    let src = lifetime_param.source(sema.db)?;
-                    let lifetime = src.value.lifetime()?;
-                    src.with_value(lifetime.syntax()).original_file_range_opt(sema.db)
-                }
-                hir::GenericParam::ConstParam(it) => name_range(it, sema),
             },
             Definition::Label(label) => {
                 let src = label.source(sema.db);
diff --git a/crates/syntax/src/ast.rs b/crates/syntax/src/ast.rs
index 91b46cf8e9..4aa64d0d6e 100644
--- a/crates/syntax/src/ast.rs
+++ b/crates/syntax/src/ast.rs
@@ -22,7 +22,7 @@ pub use self::{
     generated::{nodes::*, tokens::*},
     node_ext::{
         AttrKind, FieldKind, Macro, NameLike, NameOrNameRef, PathSegmentKind, SelfParamKind,
-        SlicePatComponents, StructKind, TypeBoundKind, VisibilityKind,
+        SlicePatComponents, StructKind, TypeBoundKind, TypeOrConstParam, VisibilityKind,
     },
     operators::{ArithOp, BinaryOp, CmpOp, LogicOp, Ordering, RangeOp, UnaryOp},
     token_ext::{CommentKind, CommentPlacement, CommentShape, IsString, QuoteOffsets, Radix},
diff --git a/crates/syntax/src/ast/node_ext.rs b/crates/syntax/src/ast/node_ext.rs
index 97455abd80..229c71c76b 100644
--- a/crates/syntax/src/ast/node_ext.rs
+++ b/crates/syntax/src/ast/node_ext.rs
@@ -638,6 +638,21 @@ impl ast::TypeBound {
     }
 }
 
+#[derive(Debug, Clone)]
+pub enum TypeOrConstParam {
+    Type(ast::TypeParam),
+    Const(ast::ConstParam),
+}
+
+impl TypeOrConstParam {
+    pub fn name(&self) -> Option<ast::Name> {
+        match self {
+            TypeOrConstParam::Type(x) => x.name(),
+            TypeOrConstParam::Const(x) => x.name(),
+        }
+    }
+}
+
 pub enum VisibilityKind {
     In(ast::Path),
     PubCrate,
@@ -746,16 +761,11 @@ impl ast::GenericParamList {
             ast::GenericParam::TypeParam(_) | ast::GenericParam::ConstParam(_) => None,
         })
     }
-    pub fn type_params(&self) -> impl Iterator<Item = ast::TypeParam> {
-        self.generic_params().filter_map(|param| match param {
-            ast::GenericParam::TypeParam(it) => Some(it),
-            ast::GenericParam::LifetimeParam(_) | ast::GenericParam::ConstParam(_) => None,
-        })
-    }
-    pub fn const_params(&self) -> impl Iterator<Item = ast::ConstParam> {
+    pub fn type_or_const_params(&self) -> impl Iterator<Item = ast::TypeOrConstParam> {
         self.generic_params().filter_map(|param| match param {
-            ast::GenericParam::ConstParam(it) => Some(it),
-            ast::GenericParam::TypeParam(_) | ast::GenericParam::LifetimeParam(_) => None,
+            ast::GenericParam::TypeParam(it) => Some(ast::TypeOrConstParam::Type(it)),
+            ast::GenericParam::LifetimeParam(_) => None,
+            ast::GenericParam::ConstParam(it) => Some(ast::TypeOrConstParam::Const(it)),
         })
     }
 }


Test patch:
diff --git a/crates/ide/src/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df0ca941c9..ab10bc6ef5 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -2913,6 +2913,27 @@ fn main() {
     );
 }
 
+#[test]
+fn const_generic_order() {
+    check(
+        r#"
+struct Foo;
+struct S$0T<const C: usize = 1, T = Foo>(T);
+"#,
+        expect![[r#"
+            *ST*
+
+            ```rust
+            test
+            ```
+
+            ```rust
+            struct ST<const C: usize, T = Foo>
+            ```
+        "#]],
+    );
+}
+
 #[test]
 fn hover_self_param_shows_type() {
     check(
diff --git a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index a04a211825..bd8d9faae8 100644
--- a/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
+++ b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
@@ -109,6 +109,13 @@ pre                 { color: #DCDCCC; background: #3F3F3F; font-size: 22px; padd
     <span class="comment documentation">/// </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">foobar</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="struct injected">Foo</span><span class="operator injected">::</span><span class="function injected">new</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="operator injected">.</span><span class="function injected">bar</span><span class="parenthesis injected">(</span><span class="parenthesis injected">)</span><span class="semicolon injected">;</span>
     <span class="comment documentation">/// ```</span>
     <span class="comment documentation">///</span>
+    <span class="comment documentation">/// ```</span>
+    <span class="comment documentation">/// </span><span class="comment injected">// functions</span>
+    <span class="comment documentation">/// </span><span class="keyword injected">fn</span><span class="none injected"> </span><span class="function declaration injected">foo</span><span class="angle injected">&lt;</span><span class="type_param declaration injected">T</span><span class="comma injected">,</span><span class="none injected"> </span><span class="keyword injected">const</span><span class="none injected"> </span><span class="const_param declaration injected">X</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">usize</span><span class="angle injected">&gt;</span><span class="parenthesis injected">(</span><span class="value_param declaration injected">arg</span><span class="colon injected">:</span><span class="none injected"> </span><span class="builtin_type injected">i32</span><span class="parenthesis injected">)</span><span class="none injected"> </span><span class="brace injected">{</span>
+    <span class="comment documentation">/// </span><span class="none injected">    </span><span class="keyword injected">let</span><span class="none injected"> </span><span class="variable declaration injected">x</span><span class="colon injected">:</span><span class="none injected"> </span><span class="type_param injected">T</span><span class="none injected"> </span><span class="operator injected">=</span><span class="none injected"> </span><span class="const_param injected">X</span><span class="semicolon injected">;</span>
+    <span class="comment documentation">/// </span><span class="brace injected">}</span>
+    <span class="comment documentation">/// ```</span>
+    <span class="comment documentation">///</span>
     <span class="comment documentation">/// ```sh</span>
     <span class="comment documentation">/// echo 1</span>
     <span class="comment documentation">/// ```</span>
diff --git a/crates/ide/src/syntax_highlighting/tests.rs b/crates/ide/src/syntax_highlighting/tests.rs
index 27686ab944..c14e3330e3 100644
--- a/crates/ide/src/syntax_highlighting/tests.rs
+++ b/crates/ide/src/syntax_highlighting/tests.rs
@@ -599,6 +599,13 @@ impl Foo {
     /// let foobar = Foo::new().bar();
     /// ```
     ///
+    /// ```
+    /// // functions
+    /// fn foo<T, const X: usize>(arg: i32) {
+    ///     let x: T = X;
+    /// }
+    /// ```
+    ///
     /// ```sh
     /// echo 1
     /// ```