diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index f6a97f04d99e4..f7fcfb6ea80d3 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -62,6 +62,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (expected_sig, expected_kind) = match expected.to_option(self) { Some(ty) => self.deduce_closure_signature( self.deeply_resolve_ignoring_regions_with_obligations(ty), + closure.def_id, closure.kind, ), None => (None, None), @@ -291,9 +292,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { fn deduce_closure_signature( &self, expected_ty: Ty<'tcx>, + closure_def_id: LocalDefId, closure_kind: hir::ClosureKind, ) -> (Option>, Option) { match *expected_ty.kind() { + ty::Coroutine(def_id, args) + if def_id == closure_def_id.to_def_id() + && matches!( + closure_kind, + hir::ClosureKind::Coroutine(hir::CoroutineKind::Desugared( + hir::CoroutineDesugaring::Async, + hir::CoroutineSource::Closure, + )) + ) => + { + // An async closure's body is itself a coroutine. Propagate the signature + // inferred for that coroutine into its body. + let args = args.as_coroutine(); + let sig = ty::Binder::dummy( + self.tcx.mk_fn_sig_safe_rust_abi([args.resume_ty()], args.return_ty()), + ); + (Some(ExpectedSig { cause_span: None, sig }), None) + } ty::Alias(_, ty::AliasTy { kind: ty::Opaque { def_id }, args, .. }) => self .deduce_closure_signature_from_predicates( expected_ty, diff --git a/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.current.stderr b/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.current.stderr new file mode 100644 index 0000000000000..62ee5193400c9 --- /dev/null +++ b/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.current.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/async-closure-output-mismatch-issue-161619.rs:16:27 + | +LL | for_each(async |_| Ok(String::new())); + | -- ^^^^^^^^^^^^^ expected `()`, found `String` + | | + | arguments to this enum variant are incorrect + | +help: the type constructed contains `String` due to the type of the argument passed + --> $DIR/async-closure-output-mismatch-issue-161619.rs:16:24 + | +LL | for_each(async |_| Ok(String::new())); + | ^^^-------------^ + | | + | this argument influences the type of `Ok` +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.next.stderr b/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.next.stderr new file mode 100644 index 0000000000000..62ee5193400c9 --- /dev/null +++ b/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.next.stderr @@ -0,0 +1,21 @@ +error[E0308]: mismatched types + --> $DIR/async-closure-output-mismatch-issue-161619.rs:16:27 + | +LL | for_each(async |_| Ok(String::new())); + | -- ^^^^^^^^^^^^^ expected `()`, found `String` + | | + | arguments to this enum variant are incorrect + | +help: the type constructed contains `String` due to the type of the argument passed + --> $DIR/async-closure-output-mismatch-issue-161619.rs:16:24 + | +LL | for_each(async |_| Ok(String::new())); + | ^^^-------------^ + | | + | this argument influences the type of `Ok` +note: tuple variant defined here + --> $SRC_DIR/core/src/result.rs:LL:COL + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0308`. diff --git a/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.rs b/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.rs new file mode 100644 index 0000000000000..aa26814ff5dbc --- /dev/null +++ b/tests/ui/async-await/async-closures/async-closure-output-mismatch-issue-161619.rs @@ -0,0 +1,18 @@ +//@ edition: 2024 +//@ revisions: current next +//@ ignore-compare-mode-next-solver (explicit revisions) +//@[next] compile-flags: -Znext-solver + +use std::future::Future; + +fn for_each(_: F) +where + F: FnMut(()) -> Fut, + Fut: Future>, +{ +} + +fn main() { + for_each(async |_| Ok(String::new())); + //~^ ERROR mismatched types +} diff --git a/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed b/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed index f3e226c9e5681..d19ab19f98012 100644 --- a/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed +++ b/tests/ui/suggestions/suggest-create-closure-issue-150701.fixed @@ -9,7 +9,6 @@ fn f(_c: impl Future) {} fn main() { f((async || {})()); //~ ERROR: expected function, found `()` - //~^ ERROR: is not a future f(async {}); //~^ ERROR: is not a future } diff --git a/tests/ui/suggestions/suggest-create-closure-issue-150701.rs b/tests/ui/suggestions/suggest-create-closure-issue-150701.rs index e7a5076d8f1d9..bbb5f4d0bb6bd 100644 --- a/tests/ui/suggestions/suggest-create-closure-issue-150701.rs +++ b/tests/ui/suggestions/suggest-create-closure-issue-150701.rs @@ -9,7 +9,6 @@ fn f(_c: impl Future) {} fn main() { f(async || {}()); //~ ERROR: expected function, found `()` - //~^ ERROR: is not a future f(async || {}); //~^ ERROR: is not a future } diff --git a/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr b/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr index 0f991169d6772..8f1f721f97f35 100644 --- a/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr +++ b/tests/ui/suggestions/suggest-create-closure-issue-150701.stderr @@ -11,30 +11,15 @@ help: if you meant to create this closure and immediately call it, surround the LL | f((async || {})()); | + + -error[E0277]: `{async closure@$DIR/suggest-create-closure-issue-150701.rs:11:7: 11:15}` is not a future - --> $DIR/suggest-create-closure-issue-150701.rs:11:7 - | -LL | f(async || {}()); - | - ^^^^^^^^^^^^^ `{async closure@$DIR/suggest-create-closure-issue-150701.rs:11:7: 11:15}` is not a future - | | - | required by a bound introduced by this call - | - = help: the trait `Future` is not implemented for `{async closure@$DIR/suggest-create-closure-issue-150701.rs:11:7: 11:15}` -note: required by a bound in `f` - --> $DIR/suggest-create-closure-issue-150701.rs:8:15 - | -LL | fn f(_c: impl Future) {} - | ^^^^^^^^^^^^^^^^^^^ required by this bound in `f` - -error[E0277]: `{async closure@$DIR/suggest-create-closure-issue-150701.rs:13:7: 13:15}` is not a future - --> $DIR/suggest-create-closure-issue-150701.rs:13:7 +error[E0277]: `{async closure@$DIR/suggest-create-closure-issue-150701.rs:12:7: 12:15}` is not a future + --> $DIR/suggest-create-closure-issue-150701.rs:12:7 | LL | f(async || {}); - | - ^^^^^^^^^^^ `{async closure@$DIR/suggest-create-closure-issue-150701.rs:13:7: 13:15}` is not a future + | - ^^^^^^^^^^^ `{async closure@$DIR/suggest-create-closure-issue-150701.rs:12:7: 12:15}` is not a future | | | required by a bound introduced by this call | - = help: the trait `Future` is not implemented for `{async closure@$DIR/suggest-create-closure-issue-150701.rs:13:7: 13:15}` + = help: the trait `Future` is not implemented for `{async closure@$DIR/suggest-create-closure-issue-150701.rs:12:7: 12:15}` note: required by a bound in `f` --> $DIR/suggest-create-closure-issue-150701.rs:8:15 | @@ -46,7 +31,7 @@ LL - f(async || {}); LL + f(async {}); | -error: aborting due to 3 previous errors +error: aborting due to 2 previous errors Some errors have detailed explanations: E0277, E0618. For more information about an error, try `rustc --explain E0277`.