Skip to content

For async closures, cap closure kind, get rid of by_mut_body #120717

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 3 commits into from
Mar 20, 2024
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
2 changes: 1 addition & 1 deletion compiler/rustc_borrowck/src/type_check/input_output.rs
Original file line number Diff line number Diff line change
@@ -87,7 +87,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
self.tcx(),
ty::CoroutineArgsParts {
parent_args: args.parent_args(),
kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()),
kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()),
return_ty: user_provided_sig.output(),
tupled_upvars_ty,
// For async closures, none of these can be annotated, so just fill
14 changes: 9 additions & 5 deletions compiler/rustc_hir_typeck/src/callee.rs
Original file line number Diff line number Diff line change
@@ -184,16 +184,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
kind: TypeVariableOriginKind::TypeInference,
span: callee_expr.span,
});
// We may actually receive a coroutine back whose kind is different
// from the closure that this dispatched from. This is because when
// we have no captures, we automatically implement `FnOnce`. This
// impl forces the closure kind to `FnOnce` i.e. `u8`.
let kind_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::TypeInference,
span: callee_expr.span,
});
let call_sig = self.tcx.mk_fn_sig(
[coroutine_closure_sig.tupled_inputs_ty],
coroutine_closure_sig.to_coroutine(
self.tcx,
closure_args.parent_args(),
// Inherit the kind ty of the closure, since we're calling this
// coroutine with the most relaxed `AsyncFn*` trait that we can.
// We don't necessarily need to do this here, but it saves us
// computing one more infer var that will get constrained later.
closure_args.kind_ty(),
kind_ty,
self.tcx.coroutine_for_closure(def_id),
tupled_upvars_ty,
),
6 changes: 5 additions & 1 deletion compiler/rustc_hir_typeck/src/closure.rs
Original file line number Diff line number Diff line change
@@ -262,6 +262,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
},
);

let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
});
let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
kind: TypeVariableOriginKind::ClosureSynthetic,
span: expr_span,
@@ -279,7 +283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
sig.to_coroutine(
tcx,
parent_args,
closure_kind_ty,
coroutine_kind_ty,
tcx.coroutine_for_closure(expr_def_id),
coroutine_upvars_ty,
)
2 changes: 1 addition & 1 deletion compiler/rustc_hir_typeck/src/upvar.rs
Original file line number Diff line number Diff line change
@@ -410,7 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
self.demand_eqtype(
span,
coroutine_args.as_coroutine().kind_ty(),
Ty::from_closure_kind(self.tcx, closure_kind),
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
);
}

12 changes: 0 additions & 12 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
@@ -278,13 +278,6 @@ pub struct CoroutineInfo<'tcx> {
/// using `run_passes`.
pub by_move_body: Option<Body<'tcx>>,

/// The body of the coroutine, modified to take its upvars by mutable ref rather than by
/// immutable ref.
///
/// FIXME(async_closures): This is literally the same body as the parent body. Find a better
/// way to represent the by-mut signature (or cap the closure-kind of the coroutine).
pub by_mut_body: Option<Body<'tcx>>,

/// The layout of a coroutine. This field is populated after the state transform pass.
pub coroutine_layout: Option<CoroutineLayout<'tcx>>,

@@ -305,7 +298,6 @@ impl<'tcx> CoroutineInfo<'tcx> {
yield_ty: Some(yield_ty),
resume_ty: Some(resume_ty),
by_move_body: None,
by_mut_body: None,
coroutine_drop: None,
coroutine_layout: None,
}
@@ -628,10 +620,6 @@ impl<'tcx> Body<'tcx> {
self.coroutine.as_ref()?.by_move_body.as_ref()
}

pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> {
self.coroutine.as_ref()?.by_mut_body.as_ref()
}

#[inline]
pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind)
7 changes: 5 additions & 2 deletions compiler/rustc_middle/src/mir/visit.rs
Original file line number Diff line number Diff line change
@@ -345,8 +345,11 @@ macro_rules! make_mir_visitor {
ty::InstanceDef::Virtual(_def_id, _) |
ty::InstanceDef::ThreadLocalShim(_def_id) |
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } |
ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } |
ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id: _def_id,
receiver_by_ref: _,
} |
ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } |
ty::InstanceDef::DropGlue(_def_id, None) => {}

ty::InstanceDef::FnPtrShim(_def_id, ty) |
21 changes: 11 additions & 10 deletions compiler/rustc_middle/src/ty/instance.rs
Original file line number Diff line number Diff line change
@@ -90,15 +90,19 @@ pub enum InstanceDef<'tcx> {
/// and dispatch to the `FnMut::call_mut` instance for the closure.
ClosureOnceShim { call_once: DefId, track_caller: bool },

/// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once` or
/// `<[Fn coroutine-closure] as FnMut>::call_mut`.
/// `<[FnMut/Fn coroutine-closure] as FnOnce>::call_once`
///
/// The body generated here differs significantly from the `ClosureOnceShim`,
/// since we need to generate a distinct coroutine type that will move the
/// closure's upvars *out* of the closure.
ConstructCoroutineInClosureShim {
coroutine_closure_def_id: DefId,
target_kind: ty::ClosureKind,
// Whether the generated MIR body takes the coroutine by-ref. This is
// because the signature of `<{async fn} as FnMut>::call_mut` is:
// `fn(&mut self, args: A) -> <Self as FnOnce>::Output`, that is to say
// that it returns the `FnOnce`-flavored coroutine but takes the closure
// by mut ref (and similarly for `Fn::call`).
receiver_by_ref: bool,
},

/// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce`
@@ -107,7 +111,7 @@ pub enum InstanceDef<'tcx> {
///
/// This will select the body that is produced by the `ByMoveBody` transform, and thus
/// take and use all of its upvars by-move rather than by-ref.
CoroutineKindShim { coroutine_def_id: DefId, target_kind: ty::ClosureKind },
CoroutineKindShim { coroutine_def_id: DefId },

/// Compiler-generated accessor for thread locals which returns a reference to the thread local
/// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking
@@ -192,9 +196,9 @@ impl<'tcx> InstanceDef<'tcx> {
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
| ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id: def_id,
target_kind: _,
receiver_by_ref: _,
}
| ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ }
| ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id }
| InstanceDef::DropGlue(def_id, _)
| InstanceDef::CloneShim(def_id, _)
| InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
@@ -651,10 +655,7 @@ impl<'tcx> Instance<'tcx> {
Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args })
} else {
Some(Instance {
def: ty::InstanceDef::CoroutineKindShim {
coroutine_def_id,
target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
},
def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id },
args,
})
}
21 changes: 20 additions & 1 deletion compiler/rustc_middle/src/ty/sty.rs
Original file line number Diff line number Diff line change
@@ -483,7 +483,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> {
self.to_coroutine(
tcx,
parent_args,
Ty::from_closure_kind(tcx, goal_kind),
Ty::from_coroutine_closure_kind(tcx, goal_kind),
coroutine_def_id,
tupled_upvars_ty,
)
@@ -2456,6 +2456,25 @@ impl<'tcx> Ty<'tcx> {
}
}

/// Like [`Ty::to_opt_closure_kind`], but it caps the "maximum" closure kind
/// to `FnMut`. This is because although we have three capability states,
/// `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`, we only need to distinguish two coroutine
/// bodies: by-ref and by-value.
///
/// See the definition of `AsyncFn` and `AsyncFnMut` and the `CallRefFuture`
/// associated type for why we don't distinguish [`ty::ClosureKind::Fn`] and
/// [`ty::ClosureKind::FnMut`] for the purpose of the generated MIR bodies.
///
/// This method should be used when constructing a `Coroutine` out of a
/// `CoroutineClosure`, when the `Coroutine`'s `kind` field is being populated
/// directly from the `CoroutineClosure`'s `kind`.
pub fn from_coroutine_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> {
match kind {
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => tcx.types.i16,
ty::ClosureKind::FnOnce => tcx.types.i32,
}
}

/// Fast path helper for testing if a type is `Sized`.
///
/// Returning true means the type is known to be sized. Returning
35 changes: 0 additions & 35 deletions compiler/rustc_mir_transform/src/coroutine/by_move_body.rs
Original file line number Diff line number Diff line change
@@ -67,45 +67,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
by_move_body.source = mir::MirSource {
instance: InstanceDef::CoroutineKindShim {
coroutine_def_id: coroutine_def_id.to_def_id(),
target_kind: ty::ClosureKind::FnOnce,
},
promoted: None,
};
body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body);

// If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body.
// This is actually just a copy of the by-ref body, but with a different self type.
// FIXME(async_closures): We could probably unify this with the by-ref body somehow.
if coroutine_kind == ty::ClosureKind::Fn {
let by_mut_coroutine_ty = Ty::new_coroutine(
tcx,
coroutine_def_id.to_def_id(),
ty::CoroutineArgs::new(
tcx,
ty::CoroutineArgsParts {
parent_args: args.as_coroutine().parent_args(),
kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut),
resume_ty: args.as_coroutine().resume_ty(),
yield_ty: args.as_coroutine().yield_ty(),
return_ty: args.as_coroutine().return_ty(),
witness: args.as_coroutine().witness(),
tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(),
},
)
.args,
);
let mut by_mut_body = body.clone();
by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty;
dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(()));
by_mut_body.source = mir::MirSource {
instance: InstanceDef::CoroutineKindShim {
coroutine_def_id: coroutine_def_id.to_def_id(),
target_kind: ty::ClosureKind::FnMut,
},
promoted: None,
};
body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body);
}
}
}

