Unnamed repository; edit this file 'description' to name the repository.
fix: panics in inlay hints that produce empty text edits for closure return types
roifewu 2025-04-22
parent 723121e · commit 97fa2a7
-rw-r--r--crates/ide/src/inlay_hints.rs12
-rw-r--r--crates/ide/src/inlay_hints/bind_pat.rs1
-rw-r--r--crates/ide/src/inlay_hints/closure_ret.rs59
3 files changed, 31 insertions, 41 deletions
diff --git a/crates/ide/src/inlay_hints.rs b/crates/ide/src/inlay_hints.rs
index 5b1738b66e..06dfa8ddec 100644
--- a/crates/ide/src/inlay_hints.rs
+++ b/crates/ide/src/inlay_hints.rs
@@ -8,7 +8,7 @@ use hir::{
ClosureStyle, DisplayTarget, EditionedFileId, HasVisibility, HirDisplay, HirDisplayError,
HirWrite, ModuleDef, ModuleDefId, Semantics, sym,
};
-use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs};
+use ide_db::{FileRange, RootDatabase, famous_defs::FamousDefs, text_edit::TextEditBuilder};
use ide_db::{FxHashSet, text_edit::TextEdit};
use itertools::Itertools;
use smallvec::{SmallVec, smallvec};
@@ -813,7 +813,8 @@ fn ty_to_text_edit(
config: &InlayHintsConfig,
node_for_hint: &SyntaxNode,
ty: &hir::Type,
- offset_to_insert: TextSize,
+ offset_to_insert_ty: TextSize,
+ additional_edits: &dyn Fn(&mut TextEditBuilder),
prefix: impl Into<String>,
) -> Option<LazyProperty<TextEdit>> {
// FIXME: Limit the length and bail out on excess somehow?
@@ -822,8 +823,11 @@ fn ty_to_text_edit(
.and_then(|scope| ty.display_source_code(scope.db, scope.module().into(), false).ok())?;
Some(config.lazy_text_edit(|| {
let mut builder = TextEdit::builder();
- builder.insert(offset_to_insert, prefix.into());
- builder.insert(offset_to_insert, rendered);
+ builder.insert(offset_to_insert_ty, prefix.into());
+ builder.insert(offset_to_insert_ty, rendered);
+
+ additional_edits(&mut builder);
+
builder.finish()
}))
}
diff --git a/crates/ide/src/inlay_hints/bind_pat.rs b/crates/ide/src/inlay_hints/bind_pat.rs
index 0718e5ac64..52ea2e5ec5 100644
--- a/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/crates/ide/src/inlay_hints/bind_pat.rs
@@ -87,6 +87,7 @@ pub(super) fn hints(
.as_ref()
.map_or_else(|| pat.syntax().text_range(), |t| t.text_range())
.end(),
+ &|_| (),
if colon_token.is_some() { "" } else { ": " },
)
} else {
diff --git a/crates/ide/src/inlay_hints/closure_ret.rs b/crates/ide/src/inlay_hints/closure_ret.rs
index f9b21c672d..9e600b5455 100644
--- a/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/crates/ide/src/inlay_hints/closure_ret.rs
@@ -1,8 +1,8 @@
//! Implementation of "closure return type" inlay hints.
//!
//! Tests live in [`bind_pat`][super::bind_pat] module.
-use hir::{DisplayTarget, HirDisplay};
-use ide_db::{famous_defs::FamousDefs, text_edit::TextEdit};
+use hir::DisplayTarget;
+use ide_db::{famous_defs::FamousDefs, text_edit::TextEditBuilder};
use syntax::ast::{self, AstNode};
use crate::{
@@ -49,45 +49,30 @@ pub(super) fn hints(
if arrow.is_none() {
label.prepend_str(" -> ");
}
- let text_edit = if has_block_body {
- ty_to_text_edit(
- sema,
- config,
- descended_closure.syntax(),
- &ty,
- arrow
- .as_ref()
- .map_or_else(|| param_list.syntax().text_range(), |t| t.text_range())
- .end(),
- if arrow.is_none() { " -> " } else { "" },
- )
- } else {
- 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(descended_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 offset_to_insert_ty =
+ arrow.as_ref().map_or_else(|| param_list.syntax().text_range(), |t| t.text_range()).end();
- 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()
- }))
+ // Insert braces if necessary
+ let insert_braces = |builder: &mut TextEditBuilder| {
+ if !has_block_body {
+ if let Some(range) = closure.body().map(|b| b.syntax().text_range()) {
+ builder.insert(range.start(), "{ ".to_owned());
+ builder.insert(range.end(), " }".to_owned());
+ }
+ }
};
+ let text_edit = ty_to_text_edit(
+ sema,
+ config,
+ descended_closure.syntax(),
+ &ty,
+ offset_to_insert_ty,
+ &insert_braces,
+ if arrow.is_none() { " -> " } else { "" },
+ );
+
acc.push(InlayHint {
range: param_list.syntax().text_range(),
kind: InlayKind::Type,