about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors[bot] <26634292+bors[bot]@users.noreply.github.com>2022-03-09 17:18:03 +0000
committerGitHub <noreply@github.com>2022-03-09 17:18:03 +0000
commit4fcaefa62a4afc533dab1380d977d625bd2c70de (patch)
treee06593963aa7dba334ed295bb1484deb014df431
parentd70ea759b3e6945749ee75fed088dc0a34f1ed26 (diff)
parent1282178783927d37f2236a44896b761097feaeac (diff)
downloadrust-4fcaefa62a4afc533dab1380d977d625bd2c70de.tar.gz
rust-4fcaefa62a4afc533dab1380d977d625bd2c70de.zip
Merge #11660
11660: Insert dummy values for const generics in subst r=flodiebold a=HKalbasi

fix #11659 

This is a band-aid until proper const generic support.

Co-authored-by: hkalbasi <hamidrezakalbasi@protonmail.com>
-rw-r--r--crates/hir/src/display.rs8
-rw-r--r--crates/hir/src/lib.rs10
-rw-r--r--crates/hir_def/src/generics.rs35
-rw-r--r--crates/hir_def/src/item_tree/lower.rs2
-rw-r--r--crates/hir_def/src/item_tree/pretty.rs6
-rw-r--r--crates/hir_def/src/resolver.rs4
-rw-r--r--crates/hir_ty/src/chalk_ext.rs2
-rw-r--r--crates/hir_ty/src/display.rs8
-rw-r--r--crates/hir_ty/src/infer/expr.rs7
-rw-r--r--crates/hir_ty/src/lower.rs44
-rw-r--r--crates/hir_ty/src/tests/regression.rs68
-rw-r--r--crates/hir_ty/src/utils.rs44
12 files changed, 176 insertions, 62 deletions
diff --git a/crates/hir/src/display.rs b/crates/hir/src/display.rs
index b7ea42236ee..8f80f3a5db6 100644
--- a/crates/hir/src/display.rs
+++ b/crates/hir/src/display.rs
@@ -293,7 +293,7 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
     let params = f.db.generic_params(def);
     if params.lifetimes.is_empty()
         && params
-            .types
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .all(|param| !matches!(param.provenance, TypeParamProvenance::TypeParamList))
@@ -315,7 +315,7 @@ fn write_generic_params(def: GenericDefId, f: &mut HirFormatter) -> Result<(), H
         delim(f)?;
         write!(f, "{}", lifetime.name)?;
     }
