diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs index 5eb63a42ad..3689bd5a42 100644 --- a/crates/ide/src/inlay_hints.rs +++ b/crates/ide/src/inlay_hints.rs @@ -26,6 +26,7 @@ pub struct InlayHintsConfig { pub lifetime_elision_hints: LifetimeElisionHints, pub param_names_for_lifetime_elision_hints: bool, pub hide_named_constructor_hints: bool, + pub hide_closure_initialization_hints: bool, pub max_length: Option, pub closing_brace_hints_min_lines: Option, } @@ -467,10 +468,11 @@ fn closure_ret_hints( return None; } - let param_list = match closure.body() { - Some(ast::Expr::BlockExpr(_)) => closure.param_list()?, - _ => return None, - }; + if !closure_has_block_body(&closure) { + return None; + } + + let param_list = closure.param_list()?; let closure = sema.descend_node_into_attributes(closure.clone()).pop()?; let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted(); @@ -693,7 +695,7 @@ fn bind_pat_hints( let desc_pat = descended.as_ref().unwrap_or(pat); let ty = sema.type_of_pat(&desc_pat.clone().into())?.original; - if should_not_display_type_hint(sema, pat, &ty) { + if should_not_display_type_hint(sema, config, pat, &ty) { return None; } @@ -848,6 +850,7 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir fn should_not_display_type_hint( sema: &Semantics, + config: &InlayHintsConfig, bind_pat: &ast::IdentPat, pat_ty: &hir::Type, ) -> bool { @@ -863,6 +866,18 @@ fn should_not_display_type_hint( } } + if config.hide_closure_initialization_hints { + if let Some(parent) = bind_pat.syntax().parent() { + if let Some(it) = ast::LetStmt::cast(parent.clone()) { + if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() { + if closure_has_block_body(&closure) { + return true; + } + } + } + } + } + for node in bind_pat.syntax().ancestors() { match_ast! { match node { @@ -889,6 +904,10 @@ fn should_not_display_type_hint( false } +fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool { + matches!(closure.body(), Some(ast::Expr::BlockExpr(_))) +} + fn should_hide_param_name_hint( sema: &Semantics, callable: &hir::Callable, @@ -1083,6 +1102,7 @@ mod tests { reborrow_hints: ReborrowHints::Always, binding_mode_hints: false, hide_named_constructor_hints: false, + hide_closure_initialization_hints: false, param_names_for_lifetime_elision_hints: false, max_length: None, closing_brace_hints_min_lines: None, @@ -2034,6 +2054,53 @@ fn main() { ); } + #[test] + fn skip_closure_type_hints() { + check_with_config( + InlayHintsConfig { + type_hints: true, + hide_closure_initialization_hints: true, + ..DISABLED_CONFIG + }, + r#" +//- minicore: fn +fn main() { + let multiple_2 = |x: i32| { x * 2 }; + + let multiple_2 = |x: i32| x * 2; + // ^^^^^^^^^^ |i32| -> i32 + + let (not) = (|x: bool| { !x }); + // ^^^ |bool| -> bool + + let (is_zero, _b) = (|x: usize| { x == 0 }, false); + // ^^^^^^^ |usize| -> bool + // ^^ bool + + let plus_one = |x| { x + 1 }; + // ^ u8 + foo(plus_one); + + let add_mul = bar(|x: u8| { x + 1 }); + // ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized + + let closure = if let Some(6) = add_mul(2).checked_sub(1) { + // ^^^^^^^ fn(i32) -> i32 + |x: i32| { x * 2 } + } else { + |x: i32| { x * 3 } + }; +} + +fn foo(f: impl FnOnce(u8) -> u8) {} + +fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 { + move |x: u8| f(x) * 2 +} +"#, + ); + } + #[test] fn hint_truncation() { check_with_config( diff --git a/crates/ide/src/static_index.rs b/crates/ide/src/static_index.rs index 01d7213630..006b18b7fd 100644 --- a/crates/ide/src/static_index.rs +++ b/crates/ide/src/static_index.rs @@ -113,6 +113,7 @@ impl StaticIndex<'_> { lifetime_elision_hints: crate::LifetimeElisionHints::Never, reborrow_hints: crate::ReborrowHints::Never, hide_named_constructor_hints: false, + hide_closure_initialization_hints: false, param_names_for_lifetime_elision_hints: false, binding_mode_hints: false, max_length: Some(25), diff --git a/crates/rust-analyzer/src/config.rs b/crates/rust-analyzer/src/config.rs index afa83e6206..d7ae4c72f5 100644 --- a/crates/rust-analyzer/src/config.rs +++ b/crates/rust-analyzer/src/config.rs @@ -281,6 +281,9 @@ config_data! { inlayHints_renderColons: bool = "true", /// Whether to show inlay type hints for variables. inlayHints_typeHints_enable: bool = "true", + /// Whether to hide inlay type hints for `let` statements that initialize to a closure. + /// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. + inlayHints_typeHints_hideClosureInitialization: bool = "false", /// Whether to hide inlay type hints for constructors. inlayHints_typeHints_hideNamedConstructor: bool = "false", @@ -1000,6 +1003,9 @@ impl Config { LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial, }, hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor, + hide_closure_initialization_hints: self + .data + .inlayHints_typeHints_hideClosureInitialization, reborrow_hints: match self.data.inlayHints_reborrowHints_enable { ReborrowHintsDef::Always => ide::ReborrowHints::Always, ReborrowHintsDef::Never => ide::ReborrowHints::Never, diff --git a/docs/user/generated_config.adoc b/docs/user/generated_config.adoc index 30722af08c..955f085d3f 100644 --- a/docs/user/generated_config.adoc +++ b/docs/user/generated_config.adoc @@ -407,6 +407,12 @@ Whether to render leading colons for type hints, and trailing colons for paramet -- Whether to show inlay type hints for variables. -- +[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`):: ++ +-- +Whether to hide inlay type hints for `let` statements that initialize to a closure. +Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`. +-- [[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`):: + -- diff --git a/editors/code/package.json b/editors/code/package.json index e81dfff278..f46c7ea92d 100644 --- a/editors/code/package.json +++ b/editors/code/package.json @@ -868,6 +868,11 @@ "default": true, "type": "boolean" }, + "rust-analyzer.inlayHints.typeHints.hideClosureInitialization": { + "markdownDescription": "Whether to hide inlay type hints for `let` statements that initialize to a closure.\nOnly applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.", + "default": false, + "type": "boolean" + }, "rust-analyzer.inlayHints.typeHints.hideNamedConstructor": { "markdownDescription": "Whether to hide inlay type hints for constructors.", "default": false,