Skip to content

Avoid GenFuture shim when compiling async constructs #104321

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Nov 24, 2022
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
36 changes: 23 additions & 13 deletions compiler/rustc_ast_lowering/src/expr.rs
Original file line number Diff line number Diff line change
@@ -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| -> <ret_ty> {
/// std::future::identity_future(static move? |_task_context| -> <ret_ty> {
/// <body>
/// })
/// ```
@@ -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 `<expr>.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);
15 changes: 11 additions & 4 deletions compiler/rustc_borrowck/src/diagnostics/region_errors.rs
Original file line number Diff line number Diff line change
@@ -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());
}
}
}
}
1 change: 0 additions & 1 deletion compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
@@ -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
21 changes: 11 additions & 10 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
@@ -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
6 changes: 5 additions & 1 deletion compiler/rustc_hir/src/lang_items.rs
Original file line number Diff line number Diff line change
@@ -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;
13 changes: 9 additions & 4 deletions compiler/rustc_hir_typeck/src/check.rs
Original file line number Diff line number Diff line change
@@ -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());
8 changes: 0 additions & 8 deletions compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs
Original file line number Diff line number Diff line change
@@ -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; };
15 changes: 14 additions & 1 deletion compiler/rustc_lint/src/unused.rs
Original file line number Diff line number Diff line change
@@ -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,
}
}
20 changes: 20 additions & 0 deletions compiler/rustc_middle/src/traits/mod.rs
Original file line number Diff line number Diff line change
@@ -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<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> {
4 changes: 4 additions & 0 deletions compiler/rustc_middle/src/traits/select.rs
Original file line number Diff line number Diff line change
@@ -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 {
12 changes: 12 additions & 0 deletions compiler/rustc_middle/src/traits/structural_impls.rs
Original file line number Diff line number Diff line change
@@ -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!(
11 changes: 11 additions & 0 deletions compiler/rustc_middle/src/ty/print/pretty.rs
Original file line number Diff line number Diff line change
@@ -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<Output = {}>", return_ty));

return Ok(self);
}

p!(write("["));
match movability {
hir::Movability::Movable => {}
95 changes: 68 additions & 27 deletions compiler/rustc_mir_transform/src/generator.rs
Original file line number Diff line number Diff line change
@@ -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<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
@@ -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<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
@@ -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
2 changes: 1 addition & 1 deletion compiler/rustc_resolve/src/late.rs
Original file line number Diff line number Diff line change
@@ -3912,7 +3912,7 @@ impl<'a: 'ast, 'b, 'ast> LateResolutionVisitor<'a, 'b, 'ast> {
visit::walk_expr(self, expr);
self.diagnostic_metadata.current_type_ascription.pop();
}
// `async |x| ...` gets desugared to `|x| future_from_generator(|| ...)`, so we need to
// `async |x| ...` gets desugared to `|x| async {...}`, so we need to
// resolve the arguments within the proper scopes so that usages of them inside the
// closure are detected as upvars rather than normal closure arg usages.
ExprKind::Closure(box ast::Closure {
3 changes: 2 additions & 1 deletion compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -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,
Original file line number Diff line number Diff line change
@@ -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,
})
47 changes: 46 additions & 1 deletion compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -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>,
Original file line number Diff line number Diff line change
@@ -314,7 +314,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
self.assemble_builtin_bound_candidates(clone_conditions, &mut candidates);
}

self.assemble_generator_candidates(obligation, &mut candidates);
if lang_items.gen_trait() == Some(def_id) {
self.assemble_generator_candidates(obligation, &mut candidates);
} else if lang_items.future_trait() == Some(def_id) {
self.assemble_future_candidates(obligation, &mut candidates);
}

self.assemble_closure_candidates(obligation, &mut candidates);
self.assemble_fn_pointer_candidates(obligation, &mut candidates);
self.assemble_candidates_from_impls(obligation, &mut candidates);
@@ -402,10 +407,6 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
if self.tcx().lang_items().gen_trait() != Some(obligation.predicate.def_id()) {
return;
}

// Okay to skip binder because the substs on generator types never
// touch bound regions, they just capture the in-scope
// type/region parameters.
@@ -424,6 +425,23 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
}
}

fn assemble_future_candidates(
&mut self,
obligation: &TraitObligation<'tcx>,
candidates: &mut SelectionCandidateSet<'tcx>,
) {
let self_ty = obligation.self_ty().skip_binder();
if let ty::Generator(did, ..) = self_ty.kind() {
if let Some(rustc_hir::GeneratorKind::Async(_generator_kind)) =
self.tcx().generator_kind(did)
{
debug!(?self_ty, ?obligation, "assemble_future_candidates",);

candidates.vec.push(FutureCandidate);
}
}
}

/// Checks for the artificial impl that the compiler will create for an obligation like `X :
/// FnMut<..>` where `X` is a closure type.
///
60 changes: 55 additions & 5 deletions compiler/rustc_trait_selection/src/traits/select/confirmation.rs
Original file line number Diff line number Diff line change
@@ -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,14 +691,58 @@ 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

you can invoke https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/ty/sty/struct.Binder.html#method.no_bound_vars instead of skip_binder and .expect the option to make sure if this condition is violated, the compiler ICEs instead of doing weird things.

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

An expect there actually does panic for the src/test/ui/generator/resume-arg-late-bound.rs test.

I only moved this code between the files, the same comment and code pattern exists as well for normal closures:

// (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,
31 changes: 8 additions & 23 deletions compiler/rustc_trait_selection/src/traits/select/mod.rs
Original file line number Diff line number Diff line change
@@ -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
11 changes: 11 additions & 0 deletions compiler/rustc_trait_selection/src/traits/util.rs
Original file line number Diff line number Diff line change
@@ -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()
6 changes: 5 additions & 1 deletion compiler/rustc_traits/src/chalk/lowering.rs
Original file line number Diff line number Diff line change
@@ -413,7 +413,11 @@ impl<'tcx> LowerInto<'tcx, Ty<'tcx>> for &chalk_ir::Ty<RustInterner<'tcx>> {
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) => {
6 changes: 6 additions & 0 deletions compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
@@ -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(
27 changes: 19 additions & 8 deletions library/core/src/future/mod.rs
Original file line number Diff line number Diff line change
@@ -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<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);

@@ -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<O, Fut: Future<Output = O>>(f: Fut) -> Fut {
Comment on lines +116 to +120
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

please open an issue reminding us that we should get rid of this function and look into what borrowck needs to handle this correctly without the identity function

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Here you go: #104826

f
}
1 change: 1 addition & 0 deletions library/core/src/task/poll.rs
Original file line number Diff line number Diff line change
@@ -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<T> {
/// Represents that a value is immediately ready.
8 changes: 5 additions & 3 deletions src/test/codegen/async-fn-debug-awaitee-field.rs
Original file line number Diff line number Diff line change
@@ -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$<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();
Original file line number Diff line number Diff line change
@@ -72,7 +72,7 @@
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;
@@ -92,7 +92,7 @@
| 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;
Original file line number Diff line number Diff line change
@@ -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 | | };
20 changes: 10 additions & 10 deletions src/test/ui/async-await/async-borrowck-escaping-block-error.stderr
Original file line number Diff line number Diff line change
@@ -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
32 changes: 12 additions & 20 deletions src/test/ui/async-await/generator-desc.stderr
Original file line number Diff line number Diff line change
@@ -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<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
@@ -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<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
|
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issue-68112.drop_tracking.stderr
Original file line number Diff line number Diff line change
@@ -59,10 +59,10 @@ LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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;
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issue-68112.no_drop_tracking.stderr
Original file line number Diff line number Diff line change
@@ -59,10 +59,10 @@ LL | fn make_non_send_future2() -> impl Future<Output = Arc<RefCell<i32>>> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
= 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;
Original file line number Diff line number Diff line change
@@ -20,10 +20,9 @@ LL | | }
| |_^
= 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;
4 changes: 2 additions & 2 deletions src/test/ui/async-await/issues/issue-78938-async-block.stderr
Original file line number Diff line number Diff line change
@@ -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 | | });
3 changes: 1 addition & 2 deletions src/test/ui/async-await/try-on-option-in-async.stderr
Original file line number Diff line number Diff line change
@@ -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<u32> = None;
LL | | x?;
| | ^ cannot use the `?` operator in an async block that returns `{integer}`
39 changes: 27 additions & 12 deletions src/test/ui/chalkify/bugs/async.stderr
Original file line number Diff line number Diff line change
@@ -1,39 +1,54 @@
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`.
2 changes: 1 addition & 1 deletion src/test/ui/lazy-type-alias-impl-trait/freeze_cycle.rs
Original file line number Diff line number Diff line change
@@ -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};
23 changes: 12 additions & 11 deletions src/test/ui/suggestions/expected-boxed-future-isnt-pinned.stderr
Original file line number Diff line number Diff line change
@@ -78,20 +78,21 @@ LL | impl<P: Deref<Target: Unpin>> Pin<P> {
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 {
4 changes: 1 addition & 3 deletions src/tools/clippy/clippy_lints/src/doc.rs
Original file line number Diff line number Diff line change
@@ -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(
2 changes: 1 addition & 1 deletion src/tools/clippy/clippy_lints/src/manual_async_fn.rs
Original file line number Diff line number Diff line change
@@ -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 {
2 changes: 1 addition & 1 deletion src/tools/clippy/tests/ui/author/blocks.stdout
Original file line number Diff line number Diff line change
@@ -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