about summary refs log tree commit diff
diff options
context:
space:
mode:
authorhkalbasi <hamidrezakalbasi@protonmail.com>2021-12-29 17:05:59 +0330
committerhkalbasi <hamidrezakalbasi@protonmail.com>2022-03-04 11:46:14 +0330
commit4fa8749c44e1c91335002eb46d59b2a72e756bb3 (patch)
treeeddaef9ea4a9ad99ae99fe288ffad4b4d34d5c88
parent9d473a0b9f92c0739e4635fa8ef95a91ac2a481d (diff)
downloadrust-4fa8749c44e1c91335002eb46d59b2a72e756bb3.tar.gz
rust-4fa8749c44e1c91335002eb46d59b2a72e756bb3.zip
Preserve order of generic args
-rw-r--r--crates/hir/src/attrs.rs4
-rw-r--r--crates/hir/src/display.rs65
-rw-r--r--crates/hir/src/from_id.rs9
-rw-r--r--crates/hir/src/has_source.rs16
-rw-r--r--crates/hir/src/lib.rs125
-rw-r--r--crates/hir/src/semantics.rs2
-rw-r--r--crates/hir/src/semantics/source_to_def.rs4
-rw-r--r--crates/hir/src/source_analyzer.rs14
-rw-r--r--crates/hir_def/src/attr.rs53
-rw-r--r--crates/hir_def/src/generics.rs174
-rw-r--r--crates/hir_def/src/item_tree/lower.rs13
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs36
-rw-r--r--crates/hir_def/src/keys.rs8
-rw-r--r--crates/hir_def/src/lib.rs67
-rw-r--r--crates/hir_def/src/resolver.rs45
-rw-r--r--crates/hir_expand/src/builtin_derive_macro.rs11
-rw-r--r--crates/hir_ty/src/chalk_ext.rs46
-rw-r--r--crates/hir_ty/src/db.rs15
-rw-r--r--crates/hir_ty/src/display.rs70
-rw-r--r--crates/hir_ty/src/infer/expr.rs12
-rw-r--r--crates/hir_ty/src/lib.rs10
-rw-r--r--crates/hir_ty/src/lower.rs60
-rw-r--r--crates/hir_ty/src/mapping.rs16
-rw-r--r--crates/hir_ty/src/utils.rs52
-rw-r--r--crates/ide/src/hover/tests.rs21
-rw-r--r--crates/ide/src/navigation_target.rs28
-rw-r--r--crates/ide/src/syntax_highlighting/inject.rs2
-rw-r--r--crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html7
-rw-r--r--crates/ide/src/syntax_highlighting/tests.rs7
-rw-r--r--crates/ide_assists/src/handlers/generate_default_from_new.rs28
-rw-r--r--crates/ide_assists/src/handlers/move_bounds.rs13
-rw-r--r--crates/ide_assists/src/utils.rs19
-rw-r--r--crates/ide_completion/src/render.rs2
-rw-r--r--crates/ide_db/src/apply_change.rs4
-rw-r--r--crates/ide_db/src/defs.rs2
-rw-r--r--crates/ide_db/src/path_transform.rs28
-rw-r--r--crates/ide_db/src/rename.rs23
-rw-r--r--crates/syntax/src/ast.rs2
-rw-r--r--crates/syntax/src/ast/node_ext.rs28
39 files changed, 714 insertions, 427 deletions
diff --git a/crates/hir/src/attrs.rs b/crates/hir/src/attrs.rs
index 46e9c54dad6..7e83819a4f5 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 1e949771ea0..d411b9d71b1 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 98c51652d95..a0b7aa3da22 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 8669b00ca1a..8683e14f2ad 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 e02ba2e7c86..45a4c6a50eb 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.rs b/crates/hir/src/semantics.rs
index 2e0dbf82b77..3af47000f41 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -70,7 +70,7 @@ impl PathResolution {
             | PathResolution::Local(_)
             | PathResolution::Macro(_)
             | PathResolution::ConstParam(_) => None,
-            PathResolution::TypeParam(param) => Some(TypeNs::GenericParam((*param).into())),
+            PathResolution::TypeParam(param) => Some(TypeNs::GenericParam(param.merge().into())),
             PathResolution::SelfType(impl_def) => Some(TypeNs::SelfType((*impl_def).into())),
             PathResolution::AssocItem(AssocItem::Const(_) | AssocItem::Function(_)) => None,
             PathResolution::AssocItem(AssocItem::TypeAlias(alias)) => {
diff --git a/crates/hir/src/semantics/source_to_def.rs b/crates/hir/src/semantics/source_to_def.rs
index dddb8e33dcc..6f93f8ac943 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 ef32a5891c7..1295d050071 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,
+    TypeOrConstParam, Variant,
 };
 use base_db::CrateId;
 
@@ -609,7 +609,10 @@ 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) => match (TypeOrConstParam { id }).split(db) {
+                either::Either::Left(x) => PathResolution::ConstParam(x),
+                either::Either::Right(x) => PathResolution::TypeParam(x),
+            },
             TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
                 PathResolution::Def(Adt::from(it).into())
             }
