about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2023-01-03 10:59:21 +0000
committerbors <bors@rust-lang.org>2023-01-03 10:59:21 +0000
commit5033213fc973e209c84b1c0309933574230254cc (patch)
treec0b0f678e40b0f00216f12708a3741810b769461
parent50801b7d6a5c18d24ae47e5a8963431899da20cd (diff)
parentb996a54cd845ae315a7b089437b43bf1b79a5e65 (diff)
downloadrust-5033213fc973e209c84b1c0309933574230254cc.tar.gz
rust-5033213fc973e209c84b1c0309933574230254cc.zip
Auto merge of #13885 - Veykril:bin-op-adjust, r=Veykril
Skip lifetime elision on fn pointers and fn trait types

These currently don't work correctly, so it's better to not render them at all there
-rw-r--r--crates/hir-ty/src/infer/expr.rs1
-rw-r--r--crates/ide-assists/src/handlers/add_explicit_type.rs5
-rw-r--r--crates/ide-assists/src/handlers/extract_type_alias.rs120
-rw-r--r--crates/ide-db/src/syntax_helpers/node_ext.rs9
-rw-r--r--crates/ide/src/inlay_hints/fn_lifetime_fn.rs30
5 files changed, 100 insertions, 65 deletions
diff --git a/crates/hir-ty/src/infer/expr.rs b/crates/hir-ty/src/infer/expr.rs
index 2e5c4244109..a015f67024f 100644
--- a/crates/hir-ty/src/infer/expr.rs
+++ b/crates/hir-ty/src/infer/expr.rs
@@ -334,6 +334,7 @@ impl<'a> InferenceContext<'a> {
                 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
                     }
diff --git a/crates/ide-assists/src/handlers/add_explicit_type.rs b/crates/ide-assists/src/handlers/add_explicit_type.rs
index b5f99726fe1..0057f439f1a 100644
--- a/crates/ide-assists/src/handlers/add_explicit_type.rs
+++ b/crates/ide-assists/src/handlers/add_explicit_type.rs
@@ -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;
diff --git a/crates/ide-assists/src/handlers/extract_type_alias.rs b/crates/ide-assists/src/handlers/extract_type_alias.rs
index 3116935fc5e..0505f5784f8 100644
--- a/crates/ide-assists/src/handlers/extract_type_alias.rs
+++ b/crates/ide-assists/src/handlers/extract_type_alias.rs
@@ -108,76 +108,80 @@ fn collect_used_generics<'gp>(
     }
 
     let mut generics = Vec::new();
