about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMax Heller <max.a.heller@gmail.com>2023-08-02 17:59:26 -0400
committerMax Heller <max.a.heller@gmail.com>2023-08-02 17:59:26 -0400
commit1b3e20fe686e5544feb134a7b1ffcd406a1189e6 (patch)
tree4d48c782ad1cda3e159516a2c32e957ff30bf4d5
parentf4038a6bf1927aee3c5a34d7ffe14da4e7ba0560 (diff)
downloadrust-1b3e20fe686e5544feb134a7b1ffcd406a1189e6.tar.gz
rust-1b3e20fe686e5544feb134a7b1ffcd406a1189e6.zip
handle more cases
-rw-r--r--crates/ide-completion/src/completions/type.rs2
-rw-r--r--crates/ide-completion/src/context/analysis.rs44
-rw-r--r--crates/ide-completion/src/tests/type_pos.rs180
3 files changed, 128 insertions, 98 deletions
diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs
index de855242ee3..69b1e1fd11f 100644
--- a/crates/ide-completion/src/completions/type.rs
+++ b/crates/ide-completion/src/completions/type.rs
@@ -173,7 +173,7 @@ pub(crate) fn complete_type_path(
                     });
                     return;
                 }
-                TypeLocation::GenericArgList(Some((arg_list, generic_param))) => {
+                TypeLocation::GenericArgList(Some((arg_list, _))) => {
                     let in_assoc_type_arg = ctx
                         .original_token
                         .parent_ancestors()
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 7fd3147a739..4bd429c5723 100644
--- a/crates/ide-completion/src/context/analysis.rs
+++ b/crates/ide-completion/src/context/analysis.rs
@@ -726,20 +726,30 @@ fn classify_name_ref(
             arg.syntax().parent().and_then(ast::GenericArgList::cast),
         )
         .map(|args| {
-            // Determine the index of the parameter in the `GenericArgList`
-            // (subtract 1 because `siblings` includes the node itself)
-            let param_idx = arg.syntax().siblings(Direction::Prev).count() - 1;
-            let parent = args.syntax().parent();
-            let param = parent.and_then(|parent| {
-                match_ast! {
+            let param = (|| {
+                let parent = args.syntax().parent()?;
+                let params = match_ast! {
                     match parent {
                         ast::PathSegment(segment) => {
                             match sema.resolve_path(&segment.parent_path().top_path())? {
                                 hir::PathResolution::Def(def) => match def {
                                     hir::ModuleDef::Function(func) => {
-                                        let src = func.source(sema.db)?;
-                                        let params = src.value.generic_param_list()?;
-                                        params.generic_params().nth(param_idx)
+                                        func.source(sema.db)?.value.generic_param_list()
+                                    }
+                                    hir::ModuleDef::Adt(adt) => {
+                                        adt.source(sema.db)?.value.generic_param_list()
+                                    }
+                                    hir::ModuleDef::Variant(variant) => {
+                                        variant.parent_enum(sema.db).source(sema.db)?.value.generic_param_list()
+                                    }
+                                    hir::ModuleDef::Trait(trait_) => {
+                                        trait_.source(sema.db)?.value.generic_param_list()
+                                    }
+                                    hir::ModuleDef::TraitAlias(trait_) => {
+                                        trait_.source(sema.db)?.value.generic_param_list()
+                                    }
+                                    hir::ModuleDef::TypeAlias(ty_) => {
+                                        ty_.source(sema.db)?.value.generic_param_list()
                                     }
                                     _ => None,
                                 },
@@ -748,9 +758,7 @@ fn classify_name_ref(
                         },
                         ast::MethodCallExpr(call) => {
                             let func = sema.resolve_method_call(&call)?;
-                            let src = func.source(sema.db)?;
-                            let params = src.value.generic_param_list()?;
-                            params.generic_params().nth(param_idx)
+                            func.source(sema.db)?.value.generic_param_list()
                         },
                         ast::AssocTypeArg(arg) => {
                             let trait_ = ast::PathSegment::cast(arg.syntax().parent()?.parent()?)?;
@@ -765,9 +773,7 @@ fn classify_name_ref(
                                             },
                                             _ => None,
                                         })?;
-                                        let src = assoc_ty.source(sema.db)?;
-                                        let params = src.value.generic_param_list()?;
-                                        params.generic_params().nth(param_idx)
+                                        assoc_ty.source(sema.db)?.value.generic_param_list()
                                     }
                                     _ => None,
                                 },
@@ -776,8 +782,12 @@ fn classify_name_ref(
                         },
                         _ => None,
                     }
-                }
-            });
+                }?;
+                // Determine the index of the parameter in the `GenericArgList`
+                // (subtract 1 because `siblings` includes the node itself)
+                let param_idx = arg.syntax().siblings(Direction::Prev).count() - 1;
+                params.generic_params().nth(param_idx)
+            })();
             (args, param)
         });
         TypeLocation::GenericArgList(location)
diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs
index 67110b3d7fb..27bcf4c630a 100644
--- a/crates/ide-completion/src/tests/type_pos.rs
+++ b/crates/ide-completion/src/tests/type_pos.rs
@@ -722,16 +722,31 @@ pub struct S;
 
 #[test]
 fn completes_const_and_type_generics_separately() {
-    check(
+    let type_completion_cases = [
+        // Function
         r#"
-    struct Foo;
-    const X: usize = 0;
-    fn foo<T, const N: usize>() {}
-    fn main() {
-        foo::<F$0, _>();
-    }
-    "#,
-        expect![[r#"
+struct Foo;
+const X: usize = 0;
+fn foo<T, const N: usize>() {}
+fn main() {
+    foo::<F$0, _>();
+}
+        "#,
+        // Method
+        r#"
+const X: usize = 0;
+struct Foo;
+impl Foo { fn bar<const N: usize, T>(self) {} }
+fn main() {
+    Foo.bar::<_, $0>();
+}
+        "#,
+    ];
+
+    for case in type_completion_cases {
+        check(
+            case,
+            expect![[r#"
                 en Enum
                 ma makro!(…) macro_rules! makro
                 md module
@@ -745,51 +760,18 @@ fn completes_const_and_type_generics_separately() {
                 kw crate::
                 kw self::
             "#]],
-    );
-    check(
-        r#"
-    struct Foo;
-    const X: usize = 0;
-    fn foo<T, const N: usize>() {}
-    fn main() {
-        foo::<_, $0>();
+        )
     }
-    "#,
-        expect![[r#"
-                ct CONST
-                ct X
-                ma makro!(…) macro_rules! makro
-                kw crate::
-                kw self::
-            "#]],
-    );
 
     check(
         r#"
 const X: usize = 0;
 struct Foo;
-impl Foo { fn bar<const N: usize, T>(self) {} }
-fn main() {
-    Foo.bar::<X$0, _>();
-}
-"#,
-        expect![[r#"
-            ct CONST
-            ct X
-            ma makro!(…) macro_rules! makro
-            kw crate::
-            kw self::
-        "#]],
-    );
-    check(
-        r#"
-const X: usize = 0;
-struct Foo;
-impl Foo { fn bar<const N: usize, T>(self) {} }
-fn main() {
-    Foo.bar::<_, $0>();
+trait Bar {
+    type Baz<T, const X: usize>;
 }
-"#,
+fn foo(_: impl Bar<Baz<F$0, 0> = ()>) {}
+        "#,
         expect![[r#"
             en Enum
             ma makro!(…) macro_rules! makro
@@ -798,6 +780,7 @@ fn main() {
             st Record
             st Tuple
             st Unit
+            tt Bar
             tt Trait
             un Union
             bt u32
@@ -806,47 +789,84 @@ fn main() {
         "#]],
     );
 
-    check(
+    let const_completion_cases = [
+        // Function params
+        r#"
+struct Foo;
+const X: usize = 0;
+fn foo<T, const N: usize>() {}
+fn main() {
+    foo::<_, $0>();
+}
+        "#,
+        // Method params
         r#"
 const X: usize = 0;
 struct Foo;
-trait Bar {
-    type Baz<T, const X: usize>;
+impl Foo { fn bar<const N: usize, T>(self) {} }
+fn main() {
+    Foo.bar::<X$0, _>();
 }
-fn foo<T: Bar<Baz<(), $0> = ()>>() {}
-"#,
-        expect![[r#"
-            ct CONST
-            ct X
-            ma makro!(…) macro_rules! makro
-            kw crate::
-            kw self::
-        "#]],
-    );
-    check(
+        "#,
+        // Associated type params
         r#"
 const X: usize = 0;
 struct Foo;
 trait Bar {
     type Baz<T, const X: usize>;
 }
-fn foo<T: Bar<Baz<F$0, 0> = ()>>() {}
-"#,
-        expect![[r#"
-            en Enum
-            ma makro!(…) macro_rules! makro
-            md module
-            st Foo
-            st Record
-            st Tuple
-            st Unit
-            tt Bar
-            tt Trait
-            tp T
-            un Union
-            bt u32
-            kw crate::
-            kw self::
-        "#]],
-    );
+fn foo<T: Bar<Baz<(), $0> = ()>>() {}
+        "#,
+        // Type params
+        r#"
+const X: usize = 0;
+struct Foo<T, const N: usize>(T);
+fn main() {
+    let _: Foo::<_, $0> = todo!();
+}
+        "#,
+        // Enum variant params
+        r#"
+const X: usize = 0;
+struct Foo<T, const N: usize>(T);
+type Bar<const X: usize, U> = Foo<U, X>;
+fn main() {
+    let _: Bar::<X$0, _> = todo!();
+}
+        "#,
+        r#"
+const X: usize = 0;
+enum Foo<T, const N: usize> { A(T), B }
+fn main() {
+    Foo::B::<(), $0>;
+}
+        "#,
+        // Trait params
+        r#"
+const X: usize = 0;
+trait Foo<T, const N: usize> {}
+impl Foo<(), $0> for () {}
+        "#,
+        // Trait alias params
+        r#"
+#![feature(trait_alias)]
+const X: usize = 0;
+trait Foo<T, const N: usize> {}
+trait Bar<const M: usize, U> = Foo<U, M>;
+fn foo<T: Bar<X$0, ()>>() {}
+        "#,
+    ];
+
+    for case in const_completion_cases {
+        check(
+            case,
+            expect![[r#"
+                ct CONST
+                ct X
+                ma makro!(…) macro_rules! makro
+                kw crate::
+                kw self::
+            "#]],
+        );
+    }
 }