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 {
Some(res) => {
let adjustments = auto_deref_adjust_steps(&derefs);
// FIXME: Handle call adjustments for Fn/FnMut
self.write_expr_adj(*callee, adjustments);
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
if let Some(ty) = &ascribed_ty {
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 {
cov_mark::hit!(add_explicit_type_not_applicable_if_ty_already_specified);
return None;

View File

@ -108,7 +108,8 @@ fn find_lifetime(text: &str) -> impl Fn(&&ast::GenericParam) -> bool + '_ {
}
let mut generics = Vec::new();
walk_ty(ty, &mut |ty| match ty {
walk_ty(ty, &mut |ty| {
match ty {
ast::Type::PathType(ty) => {
if let Some(path) = ty.path() {
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(
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) => {
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
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.
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();
while let Some(event) = preorder.next() {
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) {
Some(ty @ ast::Type::MacroType(_)) => {
preorder.skip_subtree();
cb(ty)
cb(ty);
}
Some(ty) => {
cb(ty);
if cb(ty) {
preorder.skip_subtree();
}
}
// skip const args
None if ast::ConstArg::can_cast(kind) => {

View File

@ -59,9 +59,14 @@ pub(super) fn hints(
r.amp_token(),
lifetime,
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
@ -146,8 +151,13 @@ pub(super) fn hints(
is_trivial = false;
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
}
"#,
);
}
#[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(&()) -> &()) {}
"#,
);
}