about summary refs log tree commit diff
diff options
context:
space:
mode:
authorroifewu <roifewu@gmail.com>2025-04-21 11:20:26 +0800
committerroifewu <roifewu@gmail.com>2025-04-23 00:01:35 +0800
commit68c03725c953c4d3584e533f712aedb9e7e03fa5 (patch)
tree9117b1f5457a5a3367b50bc03fd80eda435a4ada
parent31c591846348793d59f99a86778e2dd2e3df2442 (diff)
downloadrust-68c03725c953c4d3584e533f712aedb9e7e03fa5.tar.gz
rust-68c03725c953c4d3584e533f712aedb9e7e03fa5.zip
fix: panics in inlay hints that produce empty text edits for closure return types
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs12
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs1
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs59
3 files changed, 31 insertions, 41 deletions
diff --git a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
index 5b1738b66e5..06dfa8ddec0 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
index 0718e5ac646..52ea2e5ec58 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs
+++ b/src/tools/rust-analyzer/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/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs b/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
index f9b21c672dc..9e600b5455b 100644
--- a/src/tools/rust-analyzer/crates/ide/src/inlay_hints/closure_ret.rs
+++ b/src/tools/rust-analyzer/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,