Skip to content

Commit a710b87

Browse files
committed
Fix generic type substitution in impl trait with assoc const
1 parent d9b3242 commit a710b87

File tree

2 files changed

+71
-14
lines changed

2 files changed

+71
-14
lines changed

crates/ide_assists/src/handlers/add_missing_impl_members.rs

Lines changed: 56 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1245,6 +1245,62 @@ impl Behavior<u32> for Impl {
12451245
fn reproduce(&self, foo: <u32 as bar::Types2>::Bar) {
12461246
${0:todo!()}
12471247
}
1248+
}"#,
1249+
);
1250+
}
1251+
1252+
#[test]
1253+
fn test_transform_path_in_path_expr() {
1254+
check_assist(
1255+
add_missing_default_members,
1256+
r#"
1257+
pub trait Const {
1258+
const FOO: u32;
1259+
}
1260+
1261+
pub trait Trait<T: Const> {
1262+
fn foo() -> bool {
1263+
match T::FOO {
1264+
0 => true,
1265+
_ => false,
1266+
}
1267+
}
1268+
}
1269+
1270+
impl Const for u32 {
1271+
const FOO: u32 = 1;
1272+
}
1273+
1274+
struct Impl;
1275+
1276+
impl Trait<u32> for Impl { $0 }"#,
1277+
r#"
1278+
pub trait Const {
1279+
const FOO: u32;
1280+
}
1281+
1282+
pub trait Trait<T: Const> {
1283+
fn foo() -> bool {
1284+
match T::FOO {
1285+
0 => true,
1286+
_ => false,
1287+
}
1288+
}
1289+
}
1290+
1291+
impl Const for u32 {
1292+
const FOO: u32 = 1;
1293+
}
1294+
1295+
struct Impl;
1296+
1297+
impl Trait<u32> for Impl {
1298+
$0fn foo() -> bool {
1299+
match <u32 as Const>::FOO {
1300+
0 => true,
1301+
_ => false,
1302+
}
1303+
}
12481304
}"#,
12491305
);
12501306
}

crates/ide_db/src/path_transform.rs

Lines changed: 15 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -154,14 +154,14 @@ impl<'a> Ctx<'a> {
154154
let parent = path.syntax().parent()?;
155155
if let Some(parent) = ast::Path::cast(parent.clone()) {
156156
// Path inside path means that there is an associated
157-
// type on the type parameter. It is necessary to fully
158-
// qualify the type with `as Trait`. Even though it
159-
// might be unnecessary if `subst` is generic type,
160-
// always fully qualifying the path is safer because of
161-
// potential clash of associated types from multiple
162-
// traits
157+
// type/constant on the type parameter. It is necessary
158+
// to fully qualify the type with `as Trait`. Even
159+
// though it might be unnecessary if `subst` is generic
160+
// type, always fully qualifying the path is safer
161+
// because of potential clash of associated types from
162+
// multiple traits
163163

164-
let trait_ref = find_trait_for_assoc_type(
164+
let trait_ref = find_trait_for_assoc_item(
165165
self.source_scope,
166166
tp,
167167
parent.segment()?.name_ref()?,
@@ -252,24 +252,25 @@ fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option<
252252
Some(result)
253253
}
254254

255-
fn find_trait_for_assoc_type(
255+
fn find_trait_for_assoc_item(
256256
scope: &SemanticsScope,
257257
type_param: hir::TypeParam,
258-
assoc_type: ast::NameRef,
258+
assoc_item: ast::NameRef,
259259
) -> Option<hir::Trait> {
260260
let db = scope.db;
261261
let trait_bounds = type_param.trait_bounds(db);
262262

263-
let assoc_type_name = assoc_type.text();
263+
let assoc_item_name = assoc_item.text();
264264

265265
for trait_ in trait_bounds {
266-
let type_aliases = trait_.items(db).into_iter().filter_map(|item| match item {
267-
hir::AssocItem::TypeAlias(ta) => Some(ta),
266+
let names = trait_.items(db).into_iter().filter_map(|item| match item {
267+
hir::AssocItem::TypeAlias(ta) => Some(ta.name(db)),
268+
hir::AssocItem::Const(cst) => cst.name(db),
268269
_ => None,
269270
});
270271

271-
for type_alias in type_aliases {
272-
if assoc_type_name.as_str() == type_alias.name(db).as_text()?.as_str() {
272+
for name in names {
273+
if assoc_item_name.as_str() == name.as_text()?.as_str() {
273274
// It is fine to return the first match because in case of
274275
// multiple possibilities, the exact trait must be disambiguated
275276
// in the definition of trait being implemented, so this search

0 commit comments

Comments
 (0)