Repository: rust-analyzer/rust-analyzer (rust)

Issue:
Associated types are not resolved in the IDE layer
Like the `T::S` here:

```rust
trait D {}

trait Foo {
    type S;
}

trait Bar<T>
where
    T: Foo,
    T::S: D,
{
}

fn main() {}
```

CC #4991

Another one:

```rust
trait Foo {
    type Bar;

    fn foo(_: Self::Bar);
}

struct S;

impl Foo for S {
    type Bar = i32;

    fn foo(_: Self::Bar) {
        todo!()
    }
}
```

Pull request:
Resolve associated types
Prior we were only resolving paths until the first type was found, then discarding the result if the path wasn't fully consumed. That of course causes associated types to not resolve. Fixes #5003

Patch:
diff --git a/crates/hir/src/semantics.rs b/crates/hir/src/semantics.rs
index d3caeef4ee..3bf722d2a7 100644
--- a/crates/hir/src/semantics.rs
+++ b/crates/hir/src/semantics.rs
@@ -76,9 +76,11 @@ impl PathResolution {
     pub fn assoc_type_shorthand_candidates<R>(
         &self,
         db: &dyn HirDatabase,
-        mut cb: impl FnMut(TypeAlias) -> Option<R>,
+        mut cb: impl FnMut(&Name, TypeAlias) -> Option<R>,
     ) -> Option<R> {
-        associated_type_shorthand_candidates(db, self.in_type_ns()?, |_, _, id| cb(id.into()))
+        associated_type_shorthand_candidates(db, self.in_type_ns()?, |name, _, id| {
+            cb(name, id.into())
+        })
     }
 }
 
