about summary refs log tree commit diff
diff options
context:
space:
mode:
authorPetr Nevyhoštěný <petr.nevyhosteny@gmail.com>2022-01-07 16:41:39 +0100
committerPetr Nevyhoštěný <petr.nevyhosteny@gmail.com>2022-01-07 16:41:39 +0100
commita710b87b1bb86602e9acccbb098039f66e27d80d (patch)
treeefa115cf335c4b2bc5fd79255d525903be4633b2
parentd9b3242bcd5f4208fad707a30907633ccf081056 (diff)
downloadrust-a710b87b1bb86602e9acccbb098039f66e27d80d.tar.gz
rust-a710b87b1bb86602e9acccbb098039f66e27d80d.zip
Fix generic type substitution in impl trait with assoc const
-rw-r--r--crates/ide_assists/src/handlers/add_missing_impl_members.rs56
-rw-r--r--crates/ide_db/src/path_transform.rs29
2 files changed, 71 insertions, 14 deletions
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 6546d8f7fb4..3105b289116 100644
--- a/crates/ide_assists/src/handlers/add_missing_impl_members.rs
+++ b/crates/ide_assists/src/handlers/add_missing_impl_members.rs
@@ -1248,4 +1248,60 @@ impl Behavior<u32> for Impl {
 }"#,
         );
     }
+
+    #[test]
+    fn test_transform_path_in_path_expr() {
+        check_assist(
+            add_missing_default_members,
+            r#"
+pub trait Const {
+    const FOO: u32;
+}
+
+pub trait Trait<T: Const> {
+    fn foo() -> bool {
+        match T::FOO {
+            0 => true,
+            _ => false,
+        }
+    }
+}
+
+impl Const for u32 {
+    const FOO: u32 = 1;
+}
+
+struct Impl;
+
+impl Trait<u32> for Impl { $0 }"#,
+            r#"
+pub trait Const {
+    const FOO: u32;
+}
+
+pub trait Trait<T: Const> {
+    fn foo() -> bool {
+        match T::FOO {
+            0 => true,
+            _ => false,
+        }
+    }
+}
+
+impl Const for u32 {
+    const FOO: u32 = 1;
+}
+
+struct Impl;
+
+impl Trait<u32> for Impl {
+    $0fn foo() -> bool {
+        match <u32 as Const>::FOO {
+            0 => true,
+            _ => false,
+        }
+    }
+}"#,
+        );
+    }
 }
diff --git a/crates/ide_db/src/path_transform.rs b/crates/ide_db/src/path_transform.rs
index 5507c9cd684..524af7fe8f0 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<hir::Trait> {
     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