Skip to content

Commit 532d2b1

Browse files
committed
Auto merge of rust-lang#90737 - eholk:intofuture, r=tmandry
Reintroduce `into_future` in `.await` desugaring This is a reintroduction of the remaining parts from rust-lang#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 rust-lang#67644, rust-lang#67982 /cc `@yoshuawuyts`
2 parents ff2439b + 3268bf1 commit 532d2b1

15 files changed

+105
-9
lines changed

compiler/rustc_ast_lowering/src/expr.rs

+20-4
Original file line numberDiff line numberDiff line change
@@ -593,7 +593,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
593593

594594
/// Desugar `<expr>.await` into:
595595
/// ```rust
596-
/// match <expr> {
596+
/// match ::std::future::IntoFuture::into_future(<expr>) {
597597
/// mut pinned => loop {
598598
/// match unsafe { ::std::future::Future::poll(
599599
/// <::std::pin::Pin>::new_unchecked(&mut pinned),
@@ -629,7 +629,7 @@ impl<'hir> LoweringContext<'_, 'hir> {
629629
await_span,
630630
self.allow_gen_future.clone(),
631631
);
632-
let expr = self.lower_expr(expr);
632+
let expr = self.lower_expr_mut(expr);
633633

634634
let pinned_ident = Ident::with_dummy_span(sym::pinned);
635635
let (pinned_pat, pinned_pat_hid) =
@@ -746,10 +746,26 @@ impl<'hir> LoweringContext<'_, 'hir> {
746746
// mut pinned => loop { ... }
747747
let pinned_arm = self.arm(pinned_pat, loop_expr);
748748

749-
// match <expr> {
749+
// `match ::std::future::IntoFuture::into_future(<expr>) { ... }`
750+
let into_future_span = self.mark_span_with_reason(
751+
DesugaringKind::Await,
752+
await_span,
753+
self.allow_into_future.clone(),
754+
);
755+
let into_future_expr = self.expr_call_lang_item_fn(
756+
into_future_span,
757+
hir::LangItem::IntoFutureIntoFuture,
758+
arena_vec![self; expr],
759+
);
760+
761+
// match <into_future_expr> {
750762
// mut pinned => loop { .. }
751763
// }
752-
hir::ExprKind::Match(expr, arena_vec![self; pinned_arm], hir::MatchSource::AwaitDesugar)
764+
hir::ExprKind::Match(
765+
into_future_expr,
766+
arena_vec![self; pinned_arm],
767+
hir::MatchSource::AwaitDesugar,
768+
)
753769
}
754770

755771
fn lower_expr_closure(

compiler/rustc_ast_lowering/src/lib.rs

+2
Original file line numberDiff line numberDiff line change
@@ -162,6 +162,7 @@ struct LoweringContext<'a, 'hir: 'a> {
162162

163163
allow_try_trait: Option<Lrc<[Symbol]>>,
164164
allow_gen_future: Option<Lrc<[Symbol]>>,
165+
allow_into_future: Option<Lrc<[Symbol]>>,
165166
}
166167

167168
pub trait ResolverAstLowering {
@@ -320,6 +321,7 @@ pub fn lower_crate<'a, 'hir>(
320321
in_scope_lifetimes: Vec::new(),
321322
allow_try_trait: Some([sym::try_trait_v2][..].into()),
322323
allow_gen_future: Some([sym::gen_future][..].into()),
324+
allow_into_future: Some([sym::into_future][..].into()),
323325
}
324326
.lower_crate(krate)
325327
}

compiler/rustc_hir/src/lang_items.rs

