From 1a764a7ef59b9cb2eb31658625a6a7dacc3d819b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 10 Feb 2020 17:21:50 +0100 Subject: [PATCH 01/12] Add futures scaffolding to libcore --- src/libcore/future/mod.rs | 79 +++++++++++++++++++++++++++++++++++++++ src/libstd/future.rs | 25 +++++++++---- 2 files changed, 97 insertions(+), 7 deletions(-) diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 89ea4713cfdaa..6150f34d8446d 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -2,6 +2,85 @@ //! Asynchronous values. +#[cfg(not(bootstrap))] +use crate::{ + ops::{Generator, GeneratorState}, + pin::Pin, + ptr::NonNull, + task::{Context, Poll}, +}; + mod future; #[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; + +/// This type is needed because: +/// +/// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass +/// a raw pointer. +/// b) Raw pointers and `NonNull` aren't `Send` or `Sync`, so that would make every single future +/// non-Send/Sync as well, and we don't want that. +/// +/// It also simplifies the HIR lowering of `.await`. +#[doc(hidden)] +#[unstable(feature = "gen_future", issue = "50547")] +#[cfg(not(bootstrap))] +#[derive(Debug, Copy, Clone)] +pub struct ResumeTy(pub NonNull>); + +#[unstable(feature = "gen_future", issue = "50547")] +#[cfg(not(bootstrap))] +unsafe impl Send for ResumeTy {} + +#[unstable(feature = "gen_future", issue = "50547")] +#[cfg(not(bootstrap))] +unsafe impl Sync for ResumeTy {} + +/// Wrap a generator in a future. +/// +/// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give +/// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). +// This is `const` to avoid extra errors after we recover from `const async fn` +#[doc(hidden)] +#[unstable(feature = "gen_future", issue = "50547")] +#[cfg(not(bootstrap))] +#[inline] +pub const fn from_generator(gen: T) -> impl Future +where + T: Generator +{ + #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] + struct GenFuture>(T); + + // We rely on the fact that async/await futures are immovable in order to create + // self-referential borrows in the underlying generator. + impl> !Unpin for GenFuture {} + + impl> Future for GenFuture { + type Output = T::Return; + fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { + // Safety: Safe because we're !Unpin + !Drop mapping to a ?Unpin value + let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; + + // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The + // `.await` lowering will safely cast that back to a `&mut Context`. + match gen.resume(ResumeTy(NonNull::from(cx).cast::>())) { + GeneratorState::Yielded(()) => Poll::Pending, + GeneratorState::Complete(x) => Poll::Ready(x), + } + } + } + + GenFuture(gen) +} + +#[doc(hidden)] +#[unstable(feature = "gen_future", issue = "50547")] +#[cfg(not(bootstrap))] +#[inline] +pub unsafe fn poll_with_context(f: Pin<&mut F>, mut cx: ResumeTy) -> Poll +where + F: Future, +{ + F::poll(f, cx.0.as_mut()) +} diff --git a/src/libstd/future.rs b/src/libstd/future.rs index c1ca6771326cb..c0675eeba98da 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -1,12 +1,14 @@ //! Asynchronous values. -use core::cell::Cell; -use core::marker::Unpin; -use core::ops::{Drop, Generator, GeneratorState}; -use core::option::Option; -use core::pin::Pin; -use core::ptr::NonNull; -use core::task::{Context, Poll}; +#[cfg(bootstrap)] +use core::{ + cell::Cell, + marker::Unpin, + ops::{Drop, Generator, GeneratorState}, + pin::Pin, + ptr::NonNull, + task::{Context, Poll}, +}; #[doc(inline)] #[stable(feature = "futures_api", since = "1.36.0")] @@ -17,6 +19,7 @@ pub use core::future::*; /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` +#[cfg(bootstrap)] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] pub const fn from_generator>(x: T) -> impl Future { @@ -24,6 +27,7 @@ pub const fn from_generator>(x: T) -> impl Future>(T); // We rely on the fact that async/await futures are immovable in order to create // self-referential borrows in the underlying generator. +#[cfg(bootstrap)] impl> !Unpin for GenFuture {} +#[cfg(bootstrap)] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] impl> Future for GenFuture { @@ -48,12 +54,15 @@ impl> Future for GenFuture { } } +#[cfg(bootstrap)] thread_local! { static TLS_CX: Cell>>> = Cell::new(None); } +#[cfg(bootstrap)] struct SetOnDrop(Option>>); +#[cfg(bootstrap)] impl Drop for SetOnDrop { fn drop(&mut self) { TLS_CX.with(|tls_cx| { @@ -64,6 +73,7 @@ impl Drop for SetOnDrop { // Safety: the returned guard must drop before `cx` is dropped and before // any previous guard is dropped. +#[cfg(bootstrap)] unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop { // transmute the context's lifetime to 'static so we can store it. let cx = core::mem::transmute::<&mut Context<'_>, &mut Context<'static>>(cx); @@ -71,6 +81,7 @@ unsafe fn set_task_context(cx: &mut Context<'_>) -> SetOnDrop { SetOnDrop(old_cx) } +#[cfg(bootstrap)] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] /// Polls a future in the current thread-local task waker. From 18adc45a26127be7c38c81b8c6e1caaab3c8132e Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 10 Feb 2020 17:22:29 +0100 Subject: [PATCH 02/12] Improve debug log in MIR type check --- src/librustc_mir/borrow_check/type_check/input_output.rs | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/src/librustc_mir/borrow_check/type_check/input_output.rs b/src/librustc_mir/borrow_check/type_check/input_output.rs index 37cf77b7095c6..f2194c77c8991 100644 --- a/src/librustc_mir/borrow_check/type_check/input_output.rs +++ b/src/librustc_mir/borrow_check/type_check/input_output.rs @@ -64,13 +64,16 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } }; + debug!( + "equate_inputs_and_outputs: normalized_input_tys = {:?}, local_decls = {:?}", + normalized_input_tys, body.local_decls + ); + // Equate expected input tys with those in the MIR. for (&normalized_input_ty, argument_index) in normalized_input_tys.iter().zip(0..) { // In MIR, argument N is stored in local N+1. let local = Local::new(argument_index + 1); - debug!("equate_inputs_and_outputs: normalized_input_ty = {:?}", normalized_input_ty); - let mir_input_ty = body.local_decls[local].ty; let mir_input_span = body.local_decls[local].source_info.span; self.equate_normalized_input_or_output( From dfcfa170f57695cd1169ae9dc65c0ed629e1a2a3 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 10 Feb 2020 17:23:09 +0100 Subject: [PATCH 03/12] Make async/await lowering use resume arguments --- src/librustc_ast_lowering/expr.rs | 95 +++++++++++++++---- src/librustc_ast_lowering/item.rs | 2 +- src/librustc_ast_lowering/lib.rs | 5 + src/librustc_span/symbol.rs | 3 +- .../async-await/issues/issue-62009-1.stderr | 4 +- 5 files changed, 86 insertions(+), 23 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index a4cbae5196635..104634f4fa0bb 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -10,6 +10,7 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Symbol}; +use rustc_span::DUMMY_SP; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { @@ -483,14 +484,44 @@ impl<'hir> LoweringContext<'_, 'hir> { Some(ty) => FnRetTy::Ty(ty), None => FnRetTy::Default(span), }; - let ast_decl = FnDecl { inputs: vec![], output }; + + let task_context_id = self.resolver.next_node_id(); + let task_context_hid = self.lower_node_id(task_context_id); + let ast_decl = FnDecl { + inputs: vec![Param { + attrs: AttrVec::new(), + ty: AstP(Ty { + id: self.resolver.next_node_id(), + kind: TyKind::Infer, + span: DUMMY_SP, + }), + pat: AstP(Pat { + id: task_context_id, + kind: PatKind::Ident( + BindingMode::ByValue(Mutability::Mut), + Ident::with_dummy_span(sym::_task_context), + None, + ), + span: DUMMY_SP, + }), + id: self.resolver.next_node_id(), + span: DUMMY_SP, + is_placeholder: false, + }], + output, + }; let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); let body_id = self.lower_fn_body(&ast_decl, |this| { this.generator_kind = Some(hir::GeneratorKind::Async(async_gen_kind)); - body(this) + + let old_ctx = this.task_context; + this.task_context = Some(task_context_hid); + let res = body(this); + this.task_context = old_ctx; + res }); - // `static || -> { body }`: + // `static |task_context| -> { body }`: let generator_kind = hir::ExprKind::Closure( capture_clause, decl, @@ -523,9 +554,10 @@ impl<'hir> LoweringContext<'_, 'hir> { /// ```rust /// match { /// mut pinned => loop { - /// match ::std::future::poll_with_tls_context(unsafe { - /// <::std::pin::Pin>::new_unchecked(&mut pinned) - /// }) { + /// match unsafe { ::std::future::poll_with_context( + /// <::std::pin::Pin>::new_unchecked(&mut pinned), + /// task_context, + /// ) } { /// ::std::task::Poll::Ready(result) => break result, /// ::std::task::Poll::Pending => {} /// } @@ -561,12 +593,23 @@ impl<'hir> LoweringContext<'_, 'hir> { let (pinned_pat, pinned_pat_hid) = self.pat_ident_binding_mode(span, pinned_ident, hir::BindingAnnotation::Mutable); - // ::std::future::poll_with_tls_context(unsafe { - // ::std::pin::Pin::new_unchecked(&mut pinned) - // })` + let task_context_ident = Ident::with_dummy_span(sym::_task_context); + + // unsafe { + // ::std::future::poll_with_context( + // ::std::pin::Pin::new_unchecked(&mut pinned), + // task_context, + // ) + // } let poll_expr = { let pinned = self.expr_ident(span, pinned_ident, pinned_pat_hid); let ref_mut_pinned = self.expr_mut_addr_of(span, pinned); + let task_context = if let Some(task_context_hid) = self.task_context { + self.expr_ident_mut(span, task_context_ident, task_context_hid) + } else { + // Use of `await` outside of an async context, we cannot use `task_context` here. + self.expr_err(span) + }; let pin_ty_id = self.next_id(); let new_unchecked_expr_kind = self.expr_call_std_assoc_fn( pin_ty_id, @@ -575,14 +618,13 @@ impl<'hir> LoweringContext<'_, 'hir> { "new_unchecked", arena_vec![self; ref_mut_pinned], ); - let new_unchecked = - self.arena.alloc(self.expr(span, new_unchecked_expr_kind, ThinVec::new())); - let unsafe_expr = self.expr_unsafe(new_unchecked); - self.expr_call_std_path( + let new_unchecked = self.expr(span, new_unchecked_expr_kind, ThinVec::new()); + let call = self.expr_call_std_path( gen_future_span, - &[sym::future, sym::poll_with_tls_context], - arena_vec![self; unsafe_expr], - ) + &[sym::future, sym::poll_with_context], + arena_vec![self; new_unchecked, task_context], + ); + self.arena.alloc(self.expr_unsafe(call)) }; // `::std::task::Poll::Ready(result) => break result` @@ -629,12 +671,27 @@ impl<'hir> LoweringContext<'_, 'hir> { hir::ExprKind::Yield(unit, hir::YieldSource::Await), ThinVec::new(), ); - self.stmt_expr(span, yield_expr) + let yield_expr = self.arena.alloc(yield_expr); + + if let Some(task_context_hid) = self.task_context { + let lhs = self.expr_ident(span, task_context_ident, task_context_hid); + let assign = self.expr( + span, + hir::ExprKind::Assign(lhs, yield_expr, span), + AttrVec::new(), + ); + self.stmt_expr(span, assign) + } else { + // Use of `await` outside of an async context. Return `yield_expr` so that we can + // proceed with type checking. + self.stmt(span, hir::StmtKind::Semi(yield_expr)) + } }; - let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None); + let loop_block = + self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None); - // loop { .. } + // loop { ...; task_context = yield (); } let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop), diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index aab6aa7c35b0e..b1fd3da99ce01 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -809,7 +809,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } /// Construct `ExprKind::Err` for the given `span`. - fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> { + crate fn expr_err(&mut self, span: Span) -> hir::Expr<'hir> { self.expr(span, hir::ExprKind::Err, AttrVec::new()) } diff --git a/src/librustc_ast_lowering/lib.rs b/src/librustc_ast_lowering/lib.rs index 32b0f0db3589d..3c1a82febdae4 100644 --- a/src/librustc_ast_lowering/lib.rs +++ b/src/librustc_ast_lowering/lib.rs @@ -117,6 +117,10 @@ struct LoweringContext<'a, 'hir: 'a> { generator_kind: Option, + /// When inside an `async` context, this is the `HirId` of the + /// `task_context` local bound to the resume argument of the generator. + task_context: Option, + /// Used to get the current `fn`'s def span to point to when using `await` /// outside of an `async fn`. current_item: Option, @@ -295,6 +299,7 @@ pub fn lower_crate<'a, 'hir>( item_local_id_counters: Default::default(), node_id_to_hir_id: IndexVec::new(), generator_kind: None, + task_context: None, current_item: None, lifetimes_to_define: Vec::new(), is_collecting_in_band_lifetimes: false, diff --git a/src/librustc_span/symbol.rs b/src/librustc_span/symbol.rs index 19754c83038e2..e7adbaa03eba4 100644 --- a/src/librustc_span/symbol.rs +++ b/src/librustc_span/symbol.rs @@ -544,7 +544,7 @@ symbols! { plugin_registrar, plugins, Poll, - poll_with_tls_context, + poll_with_context, powerpc_target_feature, precise_pointer_size_matching, pref_align_of, @@ -720,6 +720,7 @@ symbols! { target_has_atomic_load_store, target_thread_local, task, + _task_context, tbm_target_feature, termination_trait, termination_trait_test, diff --git a/src/test/ui/async-await/issues/issue-62009-1.stderr b/src/test/ui/async-await/issues/issue-62009-1.stderr index cd6670923c2c6..0624c049048c7 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -33,10 +33,10 @@ error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:16:5: 16:15]: std: LL | (|_| 2333).await; | ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:16:5: 16:15]` | - ::: $SRC_DIR/libstd/future.rs:LL:COL + ::: $SRC_DIR/libcore/future/mod.rs:LL:COL | LL | F: Future, - | ------ required by this bound in `std::future::poll_with_tls_context` + | ------ required by this bound in `std::future::poll_with_context` error: aborting due to 4 previous errors From f79a95a65dea5901cb020b41997fb4d4ca806b18 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 10 Feb 2020 17:35:58 +0100 Subject: [PATCH 04/12] Test that async/await compiles with `#![no_std]` --- src/test/ui/async-await/no-std.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) create mode 100644 src/test/ui/async-await/no-std.rs diff --git a/src/test/ui/async-await/no-std.rs b/src/test/ui/async-await/no-std.rs new file mode 100644 index 0000000000000..63e93cdff7e77 --- /dev/null +++ b/src/test/ui/async-await/no-std.rs @@ -0,0 +1,13 @@ +// edition:2018 +// check-pass + +#![no_std] +#![crate_type = "rlib"] + +use core::future::Future; + +async fn a(f: impl Future) { + f.await; +} + +fn main() {} From b7fba973cb4b6547f24d89b901f7ac294c269503 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 10 Feb 2020 18:20:22 +0100 Subject: [PATCH 05/12] Format --- src/libcore/future/mod.rs | 2 +- src/librustc_ast_lowering/expr.rs | 10 +++------- 2 files changed, 4 insertions(+), 8 deletions(-) diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 6150f34d8446d..9dcb2cea2ea71 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -47,7 +47,7 @@ unsafe impl Sync for ResumeTy {} #[inline] pub const fn from_generator(gen: T) -> impl Future where - T: Generator + T: Generator, { #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] struct GenFuture>(T); diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 104634f4fa0bb..868b31d668c0c 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -675,11 +675,8 @@ impl<'hir> LoweringContext<'_, 'hir> { if let Some(task_context_hid) = self.task_context { let lhs = self.expr_ident(span, task_context_ident, task_context_hid); - let assign = self.expr( - span, - hir::ExprKind::Assign(lhs, yield_expr, span), - AttrVec::new(), - ); + let assign = + self.expr(span, hir::ExprKind::Assign(lhs, yield_expr, span), AttrVec::new()); self.stmt_expr(span, assign) } else { // Use of `await` outside of an async context. Return `yield_expr` so that we can @@ -688,8 +685,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } }; - let loop_block = - self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None); + let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None); // loop { ...; task_context = yield (); } let loop_expr = self.arena.alloc(hir::Expr { From 37b5bfce7612d1a5d8862fbfc9034aca5df33f88 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Mon, 10 Feb 2020 18:59:21 +0100 Subject: [PATCH 06/12] Improve comments in HIR lowering code --- src/librustc_ast_lowering/expr.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 868b31d668c0c..93e32e85efc41 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -561,7 +561,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// ::std::task::Poll::Ready(result) => break result, /// ::std::task::Poll::Pending => {} /// } - /// yield (); + /// task_context = yield (); /// } /// } /// ``` @@ -664,6 +664,7 @@ impl<'hir> LoweringContext<'_, 'hir> { self.stmt_expr(span, match_expr) }; + // task_context = yield (); let yield_stmt = { let unit = self.expr_unit(span); let yield_expr = self.expr( @@ -687,7 +688,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let loop_block = self.block_all(span, arena_vec![self; inner_match_stmt, yield_stmt], None); - // loop { ...; task_context = yield (); } + // loop { .. } let loop_expr = self.arena.alloc(hir::Expr { hir_id: loop_hir_id, kind: hir::ExprKind::Loop(loop_block, None, hir::LoopSource::Loop), From be62aed2025a19aadadbfa09633ef5d20dbfb668 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 11 Feb 2020 11:51:58 +0100 Subject: [PATCH 07/12] Remove useless derives on `GenFuture` Not sure why these were there, I guess because this type used to kind of be part of public API? --- src/libcore/future/mod.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 9dcb2cea2ea71..e808f9d2f1024 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -49,7 +49,6 @@ pub const fn from_generator(gen: T) -> impl Future where T: Generator, { - #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] struct GenFuture>(T); // We rely on the fact that async/await futures are immovable in order to create From 6450101b6947d0ff891475dad8668b2f1224212b Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 11 Feb 2020 12:03:52 +0100 Subject: [PATCH 08/12] Split up large `FnDecl` expression --- src/librustc_ast_lowering/expr.rs | 27 +++++++++++++-------------- 1 file changed, 13 insertions(+), 14 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index 93e32e85efc41..f84efe2ba76f5 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -487,23 +487,22 @@ impl<'hir> LoweringContext<'_, 'hir> { let task_context_id = self.resolver.next_node_id(); let task_context_hid = self.lower_node_id(task_context_id); + + let arg_ty = Ty { id: self.resolver.next_node_id(), kind: TyKind::Infer, span: DUMMY_SP }; + let arg_pat = Pat { + id: task_context_id, + kind: PatKind::Ident( + BindingMode::ByValue(Mutability::Mut), + Ident::with_dummy_span(sym::_task_context), + None, + ), + span: DUMMY_SP, + }; let ast_decl = FnDecl { inputs: vec![Param { attrs: AttrVec::new(), - ty: AstP(Ty { - id: self.resolver.next_node_id(), - kind: TyKind::Infer, - span: DUMMY_SP, - }), - pat: AstP(Pat { - id: task_context_id, - kind: PatKind::Ident( - BindingMode::ByValue(Mutability::Mut), - Ident::with_dummy_span(sym::_task_context), - None, - ), - span: DUMMY_SP, - }), + ty: AstP(arg_ty), + pat: AstP(arg_pat), id: self.resolver.next_node_id(), span: DUMMY_SP, is_placeholder: false, From 50b9d772dbca3cd54c772b67abe2eff24e6abac0 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 3 Mar 2020 16:05:11 +0100 Subject: [PATCH 09/12] Make `ResumeTy` contents private --- src/libcore/future/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index e808f9d2f1024..517f8c98c4774 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -26,7 +26,7 @@ pub use self::future::Future; #[unstable(feature = "gen_future", issue = "50547")] #[cfg(not(bootstrap))] #[derive(Debug, Copy, Clone)] -pub struct ResumeTy(pub NonNull>); +pub struct ResumeTy(NonNull>); #[unstable(feature = "gen_future", issue = "50547")] #[cfg(not(bootstrap))] From e419168bb8256444ab98f220c03545b8824037d4 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 3 Mar 2020 17:04:35 +0100 Subject: [PATCH 10/12] Clarify comment --- src/libcore/future/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 517f8c98c4774..6ee8479b34780 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -58,7 +58,7 @@ where impl> Future for GenFuture { type Output = T::Return; fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - // Safety: Safe because we're !Unpin + !Drop mapping to a ?Unpin value + // Safety: Safe because we're !Unpin + !Drop, and this is just a field projection. let gen = unsafe { Pin::map_unchecked_mut(self, |s| &mut s.0) }; // Resume the generator, turning the `&mut Context` into a `NonNull` raw pointer. The From 78274bc17c671655aaadba2096490fad59de2133 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Wed, 4 Mar 2020 14:53:47 +0100 Subject: [PATCH 11/12] Don't create AST fragments when lowering to HIR --- src/librustc_ast_lowering/expr.rs | 62 ++++++++++++++++--------------- src/librustc_ast_lowering/item.rs | 2 +- 2 files changed, 34 insertions(+), 30 deletions(-) diff --git a/src/librustc_ast_lowering/expr.rs b/src/librustc_ast_lowering/expr.rs index f84efe2ba76f5..a212f0a71077b 100644 --- a/src/librustc_ast_lowering/expr.rs +++ b/src/librustc_ast_lowering/expr.rs @@ -10,7 +10,6 @@ use rustc_hir as hir; use rustc_hir::def::Res; use rustc_span::source_map::{respan, DesugaringKind, Span, Spanned}; use rustc_span::symbol::{sym, Symbol}; -use rustc_span::DUMMY_SP; impl<'hir> LoweringContext<'_, 'hir> { fn lower_exprs(&mut self, exprs: &[AstP]) -> &'hir [hir::Expr<'hir>] { @@ -471,6 +470,15 @@ impl<'hir> LoweringContext<'_, 'hir> { } } + /// Lower an `async` construct to a generator that is then wrapped so it implements `Future`. + /// + /// This results in: + /// + /// ```text + /// std::future::from_generator(static move? |_task_context| -> { + /// + /// }) + /// ``` pub(super) fn make_async_expr( &mut self, capture_clause: CaptureBy, @@ -481,46 +489,42 @@ impl<'hir> LoweringContext<'_, 'hir> { body: impl FnOnce(&mut Self) -> hir::Expr<'hir>, ) -> hir::ExprKind<'hir> { let output = match ret_ty { - Some(ty) => FnRetTy::Ty(ty), - None => FnRetTy::Default(span), + Some(ty) => hir::FnRetTy::Return(self.lower_ty(&ty, ImplTraitContext::disallowed())), + None => hir::FnRetTy::DefaultReturn(span), }; - let task_context_id = self.resolver.next_node_id(); - let task_context_hid = self.lower_node_id(task_context_id); + // Resume argument type. We let the compiler infer this to simplify the lowering. It is + // fully constrained by `future::from_generator`. + let input_ty = hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::Infer, span }; - let arg_ty = Ty { id: self.resolver.next_node_id(), kind: TyKind::Infer, span: DUMMY_SP }; - let arg_pat = Pat { - id: task_context_id, - kind: PatKind::Ident( - BindingMode::ByValue(Mutability::Mut), - Ident::with_dummy_span(sym::_task_context), - None, - ), - span: DUMMY_SP, - }; - let ast_decl = FnDecl { - inputs: vec![Param { - attrs: AttrVec::new(), - ty: AstP(arg_ty), - pat: AstP(arg_pat), - id: self.resolver.next_node_id(), - span: DUMMY_SP, - is_placeholder: false, - }], + // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`. + let decl = self.arena.alloc(hir::FnDecl { + inputs: arena_vec![self; input_ty], output, - }; - let decl = self.lower_fn_decl(&ast_decl, None, /* impl trait allowed */ false, None); - let body_id = self.lower_fn_body(&ast_decl, |this| { + c_variadic: false, + implicit_self: hir::ImplicitSelfKind::None, + }); + + // Lower the argument pattern/ident. The ident is used again in the `.await` lowering. + let (pat, task_context_hid) = self.pat_ident_binding_mode( + span, + Ident::with_dummy_span(sym::_task_context), + hir::BindingAnnotation::Mutable, + ); + let param = hir::Param { attrs: &[], hir_id: self.next_id(), pat, span }; + let params = arena_vec![self; param]; + + let body_id = self.lower_body(move |this| { this.generator_kind = Some(hir::GeneratorKind::Async(async_gen_kind)); let old_ctx = this.task_context; this.task_context = Some(task_context_hid); let res = body(this); this.task_context = old_ctx; - res + (params, res) }); - // `static |task_context| -> { body }`: + // `static |_task_context| -> { body }`: let generator_kind = hir::ExprKind::Closure( capture_clause, decl, diff --git a/src/librustc_ast_lowering/item.rs b/src/librustc_ast_lowering/item.rs index b1fd3da99ce01..5f056ef6a4d86 100644 --- a/src/librustc_ast_lowering/item.rs +++ b/src/librustc_ast_lowering/item.rs @@ -955,7 +955,7 @@ impl<'hir> LoweringContext<'_, 'hir> { id } - fn lower_body( + pub(super) fn lower_body( &mut self, f: impl FnOnce(&mut Self) -> (&'hir [hir::Param<'hir>], hir::Expr<'hir>), ) -> hir::BodyId { From db0126a7c251f4cca39ad4c50527e88c97190992 Mon Sep 17 00:00:00 2001 From: Jonas Schievink Date: Tue, 17 Mar 2020 22:19:11 +0100 Subject: [PATCH 12/12] Add issue reference --- src/libcore/future/mod.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 6ee8479b34780..8dfda7a4a3236 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -17,7 +17,7 @@ pub use self::future::Future; /// This type is needed because: /// /// a) Generators cannot implement `for<'a, 'b> Generator<&'a mut Context<'b>>`, so we need to pass -/// a raw pointer. +/// a raw pointer (see https://github.com/rust-lang/rust/issues/68923). /// b) Raw pointers and `NonNull` aren't `Send` or `Sync`, so that would make every single future /// non-Send/Sync as well, and we don't want that. ///