about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-08-01 14:16:08 +0000
committerbors <bors@rust-lang.org>2024-08-01 14:16:08 +0000
commit61ebcf631b3c3267f6166fc97917da7c30d4d846 (patch)
tree2f11a7718a53f2b9b6b6c9ed5ff17dac4a01effe
parent9ec4844925a37aae5665491b43ca526d47501d48 (diff)
parent44f5392f5a7f6ab4a6e8c42a436ef7cda54929d0 (diff)
downloadrust-61ebcf631b3c3267f6166fc97917da7c30d4d846.tar.gz
rust-61ebcf631b3c3267f6166fc97917da7c30d4d846.zip
Auto merge of #17763 - ShoyuVanilla:wrap-unit, r=Veykril
fix: Insert a tail `Ok(())` for expr block instead of wrapping with `Ok`

Fixes #17728

When type mismatch is `Result<(), E>, ()` or `Option<()>, ()` and target expr is a block expression, it is more reasonable to insert a wrapped unit - `Ok(())` or `Some(())` - as the tail expression of that block than wrapping the entire block with `Ok` or `Some`
-rw-r--r--src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs70
1 files changed, 68 insertions, 2 deletions
diff --git a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
index 4e52d28051b..6f5c68d4b5c 100644
--- a/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
+++ b/src/tools/rust-analyzer/crates/ide-diagnostics/src/handlers/type_mismatch.rs
@@ -2,8 +2,12 @@ use either::Either;
 use hir::{db::ExpandDatabase, ClosureStyle, HirDisplay, HirFileIdExt, InFile, Type};
 use ide_db::{famous_defs::FamousDefs, source_change::SourceChange};
 use syntax::{
-    ast::{self, BlockExpr, ExprStmt},
-    AstNode, AstPtr,
+    ast::{
+        self,
+        edit::{AstNodeEdit, IndentLevel},
+        BlockExpr, Expr, ExprStmt,
+    },
+    AstNode, AstPtr, TextSize,
 };
 use text_edit::TextEdit;
 
@@ -119,6 +123,38 @@ fn add_missing_ok_or_some(
         return None;
     }
 
+    if d.actual.is_unit() {
+        if let Expr::BlockExpr(block) = &expr {
+            if block.tail_expr().is_none() {
+                let mut builder = TextEdit::builder();
+                let block_indent = block.indent_level();
+
+                if block.statements().count() == 0 {
+                    // Empty block
+                    let indent = block_indent + 1;
+                    builder.insert(
+                        block.syntax().text_range().start() + TextSize::from(1),
+                        format!("\n{indent}{variant_name}(())\n{block_indent}"),
+                    );
+                } else {
+                    let indent = IndentLevel::from(1);
+                    builder.insert(
+                        block.syntax().text_range().end() - TextSize::from(1),
+                        format!("{indent}{variant_name}(())\n{block_indent}"),
+                    );
+                }
+
+                let source_change = SourceChange::from_text_edit(
+                    expr_ptr.file_id.original_file(ctx.sema.db),
+                    builder.finish(),
+                );
+                let name = format!("Insert {variant_name}(()) as the tail of this block");
+                acc.push(fix("insert_wrapped_unit", &name, source_change, expr_range));
+            }
+            return Some(());
+        }
+    }
+
     let mut builder = TextEdit::builder();
     builder.insert(expr.syntax().text_range().start(), format!("{variant_name}("));
     builder.insert(expr.syntax().text_range().end(), ")".to_owned());
@@ -534,6 +570,36 @@ fn div(x: i32, y: i32) -> MyResult<i32> {
     }
 
     #[test]
+    fn test_wrapped_unit_as_block_tail_expr() {
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> Result<(), ()> {
+    foo();
+}$0
+            "#,
+            r#"
+fn foo() -> Result<(), ()> {
+    foo();
+    Ok(())
+}
+            "#,
+        );
+
+        check_fix(
+            r#"
+//- minicore: result
+fn foo() -> Result<(), ()> {}$0
+            "#,
+            r#"
+fn foo() -> Result<(), ()> {
+    Ok(())
+}
+            "#,
+        );
+    }
+
+    #[test]
     fn test_in_const_and_static() {
         check_fix(
             r#"