diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index fc1af3fc3dd11..c1ae940354f62 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -1214,6 +1214,30 @@ impl Expr { } } + pub fn peel_uwu(&self) -> &Expr { + let mut expr = self; + loop { + match &expr.kind { + ExprKind::Block(blk, None) => { + if blk.stmts.len() == 1 + && let StmtKind::Expr(blk) = &blk.stmts[0].kind + { + expr = blk; + } else { + break; + } + } + ExprKind::Paren(paren) => { + expr = paren; + } + _ => { + break; + } + } + } + expr + } + pub fn peel_parens(&self) -> &Expr { let mut expr = self; while let ExprKind::Paren(inner) = &expr.kind { @@ -1614,15 +1638,16 @@ pub struct QSelf { } /// A capture clause used in closures and `async` blocks. -#[derive(Clone, Copy, PartialEq, Encodable, Decodable, Debug, HashStable_Generic)] +#[derive(Clone, Copy, PartialEq, Ord, Eq, PartialOrd, Debug)] +#[derive(Encodable, Decodable, HashStable_Generic)] pub enum CaptureBy { + /// `move` keyword was not specified. + Ref, /// `move |x| y + x`. Value { /// The span of the `move` keyword. move_kw: Span, }, - /// `move` keyword was not specified. - Ref, } /// Closure lifetime binder, `for<'a, 'b>` in `for<'a, 'b> |_: &'a (), _: &'b ()|`. diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 124fe6bd380d2..c20223765bb04 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -219,18 +219,65 @@ impl<'hir> LoweringContext<'_, 'hir> { *fn_decl_span, *fn_arg_span, ), - None => self.lower_expr_closure( - binder, - *capture_clause, - e.id, - hir_id, - *constness, - *movability, - fn_decl, - body, - *fn_decl_span, - *fn_arg_span, - ), + None => { + let peeled = body.peel_uwu(); + if let ast::ExprKind::Gen( + _, + block, + gen_kind @ ast::GenBlockKind::Async, + span, + ) = &peeled.kind + { + let coroutine_kind = match gen_kind { + GenBlockKind::Async => CoroutineKind::Async { + span: *span, + closure_id: peeled.node_id(), + return_impl_trait_id: self.next_node_id(), + }, + GenBlockKind::Gen => CoroutineKind::Gen { + span: *span, + closure_id: peeled.node_id(), + return_impl_trait_id: self.next_node_id(), + }, + GenBlockKind::AsyncGen => CoroutineKind::AsyncGen { + span: *span, + closure_id: peeled.node_id(), + return_impl_trait_id: self.next_node_id(), + }, + }; + let id = self.next_node_id(); + self.lower_expr_coroutine_closure( + binder, + *capture_clause, + e.id, + hir_id, + coroutine_kind, + fn_decl, + &ast::Expr { + id, + span: *span, + kind: ExprKind::Block(block.clone(), None), + attrs: thin_vec![], + tokens: None, + }, + *fn_decl_span, + *fn_arg_span, + ) + } else { + self.lower_expr_closure( + binder, + *capture_clause, + e.id, + hir_id, + *constness, + *movability, + fn_decl, + body, + *fn_decl_span, + *fn_arg_span, + ) + } + } }, ExprKind::Gen(capture_clause, block, genblock_kind, decl_span) => { let desugaring_kind = match genblock_kind { diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index a7953acc95c80..ee49f01c77efc 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -14,7 +14,7 @@ use rustc_middle::span_bug; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, GenericArgs, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_span::def_id::LocalDefId; -use rustc_span::Span; +use rustc_span::{Span, DUMMY_SP}; use rustc_target::spec::abi::Abi; use rustc_trait_selection::error_reporting::traits::ArgKind; use rustc_trait_selection::traits; @@ -563,25 +563,27 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; }; + let mut return_ty = None; + // FIXME: We may want to elaborate here, though I assume this will be exceedingly rare. for bound in self.obligations_for_self_ty(return_vid) { if let Some(ret_projection) = bound.predicate.as_projection_clause() && let Some(ret_projection) = ret_projection.no_bound_vars() && self.tcx.is_lang_item(ret_projection.def_id(), LangItem::FutureOutput) { - let sig = projection.rebind(self.tcx.mk_fn_sig( - input_tys, - ret_projection.term.expect_type(), - false, - hir::Safety::Safe, - Abi::Rust, - )); - - return Some(ExpectedSig { cause_span, sig }); + return_ty = Some(ret_projection.term.expect_type()); } } - None + let sig = projection.rebind(self.tcx.mk_fn_sig( + input_tys, + return_ty.unwrap_or_else(|| self.next_ty_var(cause_span.unwrap_or(DUMMY_SP))), + false, + hir::Safety::Safe, + Abi::Rust, + )); + + return Some(ExpectedSig { cause_span, sig }); } fn sig_of_closure( diff --git a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr index 1df5abdbb18e3..ed32a53e80728 100644 --- a/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr +++ b/tests/ui/async-await/async-closures/without-precise-captures-we-are-powerless.stderr @@ -56,6 +56,11 @@ LL | outlives::<'a>(call_once(c)); LL | LL | let c = async move || { println!("{}", *x.0); }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ move out of `x` occurs here + | +help: consider cloning the value if the performance cost is acceptable + | +LL | let c = async || { println!("{}", *x.0); }.clone(); + | ++++++++ error[E0597]: `c` does not live long enough --> $DIR/without-precise-captures-we-are-powerless.rs:33:20 diff --git a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr index 4b626c1bed6c3..a5a67bf887c5c 100644 --- a/tests/ui/async-await/async-closures/wrong-fn-kind.stderr +++ b/tests/ui/async-await/async-closures/wrong-fn-kind.stderr @@ -1,24 +1,3 @@ -error[E0525]: expected a closure that implements the `async Fn` trait, but this closure only implements `async FnOnce` - --> $DIR/wrong-fn-kind.rs:17:20 - | -LL | needs_async_fn(move || async move { - | -------------- -^^^^^^ - | | | - | _____|______________this closure implements `async FnOnce`, not `async Fn` - | | | - | | required by a bound introduced by this call -LL | | -LL | | println!("{x}"); - | | - closure is `async FnOnce` because it moves the variable `x` out of its environment -LL | | }); - | |_____- the requirement to implement `async Fn` derives from here - | -note: required by a bound in `needs_async_fn` - --> $DIR/wrong-fn-kind.rs:5:27 - | -LL | fn needs_async_fn(_: impl async Fn()) {} - | ^^^^^^^^^^ required by this bound in `needs_async_fn` - error[E0596]: cannot borrow `x` as mutable, as it is a captured variable in a `Fn` closure --> $DIR/wrong-fn-kind.rs:9:20 | @@ -35,7 +14,6 @@ LL | LL | x += 1; | - mutable borrow occurs due to use of `x` in closure -error: aborting due to 2 previous errors +error: aborting due to 1 previous error -Some errors have detailed explanations: E0525, E0596. -For more information about an error, try `rustc --explain E0525`. +For more information about this error, try `rustc --explain E0596`. diff --git a/tests/ui/async-await/issue-69446-fnmut-capture.stderr b/tests/ui/async-await/issue-69446-fnmut-capture.stderr index 0366c2f44c0e7..8a94209e09617 100644 --- a/tests/ui/async-await/issue-69446-fnmut-capture.stderr +++ b/tests/ui/async-await/issue-69446-fnmut-capture.stderr @@ -1,19 +1,16 @@ -error: captured variable cannot escape `FnMut` closure body - --> $DIR/issue-69446-fnmut-capture.rs:19:17 +error: async closure does not implement `FnMut` because it captures state from its environment + --> $DIR/issue-69446-fnmut-capture.rs:19:9 | -LL | let mut x = Foo; - | ----- variable defined here -LL | bar(move || async { - | _______________-_^ - | | | - | | inferred to be a `FnMut` closure -LL | | x.foo(); - | | - variable captured here -LL | | }); - | |_____^ returns an `async` block that contains a reference to a captured variable, which then escapes the closure body +LL | bar(move || async { + | --- ^^^^^^^ + | | + | required by a bound introduced by this call | - = note: `FnMut` closures only have access to their captured variables while they are executing... - = note: ...therefore, they cannot allow references to captured variables to escape +note: required by a bound in `bar` + --> $DIR/issue-69446-fnmut-capture.rs:12:25 + | +LL | async fn bar(_: impl FnMut() -> T) + | ^^^^^^^^^^^^ required by this bound in `bar` error: aborting due to 1 previous error diff --git a/tests/ui/async-await/issue-70935-complex-spans.stderr b/tests/ui/async-await/issue-70935-complex-spans.stderr index 1ca0b339c16ad..080c3af6be6a2 100644 --- a/tests/ui/async-await/issue-70935-complex-spans.stderr +++ b/tests/ui/async-await/issue-70935-complex-spans.stderr @@ -13,6 +13,7 @@ note: required because it appears within the type `NotSync` LL | struct NotSync(PhantomData<*mut ()>); | ^^^^^^^ = note: required for `&NotSync` to implement `Send` + = note: required because it appears within the type `(&NotSync,)` note: required because it's used within this closure --> $DIR/issue-70935-complex-spans.rs:19:13 | @@ -46,6 +47,7 @@ note: required because it appears within the type `NotSync` LL | struct NotSync(PhantomData<*mut ()>); | ^^^^^^^ = note: required for `&NotSync` to implement `Send` + = note: required because it appears within the type `(&NotSync,)` note: required because it's used within this closure --> $DIR/issue-70935-complex-spans.rs:19:13 | diff --git a/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr b/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr index 5ade6a69d4b0d..df375ccd773a2 100644 --- a/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr +++ b/tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr @@ -1,3 +1,9 @@ +error[E0282]: type annotations needed + --> $DIR/opaque-cast-field-access-in-future.rs:7:14 + | +LL | &mut foo.bar; + | ^^^ cannot infer type + error[E0283]: type annotations needed --> $DIR/opaque-cast-field-access-in-future.rs:22:17 | @@ -6,6 +12,7 @@ LL | fn run() -> Foo> { | = note: cannot satisfy `_: Future` -error: aborting due to 1 previous error +error: aborting due to 2 previous errors -For more information about this error, try `rustc --explain E0283`. +Some errors have detailed explanations: E0282, E0283. +For more information about an error, try `rustc --explain E0282`.