From 9f36f988ad873f5d34cd9c08e4903c597ffc9532 Mon Sep 17 00:00:00 2001 From: Arpad Borsos Date: Fri, 18 Nov 2022 22:56:22 +0100 Subject: [PATCH] Avoid `GenFuture` shim when compiling async constructs Previously, async constructs would be lowered to "normal" generators, with an additional `from_generator` / `GenFuture` shim in between to convert from `Generator` to `Future`. The compiler will now special-case these generators internally so that async constructs will *directly* implement `Future` without the need to go through the `from_generator` / `GenFuture` shim. The primary motivation for this change was hiding this implementation detail in stack traces and debuginfo, but it can in theory also help the optimizer as there is less abstractions to see through. --- compiler/rustc_ast_lowering/src/expr.rs | 36 ++++--- .../src/diagnostics/region_errors.rs | 15 ++- compiler/rustc_borrowck/src/type_check/mod.rs | 1 - .../src/transform/check_consts/check.rs | 21 ++-- compiler/rustc_hir/src/lang_items.rs | 6 +- compiler/rustc_hir_typeck/src/check.rs | 13 ++- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 8 -- compiler/rustc_lint/src/unused.rs | 15 ++- compiler/rustc_middle/src/traits/mod.rs | 20 ++++ compiler/rustc_middle/src/traits/select.rs | 4 + .../src/traits/structural_impls.rs | 12 +++ compiler/rustc_middle/src/ty/print/pretty.rs | 11 +++ compiler/rustc_mir_transform/src/generator.rs | 95 +++++++++++++------ compiler/rustc_resolve/src/late.rs | 2 +- compiler/rustc_span/src/symbol.rs | 3 +- .../src/traits/error_reporting/suggestions.rs | 33 +++---- .../src/traits/project.rs | 47 ++++++++- .../src/traits/select/candidate_assembly.rs | 28 +++++- .../src/traits/select/confirmation.rs | 60 +++++++++++- .../src/traits/select/mod.rs | 31 ++---- .../rustc_trait_selection/src/traits/util.rs | 11 +++ compiler/rustc_traits/src/chalk/lowering.rs | 6 +- compiler/rustc_ty_utils/src/instance.rs | 6 ++ library/core/src/future/mod.rs | 27 ++++-- library/core/src/task/poll.rs | 1 + .../codegen/async-fn-debug-awaitee-field.rs | 8 +- .../expected_show_coverage.async2.txt | 4 +- ...block-control-flow-static-semantics.stderr | 6 +- ...async-borrowck-escaping-block-error.stderr | 20 ++-- src/test/ui/async-await/generator-desc.stderr | 32 +++---- .../issue-68112.drop_tracking.stderr | 4 +- .../issue-68112.no_drop_tracking.stderr | 4 +- ...e-70935-complex-spans.drop_tracking.stderr | 5 +- .../issues/issue-78938-async-block.stderr | 4 +- .../async-await/try-on-option-in-async.stderr | 3 +- src/test/ui/chalkify/bugs/async.stderr | 39 +++++--- .../freeze_cycle.rs | 2 +- .../expected-boxed-future-isnt-pinned.stderr | 23 ++--- src/tools/clippy/clippy_lints/src/doc.rs | 4 +- .../clippy_lints/src/manual_async_fn.rs | 2 +- .../clippy/tests/ui/author/blocks.stdout | 2 +- 41 files changed, 461 insertions(+), 213 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index a00100ee0a845..b222ef4a88924 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -149,7 +149,7 @@ impl<'hir> LoweringContext<'_, 'hir> { *capture_clause, *closure_node_id, None, - block.span, + e.span, hir::AsyncGeneratorKind::Block, |this| this.with_new_scopes(|this| this.lower_block_expr(block)), ), @@ -569,12 +569,12 @@ impl<'hir> LoweringContext<'_, 'hir> { } } - /// Lower an `async` construct to a generator that is then wrapped so it implements `Future`. + /// Lower an `async` construct to a generator that implements `Future`. /// /// This results in: /// /// ```text - /// std::future::from_generator(static move? |_task_context| -> { + /// std::future::identity_future(static move? |_task_context| -> { /// /// }) /// ``` @@ -589,12 +589,14 @@ impl<'hir> LoweringContext<'_, 'hir> { ) -> hir::ExprKind<'hir> { let output = ret_ty.unwrap_or_else(|| hir::FnRetTy::DefaultReturn(self.lower_span(span))); - // Resume argument type. We let the compiler infer this to simplify the lowering. It is - // fully constrained by `future::from_generator`. + // Resume argument type: `ResumeTy` + let unstable_span = + self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); + let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None); let input_ty = hir::Ty { hir_id: self.next_id(), - kind: hir::TyKind::Infer, - span: self.lower_span(span), + kind: hir::TyKind::Path(resume_ty), + span: unstable_span, }; // The closure/generator `FnDecl` takes a single (resume) argument of type `input_ty`. @@ -677,16 +679,24 @@ impl<'hir> LoweringContext<'_, 'hir> { let generator = hir::Expr { hir_id, kind: generator_kind, span: self.lower_span(span) }; - // `future::from_generator`: - let gen_future = self.expr_lang_item_path( + // FIXME(swatinem): + // For some reason, the async block needs to flow through *any* + // call (like the identity function), as otherwise type and lifetime + // inference have a hard time figuring things out. + // Without this, we would get: + // E0720 in src/test/ui/impl-trait/in-trait/default-body-with-rpit.rs + // E0700 in src/test/ui/self/self_lifetime-async.rs + + // `future::identity_future`: + let identity_future = self.expr_lang_item_path( unstable_span, - hir::LangItem::FromGenerator, + hir::LangItem::IdentityFuture, AttrVec::new(), None, ); - // `future::from_generator(generator)`: - hir::ExprKind::Call(self.arena.alloc(gen_future), arena_vec![self; generator]) + // `future::identity_future(generator)`: + hir::ExprKind::Call(self.arena.alloc(identity_future), arena_vec![self; generator]) } /// Desugar `.await` into: @@ -990,7 +1000,7 @@ impl<'hir> LoweringContext<'_, 'hir> { } // Transform `async |x: u8| -> X { ... }` into - // `|x: u8| future_from_generator(|| -> X { ... })`. + // `|x: u8| identity_future(|| -> X { ... })`. let body_id = this.lower_fn_body(&outer_decl, |this| { let async_ret_ty = if let FnRetTy::Ty(ty) = &decl.output { let itctx = ImplTraitContext::Disallowed(ImplTraitPosition::AsyncBlock); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 76f249dac5181..534675f1dc042 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -21,7 +21,7 @@ use rustc_middle::ty::subst::InternalSubsts; use rustc_middle::ty::Region; use rustc_middle::ty::TypeVisitor; use rustc_middle::ty::{self, RegionVid, Ty}; -use rustc_span::symbol::{kw, sym, Ident}; +use rustc_span::symbol::{kw, Ident}; use rustc_span::Span; use crate::borrowck_errors; @@ -514,8 +514,11 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { span: *span, ty_err: match output_ty.kind() { ty::Closure(_, _) => FnMutReturnTypeErr::ReturnClosure { span: *span }, - ty::Adt(def, _) - if self.infcx.tcx.is_diagnostic_item(sym::gen_future, def.did()) => + ty::Generator(def, ..) + if matches!( + self.infcx.tcx.generator_kind(def), + Some(hir::GeneratorKind::Async(_)) + ) => { FnMutReturnTypeErr::ReturnAsyncBlock { span: *span } } @@ -927,10 +930,14 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { // only when the block is a closure if let hir::ExprKind::Closure(hir::Closure { capture_clause: hir::CaptureBy::Ref, + body, .. }) = expr.kind { - closure_span = Some(expr.span.shrink_to_lo()); + let body = map.body(*body); + if !matches!(body.generator_kind, Some(hir::GeneratorKind::Async(..))) { + closure_span = Some(expr.span.shrink_to_lo()); + } } } } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 7467212bed883..b268eac97d0b0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2588,7 +2588,6 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { } // For closures, we have some **extra requirements** we - // // have to check. In particular, in their upvars and // signatures, closures often reference various regions // from the surrounding function -- we call those the diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 36956f5dd6d96..4564a6c4f2f4e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -449,8 +449,17 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { | Rvalue::CopyForDeref(..) | Rvalue::Repeat(..) | Rvalue::Discriminant(..) - | Rvalue::Len(_) - | Rvalue::Aggregate(..) => {} + | Rvalue::Len(_) => {} + + Rvalue::Aggregate(ref kind, ..) => { + if let AggregateKind::Generator(def_id, ..) = kind.as_ref() { + if let Some(generator_kind) = self.tcx.generator_kind(def_id.to_def_id()) { + if matches!(generator_kind, hir::GeneratorKind::Async(..)) { + self.check_op(ops::Generator(generator_kind)); + } + } + } + } Rvalue::Ref(_, kind @ BorrowKind::Mut { .. }, ref place) | Rvalue::Ref(_, kind @ BorrowKind::Unique, ref place) => { @@ -889,14 +898,6 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> { return; } - // `async` blocks get lowered to `std::future::from_generator(/* a closure */)`. - let is_async_block = Some(callee) == tcx.lang_items().from_generator_fn(); - if is_async_block { - let kind = hir::GeneratorKind::Async(hir::AsyncGeneratorKind::Block); - self.check_op(ops::Generator(kind)); - return; - } - if !tcx.is_const_fn_raw(callee) { if !tcx.is_const_default_method(callee) { // To get to here we must have already found a const impl for the diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b68dd25996b11..038509031b180 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -280,10 +280,14 @@ language_item_table! { PointerSized, sym::pointer_sized, pointer_sized, Target::Trait, GenericRequirement::Exact(0); + Poll, sym::Poll, poll, Target::Enum, GenericRequirement::None; PollReady, sym::Ready, poll_ready_variant, Target::Variant, GenericRequirement::None; PollPending, sym::Pending, poll_pending_variant, Target::Variant, GenericRequirement::None; - FromGenerator, sym::from_generator, from_generator_fn, Target::Fn, GenericRequirement::None; + // FIXME(swatinem): the following lang items are used for async lowering and + // should become obsolete eventually. + ResumeTy, sym::ResumeTy, resume_ty, Target::Struct, GenericRequirement::None; + IdentityFuture, sym::identity_future, identity_future_fn, Target::Fn, GenericRequirement::None; GetContext, sym::get_context, get_context_fn, Target::Fn, GenericRequirement::None; FuturePoll, sym::poll, future_poll_fn, Target::Method(MethodKind::Trait { body: false }), GenericRequirement::None; diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index b9e90e47e508b..2c24b9ef14e85 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -56,10 +56,15 @@ pub(super) fn check_fn<'a, 'tcx>( fn_maybe_err(tcx, span, fn_sig.abi); - if body.generator_kind.is_some() && can_be_generator.is_some() { - let yield_ty = fcx - .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); - fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + if let Some(kind) = body.generator_kind && can_be_generator.is_some() { + let yield_ty = if kind == hir::GeneratorKind::Gen { + let yield_ty = fcx + .next_ty_var(TypeVariableOrigin { kind: TypeVariableOriginKind::TypeInference, span }); + fcx.require_type_is_sized(yield_ty, span, traits::SizedYieldType); + yield_ty + } else { + tcx.mk_unit() + }; // Resume type defaults to `()` if the generator has no argument. let resume_ty = fn_sig.inputs().get(0).copied().unwrap_or_else(|| tcx.mk_unit()); diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a31ab9c8b23b8..5727a120390d4 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1734,14 +1734,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let hir = self.tcx.hir(); let hir::Node::Expr(expr) = hir.get(hir_id) else { return false; }; - // Skip over mentioning async lang item - if Some(def_id) == self.tcx.lang_items().from_generator_fn() - && error.obligation.cause.span.desugaring_kind() - == Some(rustc_span::DesugaringKind::Async) - { - return false; - } - let Some(unsubstituted_pred) = self.tcx.predicates_of(def_id).instantiate_identity(self.tcx).predicates.into_iter().nth(idx) else { return false; }; diff --git a/compiler/rustc_lint/src/unused.rs b/compiler/rustc_lint/src/unused.rs index 0471890230aa6..d6a01b4254831 100644 --- a/compiler/rustc_lint/src/unused.rs +++ b/compiler/rustc_lint/src/unused.rs @@ -319,7 +319,20 @@ impl<'tcx> LateLintPass<'tcx> for UnusedResults { .map(|inner| MustUsePath::Array(Box::new(inner), len)), }, ty::Closure(..) => Some(MustUsePath::Closure(span)), - ty::Generator(..) => Some(MustUsePath::Generator(span)), + ty::Generator(def_id, ..) => { + // async fn should be treated as "implementor of `Future`" + let must_use = if matches!( + cx.tcx.generator_kind(def_id), + Some(hir::GeneratorKind::Async(..)) + ) { + let def_id = cx.tcx.lang_items().future_trait().unwrap(); + is_def_must_use(cx, def_id, span) + .map(|inner| MustUsePath::Opaque(Box::new(inner))) + } else { + None + }; + must_use.or(Some(MustUsePath::Generator(span))) + } _ => None, } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1890c0e24bb44..536d2872bf084 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -660,6 +660,9 @@ pub enum ImplSource<'tcx, N> { /// ImplSource automatically generated for a generator. Generator(ImplSourceGeneratorData<'tcx, N>), + /// ImplSource automatically generated for a generator backing an async future. + Future(ImplSourceFutureData<'tcx, N>), + /// ImplSource for a trait alias. TraitAlias(ImplSourceTraitAliasData<'tcx, N>), @@ -676,6 +679,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::AutoImpl(d) => d.nested, ImplSource::Closure(c) => c.nested, ImplSource::Generator(c) => c.nested, + ImplSource::Future(c) => c.nested, ImplSource::Object(d) => d.nested, ImplSource::FnPointer(d) => d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) @@ -694,6 +698,7 @@ impl<'tcx, N> ImplSource<'tcx, N> { ImplSource::AutoImpl(d) => &d.nested, ImplSource::Closure(c) => &c.nested, ImplSource::Generator(c) => &c.nested, + ImplSource::Future(c) => &c.nested, ImplSource::Object(d) => &d.nested, ImplSource::FnPointer(d) => &d.nested, ImplSource::DiscriminantKind(ImplSourceDiscriminantKindData) @@ -737,6 +742,11 @@ impl<'tcx, N> ImplSource<'tcx, N> { substs: c.substs, nested: c.nested.into_iter().map(f).collect(), }), + ImplSource::Future(c) => ImplSource::Future(ImplSourceFutureData { + generator_def_id: c.generator_def_id, + substs: c.substs, + nested: c.nested.into_iter().map(f).collect(), + }), ImplSource::FnPointer(p) => ImplSource::FnPointer(ImplSourceFnPointerData { fn_ty: p.fn_ty, nested: p.nested.into_iter().map(f).collect(), @@ -796,6 +806,16 @@ pub struct ImplSourceGeneratorData<'tcx, N> { pub nested: Vec, } +#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] +#[derive(TypeFoldable, TypeVisitable)] +pub struct ImplSourceFutureData<'tcx, N> { + pub generator_def_id: DefId, + pub substs: SubstsRef<'tcx>, + /// Nested obligations. This can be non-empty if the generator + /// signature contains associated types. + pub nested: Vec, +} + #[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)] #[derive(TypeFoldable, TypeVisitable)] pub struct ImplSourceClosureData<'tcx, N> { diff --git a/compiler/rustc_middle/src/traits/select.rs b/compiler/rustc_middle/src/traits/select.rs index 85ead3171e785..99bfa477f74e8 100644 --- a/compiler/rustc_middle/src/traits/select.rs +++ b/compiler/rustc_middle/src/traits/select.rs @@ -131,6 +131,10 @@ pub enum SelectionCandidate<'tcx> { /// generated for a generator. GeneratorCandidate, + /// Implementation of a `Future` trait by one of the generator types + /// generated for an async construct. + FutureCandidate, + /// Implementation of a `Fn`-family trait by one of the anonymous /// types generated for a fn pointer type (e.g., `fn(int) -> int`) FnPointerCandidate { diff --git a/compiler/rustc_middle/src/traits/structural_impls.rs b/compiler/rustc_middle/src/traits/structural_impls.rs index 7fbd57ac7354a..735cece83997a 100644 --- a/compiler/rustc_middle/src/traits/structural_impls.rs +++ b/compiler/rustc_middle/src/traits/structural_impls.rs @@ -15,6 +15,8 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSource<'tcx, N> { super::ImplSource::Generator(ref d) => write!(f, "{:?}", d), + super::ImplSource::Future(ref d) => write!(f, "{:?}", d), + super::ImplSource::FnPointer(ref d) => write!(f, "({:?})", d), super::ImplSource::DiscriminantKind(ref d) => write!(f, "{:?}", d), @@ -58,6 +60,16 @@ impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceGeneratorData<'tcx, N } } +impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceFutureData<'tcx, N> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!( + f, + "ImplSourceFutureData(generator_def_id={:?}, substs={:?}, nested={:?})", + self.generator_def_id, self.substs, self.nested + ) + } +} + impl<'tcx, N: fmt::Debug> fmt::Debug for traits::ImplSourceClosureData<'tcx, N> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index bddcdd0b693ca..c54edf10c2d8f 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -681,6 +681,17 @@ pub trait PrettyPrinter<'tcx>: } ty::Str => p!("str"), ty::Generator(did, substs, movability) => { + // FIXME(swatinem): async constructs used to be pretty printed + // as `impl Future` previously due to the `from_generator` wrapping. + // lets special case this here for now to avoid churn in diagnostics. + let generator_kind = self.tcx().generator_kind(did); + if matches!(generator_kind, Some(hir::GeneratorKind::Async(..))) { + let return_ty = substs.as_generator().return_ty(); + p!(write("impl Future", return_ty)); + + return Ok(self); + } + p!(write("[")); match movability { hir::Movability::Movable => {} diff --git a/compiler/rustc_mir_transform/src/generator.rs b/compiler/rustc_mir_transform/src/generator.rs index fcd63b6cfa178..ffe4d43bc88e8 100644 --- a/compiler/rustc_mir_transform/src/generator.rs +++ b/compiler/rustc_mir_transform/src/generator.rs @@ -11,10 +11,10 @@ //! generator in the MIR, since it is used to create the drop glue for the generator. We'd get //! infinite recursion otherwise. //! -//! This pass creates the implementation for the Generator::resume function and the drop shim -//! for the generator based on the MIR input. It converts the generator argument from Self to -//! &mut Self adding derefs in the MIR as needed. It computes the final layout of the generator -//! struct which looks like this: +//! This pass creates the implementation for either the `Generator::resume` or `Future::poll` +//! function and the drop shim for the generator based on the MIR input. +//! It converts the generator argument from Self to &mut Self adding derefs in the MIR as needed. +//! It computes the final layout of the generator struct which looks like this: //! First upvars are stored //! It is followed by the generator state field. //! Then finally the MIR locals which are live across a suspension point are stored. @@ -32,14 +32,15 @@ //! 2 - Generator has been poisoned //! //! It also rewrites `return x` and `yield y` as setting a new generator state and returning -//! GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. +//! `GeneratorState::Complete(x)` and `GeneratorState::Yielded(y)`, +//! or `Poll::Ready(x)` and `Poll::Pending` respectively. //! MIR locals which are live across a suspension point are moved to the generator struct //! with references to them being updated with references to the generator struct. //! //! The pass creates two functions which have a switch on the generator state giving //! the action to take. //! -//! One of them is the implementation of Generator::resume. +//! One of them is the implementation of `Generator::resume` / `Future::poll`. //! For generators with state 0 (unresumed) it starts the execution of the generator. //! For generators with state 1 (returned) and state 2 (poisoned) it panics. //! Otherwise it continues the execution from the last suspension point. @@ -56,6 +57,7 @@ use crate::MirPass; use rustc_data_structures::fx::FxHashMap; use rustc_hir as hir; use rustc_hir::lang_items::LangItem; +use rustc_hir::GeneratorKind; use rustc_index::bit_set::{BitMatrix, BitSet, GrowableBitSet}; use rustc_index::vec::{Idx, IndexVec}; use rustc_middle::mir::dump_mir; @@ -215,6 +217,7 @@ struct SuspensionPoint<'tcx> { struct TransformVisitor<'tcx> { tcx: TyCtxt<'tcx>, + is_async_kind: bool, state_adt_ref: AdtDef<'tcx>, state_substs: SubstsRef<'tcx>, @@ -239,28 +242,57 @@ struct TransformVisitor<'tcx> { } impl<'tcx> TransformVisitor<'tcx> { - // Make a GeneratorState variant assignment. `core::ops::GeneratorState` only has single - // element tuple variants, so we can just write to the downcasted first field and then set the + // Make a `GeneratorState` or `Poll` variant assignment. + // + // `core::ops::GeneratorState` only has single element tuple variants, + // so we can just write to the downcasted first field and then set the // discriminant to the appropriate variant. fn make_state( &self, - idx: VariantIdx, val: Operand<'tcx>, source_info: SourceInfo, - ) -> impl Iterator> { + is_return: bool, + statements: &mut Vec>, + ) { + let idx = VariantIdx::new(match (is_return, self.is_async_kind) { + (true, false) => 1, // GeneratorState::Complete + (false, false) => 0, // GeneratorState::Yielded + (true, true) => 0, // Poll::Ready + (false, true) => 1, // Poll::Pending + }); + let kind = AggregateKind::Adt(self.state_adt_ref.did(), idx, self.state_substs, None, None); + + // `Poll::Pending` + if self.is_async_kind && idx == VariantIdx::new(1) { + assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 0); + + // FIXME(swatinem): assert that `val` is indeed unit? + statements.extend(expand_aggregate( + Place::return_place(), + std::iter::empty(), + kind, + source_info, + self.tcx, + )); + return; + } + + // else: `Poll::Ready(x)`, `GeneratorState::Yielded(x)` or `GeneratorState::Complete(x)` assert_eq!(self.state_adt_ref.variant(idx).fields.len(), 1); + let ty = self .tcx .bound_type_of(self.state_adt_ref.variant(idx).fields[0].did) .subst(self.tcx, self.state_substs); - expand_aggregate( + + statements.extend(expand_aggregate( Place::return_place(), std::iter::once((val, ty)), kind, source_info, self.tcx, - ) + )); } // Create a Place referencing a generator struct field @@ -331,22 +363,19 @@ impl<'tcx> MutVisitor<'tcx> for TransformVisitor<'tcx> { }); let ret_val = match data.terminator().kind { - TerminatorKind::Return => Some(( - VariantIdx::new(1), - None, - Operand::Move(Place::from(self.new_ret_local)), - None, - )), + TerminatorKind::Return => { + Some((true, None, Operand::Move(Place::from(self.new_ret_local)), None)) + } TerminatorKind::Yield { ref value, resume, resume_arg, drop } => { - Some((VariantIdx::new(0), Some((resume, resume_arg)), value.clone(), drop)) + Some((false, Some((resume, resume_arg)), value.clone(), drop)) } _ => None, }; - if let Some((state_idx, resume, v, drop)) = ret_val { + if let Some((is_return, resume, v, drop)) = ret_val { let source_info = data.terminator().source_info; // We must assign the value first in case it gets declared dead below - data.statements.extend(self.make_state(state_idx, v, source_info)); + self.make_state(v, source_info, is_return, &mut data.statements); let state = if let Some((resume, mut resume_arg)) = resume { // Yield let state = RESERVED_VARIANTS + self.suspension_points.len(); @@ -1268,10 +1297,20 @@ impl<'tcx> MirPass<'tcx> for StateTransform { } }; - // Compute GeneratorState - let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); - let state_adt_ref = tcx.adt_def(state_did); - let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]); + let is_async_kind = body.generator_kind().unwrap() != GeneratorKind::Gen; + let (state_adt_ref, state_substs) = if is_async_kind { + // Compute Poll + let state_did = tcx.require_lang_item(LangItem::Poll, None); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.intern_substs(&[body.return_ty().into()]); + (state_adt_ref, state_substs) + } else { + // Compute GeneratorState + let state_did = tcx.require_lang_item(LangItem::GeneratorState, None); + let state_adt_ref = tcx.adt_def(state_did); + let state_substs = tcx.intern_substs(&[yield_ty.into(), body.return_ty().into()]); + (state_adt_ref, state_substs) + }; let ret_ty = tcx.mk_adt(state_adt_ref, state_substs); // We rename RETURN_PLACE which has type mir.return_ty to new_ret_local @@ -1327,9 +1366,11 @@ impl<'tcx> MirPass<'tcx> for StateTransform { // Run the transformation which converts Places from Local to generator struct // accesses for locals in `remap`. // It also rewrites `return x` and `yield y` as writing a new generator state and returning - // GeneratorState::Complete(x) and GeneratorState::Yielded(y) respectively. + // either GeneratorState::Complete(x) and GeneratorState::Yielded(y), + // or Poll::Ready(x) and Poll::Pending respectively depending on `is_async_kind`. let mut transform = TransformVisitor { tcx, + is_async_kind, state_adt_ref, state_substs, remap, @@ -1367,7 +1408,7 @@ impl<'tcx> MirPass<'tcx> for StateTransform { body.generator.as_mut().unwrap().generator_drop = Some(drop_shim); - // Create the Generator::resume function + // Create the Generator::resume / Future::poll function create_generator_resume_function(tcx, transform, body, can_return); // Run derefer to fix Derefs that are not in the first place diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 5072d2aad1669..2cc3e410d206f 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3912,7 +3912,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> { visit::walk_expr(self, expr); self.diagnostic_metadata.current_type_ascription.pop(); } - // `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to + // `async |x| ...` gets desugared to `|x| async {...}`, so we need to // resolve the arguments within the proper scopes so that usages of them inside the // closure are detected as upvars rather than normal closure arg usages. ExprKind::Closure(box ast::Closure { diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index 29312a21b4d46..aba301dce1098 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -264,6 +264,7 @@ symbols! { Relaxed, Release, Result, + ResumeTy, Return, Right, Rust, @@ -728,7 +729,6 @@ symbols! { frem_fast, from, from_desugaring, - from_generator, from_iter, from_method, from_output, @@ -779,6 +779,7 @@ symbols! { i64, i8, ident, + identity_future, if_let, if_let_guard, if_while_or_patterns, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index bb6d7d0e8dff1..30207033236c5 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1885,13 +1885,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // // - `BuiltinDerivedObligation` with a generator witness (B) // - `BuiltinDerivedObligation` with a generator (B) - // - `BuiltinDerivedObligation` with `std::future::GenFuture` (B) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) // - `BuiltinDerivedObligation` with `impl std::future::Future` (B) // - `BuiltinDerivedObligation` with a generator witness (A) // - `BuiltinDerivedObligation` with a generator (A) - // - `BuiltinDerivedObligation` with `std::future::GenFuture` (A) - // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) // - `BuiltinDerivedObligation` with `impl std::future::Future` (A) // - `BindingObligation` with `impl_send (Send requirement) // @@ -2624,30 +2620,24 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { } }; - let from_generator = tcx.require_lang_item(LangItem::FromGenerator, None); + let identity_future = tcx.require_lang_item(LangItem::IdentityFuture, None); // Don't print the tuple of capture types 'print: { if !is_upvar_tys_infer_tuple { let msg = format!("required because it appears within the type `{}`", ty); match ty.kind() { - ty::Adt(def, _) => { - // `gen_future` is used in all async functions; it doesn't add any additional info. - if self.tcx.is_diagnostic_item(sym::gen_future, def.did()) { - break 'print; - } - match self.tcx.opt_item_ident(def.did()) { - Some(ident) => err.span_note(ident.span, &msg), - None => err.note(&msg), - } - } + ty::Adt(def, _) => match self.tcx.opt_item_ident(def.did()) { + Some(ident) => err.span_note(ident.span, &msg), + None => err.note(&msg), + }, ty::Opaque(def_id, _) => { - // Avoid printing the future from `core::future::from_generator`, it's not helpful - if tcx.parent(*def_id) == from_generator { + // Avoid printing the future from `core::future::identity_future`, it's not helpful + if tcx.parent(*def_id) == identity_future { break 'print; } - // If the previous type is `from_generator`, this is the future generated by the body of an async function. + // If the previous type is `identity_future`, this is the future generated by the body of an async function. // Avoid printing it twice (it was already printed in the `ty::Generator` arm below). let is_future = tcx.ty_is_opaque_future(ty); debug!( @@ -2657,8 +2647,11 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ); if is_future && obligated_types.last().map_or(false, |ty| match ty.kind() { - ty::Opaque(last_def_id, _) => { - tcx.parent(*last_def_id) == from_generator + ty::Generator(last_def_id, ..) => { + matches!( + tcx.generator_kind(last_def_id), + Some(GeneratorKind::Async(..)) + ) } _ => false, }) diff --git a/compiler/rustc_trait_selection/src/traits/project.rs b/compiler/rustc_trait_selection/src/traits/project.rs index 7b2329b1ddd60..f17d702d421bd 100644 --- a/compiler/rustc_trait_selection/src/traits/project.rs +++ b/compiler/rustc_trait_selection/src/traits/project.rs @@ -12,7 +12,8 @@ use super::SelectionContext; use super::SelectionError; use super::{ ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, - ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData, + ImplSourceFutureData, ImplSourceGeneratorData, ImplSourcePointeeData, + ImplSourceUserDefinedData, }; use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey}; @@ -1544,6 +1545,7 @@ fn assemble_candidates_from_impls<'cx, 'tcx>( let eligible = match &impl_source { super::ImplSource::Closure(_) | super::ImplSource::Generator(_) + | super::ImplSource::Future(_) | super::ImplSource::FnPointer(_) | super::ImplSource::TraitAlias(_) => true, super::ImplSource::UserDefined(impl_data) => { @@ -1832,6 +1834,7 @@ fn confirm_select_candidate<'cx, 'tcx>( match impl_source { super::ImplSource::UserDefined(data) => confirm_impl_candidate(selcx, obligation, data), super::ImplSource::Generator(data) => confirm_generator_candidate(selcx, obligation, data), + super::ImplSource::Future(data) => confirm_future_candidate(selcx, obligation, data), super::ImplSource::Closure(data) => confirm_closure_candidate(selcx, obligation, data), super::ImplSource::FnPointer(data) => confirm_fn_pointer_candidate(selcx, obligation, data), super::ImplSource::DiscriminantKind(data) => { @@ -1905,6 +1908,48 @@ fn confirm_generator_candidate<'cx, 'tcx>( .with_addl_obligations(obligations) } +fn confirm_future_candidate<'cx, 'tcx>( + selcx: &mut SelectionContext<'cx, 'tcx>, + obligation: &ProjectionTyObligation<'tcx>, + impl_source: ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>, +) -> Progress<'tcx> { + let gen_sig = impl_source.substs.as_generator().poly_sig(); + let Normalized { value: gen_sig, obligations } = normalize_with_depth( + selcx, + obligation.param_env, + obligation.cause.clone(), + obligation.recursion_depth + 1, + gen_sig, + ); + + debug!(?obligation, ?gen_sig, ?obligations, "confirm_future_candidate"); + + let tcx = selcx.tcx(); + let fut_def_id = tcx.require_lang_item(LangItem::Future, None); + + let predicate = super::util::future_trait_ref_and_outputs( + tcx, + fut_def_id, + obligation.predicate.self_ty(), + gen_sig, + ) + .map_bound(|(trait_ref, return_ty)| { + debug_assert_eq!(tcx.associated_item(obligation.predicate.item_def_id).name, sym::Output); + + ty::ProjectionPredicate { + projection_ty: ty::ProjectionTy { + substs: trait_ref.substs, + item_def_id: obligation.predicate.item_def_id, + }, + term: return_ty.into(), + } + }); + + confirm_param_env_candidate(selcx, obligation, predicate, false) + .with_addl_obligations(impl_source.nested) + .with_addl_obligations(obligations) +} + fn confirm_discriminant_kind_candidate<'cx, 'tcx>( selcx: &mut SelectionContext<'cx, 'tcx>, obligation: &ProjectionTyObligation<'tcx>, diff --git a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs index 3b107d9570f14..617dbe240e94a 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -314,7 +314,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates); } - self.assemble_generator_candidates(obligation, &mut candidates); + if lang_items.gen_trait() == Some(def_id) { + self.assemble_generator_candidates(obligation, &mut candidates); + } else if lang_items.future_trait() == Some(def_id) { + self.assemble_future_candidates(obligation, &mut candidates); + } + self.assemble_closure_candidates(obligation, &mut candidates); self.assemble_fn_pointer_candidates(obligation, &mut candidates); self.assemble_candidates_from_impls(obligation, &mut candidates); @@ -402,10 +407,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { obligation: &TraitObligation<'tcx>, candidates: &mut SelectionCandidateSet<'tcx>, ) { - if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) { - return; - } - // Okay to skip binder because the substs on generator types never // touch bound regions, they just capture the in-scope // type/region parameters. @@ -424,6 +425,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { } } + fn assemble_future_candidates( + &mut self, + obligation: &TraitObligation<'tcx>, + candidates: &mut SelectionCandidateSet<'tcx>, + ) { + let self_ty = obligation.self_ty().skip_binder(); + if let ty::Generator(did, ..) = self_ty.kind() { + if let Some(rustc_hir::GeneratorKind::Async(_generator_kind)) = + self.tcx().generator_kind(did) + { + debug!(?self_ty, ?obligation, "assemble_future_candidates",); + + candidates.vec.push(FutureCandidate); + } + } + } + /// Checks for the artificial impl that the compiler will create for an obligation like `X : /// FnMut<..>` where `X` is a closure type. /// diff --git a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs index 2ec5d925b6900..4a90d8baf9e44 100644 --- a/compiler/rustc_trait_selection/src/traits/select/confirmation.rs +++ b/compiler/rustc_trait_selection/src/traits/select/confirmation.rs @@ -23,10 +23,11 @@ use crate::traits::{ BuiltinDerivedObligation, ImplDerivedObligation, ImplDerivedObligationCause, ImplSource, ImplSourceAutoImplData, ImplSourceBuiltinData, ImplSourceClosureData, ImplSourceConstDestructData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData, - ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, ImplSourceTraitAliasData, - ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, ObjectCastObligation, - Obligation, ObligationCause, OutputTypeParameterMismatch, PredicateObligation, Selection, - SelectionError, TraitNotObjectSafe, TraitObligation, Unimplemented, VtblSegment, + ImplSourceFutureData, ImplSourceGeneratorData, ImplSourceObjectData, ImplSourcePointeeData, + ImplSourceTraitAliasData, ImplSourceTraitUpcastingData, ImplSourceUserDefinedData, Normalized, + ObjectCastObligation, Obligation, ObligationCause, OutputTypeParameterMismatch, + PredicateObligation, Selection, SelectionError, TraitNotObjectSafe, TraitObligation, + Unimplemented, VtblSegment, }; use super::BuiltinImplConditions; @@ -89,6 +90,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplSource::Generator(vtable_generator) } + FutureCandidate => { + let vtable_future = self.confirm_future_candidate(obligation)?; + ImplSource::Future(vtable_future) + } + FnPointerCandidate { .. } => { let data = self.confirm_fn_pointer_candidate(obligation)?; ImplSource::FnPointer(data) @@ -685,7 +691,21 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { debug!(?obligation, ?generator_def_id, ?substs, "confirm_generator_candidate"); - let trait_ref = self.generator_trait_ref_unnormalized(obligation, substs); + let gen_sig = substs.as_generator().poly_sig(); + + // (1) Feels icky to skip the binder here, but OTOH we know + // that the self-type is an generator type and hence is + // in fact unparameterized (or at least does not reference any + // regions bound in the obligation). Still probably some + // refactoring could make this nicer. + + let trait_ref = super::util::generator_trait_ref_and_outputs( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.skip_binder().self_ty(), // (1) + gen_sig, + ) + .map_bound(|(trait_ref, ..)| trait_ref); let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; debug!(?trait_ref, ?nested, "generator candidate obligations"); @@ -693,6 +713,36 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { Ok(ImplSourceGeneratorData { generator_def_id, substs, nested }) } + fn confirm_future_candidate( + &mut self, + obligation: &TraitObligation<'tcx>, + ) -> Result>, SelectionError<'tcx>> { + // Okay to skip binder because the substs on generator types never + // touch bound regions, they just capture the in-scope + // type/region parameters. + let self_ty = self.infcx.shallow_resolve(obligation.self_ty().skip_binder()); + let ty::Generator(generator_def_id, substs, _) = *self_ty.kind() else { + bug!("closure candidate for non-closure {:?}", obligation); + }; + + debug!(?obligation, ?generator_def_id, ?substs, "confirm_future_candidate"); + + let gen_sig = substs.as_generator().poly_sig(); + + let trait_ref = super::util::future_trait_ref_and_outputs( + self.tcx(), + obligation.predicate.def_id(), + obligation.predicate.no_bound_vars().expect("future has no bound vars").self_ty(), + gen_sig, + ) + .map_bound(|(trait_ref, ..)| trait_ref); + + let nested = self.confirm_poly_trait_refs(obligation, trait_ref)?; + debug!(?trait_ref, ?nested, "future candidate obligations"); + + Ok(ImplSourceFutureData { generator_def_id, substs, nested }) + } + #[instrument(skip(self), level = "debug")] fn confirm_closure_candidate( &mut self, diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index 2803a2d38c807..9fe13fe296a16 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -1139,9 +1139,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ProjectionCandidate(_, ty::BoundConstness::ConstIfConst) => {} // auto trait impl AutoImplCandidate => {} - // generator, this will raise error in other places + // generator / future, this will raise error in other places // or ignore error with const_async_blocks feature GeneratorCandidate => {} + FutureCandidate => {} // FnDef where the function is const FnPointerCandidate { is_const: true } => {} ConstDestructCandidate(_) => {} @@ -1620,6 +1621,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(..) | ClosureCandidate | GeneratorCandidate + | FutureCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1638,6 +1640,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(_) | ClosureCandidate | GeneratorCandidate + | FutureCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1668,6 +1671,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(..) | ClosureCandidate | GeneratorCandidate + | FutureCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1680,6 +1684,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(..) | ClosureCandidate | GeneratorCandidate + | FutureCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1761,6 +1766,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(_) | ClosureCandidate | GeneratorCandidate + | FutureCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -1770,6 +1776,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ImplCandidate(_) | ClosureCandidate | GeneratorCandidate + | FutureCandidate | FnPointerCandidate { .. } | BuiltinObjectCandidate | BuiltinUnsizeCandidate @@ -2279,28 +2286,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { .map_bound(|(trait_ref, _)| trait_ref) } - fn generator_trait_ref_unnormalized( - &mut self, - obligation: &TraitObligation<'tcx>, - substs: SubstsRef<'tcx>, - ) -> ty::PolyTraitRef<'tcx> { - let gen_sig = substs.as_generator().poly_sig(); - - // (1) Feels icky to skip the binder here, but OTOH we know - // that the self-type is an generator type and hence is - // in fact unparameterized (or at least does not reference any - // regions bound in the obligation). Still probably some - // refactoring could make this nicer. - - super::util::generator_trait_ref_and_outputs( - self.tcx(), - obligation.predicate.def_id(), - obligation.predicate.skip_binder().self_ty(), // (1) - gen_sig, - ) - .map_bound(|(trait_ref, ..)| trait_ref) - } - /// Returns the obligations that are implied by instantiating an /// impl or trait. The obligations are substituted and fully /// normalized. This is used when confirming an impl or default diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index 895b84fd7e9df..20d8a7a742c3a 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -318,6 +318,17 @@ pub fn generator_trait_ref_and_outputs<'tcx>( sig.map_bound(|sig| (trait_ref, sig.yield_ty, sig.return_ty)) } +pub fn future_trait_ref_and_outputs<'tcx>( + tcx: TyCtxt<'tcx>, + fn_trait_def_id: DefId, + self_ty: Ty<'tcx>, + sig: ty::PolyGenSig<'tcx>, +) -> ty::Binder<'tcx, (ty::TraitRef<'tcx>, Ty<'tcx>)> { + debug_assert!(!self_ty.has_escaping_bound_vars()); + let trait_ref = tcx.mk_trait_ref(fn_trait_def_id, [self_ty]); + sig.map_bound(|sig| (trait_ref, sig.return_ty)) +} + pub fn impl_item_is_final(tcx: TyCtxt<'_>, assoc_item: &ty::AssocItem) -> bool { assoc_item.defaultness(tcx).is_final() && tcx.impl_defaultness(assoc_item.container_id(tcx)).is_final() diff --git a/compiler/rustc_traits/src/chalk/lowering.rs b/compiler/rustc_traits/src/chalk/lowering.rs index ee013515e86c4..9931a7f32ef77 100644 --- a/compiler/rustc_traits/src/chalk/lowering.rs +++ b/compiler/rustc_traits/src/chalk/lowering.rs @@ -413,7 +413,11 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty> { TyKind::Closure(closure, substitution) => { ty::Closure(closure.0, substitution.lower_into(interner)) } - TyKind::Generator(..) => unimplemented!(), + TyKind::Generator(generator, substitution) => ty::Generator( + generator.0, + substitution.lower_into(interner), + ast::Movability::Static, + ), TyKind::GeneratorWitness(..) => unimplemented!(), TyKind::Never => ty::Never, TyKind::Tuple(_len, substitution) => { diff --git a/compiler/rustc_ty_utils/src/instance.rs b/compiler/rustc_ty_utils/src/instance.rs index 6436713b38811..7f16b2d35e800 100644 --- a/compiler/rustc_ty_utils/src/instance.rs +++ b/compiler/rustc_ty_utils/src/instance.rs @@ -202,6 +202,12 @@ fn resolve_associated_item<'tcx>( )), substs: generator_data.substs, }), + traits::ImplSource::Future(future_data) => Some(Instance { + def: ty::InstanceDef::Item(ty::WithOptConstParam::unknown( + future_data.generator_def_id, + )), + substs: future_data.substs, + }), traits::ImplSource::Closure(closure_data) => { let trait_closure_kind = tcx.fn_trait_kind_from_lang_item(trait_id).unwrap(); Instance::resolve_closure( diff --git a/library/core/src/future/mod.rs b/library/core/src/future/mod.rs index 107cf92c1c0f7..f2b961d62e00c 100644 --- a/library/core/src/future/mod.rs +++ b/library/core/src/future/mod.rs @@ -9,12 +9,8 @@ //! [`await`]: ../../std/keyword.await.html //! [async book]: https://rust-lang.github.io/async-book/ -use crate::{ - ops::{Generator, GeneratorState}, - pin::Pin, - ptr::NonNull, - task::{Context, Poll}, -}; +use crate::ptr::NonNull; +use crate::task::Context; mod future; mod into_future; @@ -48,6 +44,7 @@ pub use poll_fn::{poll_fn, PollFn}; /// non-Send/Sync as well, and we don't want that. /// /// It also simplifies the HIR lowering of `.await`. +#[cfg_attr(not(bootstrap), lang = "ResumeTy")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[derive(Debug, Copy, Clone)] @@ -64,15 +61,21 @@ unsafe impl Sync for ResumeTy {} /// This function returns a `GenFuture` underneath, but hides it in `impl Trait` to give /// better error messages (`impl Future` rather than `GenFuture<[closure.....]>`). // This is `const` to avoid extra errors after we recover from `const async fn` -#[lang = "from_generator"] +#[cfg_attr(bootstrap, lang = "from_generator")] #[doc(hidden)] #[unstable(feature = "gen_future", issue = "50547")] #[rustc_const_unstable(feature = "gen_future", issue = "50547")] #[inline] pub const fn from_generator(gen: T) -> impl Future where - T: Generator, + T: crate::ops::Generator, { + use crate::{ + ops::{Generator, GeneratorState}, + pin::Pin, + task::Poll, + }; + #[rustc_diagnostic_item = "gen_future"] struct GenFuture>(T); @@ -109,3 +112,11 @@ pub unsafe fn get_context<'a, 'b>(cx: ResumeTy) -> &'a mut Context<'b> { // that fulfills all the requirements for a mutable reference. unsafe { &mut *cx.0.as_ptr().cast() } } + +#[cfg_attr(not(bootstrap), lang = "identity_future")] +#[doc(hidden)] +#[unstable(feature = "gen_future", issue = "50547")] +#[inline] +pub const fn identity_future>(f: Fut) -> Fut { + f +} diff --git a/library/core/src/task/poll.rs b/library/core/src/task/poll.rs index 41f0a25dbc3e0..f1dc4f7b575aa 100644 --- a/library/core/src/task/poll.rs +++ b/library/core/src/task/poll.rs @@ -9,6 +9,7 @@ use crate::task::Ready; /// scheduled to receive a wakeup instead. #[must_use = "this `Poll` may be a `Pending` variant, which should be handled"] #[derive(Copy, Clone, Debug, Eq, PartialEq, Ord, PartialOrd, Hash)] +#[cfg_attr(not(bootstrap), lang = "Poll")] #[stable(feature = "futures_api", since = "1.36.0")] pub enum Poll { /// Represents that a value is immediately ready. diff --git a/src/test/codegen/async-fn-debug-awaitee-field.rs b/src/test/codegen/async-fn-debug-awaitee-field.rs index 909cd0062a623..bc26861581401 100644 --- a/src/test/codegen/async-fn-debug-awaitee-field.rs +++ b/src/test/codegen/async-fn-debug-awaitee-field.rs @@ -11,12 +11,14 @@ async fn async_fn_test() { foo().await; } -// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", +// NONMSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[GEN_SCOPE:![0-9]*]], // MSVC: [[GEN:!.*]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", +// NONMSVC: [[GEN_SCOPE:!.*]] = !DINamespace(name: "async_fn_test", // CHECK: [[SUSPEND_STRUCT:!.*]] = !DICompositeType(tag: DW_TAG_structure_type, name: "Suspend0", scope: [[GEN]], // CHECK: !DIDerivedType(tag: DW_TAG_member, name: "__awaitee", scope: [[SUSPEND_STRUCT]], {{.*}}, baseType: [[AWAITEE_TYPE:![0-9]*]], -// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture", -// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture >", +// NONMSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "{async_fn_env#0}", scope: [[AWAITEE_SCOPE:![0-9]*]], +// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_union_type, name: "enum2$", +// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo", fn main() { let _fn = async_fn_test(); diff --git a/src/test/run-make/coverage-reports/expected_show_coverage.async2.txt b/src/test/run-make/coverage-reports/expected_show_coverage.async2.txt index dc06a485a8fc1..500dde1f2698a 100644 --- a/src/test/run-make/coverage-reports/expected_show_coverage.async2.txt +++ b/src/test/run-make/coverage-reports/expected_show_coverage.async2.txt @@ -72,7 +72,7 @@ 67| | } 68| 2| } ------------------ - | async2::executor::block_on::>: + | async2::executor::block_on::: | 51| 1| pub fn block_on(mut future: F) -> F::Output { | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; | 53| 1| use std::hint::unreachable_unchecked; @@ -92,7 +92,7 @@ | 67| | } | 68| 1| } ------------------ - | async2::executor::block_on::>: + | async2::executor::block_on::: | 51| 1| pub fn block_on(mut future: F) -> F::Output { | 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) }; | 53| 1| use std::hint::unreachable_unchecked; diff --git a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr index 2a08d5d6ce5f8..b8ca64fae8319 100644 --- a/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr +++ b/src/test/ui/async-await/async-block-control-flow-static-semantics.stderr @@ -1,8 +1,7 @@ error[E0267]: `break` inside of an `async` block --> $DIR/async-block-control-flow-static-semantics.rs:32:9 | -LL | async { - | ___________- +LL | / async { LL | | break 0u8; | | ^^^^^^^^^ cannot `break` inside of an `async` block LL | | }; @@ -11,8 +10,7 @@ LL | | }; error[E0267]: `break` inside of an `async` block --> $DIR/async-block-control-flow-static-semantics.rs:39:13 | -LL | async { - | _______________- +LL | / async { LL | | break 0u8; | | ^^^^^^^^^ cannot `break` inside of an `async` block LL | | }; diff --git a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr index f21c811512416..190c59e32ebbb 100644 --- a/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr +++ b/src/test/ui/async-await/async-borrowck-escaping-block-error.stderr @@ -1,11 +1,11 @@ error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/async-borrowck-escaping-block-error.rs:6:20 + --> $DIR/async-borrowck-escaping-block-error.rs:6:14 | LL | Box::new(async { x } ) - | ^^-^^ - | | | - | | `x` is borrowed here - | may outlive borrowed value `x` + | ^^^^^^^^-^^ + | | | + | | `x` is borrowed here + | may outlive borrowed value `x` | note: async block is returned here --> $DIR/async-borrowck-escaping-block-error.rs:6:5 @@ -18,13 +18,13 @@ LL | Box::new(async move { x } ) | ++++ error[E0373]: async block may outlive the current function, but it borrows `x`, which is owned by the current function - --> $DIR/async-borrowck-escaping-block-error.rs:11:11 + --> $DIR/async-borrowck-escaping-block-error.rs:11:5 | LL | async { *x } - | ^^--^^ - | | | - | | `x` is borrowed here - | may outlive borrowed value `x` + | ^^^^^^^^--^^ + | | | + | | `x` is borrowed here + | may outlive borrowed value `x` | note: async block is returned here --> $DIR/async-borrowck-escaping-block-error.rs:11:5 diff --git a/src/test/ui/async-await/generator-desc.stderr b/src/test/ui/async-await/generator-desc.stderr index 2494c3feb2a89..774c97966b18e 100644 --- a/src/test/ui/async-await/generator-desc.stderr +++ b/src/test/ui/async-await/generator-desc.stderr @@ -1,20 +1,20 @@ error[E0308]: mismatched types - --> $DIR/generator-desc.rs:10:25 + --> $DIR/generator-desc.rs:10:19 | LL | fun(async {}, async {}); - | -- ^^ - | | | - | | expected `async` block, found a different `async` block - | | arguments to this function are incorrect - | the expected `async` block + | -------- ^^^^^^^^ + | | | + | | expected `async` block, found a different `async` block + | | arguments to this function are incorrect + | the expected `async` block | - = note: expected `async` block `[static generator@$DIR/generator-desc.rs:10:15: 10:17]` - found `async` block `[static generator@$DIR/generator-desc.rs:10:25: 10:27]` + = note: expected `async` block `impl Future` (`async` block) + found `async` block `impl Future` (`async` block) note: function defined here --> $SRC_DIR/core/src/future/mod.rs:LL:COL | -LL | pub const fn from_generator(gen: T) -> impl Future - | ^^^^^^^^^^^^^^ +LL | pub const fn identity_future>(f: Fut) -> Fut { + | ^^^^^^^^^^^^^^^ error[E0308]: mismatched types --> $DIR/generator-desc.rs:12:16 @@ -53,16 +53,8 @@ LL | fun((async || {})(), (async || {})()); | | the expected `async` closure body | arguments to this function are incorrect | - ::: $SRC_DIR/core/src/future/mod.rs:LL:COL - | -LL | pub const fn from_generator(gen: T) -> impl Future - | ------------------------------- - | | - | the expected opaque type - | the found opaque type - | - = note: expected opaque type `impl Future` (`async` closure body) - found opaque type `impl Future` (`async` closure body) + = note: expected `async` closure body `impl Future` (`async` closure body) + found `async` closure body `impl Future` (`async` closure body) note: function defined here --> $DIR/generator-desc.rs:8:4 | diff --git a/src/test/ui/async-await/issue-68112.drop_tracking.stderr b/src/test/ui/async-await/issue-68112.drop_tracking.stderr index c915164cfce86..f2802698fd5b6 100644 --- a/src/test/ui/async-await/issue-68112.drop_tracking.stderr +++ b/src/test/ui/async-await/issue-68112.drop_tracking.stderr @@ -59,10 +59,10 @@ LL | fn make_non_send_future2() -> impl Future>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: required because it captures the following types: `ResumeTy`, `impl Future>>`, `()`, `Ready` note: required because it's used within this `async` block - --> $DIR/issue-68112.rs:60:26 + --> $DIR/issue-68112.rs:60:20 | LL | let send_fut = async { - | __________________________^ + | ____________________^ LL | | let non_send_fut = make_non_send_future2(); LL | | let _ = non_send_fut.await; LL | | ready(0).await; diff --git a/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr b/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr index 11b7d1aaaa6c7..38eb85b302fd5 100644 --- a/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr +++ b/src/test/ui/async-await/issue-68112.no_drop_tracking.stderr @@ -59,10 +59,10 @@ LL | fn make_non_send_future2() -> impl Future>> { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ = note: required because it captures the following types: `ResumeTy`, `impl Future>>`, `()`, `i32`, `Ready` note: required because it's used within this `async` block - --> $DIR/issue-68112.rs:60:26 + --> $DIR/issue-68112.rs:60:20 | LL | let send_fut = async { - | __________________________^ + | ____________________^ LL | | let non_send_fut = make_non_send_future2(); LL | | let _ = non_send_fut.await; LL | | ready(0).await; diff --git a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr index 7fb8811666536..721234aa4a782 100644 --- a/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr +++ b/src/test/ui/async-await/issue-70935-complex-spans.drop_tracking.stderr @@ -20,10 +20,9 @@ LL | | } | |_^ = note: required because it captures the following types: `ResumeTy`, `impl Future`, `()` note: required because it's used within this `async` block - --> $DIR/issue-70935-complex-spans.rs:16:16 + --> $DIR/issue-70935-complex-spans.rs:16:5 | -LL | async move { - | ________________^ +LL | / async move { LL | | baz(|| async{ LL | | foo(tx.clone()); LL | | }).await; diff --git a/src/test/ui/async-await/issues/issue-78938-async-block.stderr b/src/test/ui/async-await/issues/issue-78938-async-block.stderr index 29aa8372f87d0..c1a4b467f104e 100644 --- a/src/test/ui/async-await/issues/issue-78938-async-block.stderr +++ b/src/test/ui/async-await/issues/issue-78938-async-block.stderr @@ -1,8 +1,8 @@ error[E0373]: async block may outlive the current function, but it borrows `room_ref`, which is owned by the current function - --> $DIR/issue-78938-async-block.rs:8:39 + --> $DIR/issue-78938-async-block.rs:8:33 | LL | let gameloop_handle = spawn(async { - | _______________________________________^ + | _________________________________^ LL | | game_loop(Arc::clone(&room_ref)) | | -------- `room_ref` is borrowed here LL | | }); diff --git a/src/test/ui/async-await/try-on-option-in-async.stderr b/src/test/ui/async-await/try-on-option-in-async.stderr index a55850d76c3d8..4c7b4fa41faea 100644 --- a/src/test/ui/async-await/try-on-option-in-async.stderr +++ b/src/test/ui/async-await/try-on-option-in-async.stderr @@ -1,8 +1,7 @@ error[E0277]: the `?` operator can only be used in an async block that returns `Result` or `Option` (or another type that implements `FromResidual`) --> $DIR/try-on-option-in-async.rs:8:10 | -LL | async { - | ___________- +LL | / async { LL | | let x: Option = None; LL | | x?; | | ^ cannot use the `?` operator in an async block that returns `{integer}` diff --git a/src/test/ui/chalkify/bugs/async.stderr b/src/test/ui/chalkify/bugs/async.stderr index f53ed53f73c49..6f22d2c593a3b 100644 --- a/src/test/ui/chalkify/bugs/async.stderr +++ b/src/test/ui/chalkify/bugs/async.stderr @@ -1,32 +1,47 @@ -error[E0277]: the trait bound `[static generator@$DIR/async.rs:7:29: 9:2]: Generator` is not satisfied +error[E0277]: `impl Future` is not a future --> $DIR/async.rs:7:29 | LL | async fn foo(x: u32) -> u32 { - | _____________________________^ + | _____________________________- LL | | x LL | | } - | |_^ the trait `Generator` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]` + | | ^ + | | | + | |_`impl Future` is not a future + | required by a bound introduced by this call | -note: required by a bound in `std::future::from_generator` + = help: the trait `Future` is not implemented for `impl Future` + = note: impl Future must be a future or must implement `IntoFuture` to be awaited +note: required by a bound in `identity_future` --> $SRC_DIR/core/src/future/mod.rs:LL:COL | -LL | T: Generator, - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `std::future::from_generator` +LL | pub const fn identity_future>(f: Fut) -> Fut { + | ^^^^^^^^^^^^^^^^^^ required by this bound in `identity_future` -error[E0280]: the requirement `<[static generator@$DIR/async.rs:7:29: 9:2] as Generator>::Yield == ()` is not satisfied +error[E0277]: the size for values of type ` as Future>::Output` cannot be known at compilation time --> $DIR/async.rs:7:29 | LL | async fn foo(x: u32) -> u32 { | _____________________________^ LL | | x LL | | } - | |_^ + | |_^ doesn't have a size known at compile-time | -note: required by a bound in `std::future::from_generator` + = help: the trait `Sized` is not implemented for ` as Future>::Output` +note: required by a bound in `identity_future` --> $SRC_DIR/core/src/future/mod.rs:LL:COL | -LL | T: Generator, - | ^^^^^^^^^^ required by this bound in `std::future::from_generator` +LL | pub const fn identity_future>(f: Fut) -> Fut { + | ^ required by this bound in `identity_future` + +error[E0277]: `impl Future` is not a future + --> $DIR/async.rs:7:25 + | +LL | async fn foo(x: u32) -> u32 { + | ^^^ `impl Future` is not a future + | + = help: the trait `Future` is not implemented for `impl Future` + = note: impl Future must be a future or must implement `IntoFuture` to be awaited error[E0280]: the requirement ` as Future>::Output == u32` is not satisfied --> $DIR/async.rs:7:25 @@ -34,6 +49,6 @@ error[E0280]: the requirement ` as Future>::Output == LL | async fn foo(x: u32) -> u32 { | ^^^ -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors For more information about this error, try `rustc --explain E0277`. diff --git a/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs b/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs index 10f6bd74031ac..f02a93ed41b9a 100644 --- a/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs +++ b/src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs @@ -1,6 +1,6 @@ // check-pass -#![feature(gen_future, generator_trait, negative_impls)] +#![feature(generator_trait, negative_impls)] use std::ops::{Generator, GeneratorState}; use std::task::{Poll, Context}; diff --git a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr index 77cef485f30e9..918d37e65594d 100644 --- a/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr +++ b/src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr @@ -78,20 +78,21 @@ LL | impl> Pin

