Repository: intellij-rust/intellij-rust
Issue: Types of components in hecs query are not deduced

<!--
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.155.4114-212
* **Rust toolchain version:** 1.55.0 (c8dfcfe04 2021-09-06) aarch64-apple-darwin
* **IDE name and version:** CLion 2021.2.2 (CL-212.5284.51)
* **Operating system:** macOS 11.5.2
* **Macro expansion engine:** new
* **Name resolution engine:** new

## Problem description

I am using the `hecs` crate with v0.6.5 and noticed that CLion unlike VSCode with rust-analyzer is not able to deduce the type of components when using the `hecs` query API.

## Steps to reproduce
```rust
fn main() {
    let mut world = hecs::World::new();
    for (entity, (component1, component2)) in world.query::<(&i32, &bool)>().iter() {}
}
```

In the above snippet `component1` and `component2` are of unknown type to CLion which is unexpected. Using structs instead of `i32` or `bool` makes it inconvenient to access members of the components:

```rust
pub struct Component {
    pub value: i32,
}

fn main() {
    let mut world = hecs::World::new();
    for (entity, (component1, component2)) in world.query::<(&i32, &Component)>().iter() {
        component2. // no code-completion since component2 is of unknown type
    }
}
```

<!--
Please include as much of your codebase as needed to reproduce the error.
If the relevant files are large, please provide a link to a public repository or a [Gist](https://gist.github.com/).
-->

Changed files:
src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt, src/test/kotlin/org/rust/lang/core/resolve/RsTypeAwareResolveTest.kt

diff --git a/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt b/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
index 5580bc358..3e1ddb4e3 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
@@ -597,6 +597,7 @@ private fun processTypeQualifiedPathResolveVariants(
 ): Boolean {
     @Suppress("NAME_SHADOWING")
     val lookup = lookup ?: ImplLookup.relativeTo(path)
+    var hasAppropriateTrait = false
     val shadowingProcessor = if (restrictedTraits != null) {
         createProcessorGeneric<AssocItemScopeEntry>(processor.name) { e ->
             if (e.element !is RsTypeAlias) return@createProcessorGeneric processor(e)
@@ -609,6 +610,7 @@ private fun processTypeQualifiedPathResolveVariants(
             val isAppropriateTrait = restrictedTraits.any {
                 lookup.ctx.probe { lookup.ctx.combineBoundElements(it, implementedTrait) }
             }
+            hasAppropriateTrait = hasAppropriateTrait || isAppropriateTrait
             if (isAppropriateTrait) processor(e) else false
         }
     } else {
@@ -628,6 +630,17 @@ private fun processTypeQualifiedPathResolveVariants(
         emptySubstitution
     }
     if (processAssociatedItemsWithSelfSubst(lookup, path, baseTy, ns, selfSubst, shadowingProcessor)) return true
+
+    // For `Item` in `type Alias<T> = <T as Trait>::Item;`, process members of `Trait`
+    if (!hasAppropriateTrait && restrictedTraits != null && restrictedTraits.size == 1 && Namespace.Types in ns) {
+        val trait = restrictedTraits.single()
+        val source = TraitImplSource.TraitBound(trait.element, isInherent = baseTy is TyTypeParameter)
+        val result = trait.element.members?.expandedMembers?.any {
+            val name = it.name ?: return@any false
+            processor(AssocItemScopeEntry(name, it, trait.subst + selfSubst, baseTy, source))
+        }
+        if (result == true) return true
+    }
     return false
 }
 
diff --git a/src/test/kotlin/org/rust/lang/core/resolve/RsTypeAwareResolveTest.kt b/src/test/kotlin/org/rust/lang/core/resolve/RsTypeAwareResolveTest.kt
index 4d6aa1851..b2d4d0f98 100644
--- a/src/test/kotlin/org/rust/lang/core/resolve/RsTypeAwareResolveTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/resolve/RsTypeAwareResolveTest.kt
@@ -864,4 +864,47 @@ class RsTypeAwareResolveTest : RsResolveTestBase() {
             X.foo();
         }   //^
     """)
+
+    fun `test non-UFCS associated type in type alias with bound`() = checkByCode("""
+        trait Trait {
+            type Item;
+        }      //X
+        type Alias<T: Trait> = T::Item;
+                                //^
+    """)
+
+    fun `test associated type in type alias with bound`() = checkByCode("""
+        trait Trait {
+            type Item;
+        }      //X
+        type Alias<T: Trait> = <T as Trait>::Item;
+                                           //^
+    """)
+
+    fun `test associated type in type alias without bound`() = checkByCode("""
+        trait Trait {
+            type Item;
+        }      //X
+        type Alias<T> = <T as Trait>::Item;
+                                    //^
+    """)
+
+    fun `test nested associated type in type alias without bound`() = checkByCode("""
+        trait Trait {
+            type Item;
+        }      //X
+        type Alias1<Q> = <<Q as Trait>::Item as Trait>::Item;
+                                                      //^
+    """)
+
+    fun `test nested associated type in type alias without bound 2`() = checkByCode("""
+        trait Trait {
+            type Item: Trait2;
+        }
+        trait Trait2 {
+            type Item;
+        }      //X
+        type Alias1<Q> = <<Q as Trait>::Item as Trait2>::Item;
+                                                       //^
+    """)
 }