Unnamed repository; edit this file 'description' to name the repository.
Diffstat (limited to 'crates/ide-completion/src/context/analysis.rs')
-rw-r--r--crates/ide-completion/src/context/analysis.rs24
1 files changed, 21 insertions, 3 deletions
diff --git a/crates/ide-completion/src/context/analysis.rs b/crates/ide-completion/src/context/analysis.rs
index 8de4d0827f..dfceb67f20 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)