diff --git a/crates/hir/src/source_analyzer.rs b/crates/hir/src/source_analyzer.rs
index 37d162b328..8e9ea0a038 100644
--- a/crates/hir/src/source_analyzer.rs
+++ b/crates/hir/src/source_analyzer.rs
@@ -20,7 +20,7 @@ use hir_def::{
 use hir_expand::{hygiene::Hygiene, name::AsName, HirFileId, InFile};
 use hir_ty::{
     diagnostics::{record_literal_missing_fields, record_pattern_missing_fields},
-    InferenceResult, Substitution,
+    InferenceResult, Substitution, TyLoweringContext,
 };
 use syntax::{
     ast::{self, AstNode},
@@ -466,7 +466,21 @@ fn resolve_hir_path_(
     prefer_value_ns: bool,
 ) -> Option<PathResolution> {
     let types = || {
-        resolver.resolve_path_in_type_ns_fully(db.upcast(), path.mod_path()).map(|ty| match ty {
+        let (ty, unresolved) = match path.type_anchor() {
+            Some(type_ref) => {
+                let (_, res) = TyLoweringContext::new(db, resolver).lower_ty_ext(type_ref);
+                res.map(|ty_ns| (ty_ns, path.segments().first()))
+            }
+            None => {
+                let (ty, remaining) =
+                    resolver.resolve_path_in_type_ns(db.upcast(), path.mod_path())?;
+                match remaining {
+                    Some(remaining) if remaining > 1 => None,
+                    _ => Some((ty, path.segments().get(1))),
+                }
+            }
+        }?;
+        let res = match ty {
             TypeNs::SelfType(it) => PathResolution::SelfType(it.into()),
             TypeNs::GenericParam(id) => PathResolution::TypeParam(TypeParam { id }),
             TypeNs::AdtSelfType(it) | TypeNs::AdtId(it) => {
@@ -476,7 +490,17 @@ fn resolve_hir_path_(
             TypeNs::TypeAliasId(it) => PathResolution::Def(TypeAlias::from(it).into()),
             TypeNs::BuiltinType(it) => PathResolution::Def(BuiltinType::from(it).into()),
             TypeNs::TraitId(it) => PathResolution::Def(Trait::from(it).into()),
-        })
+        };
+        match unresolved {
+            Some(unresolved) => res
+                .assoc_type_shorthand_candidates(db, |name, alias| {
+                    (name == unresolved.name).then(|| alias)
+                })
+                .map(TypeAlias::from)
+                .map(Into::into)
+                .map(PathResolution::Def),
+            None => Some(res),
+        }
     };
 
     let body_owner = resolver.body_owner();
diff --git a/crates/hir_def/src/item_tree/lower.rs b/crates/hir_def/src/item_tree/lower.rs
index 124dcc8666..8d38628111 100644
--- a/crates/hir_def/src/item_tree/lower.rs
+++ b/crates/hir_def/src/item_tree/lower.rs
@@ -174,12 +174,6 @@ impl Ctx {
         let forced_vis = self.forced_visibility.take();
 
         let mut block_stack = Vec::new();
-
-        // if container itself is block, add it to the stack
-        if let Some(block) = ast::BlockExpr::cast(container.clone()) {
-            block_stack.push(self.source_ast_id_map.ast_id(&block));
-        }
-
         for event in container.preorder().skip(1) {
             match event {
                 WalkEvent::Enter(node) => {
diff --git a/crates/hir_ty/src/lower.rs b/crates/hir_ty/src/lower.rs
index afbfa12d51..14f34d73c6 100644
--- a/crates/hir_ty/src/lower.rs
+++ b/crates/hir_ty/src/lower.rs
@@ -146,7 +146,7 @@ impl<'a> TyLoweringContext<'a> {
         self.lower_ty_ext(type_ref).0
     }
 
-    fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
+    pub fn lower_ty_ext(&self, type_ref: &TypeRef) -> (Ty, Option<TypeNs>) {
         let mut res = None;
         let ty = match type_ref {
             TypeRef::Never => TyKind::Never.intern(&Interner),
diff --git a/crates/ide/src/hover.rs b/crates/ide/src/hover.rs
index 5f9edb4761..28e2e17dc2 100644
--- a/crates/ide/src/hover.rs
+++ b/crates/ide/src/hover.rs
@@ -3834,4 +3834,67 @@ fn foo() {}
             "#]],
         );
     }
+
+    #[test]
+    fn hover_generic_assoc() {
+        check(
+            r#"
+fn foo<T: A>() where T::Assoc$0: {}
+
+trait A {
+    type Assoc;
+}"#,
+            expect![[r#"
+                *Assoc*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                type Assoc
+                ```
+            "#]],
+        );
+        check(
+            r#"
+fn foo<T: A>() {
+    let _: <T>::Assoc$0;
+}
+
+trait A {
+    type Assoc;
+}"#,
+            expect![[r#"
+                *Assoc*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                type Assoc
+                ```
+            "#]],
+        );
+        check(
+            r#"
+trait A where
+    Self::Assoc$0: ,
+{
+    type Assoc;
+}"#,
+            expect![[r#"
+                *Assoc*
+
+                ```rust
+                test
+                ```
+
+                ```rust
+                type Assoc
+                ```
+            "#]],
+        );
+    }
 }
diff --git a/crates/ide/src/syntax_highlighting.rs b/crates/ide/src/syntax_highlighting.rs
index 9df8d21afc..67a10766b2 100644
--- a/crates/ide/src/syntax_highlighting.rs
+++ b/crates/ide/src/syntax_highlighting.rs
@@ -48,9 +48,6 @@ pub struct HlRange {
 //
 // The general rule is that a reference to an entity gets colored the same way as the entity itself.
 // We also give special modifier for `mut` and `&mut` local variables.
-//
-// image::https://user-images.githubusercontent.com/48062697/113164457-06cfb980-9239-11eb-819b-0f93e646acf8.png[]
-// image::https://user-images.githubusercontent.com/48062697/113187625-f7f50100-9250-11eb-825e-91c58f236071.png[]
 pub(crate) fn highlight(
     db: &RootDatabase,
     file_id: FileId,
diff --git a/crates/ide/src/typing.rs b/crates/ide/src/typing.rs
index 11408d445a..e10b7d98e3 100644
--- a/crates/ide/src/typing.rs
+++ b/crates/ide/src/typing.rs
@@ -49,9 +49,6 @@ pub(crate) const TRIGGER_CHARS: &str = ".=>";
 // ----
 // "editor.formatOnType": true,
 // ----
-//
-// image::https://user-images.githubusercontent.com/48062697/113166163-69758500-923a-11eb-81ee-eb33ec380399.gif[]
-// image::https://user-images.githubusercontent.com/48062697/113171066-105c2000-923f-11eb-87ab-f4a263346567.gif[]
 pub(crate) fn on_char_typed(
     db: &RootDatabase,
     position: FilePosition,
diff --git a/crates/ide_completion/src/completions/qualified_path.rs b/crates/ide_completion/src/completions/qualified_path.rs
index 1891eb5b36..969249df60 100644
--- a/crates/ide_completion/src/completions/qualified_path.rs
+++ b/crates/ide_completion/src/completions/qualified_path.rs
@@ -24,7 +24,7 @@ pub(crate) fn complete_qualified_path(acc: &mut Completions, ctx: &CompletionCon
     };
 
     // Add associated types on type parameters and `Self`.
-    resolution.assoc_type_shorthand_candidates(ctx.db, |alias| {
+    resolution.assoc_type_shorthand_candidates(ctx.db, |_, alias| {
         acc.add_type_alias(ctx, alias);
         None::<()>
     });


Test patch:
diff --git a/crates/hir_ty/src/tests/macros.rs b/crates/hir_ty/src/tests/macros.rs
index 86e3d8b86e..3eb01dbd0f 100644
--- a/crates/hir_ty/src/tests/macros.rs
+++ b/crates/hir_ty/src/tests/macros.rs
@@ -372,32 +372,6 @@ fn recursive_inner_item_macro_rules() {
     );
 }
 
-#[test]
-fn infer_macro_defining_block_with_items() {
-    check_infer(
-        r#"
-        macro_rules! foo {
-            () => {{
-                fn bar() -> usize { 0 }
-                bar()
-            }};
-        }
-        fn main() {
-            let _a = foo!();
-        }
-    "#,
-        expect![[r#"
-            !15..18 '{0}': usize
-            !16..17 '0': usize
-            !0..24 '{fnbar...bar()}': usize
-            !18..21 'bar': fn bar() -> usize
-            !18..23 'bar()': usize
-            98..122 '{     ...!(); }': ()
-            108..110 '_a': usize
-        "#]],
-    );
-}
-
 #[test]
 fn infer_type_value_macro_having_same_name() {
     check_infer(