From cab360fe3105264f483c4f2b1a33f3d9010e3436 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Fri, 17 Jul 2020 14:58:49 +0200 Subject: [PATCH] Correctly resolve assoc. types in path bindings --- crates/ra_ide/src/goto_definition.rs | 80 ++++++++++++++++++++++++++++ crates/ra_ide_db/src/defs.rs | 22 ++++++++ 2 files changed, 102 insertions(+) diff --git a/crates/ra_ide/src/goto_definition.rs b/crates/ra_ide/src/goto_definition.rs index db6d20a374..4e3f428fae 100644 --- a/crates/ra_ide/src/goto_definition.rs +++ b/crates/ra_ide/src/goto_definition.rs @@ -881,6 +881,86 @@ pub mod module { macro_rules! _mac { () => { () } } pub use crate::_mac as mac; } +"#, + ); + } + + #[test] + fn goto_def_for_assoc_ty_in_path() { + check( + r#" +trait Iterator { + type Item; + //^^^^ +} + +fn f() -> impl Iterator = u8> {} +"#, + ); + } + + #[test] + fn goto_def_for_assoc_ty_in_path_multiple() { + check( + r#" +trait Iterator { + type A; + //^ + type B; +} + +fn f() -> impl Iterator = u8, B = ()> {} +"#, + ); + check( + r#" +trait Iterator { + type A; + type B; + //^ +} + +fn f() -> impl Iterator = ()> {} +"#, + ); + } + + #[test] + fn goto_def_for_assoc_ty_ufcs() { + check( + r#" +trait Iterator { + type Item; + //^^^^ +} + +fn g() -> <() as Iterator = ()>>::Item {} +"#, + ); + } + + #[test] + fn goto_def_for_assoc_ty_ufcs_multiple() { + check( + r#" +trait Iterator { + type A; + //^ + type B; +} + +fn g() -> <() as Iterator = (), B = u8>>::B {} +"#, + ); + check( + r#" +trait Iterator { + type A; + type B; + //^ +} + +fn g() -> <() as Iterator = u8>>::A {} "#, ); } diff --git a/crates/ra_ide_db/src/defs.rs b/crates/ra_ide_db/src/defs.rs index bcaabca92f..e06b189a00 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` + // ^^^^^ + 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() {