Skip to content

Commit

Permalink
Auto merge of #127827 - compiler-errors:async-closure-closure-async, …
Browse files Browse the repository at this point in the history
…r=<try>

[EXPERIMENT] Rewrite closure-of-async to async-closure

to see what the fallout is

uwuwuwu
  • Loading branch information
bors committed Jul 16, 2024
2 parents 16b5690 + 8f4f214 commit 8a6640b
Show file tree
Hide file tree
Showing 6 changed files with 111 additions and 55 deletions.
31 changes: 28 additions & 3 deletions compiler/rustc_ast/src/ast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down Expand Up @@ -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 ()|`.
Expand Down
71 changes: 59 additions & 12 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -213,18 +213,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(
gen_capture_clause,
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).max(*gen_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 {
Expand Down
26 changes: 2 additions & 24 deletions tests/ui/async-await/async-closures/wrong-fn-kind.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand All @@ -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`.
25 changes: 11 additions & 14 deletions tests/ui/async-await/issue-69446-fnmut-capture.stderr
Original file line number Diff line number Diff line change
@@ -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<T>(_: impl FnMut() -> T)
| ^^^^^^^^^^^^ required by this bound in `bar`

error: aborting due to 1 previous error

2 changes: 2 additions & 0 deletions tests/ui/async-await/issue-70935-complex-spans.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -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
|
Expand Down Expand Up @@ -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
|
Expand Down
11 changes: 9 additions & 2 deletions tests/ui/impl-trait/opaque-cast-field-access-in-future.stderr
Original file line number Diff line number Diff line change
@@ -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
|
Expand All @@ -6,6 +12,7 @@ LL | fn run() -> Foo<impl Future<Output = ()>> {
|
= 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`.

0 comments on commit 8a6640b

Please sign in to comment.