Repository: intellij-rust/intellij-rust
Issue: Invalid error: unresolved reference

## Environment

* **Intellij-Rust plugin version: 0.2.0.2422-182-nightly**
* **Rust toolchain version: rustc 1.29.0 (aa3ca1994 2018-09-11)**
* **IDE name and version: IntelliJ IDEA Ultimate 2018.2.3**
* **Operating system: Ubuntu 16.04 LTS**

## Problem description
Invalid error for method invocation of a trait bound to a new name.

## Steps to reproduce
```rust
mod x {
    pub trait X {
        fn x(&self);
    }
    pub struct XS {}
    impl X for XS {
        fn x(&self) {}
    }
}
use x::XS;
use x::X as _X;
impl XS {
    fn y(&self) {
        self.x()
    }
}
fn main() {
}
```
Unresolved reference: `x`


Changed files:
src/main/kotlin/org/rust/ide/inspections/import/AutoImportFix.kt, src/test/kotlin/org/rust/ide/inspections/import/AutoImportFixTest.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/resolve/RsPreciseTraitMatchingTest.kt, src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt, src/main/kotlin/org/rust/lang/core/psi/ext/RsItemElement.kt

diff --git a/src/main/kotlin/org/rust/ide/inspections/import/AutoImportFix.kt b/src/main/kotlin/org/rust/ide/inspections/import/AutoImportFix.kt
index 2835f9b3d..d074e006b 100644
--- a/src/main/kotlin/org/rust/ide/inspections/import/AutoImportFix.kt
+++ b/src/main/kotlin/org/rust/ide/inspections/import/AutoImportFix.kt
@@ -20,7 +20,6 @@ import org.rust.cargo.util.AutoInjectedCrates
 import org.rust.ide.search.RsCargoProjectScope
 import org.rust.lang.core.psi.*
 import org.rust.lang.core.psi.ext.*
-import org.rust.lang.core.resolve.ImplLookup
 import org.rust.lang.core.resolve.TraitImplSource
 import org.rust.lang.core.resolve.ref.MethodResolveVariant
 import org.rust.lang.core.resolve.ref.deepResolve
@@ -217,16 +216,13 @@ class AutoImportFix(element: RsElement) : LocalQuickFixOnPsiElement(element), Hi
             methodCall: RsMethodCall,
             resolveResults: List<MethodResolveVariant>
         ): List<RsTraitItem>? {
-            val lookup = ImplLookup.relativeTo(methodCall)
-
-            val traitsToImport = mutableListOf<RsTraitItem>()
-            loop@ for (variant in resolveResults) {
+            val traits = resolveResults.mapNotNull { variant ->
                 val source = variant.source
                 val trait = when (source) {
                     is TraitImplSource.ExplicitImpl -> {
                         val impl = source.value
                         if (impl.traitRef == null) return null
-                        impl.traitRef?.resolveToTrait ?: continue@loop
+                        impl.traitRef?.resolveToTrait ?: return@mapNotNull null
                     }
                     is TraitImplSource.Derived -> source.value
                     is TraitImplSource.Collapsed -> source.value
@@ -236,10 +232,9 @@ class AutoImportFix(element: RsElement) : LocalQuickFixOnPsiElement(element), Hi
                     is TraitImplSource.Object -> return null
                 }
 
-                if (lookup.isTraitVisibleFrom(trait, methodCall)) return null
-                traitsToImport += trait
+                trait
             }
-            return traitsToImport
+            return if (traits.filterInScope(methodCall).isNotEmpty()) null else traits
         }
 
         // Semantic signature of method is `ImportItem.canBeImported(mod: RsMod)`
diff --git a/src/main/kotlin/org/rust/lang/core/psi/ext/RsItemElement.kt b/src/main/kotlin/org/rust/lang/core/psi/ext/RsItemElement.kt
index 42434f65a..f30215f84 100644
--- a/src/main/kotlin/org/rust/lang/core/psi/ext/RsItemElement.kt
+++ b/src/main/kotlin/org/rust/lang/core/psi/ext/RsItemElement.kt
@@ -6,5 +6,16 @@
 package org.rust.lang.core.psi.ext
 
 import org.rust.lang.core.macros.RsExpandedElement
+import org.rust.lang.core.resolve.TYPES
+import org.rust.lang.core.resolve.processNestedScopesUpwards
 
 interface RsItemElement : RsVisibilityOwner, RsOuterAttributeOwner, RsExpandedElement
+
+fun <T : RsItemElement> Iterable<T>.filterInScope(scope: RsElement): List<T> {
+    val set = toMutableSet()
+    processNestedScopesUpwards(scope, {
+        set.remove(it.element)
+        set.isEmpty()
+    }, TYPES)
+    return if (set.isEmpty()) toList() else toMutableList().apply { removeAll(set) }
+}
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 b1e30f77d..fb994cc16 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/ImplLookup.kt
@@ -13,7 +13,6 @@ import org.rust.lang.core.psi.RsTypeAlias
 import org.rust.lang.core.psi.ext.*
 import org.rust.lang.core.resolve.indexes.RsImplIndex
 import org.rust.lang.core.resolve.indexes.RsLangItemIndex
-import org.rust.lang.core.resolve.ref.resolvePath
 import org.rust.lang.core.types.*
 import org.rust.lang.core.types.infer.*
 import org.rust.lang.core.types.ty.*
@@ -693,12 +692,6 @@ class ImplLookup(
             return TyFunction(argumentTypes, outputType)
         }
 
-    fun isTraitVisibleFrom(trait: RsTraitItem, scope: RsElement): Boolean {
-        val name = trait.name ?: return true
-        val path = codeFragmentFactory.createPath(name, scope) ?: return true
-        return resolvePath(path, this).any { it.element == trait }
-    }
-
     companion object {
         fun relativeTo(psi: RsElement): ImplLookup =
             ImplLookup(psi.project, StdKnownItems.relativeTo(psi))
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 9a3e20898..837f58d2b 100644
--- a/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
+++ b/src/main/kotlin/org/rust/lang/core/resolve/NameResolution.kt
@@ -853,14 +853,14 @@ private fun processLexicalDeclarations(
     return false
 }
 
-private fun processNestedScopesUpwards(
+fun processNestedScopesUpwards(
     scopeStart: RsElement,
     processor: RsResolveProcessor,
     ns: Set<Namespace>,
     withPlainExternCrateItems: Boolean = true
 ): Boolean {
     val prevScope = mutableSetOf<String>()
-    walkUp(scopeStart, { it is RsMod }) { cameFrom, scope ->
+    if (walkUp(scopeStart, { it is RsMod }) { cameFrom, scope ->
         val currScope = mutableListOf<String>()
         val shadowingProcessor = { e: ScopeEntry ->
             e.name !in prevScope && run {
@@ -871,6 +871,8 @@ private fun processNestedScopesUpwards(
         if (processLexicalDeclarations(scope, cameFrom, ns, withPlainExternCrateItems, shadowingProcessor)) return@walkUp true
         prevScope.addAll(currScope)
         false
+    }) {
+        return true
     }
 
     val prelude = findPrelude(scopeStart)
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 5001200b3..e75766275 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
@@ -1124,12 +1124,23 @@ class RsFnInferenceContext(
     }
 
     private fun pickSingleMethod(receiver: Ty, variants: List<MethodResolveVariant>, methodCall: RsMethodCall): MethodResolveVariant? {
-        val filtered = variants.singleOrFilter {
+        val filtered = variants.singleOrLet { list ->
             // 1. filter traits that are not imported
             TypeInferenceMarks.methodPickTraitScope.hit()
-            val trait = it.source.impl?.traitRef?.path?.reference?.resolve() as? RsTraitItem
-                ?: return@singleOrFilter true
-            lookup.isTraitVisibleFrom(trait, methodCall)
+            val traitToCallee = hashMapOf<RsTraitItem, MutableList<MethodResolveVariant>>()
+            val filtered = mutableListOf<MethodResolveVariant>()
+            for (callee in list) {
+                val trait = callee.source.impl?.traitRef?.resolveToTrait
+                if (trait != null) {
+                    traitToCallee.getOrPut(trait) { mutableListOf() }.add(callee)
+                } else {
+                    filtered.add(callee) // inherent impl
+                }
+            }
+            traitToCallee.keys.filterInScope(methodCall).forEach {
+                filtered += traitToCallee.getValue(it)
+            }
+            filtered
         }.singleOrFilter { callee ->
             // 2. Filter methods by trait bounds (try to select all obligations for each impl)
             TypeInferenceMarks.methodPickCheckBounds.hit()
diff --git a/src/test/kotlin/org/rust/ide/inspections/import/AutoImportFixTest.kt b/src/test/kotlin/org/rust/ide/inspections/import/AutoImportFixTest.kt
index 5b17ac6ee..1759016cf 100644
--- a/src/test/kotlin/org/rust/ide/inspections/import/AutoImportFixTest.kt
+++ b/src/test/kotlin/org/rust/ide/inspections/import/AutoImportFixTest.kt
@@ -1305,6 +1305,23 @@ class AutoImportFixTest : AutoImportFixTestBase() {
         }
     """)
 
+    /** Issue [2863](https://github.com/intellij-rust/intellij-rust/issues/2863) */
+    fun `test do not try to import aliased trait`() = checkAutoImportFixIsUnavailable("""
+        mod foo {
+            pub trait Foo {
+                fn foo(&self) {}
+            }
+
+            impl<T> Foo for T {}
+        }
+
+        use foo::Foo as _Foo;
+
+        fn main() {
+            123.foo/*caret*/();
+        }
+    """)
+
     @MockEdition(CargoWorkspace.Edition.EDITION_2018)
     fun `test import item in root module (edition 2018)`() = checkAutoImportFixByText("""
         mod foo {
diff --git a/src/test/kotlin/org/rust/lang/core/resolve/RsPreciseTraitMatchingTest.kt b/src/test/kotlin/org/rust/lang/core/resolve/RsPreciseTraitMatchingTest.kt
index 758709274..496cc79c9 100644
--- a/src/test/kotlin/org/rust/lang/core/resolve/RsPreciseTraitMatchingTest.kt
+++ b/src/test/kotlin/org/rust/lang/core/resolve/RsPreciseTraitMatchingTest.kt
@@ -231,6 +231,28 @@ class RsPreciseTraitMatchingTest : RsResolveTestBase() {
         }   //^
     """, TypeInferenceMarks.methodPickTraitScope)
 
+    fun `test method defined in out of scope trait (with aliased import)`() = checkByCode("""
+        struct S;
+
+        mod a {
+            use super::S;
+            pub trait A { fn foo(&self){} }
+                           //X
+            impl A for S {}
+        }
+
+        mod b {
+            use super::S;
+            pub trait B { fn foo(&self){} }
+            impl B for S {}
+        }
+
+        fn main() {
+            use a::A as _A;
+            S.foo();
+        }   //^
+    """, TypeInferenceMarks.methodPickTraitScope)
+
     fun `test specialization simple`() = checkByCode("""
         trait Tr { fn foo(&self); }
         struct S;