-    for (_, ty) in params.types.iter() {
+    for (_, ty) in params.tocs.iter() {
         if let Some(name) = &ty.name() {
             match ty {
                 TypeOrConstParamData::TypeParamData(ty) => {
@@ -348,7 +348,7 @@ fn write_where_clause(def: GenericDefId, f: &mut HirFormatter) -> Result<(), Hir
     // unnamed type targets are displayed inline with the argument itself, e.g. `f: impl Y`.
     let is_unnamed_type_target = |target: &WherePredicateTypeTarget| match target {
         WherePredicateTypeTarget::TypeRef(_) => false,
-        WherePredicateTypeTarget::TypeOrConstParam(id) => params.types[*id].name().is_none(),
+        WherePredicateTypeTarget::TypeOrConstParam(id) => params.tocs[*id].name().is_none(),
     };
 
     let has_displayable_predicate = params
@@ -364,7 +364,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::TypeOrConstParam(id) => match &params.types[*id].name() {
+        WherePredicateTypeTarget::TypeOrConstParam(id) => match &params.tocs[*id].name() {
             Some(name) => write!(f, "{}", name),
             None => write!(f, "{{unnamed}}"),
         },
diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs
index d38c91ac437..0aabb415d46 100644
--- a/crates/hir/src/lib.rs
+++ b/crates/hir/src/lib.rs
@@ -2029,7 +2029,7 @@ impl_from!(
 impl GenericDef {
     pub fn params(self, db: &dyn HirDatabase) -> Vec<GenericParam> {
         let generics = db.generic_params(self.into());
-        let ty_params = generics.types.iter().map(|(local_id, _)| {
+        let ty_params = generics.tocs.iter().map(|(local_id, _)| {
             let toc = TypeOrConstParam { id: TypeOrConstParamId { parent: self.into(), local_id } };
             match toc.split(db) {
                 Either::Left(x) => GenericParam::ConstParam(x),
@@ -2049,7 +2049,7 @@ impl GenericDef {
     pub fn type_params(self, db: &dyn HirDatabase) -> Vec<TypeOrConstParam> {
         let generics = db.generic_params(self.into());
         generics
-            .types
+            .tocs
             .iter()
             .map(|(local_id, _)| TypeOrConstParam {
                 id: TypeOrConstParamId { parent: self.into(), local_id },
@@ -2371,7 +2371,7 @@ impl ConstParam {
 
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let params = db.generic_params(self.id.parent());
-        match params.types[self.id.local_id()].name() {
+        match params.tocs[self.id.local_id()].name() {
             Some(x) => x.clone(),
             None => {
                 never!();
@@ -2403,7 +2403,7 @@ pub struct TypeOrConstParam {
 impl TypeOrConstParam {
     pub fn name(self, db: &dyn HirDatabase) -> Name {
         let params = db.generic_params(self.id.parent);
-        match params.types[self.id.local_id].name() {
+        match params.tocs[self.id.local_id].name() {
             Some(n) => n.clone(),
             _ => Name::missing(),
         }
@@ -2419,7 +2419,7 @@ impl TypeOrConstParam {
 
     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] {
+        match &params.tocs[self.id.local_id] {
             hir_def::generics::TypeOrConstParamData::TypeParamData(_) => {
                 Either::Right(TypeParam { id: self.id.into() })
             }
diff --git a/crates/hir_def/src/generics.rs b/crates/hir_def/src/generics.rs
index b5a11a1ba55..60d79f1473e 100644
--- a/crates/hir_def/src/generics.rs
+++ b/crates/hir_def/src/generics.rs
@@ -77,6 +77,13 @@ impl TypeOrConstParamData {
         }
     }
 
+    pub fn const_param(&self) -> Option<&ConstParamData> {
+        match self {
+            TypeOrConstParamData::TypeParamData(_) => None,
+            TypeOrConstParamData::ConstParamData(x) => Some(x),
+        }
+    }
+
     pub fn is_trait_self(&self) -> bool {
         match self {
             TypeOrConstParamData::TypeParamData(x) => {
@@ -92,7 +99,7 @@ impl_from!(TypeParamData, ConstParamData for TypeOrConstParamData);
 /// Data about the generic parameters of a function, struct, impl, etc.
 #[derive(Clone, PartialEq, Eq, Debug, Default, Hash)]
 pub struct GenericParams {
-    pub types: Arena<TypeOrConstParamData>,
+    pub tocs: Arena<TypeOrConstParamData>,
     pub lifetimes: Arena<LifetimeParamData>,
     pub where_predicates: Vec<WherePredicate>,
 }
@@ -131,7 +138,13 @@ impl GenericParams {
     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)))
+        self.tocs.iter().filter_map(|x| x.1.type_param().map(|y| (x.0, y)))
+    }
+
+    pub fn toc_iter<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = (Idx<TypeOrConstParamData>, &TypeOrConstParamData)> {
+        self.tocs.iter()
     }
 
     pub(crate) fn generic_params_query(
@@ -238,7 +251,7 @@ impl GenericParams {
                         default,
                         provenance: TypeParamProvenance::TypeParamList,
                     };
-                    self.types.alloc(param.into());
+                    self.tocs.alloc(param.into());
                     let type_ref = TypeRef::Path(name.into());
                     self.fill_bounds(lower_ctx, &type_param, Either::Left(type_ref));
                 }
@@ -248,7 +261,7 @@ impl GenericParams {
                         .ty()
                         .map_or(TypeRef::Error, |it| TypeRef::from_ast(lower_ctx, it));
                     let param = ConstParamData { name, ty: Interned::new(ty) };
-                    self.types.alloc(param.into());
+                    self.tocs.alloc(param.into());
                 }
             }
         }
@@ -335,7 +348,7 @@ impl GenericParams {
                     default: None,
                     provenance: TypeParamProvenance::ArgumentImplTrait,
                 };
-                let param_id = self.types.alloc(param.into());
+                let param_id = self.tocs.alloc(param.into());
                 for bound in bounds {
                     self.where_predicates.push(WherePredicate::TypeBound {
                         target: WherePredicateTypeTarget::TypeOrConstParam(param_id),
@@ -359,27 +372,27 @@ impl GenericParams {
     }
 
     pub(crate) fn shrink_to_fit(&mut self) {
-        let Self { lifetimes, types, where_predicates } = self;
+        let Self { lifetimes, tocs: types, where_predicates } = self;
         lifetimes.shrink_to_fit();
         types.shrink_to_fit();
         where_predicates.shrink_to_fit();
     }
 
     pub fn find_type_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
-        self.types
+        self.tocs
             .iter()
             .filter(|x| matches!(x.1, TypeOrConstParamData::TypeParamData(_)))
             .find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
     }
 
     pub fn find_type_or_const_by_name(&self, name: &Name) -> Option<LocalTypeOrConstParamId> {
-        self.types
+        self.tocs
             .iter()
             .find_map(|(id, p)| if p.name().as_ref() == Some(&name) { Some(id) } else { None })
     }
 
     pub fn find_trait_self_param(&self) -> Option<LocalTypeOrConstParamId> {
-        self.types.iter().find_map(|(id, p)| {
+        self.tocs.iter().find_map(|(id, p)| {
             if let TypeOrConstParamData::TypeParamData(p) = p {
                 if p.provenance == TypeParamProvenance::TraitSelf {
                     Some(id)
@@ -438,7 +451,7 @@ impl HasChildSource<LocalTypeOrConstParamId> for GenericDefId {
         db: &dyn DefDatabase,
     ) -> InFile<ArenaMap<LocalTypeOrConstParamId, Self::Value>> {
         let generic_params = db.generic_params(*self);
-        let mut idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
+        let mut idx_iter = generic_params.tocs.iter().map(|(idx, _)| idx);
 
         let (file_id, generic_params_list) = file_id_and_params_of(*self, db);
 
@@ -492,7 +505,7 @@ impl ChildBySource for GenericDefId {
         }
 
         let generic_params = db.generic_params(*self);
-        let mut toc_idx_iter = generic_params.types.iter().map(|(idx, _)| idx);
+        let mut toc_idx_iter = generic_params.tocs.iter().map(|(idx, _)| idx);
         let lts_idx_iter = generic_params.lifetimes.iter().map(|(idx, _)| idx);
 
         // For traits the first type index is `Self`, skip it.
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index d215ce101f0..45b5430a22f 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -582,7 +582,7 @@ impl<'a> Ctx<'a> {
             }
             GenericsOwner::Trait(trait_def) => {
                 // traits get the Self type as an implicit first type parameter
-                generics.types.alloc(
+                generics.tocs.alloc(
                     TypeParamData {
                         name: Some(name![Self]),
                         default: None,
diff --git a/crates/hir_def/src/item_tree/pretty.rs b/crates/hir_def/src/item_tree/pretty.rs
index 5b211a142ab..6fea95a2ac9 100644
--- a/crates/hir_def/src/item_tree/pretty.rs
+++ b/crates/hir_def/src/item_tree/pretty.rs
@@ -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() {
+        if params.tocs.is_empty() && params.lifetimes.is_empty() {
             return;
         }
 
@@ -639,7 +639,7 @@ impl<'a> Printer<'a> {
             first = false;
             w!(self, "{}", lt.name);
         }
-        for (idx, x) in params.types.iter() {
+        for (idx, x) in params.tocs.iter() {
             if !first {
                 w!(self, ", ");
             }
@@ -701,7 +701,7 @@ impl<'a> Printer<'a> {
                 match target {
                     WherePredicateTypeTarget::TypeRef(ty) => this.print_type_ref(ty),
                     WherePredicateTypeTarget::TypeOrConstParam(id) => {
-                        match &params.types[*id].name() {
+                        match &params.tocs[*id].name() {
                             Some(name) => w!(this, "{}", name),
                             None => w!(this, "_anon_{}", id.into_raw()),
                         }
diff --git a/crates/hir_def/src/resolver.rs b/crates/hir_def/src/resolver.rs
index 22f66a0d621..3d47064e4f6 100644
--- a/crates/hir_def/src/resolver.rs
+++ b/crates/hir_def/src/resolver.rs
@@ -518,10 +518,10 @@ impl Scope {
             }
             Scope::GenericParams { params, def: parent } => {
                 let parent = *parent;
-                for (local_id, param) in params.types.iter() {
+                for (local_id, param) in params.tocs.iter() {
                     if let Some(name) = &param.name() {
                         let id = TypeOrConstParamId { parent, local_id };
-                        let data = &db.generic_params(parent).types[local_id];
+                        let data = &db.generic_params(parent).tocs[local_id];
                         acc.add(
                             name,
                             ScopeDef::GenericParam(match data {
diff --git a/crates/hir_ty/src/chalk_ext.rs b/crates/hir_ty/src/chalk_ext.rs
index d34257f1184..8758f38bfc9 100644
--- a/crates/hir_ty/src/chalk_ext.rs
+++ b/crates/hir_ty/src/chalk_ext.rs
@@ -237,7 +237,7 @@ impl TyExt for Ty {
             TyKind::Placeholder(idx) => {
                 let id = from_placeholder_idx(db, *idx);
                 let generic_params = db.generic_params(id.parent);
-                let param_data = &generic_params.types[id.local_id];
+                let param_data = &generic_params.tocs[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         hir_def::generics::TypeParamProvenance::ArgumentImplTrait => {
diff --git a/crates/hir_ty/src/display.rs b/crates/hir_ty/src/display.rs
index a2644e74b8d..d81aa348248 100644
--- a/crates/hir_ty/src/display.rs
+++ b/crates/hir_ty/src/display.rs
@@ -320,7 +320,7 @@ impl HirDisplay for Const {
             ConstValue::Placeholder(idx) => {
                 let id = from_placeholder_idx(f.db, idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params.types[id.local_id];
+                let param_data = &generics.params.tocs[id.local_id];
                 write!(f, "{}", param_data.name().unwrap())
             }
             ConstValue::Concrete(c) => write!(f, "{}", c.interned),
@@ -489,9 +489,9 @@ impl HirDisplay for Ty {
                 };
                 if parameters.len(Interner) > 0 {
                     let generics = generics(f.db.upcast(), def.into());
-                    let (parent_params, self_param, type_params, _impl_trait_params) =
+                    let (parent_params, self_param, type_params, const_params, _impl_trait_params) =
                         generics.provenance_split();
-                    let total_len = parent_params + self_param + type_params;
+                    let total_len = parent_params + self_param + type_params + const_params;
                     // We print all params except implicit impl Trait params. Still a bit weird; should we leave out parent and self?
                     if total_len > 0 {
                         write!(f, "<")?;
@@ -680,7 +680,7 @@ impl HirDisplay for Ty {
             TyKind::Placeholder(idx) => {
                 let id = from_placeholder_idx(f.db, *idx);
                 let generics = generics(f.db.upcast(), id.parent);
-                let param_data = &generics.params.types[id.local_id];
+                let param_data = &generics.params.tocs[id.local_id];
                 match param_data {
                     TypeOrConstParamData::TypeParamData(p) => match p.provenance {
                         TypeParamProvenance::TypeParamList | TypeParamProvenance::TraitSelf => {
diff --git a/crates/hir_ty/src/infer/expr.rs b/crates/hir_ty/src/infer/expr.rs
index c52dd3e8edb..c093f0e4b23 100644
--- a/crates/hir_ty/src/infer/expr.rs
+++ b/crates/hir_ty/src/infer/expr.rs
@@ -1032,10 +1032,10 @@ impl<'a> InferenceContext<'a> {
         def_generics: Generics,
         generic_args: Option<&GenericArgs>,
     ) -> Substitution {
-        let (parent_params, self_params, type_params, impl_trait_params) =
+        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
             def_generics.provenance_split();
         assert_eq!(self_params, 0); // method shouldn't have another Self param
-        let total_len = parent_params + type_params + impl_trait_params;
+        let total_len = parent_params + type_params + const_params + impl_trait_params;
         let mut substs = Vec::with_capacity(total_len);
         // Parent arguments are unknown
         for (_id, param) in def_generics.iter_parent() {
@@ -1044,7 +1044,8 @@ impl<'a> InferenceContext<'a> {
                     substs.push(self.table.new_type_var());
                 }
                 TypeOrConstParamData::ConstParamData(_) => {
-                    // FIXME: here we should do something
+                    // FIXME: here we should do something else
+                    substs.push(self.table.new_type_var());
                 }
             }
         }
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index 3147b6f330b..15f91ce799b 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -286,16 +286,21 @@ impl<'a> TyLoweringContext<'a> {
                         let idx = self.impl_trait_counter.get();
                         // FIXME we're probably doing something wrong here
                         self.impl_trait_counter.set(idx + count_impl_traits(type_ref) as u16);
-                        let (parent_params, self_params, list_params, _impl_trait_params) =
-                            if let Some(def) = self.resolver.generic_def() {
-                                let generics = generics(self.db.upcast(), def);
-                                generics.provenance_split()
-                            } else {
-                                (0, 0, 0, 0)
-                            };
+                        let (
+                            parent_params,
+                            self_params,
+                            list_params,
+                            const_params,
+                            _impl_trait_params,
+                        ) = if let Some(def) = self.resolver.generic_def() {
+                            let generics = generics(self.db.upcast(), def);
+                            generics.provenance_split()
+                        } else {
+                            (0, 0, 0, 0, 0)
+                        };
                         TyKind::BoundVar(BoundVar::new(
                             self.in_binders,
-                            idx as usize + parent_params + self_params + list_params,
+                            idx as usize + parent_params + self_params + list_params + const_params,
                         ))
                         .intern(Interner)
                     }
@@ -639,9 +644,10 @@ impl<'a> TyLoweringContext<'a> {
         let mut substs = Vec::new();
         let def_generics = def_generic.map(|def| generics(self.db.upcast(), def));
 
-        let (parent_params, self_params, type_params, impl_trait_params) =
-            def_generics.map_or((0, 0, 0, 0), |g| g.provenance_split());
-        let total_len = parent_params + self_params + type_params + impl_trait_params;
+        let (parent_params, self_params, type_params, const_params, impl_trait_params) =
+            def_generics.map_or((0, 0, 0, 0, 0), |g| g.provenance_split());
+        let total_len =
+            parent_params + self_params + type_params + const_params + impl_trait_params;
 
         substs.extend(iter::repeat(TyKind::Error.intern(Interner)).take(parent_params));
 
@@ -993,7 +999,7 @@ fn named_associated_type_shorthand_candidates<R>(
             // Handle `Self::Type` referring to own associated type in trait definitions
             if let GenericDefId::TraitId(trait_id) = param_id.parent() {
                 let generics = generics(db.upcast(), trait_id.into());
-                if generics.params.types[param_id.local_id()].is_trait_self() {
+                if generics.params.tocs[param_id.local_id()].is_trait_self() {
                     let trait_ref = TyBuilder::trait_ref(db, trait_id)
                         .fill_with_bound_vars(DebruijnIndex::INNERMOST, 0)
                         .build();
@@ -1235,9 +1241,17 @@ pub(crate) fn generic_defaults_query(
     let generic_params = generics(db.upcast(), def);
 
     let defaults = generic_params
-        .type_iter()
+        .toc_iter()
         .enumerate()
         .map(|(idx, (_, p))| {
+            let p = match p {
+                TypeOrConstParamData::TypeParamData(p) => p,
+                TypeOrConstParamData::ConstParamData(_) => {
+                    // FIXME: here we should add const generic parameters
+                    let ty = TyKind::Error.intern(Interner);
+                    return crate::make_only_type_binders(idx, ty);
+                }
+            };
             let mut ty =
                 p.default.as_ref().map_or(TyKind::Error.intern(Interner), |t| ctx.lower_ty(t));
 
@@ -1269,7 +1283,7 @@ pub(crate) fn generic_defaults_recover(
 
     // we still need one default per parameter
     let defaults = generic_params
-        .type_iter()
+        .toc_iter()
         .enumerate()
         .map(|(idx, _)| {
             let ty = TyKind::Error.intern(Interner);
@@ -1502,7 +1516,7 @@ pub(crate) fn impl_self_ty_query(db: &dyn HirDatabase, impl_id: ImplId) -> Binde
 // 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.types[def.local_id()];
+    let data = &parent_data.tocs[def.local_id()];
     let resolver = def.parent().resolver(db.upcast());
     let ctx = TyLoweringContext::new(db, &resolver);
     match data {
diff --git a/crates/hir_ty/src/tests/regression.rs b/crates/hir_ty/src/tests/regression.rs
index b17e517ccb0..020c5da6804 100644
--- a/crates/hir_ty/src/tests/regression.rs
+++ b/crates/hir_ty/src/tests/regression.rs
@@ -1298,3 +1298,71 @@ impl<I: Iterator> IntoIterator for I {
 "#,
     );
 }
+
+#[test]
+fn bug_11659() {
+    check_infer(
+        r#"
+struct LinkArray<const N: usize, LD>(LD);
+fn f<const N: usize, LD>(x: LD) -> LinkArray<N, LD> {
+    let r = LinkArray::<N, LD>(x);
+    r
+}
+
+fn test() {
+    let x = f::<2, i32>(5);
+    let y = LinkArray::<52, LinkArray<2, i32>>(x);
+}
+        "#,
+        expect![[r#"
+        67..68 'x': LD
+        94..138 '{     ...   r }': LinkArray<{unknown}, LD>
+        104..105 'r': LinkArray<{unknown}, LD>
+        108..126 'LinkAr...N, LD>': LinkArray<{unknown}, LD>(LD) -> LinkArray<{unknown}, LD>
+        108..129 'LinkAr...LD>(x)': LinkArray<{unknown}, LD>
+        127..128 'x': LD
+        135..136 'r': LinkArray<{unknown}, LD>
+        150..232 '{     ...(x); }': ()
+        160..161 'x': LinkArray<{unknown}, {unknown}>
+        164..175 'f::<2, i32>': fn f<i32, i32>(i32) -> LinkArray<{unknown}, {unknown}>
+        164..178 'f::<2, i32>(5)': LinkArray<{unknown}, {unknown}>
+        176..177 '5': i32
+        188..189 'y': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
+        192..226 'LinkAr... i32>>': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>(LinkArray<{unknown}, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
+        192..229 'LinkAr...2>>(x)': LinkArray<LinkArray<i32, {unknown}>, LinkArray<{unknown}, {unknown}>>
+        227..228 'x': LinkArray<{unknown}, {unknown}>
+        "#]],
+    );
+    check_infer(
+        r#"
+struct LinkArray<LD, const N: usize>(LD);
+fn f<const N: usize, LD>(x: LD) -> LinkArray<LD, N> {
+    let r = LinkArray::<LD, N>(x);
+    r
+}
+
+fn test() {
+    let x = f::<i32, 2>(5);
+    let y = LinkArray::<LinkArray<i32, 2>, 52>(x);
+}
+        "#,
+        expect![[r#"
+        67..68 'x': LD
+        94..138 '{     ...   r }': LinkArray<LD, {unknown}>
+        104..105 'r': LinkArray<LD, {unknown}>
+        108..126 'LinkAr...LD, N>': LinkArray<LD, {unknown}>(LD) -> LinkArray<LD, {unknown}>
+        108..129 'LinkAr... N>(x)': LinkArray<LD, {unknown}>
+        127..128 'x': LD
+        135..136 'r': LinkArray<LD, {unknown}>
+        150..232 '{     ...(x); }': ()
+        160..161 'x': LinkArray<i32, {unknown}>
+        164..175 'f::<i32, 2>': fn f<i32, i32>(i32) -> LinkArray<i32, {unknown}>
+        164..178 'f::<i32, 2>(5)': LinkArray<i32, {unknown}>
+        176..177 '5': i32
+        188..189 'y': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
+        192..226 'LinkAr...>, 52>': LinkArray<LinkArray<i32, {unknown}>, {unknown}>(LinkArray<i32, {unknown}>) -> LinkArray<LinkArray<i32, {unknown}>, {unknown}>
+        192..229 'LinkAr...52>(x)': LinkArray<LinkArray<i32, {unknown}>, {unknown}>
+        227..228 'x': LinkArray<i32, {unknown}>
+        "#]],
+    );
+}
diff --git a/crates/hir_ty/src/utils.rs b/crates/hir_ty/src/utils.rs
index cf8e284c627..a6706aa81d5 100644
--- a/crates/hir_ty/src/utils.rs
+++ b/crates/hir_ty/src/utils.rs
@@ -203,12 +203,30 @@ impl Generics {
             )
     }
 
+    pub(crate) fn toc_iter<'a>(
+        &'a self,
+    ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
+        self.parent_generics
+            .as_ref()
+            .into_iter()
+            .flat_map(|it| {
+                it.params
+                    .toc_iter()
+                    .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
+            })
+            .chain(
+                self.params.toc_iter().map(move |(local_id, p)| {
+                    (TypeOrConstParamId { parent: self.def, local_id }, p)
+                }),
+            )
+    }
+
     pub(crate) fn iter_parent<'a>(
         &'a self,
     ) -> impl Iterator<Item = (TypeOrConstParamId, &'a TypeOrConstParamData)> + 'a {
         self.parent_generics.as_ref().into_iter().flat_map(|it| {
             it.params
-                .types
+                .tocs
                 .iter()
                 .map(move |(local_id, p)| (TypeOrConstParamId { parent: it.def, local_id }, p))
         })
@@ -221,36 +239,36 @@ 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());
-        // 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();
+        let child = self.params.tocs.len();
         (parent + child, parent, child)
     }
 
-    /// (parent total, self param, type param list, impl trait)
-    pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize) {
+    /// (parent total, self param, type param list, const param list, impl trait)
+    pub(crate) fn provenance_split(&self) -> (usize, usize, usize, usize, usize) {
         let parent = self.parent_generics.as_ref().map_or(0, |p| p.len());
         let self_params = self
             .params
-            .types
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .filter(|p| p.provenance == TypeParamProvenance::TraitSelf)
             .count();
-        let list_params = self
+        let type_params = self
             .params
-            .types
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .filter(|p| p.provenance == TypeParamProvenance::TypeParamList)
             .count();
+        let const_params = self.params.tocs.iter().filter_map(|x| x.1.const_param()).count();
         let impl_trait_params = self
             .params
-            .types
+            .tocs
             .iter()
             .filter_map(|x| x.1.type_param())
             .filter(|p| p.provenance == TypeParamProvenance::ArgumentImplTrait)
             .count();
-        (parent, self_params, list_params, impl_trait_params)
+        (parent, self_params, type_params, const_params, impl_trait_params)
     }
 
     pub(crate) fn param_idx(&self, param: TypeOrConstParamId) -> Option<usize> {
@@ -261,7 +279,7 @@ impl Generics {
         if param.parent == self.def {
             let (idx, (_local_id, data)) = self
                 .params
-                .types
+                .tocs
                 .iter()
                 .enumerate()
                 .find(|(_, (idx, _))| *idx == param.local_id)
@@ -277,7 +295,7 @@ impl Generics {
     pub(crate) fn bound_vars_subst(&self, debruijn: DebruijnIndex) -> Substitution {
         Substitution::from_iter(
             Interner,
-            self.type_iter()
+            self.toc_iter()
                 .enumerate()
                 .map(|(idx, _)| TyKind::BoundVar(BoundVar::new(debruijn, idx)).intern(Interner)),
         )
@@ -287,7 +305,7 @@ impl Generics {
     pub(crate) fn type_params_subst(&self, db: &dyn HirDatabase) -> Substitution {
         Substitution::from_iter(
             Interner,
-            self.type_iter().map(|(id, _)| {
+            self.toc_iter().map(|(id, _)| {
                 TyKind::Placeholder(crate::to_placeholder_idx(db, id)).intern(Interner)
             }),
         )