From f35517ee861dc012ccc26083dd4520045e2c4f6f Mon Sep 17 00:00:00 2001 From: Sean McArthur Date: Thu, 26 Dec 2019 12:57:09 -0800 Subject: [PATCH] core: add IntoFuture trait and support for await --- src/libcore/future/future.rs | 25 +++++++++++++++++ src/libcore/future/mod.rs | 3 ++ src/librustc/hir/lowering.rs | 2 ++ src/librustc/hir/lowering/expr.rs | 24 +++++++++++++--- src/libstd/future.rs | 6 +++- src/libstd/lib.rs | 1 + src/libsyntax_pos/symbol.rs | 2 ++ .../async-await/async-fn-size-moved-locals.rs | 6 ++-- src/test/ui/async-await/await-into-future.rs | 28 +++++++++++++++++++ .../async-await/issues/issue-62009-1.stderr | 5 +--- 10 files changed, 90 insertions(+), 12 deletions(-) create mode 100644 src/test/ui/async-await/await-into-future.rs diff --git a/src/libcore/future/future.rs b/src/libcore/future/future.rs index f14ed38b9b0f2..dcb819f9381a4 100644 --- a/src/libcore/future/future.rs +++ b/src/libcore/future/future.rs @@ -99,6 +99,21 @@ pub trait Future { fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll; } +/// Conversion into a `Future`. +#[unstable(feature = "into_future", issue = "67644")] +pub trait IntoFuture { + /// The output that the future will produce on completion. + #[unstable(feature = "into_future", issue = "67644")] + type Output; + /// Which kind of future are we turning this into? + #[unstable(feature = "into_future", issue = "67644")] + type Future: Future; + + /// Creates a future from a value. + #[unstable(feature = "into_future", issue = "67644")] + fn into_future(self) -> Self::Future; +} + #[stable(feature = "futures_api", since = "1.36.0")] impl Future for &mut F { type Output = F::Output; @@ -119,3 +134,13 @@ where Pin::get_mut(self).as_mut().poll(cx) } } + +#[unstable(feature = "into_future", issue = "67644")] +impl IntoFuture for F { + type Output = F::Output; + type Future = F; + + fn into_future(self) -> Self::Future { + self + } +} diff --git a/src/libcore/future/mod.rs b/src/libcore/future/mod.rs index 89ea4713cfdaa..aecd57b9ce71a 100644 --- a/src/libcore/future/mod.rs +++ b/src/libcore/future/mod.rs @@ -5,3 +5,6 @@ mod future; #[stable(feature = "futures_api", since = "1.36.0")] pub use self::future::Future; + +#[unstable(feature = "into_future", issue = "67644")] +pub use self::future::IntoFuture; diff --git a/src/librustc/hir/lowering.rs b/src/librustc/hir/lowering.rs index ed84bd118f725..5fca5f061caf2 100644 --- a/src/librustc/hir/lowering.rs +++ b/src/librustc/hir/lowering.rs @@ -168,6 +168,7 @@ pub struct LoweringContext<'a, 'hir: 'a> { allow_try_trait: Option>, allow_gen_future: Option>, + allow_into_future: Option>, } pub trait Resolver { @@ -300,6 +301,7 @@ pub fn lower_crate<'a, 'hir>( in_scope_lifetimes: Vec::new(), allow_try_trait: Some([sym::try_trait][..].into()), allow_gen_future: Some([sym::gen_future][..].into()), + allow_into_future: Some([sym::into_future][..].into()), } .lower_crate(krate) } diff --git a/src/librustc/hir/lowering/expr.rs b/src/librustc/hir/lowering/expr.rs index 8a9614c6cb2c0..dbfa351b918b2 100644 --- a/src/librustc/hir/lowering/expr.rs +++ b/src/librustc/hir/lowering/expr.rs @@ -529,7 +529,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `.await` into: /// ```rust - /// match { + /// match ::std::future::IntoFuture::into_future() { /// mut pinned => loop { /// match ::std::future::poll_with_tls_context(unsafe { /// <::std::pin::Pin>::new_unchecked(&mut pinned) @@ -653,11 +653,27 @@ impl<'hir> LoweringContext<'_, 'hir> { // mut pinned => loop { ... } let pinned_arm = self.arm(pinned_pat, loop_expr); - // match { + // `match ::std::future::IntoFuture::into_future() { ... }` + let into_future_span = self.mark_span_with_reason( + DesugaringKind::Await, + await_span, + self.allow_into_future.clone(), + ); + let expr = self.lower_expr_mut(expr); + let into_future_expr = self.expr_call_std_path( + into_future_span, + &[sym::future, sym::IntoFuture, sym::into_future], + arena_vec![self; expr], + ); + + // match { // mut pinned => loop { .. } // } - let expr = self.lower_expr(expr); - hir::ExprKind::Match(expr, arena_vec![self; pinned_arm], hir::MatchSource::AwaitDesugar) + hir::ExprKind::Match( + into_future_expr, + arena_vec![self; pinned_arm], + hir::MatchSource::AwaitDesugar, + ) } fn lower_expr_closure( diff --git a/src/libstd/future.rs b/src/libstd/future.rs index 9c7422c2b20a6..908736c63931b 100644 --- a/src/libstd/future.rs +++ b/src/libstd/future.rs @@ -10,7 +10,11 @@ use core::task::{Context, Poll}; #[doc(inline)] #[stable(feature = "futures_api", since = "1.36.0")] -pub use core::future::*; +pub use core::future::Future; + +#[doc(inline)] +#[unstable(feature = "into_future", issue = "67644")] +pub use core::future::IntoFuture; /// Wrap a generator in a future. /// diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs index 9e9df5ab9b6ce..82c8dc1237e2c 100644 --- a/src/libstd/lib.rs +++ b/src/libstd/lib.rs @@ -269,6 +269,7 @@ #![feature(hashmap_internals)] #![feature(int_error_internals)] #![feature(int_error_matching)] +#![feature(into_future)] #![feature(integer_atomics)] #![feature(lang_items)] #![feature(libc)] diff --git a/src/libsyntax_pos/symbol.rs b/src/libsyntax_pos/symbol.rs index 8fdc199d9ed7c..7ae037faf151d 100644 --- a/src/libsyntax_pos/symbol.rs +++ b/src/libsyntax_pos/symbol.rs @@ -379,6 +379,8 @@ symbols! { infer_static_outlives_requirements, inline, intel, + into_future, + IntoFuture, into_iter, IntoIterator, into_result, diff --git a/src/test/ui/async-await/async-fn-size-moved-locals.rs b/src/test/ui/async-await/async-fn-size-moved-locals.rs index 4a413381aa300..f2469de7394b0 100644 --- a/src/test/ui/async-await/async-fn-size-moved-locals.rs +++ b/src/test/ui/async-await/async-fn-size-moved-locals.rs @@ -112,7 +112,7 @@ async fn mixed_sizes() { fn main() { assert_eq!(1028, std::mem::size_of_val(&single())); assert_eq!(1032, std::mem::size_of_val(&single_with_noop())); - assert_eq!(3084, std::mem::size_of_val(&joined())); - assert_eq!(3084, std::mem::size_of_val(&joined_with_noop())); - assert_eq!(7188, std::mem::size_of_val(&mixed_sizes())); + assert_eq!(3080, std::mem::size_of_val(&joined())); + assert_eq!(3080, std::mem::size_of_val(&joined_with_noop())); + assert_eq!(6164, std::mem::size_of_val(&mixed_sizes())); } diff --git a/src/test/ui/async-await/await-into-future.rs b/src/test/ui/async-await/await-into-future.rs new file mode 100644 index 0000000000000..d5ff0eb304937 --- /dev/null +++ b/src/test/ui/async-await/await-into-future.rs @@ -0,0 +1,28 @@ +// check-pass + +// edition:2018 + +#![feature(into_future)] + +use std::{future::{Future, IntoFuture}, pin::Pin}; + +struct AwaitMe; + +impl IntoFuture for AwaitMe { + type Output = i32; + type Future = Pin>>; + + fn into_future(self) -> Self::Future { + Box::pin(me()) + } +} + +async fn me() -> i32 { + 41 +} + +async fn run() { + assert_eq!(AwaitMe.await, 41); +} + +fn main() {} 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 3a49a5a97de3d..e31904b6c1f7b 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -32,11 +32,8 @@ error[E0277]: the trait bound `[closure@$DIR/issue-62009-1.rs:13:5: 13:15]: std: | LL | (|_| 2333).await; | ^^^^^^^^^^^^^^^^ the trait `std::future::Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:13:5: 13:15]` - | - ::: $SRC_DIR/libstd/future.rs:LL:COL | -LL | F: Future, - | ------ required by this bound in `std::future::poll_with_tls_context` + = note: required by `std::future::IntoFuture::into_future` error: aborting due to 4 previous errors