*capture_clause,
*closure_node_id,
None,
- block.span,
+ e.span,
hir::AsyncGeneratorKind::Block,
|this| this.with_new_scopes(|this| this.lower_block_expr(block)),
),
}
}
- /// 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| -> <ret_ty> {
+ /// std::future::identity_future(static move? |_task_context| -> <ret_ty> {
/// <body>
/// })
/// ```
) -> 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`.
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 `<expr>.await` into:
}
// 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);
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;
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 }
}
// 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());
+ }
}
}
}
}
// 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
| 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) => {
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
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;
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());
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; };
.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,
}
}
/// 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>),
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)
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)
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(),
pub nested: Vec<N>,
}
+#[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<N>,
+}
+
#[derive(Clone, PartialEq, Eq, TyEncodable, TyDecodable, HashStable, Lift)]
#[derive(TypeFoldable, TypeVisitable)]
pub struct ImplSourceClosureData<'tcx, N> {
/// 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 {
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),
}
}
+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!(
}
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<Output = {}>", return_ty));
+
+ return Ok(self);
+ }
+
p!(write("["));
match movability {
hir::Movability::Movable => {}
//! 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.
//! 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.
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;
struct TransformVisitor<'tcx> {
tcx: TyCtxt<'tcx>,
+ is_async_kind: bool,
state_adt_ref: AdtDef<'tcx>,
state_substs: SubstsRef<'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<Item = Statement<'tcx>> {
+ is_return: bool,
+ statements: &mut Vec<Statement<'tcx>>,
+ ) {
+ 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
});
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();
}
};
- // Compute GeneratorState<yield_ty, return_ty>
- 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<return_ty>
+ 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<yield_ty, return_ty>
+ 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
// 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,
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
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 {
Relaxed,
Release,
Result,
+ ResumeTy,
Return,
Right,
Rust,
frem_fast,
from,
from_desugaring,
- from_generator,
from_iter,
from_method,
from_output,
i64,
i8,
ident,
+ identity_future,
if_let,
if_let_guard,
if_while_or_patterns,
//
// - `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)
//
}
};
- 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!(
);
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,
})
use super::SelectionError;
use super::{
ImplSourceClosureData, ImplSourceDiscriminantKindData, ImplSourceFnPointerData,
- ImplSourceGeneratorData, ImplSourcePointeeData, ImplSourceUserDefinedData,
+ ImplSourceFutureData, ImplSourceGeneratorData, ImplSourcePointeeData,
+ ImplSourceUserDefinedData,
};
use super::{Normalized, NormalizedTy, ProjectionCacheEntry, ProjectionCacheKey};
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) => {
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) => {
.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>,
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);
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.
}
}
+ 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.
///
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;
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)
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");
Ok(ImplSourceGeneratorData { generator_def_id, substs, nested })
}
+ fn confirm_future_candidate(
+ &mut self,
+ obligation: &TraitObligation<'tcx>,
+ ) -> Result<ImplSourceFutureData<'tcx, PredicateObligation<'tcx>>, 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,
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(_) => {}
ImplCandidate(..)
| ClosureCandidate
| GeneratorCandidate
+ | FutureCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
ImplCandidate(_)
| ClosureCandidate
| GeneratorCandidate
+ | FutureCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
ImplCandidate(..)
| ClosureCandidate
| GeneratorCandidate
+ | FutureCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
ImplCandidate(..)
| ClosureCandidate
| GeneratorCandidate
+ | FutureCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
ImplCandidate(_)
| ClosureCandidate
| GeneratorCandidate
+ | FutureCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
ImplCandidate(_)
| ClosureCandidate
| GeneratorCandidate
+ | FutureCandidate
| FnPointerCandidate { .. }
| BuiltinObjectCandidate
| BuiltinUnsizeCandidate
.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
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()
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) => {
)),
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(
//! [`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;
/// 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)]
/// 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<T>(gen: T) -> impl Future<Output = T::Return>
where
- T: Generator<ResumeTy, Yield = ()>,
+ T: crate::ops::Generator<ResumeTy, Yield = ()>,
{
+ use crate::{
+ ops::{Generator, GeneratorState},
+ pin::Pin,
+ task::Poll,
+ };
+
#[rustc_diagnostic_item = "gen_future"]
struct GenFuture<T: Generator<ResumeTy, Yield = ()>>(T);
// 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<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
+ f
+}
/// 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<T> {
/// Represents that a value is immediately ready.
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$<async_fn_debug_awaitee_field::async_fn_test::async_fn_env$0>",
+// 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<async_fn_debug_awaitee_field::foo::{async_fn_env#0}>",
-// MSVC: [[AWAITEE_TYPE]] = !DICompositeType(tag: DW_TAG_structure_type, name: "GenFuture<enum2$<async_fn_debug_awaitee_field::foo::async_fn_env$0> >",
+// 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$<async_fn_debug_awaitee_field::foo::async_fn_env$0>",
+// NONMSVC: [[AWAITEE_SCOPE]] = !DINamespace(name: "foo",
fn main() {
let _fn = async_fn_test();
67| | }
68| 2| }
------------------
- | async2::executor::block_on::<core::future::from_generator::GenFuture<async2::async_func::{closure#0}>>:
+ | async2::executor::block_on::<async2::async_func::{closure#0}>:
| 51| 1| pub fn block_on<F: Future>(mut future: F) -> F::Output {
| 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) };
| 53| 1| use std::hint::unreachable_unchecked;
| 67| | }
| 68| 1| }
------------------
- | async2::executor::block_on::<core::future::from_generator::GenFuture<async2::async_func_just_println::{closure#0}>>:
+ | async2::executor::block_on::<async2::async_func_just_println::{closure#0}>:
| 51| 1| pub fn block_on<F: Future>(mut future: F) -> F::Output {
| 52| 1| let mut future = unsafe { Pin::new_unchecked(&mut future) };
| 53| 1| use std::hint::unreachable_unchecked;
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 | | };
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 | | };
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
| ++++
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
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<Output = ()>` (`async` block)
+ found `async` block `impl Future<Output = ()>` (`async` block)
note: function defined here
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
-LL | pub const fn from_generator<T>(gen: T) -> impl Future<Output = T::Return>
- | ^^^^^^^^^^^^^^
+LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
+ | ^^^^^^^^^^^^^^^
error[E0308]: mismatched types
--> $DIR/generator-desc.rs:12:16
| | 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<T>(gen: T) -> impl Future<Output = T::Return>
- | -------------------------------
- | |
- | the expected opaque type
- | the found opaque type
- |
- = note: expected opaque type `impl Future<Output = ()>` (`async` closure body)
- found opaque type `impl Future<Output = ()>` (`async` closure body)
+ = note: expected `async` closure body `impl Future<Output = ()>` (`async` closure body)
+ found `async` closure body `impl Future<Output = ()>` (`async` closure body)
note: function defined here
--> $DIR/generator-desc.rs:8:4
|
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `Ready<i32>`
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;
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = Arc<RefCell<i32>>>`, `()`, `i32`, `Ready<i32>`
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;
| |_^
= note: required because it captures the following types: `ResumeTy`, `impl Future<Output = ()>`, `()`
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;
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 | | });
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<u32> = None;
LL | | x?;
| | ^ cannot use the `?` operator in an async block that returns `{integer}`
-error[E0277]: the trait bound `[static generator@$DIR/async.rs:7:29: 9:2]: Generator<ResumeTy>` is not satisfied
+error[E0277]: `impl Future<Output = u32>` is not a future
--> $DIR/async.rs:7:29
|
LL | async fn foo(x: u32) -> u32 {
- | _____________________________^
+ | _____________________________-
LL | | x
LL | | }
- | |_^ the trait `Generator<ResumeTy>` is not implemented for `[static generator@$DIR/async.rs:7:29: 9:2]`
+ | | ^
+ | | |
+ | |_`impl Future<Output = u32>` 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<Output = u32>`
+ = note: impl Future<Output = u32> 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<ResumeTy, Yield = ()>,
- | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ required by this bound in `std::future::from_generator`
+LL | pub const fn identity_future<O, Fut: Future<Output = O>>(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<ResumeTy>>::Yield == ()` is not satisfied
+error[E0277]: the size for values of type `<impl Future<Output = u32> 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 `<impl Future<Output = u32> as Future>::Output`
+note: required by a bound in `identity_future`
--> $SRC_DIR/core/src/future/mod.rs:LL:COL
|
-LL | T: Generator<ResumeTy, Yield = ()>,
- | ^^^^^^^^^^ required by this bound in `std::future::from_generator`
+LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
+ | ^ required by this bound in `identity_future`
+
+error[E0277]: `impl Future<Output = u32>` is not a future
+ --> $DIR/async.rs:7:25
+ |
+LL | async fn foo(x: u32) -> u32 {
+ | ^^^ `impl Future<Output = u32>` is not a future
+ |
+ = help: the trait `Future` is not implemented for `impl Future<Output = u32>`
+ = note: impl Future<Output = u32> must be a future or must implement `IntoFuture` to be awaited
error[E0280]: the requirement `<impl Future<Output = u32> as Future>::Output == u32` is not satisfied
--> $DIR/async.rs:7:25
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`.
// check-pass
-#![feature(gen_future, generator_trait, negative_impls)]
+#![feature(generator_trait, negative_impls)]
use std::ops::{Generator, GeneratorState};
use std::task::{Poll, Context};
error[E0308]: mismatched types
--> $DIR/expected-boxed-future-isnt-pinned.rs:28:5
|
-LL | fn zap() -> BoxFuture<'static, i32> {
- | ----------------------- expected `Pin<Box<(dyn Future<Output = i32> + 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<T>(gen: T) -> impl Future<Output = T::Return>
- | ------------------------------- the found opaque type
- |
- = note: expected struct `Pin<Box<(dyn Future<Output = i32> + Send + 'static)>>`
- found opaque type `impl Future<Output = {integer}>`
+ | | ^
+ | | |
+ | |_____expected struct `Pin`, found `async` block
+ | arguments to this function are incorrect
+ |
+ = note: expected struct `Pin<Box<dyn Future<Output = i32> + Send>>`
+ found `async` block `impl Future<Output = {integer}>`
+note: function defined here
+ --> $SRC_DIR/core/src/future/mod.rs:LL:COL
+ |
+LL | pub const fn identity_future<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
+ | ^^^^^^^^^^^^^^^
help: you need to pin and box this expression
|
LL ~ Box::pin(async {
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(
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 {
&& 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