about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2024-05-23 08:42:09 +0000
committerbors <bors@rust-lang.org>2024-05-23 08:42:09 +0000
commit6e8646df8b46ed376c26b457e1340f2dacb00628 (patch)
tree082b2a44f44c0c11e108a1f9f89dd505df66ea5b
parent68fe34a4c2a5a864ed212ac2b0151ff7a52bab09 (diff)
parent425ed6a181e07abde8d6a722179a953639b34aaf (diff)
downloadrust-6e8646df8b46ed376c26b457e1340f2dacb00628.tar.gz
rust-6e8646df8b46ed376c26b457e1340f2dacb00628.zip
Auto merge of #17174 - Kohei316:fix-infer-async-block-with-tail-return-expr, r=Veykril
Fix: infer type of async block with tail return expr

Fixes #17106
The `infer_async_block` method calls the `infer_block` method internally, which returns the never type without coercion when `tail_expr` is `None` and `ctx.diverges` is `Diverges::Always`.This is the reason for the bug in this issue.
https://github.com/rust-lang/rust-analyzer/blob/cfce2bb46da62950a8b70ddb0b2a12332da1b1e1/crates/hir-ty/src/infer/expr.rs#L1411-L1413

This PR solves the bug by adding a process to coerce after calling `infer_block` method.

This code passes all the tests, including tests I added for this isuue, however, I am not sure if this solution is right. I think that this solution is an ad hoc solution. So, I would appreciate to have your review.
I apologize if I'm off the mark, but `infer_async_block` method should be rewritten to share code with the process of infering type of `expr::Closure` instead of the `infer_block` method. That way it will be closer to the infer process of rustc.
-rw-r--r--src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs18
-rw-r--r--src/tools/rust-analyzer/crates/ide/src/inlay_hints/bind_pat.rs26
2 files changed, 43 insertions, 1 deletions
diff --git a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
index 38076fce8f8..4c12786362f 100644
--- a/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
+++ b/src/tools/rust-analyzer/crates/hir-ty/src/infer/expr.rs
@@ -933,8 +933,24 @@ impl InferenceContext<'_> {
         let prev_ret_coercion =
             mem::replace(&mut self.return_coercion, Some(CoerceMany::new(ret_ty.clone())));
 
+        // FIXME: We should handle async blocks like we handle closures
+        let expected = &Expectation::has_type(ret_ty);
         let (_, inner_ty) = self.with_breakable_ctx(BreakableKind::Border, None, None, |this| {
-            this.infer_block(tgt_expr, *id, statements, *tail, None, &Expectation::has_type(ret_ty))
+            let ty = this.infer_block(tgt_expr, *id, statements, *tail, None, expected);
+            if let Some(target) = expected.only_has_type(&mut this.table) {
+                match this.coerce(Some(tgt_expr), &ty, &target) {
+                    Ok(res) => res,
+                    Err(_) => {
+                        this.result.type_mismatches.insert(
+                            tgt_expr.into(),
+                            TypeMismatch { expected: target.clone(), actual: ty.clone() },
+                        );
+                        target
+                    }
+                }
+            } else {
+                ty
+            }
         });
 
         self.diverges = prev_diverges;
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 0cb8c485b2f..3311bb48ad6 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
@@ -1120,4 +1120,30 @@ fn test() {
 "#,
         );
     }
+
+    #[test]
+    fn type_hints_async_block() {
+        check_types(
+            r#"
+//- minicore: future
+async fn main() {
+    let _x = async { 8_i32 };
+      //^^ impl Future<Output = i32>
+}"#,
+        );
+    }
+
+    #[test]
+    fn type_hints_async_block_with_tail_return_exp() {
+        check_types(
+            r#"
+//- minicore: future
+async fn main() {
+    let _x = async {
+      //^^ impl Future<Output = i32>
+        return 8_i32;
+    };
+}"#,
+        );
+    }
 }