Skip to content

Commit 41388bf

Browse files
committed
Auto merge of #12263 - andylizi:hide-type-hint-closure, r=Veykril
feat: hide type inlay hints for initializations of closures ![hide_closure_initialization](https://user-images.githubusercontent.com/12008103/168470158-6cb77b18-068e-4431-a8b5-e2b22d50d263.gif) This PR adds an option to hide the inlay hints for `let IDENT_PAT = CLOSURE_EXPR;`, which is a somewhat common coding pattern. Currently the inlay hints for the assigned variable and the closure expression itself are both displayed, making it rather repetitive. In order to be consistent with closure return type hints, only closures with block bodies will be hid by this option. Personally I'd feel comfortable making it always enabled (or at least when closure return type hints are enabled), but considering the precedent set in #10761, I introduced an off-by-default option for this. changelog feature: option to hide type inlay hints for initializations of closures
2 parents f5229ce + 2b1c1a9 commit 41388bf

File tree

5 files changed

+90
-5
lines changed

5 files changed

+90
-5
lines changed

crates/ide/src/inlay_hints.rs

+72-5
Original file line numberDiff line numberDiff line change
@@ -26,6 +26,7 @@ pub struct InlayHintsConfig {
2626
pub lifetime_elision_hints: LifetimeElisionHints,
2727
pub param_names_for_lifetime_elision_hints: bool,
2828
pub hide_named_constructor_hints: bool,
29+
pub hide_closure_initialization_hints: bool,
2930
pub max_length: Option<usize>,
3031
pub closing_brace_hints_min_lines: Option<usize>,
3132
}
@@ -467,10 +468,11 @@ fn closure_ret_hints(
467468
return None;
468469
}
469470

470-
let param_list = match closure.body() {
471-
Some(ast::Expr::BlockExpr(_)) => closure.param_list()?,
472-
_ => return None,
473-
};
471+
if !closure_has_block_body(&closure) {
472+
return None;
473+
}
474+
475+
let param_list = closure.param_list()?;
474476

475477
let closure = sema.descend_node_into_attributes(closure.clone()).pop()?;
476478
let ty = sema.type_of_expr(&ast::Expr::ClosureExpr(closure))?.adjusted();
@@ -693,7 +695,7 @@ fn bind_pat_hints(
693695
let desc_pat = descended.as_ref().unwrap_or(pat);
694696
let ty = sema.type_of_pat(&desc_pat.clone().into())?.original;
695697

696-
if should_not_display_type_hint(sema, pat, &ty) {
698+
if should_not_display_type_hint(sema, config, pat, &ty) {
697699
return None;
698700
}
699701

@@ -848,6 +850,7 @@ fn pat_is_enum_variant(db: &RootDatabase, bind_pat: &ast::IdentPat, pat_ty: &hir
848850

849851
fn should_not_display_type_hint(
850852
sema: &Semantics<RootDatabase>,
853+
config: &InlayHintsConfig,
851854
bind_pat: &ast::IdentPat,
852855
pat_ty: &hir::Type,
853856
) -> bool {
@@ -863,6 +866,18 @@ fn should_not_display_type_hint(
863866
}
864867
}
865868

869+
if config.hide_closure_initialization_hints {
870+
if let Some(parent) = bind_pat.syntax().parent() {
871+
if let Some(it) = ast::LetStmt::cast(parent.clone()) {
872+
if let Some(ast::Expr::ClosureExpr(closure)) = it.initializer() {
873+
if closure_has_block_body(&closure) {
874+
return true;
875+
}
876+
}
877+
}
878+
}
879+
}
880+
866881
for node in bind_pat.syntax().ancestors() {
867882
match_ast! {
868883
match node {
@@ -889,6 +904,10 @@ fn should_not_display_type_hint(
889904
false
890905
}
891906

907+
fn closure_has_block_body(closure: &ast::ClosureExpr) -> bool {
908+
matches!(closure.body(), Some(ast::Expr::BlockExpr(_)))
909+
}
910+
892911
fn should_hide_param_name_hint(
893912
sema: &Semantics<RootDatabase>,
894913
callable: &hir::Callable,
@@ -1083,6 +1102,7 @@ mod tests {
10831102
reborrow_hints: ReborrowHints::Always,
10841103
binding_mode_hints: false,
10851104
hide_named_constructor_hints: false,
1105+
hide_closure_initialization_hints: false,
10861106
param_names_for_lifetime_elision_hints: false,
10871107
max_length: None,
10881108
closing_brace_hints_min_lines: None,
@@ -2034,6 +2054,53 @@ fn main() {
20342054
);
20352055
}
20362056

2057+
#[test]
2058+
fn skip_closure_type_hints() {
2059+
check_with_config(
2060+
InlayHintsConfig {
2061+
type_hints: true,
2062+
hide_closure_initialization_hints: true,
2063+
..DISABLED_CONFIG
2064+
},
2065+
r#"
2066+
//- minicore: fn
2067+
fn main() {
2068+
let multiple_2 = |x: i32| { x * 2 };
2069+
2070+
let multiple_2 = |x: i32| x * 2;
2071+
// ^^^^^^^^^^ |i32| -> i32
2072+
2073+
let (not) = (|x: bool| { !x });
2074+
// ^^^ |bool| -> bool
2075+
2076+
let (is_zero, _b) = (|x: usize| { x == 0 }, false);
2077+
// ^^^^^^^ |usize| -> bool
2078+
// ^^ bool
2079+
2080+
let plus_one = |x| { x + 1 };
2081+
// ^ u8
2082+
foo(plus_one);
2083+
2084+
let add_mul = bar(|x: u8| { x + 1 });
2085+
// ^^^^^^^ impl FnOnce(u8) -> u8 + ?Sized
2086+
2087+
let closure = if let Some(6) = add_mul(2).checked_sub(1) {
2088+
// ^^^^^^^ fn(i32) -> i32
2089+
|x: i32| { x * 2 }
2090+
} else {
2091+
|x: i32| { x * 3 }
2092+
};
2093+
}
2094+
2095+
fn foo(f: impl FnOnce(u8) -> u8) {}
2096+
2097+
fn bar(f: impl FnOnce(u8) -> u8) -> impl FnOnce(u8) -> u8 {
2098+
move |x: u8| f(x) * 2
2099+
}
2100+
"#,
2101+
);
2102+
}
2103+
20372104
#[test]
20382105
fn hint_truncation() {
20392106
check_with_config(

crates/ide/src/static_index.rs

+1
Original file line numberDiff line numberDiff line change
@@ -113,6 +113,7 @@ impl StaticIndex<'_> {
113113
lifetime_elision_hints: crate::LifetimeElisionHints::Never,
114114
reborrow_hints: crate::ReborrowHints::Never,
115115
hide_named_constructor_hints: false,
116+
hide_closure_initialization_hints: false,
116117
param_names_for_lifetime_elision_hints: false,
117118
binding_mode_hints: false,
118119
max_length: Some(25),

crates/rust-analyzer/src/config.rs

+6
Original file line numberDiff line numberDiff line change
@@ -281,6 +281,9 @@ config_data! {
281281
inlayHints_renderColons: bool = "true",
282282
/// Whether to show inlay type hints for variables.
283283
inlayHints_typeHints_enable: bool = "true",
284+
/// Whether to hide inlay type hints for `let` statements that initialize to a closure.
285+
/// Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
286+
inlayHints_typeHints_hideClosureInitialization: bool = "false",
284287
/// Whether to hide inlay type hints for constructors.
285288
inlayHints_typeHints_hideNamedConstructor: bool = "false",
286289

@@ -1000,6 +1003,9 @@ impl Config {
10001003
LifetimeElisionDef::SkipTrivial => ide::LifetimeElisionHints::SkipTrivial,
10011004
},
10021005
hide_named_constructor_hints: self.data.inlayHints_typeHints_hideNamedConstructor,
1006+
hide_closure_initialization_hints: self
1007+
.data
1008+
.inlayHints_typeHints_hideClosureInitialization,
10031009
reborrow_hints: match self.data.inlayHints_reborrowHints_enable {
10041010
ReborrowHintsDef::Always => ide::ReborrowHints::Always,
10051011
ReborrowHintsDef::Never => ide::ReborrowHints::Never,

docs/user/generated_config.adoc

+6
Original file line numberDiff line numberDiff line change
@@ -407,6 +407,12 @@ Whether to render leading colons for type hints, and trailing colons for paramet
407407
--
408408
Whether to show inlay type hints for variables.
409409
--
410+
[[rust-analyzer.inlayHints.typeHints.hideClosureInitialization]]rust-analyzer.inlayHints.typeHints.hideClosureInitialization (default: `false`)::
411+
+
412+
--
413+
Whether to hide inlay type hints for `let` statements that initialize to a closure.
414+
Only applies to closures with blocks, same as `#rust-analyzer.inlayHints.closureReturnTypeHints.enable#`.
415+
--
410416
[[rust-analyzer.inlayHints.typeHints.hideNamedConstructor]]rust-analyzer.inlayHints.typeHints.hideNamedConstructor (default: `false`)::
411417
+
412418
--

editors/code/package.json

+5
Original file line numberDiff line numberDiff line change
@@ -868,6 +868,11 @@
868868
"default": true,
869869
"type": "boolean"
870870
},
871+
"rust-analyzer.inlayHints.typeHints.hideClosureInitialization": {
872+
"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#`.",
873+
"default": false,
874+
"type": "boolean"
875+
},
871876
"rust-analyzer.inlayHints.typeHints.hideNamedConstructor": {
872877
"markdownDescription": "Whether to hide inlay type hints for constructors.",
873878
"default": false,

0 commit comments

Comments
 (0)