diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs index de855242ee..69b1e1fd11 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 7fd3147a73..4bd429c572 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 67110b3d7f..27bcf4c630 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() {} - fn main() { - foo::(); - } - "#, - expect![[r#" +struct Foo; +const X: usize = 0; +fn foo() {} +fn main() { + foo::(); +} + "#, + // Method + r#" +const X: usize = 0; +struct Foo; +impl Foo { fn bar(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,66 +760,8 @@ fn completes_const_and_type_generics_separately() { kw crate:: kw self:: "#]], - ); - check( - r#" - struct Foo; - const X: usize = 0; - fn foo() {} - 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(self) {} } -fn main() { - Foo.bar::(); -} -"#, - 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(self) {} } -fn main() { - Foo.bar::<_, $0>(); -} -"#, - expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Foo - st Record - st Tuple - st Unit - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], - ); check( r#" @@ -813,25 +770,8 @@ struct Foo; trait Bar { type Baz; } -fn foo = ()>>() {} -"#, - expect![[r#" - ct CONST - ct X - ma makro!(…) macro_rules! makro - kw crate:: - kw self:: - "#]], - ); - check( - r#" -const X: usize = 0; -struct Foo; -trait Bar { - type Baz; -} -fn foo = ()>>() {} -"#, +fn foo(_: impl Bar = ()>) {} + "#, expect![[r#" en Enum ma makro!(…) macro_rules! makro @@ -842,11 +782,91 @@ fn foo = ()>>() {} st Unit tt Bar tt Trait - tp T un Union bt u32 kw crate:: kw self:: "#]], ); + + let const_completion_cases = [ + // Function params + r#" +struct Foo; +const X: usize = 0; +fn foo() {} +fn main() { + foo::<_, $0>(); +} + "#, + // Method params + r#" +const X: usize = 0; +struct Foo; +impl Foo { fn bar(self) {} } +fn main() { + Foo.bar::(); +} + "#, + // Associated type params + r#" +const X: usize = 0; +struct Foo; +trait Bar { + type Baz; +} +fn foo = ()>>() {} + "#, + // Type params + r#" +const X: usize = 0; +struct Foo(T); +fn main() { + let _: Foo::<_, $0> = todo!(); +} + "#, + // Enum variant params + r#" +const X: usize = 0; +struct Foo(T); +type Bar = Foo; +fn main() { + let _: Bar:: = todo!(); +} + "#, + r#" +const X: usize = 0; +enum Foo { A(T), B } +fn main() { + Foo::B::<(), $0>; +} + "#, + // Trait params + r#" +const X: usize = 0; +trait Foo {} +impl Foo<(), $0> for () {} + "#, + // Trait alias params + r#" +#![feature(trait_alias)] +const X: usize = 0; +trait Foo {} +trait Bar = Foo; +fn foo>() {} + "#, + ]; + + for case in const_completion_cases { + check( + case, + expect![[r#" + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], + ); + } }