diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 9c579209fe51c..c9578c2f50f90 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -593,7 +593,7 @@ impl<'hir> LoweringContext<'_, 'hir> { /// Desugar `.await` into: /// ```rust - /// match { + /// match ::std::future::IntoFuture::into_future() { /// 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 { + // `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 into_future_expr = self.expr_call_lang_item_fn( + into_future_span, + hir::LangItem::IntoFutureIntoFuture, + arena_vec![self; expr], + ); + + // match { // 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( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 2a246a99a7032..1a4f0a26f2bd5 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -162,6 +162,7 @@ struct LoweringContext<'a, 'hir: 'a> { allow_try_trait: Option>, allow_gen_future: Option>, + allow_into_future: Option>, } 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) } diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index 05659e976dd44..a03c561861e2b 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -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; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index dd6ce60abfb3d..06e4cee30ed81 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -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, diff --git a/library/core/src/future/future.rs b/library/core/src/future/future.rs index 09d8a2aac26e9..6b62236b32faf 100644 --- a/library/core/src/future/future.rs +++ b/library/core/src/future/future.rs @@ -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")] diff --git a/library/core/src/future/into_future.rs b/library/core/src/future/into_future.rs index 4020c254446e3..cac1866188eff 100644 --- a/library/core/src/future/into_future.rs +++ b/library/core/src/future/into_future.rs @@ -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; } diff --git a/src/test/ui/async-await/async-error-span.stderr b/src/test/ui/async-await/async-error-span.stderr index 994bfd33ba42e..2e3f8bb52560a 100644 --- a/src/test/ui/async-await/async-error-span.stderr +++ b/src/test/ui/async-await/async-error-span.stderr @@ -5,6 +5,7 @@ LL | fn get_future() -> impl Future { | ^^^^^^^^^^^^^^^^^^^^^^^^ `()` 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 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 636fafc2bc44a..a603ebd6e8547 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!(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())); } 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..b74b168444085 --- /dev/null +++ b/src/test/ui/async-await/await-into-future.rs @@ -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>>; + + 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()); +} diff --git a/src/test/ui/async-await/issue-70594.stderr b/src/test/ui/async-await/issue-70594.stderr index eb24040404b90..ab05251526b0d 100644 --- a/src/test/ui/async-await/issue-70594.stderr +++ b/src/test/ui/async-await/issue-70594.stderr @@ -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 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 e2ea72a1e6178..19d6f9bc43866 100644 --- a/src/test/ui/async-await/issues/issue-62009-1.stderr +++ b/src/test/ui/async-await/issues/issue-62009-1.stderr @@ -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 diff --git a/src/test/ui/async-await/unresolved_type_param.rs b/src/test/ui/async-await/unresolved_type_param.rs index d313691b38857..85d868c27032e 100644 --- a/src/test/ui/async-await/unresolved_type_param.rs +++ b/src/test/ui/async-await/unresolved_type_param.rs @@ -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` diff --git a/src/test/ui/async-await/unresolved_type_param.stderr b/src/test/ui/async-await/unresolved_type_param.stderr index 6b9e960ca1ae6..130667a49c53a 100644 --- a/src/test/ui/async-await/unresolved_type_param.stderr +++ b/src/test/ui/async-await/unresolved_type_param.stderr @@ -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`. diff --git a/src/test/ui/issues-71798.stderr b/src/test/ui/issues-71798.stderr index bbcdd3e37a96e..bc4dc9ebf9e00 100644 --- a/src/test/ui/issues-71798.stderr +++ b/src/test/ui/issues-71798.stderr @@ -11,6 +11,7 @@ LL | fn test_ref(x: &u32) -> impl std::future::Future + '_ { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `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 diff --git a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr index 4759ebea0e9b7..766db2a8356e7 100644 --- a/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr +++ b/src/test/ui/suggestions/async-fn-ctor-passed-as-arg-where-it-should-have-been-called.stderr @@ -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 {foo}` + = note: fn() -> impl Future {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 |