Skip lifetime elision on fn pointers and fn trait types

This commit is contained in:
Lukas Wirth 2023-01-03 11:58:31 +01:00
parent 506895fa2f
commit b996a54cd8
5 changed files with 105 additions and 70 deletions

View File

@ -334,6 +334,7 @@ fn infer_expr_inner(&mut self, tgt_expr: ExprId, expected: &Expectation) -> Ty {
let (param_tys, ret_ty) = match res { let (param_tys, ret_ty) = match res {
Some(res) => { Some(res) => {
let adjustments = auto_deref_adjust_steps(&derefs); let adjustments = auto_deref_adjust_steps(&derefs);
// FIXME: Handle call adjustments for Fn/FnMut
self.write_expr_adj(*callee, adjustments); self.write_expr_adj(*callee, adjustments);
res res
} }

View File

@ -47,7 +47,10 @@ pub(crate) fn add_explicit_type(acc: &mut Assists, ctx: &AssistContext<'_>) -> O
// Don't enable the assist if there is a type ascription without any placeholders // Don't enable the assist if there is a type ascription without any placeholders
if let Some(ty) = &ascribed_ty { if let Some(ty) = &ascribed_ty {
let mut contains_infer_ty = false; let mut contains_infer_ty = false;
walk_ty(ty, &mut |ty| contains_infer_ty |= matches!(ty, ast::Type::InferType(_))); walk_ty(ty, &mut |ty| {
contains_infer_ty |= matches!(ty, ast::Type::InferType(_));
false
});
if !contains_infer_ty { if !contains_infer_ty {
cov_mark::hit!(add_explicit_type_not_applicable_if_ty_already_specified); cov_mark::hit!(add_explicit_type_not_applicable_if_ty_already_specified);
return None; return None;

View File

@ -108,7 +108,8 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
} }
let mut generics = Vec::new(); let mut generics = Vec::new();
walk_ty(ty, &mut |ty| match ty { walk_ty(ty, &mut |ty| {
match ty {
ast::Type::PathType(ty) => { ast::Type::PathType(ty) => {
if let Some(path) = ty.path() { if let Some(path) = ty.path() {
if let Some(name_ref) = path.as_single_name_ref() { if let Some(name_ref) = path.as_single_name_ref() {
@ -156,7 +157,8 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
} }
} }
ast::Type::RefType(ref_) => generics.extend( ast::Type::RefType(ref_) => generics.extend(
ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))), ref_.lifetime()
.and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
), ),
ast::Type::ArrayType(ar) => { ast::Type::ArrayType(ar) => {
if let Some(expr) = ar.expr() { if let Some(expr) = ar.expr() {
@ -178,6 +180,8 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
} }
} }
_ => (), _ => (),
};
false
}); });
// stable resort to lifetime, type, const // stable resort to lifetime, type, const
generics.sort_by_key(|gp| match gp { generics.sort_by_key(|gp| match gp {

View File

@ -173,7 +173,8 @@ pub fn walk_pat(pat: &ast::Pat, cb: &mut dyn FnMut(ast::Pat)) {
} }
/// Preorder walk all the type's sub types. /// Preorder walk all the type's sub types.
pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) { // FIXME: Make the control flow more proper
pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type) -> bool) {
let mut preorder = ty.syntax().preorder(); let mut preorder = ty.syntax().preorder();
while let Some(event) = preorder.next() { while let Some(event) = preorder.next() {
let node = match event { let node = match event {
@ -184,10 +185,12 @@ pub fn walk_ty(ty: &ast::Type, cb: &mut dyn FnMut(ast::Type)) {
match ast::Type::cast(node) { match ast::Type::cast(node) {
Some(ty @ ast::Type::MacroType(_)) => { Some(ty @ ast::Type::MacroType(_)) => {
preorder.skip_subtree(); preorder.skip_subtree();
cb(ty) cb(ty);
} }
Some(ty) => { Some(ty) => {
cb(ty); if cb(ty) {
preorder.skip_subtree();
}
} }
// skip const args // skip const args
None if ast::ConstArg::can_cast(kind) => { None if ast::ConstArg::can_cast(kind) => {

View File

@ -59,9 +59,14 @@ pub(super) fn hints(
r.amp_token(), r.amp_token(),
lifetime, lifetime,
is_elided, is_elided,
)) ));
false
} }
_ => (), ast::Type::FnPtrType(_) => true,
ast::Type::PathType(t) => {
t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some()
}
_ => false,
}) })
}); });
acc acc
@ -146,8 +151,13 @@ pub(super) fn hints(
is_trivial = false; is_trivial = false;
acc.push(mk_lt_hint(amp, output_lt.to_string())); acc.push(mk_lt_hint(amp, output_lt.to_string()));
} }
false
} }
_ => (), ast::Type::FnPtrType(_) => true,
ast::Type::PathType(t) => {
t.path().and_then(|it| it.segment()).and_then(|it| it.param_list()).is_some()
}
_ => false,
}) })
} }
} }
@ -295,6 +305,20 @@ fn foo(&self, a: &()) -> &() {}
// ^^^<'0, '1> // ^^^<'0, '1>
// ^'0 ^'1 ^'0 // ^'0 ^'1 ^'0
} }
"#,
);
}
#[test]
fn hints_lifetimes_skip_fn_likes() {
check_with_config(
InlayHintsConfig {
lifetime_elision_hints: LifetimeElisionHints::Always,
..TEST_CONFIG
},
r#"
fn fn_ptr(a: fn(&()) -> &()) {}
fn fn_trait<>(a: impl Fn(&()) -> &()) {}
"#, "#,
); );
} }