3 changes: 0 additions & 3 deletions compiler/rustc_mir_transform/src/pass_manager.rs
Original file line number Diff line number Diff line change
@@ -186,9 +186,6 @@ fn run_passes_inner<'tcx>(
if let Some(by_move_body) = coroutine.by_move_body.as_mut() {
run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each);
}
if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() {
run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each);
}
}
}

121 changes: 35 additions & 86 deletions compiler/rustc_mir_transform/src/shim.rs
Original file line number Diff line number Diff line change
@@ -3,8 +3,8 @@ use rustc_hir::def_id::DefId;
use rustc_hir::lang_items::LangItem;
use rustc_middle::mir::*;
use rustc_middle::query::Providers;
use rustc_middle::ty::GenericArgs;
use rustc_middle::ty::{self, CoroutineArgs, EarlyBinder, Ty, TyCtxt};
use rustc_middle::ty::{GenericArgs, CAPTURE_STRUCT_LOCAL};
use rustc_target::abi::{FieldIdx, VariantIdx, FIRST_VARIANT};

use rustc_index::{Idx, IndexVec};
@@ -72,37 +72,12 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'

ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
target_kind,
} => match target_kind {
ty::ClosureKind::Fn => unreachable!("shouldn't be building shim for Fn"),
ty::ClosureKind::FnMut => {
// No need to optimize the body, it has already been optimized
// since we steal it from the `AsyncFn::call` body and just fix
// the return type.
return build_construct_coroutine_by_mut_shim(tcx, coroutine_closure_def_id);
}
ty::ClosureKind::FnOnce => {
build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id)
}
},
receiver_by_ref,
} => build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id, receiver_by_ref),

ty::InstanceDef::CoroutineKindShim { coroutine_def_id, target_kind } => match target_kind {
ty::ClosureKind::Fn => unreachable!(),
ty::ClosureKind::FnMut => {
return tcx
.optimized_mir(coroutine_def_id)
.coroutine_by_mut_body()
.unwrap()
.clone();
}
ty::ClosureKind::FnOnce => {
return tcx
.optimized_mir(coroutine_def_id)
.coroutine_by_move_body()
.unwrap()
.clone();
}
},
ty::InstanceDef::CoroutineKindShim { coroutine_def_id } => {
return tcx.optimized_mir(coroutine_def_id).coroutine_by_move_body().unwrap().clone();
}

ty::InstanceDef::DropGlue(def_id, ty) => {
// FIXME(#91576): Drop shims for coroutines aren't subject to the MIR passes at the end
@@ -123,21 +98,11 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
let body = if id_args.as_coroutine().kind_ty() == args.as_coroutine().kind_ty() {
coroutine_body.coroutine_drop().unwrap()
} else {
match args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap() {
ty::ClosureKind::Fn => {
unreachable!()
}
ty::ClosureKind::FnMut => coroutine_body
.coroutine_by_mut_body()
.unwrap()
.coroutine_drop()
.unwrap(),
ty::ClosureKind::FnOnce => coroutine_body
.coroutine_by_move_body()
.unwrap()
.coroutine_drop()
.unwrap(),
}
assert_eq!(
args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
ty::ClosureKind::FnOnce
);
coroutine_body.coroutine_by_move_body().unwrap().coroutine_drop().unwrap()
};

let mut body = EarlyBinder::bind(body.clone()).instantiate(tcx, args);
@@ -1051,12 +1016,26 @@ fn build_fn_ptr_addr_shim<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, self_ty: Ty<'t
fn build_construct_coroutine_by_move_shim<'tcx>(
tcx: TyCtxt<'tcx>,
coroutine_closure_def_id: DefId,
receiver_by_ref: bool,
) -> Body<'tcx> {
let self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
let mut self_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
let ty::CoroutineClosure(_, args) = *self_ty.kind() else {
bug!();
};

// We use `*mut Self` here because we only need to emit an ABI-compatible shim body,
// rather than match the signature exactly.
//
// The self type here is a coroutine-closure, not a coroutine, and we never read from
// it because it never has any captures, because this is only true in the Fn/FnMut
// implementation, not the AsyncFn/AsyncFnMut implementation, which is implemented only
// if the coroutine-closure has no captures.
if receiver_by_ref {
// Triple-check that there's no captures here.
assert_eq!(args.as_coroutine_closure().tupled_upvars_ty(), tcx.types.unit);
self_ty = Ty::new_mut_ptr(tcx, self_ty);
}

