Auto merge of #90737 - eholk:intofuture, r=tmandry
Reintroduce `into_future` in `.await` desugaring This is a reintroduction of the remaining parts from https://github.com/rust-lang/rust/pull/65244 that have not been relanded yet. This isn't quite ready to merge yet. The last attempt was reverting due to performance regressions, so we need to make sure this does not introduce those issues again. Issues #67644, #67982 /cc `@yoshuawuyts`
This commit is contained in:
commit
532d2b14c0
15 changed files with 105 additions and 9 deletions
|
@ -593,7 +593,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
|
||||
/// Desugar `<expr>.await` into:
|
||||
/// ```rust
|
||||
/// match <expr> {
|
||||
/// match ::std::future::IntoFuture::into_future(<expr>) {
|
||||
/// mut pinned => loop {
|
||||
/// match unsafe { ::std::future::Future::poll(
|
||||
/// <::std::pin::Pin>::new_unchecked(&mut pinned),
|
||||
|
@ -629,7 +629,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
|
|||
await_span,
|
||||
self.allow_gen_future.clone(),
|
||||
);
|
||||
let expr = self.lower_expr(expr);
|
||||
let expr = self.lower_expr_mut(expr);
|
||||
|
||||
let pinned_ident = Ident::with_dummy_span(sym::pinned);
|
||||
let (pinned_pat, pinned_pat_hid) =
|
||||
|
@ -746,10 +746,26 @@ 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 into_future_expr = self.expr_call_lang_item_fn(
|
||||
into_future_span,
|
||||
hir::LangItem::IntoFutureIntoFuture,
|
||||
arena_vec![self; expr],
|
||||
);
|
||||
|
||||
// match <into_future_expr> {
|
||||
// mut pinned => loop { .. }
|
||||
// }
|
||||
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(
|
||||
|
|
|
@ -162,6 +162,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 ResolverAstLowering {
|
||||
|
@ -320,6 +321,7 @@ pub fn lower_crate<'a, 'hir>(
|
|||
in_scope_lifetimes: Vec::new(),
|
||||
allow_try_trait: Some([sym::try_trait_v2][..].into()),
|
||||
allow_gen_future: Some([sym::gen_future][..].into()),
|
||||
allow_into_future: Some([sym::into_future][..].into()),
|
||||
}
|
||||
.lower_crate(krate)
|
||||
}
|
||||
|
|
|
@ -348,6 +348,7 @@ language_item_table! {
|
|||
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant, GenericRequirement::None;
|
||||
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None;
|
||||
|
||||
IntoFutureIntoFuture, sym::into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
|
||||
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
|
||||
|
||||
|
|
|
@ -196,6 +196,7 @@ symbols! {
|
|||
Implied,
|
||||
Input,
|
||||
Into,
|
||||
IntoFuture,
|
||||
IntoIterator,
|
||||
IoRead,
|
||||
IoWrite,
|
||||
|
@ -737,6 +738,7 @@ symbols! {
|
|||
inout,
|
||||
instruction_set,
|
||||
intel,
|
||||
into_future,
|
||||
into_iter,
|
||||
intra_doc_pointers,
|
||||
intrinsics,
|
||||
|
|
|
@ -28,7 +28,11 @@ use crate::task::{Context, Poll};
|
|||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
#[lang = "future_trait"]
|
||||
#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
|
||||
#[rustc_on_unimplemented(
|
||||
label = "`{Self}` is not a future",
|
||||
message = "`{Self}` is not a future",
|
||||
note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
|
||||
)]
|
||||
pub trait Future {
|
||||
/// The type of value produced on completion.
|
||||
#[stable(feature = "futures_api", since = "1.36.0")]
|
||||
|
|
|
@ -13,6 +13,7 @@ pub trait IntoFuture {
|
|||
|
||||
/// Creates a future from a value.
|
||||
#[unstable(feature = "into_future", issue = "67644")]
|
||||
#[cfg_attr(not(bootstrap), lang = "into_future")]
|
||||
fn into_future(self) -> Self::Future;
|
||||
}
|
||||
|
||||
|
|
|
@ -5,6 +5,7 @@ LL | fn get_future() -> impl Future<Output = ()> {
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `()`
|
||||
= note: () must be a future or must implement `IntoFuture` to be awaited
|
||||
|
||||
error[E0698]: type inside `async fn` body must be known in this context
|
||||
--> $DIR/async-error-span.rs:13:9
|
||||
|
|
|
@ -112,7 +112,7 @@ async fn mixed_sizes() {
|
|||
fn main() {
|
||||
assert_eq!(1025, std::mem::size_of_val(&single()));
|
||||
assert_eq!(1026, std::mem::size_of_val(&single_with_noop()));
|
||||
assert_eq!(3078, std::mem::size_of_val(&joined()));
|
||||
assert_eq!(3079, std::mem::size_of_val(&joined_with_noop()));
|
||||
assert_eq!(7181, std::mem::size_of_val(&mixed_sizes()));
|
||||
assert_eq!(3076, std::mem::size_of_val(&joined()));
|
||||
assert_eq!(3076, std::mem::size_of_val(&joined_with_noop()));
|
||||
assert_eq!(6157, std::mem::size_of_val(&mixed_sizes()));
|
||||
}
|
||||
|
|
30
src/test/ui/async-await/await-into-future.rs
Normal file
30
src/test/ui/async-await/await-into-future.rs
Normal file
|
@ -0,0 +1,30 @@
|
|||
// run-pass
|
||||
// aux-build: issue-72470-lib.rs
|
||||
// edition:2021
|
||||
#![feature(into_future)]
|
||||
|
||||
extern crate issue_72470_lib;
|
||||
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() {
|
||||
issue_72470_lib::run(run());
|
||||
}
|
|
@ -25,6 +25,8 @@ LL | [1; ().await];
|
|||
| ^^^^^^^^ `()` is not a future
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `()`
|
||||
= note: () must be a future or must implement `IntoFuture` to be awaited
|
||||
= note: required because of the requirements on the impl of `IntoFuture` for `()`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -34,6 +34,8 @@ LL | (|_| 2333).await;
|
|||
| ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
|
||||
= note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited
|
||||
= note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
|
||||
|
||||
error: aborting due to 4 previous errors
|
||||
|
||||
|
|
|
@ -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`
|
||||
|
|
|
@ -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`.
|
||||
|
|
|
@ -11,6 +11,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
|
|||
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `u32`
|
||||
= note: u32 must be a future or must implement `IntoFuture` to be awaited
|
||||
|
||||
error: aborting due to 2 previous errors
|
||||
|
||||
|
|
|
@ -10,6 +10,7 @@ LL | bar(foo);
|
|||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `fn() -> impl Future<Output = ()> {foo}`
|
||||
= note: fn() -> impl Future<Output = ()> {foo} must be a future or must implement `IntoFuture` to be awaited
|
||||
note: required by a bound in `bar`
|
||||
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
|
||||
|
|
||||
|
@ -31,6 +32,7 @@ LL | bar(async_closure);
|
|||
| required by a bound introduced by this call
|
||||
|
|
||||
= help: the trait `Future` is not implemented for `[closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36]`
|
||||
= note: [closure@$DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:11:25: 11:36] must be a future or must implement `IntoFuture` to be awaited
|
||||
note: required by a bound in `bar`
|
||||
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
|
||||
|
|
||||
|
|
Loading…
Add table
Reference in a new issue