about summary refs log tree commit diff
diff options
context:
space:
mode:
authorArpad Borsos <swatinem@swatinem.de>2023-06-04 10:38:14 +0200
committerArpad Borsos <swatinem@swatinem.de>2023-06-04 10:56:00 +0200
commit75b557a2c416f997385a886b39e7ef7625073f5a (patch)
tree0272e3eac75a52abfe30db85910883c2371d7502
parent9eee230cd0a56bfba3ce65121798d9f9f4341cdd (diff)
downloadrust-75b557a2c416f997385a886b39e7ef7625073f5a.tar.gz
rust-75b557a2c416f997385a886b39e7ef7625073f5a.zip
Fix type-inference regression in #112225
The type inference of argument-position closures and async blocks
regressed in 1.70 as the evaluation order of async blocks changed, as
they are not implicitly wrapped in an identity-function anymore.

Fixes #112225 by making sure the evaluation order stays the same as it
used to.
-rw-r--r--compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs11
-rw-r--r--tests/ui/async-await/issues/issue-112225-1.rs18
-rw-r--r--tests/ui/async-await/issues/issue-112225-2.rs20
-rw-r--r--tests/ui/async-await/issues/issue-112225-2.stderr17
4 files changed, 65 insertions, 1 deletions
diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
index 72c42f8e789..eba5c829e39 100644
--- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
+++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
@@ -362,7 +362,16 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                     continue;
                 }
 
-                let is_closure = matches!(arg.kind, ExprKind::Closure { .. });
+                // For this check, we do *not* want to treat async generator closures (async blocks)
+                // as proper closures. Doing so would regress type inference when feeding
+                // the return value of an argument-position async block to an argument-position
+                // closure wrapped in a block.
+                // See <https://github.com/rust-lang/rust/issues/112225>.
+                let is_closure = if let ExprKind::Closure(closure) = arg.kind {
+                    !tcx.generator_is_async(closure.def_id.to_def_id())
+                } else {
+                    false
+                };
                 if is_closure != check_closures {
                     continue;
                 }
diff --git a/tests/ui/async-await/issues/issue-112225-1.rs b/tests/ui/async-await/issues/issue-112225-1.rs
new file mode 100644
index 00000000000..e28cbee214e
--- /dev/null
+++ b/tests/ui/async-await/issues/issue-112225-1.rs
@@ -0,0 +1,18 @@
+// check-pass
+// edition:2021
+
+use core::future::Future;
+
+fn main() {
+    do_async(async { (0,) }, {
+        // closure must be inside block
+        |info| println!("{:?}", info.0)
+    });
+}
+
+fn do_async<R, Fut, F>(_tokio_fut: Fut, _glib_closure: F)
+where
+    Fut: Future<Output = R>,
+    F: FnOnce(R),
+{
+}
diff --git a/tests/ui/async-await/issues/issue-112225-2.rs b/tests/ui/async-await/issues/issue-112225-2.rs
new file mode 100644
index 00000000000..50fa1a79b6b
--- /dev/null
+++ b/tests/ui/async-await/issues/issue-112225-2.rs
@@ -0,0 +1,20 @@
+// edition:2021
+
+// With the current compiler logic, we cannot have both the `112225-1` case,
+// and this `112225-2` case working, as the type inference depends on the evaluation
+// order, and there is some explicit ordering going on.
+// See the `check_closures` part in `FnCtxt::check_argument_types`.
+// The `112225-1` case was a regression in real world code, whereas the `112225-2`
+// case never used to work prior to 1.70.
+
+use core::future::Future;
+
+fn main() {
+    let x = Default::default();
+    //~^ ERROR: type annotations needed
+    do_async(
+        async { x.0; },
+        { || { let _: &(i32,) = &x; } },
+    );
+}
+fn do_async<Fut, T>(_fut: Fut, _val: T, ) {}
diff --git a/tests/ui/async-await/issues/issue-112225-2.stderr b/tests/ui/async-await/issues/issue-112225-2.stderr
new file mode 100644
index 00000000000..5926a4f3995
--- /dev/null
+++ b/tests/ui/async-await/issues/issue-112225-2.stderr
@@ -0,0 +1,17 @@
+error[E0282]: type annotations needed
+  --> $DIR/issue-112225-2.rs:13:9
+   |
+LL |     let x = Default::default();
+   |         ^
+...
+LL |         async { x.0; },
+   |                 - type must be known at this point
+   |
+help: consider giving `x` an explicit type
+   |
+LL |     let x: /* Type */ = Default::default();
+   |          ++++++++++++
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0282`.