let poly_sig = args.as_coroutine_closure().coroutine_closure_sig().map_bound(|sig| {
tcx.mk_fn_sig(
[self_ty].into_iter().chain(sig.tupled_inputs_ty.tuple_fields()),
@@ -1112,49 +1091,19 @@ fn build_construct_coroutine_by_move_shim<'tcx>(

let source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
target_kind: ty::ClosureKind::FnOnce,
receiver_by_ref,
});

let body =
new_body(source, IndexVec::from_elem_n(start_block, 1), locals, sig.inputs().len(), span);
dump_mir(tcx, false, "coroutine_closure_by_move", &0, &body, |_, _| Ok(()));

body
}

fn build_construct_coroutine_by_mut_shim<'tcx>(
tcx: TyCtxt<'tcx>,
coroutine_closure_def_id: DefId,
) -> Body<'tcx> {
let mut body = tcx.optimized_mir(coroutine_closure_def_id).clone();
let coroutine_closure_ty = tcx.type_of(coroutine_closure_def_id).instantiate_identity();
let ty::CoroutineClosure(_, args) = *coroutine_closure_ty.kind() else {
bug!();
};
let args = args.as_coroutine_closure();

body.local_decls[RETURN_PLACE].ty =
tcx.instantiate_bound_regions_with_erased(args.coroutine_closure_sig().map_bound(|sig| {
sig.to_coroutine_given_kind_and_upvars(
tcx,
args.parent_args(),
tcx.coroutine_for_closure(coroutine_closure_def_id),
ty::ClosureKind::FnMut,
tcx.lifetimes.re_erased,
args.tupled_upvars_ty(),
args.coroutine_captures_by_ref_ty(),
)
}));
body.local_decls[CAPTURE_STRUCT_LOCAL].ty =
Ty::new_mut_ref(tcx, tcx.lifetimes.re_erased, coroutine_closure_ty);

body.source = MirSource::from_instance(ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
target_kind: ty::ClosureKind::FnMut,
});

body.pass_count = 0;
dump_mir(tcx, false, "coroutine_closure_by_mut", &0, &body, |_, _| Ok(()));
dump_mir(
tcx,
false,
if receiver_by_ref { "coroutine_closure_by_ref" } else { "coroutine_closure_by_move" },
&0,
&body,
|_, _| Ok(()),
);

body
}
3 changes: 1 addition & 2 deletions compiler/rustc_span/src/symbol.rs
Original file line number Diff line number Diff line change
@@ -166,9 +166,8 @@ symbols! {
Break,
C,
CStr,
CallFuture,
CallMutFuture,
CallOnceFuture,
CallRefFuture,
Capture,
Center,
Cleanup,
14 changes: 4 additions & 10 deletions compiler/rustc_symbol_mangling/src/legacy.rs
Original file line number Diff line number Diff line change
@@ -76,16 +76,10 @@ pub(super) fn mangle<'tcx>(
}
// FIXME(async_closures): This shouldn't be needed when we fix
// `Instance::ty`/`Instance::def_id`.
ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. }
| ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind {
ty::ClosureKind::Fn => unreachable!(),
ty::ClosureKind::FnMut => {
printer.write_str("{{fn-mut-shim}}").unwrap();
}
ty::ClosureKind::FnOnce => {
printer.write_str("{{fn-once-shim}}").unwrap();
}
},
ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
| ty::InstanceDef::CoroutineKindShim { .. } => {
printer.write_str("{{fn-once-shim}}").unwrap();
}
_ => {}
}

8 changes: 2 additions & 6 deletions compiler/rustc_symbol_mangling/src/v0.rs
Original file line number Diff line number Diff line change
@@ -46,12 +46,8 @@ pub(super) fn mangle<'tcx>(
ty::InstanceDef::VTableShim(_) => Some("vtable"),
ty::InstanceDef::ReifyShim(_) => Some("reify"),

ty::InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. }
| ty::InstanceDef::CoroutineKindShim { target_kind, .. } => match target_kind {
ty::ClosureKind::Fn => unreachable!(),
ty::ClosureKind::FnMut => Some("fn_mut"),
ty::ClosureKind::FnOnce => Some("fn_once"),
},
ty::InstanceDef::ConstructCoroutineInClosureShim { .. }
| ty::InstanceDef::CoroutineKindShim { .. } => Some("fn_once"),

