Repository: intellij-rust/intellij-rust
Issue: Parameter info doesn't show cosnt generic parameters

<!--
Hello and thank you for the issue!
If you would like to report a bug, we have added some points below that you can fill out.
Feel free to remove all the irrelevant text to request a new feature.
-->

## Environment

* **IntelliJ Rust plugin version:** 0.4.152.3998-211-nightly
* **Rust toolchain version:** 1.53.0 (53cb7b09b 2021-06-17) x86_64-unknown-linux-gnu
* **IDE name and version:** CLion 2021.1.3 (CL-211.7628.27)
* **Operating system:** Linux 5.4.0-77-generic
* **Macro expansion engine:** new
* **Name resolution engine:** new

## Problem description

Parameter info in const generic argument lists doesn't show the const generics. 

```rust
struct Foo<const N: usize>;
type Bar = Foo</*caret*/>;
```

Invoke "Parameter Info" (Ctrl+P): no parameter hint is shown. Expected: `N` or `const N`.

If some type generic parameters are present, they are show but the const generic parameters are omitted.

```rust
struct Foo<T, const N: usize>;
type Bar = Foo</*caret*/>;
```

Invoke "Parameter Info" (Ctrl+P): hint shows `T`. Expected: `T, N` or `T, const N`.

Changed files:
src/main/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandler.kt
src/test/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandlerTest.kt

diff --git a/src/main/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandler.kt b/src/main/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandler.kt
index b90439bfa..7a066086b 100644
--- a/src/main/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandler.kt
+++ b/src/main/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandler.kt
@@ -12,6 +12,9 @@ import com.intellij.lang.parameterInfo.UpdateParameterInfoContext
 import com.intellij.openapi.util.TextRange
 import com.intellij.psi.PsiFile
 import com.intellij.util.containers.nullize
+import org.rust.ide.presentation.PsiRenderingOptions
+import org.rust.ide.presentation.RsPsiRenderer
+import org.rust.ide.presentation.renderTypeReference
 import org.rust.lang.core.psi.*
 import org.rust.lang.core.psi.ext.*
 
@@ -28,8 +31,11 @@ class RsGenericParameterInfoHandler : RsAsyncParameterInfoHandler<RsTypeArgument
         } else {
             return null
         }
-        val typesWithBounds = genericDeclaration.typeParameters.nullize() ?: return null
-        return listOfNotNull(firstLine(typesWithBounds), secondLine(typesWithBounds)).toTypedArray()
+        val paramsWithBounds = genericDeclaration
+            .genericParameters
+            .filterNot { it is RsLifetimeParameter }
+            .nullize() ?: return null
+        return listOfNotNull(firstLine(paramsWithBounds), secondLine(paramsWithBounds)).toTypedArray()
     }
 
     override fun showParameterInfo(element: RsTypeArgumentList, context: CreateParameterInfoContext) {
@@ -80,16 +86,26 @@ class HintLine(
 /**
  * Calculates the text representation and ranges for parameters
  */
-private fun firstLine(params: List<RsTypeParameter>): HintLine {
+private fun firstLine(params: List<RsGenericParameter>): HintLine {
+    val renderer = RsPsiRenderer(PsiRenderingOptions(renderLifetimes = false))
     val splited = params.map { param ->
-        param.name ?: return@map ""
-        val qSizedBound = if (!param.isSized) listOf("?Sized") else emptyList()
-        val declaredBounds = param.bounds
-            // `?Sized`, if needed, in separate val, `Sized` shouldn't be shown
-            .filter { it.bound.traitRef?.resolveToBoundTrait()?.element?.isSizedTrait == false }
-            .mapNotNull { it.bound.traitRef?.path?.text }
-        val allBounds = qSizedBound + declaredBounds
-        param.name + (allBounds.nullize()?.joinToString(prefix = ": ", separator = " + ") ?: "")
+        when (param) {
+            is RsTypeParameter -> {
+                param.name ?: return@map ""
+                val qSizedBound = if (!param.isSized) listOf("?Sized") else emptyList()
+                val declaredBounds = param.bounds
+                    // `?Sized`, if needed, in separate val, `Sized` shouldn't be shown
+                    .filter { it.bound.traitRef?.resolveToBoundTrait()?.element?.isSizedTrait == false }
+                    .mapNotNull { it.bound.traitRef?.path?.text }
+                val allBounds = qSizedBound + declaredBounds
+                param.name + (allBounds.nullize()?.joinToString(prefix = ": ", separator = " + ") ?: "")
+            }
+            is RsConstParameter -> {
+                val typeReference = param.typeReference?.let { ": ${renderer.renderTypeReference(it)}" } ?: ""
+                "const ${param.name ?: "_"}$typeReference"
+            }
+            else -> error("unreachable")
+        }
     }
     return HintLine(splited.joinToString(), splited.indices.map { splited.calculateRange(it) })
 }
@@ -98,7 +114,7 @@ private fun firstLine(params: List<RsTypeParameter>): HintLine {
  * Not null, when complicated parts of where exists,
  * i.e. `where i32: SomeTrait<T>` or `where Option<T>: SomeTrait`
  */
-private fun secondLine(params: List<RsTypeParameter>): HintLine? {
+private fun secondLine(params: List<RsGenericParameter>): HintLine? {
     val owner = params.getOrNull(0)?.parent?.parent as? RsGenericDeclaration
     val wherePreds = owner?.whereClause?.wherePredList.orEmpty()
         // retain specific preds
diff --git a/src/test/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandlerTest.kt b/src/test/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandlerTest.kt
index 3bb286ade..2da25495d 100644
--- a/src/test/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandlerTest.kt
+++ b/src/test/kotlin/org/rust/ide/hints/parameter/RsGenericParameterInfoHandlerTest.kt
@@ -43,6 +43,11 @@ class RsGenericParameterInfoHandlerTest
         fn main() { foo::<i32,/*caret*/>(); }
     """, "T, P", "", 1)
 
+    fun `test fn const param`() = checkByText("""
+        fn foo<T, const P: usize>(x: T) {}
+        fn main() { foo::<i32,/*caret*/>(); }
+    """, "T, const P: usize", "", 1)
+
     fun `test fn param out of bounds`() = checkByText("""
         fn foo<T>(x: T) {}
         fn main() { foo::<i32, /*caret*/>(); }