@@ -650,7 +653,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 +706,10 @@ 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) => match (TypeOrConstParam { id }).split(db) {
+            either::Either::Left(x) => PathResolution::ConstParam(x),
+            either::Either::Right(x) => PathResolution::TypeParam(x),
+        },
         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 3ff2d7b915e..694c24a4fee 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 7febf1b5e86..341d444d619 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,26 @@ 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_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 })
+            .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_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 +424,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 +445,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 +477,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 +485,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 f1b378a3be5..d215ce101f0 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 0df6e97dd46..5b211a142ab 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 8cd2d771721..5f219143055 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 bb65d1dec87..21096166d7b 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 9f68b800a55..e19e8543b41 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, VariantId,
 };
 
 #[derive(Debug, Clone, Default)]
@@ -68,7 +68,7 @@ enum Scope {
 #[derive(Debug, Clone, PartialEq, Eq, Hash)]
 pub enum TypeNs {
     SelfType(ImplId),
-    GenericParam(TypeParamId),
+    GenericParam(TypeOrConstParamId),
     AdtId(AdtId),
     AdtSelfType(AdtId),
     // Yup, enum variants are added to the types ns, but any usage of variant as
@@ -192,10 +192,12 @@ impl Resolver {
                 Scope::GenericParams { .. } | Scope::ImplDefScope(_) if skip_to_mod => continue,
 
                 Scope::GenericParams { params, def } => {
-                    if let Some(local_id) = params.find_type_by_name(first_name) {
+                    if let Some(local_id) = params.find_type_or_const_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 dd7d249efa3..d56cd99269c 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 bd5aab1b3d5..d34257f1184 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 c3b9255baf4..e144dd43f44 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 2020834fbc4..a2644e74b8d 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 ad54b72b4b5..c52dd3e8edb 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 f1280fcc101..b57ad620684 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 a140dd4057c..3444ffd2020 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,
@@ -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(
@@ -989,9 +993,7 @@ fn named_associated_type_shorthand_candidates<R>(
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent {
                 let generics = generics(db.upcast(), trait_id.into());
-                if generics.params.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 5e86fafe5d6..d765fee0e1f 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 c5646e08e6c..cf8e284c627 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/hover/tests.rs b/crates/ide/src/hover/tests.rs
index df0ca941c99..ab10bc6ef5c 100644
--- a/crates/ide/src/hover/tests.rs
+++ b/crates/ide/src/hover/tests.rs
@@ -2914,6 +2914,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(
         r#"
diff --git a/crates/ide/src/navigation_target.rs b/crates/ide/src/navigation_target.rs
index 834668960f3..97545bd20dd 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 a3b05ee2633..ec1df6d1de5 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/src/syntax_highlighting/test_data/highlight_doctest.html b/crates/ide/src/syntax_highlighting/test_data/highlight_doctest.html
index a04a211825d..bd8d9faae84 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 27686ab9447..c14e3330e31 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
     /// ```
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 680ec0d1cd8..6f158ceb993 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 01c6eea225b..425dba1a75f 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 e1ee3f3ad45..116f150ef2d 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 027fb535271..d5618f14743 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 6c085ffc979..98b0e9c947a 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 e41c97ea953..80988986ce5 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 524af7fe8f0..a293713026f 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 404e17c022b..970ca2b6d7a 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 91b46cf8e9d..4aa64d0d6e8 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 97455abd809..229c71c76b1 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)),
         })
     }
 }