_ => None,
};
Original file line number Diff line number Diff line change
@@ -414,7 +414,7 @@ impl<'tcx> assembly::GoalKind<'tcx> for NormalizesTo<'tcx> {
),
output_coroutine_ty.into(),
),
sym::CallMutFuture | sym::CallFuture => (
sym::CallRefFuture => (
ty::AliasTy::new(
tcx,
goal.predicate.def_id(),
12 changes: 6 additions & 6 deletions compiler/rustc_trait_selection/src/traits/project.rs
Original file line number Diff line number Diff line change
@@ -1726,7 +1726,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
let sig = args.coroutine_closure_sig().skip_binder();

let term = match item_name {
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => {
sym::CallOnceFuture | sym::CallRefFuture => {
if let Some(closure_kind) = kind_ty.to_opt_closure_kind() {
if !closure_kind.extends(goal_kind) {
bug!("we should not be confirming if the closure kind is not met");
@@ -1787,7 +1787,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
obligation.predicate.def_id,
[self_ty, sig.tupled_inputs_ty],
),
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
sym::CallRefFuture => ty::AliasTy::new(
tcx,
obligation.predicate.def_id,
[ty::GenericArg::from(self_ty), sig.tupled_inputs_ty.into(), env_region.into()],
@@ -1803,7 +1803,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
let sig = bound_sig.skip_binder();

let term = match item_name {
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(),
sym::CallOnceFuture | sym::CallRefFuture => sig.output(),
sym::Output => {
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
let future_output_def_id = tcx
@@ -1822,7 +1822,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
obligation.predicate.def_id,
[self_ty, Ty::new_tup(tcx, sig.inputs())],
),
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
sym::CallRefFuture => ty::AliasTy::new(
tcx,
obligation.predicate.def_id,
[
@@ -1842,7 +1842,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
let sig = bound_sig.skip_binder();

let term = match item_name {
sym::CallOnceFuture | sym::CallMutFuture | sym::CallFuture => sig.output(),
sym::CallOnceFuture | sym::CallRefFuture => sig.output(),
sym::Output => {
let future_trait_def_id = tcx.require_lang_item(LangItem::Future, None);
let future_output_def_id = tcx
@@ -1859,7 +1859,7 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
sym::CallOnceFuture | sym::Output => {
ty::AliasTy::new(tcx, obligation.predicate.def_id, [self_ty, sig.inputs()[0]])
}
sym::CallMutFuture | sym::CallFuture => ty::AliasTy::new(
sym::CallRefFuture => ty::AliasTy::new(
tcx,
obligation.predicate.def_id,
[ty::GenericArg::from(self_ty), sig.inputs()[0].into(), env_region.into()],
25 changes: 16 additions & 9 deletions compiler/rustc_ty_utils/src/abi.rs
Original file line number Diff line number Diff line change
@@ -102,6 +102,7 @@ fn fn_sig_for_fn_abi<'tcx>(
)
}
ty::CoroutineClosure(def_id, args) => {
let coroutine_ty = Ty::new_coroutine_closure(tcx, def_id, args);
let sig = args.as_coroutine_closure().coroutine_closure_sig();
let bound_vars = tcx.mk_bound_variable_kinds_from_iter(
sig.bound_vars().iter().chain(iter::once(ty::BoundVariableKind::Region(ty::BrEnv))),
@@ -111,18 +112,24 @@ fn fn_sig_for_fn_abi<'tcx>(
kind: ty::BoundRegionKind::BrEnv,
};
let env_region = ty::Region::new_bound(tcx, ty::INNERMOST, br);

// When this `CoroutineClosure` comes from a `ConstructCoroutineInClosureShim`,
// make sure we respect the `target_kind` in that shim.
// FIXME(async_closures): This shouldn't be needed, and we should be populating
// a separate def-id for these bodies.
let mut kind = args.as_coroutine_closure().kind();
if let InstanceDef::ConstructCoroutineInClosureShim { target_kind, .. } = instance.def {
kind = target_kind;
}
let mut coroutine_kind = args.as_coroutine_closure().kind();

let env_ty =
tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region);
if let InstanceDef::ConstructCoroutineInClosureShim { receiver_by_ref, .. } =
instance.def
{
coroutine_kind = ty::ClosureKind::FnOnce;

// Implementations of `FnMut` and `Fn` for coroutine-closures
// still take their receiver by ref.
if receiver_by_ref { Ty::new_mut_ptr(tcx, coroutine_ty) } else { coroutine_ty }
} else {
tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region)
};

let sig = sig.skip_binder();
ty::Binder::bind_with_vars(
@@ -132,7 +139,7 @@ fn fn_sig_for_fn_abi<'tcx>(
tcx,
args.as_coroutine_closure().parent_args(),
tcx.coroutine_for_closure(def_id),
kind,
coroutine_kind,
env_region,
args.as_coroutine_closure().tupled_upvars_ty(),
args.as_coroutine_closure().coroutine_captures_by_ref_ty(),
@@ -161,7 +168,7 @@ fn fn_sig_for_fn_abi<'tcx>(
// make sure we respect the `target_kind` in that shim.
// FIXME(async_closures): This shouldn't be needed, and we should be populating
// a separate def-id for these bodies.
if let InstanceDef::CoroutineKindShim { target_kind, .. } = instance.def {
if let InstanceDef::CoroutineKindShim { .. } = instance.def {
// Grab the parent coroutine-closure. It has the same args for the purposes
// of instantiation, so this will be okay to do.
let ty::CoroutineClosure(_, coroutine_closure_args) = *tcx
@@ -181,7 +188,7 @@ fn fn_sig_for_fn_abi<'tcx>(
tcx,
coroutine_closure_args.parent_args(),
did,
target_kind,
ty::ClosureKind::FnOnce,
tcx.lifetimes.re_erased,
coroutine_closure_args.tupled_upvars_ty(),
coroutine_closure_args.coroutine_captures_by_ref_ty(),
35 changes: 15 additions & 20 deletions compiler/rustc_ty_utils/src/instance.rs
Original file line number Diff line number Diff line change
@@ -282,7 +282,7 @@ fn resolve_associated_item<'tcx>(
Some(Instance {
def: ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
target_kind: ty::ClosureKind::FnOnce,
receiver_by_ref: target_kind != ty::ClosureKind::FnOnce,
},
args,
})
@@ -297,25 +297,20 @@ fn resolve_associated_item<'tcx>(
{
match *rcvr_args.type_at(0).kind() {
ty::CoroutineClosure(coroutine_closure_def_id, args) => {
match (target_kind, args.as_coroutine_closure().kind()) {
(ClosureKind::FnOnce | ClosureKind::FnMut, ClosureKind::Fn)
| (ClosureKind::FnOnce, ClosureKind::FnMut) => {
// If we're computing `AsyncFnOnce`/`AsyncFnMut` for a by-ref closure,
// or `AsyncFnOnce` for a by-mut closure, then construct a new body that
// has the right return types.
//
// Specifically, `AsyncFnMut` for a by-ref coroutine-closure just needs
// to have its input and output types fixed (`&mut self` and returning
// `i16` coroutine kind).
Some(Instance {
def: ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
target_kind,
},
args,
})
}
_ => Some(Instance::new(coroutine_closure_def_id, args)),
if target_kind == ClosureKind::FnOnce
&& args.as_coroutine_closure().kind() != ClosureKind::FnOnce
{
// If we're computing `AsyncFnOnce` for a by-ref closure then
// construct a new body that has the right return types.
Some(Instance {
def: ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
receiver_by_ref: false,
},
args,
})
} else {
Some(Instance::new(coroutine_closure_def_id, args))
}
}
ty::Closure(closure_def_id, args) => {
8 changes: 3 additions & 5 deletions library/alloc/src/boxed.rs
Original file line number Diff line number Diff line change
@@ -2042,18 +2042,16 @@ impl<Args: Tuple, F: AsyncFnOnce<Args> + ?Sized, A: Allocator> AsyncFnOnce<Args>

#[unstable(feature = "async_fn_traits", issue = "none")]
impl<Args: Tuple, F: AsyncFnMut<Args> + ?Sized, A: Allocator> AsyncFnMut<Args> for Box<F, A> {
type CallMutFuture<'a> = F::CallMutFuture<'a> where Self: 'a;
type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a;

extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_> {
extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_> {
F::async_call_mut(self, args)
}
}

#[unstable(feature = "async_fn_traits", issue = "none")]
impl<Args: Tuple, F: AsyncFn<Args> + ?Sized, A: Allocator> AsyncFn<Args> for Box<F, A> {
type CallFuture<'a> = F::CallFuture<'a> where Self: 'a;

extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_> {
extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_> {
F::async_call(self, args)
}
}
30 changes: 11 additions & 19 deletions library/core/src/ops/async_function.rs
Original file line number Diff line number Diff line change
@@ -10,15 +10,9 @@ use crate::marker::Tuple;
#[must_use = "async closures are lazy and do nothing unless called"]
#[lang = "async_fn"]
pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
/// Future returned by [`AsyncFn::async_call`].
#[unstable(feature = "async_fn_traits", issue = "none")]
type CallFuture<'a>: Future<Output = Self::Output>
where
Self: 'a;

/// Call the [`AsyncFn`], returning a future which may borrow from the called closure.
#[unstable(feature = "async_fn_traits", issue = "none")]
extern "rust-call" fn async_call(&self, args: Args) -> Self::CallFuture<'_>;
extern "rust-call" fn async_call(&self, args: Args) -> Self::CallRefFuture<'_>;
}

/// An async-aware version of the [`FnMut`](crate::ops::FnMut) trait.
@@ -30,15 +24,15 @@ pub trait AsyncFn<Args: Tuple>: AsyncFnMut<Args> {
#[must_use = "async closures are lazy and do nothing unless called"]
#[lang = "async_fn_mut"]
pub trait AsyncFnMut<Args: Tuple>: AsyncFnOnce<Args> {
/// Future returned by [`AsyncFnMut::async_call_mut`].
/// Future returned by [`AsyncFnMut::async_call_mut`] and [`AsyncFn::async_call`].
#[unstable(feature = "async_fn_traits", issue = "none")]
type CallMutFuture<'a>: Future<Output = Self::Output>
type CallRefFuture<'a>: Future<Output = Self::Output>
where
Self: 'a;

/// Call the [`AsyncFnMut`], returning a future which may borrow from the called closure.
#[unstable(feature = "async_fn_traits", issue = "none")]
extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallMutFuture<'_>;
extern "rust-call" fn async_call_mut(&mut self, args: Args) -> Self::CallRefFuture<'_>;
}

/// An async-aware version of the [`FnOnce`](crate::ops::FnOnce) trait.
@@ -72,9 +66,7 @@ mod impls {
where
F: AsyncFn<A>,
{
type CallFuture<'a> = F::CallFuture<'a> where Self: 'a;

extern "rust-call" fn async_call(&self, args: A) -> Self::CallFuture<'_> {
extern "rust-call" fn async_call(&self, args: A) -> Self::CallRefFuture<'_> {
F::async_call(*self, args)
}
}
@@ -84,9 +76,9 @@ mod impls {
where
F: AsyncFn<A>,
{
type CallMutFuture<'a> = F::CallFuture<'a> where Self: 'a;
type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a;

extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> {
extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallRefFuture<'_> {
F::async_call(*self, args)
}
}
@@ -97,7 +89,7 @@ mod impls {
F: AsyncFn<A>,
{
type Output = F::Output;
type CallOnceFuture = F::CallFuture<'a>;
type CallOnceFuture = F::CallRefFuture<'a>;

extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture {
F::async_call(self, args)
@@ -109,9 +101,9 @@ mod impls {
where
F: AsyncFnMut<A>,
{
type CallMutFuture<'a> = F::CallMutFuture<'a> where Self: 'a;
type CallRefFuture<'a> = F::CallRefFuture<'a> where Self: 'a;

extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallMutFuture<'_> {
extern "rust-call" fn async_call_mut(&mut self, args: A) -> Self::CallRefFuture<'_> {
F::async_call_mut(*self, args)
}
}
@@ -122,7 +114,7 @@ mod impls {
F: AsyncFnMut<A>,
{
type Output = F::Output;
type CallOnceFuture = F::CallMutFuture<'a>;
type CallOnceFuture = F::CallRefFuture<'a>;

extern "rust-call" fn async_call_once(self, args: A) -> Self::CallOnceFuture {
F::async_call_mut(self, args)
Original file line number Diff line number Diff line change
@@ -10,4 +10,4 @@ for creating custom closure-like types that return futures.
[`AsyncFn*`]: ../../std/ops/trait.AsyncFn.html

The main difference to the `Fn*` family of traits is that `AsyncFn` can return a future
that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFn::CallFuture` does).
that borrows from itself (`FnOnce::Output` has no lifetime parameters, while `AsyncFnMut::CallRefFuture` does).
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move

fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_move

fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move

fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:42:33: 42:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10};

bb0: {
_0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) };
_0 = {coroutine@$DIR/async_closure_shims.rs:42:53: 45:10 (#0)} { a: move _2, b: move (_1.0: i32) };
return;
}
}
Original file line number Diff line number Diff line change
@@ -1,10 +1,10 @@
// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_move

fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:39:33: 39:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
fn main::{closure#0}::{closure#0}(_1: {async closure@$DIR/async_closure_shims.rs:42:33: 42:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:42:53: 45:10};

bb0: {
_0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: move _2, b: move (_1.0: i32) };
_0 = {coroutine@$DIR/async_closure_shims.rs:42:53: 45:10 (#0)} { a: move _2, b: move (_1.0: i32) };
return;
}
}

This file was deleted.

This file was deleted.

Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref

fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};

bb0: {
_0 = {coroutine@$DIR/async_closure_shims.rs:49:49: 51:10 (#0)} { a: move _2 };
return;
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,10 @@
// MIR for `main::{closure#0}::{closure#1}` 0 coroutine_closure_by_ref

fn main::{closure#0}::{closure#1}(_1: *mut {async closure@$DIR/async_closure_shims.rs:49:29: 49:48}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:49:49: 51:10};

bb0: {
_0 = {coroutine@$DIR/async_closure_shims.rs:49:49: 51:10 (#0)} { a: move _2 };
return;
}
}
12 changes: 10 additions & 2 deletions tests/mir-opt/async_closure_shims.rs
Original file line number Diff line number Diff line change
@@ -29,10 +29,13 @@ async fn call_once(f: impl AsyncFnOnce(i32)) {
f(1).await;
}

async fn call_normal<F: Future<Output = ()>>(f: &impl Fn(i32) -> F) {
f(1).await;
}

// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_move.0.mir
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}.coroutine_closure_by_mut.0.mir
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_mut.0.mir
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#0}-{closure#0}.coroutine_by_move.0.mir
// EMIT_MIR async_closure_shims.main-{closure#0}-{closure#1}.coroutine_closure_by_ref.0.mir
pub fn main() {
block_on(async {
let b = 2i32;
@@ -42,5 +45,10 @@ pub fn main() {
};
call_mut(&mut async_closure).await;
call_once(async_closure).await;

let async_closure = async move |a: i32| {
let a = &a;
};
call_normal(&async_closure).await;
});
}
4 changes: 2 additions & 2 deletions tests/ui/async-await/async-closures/def-path.stderr
Original file line number Diff line number Diff line change
@@ -5,11 +5,11 @@ LL | let x = async || {};
| -- the expected `async` closure body
LL |
LL | let () = x();
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?7t> upvar_tys=?15t witness=?6t}`
| ^^ --- this expression has type `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t witness=?6t}`
| |
| expected `async` closure body, found `()`
|
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?7t> upvar_tys=?15t witness=?6t}`
= note: expected `async` closure body `{static main::{closure#0}::{closure#0}<?17t> upvar_tys=?16t witness=?6t}`
found unit type `()`

error: aborting due to 1 previous error
3 changes: 0 additions & 3 deletions tests/ui/async-await/async-fn/dyn-pos.rs
Original file line number Diff line number Diff line change
@@ -4,9 +4,6 @@

fn foo(x: &dyn async Fn()) {}
//~^ ERROR the trait `AsyncFn` cannot be made into an object
//~| ERROR the trait `AsyncFn` cannot be made into an object
//~| ERROR the trait `AsyncFn` cannot be made into an object
//~| ERROR the trait `AsyncFn` cannot be made into an object
//~| ERROR the trait `AsyncFnMut` cannot be made into an object
//~| ERROR the trait `AsyncFnMut` cannot be made into an object
//~| ERROR the trait `AsyncFnMut` cannot be made into an object
57 changes: 5 additions & 52 deletions tests/ui/async-await/async-fn/dyn-pos.stderr
Original file line number Diff line number Diff line change
@@ -1,17 +1,3 @@
error[E0038]: the trait `AsyncFn` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
|
LL | fn foo(x: &dyn async Fn()) {}
| ^^^^^^^^^^ `AsyncFn` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>

error[E0038]: the trait `AsyncFnMut` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
|
@@ -21,27 +7,12 @@ LL | fn foo(x: &dyn async Fn()) {}
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
&F
&mut F
std::boxed::Box<F, A>

error[E0038]: the trait `AsyncFn` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
|
LL | fn foo(x: &dyn async Fn()) {}
| ^^^^^^^^^^ `AsyncFn` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFnMut` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
|
@@ -51,28 +22,13 @@ LL | fn foo(x: &dyn async Fn()) {}
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
&F
&mut F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFn` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
|
LL | fn foo(x: &dyn async Fn()) {}
| ^^^^^^^^^^ `AsyncFn` cannot be made into an object
|
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>
= note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no`

error[E0038]: the trait `AsyncFnMut` cannot be made into an object
--> $DIR/dyn-pos.rs:5:16
|
@@ -82,7 +38,7 @@ LL | fn foo(x: &dyn async Fn()) {}
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFnMut` for this new enum and using it instead:
&F
&mut F
@@ -98,14 +54,11 @@ LL | fn foo(x: &dyn async Fn()) {}
note: for a trait to be "object safe" it needs to allow building a vtable to allow the call to be resolvable dynamically; for more information visit <https://doc.rust-lang.org/reference/items/traits.html#object-safety>
--> $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallFuture`
::: $SRC_DIR/core/src/ops/async_function.rs:LL:COL
|
= note: the trait cannot be made into an object because it contains the generic associated type `CallMutFuture`
= note: the trait cannot be made into an object because it contains the generic associated type `CallRefFuture`
= help: the following types implement the trait, consider defining an enum where each variant holds one of these types, implementing `AsyncFn` for this new enum and using it instead:
&F
std::boxed::Box<F, A>

error: aborting due to 7 previous errors
error: aborting due to 4 previous errors

For more information about this error, try `rustc --explain E0038`.