Skip to content

Commit

Permalink
Auto merge of #68811 - tmandry:back-to-intofuture, r=<try>
Browse files Browse the repository at this point in the history
Re-land "add IntoFuture trait and support for await"

Testing the code from #65244 to see if the performance regressions are still there. #68606 and #68672 made perf optimizations that might interact with this change.

If this lands, fixes #67982.

cc @seanmonstar @jonas-schievink
r? @cramertj
  • Loading branch information
bors committed Feb 3, 2020
2 parents 8417d68 + c27d6f5 commit 976ac3b
Show file tree
Hide file tree
Showing 12 changed files with 123 additions and 13 deletions.
25 changes: 25 additions & 0 deletions src/libcore/future/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,21 @@ pub trait Future {
fn poll(self: Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output>;
}

/// 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<Output = Self::Output>;

/// 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<F: ?Sized + Future + Unpin> Future for &mut F {
type Output = F::Output;
Expand All @@ -119,3 +134,13 @@ where
Pin::get_mut(self).as_mut().poll(cx)
}
}

#[unstable(feature = "into_future", issue = "67644")]
impl<F: Future> IntoFuture for F {
type Output = F::Output;
type Future = F;

fn into_future(self) -> Self::Future {
self
}
}
3 changes: 3 additions & 0 deletions src/libcore/future/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
24 changes: 20 additions & 4 deletions src/librustc_ast_lowering/expr.rs
Original file line number Diff line number Diff line change
Expand Up @@ -521,7 +521,7 @@ impl<'hir> LoweringContext<'_, 'hir> {

/// Desugar `<expr>.await` into:
/// ```rust
/// match <expr> {
/// match ::std::future::IntoFuture::into_future(<expr>) {
/// mut pinned => loop {
/// match ::std::future::poll_with_tls_context(unsafe {
/// <::std::pin::Pin>::new_unchecked(&mut pinned)
Expand Down Expand Up @@ -645,11 +645,27 @@ impl<'hir> LoweringContext<'_, 'hir> {
// mut pinned => loop { ... }
let pinned_arm = self.arm(pinned_pat, loop_expr);

// match <expr> {
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
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 <into_future_expr> {
// 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(
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_ast_lowering/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -166,6 +166,7 @@ struct LoweringContext<'a, 'hir: 'a> {

allow_try_trait: Option<Lrc<[Symbol]>>,
allow_gen_future: Option<Lrc<[Symbol]>>,
allow_into_future: Option<Lrc<[Symbol]>>,
}

pub trait Resolver {
Expand Down Expand Up @@ -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)
}
Expand Down
2 changes: 2 additions & 0 deletions src/librustc_span/symbol.rs
Original file line number Diff line number Diff line change
Expand Up @@ -383,6 +383,8 @@ symbols! {
infer_static_outlives_requirements,
inline,
intel,
into_future,
IntoFuture,
into_iter,
IntoIterator,
into_result,
Expand Down
6 changes: 5 additions & 1 deletion src/libstd/future.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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.
///
Expand Down
1 change: 1 addition & 0 deletions src/libstd/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -270,6 +270,7 @@
#![feature(hashmap_internals)]
#![feature(int_error_internals)]
#![feature(int_error_matching)]
#![feature(into_future)]
#![feature(integer_atomics)]
#![feature(lang_items)]
#![feature(libc)]
Expand Down
6 changes: 3 additions & 3 deletions src/test/ui/async-await/async-fn-size-moved-locals.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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()));
}
28 changes: 28 additions & 0 deletions src/test/ui/async-await/await-into-future.rs
Original file line number Diff line number Diff line change
@@ -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<Box<dyn Future<Output = i32>>>;

fn into_future(self) -> Self::Future {
Box::pin(me())
}
}

async fn me() -> i32 {
41
}

async fn run() {
assert_eq!(AwaitMe.await, 41);
}

fn main() {}
5 changes: 1 addition & 4 deletions src/test/ui/async-await/issues/issue-62009-1.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -32,11 +32,8 @@ 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
|
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

Expand Down
8 changes: 8 additions & 0 deletions src/test/ui/async-await/unresolved_type_param.rs
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,20 @@ async fn foo() {
//~^ ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
//~| ERROR type inside `async fn` body must be known in this context
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE cannot infer type for type parameter `T`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE the type is part of the `async fn` body because of this `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
//~| NOTE in this expansion of desugaring of `await`
Expand Down
26 changes: 25 additions & 1 deletion src/test/ui/async-await/unresolved_type_param.stderr
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,30 @@ note: the type is part of the `async fn` body because of this `await`
LL | bar().await;
| ^^^^^^^^^^^

error: aborting due to 3 previous errors
error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
| ^^^^^^^^^^^

error[E0698]: type inside `async fn` body must be known in this context
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
|
note: the type is part of the `async fn` body because of this `await`
--> $DIR/unresolved_type_param.rs:9:5
|
LL | bar().await;
| ^^^^^^^^^^^

error: aborting due to 5 previous errors

For more information about this error, try `rustc --explain E0698`.

0 comments on commit 976ac3b

Please sign in to comment.