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
This commit is contained in:
bors 2022-05-20 12:35:36 +00:00
commit 41388bf81a
5 changed files with 90 additions and 5 deletions

View file

@ -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<usize>,
pub closing_brace_hints_min_lines: Option<usize>,
}
@ -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<RootDatabase>,
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<RootDatabase>,
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(

View file

@ -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),

View file

@ -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,

View file

@ -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`)::
+
--

View file

@ -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,