Only split by-ref/by-move futures for async closures

This commit is contained in:
Michael Goulet 2024-02-13 15:29:50 +00:00
parent e760daa6a7
commit 05116c5c30
33 changed files with 119 additions and 432 deletions

View File

@ -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

View File

@ -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,
),

View File

@ -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,
)

View File

@ -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),
);
}

View File

@ -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)

View File

@ -345,8 +345,10 @@ 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,
} |
ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } |
ty::InstanceDef::DropGlue(_def_id, None) => {}
ty::InstanceDef::FnPtrShim(_def_id, ty) |

View File

@ -90,16 +90,12 @@ 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,
},
ConstructCoroutineInClosureShim { coroutine_closure_def_id: DefId },
/// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce`
/// is called on a coroutine-closure whose closure kind greater than `FnOnce`, or
@ -107,7 +103,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 +188,8 @@ impl<'tcx> InstanceDef<'tcx> {
| 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::CoroutineKindShim { coroutine_def_id: def_id }
| InstanceDef::DropGlue(def_id, _)
| InstanceDef::CloneShim(def_id, _)
| InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
@ -651,10 +646,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,
})
}

View File

@ -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,21 @@ 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.
///
/// 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

View File

@ -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);
}
}
}

View File

@ -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);
}
}
}

View File

@ -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};
@ -70,39 +70,13 @@ fn make_shim<'tcx>(tcx: TyCtxt<'tcx>, instance: ty::InstanceDef<'tcx>) -> Body<'
build_call_shim(tcx, instance, Some(Adjustment::RefMut), CallKind::Direct(call_mut))
}
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)
}
},
ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id } => {
build_construct_coroutine_by_move_shim(tcx, coroutine_closure_def_id)
}
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 +97,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);
@ -1112,7 +1076,6 @@ 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,
});
let body =
@ -1121,40 +1084,3 @@ fn build_construct_coroutine_by_move_shim<'tcx>(
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(()));
body
}

View File

@ -166,9 +166,8 @@ symbols! {
Break,
C,
CStr,
CallFuture,
CallMutFuture,
CallOnceFuture,
CallRefFuture,
Capture,
Center,
Cleanup,

View File

@ -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();
}
_ => {}
}

View File

@ -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,
};

View File

@ -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(),

View File

@ -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()],

View File

@ -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,17 @@ 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();
if let InstanceDef::ConstructCoroutineInClosureShim { .. } = instance.def {
coroutine_kind = ty::ClosureKind::FnOnce;
}
let env_ty =
tcx.closure_env_ty(Ty::new_coroutine_closure(tcx, def_id, args), kind, env_region);
let env_ty = tcx.closure_env_ty(coroutine_ty, coroutine_kind, env_region);
let sig = sig.skip_binder();
ty::Binder::bind_with_vars(
@ -132,7 +132,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 +161,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 +181,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(),

View File

@ -282,7 +282,6 @@ fn resolve_associated_item<'tcx>(
Some(Instance {
def: ty::InstanceDef::ConstructCoroutineInClosureShim {
coroutine_closure_def_id,
target_kind: ty::ClosureKind::FnOnce,
},
args,
})
@ -297,25 +296,19 @@ 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,
},
args,
})
} else {
Some(Instance::new(coroutine_closure_def_id, args))
}
}
ty::Closure(closure_def_id, args) => {

View File

@ -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)
}
}

View File

@ -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)

View File

@ -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).

View File

@ -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:37:53: 40:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;

View File

@ -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:37:53: 40:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;

View File

@ -1,47 +0,0 @@
// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut
fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
debug a => (_1.0: i32);
debug b => (*(_1.1: &i32));
let mut _0: ();
let _3: i32;
scope 1 {
debug a => _3;
let _4: &i32;
scope 2 {
debug a => _4;
let _5: &i32;
scope 3 {
debug b => _5;
}
}
}
bb0: {
StorageLive(_3);
_3 = (_1.0: i32);
FakeRead(ForLet(None), _3);
StorageLive(_4);
_4 = &_3;
FakeRead(ForLet(None), _4);
StorageLive(_5);
_5 = &(*(_1.1: &i32));
FakeRead(ForLet(None), _5);
_0 = const ();
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
drop(_1) -> [return: bb1, unwind: bb2];
}
bb1: {
return;
}
bb2 (cleanup): {
resume;
}
}

View File

@ -1,47 +0,0 @@
// MIR for `main::{closure#0}::{closure#0}::{closure#0}` 0 coroutine_by_mut
fn main::{closure#0}::{closure#0}::{closure#0}(_1: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10}, _2: ResumeTy) -> ()
yields ()
{
debug _task_context => _2;
debug a => (_1.0: i32);
debug b => (*(_1.1: &i32));
let mut _0: ();
let _3: i32;
scope 1 {
debug a => _3;
let _4: &i32;
scope 2 {
debug a => _4;
let _5: &i32;
scope 3 {
debug b => _5;
}
}
}
bb0: {
StorageLive(_3);
_3 = (_1.0: i32);
FakeRead(ForLet(None), _3);
StorageLive(_4);
_4 = &_3;
FakeRead(ForLet(None), _4);
StorageLive(_5);
_5 = &(*(_1.1: &i32));
FakeRead(ForLet(None), _5);
_0 = const ();
StorageDead(_5);
StorageDead(_4);
StorageDead(_3);
drop(_1) -> [return: bb1, unwind: bb2];
}
bb1: {
return;
}
bb2 (cleanup): {
resume;
}
}

View File

@ -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:37:33: 37:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:37:53: 40: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:37:53: 40:10 (#0)} { a: move _2, b: move (_1.0: i32) };
return;
}
}

View File

@ -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:37:33: 37:52}, _2: i32) -> {async closure body@$DIR/async_closure_shims.rs:37:53: 40:10} {
let mut _0: {async closure body@$DIR/async_closure_shims.rs:37:53: 40: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:37:53: 40:10 (#0)} { a: move _2, b: move (_1.0: i32) };
return;
}
}

View File

@ -1,16 +0,0 @@
// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut
fn main::{closure#0}::{closure#0}(_1: &mut {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} {
debug a => _2;
debug b => ((*_1).0: i32);
let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
let mut _3: &i32;
bb0: {
StorageLive(_3);
_3 = &((*_1).0: i32);
_0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 };
StorageDead(_3);
return;
}
}

View File

@ -1,16 +0,0 @@
// MIR for `main::{closure#0}::{closure#0}` 0 coroutine_closure_by_mut
fn main::{closure#0}::{closure#0}(_1: &mut {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} {
debug a => _2;
debug b => ((*_1).0: i32);
let mut _0: {async closure body@$DIR/async_closure_shims.rs:39:53: 42:10};
let mut _3: &i32;
bb0: {
StorageLive(_3);
_3 = &((*_1).0: i32);
_0 = {coroutine@$DIR/async_closure_shims.rs:39:53: 42:10 (#0)} { a: _2, b: move _3 };
StorageDead(_3);
return;
}
}

View File

@ -30,8 +30,6 @@ async fn call_once(f: impl AsyncFnOnce(i32)) {
}
// 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
pub fn main() {
block_on(async {

View File

@ -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

View File

@ -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

View File

@ -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`.