-    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() {
-                    if let Some(param) = known_generics.iter().find(|gp| {
-                        match gp {
-                            ast::GenericParam::ConstParam(cp) => cp.name(),
-                            ast::GenericParam::TypeParam(tp) => tp.name(),
-                            _ => None,
+    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() {
+                        if let Some(param) = known_generics.iter().find(|gp| {
+                            match gp {
+                                ast::GenericParam::ConstParam(cp) => cp.name(),
+                                ast::GenericParam::TypeParam(tp) => tp.name(),
+                                _ => None,
+                            }
+                            .map_or(false, |n| n.text() == name_ref.text())
+                        }) {
+                            generics.push(param);
                         }
-                        .map_or(false, |n| n.text() == name_ref.text())
-                    }) {
-                        generics.push(param);
                     }
+                    generics.extend(
+                        path.segments()
+                            .filter_map(|seg| seg.generic_arg_list())
+                            .flat_map(|it| it.generic_args())
+                            .filter_map(|it| match it {
+                                ast::GenericArg::LifetimeArg(lt) => {
+                                    let lt = lt.lifetime()?;
+                                    known_generics.iter().find(find_lifetime(&lt.text()))
+                                }
+                                _ => None,
+                            }),
+                    );
                 }
-                generics.extend(
-                    path.segments()
-                        .filter_map(|seg| seg.generic_arg_list())
-                        .flat_map(|it| it.generic_args())
-                        .filter_map(|it| match it {
-                            ast::GenericArg::LifetimeArg(lt) => {
-                                let lt = lt.lifetime()?;
-                                known_generics.iter().find(find_lifetime(&lt.text()))
-                            }
-                            _ => None,
-                        }),
-                );
             }
-        }
-        ast::Type::ImplTraitType(impl_ty) => {
-            if let Some(it) = impl_ty.type_bound_list() {
-                generics.extend(
-                    it.bounds()
-                        .filter_map(|it| it.lifetime())
-                        .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
-                );
+            ast::Type::ImplTraitType(impl_ty) => {
+                if let Some(it) = impl_ty.type_bound_list() {
+                    generics.extend(
+                        it.bounds()
+                            .filter_map(|it| it.lifetime())
+                            .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
+                    );
+                }
             }
-        }
-        ast::Type::DynTraitType(dyn_ty) => {
-            if let Some(it) = dyn_ty.type_bound_list() {
-                generics.extend(
-                    it.bounds()
-                        .filter_map(|it| it.lifetime())
-                        .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
-                );
+            ast::Type::DynTraitType(dyn_ty) => {
+                if let Some(it) = dyn_ty.type_bound_list() {
+                    generics.extend(
+                        it.bounds()
+                            .filter_map(|it| it.lifetime())
+                            .filter_map(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
+                    );
+                }
             }
-        }
-        ast::Type::RefType(ref_) => generics.extend(
-            ref_.lifetime().and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
-        ),
-        ast::Type::ArrayType(ar) => {
-            if let Some(expr) = ar.expr() {
-                if let ast::Expr::PathExpr(p) = expr {
-                    if let Some(path) = p.path() {
-                        if let Some(name_ref) = path.as_single_name_ref() {
-                            if let Some(param) = known_generics.iter().find(|gp| {
-                                if let ast::GenericParam::ConstParam(cp) = gp {
-                                    cp.name().map_or(false, |n| n.text() == name_ref.text())
-                                } else {
-                                    false
+            ast::Type::RefType(ref_) => generics.extend(
+                ref_.lifetime()
+                    .and_then(|lt| known_generics.iter().find(find_lifetime(&lt.text()))),
+            ),
+            ast::Type::ArrayType(ar) => {
+                if let Some(expr) = ar.expr() {
+                    if let ast::Expr::PathExpr(p) = expr {
+                        if let Some(path) = p.path() {
+                            if let Some(name_ref) = path.as_single_name_ref() {
+                                if let Some(param) = known_generics.iter().find(|gp| {
+                                    if let ast::GenericParam::ConstParam(cp) = gp {
+                                        cp.name().map_or(false, |n| n.text() == name_ref.text())
+                                    } else {
+                                        false
+                                    }
+                                }) {
+                                    generics.push(param);
                                 }
-                            }) {
-                                generics.push(param);
                             }
                         }
                     }
                 }
             }
-        }
-        _ => (),
+            _ => (),
+        };
+        false
     });
     // stable resort to lifetime, type, const
     generics.sort_by_key(|gp| match gp {
diff --git a/crates/ide-db/src/syntax_helpers/node_ext.rs b/crates/ide-db/src/syntax_helpers/node_ext.rs
index b72003ff363..aa03478599d 100644
--- a/crates/ide-db/src/syntax_helpers/node_ext.rs
+++ b/crates/ide-db/src/syntax_helpers/node_ext.rs
@@ -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) => {
diff --git a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
index 1f5bcea63a2..2aa5e3dc734 100644
--- a/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
+++ b/crates/ide/src/inlay_hints/fn_lifetime_fn.rs
@@ -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,
             })
         }
     }
@@ -298,4 +308,18 @@ impl () {
 "#,
         );
     }
+
+    #[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(&()) -> &()) {}
+"#,
+        );
+    }
 }