diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index 3c217c0249aba..23a38a092d957 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 93b0f5814dedf..8555e4c86261b 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -3914,7 +3914,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 cd4a044739172..c7983ecbd43c8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs +++ b/compiler/rustc_trait_selection/src/traits/select/candidate_assembly.rs @@ -312,7 +312,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); @@ -400,10 +405,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. @@ -422,6 +423,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 3cffd2bb78017..c0edbebed54ee 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