Skip to content

Commit

Permalink
Auto merge of rust-lang#12263 - andylizi:hide-type-hint-closure, r=Ve…
Browse files Browse the repository at this point in the history
…ykril

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 rust-lang#10761, I introduced an off-by-default option for this.

changelog feature: option to hide type inlay hints for initializations of closures
  • Loading branch information
bors committed May 20, 2022
2 parents f5229ce + 2b1c1a9 commit 41388bf
Show file tree
Hide file tree
Showing 5 changed files with 90 additions and 5 deletions.
77 changes: 72 additions & 5 deletions crates/ide/src/inlay_hints.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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>,
}
Expand Down Expand Up @@ -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();
Expand Down Expand Up @@ -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;
}

Expand Down Expand Up @@ -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 {
Expand All @@ -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 {
Expand All @@ -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,
Expand Down Expand Up @@ -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,
Expand Down Expand Up @@ -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(
Expand Down
1 change: 1 addition & 0 deletions crates/ide/src/static_index.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
Expand Down
6 changes: 6 additions & 0 deletions crates/rust-analyzer/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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",

Expand Down Expand Up @@ -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,
Expand Down
6 changes: 6 additions & 0 deletions docs/user/generated_config.adoc
Original file line number Diff line number Diff line change
Expand Up @@ -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`)::
+
--
Expand Down
5 changes: 5 additions & 0 deletions editors/code/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 41388bf

Please sign in to comment.