{ error[E0308]: mismatched types --> $DIR/expected-boxed-future-isnt-pinned.rs:28:5 | -LL | fn zap() -> BoxFuture<'static, i32> { - | ----------------------- expected `Pin + Send + 'static)>>` because of return type LL | / async { LL | | 42 LL | | } - | |_____^ expected struct `Pin`, found opaque type - | - ::: $SRC_DIR/core/src/future/mod.rs:LL:COL - | -LL | pub const fn from_generator(gen: T) -> impl Future - | ------------------------------- the found opaque type - | - = note: expected struct `Pin + Send + 'static)>>` - found opaque type `impl Future` + | | ^ + | | | + | |_____expected struct `Pin`, found `async` block + | arguments to this function are incorrect + | + = note: expected struct `Pin + Send>>` + found `async` block `impl Future` +note: function defined here + --> $SRC_DIR/core/src/future/mod.rs:LL:COL + | +LL | pub const fn identity_future>(f: Fut) -> Fut { + | ^^^^^^^^^^^^^^^ help: you need to pin and box this expression | LL ~ Box::pin(async { diff --git a/src/tools/clippy/clippy_lints/src/doc.rs b/src/tools/clippy/clippy_lints/src/doc.rs index 4557e43288542..ae5f9424b2323 100644 --- a/src/tools/clippy/clippy_lints/src/doc.rs +++ b/src/tools/clippy/clippy_lints/src/doc.rs @@ -427,9 +427,7 @@ fn lint_for_missing_headers( let body = cx.tcx.hir().body(body_id); let ret_ty = typeck.expr_ty(body.value); if implements_trait(cx, ret_ty, future, &[]); - if let ty::Opaque(_, subs) = ret_ty.kind(); - if let Some(gen) = subs.types().next(); - if let ty::Generator(_, subs, _) = gen.kind(); + if let ty::Generator(_, subs, _) = ret_ty.kind(); if is_type_diagnostic_item(cx, subs.as_generator().return_ty(), sym::Result); then { span_lint( diff --git a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs index 5c6a342b3d074..6a98df4991259 100644 --- a/src/tools/clippy/clippy_lints/src/manual_async_fn.rs +++ b/src/tools/clippy/clippy_lints/src/manual_async_fn.rs @@ -177,7 +177,7 @@ fn desugared_async_block<'tcx>(cx: &LateContext<'tcx>, block: &'tcx Block<'tcx>) if let Some(args) = cx .tcx .lang_items() - .from_generator_fn() + .identity_future_fn() .and_then(|def_id| match_function_call_with_def_id(cx, block_expr, def_id)); if args.len() == 1; if let Expr { diff --git a/src/tools/clippy/tests/ui/author/blocks.stdout b/src/tools/clippy/tests/ui/author/blocks.stdout index 9de0550d81d00..c6acf24c21ecf 100644 --- a/src/tools/clippy/tests/ui/author/blocks.stdout +++ b/src/tools/clippy/tests/ui/author/blocks.stdout @@ -45,7 +45,7 @@ if let ExprKind::Closure(CaptureBy::Value, fn_decl, body_id, _, None) = expr.kin && expr1 = &cx.tcx.hir().body(body_id).value && let ExprKind::Call(func, args) = expr1.kind && let ExprKind::Path(ref qpath) = func.kind - && matches!(qpath, QPath::LangItem(LangItem::FromGenerator, _)) + && matches!(qpath, QPath::LangItem(LangItem::IdentityFuture, _)) && args.len() == 1 && let ExprKind::Closure(CaptureBy::Value, fn_decl1, body_id1, _, Some(Movability::Static)) = args[0].kind && let FnRetTy::DefaultReturn(_) = fn_decl1.output