Repository: intellij-rust/intellij-rust
Issue: Completion issues with `twitter_v2` crate

## Environment

* **IntelliJ Rust plugin version:** 0.4.179.4882-222-nightly
* **Rust toolchain version:** 1.64.0 (a55dd71d5 2022-09-19) x86_64-unknown-linux-gnu
* **IDE name and version:** IntelliJ IDEA 2022.2.1 Ultimate Edition (IU-222.3739.54)
* **Operating system:** Linux 5.15.0-48-generic
* **Macro expansion:** enabled
* **Additional experimental features:** org.rust.cargo.emulate.terminal, org.rust.cargo.evaluate.build.scripts, org.rust.macros.proc

## Steps to reproduce

1. Create the sample project:

```toml
[dependencies]
twitter-v2 = "0.1.7"
```

```rust
// main.rs
use twitter_v2::authorization::{BearerToken, Oauth1aToken};
use twitter_v2::TwitterApi;

fn main() {
    let auth = BearerToken::new(std::env::var("APP_BEARER_TOKEN").unwrap());
    // let auth = Oauth1aToken::new("", "", "", "");
    let tweet = TwitterApi::new(auth)./*caret*/
}
```

2. Invoke completion at /*caret*/
3. See a many completion variants
4. Then uncomment `let auth = Oauth1aToken::new("", "", "", "");`
5. Invoke completion at `/*caret*/` again
6. See much less completion variants. But expected the same number of variants

Changed files:
src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt, src/main/kotlin/org/rust/lang/core/types/Substitution.kt, src/main/kotlin/org/rust/lang/core/types/infer/TyLowering.kt, src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt

diff --git a/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt b/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt
index 6ee104e7a..1db1fff2d 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/ref/RsPathReferenceImpl.kt
@@ -419,8 +419,8 @@ fun pathPsiSubst(
         }
     }
 
-    val typeSubst = hashMapOf<RsTypeParameter, Value<TypeValue, TypeDefault>>()
-    val constSubst = hashMapOf<RsConstParameter, Value<RsElement, RsExpr>>()
+    val typeSubst = linkedMapOf<RsTypeParameter, Value<TypeValue, TypeDefault>>()
+    val constSubst = linkedMapOf<RsConstParameter, Value<RsElement, RsExpr>>()
 
     for ((k, v) in typeOrConstSubst) {
         when (k) {
diff --git a/src/main/kotlin/org/rust/lang/core/types/Substitution.kt b/src/main/kotlin/org/rust/lang/core/types/Substitution.kt
index 89cce1e7e..427567fb5 100644
--- a/src/main/kotlin/org/rust/lang/core/types/Substitution.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/Substitution.kt
@@ -114,6 +114,7 @@ private object EmptySubstitution : Substitution()
 val emptySubstitution: Substitution = EmptySubstitution
 
 fun Map<TyTypeParameter, Ty>.toTypeSubst(): Substitution = Substitution(typeSubst = this)
+fun Map<CtConstParameter, Const>.toConstSubst(): Substitution = Substitution(constSubst = this)
 
 private fun <K, V> mergeMaps(map1: Map<K, V>, map2: Map<K, V>): Map<K, V> =
     when {
diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TyLowering.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TyLowering.kt
index 1b6996509..cd23d40d4 100644
--- a/src/main/kotlin/org/rust/lang/core/types/infer/TyLowering.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/infer/TyLowering.kt
@@ -195,7 +195,8 @@ class TyLowering private constructor(
         val genericParameters = genericParametersCache.getOrPut(element) { element.getGenericParameters() }
         val psiSubstitution = pathPsiSubst(path, element, givenGenericParameters = genericParameters)
 
-        val typeSubst = psiSubstitution.typeSubst.entries.associate { (param, value) ->
+        val typeSubst = hashMapOf<TyTypeParameter, Ty>()
+        for ((param, value) in psiSubstitution.typeSubst.entries) {
             val paramTy = TyTypeParameter.named(param)
             val valueTy = when (value) {
                 is RsPsiSubstitution.Value.DefaultValue -> {
@@ -207,8 +208,9 @@ class TyLowering private constructor(
                         defaultValueTy.substitute(mapOf(TyTypeParameter.self() to value.value.selfTy).toTypeSubst())
                     } else {
                         defaultValueTy
-                    }
+                    }.substitute(typeSubst.toTypeSubst())
                 }
+
                 is RsPsiSubstitution.Value.OptionalAbsent -> paramTy
                 is RsPsiSubstitution.Value.Present -> when (value.value) {
                     is RsPsiSubstitution.TypeValue.InAngles -> lowerTy(value.value.value, null)
@@ -218,9 +220,10 @@ class TyLowering private constructor(
                         TyUnit.INSTANCE
                     }
                 }
+
                 RsPsiSubstitution.Value.RequiredAbsent -> TyUnknown
             }
-            paramTy to valueTy
+            typeSubst[paramTy] = valueTy
         }
 
         val regionSubst = psiSubstitution.regionSubst.entries.mapNotNull { (psiParam, psiValue) ->
@@ -234,7 +237,8 @@ class TyLowering private constructor(
             param to value
         }.toMap()
 
-        val constSubst = psiSubstitution.constSubst.entries.associate { (psiParam, psiValue) ->
+        val constSubst = hashMapOf<CtConstParameter, Const>()
+        psiSubstitution.constSubst.entries.forEach { (psiParam, psiValue) ->
             val param = CtConstParameter(psiParam)
             val value = when (psiValue) {
                 RsPsiSubstitution.Value.OptionalAbsent -> param
@@ -245,11 +249,11 @@ class TyLowering private constructor(
                 }
                 is RsPsiSubstitution.Value.DefaultValue -> {
                     val expectedTy = psiParam.typeReference?.normType ?: TyUnknown
-                    psiValue.value.toConst(expectedTy, resolver)
+                    psiValue.value.toConst(expectedTy, resolver).substitute(constSubst.toConstSubst())
                 }
             }
 
-            param to value
+            constSubst[param] = value
         }
 
         val newSubst = Substitution(typeSubst, regionSubst, constSubst)
diff --git a/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
index 6966fc368..38fa8916d 100644
--- a/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/type/RsTypeResolvingTest.kt
@@ -633,6 +633,33 @@ class RsTypeResolvingTest : RsTypificationTestBase() {
                //^ <<unknown> as Trait<<unknown>>>::Item
     """)
 
+    fun `test default type argument refers to another type parameter 1`() = testType("""
+        struct Foo;
+        struct Bar<A = Foo, B = A>(A, B);
+        type T = Bar;
+               //^ Bar<Foo, Foo>
+    """)
+
+    fun `test default type argument refers to another type parameter 2`() = testType("""
+        struct Foo;
+        struct Bar<A = Foo, B = A>(A, B);
+        struct Baz;
+        type T = Bar<Baz>;
+               //^ Bar<Baz, Baz>
+    """)
+
+    fun `test default const argument refers to another const parameter 1`() = testType("""
+        struct Bar<const A: i32 = 1, const B: i32 = A>();
+        type T = Bar;
+               //^ Bar<1, 1>
+    """)
+
+    fun `test default const argument refers to another const parameter 2`() = testType("""
+        struct Bar<const A: i32 = 1, const B: i32 = A>();
+        type T = Bar<2>;
+               //^ Bar<2, 2>
+    """)
+
     /**
      * Checks the type of the element in [code] pointed to by `//^` marker.
      */