diff --git a/crates/ide-completion/src/completions/type.rs b/crates/ide-completion/src/completions/type.rs index 69b1e1fd11f..f4efaecba8a 100644 --- a/crates/ide-completion/src/completions/type.rs +++ b/crates/ide-completion/src/completions/type.rs @@ -20,7 +20,16 @@ pub(crate) fn complete_type_path( let scope_def_applicable = |def| { use hir::{GenericParam::*, ModuleDef::*}; match def { - ScopeDef::GenericParam(LifetimeParam(_)) | ScopeDef::Label(_) => false, + ScopeDef::GenericParam(LifetimeParam(_)) => { + matches!( + location, + TypeLocation::GenericArgList(Some(( + _, + Some(ast::GenericParam::LifetimeParam(_)) + ))) + ) + } + ScopeDef::Label(_) => false, // no values in type places ScopeDef::ModuleDef(Function(_) | Variant(_) | Static(_)) | ScopeDef::Local(_) => false, // unless its a constant in a generic arg list position diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs index 8de4d0827f9..dfceb67f209 100644 --- a/crates/ide-completion/src/context/analysis.rs +++ b/crates/ide-completion/src/context/analysis.rs @@ -783,9 +783,27 @@ 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; + // Determine the index of the argument in the `GenericArgList` and match it with + // the corresponding parameter in the `GenericParamList`. + // Since lifetime parameters are often omitted, ignore them for the purposes of + // matching the argument with its parameter unless a lifetime argument is provided + // explicitly. That is, for `struct S<'a, 'b, T>`, match `S::<$0>` to to `T` and + // `S::<'a, $0, _>` to `'b`. + let mut explicit_lifetime_arg = false; + let arg_idx = arg + .syntax() + .siblings(Direction::Prev) + // Skip the node itself + .skip(1) + .map(|arg| if ast::LifetimeArg::can_cast(arg.kind()) { explicit_lifetime_arg = true }) + .count(); + let param_idx = if explicit_lifetime_arg { + arg_idx + } else { + // Lifetimes parameters always precede type and generic parameters, + // so offset the argument index by the total number of lifetime params + arg_idx + params.lifetime_params().count() + }; params.generic_params().nth(param_idx) })(); (args, param) diff --git a/crates/ide-completion/src/tests/type_pos.rs b/crates/ide-completion/src/tests/type_pos.rs index 31ff9cf956e..4b441391094 100644 --- a/crates/ide-completion/src/tests/type_pos.rs +++ b/crates/ide-completion/src/tests/type_pos.rs @@ -718,216 +718,255 @@ fn completes_const_and_type_generics_separately() { // Function generic params check( r#" -struct Foo; -const X: usize = 0; -fn foo() {} -fn main() { - foo::(); -} - "#, + struct Foo; + const X: usize = 0; + fn foo() {} + fn main() { + foo::(); + } + "#, 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:: - "#]], + 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#" -struct Foo; -const X: usize = 0; -fn foo() {} -fn main() { - foo::<_, $0>(); -} - "#, + 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:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Method generic params check( r#" -const X: usize = 0; -struct Foo; -impl Foo { fn bar(self) {} } -fn main() { - Foo.bar::<_, $0>(); -} - "#, + 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:: - "#]], + 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#" -const X: usize = 0; -struct Foo; -impl Foo { fn bar(self) {} } -fn main() { - Foo.bar::(); -} - "#, + 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:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Associated type generic params check( r#" -const X: usize = 0; -struct Foo; -trait Bar { - type Baz; -} -fn foo(_: impl Bar = ()>) {} - "#, + const X: usize = 0; + struct Foo; + trait Bar { + type Baz; + } + fn foo(_: impl Bar = ()>) {} + "#, expect![[r#" - en Enum - ma makro!(…) macro_rules! makro - md module - st Foo - st Record - st Tuple - st Unit - tt Bar - tt Trait - un Union - bt u32 - kw crate:: - kw self:: - "#]], + en Enum + ma makro!(…) macro_rules! makro + md module + st Foo + st Record + st Tuple + st Unit + tt Bar + tt Trait + un Union + bt u32 + kw crate:: + kw self:: + "#]], ); check( r#" -const X: usize = 0; -struct Foo; -trait Bar { - type Baz; -} -fn foo = ()>>() {} - "#, + const X: usize = 0; + struct Foo; + trait Bar { + type Baz; + } + fn foo = ()>>() {} + "#, expect![[r#" - ct CONST - ct X - ma makro!(…) macro_rules! makro - kw crate:: - kw self:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Type generic params check( r#" -const X: usize = 0; -struct Foo(T); -fn main() { - let _: Foo::<_, $0> = Foo(()); -} - "#, + const X: usize = 0; + struct Foo(T); + fn main() { + let _: Foo::<_, $0> = Foo(()); + } + "#, expect![[r#" - ct CONST - ct X - ma makro!(…) macro_rules! makro - kw crate:: - kw self:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Type alias generic params check( r#" -const X: usize = 0; -struct Foo(T); -type Bar = Foo; -fn main() { - let _: Bar:: = Bar(()); -} - "#, + const X: usize = 0; + struct Foo(T); + type Bar = Foo; + fn main() { + let _: Bar:: = Bar(()); + } + "#, expect![[r#" - ct CONST - ct X - ma makro!(…) macro_rules! makro - kw crate:: - kw self:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Enum variant params check( r#" -const X: usize = 0; -enum Foo { A(T), B } -fn main() { - Foo::B::<(), $0>; -} - "#, + const X: usize = 0; + enum Foo { A(T), B } + fn main() { + Foo::B::<(), $0>; + } + "#, expect![[r#" - ct CONST - ct X - ma makro!(…) macro_rules! makro - kw crate:: - kw self:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Trait params check( r#" -const X: usize = 0; -trait Foo {} -impl Foo<(), $0> for () {} - "#, + const X: usize = 0; + trait Foo {} + impl Foo<(), $0> for () {} + "#, expect![[r#" - ct CONST - ct X - ma makro!(…) macro_rules! makro - kw crate:: - kw self:: - "#]], + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], ); // Trait alias params check( r#" -#![feature(trait_alias)] -const X: usize = 0; -trait Foo {} -trait Bar = Foo; -fn foo>() {} + #![feature(trait_alias)] + const X: usize = 0; + trait Foo {} + trait Bar = Foo; + fn foo>() {} + "#, + expect![[r#" + ct CONST + ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], + ); + + // Omitted lifetime params + check( + r#" +struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); +fn foo<'a>() { S::; } "#, expect![[r#" ct CONST - ct X + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], + ); + // Explicit lifetime params + check( + r#" +struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); +fn foo<'a>() { S::<'static, 'static, F$0, _>; } + "#, + expect![[r#" + ct CONST + ma makro!(…) macro_rules! makro + kw crate:: + kw self:: + "#]], + ); + check( + r#" +struct S<'a, 'b, const C: usize, T>(core::marker::PhantomData<&'a &'b T>); +fn foo<'a>() { S::<'static, F$0, _, _>; } + "#, + expect![[r#" + lt 'a ma makro!(…) macro_rules! makro kw crate:: kw self::