Repository: intellij-rust/intellij-rust
Issue: No type inference

<!--
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.2.107.2137-192
* **Rust toolchain version:** 1.38
* **IDE name and version:** PyCharm Community 2019.2
* **Operating system:** Windows 10 x64

## Problem description
No type inference in such code

## Steps to reproduce
```rust
fn main() -> Result<(), &'static str> {
    let array = [Err("fail"), Ok(1)];
    let result = array.iter().cloned().collect::<Result<Vec<_>, _>>()?;
    result. // <-- no autocomplete here
    Ok(())
}
```
<!--
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/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt, src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt, src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt, src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt

diff --git a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
index 73d5a2d78..0d47ccb7a 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
@@ -731,7 +731,7 @@ class ImplLookup(
                     .mapTypeValues { (_, v) -> ctx.resolveTypeVarsIfPossible(v) }
                     .mapConstValues { (_, v) -> ctx.resolveTypeVarsIfPossible(v) } +
                     mapOf(TyTypeParameter.self() to ref.selfTy).toTypeSubst()
-                val obligations = ctx.instantiateBounds(candidate.impl.bounds, candidateSubst, newRecDepth).toList()
+                val obligations = ctx.instantiateBounds(candidate.impl.predicates, candidateSubst, newRecDepth).toList()
                 Selection(candidate.impl, obligations, candidateSubst)
             }
             is SelectionCandidate.DerivedTrait -> {
diff --git a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
index ddf9f730b..f5b6a3acc 100644
--- a/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
+++ b/src/main/kotlin/org/rust/lang/core/types/infer/TypeInference.kt
@@ -766,14 +766,14 @@ class RsInferenceContext(
         varUnificationTable.findRoot(ty) != ty || varUnificationTable.findValue(ty) != null
 
     fun instantiateBounds(
-        bounds: List<TraitRef>,
+        bounds: List<Predicate>,
         subst: Substitution = emptySubstitution,
         recursionDepth: Int = 0
     ): Sequence<Obligation> {
         return bounds.asSequence()
             .map { it.substitute(subst) }
             .map { normalizeAssociatedTypesIn(it, recursionDepth) }
-            .flatMap { it.obligations.asSequence() + Obligation(recursionDepth, Predicate.Trait(it.value)) }
+            .flatMap { it.obligations.asSequence() + Obligation(recursionDepth, it.value) }
     }
 
     fun instantiateBounds(
@@ -791,7 +791,7 @@ class RsInferenceContext(
                 .associateWith { constVarForParam(it) }
             subst + Substitution(typeSubst = typeSubst, constSubst = constSubst)
         }
-        instantiateBounds(element.bounds, map).forEach(fulfill::registerPredicateObligation)
+        instantiateBounds(element.predicates, map).forEach(fulfill::registerPredicateObligation)
         return map
     }
 
@@ -815,7 +815,7 @@ class RsInferenceContext(
             constSubst = impl.constGenerics.associateWith { constVarForParam(it) }
         )
         return probe {
-            instantiateBounds(impl.bounds, subst).forEach(ff::registerPredicateObligation)
+            instantiateBounds(impl.predicates, subst).forEach(ff::registerPredicateObligation)
             impl.typeReference?.type?.substitute(subst)?.let { combineTypes(selfTy, it) }
             ff.selectUntilError()
         }
@@ -887,46 +887,57 @@ val RsGenericDeclaration.constGenerics: List<CtConstParameter>
     get() = constParameters.map { CtConstParameter(it) }
 
 val RsGenericDeclaration.bounds: List<TraitRef>
+    get() = predicates.mapNotNull { (it as? Predicate.Trait)?.trait }
+
+val RsGenericDeclaration.predicates: List<Predicate>
     get() = CachedValuesManager.getCachedValue(this) {
         CachedValueProvider.Result.create(
-            doGetBounds(),
+            doGetPredicates(),
             rustStructureOrAnyPsiModificationTracker
         )
     }
 
-private fun RsGenericDeclaration.doGetBounds(): List<TraitRef> {
+private fun RsGenericDeclaration.doGetPredicates(): List<Predicate> {
     val whereBounds = whereClause?.wherePredList.orEmpty().asSequence()
         .flatMap {
-            val selfTy = it.typeReference?.type ?: return@flatMap emptySequence<TraitRef>()
-            it.typeParamBounds?.polyboundList.toTraitRefs(selfTy)
+            val selfTy = it.typeReference?.type ?: return@flatMap emptySequence<Predicate>()
+            it.typeParamBounds?.polyboundList.toPredicates(selfTy)
         }
     val bounds = typeParameters.asSequence().flatMap {
         val selfTy = TyTypeParameter.named(it)
-        it.typeParamBounds?.polyboundList.toTraitRefs(selfTy)
+        it.typeParamBounds?.polyboundList.toPredicates(selfTy)
     }
     val assocTypeBounds = if (this is RsTraitItem) {
-        expandedMembers.types.asSequence().flatMap { it.typeParamBounds?.polyboundList.toTraitRefs(it.declaredType) }
+        expandedMembers.types.asSequence().flatMap { it.typeParamBounds?.polyboundList.toPredicates(it.declaredType) }
     } else {
         emptySequence()
     }
     return (bounds + whereBounds + assocTypeBounds).toList()
 }
 
-private fun List<RsPolybound>?.toTraitRefs(selfTy: Ty): Sequence<TraitRef> = orEmpty().asSequence()
+private fun List<RsPolybound>?.toPredicates(selfTy: Ty): Sequence<Predicate> = orEmpty().asSequence()
     .filter { !it.hasQ } // ignore `?Sized`
     .flatMap { bound ->
-        val traitRef = bound.bound.traitRef ?: return@flatMap emptySequence<TraitRef>()
-        val boundTrait = traitRef.resolveToBoundTrait() ?: return@flatMap emptySequence<TraitRef>()
+        val traitRef = bound.bound.traitRef ?: return@flatMap emptySequence<Predicate>()
+        val boundTrait = traitRef.resolveToBoundTrait() ?: return@flatMap emptySequence<Predicate>()
 
-        // T: Iterator<Item: Debug>
-        //             ~~~~~~~~~~~ equivalent to `<T as Iterator>::Item: Debug`
         val assocTypeBounds = traitRef.path.typeArgumentList?.assocTypeBindingList.orEmpty().asSequence()
-            .filter { it.typeReference == null }
             .flatMap nestedFlatMap@{
-                val assoc = it.reference.resolve() as? RsTypeAlias ?: return@nestedFlatMap emptySequence<TraitRef>()
-                it.polyboundList.toTraitRefs(TyProjection.valueOf(selfTy, assoc))
+                val assoc = it.reference.resolve() as? RsTypeAlias
+                    ?: return@nestedFlatMap emptySequence<Predicate>()
+                val projectionTy = TyProjection.valueOf(selfTy, assoc)
+                val typeRef = it.typeReference
+                if (typeRef != null) {
+                    // T: Iterator<Item = Foo>
+                    //             ~~~~~~~~~~ expands to predicate `T::Item = Foo`
+                    sequenceOf(Predicate.Equate(projectionTy, typeRef.type))
+                } else {
+                    // T: Iterator<Item: Debug>
+                    //             ~~~~~~~~~~~ equivalent to `T::Item: Debug`
+                    it.polyboundList.toPredicates(projectionTy)
+                }
             }
-        sequenceOf(TraitRef(selfTy, boundTrait)) + assocTypeBounds
+        sequenceOf(Predicate.Trait(TraitRef(selfTy, boundTrait))) + assocTypeBounds
     }
 
 
diff --git a/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt
index 27b1e8553..360f41259 100644
--- a/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/type/RsGenericExpressionTypeInferenceTest.kt
@@ -1838,4 +1838,17 @@ class RsGenericExpressionTypeInferenceTest : RsTypificationTestBase() {
             a;
         } //^ X
     """)
+
+    fun `test infer type parameter from associated type binding`() = testExpr("""
+        trait Foo { type Item; }
+        fn foo<A, B>(a: A) -> B where A: Foo<Item = B> { unimplemented!() }
+
+        struct S;
+        impl Foo for S { type Item = i32; }
+
+        fn main() {
+            let a = foo(S);
+            a;
+        } //^ i32
+    """)
 }
diff --git a/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt b/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt
index 8a6835f71..0619479e3 100644
--- a/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/type/RsStdlibExpressionTypeInferenceTest.kt
@@ -550,6 +550,16 @@ class RsStdlibExpressionTypeInferenceTest : RsTypificationTestBase() {
         }
     """)
 
+    fun `test iterator cloned`() = stubOnlyTypeInfer("""
+    //- main.rs
+        fn main() {
+            let a = vec![1, 2].iter()
+                .cloned()
+                .next();
+            a;
+        } //^ Option<i32>
+    """)
+
     fun `test vec push`() = stubOnlyTypeInfer("""
     //- main.rs
         use std::vec::Vec;