about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--crates/ra_ide/src/goto_definition.rs80
-rw-r--r--crates/ra_ide_db/src/defs.rs22
2 files changed, 102 insertions, 0 deletions
diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs
index db6d20a3744..4e3f428fae7 100644
--- a/crates/ra_ide/src/goto_definition.rs
+++ b/crates/ra_ide/src/goto_definition.rs
@@ -884,4 +884,84 @@ pub mod module {
 "#,
         );
     }
+
+    #[test]
+    fn goto_def_for_assoc_ty_in_path() {
+        check(
+            r#"
+trait Iterator {
+    type Item;
+       //^^^^
+}
+
+fn f() -> impl Iterator<Item<|> = u8> {}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_assoc_ty_in_path_multiple() {
+        check(
+            r#"
+trait Iterator {
+    type A;
+       //^
+    type B;
+}
+
+fn f() -> impl Iterator<A<|> = u8, B = ()> {}
+"#,
+        );
+        check(
+            r#"
+trait Iterator {
+    type A;
+    type B;
+       //^
+}
+
+fn f() -> impl Iterator<A = u8, B<|> = ()> {}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_assoc_ty_ufcs() {
+        check(
+            r#"
+trait Iterator {
+    type Item;
+       //^^^^
+}
+
+fn g() -> <() as Iterator<Item<|> = ()>>::Item {}
+"#,
+        );
+    }
+
+    #[test]
+    fn goto_def_for_assoc_ty_ufcs_multiple() {
+        check(
+            r#"
+trait Iterator {
+    type A;
+       //^
+    type B;
+}
+
+fn g() -> <() as Iterator<A<|> = (), B = u8>>::B {}
+"#,
+        );
+        check(
+            r#"
+trait Iterator {
+    type A;
+    type B;
+       //^
+}
+
+fn g() -> <() as Iterator<A = (), B<|> = u8>>::A {}
+"#,
+        );
+    }
 }
diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs
index bcaabca92f1..e06b189a00a 100644
--- a/crates/ra_ide_db/src/defs.rs
+++ b/crates/ra_ide_db/src/defs.rs
@@ -254,6 +254,28 @@ pub fn classify_name_ref(
         }
     }
 
+    if ast::AssocTypeArg::cast(parent.clone()).is_some() {
+        // `Trait<Assoc = Ty>`
+        //        ^^^^^
+        let path = name_ref.syntax().ancestors().find_map(ast::Path::cast)?;
+        let resolved = sema.resolve_path(&path)?;
+        if let PathResolution::Def(ModuleDef::Trait(tr)) = resolved {
+            if let Some(ty) = tr
+                .items(sema.db)
+                .iter()
+                .filter_map(|assoc| match assoc {
+                    hir::AssocItem::TypeAlias(it) => Some(*it),
+                    _ => None,
+                })
+                .find(|alias| alias.name(sema.db).to_string() == **name_ref.text())
+            {
+                return Some(NameRefClass::Definition(Definition::ModuleDef(
+                    ModuleDef::TypeAlias(ty),
+                )));
+            }
+        }
+    }
+
     if let Some(macro_call) = parent.ancestors().find_map(ast::MacroCall::cast) {
         if let Some(path) = macro_call.path() {
             if path.qualifier().is_none() {