diff --git a/crates/hir/src/lib.rs b/crates/hir/src/lib.rs index 1fc18767d6c..604b1cb5228 100644 --- a/crates/hir/src/lib.rs +++ b/crates/hir/src/lib.rs @@ -2637,10 +2637,14 @@ impl GenericDef { Either::Right(x) => GenericParam::TypeParam(x), } }); - self.lifetime_params(db).into_iter().chain(ty_params).collect() + self.lifetime_params(db) + .into_iter() + .map(GenericParam::LifetimeParam) + .chain(ty_params) + .collect() } - pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { + pub fn lifetime_params(self, db: &dyn HirDatabase) -> Vec { let generics = db.generic_params(self.into()); generics .lifetimes @@ -2648,7 +2652,6 @@ impl GenericDef { .map(|(local_id, _)| LifetimeParam { id: LifetimeParamId { parent: self.into(), local_id }, }) - .map(GenericParam::LifetimeParam) .collect() } diff --git a/crates/ide-completion/src/completions/item_list/trait_impl.rs b/crates/ide-completion/src/completions/item_list/trait_impl.rs index 7de1bf2dc13..664aa7b8397 100644 --- a/crates/ide-completion/src/completions/item_list/trait_impl.rs +++ b/crates/ide-completion/src/completions/item_list/trait_impl.rs @@ -833,6 +833,33 @@ impl Test for () { ); } + #[test] + fn fn_with_lifetimes() { + check_edit( + "fn foo", + r#" +trait Test<'a, 'b, T> { + fn foo(&self, a: &'a T, b: &'b T) -> &'a T; +} + +impl<'x, 'y, A> Test<'x, 'y, A> for () { + t$0 +} +"#, + r#" +trait Test<'a, 'b, T> { + fn foo(&self, a: &'a T, b: &'b T) -> &'a T; +} + +impl<'x, 'y, A> Test<'x, 'y, A> for () { + fn foo(&self, a: &'x A, b: &'y A) -> &'x A { + $0 +} +} +"#, + ); + } + #[test] fn complete_without_name() { let test = |completion: &str, hint: &str, completed: &str, next_sibling: &str| { diff --git a/crates/ide-db/src/path_transform.rs b/crates/ide-db/src/path_transform.rs index fe8ffc4354a..6afd61e84dc 100644 --- a/crates/ide-db/src/path_transform.rs +++ b/crates/ide-db/src/path_transform.rs @@ -10,7 +10,7 @@ use syntax::{ }; #[derive(Default)] -struct Substs { +struct AstSubsts { types: Vec, lifetimes: Vec, } @@ -42,7 +42,7 @@ type LifetimeName = String; /// ``` pub struct PathTransform<'a> { generic_def: Option, - substs: Substs, + substs: AstSubsts, target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, } @@ -80,7 +80,12 @@ impl<'a> PathTransform<'a> { target_scope: &'a SemanticsScope<'a>, source_scope: &'a SemanticsScope<'a>, ) -> PathTransform<'a> { - PathTransform { source_scope, target_scope, generic_def: None, substs: Substs::default() } + PathTransform { + source_scope, + target_scope, + generic_def: None, + substs: AstSubsts::default(), + } } pub fn apply(&self, syntax: &SyntaxNode) { @@ -134,7 +139,7 @@ impl<'a> PathTransform<'a> { .into_iter() .flat_map(|it| it.lifetime_params(db)) .zip(self.substs.lifetimes.clone()) - .filter_map(|(k, v)| Some((k.name(db).to_string(), v.lifetime()?))) + .filter_map(|(k, v)| Some((k.name(db).display(db.upcast()).to_string(), v.lifetime()?))) .collect(); Ctx { type_substs, lifetime_substs, target_module, source_scope: self.source_scope } } @@ -279,7 +284,7 @@ impl<'a> Ctx<'a> { // FIXME: It would probably be nicer if we could get this via HIR (i.e. get the // trait ref, and then go from the types in the substs back to the syntax). -fn get_syntactic_substs(impl_def: ast::Impl) -> Option { +fn get_syntactic_substs(impl_def: ast::Impl) -> Option { let target_trait = impl_def.trait_()?; let path_type = match target_trait { ast::Type::PathType(path) => path, @@ -290,8 +295,8 @@ fn get_syntactic_substs(impl_def: ast::Impl) -> Option { get_type_args_from_arg_list(generic_arg_list) } -fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option { - let mut result = Substs::default(); +fn get_type_args_from_arg_list(generic_arg_list: ast::GenericArgList) -> Option { + let mut result = AstSubsts::default(); generic_arg_list.generic_args().for_each(|generic_arg| match generic_arg { ast::GenericArg::TypeArg(type_arg) => result.types.push(type_arg), ast::GenericArg::LifetimeArg(l_arg) => result.lifetimes.push(l_arg),