Skip to content

Add text edit support for return type hints on non-block body closures #19348

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 4 commits into from
Mar 21, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
10 changes: 8 additions & 2 deletions crates/ide/src/inlay_hints/bind_pat.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1140,12 +1140,11 @@ fn test() {

#[test]
fn no_edit_for_closure_return_without_body_block() {
// We can lift this limitation; see FIXME in closure_ret module.
let config = InlayHintsConfig {
closure_return_type_hints: ClosureReturnTypeHints::Always,
..TEST_CONFIG
};
check_no_edit(
check_edit(
config,
r#"
struct S<T>(T);
Expand All @@ -1154,6 +1153,13 @@ fn test() {
let f = |a: S<usize>| S(a);
}
"#,
expect![[r#"
struct S<T>(T);
fn test() {
let f = || -> i32 { 3 };
let f = |a: S<usize>| -> S<S<usize>> { S(a) };
}
"#]],
);
}

Expand Down
30 changes: 26 additions & 4 deletions crates/ide/src/inlay_hints/closure_ret.rs
Original file line number Diff line number Diff line change
@@ -1,8 +1,8 @@
//! Implementation of "closure return type" inlay hints.
//!
//! Tests live in [`bind_pat`][super::bind_pat] module.
use hir::DisplayTarget;
use ide_db::famous_defs::FamousDefs;
use hir::{DisplayTarget, HirDisplay};
use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
use syntax::ast::{self, AstNode};

use crate::{
Expand Down Expand Up @@ -48,7 +48,6 @@ pub(super) fn hints(
if arrow.is_none() {
label.prepend_str(" -> ");
}
// FIXME?: We could provide text edit to insert braces for closures with non-block body.
let text_edit = if has_block_body {
ty_to_text_edit(
sema,
Expand All @@ -62,7 +61,30 @@ pub(super) fn hints(
if arrow.is_none() { " -> " } else { "" },
)
} else {
None
Some(config.lazy_text_edit(|| {
let body = closure.body();
let body_range = match body {
Some(body) => body.syntax().text_range(),
None => return TextEdit::builder().finish(),
};
let mut builder = TextEdit::builder();
let insert_pos = param_list.syntax().text_range().end();

let rendered = match sema.scope(closure.syntax()).and_then(|scope| {
ty.display_source_code(scope.db, scope.module().into(), false).ok()
}) {
Some(rendered) => rendered,
None => return TextEdit::builder().finish(),
};

let arrow_text = if arrow.is_none() { " -> ".to_owned() } else { "".to_owned() };
builder.insert(insert_pos, arrow_text);
builder.insert(insert_pos, rendered);
builder.insert(body_range.start(), "{ ".to_owned());
builder.insert(body_range.end(), " }".to_owned());

builder.finish()
}))
};

acc.push(InlayHint {
Expand Down