Async closures will move params into the future always
This commit is contained in:
parent
8bb1eaee64
commit
f1ee076f81
10 changed files with 41 additions and 89 deletions
|
@ -14,10 +14,6 @@ ast_lowering_assoc_ty_parentheses =
|
||||||
ast_lowering_async_coroutines_not_supported =
|
ast_lowering_async_coroutines_not_supported =
|
||||||
`async` coroutines are not yet supported
|
`async` coroutines are not yet supported
|
||||||
|
|
||||||
ast_lowering_async_non_move_closure_not_supported =
|
|
||||||
`async` non-`move` closures with parameters are not currently supported
|
|
||||||
.help = consider using `let` statements to manually capture variables by reference before entering an `async move` closure
|
|
||||||
|
|
||||||
ast_lowering_att_syntax_only_x86 =
|
ast_lowering_att_syntax_only_x86 =
|
||||||
the `att_syntax` option is only supported on x86
|
the `att_syntax` option is only supported on x86
|
||||||
|
|
||||||
|
|
|
@ -145,14 +145,6 @@ pub struct ClosureCannotBeStatic {
|
||||||
pub fn_decl_span: Span,
|
pub fn_decl_span: Span,
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Diagnostic, Clone, Copy)]
|
|
||||||
#[help]
|
|
||||||
#[diag(ast_lowering_async_non_move_closure_not_supported, code = "E0708")]
|
|
||||||
pub struct AsyncNonMoveClosureNotSupported {
|
|
||||||
#[primary_span]
|
|
||||||
pub fn_decl_span: Span,
|
|
||||||
}
|
|
||||||
|
|
||||||
#[derive(Diagnostic, Clone, Copy)]
|
#[derive(Diagnostic, Clone, Copy)]
|
||||||
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
#[diag(ast_lowering_functional_record_update_destructuring_assignment)]
|
||||||
pub struct FunctionalRecordUpdateDestructuringAssignment {
|
pub struct FunctionalRecordUpdateDestructuringAssignment {
|
||||||
|
|
|
@ -1,6 +1,6 @@
|
||||||
use super::errors::{
|
use super::errors::{
|
||||||
AsyncCoroutinesNotSupported, AsyncNonMoveClosureNotSupported, AwaitOnlyInAsyncFnAndBlocks,
|
AsyncCoroutinesNotSupported, AwaitOnlyInAsyncFnAndBlocks, BaseExpressionDoubleDot,
|
||||||
BaseExpressionDoubleDot, ClosureCannotBeStatic, CoroutineTooManyParameters,
|
ClosureCannotBeStatic, CoroutineTooManyParameters,
|
||||||
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
FunctionalRecordUpdateDestructuringAssignment, InclusiveRangeWithNoEnd, MatchArmWithNoBody,
|
||||||
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
|
NeverPatternWithBody, NeverPatternWithGuard, NotSupportedForLifetimeBinderAsyncClosure,
|
||||||
UnderscoreExprLhsAssign,
|
UnderscoreExprLhsAssign,
|
||||||
|
@ -13,7 +13,6 @@ use rustc_ast::*;
|
||||||
use rustc_data_structures::stack::ensure_sufficient_stack;
|
use rustc_data_structures::stack::ensure_sufficient_stack;
|
||||||
use rustc_hir as hir;
|
use rustc_hir as hir;
|
||||||
use rustc_hir::def::{DefKind, Res};
|
use rustc_hir::def::{DefKind, Res};
|
||||||
use rustc_middle::span_bug;
|
|
||||||
use rustc_session::errors::report_lit_error;
|
use rustc_session::errors::report_lit_error;
|
||||||
use rustc_span::source_map::{respan, Spanned};
|
use rustc_span::source_map::{respan, Spanned};
|
||||||
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
use rustc_span::symbol::{kw, sym, Ident, Symbol};
|
||||||
|
@ -1028,28 +1027,16 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
fn_decl_span: Span,
|
fn_decl_span: Span,
|
||||||
fn_arg_span: Span,
|
fn_arg_span: Span,
|
||||||
) -> hir::ExprKind<'hir> {
|
) -> hir::ExprKind<'hir> {
|
||||||
let CoroutineKind::Async { closure_id: inner_closure_id, .. } = coroutine_kind else {
|
|
||||||
span_bug!(fn_decl_span, "`async gen` and `gen` closures are not supported, yet");
|
|
||||||
};
|
|
||||||
|
|
||||||
if let &ClosureBinder::For { span, .. } = binder {
|
if let &ClosureBinder::For { span, .. } = binder {
|
||||||
self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
self.dcx().emit_err(NotSupportedForLifetimeBinderAsyncClosure { span });
|
||||||
}
|
}
|
||||||
|
|
||||||
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
let (binder_clause, generic_params) = self.lower_closure_binder(binder);
|
||||||
|
|
||||||
let outer_decl =
|
|
||||||
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
|
||||||
|
|
||||||
let body = self.with_new_scopes(fn_decl_span, |this| {
|
let body = self.with_new_scopes(fn_decl_span, |this| {
|
||||||
// FIXME(cramertj): allow `async` non-`move` closures with arguments.
|
|
||||||
if capture_clause == CaptureBy::Ref && !decl.inputs.is_empty() {
|
|
||||||
this.dcx().emit_err(AsyncNonMoveClosureNotSupported { fn_decl_span });
|
|
||||||
}
|
|
||||||
|
|
||||||
// Transform `async |x: u8| -> X { ... }` into
|
// Transform `async |x: u8| -> X { ... }` into
|
||||||
// `|x: u8| || -> X { ... }`.
|
// `|x: u8| || -> X { ... }`.
|
||||||
let body_id = this.lower_fn_body(&outer_decl, |this| {
|
let body_id = this.lower_body(|this| {
|
||||||
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
|
let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output {
|
||||||
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
|
let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock);
|
||||||
Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
|
Some(hir::FnRetTy::Return(this.lower_ty(ty, &itctx)))
|
||||||
|
@ -1057,22 +1044,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
None
|
None
|
||||||
};
|
};
|
||||||
|
|
||||||
let async_body = this.make_desugared_coroutine_expr(
|
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||||
capture_clause,
|
decl,
|
||||||
inner_closure_id,
|
|
||||||
async_ret_ty,
|
|
||||||
body.span,
|
|
||||||
hir::CoroutineDesugaring::Async,
|
|
||||||
hir::CoroutineSource::Closure,
|
|
||||||
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
|this| this.with_new_scopes(fn_decl_span, |this| this.lower_expr_mut(body)),
|
||||||
|
body.span,
|
||||||
|
coroutine_kind,
|
||||||
|
hir::CoroutineSource::Closure,
|
||||||
|
async_ret_ty,
|
||||||
);
|
);
|
||||||
let hir_id = this.lower_node_id(inner_closure_id);
|
|
||||||
|
let hir_id = this.lower_node_id(coroutine_kind.closure_id());
|
||||||
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
this.maybe_forward_track_caller(body.span, closure_hir_id, hir_id);
|
||||||
hir::Expr { hir_id, kind: async_body, span: this.lower_span(body.span) }
|
|
||||||
|
(parameters, expr)
|
||||||
});
|
});
|
||||||
body_id
|
body_id
|
||||||
});
|
});
|
||||||
|
|
||||||
|
let outer_decl =
|
||||||
|
FnDecl { inputs: decl.inputs.clone(), output: FnRetTy::Default(fn_decl_span) };
|
||||||
|
|
||||||
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
let bound_generic_params = self.lower_lifetime_binder(closure_id, generic_params);
|
||||||
// We need to lower the declaration outside the new scope, because we
|
// We need to lower the declaration outside the new scope, because we
|
||||||
// have to conserve the state of being inside a loop condition for the
|
// have to conserve the state of being inside a loop condition for the
|
||||||
|
|
|
@ -1085,9 +1085,11 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
self.lower_body(|this| {
|
self.lower_body(|this| {
|
||||||
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
let (parameters, expr) = this.lower_coroutine_body_with_moved_arguments(
|
||||||
decl,
|
decl,
|
||||||
body,
|
|this| this.lower_block_expr(body),
|
||||||
|
body.span,
|
||||||
coroutine_kind,
|
coroutine_kind,
|
||||||
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
hir::CoroutineSource::Fn,
|
||||||
|
None,
|
||||||
);
|
);
|
||||||
|
|
||||||
// FIXME(async_fn_track_caller): Can this be moved above?
|
// FIXME(async_fn_track_caller): Can this be moved above?
|
||||||
|
@ -1102,12 +1104,14 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
/// into the body. This is to make sure that the future actually owns the
|
/// into the body. This is to make sure that the future actually owns the
|
||||||
/// arguments that are passed to the function, and to ensure things like
|
/// arguments that are passed to the function, and to ensure things like
|
||||||
/// drop order are stable.
|
/// drop order are stable.
|
||||||
fn lower_coroutine_body_with_moved_arguments(
|
pub fn lower_coroutine_body_with_moved_arguments(
|
||||||
&mut self,
|
&mut self,
|
||||||
decl: &FnDecl,
|
decl: &FnDecl,
|
||||||
body: &Block,
|
lower_body: impl FnOnce(&mut LoweringContext<'_, 'hir>) -> hir::Expr<'hir>,
|
||||||
|
body_span: Span,
|
||||||
coroutine_kind: CoroutineKind,
|
coroutine_kind: CoroutineKind,
|
||||||
capture_clause: CaptureBy,
|
coroutine_source: hir::CoroutineSource,
|
||||||
|
return_type_hint: Option<hir::FnRetTy<'hir>>,
|
||||||
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
|
) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>) {
|
||||||
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
let mut parameters: Vec<hir::Param<'_>> = Vec::new();
|
||||||
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
|
let mut statements: Vec<hir::Stmt<'_>> = Vec::new();
|
||||||
|
@ -1246,7 +1250,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
|
|
||||||
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
let mkbody = |this: &mut LoweringContext<'_, 'hir>| {
|
||||||
// Create a block from the user's function body:
|
// Create a block from the user's function body:
|
||||||
let user_body = this.lower_block_expr(body);
|
let user_body = lower_body(this);
|
||||||
|
|
||||||
// Transform into `drop-temps { <user-body> }`, an expression:
|
// Transform into `drop-temps { <user-body> }`, an expression:
|
||||||
let desugared_span =
|
let desugared_span =
|
||||||
|
@ -1277,19 +1281,22 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
||||||
};
|
};
|
||||||
let closure_id = coroutine_kind.closure_id();
|
let closure_id = coroutine_kind.closure_id();
|
||||||
let coroutine_expr = self.make_desugared_coroutine_expr(
|
let coroutine_expr = self.make_desugared_coroutine_expr(
|
||||||
capture_clause,
|
// FIXME(async_closures): This should only move locals,
|
||||||
|
// and not upvars. Capturing closure upvars by ref doesn't
|
||||||
|
// work right now anyways, so whatever.
|
||||||
|
CaptureBy::Value { move_kw: rustc_span::DUMMY_SP },
|
||||||
closure_id,
|
closure_id,
|
||||||
None,
|
return_type_hint,
|
||||||
body.span,
|
body_span,
|
||||||
desugaring_kind,
|
desugaring_kind,
|
||||||
hir::CoroutineSource::Fn,
|
coroutine_source,
|
||||||
mkbody,
|
mkbody,
|
||||||
);
|
);
|
||||||
|
|
||||||
let expr = hir::Expr {
|
let expr = hir::Expr {
|
||||||
hir_id: self.lower_node_id(closure_id),
|
hir_id: self.lower_node_id(closure_id),
|
||||||
kind: coroutine_expr,
|
kind: coroutine_expr,
|
||||||
span: self.lower_span(body.span),
|
span: self.lower_span(body_span),
|
||||||
};
|
};
|
||||||
|
|
||||||
(self.arena.alloc_from_iter(parameters), expr)
|
(self.arena.alloc_from_iter(parameters), expr)
|
||||||
|
|
|
@ -1,12 +1,14 @@
|
||||||
|
#### Note: this error code is no longer emitted by the compiler.
|
||||||
|
|
||||||
`async` non-`move` closures with parameters are currently not supported.
|
`async` non-`move` closures with parameters are currently not supported.
|
||||||
|
|
||||||
Erroneous code example:
|
Erroneous code example:
|
||||||
|
|
||||||
```compile_fail,edition2018,E0708
|
```edition2018
|
||||||
#![feature(async_closure)]
|
#![feature(async_closure)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let add_one = async |num: u8| { // error!
|
let add_one = async |num: u8| {
|
||||||
num + 1
|
num + 1
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,9 +1,10 @@
|
||||||
// edition:2018
|
// edition:2018
|
||||||
|
// check-pass
|
||||||
|
|
||||||
#![feature(async_closure)]
|
#![feature(async_closure)]
|
||||||
fn foo() -> Box<dyn std::future::Future<Output = u32>> {
|
fn foo() -> Box<dyn std::future::Future<Output = u32>> {
|
||||||
let x = 0u32;
|
let x = 0u32;
|
||||||
Box::new((async || x)())
|
Box::new((async || x)())
|
||||||
//~^ ERROR E0373
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
|
|
|
@ -1,21 +0,0 @@
|
||||||
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
|
|
||||||
--> $DIR/async-borrowck-escaping-closure-error.rs:5:15
|
|
||||||
|
|
|
||||||
LL | Box::new((async || x)())
|
|
||||||
| ^^^^^^^^ - `x` is borrowed here
|
|
||||||
| |
|
|
||||||
| may outlive borrowed value `x`
|
|
||||||
|
|
|
||||||
note: closure is returned here
|
|
||||||
--> $DIR/async-borrowck-escaping-closure-error.rs:5:5
|
|
||||||
|
|
|
||||||
LL | Box::new((async || x)())
|
|
||||||
| ^^^^^^^^^^^^^^^^^^^^^^^^
|
|
||||||
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
|
|
||||||
|
|
|
||||||
LL | Box::new((async move || x)())
|
|
||||||
| ++++
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0373`.
|
|
|
@ -1,8 +1,8 @@
|
||||||
// edition:2018
|
// edition:2018
|
||||||
|
// check-pass
|
||||||
|
|
||||||
#![feature(async_closure)]
|
#![feature(async_closure)]
|
||||||
|
|
||||||
fn main() {
|
fn main() {
|
||||||
let _ = async |x: u8| {};
|
let _ = async |x: u8| {};
|
||||||
//~^ ERROR `async` non-`move` closures with parameters are not currently supported
|
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,11 +0,0 @@
|
||||||
error[E0708]: `async` non-`move` closures with parameters are not currently supported
|
|
||||||
--> $DIR/no-params-non-move-async-closure.rs:6:13
|
|
||||||
|
|
|
||||||
LL | let _ = async |x: u8| {};
|
|
||||||
| ^^^^^^^^^^^^^
|
|
||||||
|
|
|
||||||
= help: consider using `let` statements to manually capture variables by reference before entering an `async move` closure
|
|
||||||
|
|
||||||
error: aborting due to 1 previous error
|
|
||||||
|
|
||||||
For more information about this error, try `rustc --explain E0708`.
|
|
|
@ -18,11 +18,6 @@ LL | let _ = async ||{}();
|
||||||
| ^^--
|
| ^^--
|
||||||
| |
|
| |
|
||||||
| call expression requires function
|
| call expression requires function
|
||||||
|
|
|
||||||
help: if you meant to create this closure and immediately call it, surround the closure with parentheses
|
|
||||||
|
|
|
||||||
LL | let _ = (async ||{})();
|
|
||||||
| + +
|
|
||||||
|
|
||||||
error: aborting due to 2 previous errors
|
error: aborting due to 2 previous errors
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue