diff --git a/crates/ide_assists/src/handlers/add_missing_impl_members.rs b/crates/ide_assists/src/handlers/add_missing_impl_members.rs index 6546d8f7fb..3105b28911 100644 --- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs +++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs @@ -1245,6 +1245,62 @@ impl Behavior for Impl { fn reproduce(&self, foo: ::Bar) { ${0:todo!()} } +}"#, + ); + } + + #[test] + fn test_transform_path_in_path_expr() { + check_assist( + add_missing_default_members, + r#" +pub trait Const { + const FOO: u32; +} + +pub trait Trait { + fn foo() -> bool { + match T::FOO { + 0 => true, + _ => false, + } + } +} + +impl Const for u32 { + const FOO: u32 = 1; +} + +struct Impl; + +impl Trait for Impl { $0 }"#, + r#" +pub trait Const { + const FOO: u32; +} + +pub trait Trait { + fn foo() -> bool { + match T::FOO { + 0 => true, + _ => false, + } + } +} + +impl Const for u32 { + const FOO: u32 = 1; +} + +struct Impl; + +impl Trait for Impl { + $0fn foo() -> bool { + match ::FOO { + 0 => true, + _ => false, + } + } }"#, ); } diff --git a/crates/ide_db/src/path_transform.rs b/crates/ide_db/src/path_transform.rs index 5507c9cd68..524af7fe8f 100644 --- a/crates/ide_db/src/path_transform.rs +++ b/crates/ide_db/src/path_transform.rs @@ -154,14 +154,14 @@ impl<'a> Ctx<'a> { let parent = path.syntax().parent()?; if let Some(parent) = ast::Path::cast(parent.clone()) { // Path inside path means that there is an associated - // type on the type parameter. It is necessary to fully - // qualify the type with `as Trait`. Even though it - // might be unnecessary if `subst` is generic type, - // always fully qualifying the path is safer because of - // potential clash of associated types from multiple - // traits + // type/constant on the type parameter. It is necessary + // to fully qualify the type with `as Trait`. Even + // though it might be unnecessary if `subst` is generic + // type, always fully qualifying the path is safer + // because of potential clash of associated types from + // multiple traits - let trait_ref = find_trait_for_assoc_type( + let trait_ref = find_trait_for_assoc_item( self.source_scope, tp, parent.segment()?.name_ref()?, @@ -252,24 +252,25 @@ fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option< Some(result) } -fn find_trait_for_assoc_type( +fn find_trait_for_assoc_item( scope: &SemanticsScope, type_param: hir::TypeParam, - assoc_type: ast::NameRef, + assoc_item: ast::NameRef, ) -> Option { let db = scope.db; let trait_bounds = type_param.trait_bounds(db); - let assoc_type_name = assoc_type.text(); + let assoc_item_name = assoc_item.text(); for trait_ in trait_bounds { - let type_aliases = trait_.items(db).into_iter().filter_map(|item| match item { - hir::AssocItem::TypeAlias(ta) => Some(ta), + let names = trait_.items(db).into_iter().filter_map(|item| match item { + hir::AssocItem::TypeAlias(ta) => Some(ta.name(db)), + hir::AssocItem::Const(cst) => cst.name(db), _ => None, }); - for type_alias in type_aliases { - if assoc_type_name.as_str() == type_alias.name(db).as_text()?.as_str() { + for name in names { + if assoc_item_name.as_str() == name.as_text()?.as_str() { // It is fine to return the first match because in case of // multiple possibilities, the exact trait must be disambiguated // in the definition of trait being implemented, so this search