+1
Original file line numberDiff line numberDiff line change
@@ -348,6 +348,7 @@ language_item_table! {
348348
ControlFlowContinue, sym::Continue, cf_continue_variant, Target::Variant, GenericRequirement::None;
349349
ControlFlowBreak, sym::Break, cf_break_variant, Target::Variant, GenericRequirement::None;
350350

351+
IntoFutureIntoFuture, sym::into_future, into_future_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
351352
IntoIterIntoIter, sym::into_iter, into_iter_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None;
352353
IteratorNext, sym::next, next_fn, Target::Method(MethodKind::Trait { body: false}), GenericRequirement::None;
353354

compiler/rustc_span/src/symbol.rs

+2
Original file line numberDiff line numberDiff line change
@@ -196,6 +196,7 @@ symbols! {
196196
Implied,
197197
Input,
198198
Into,
199+
IntoFuture,
199200
IntoIterator,
200201
IoRead,
201202
IoWrite,
@@ -737,6 +738,7 @@ symbols! {
737738
inout,
738739
instruction_set,
739740
intel,
741+
into_future,
740742
into_iter,
741743
intra_doc_pointers,
742744
intrinsics,

library/core/src/future/future.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,11 @@ use crate::task::{Context, Poll};
2828
#[must_use = "futures do nothing unless you `.await` or poll them"]
2929
#[stable(feature = "futures_api", since = "1.36.0")]
3030
#[lang = "future_trait"]
31-
#[rustc_on_unimplemented(label = "`{Self}` is not a future", message = "`{Self}` is not a future")]
31+
#[rustc_on_unimplemented(
32+
label = "`{Self}` is not a future",
33+
message = "`{Self}` is not a future",
34+
note = "{Self} must be a future or must implement `IntoFuture` to be awaited"
35+
)]
3236
pub trait Future {
3337
/// The type of value produced on completion.
3438
#[stable(feature = "futures_api", since = "1.36.0")]

library/core/src/future/into_future.rs

+1
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,7 @@ pub trait IntoFuture {
1313

1414
/// Creates a future from a value.
1515
#[unstable(feature = "into_future", issue = "67644")]
16+
#[cfg_attr(not(bootstrap), lang = "into_future")]
1617
fn into_future(self) -> Self::Future;
1718
}
1819

src/test/ui/async-await/async-error-span.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@ LL | fn get_future() -> impl Future<Output = ()> {
55
| ^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not a future
66
|
77
= help: the trait `Future` is not implemented for `()`
8+
= note: () must be a future or must implement `IntoFuture` to be awaited
89

910
error[E0698]: type inside `async fn` body must be known in this context
1011
--> $DIR/async-error-span.rs:13:9

src/test/ui/async-await/async-fn-size-moved-locals.rs

+3-3
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ async fn mixed_sizes() {
112112
fn main() {
113113
assert_eq!(1025, std::mem::size_of_val(&single()));
114114
assert_eq!(1026, std::mem::size_of_val(&single_with_noop()));
115-
assert_eq!(3078, std::mem::size_of_val(&joined()));
116-
assert_eq!(3079, std::mem::size_of_val(&joined_with_noop()));
117-
assert_eq!(7181, std::mem::size_of_val(&mixed_sizes()));
115+
assert_eq!(3076, std::mem::size_of_val(&joined()));
116+
assert_eq!(3076, std::mem::size_of_val(&joined_with_noop()));
117+
assert_eq!(6157, std::mem::size_of_val(&mixed_sizes()));
118118
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
// run-pass
2+
// aux-build: issue-72470-lib.rs
3+
// edition:2021
4+
#![feature(into_future)]
5+
6+
extern crate issue_72470_lib;
7+
use std::{future::{Future, IntoFuture}, pin::Pin};
8+
9+
struct AwaitMe;
10+
11+
impl IntoFuture for AwaitMe {
12+
type Output = i32;
13+
type Future = Pin<Box<dyn Future<Output = i32>>>;
14+
15+
fn into_future(self) -> Self::Future {
16+
Box::pin(me())
17+
}
18+
}
19+
20+
async fn me() -> i32 {
21+
41
22+
}
23+
24+
async fn run() {
25+
assert_eq!(AwaitMe.await, 41);
26+
}
27+
28+
fn main() {
29+
issue_72470_lib::run(run());
30+
}

src/test/ui/async-await/issue-70594.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -25,6 +25,8 @@ LL | [1; ().await];
2525
| ^^^^^^^^ `()` is not a future
2626
|
2727
= help: the trait `Future` is not implemented for `()`
28+
= note: () must be a future or must implement `IntoFuture` to be awaited
29+
= note: required because of the requirements on the impl of `IntoFuture` for `()`
2830

2931
error: aborting due to 4 previous errors
3032

src/test/ui/async-await/issues/issue-62009-1.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,8 @@ LL | (|_| 2333).await;
3434
| ^^^^^^^^^^^^^^^^ `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]` is not a future
3535
|
3636
= help: the trait `Future` is not implemented for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
37+
= note: [closure@$DIR/issue-62009-1.rs:12:5: 12:15] must be a future or must implement `IntoFuture` to be awaited
38+
= note: required because of the requirements on the impl of `IntoFuture` for `[closure@$DIR/issue-62009-1.rs:12:5: 12:15]`
3739

3840
error: aborting due to 4 previous errors
3941

src/test/ui/async-await/unresolved_type_param.rs

+8
Original file line numberDiff line numberDiff line change
@@ -10,12 +10,20 @@ async fn foo() {
1010
//~^ ERROR type inside `async fn` body must be known in this context
1111
//~| ERROR type inside `async fn` body must be known in this context
1212
//~| ERROR type inside `async fn` body must be known in this context
13+
//~| ERROR type inside `async fn` body must be known in this context
14+
//~| ERROR type inside `async fn` body must be known in this context
15+
//~| NOTE cannot infer type for type parameter `T`
16+
//~| NOTE cannot infer type for type parameter `T`
1317
//~| NOTE cannot infer type for type parameter `T`
1418
//~| NOTE cannot infer type for type parameter `T`
1519
//~| NOTE cannot infer type for type parameter `T`
1620
//~| NOTE the type is part of the `async fn` body because of this `await`
1721
//~| NOTE the type is part of the `async fn` body because of this `await`
1822
//~| NOTE the type is part of the `async fn` body because of this `await`
23+
//~| NOTE the type is part of the `async fn` body because of this `await`
24+
//~| NOTE the type is part of the `async fn` body because of this `await`
25+
//~| NOTE in this expansion of desugaring of `await`
26+
//~| NOTE in this expansion of desugaring of `await`
1927
//~| NOTE in this expansion of desugaring of `await`
2028
//~| NOTE in this expansion of desugaring of `await`
2129
//~| NOTE in this expansion of desugaring of `await`

src/test/ui/async-await/unresolved_type_param.stderr

+25-1
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,30 @@ note: the type is part of the `async fn` body because of this `await`
3434
LL | bar().await;
3535
| ^^^^^^^^^^^
3636

37-
error: aborting due to 3 previous errors
37+
error[E0698]: type inside `async fn` body must be known in this context
38+
--> $DIR/unresolved_type_param.rs:9:5
39+
|
40+
LL | bar().await;
41+
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
42+
|
43+
note: the type is part of the `async fn` body because of this `await`
44+
--> $DIR/unresolved_type_param.rs:9:5
45+
|
46+
LL | bar().await;
47+
| ^^^^^^^^^^^
48+
49+
error[E0698]: type inside `async fn` body must be known in this context
50+
--> $DIR/unresolved_type_param.rs:9:5
51+
|
52+
LL | bar().await;
53+
| ^^^ cannot infer type for type parameter `T` declared on the function `bar`
54+
|
55+
note: the type is part of the `async fn` body because of this `await`
56+
--> $DIR/unresolved_type_param.rs:9:5
57+
|
58+
LL | bar().await;
59+
| ^^^^^^^^^^^
60+
61+
error: aborting due to 5 previous errors
3862

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

src/test/ui/issues-71798.stderr

+1
Original file line numberDiff line numberDiff line change
@@ -11,6 +11,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future<Output = u32> + '_ {
1111
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `u32` is not a future
1212
|
1313
= help: the trait `Future` is not implemented for `u32`
14+
= note: u32 must be a future or must implement `IntoFuture` to be awaited
1415

1516
error: aborting due to 2 previous errors
1617

src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr

+2
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ LL | bar(foo);
1010
| required by a bound introduced by this call
1111
|
1212
= help: the trait `Future` is not implemented for `fn() -> impl Future<Output = ()> {foo}`
13+
= note: fn() -> impl Future<Output = ()> {foo} must be a future or must implement `IntoFuture` to be awaited
1314
note: required by a bound in `bar`
1415
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
1516
|
@@ -31,6 +32,7 @@ LL | bar(async_closure);
3132
| required by a bound introduced by this call
3233
|
3334
= 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]`
35+
= 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
3436
note: required by a bound in `bar`
3537
--> $DIR/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.rs:7:16
3638
|

0 commit comments

Comments
 (0)