Skip to content

Commit c86f3ac

Browse files
committed
Auto merge of rust-lang#120717 - compiler-errors:cap-closure-kind, r=oli-obk
For async closures, cap closure kind, get rid of `by_mut_body` Right now we have three `AsyncFn*` traits, and three corresponding futures that are returned by the `call_*` functions for them. This is fine, but it is a bit excessive, since the future returned by `AsyncFn` and `AsyncFnMut` are identical. Really, the only distinction we need to make with these bodies is "by ref" and "by move". This PR removes `AsyncFn::CallFuture` and renames `AsyncFnMut::CallMutFuture` to `AsyncFnMut::CallRefFuture`. This simplifies MIR building for async closures, since we don't need to build an extra "by mut" body, but just a "by move" body which is materially different. We need to do a bit of delicate handling of the ClosureKind for async closures, since we need to "cap" it to `AsyncFnMut` in some cases when we only care about what body we're looking for. This also fixes a bug where `<{async closure} as Fn>::call` was returning a body that takes the async-closure receiver *by move*. This also helps align the `AsyncFn` traits to the `LendingFn` traits' eventual designs.
2 parents 0f706af + 541858e commit c86f3ac

File tree

35 files changed

+192
-429
lines changed

35 files changed

+192
-429
lines changed

Diff for: compiler/rustc_borrowck/src/type_check/input_output.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -87,7 +87,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
8787
self.tcx(),
8888
ty::CoroutineArgsParts {
8989
parent_args: args.parent_args(),
90-
kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()),
90+
kind_ty: Ty::from_coroutine_closure_kind(self.tcx(), args.kind()),
9191
return_ty: user_provided_sig.output(),
9292
tupled_upvars_ty,
9393
// For async closures, none of these can be annotated, so just fill

Diff for: compiler/rustc_hir_typeck/src/callee.rs

+9-5
Original file line numberDiff line numberDiff line change
@@ -184,16 +184,20 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
184184
kind: TypeVariableOriginKind::TypeInference,
185185
span: callee_expr.span,
186186
});
187+
// We may actually receive a coroutine back whose kind is different
188+
// from the closure that this dispatched from. This is because when
189+
// we have no captures, we automatically implement `FnOnce`. This
190+
// impl forces the closure kind to `FnOnce` i.e. `u8`.
191+
let kind_ty = self.next_ty_var(TypeVariableOrigin {
192+
kind: TypeVariableOriginKind::TypeInference,
193+
span: callee_expr.span,
194+
});
187195
let call_sig = self.tcx.mk_fn_sig(
188196
[coroutine_closure_sig.tupled_inputs_ty],
189197
coroutine_closure_sig.to_coroutine(
190198
self.tcx,
191199
closure_args.parent_args(),
192-
// Inherit the kind ty of the closure, since we're calling this
193-
// coroutine with the most relaxed `AsyncFn*` trait that we can.
194-
// We don't necessarily need to do this here, but it saves us
195-
// computing one more infer var that will get constrained later.
196-
closure_args.kind_ty(),
200+
kind_ty,
197201
self.tcx.coroutine_for_closure(def_id),
198202
tupled_upvars_ty,
199203
),

Diff for: compiler/rustc_hir_typeck/src/closure.rs

+5-1
Original file line numberDiff line numberDiff line change
@@ -262,6 +262,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
262262
},
263263
);
264264

265+
let coroutine_kind_ty = self.next_ty_var(TypeVariableOrigin {
266+
kind: TypeVariableOriginKind::ClosureSynthetic,
267+
span: expr_span,
268+
});
265269
let coroutine_upvars_ty = self.next_ty_var(TypeVariableOrigin {
266270
kind: TypeVariableOriginKind::ClosureSynthetic,
267271
span: expr_span,
@@ -279,7 +283,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
279283
sig.to_coroutine(
280284
tcx,
281285
parent_args,
282-
closure_kind_ty,
286+
coroutine_kind_ty,
283287
tcx.coroutine_for_closure(expr_def_id),
284288
coroutine_upvars_ty,
285289
)

Diff for: compiler/rustc_hir_typeck/src/upvar.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -410,7 +410,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
410410
self.demand_eqtype(
411411
span,
412412
coroutine_args.as_coroutine().kind_ty(),
413-
Ty::from_closure_kind(self.tcx, closure_kind),
413+
Ty::from_coroutine_closure_kind(self.tcx, closure_kind),
414414
);
415415
}
416416

Diff for: compiler/rustc_middle/src/mir/mod.rs

-12
Original file line numberDiff line numberDiff line change
@@ -278,13 +278,6 @@ pub struct CoroutineInfo<'tcx> {
278278
/// using `run_passes`.
279279
pub by_move_body: Option<Body<'tcx>>,
280280

281-
/// The body of the coroutine, modified to take its upvars by mutable ref rather than by
282-
/// immutable ref.
283-
///
284-
/// FIXME(async_closures): This is literally the same body as the parent body. Find a better
285-
/// way to represent the by-mut signature (or cap the closure-kind of the coroutine).
286-
pub by_mut_body: Option<Body<'tcx>>,
287-
288281
/// The layout of a coroutine. This field is populated after the state transform pass.
289282
pub coroutine_layout: Option<CoroutineLayout<'tcx>>,
290283

@@ -305,7 +298,6 @@ impl<'tcx> CoroutineInfo<'tcx> {
305298
yield_ty: Some(yield_ty),
306299
resume_ty: Some(resume_ty),
307300
by_move_body: None,
308-
by_mut_body: None,
309301
coroutine_drop: None,
310302
coroutine_layout: None,
311303
}
@@ -628,10 +620,6 @@ impl<'tcx> Body<'tcx> {
628620
self.coroutine.as_ref()?.by_move_body.as_ref()
629621
}
630622

631-
pub fn coroutine_by_mut_body(&self) -> Option<&Body<'tcx>> {
632-
self.coroutine.as_ref()?.by_mut_body.as_ref()
633-
}
634-
635623
#[inline]
636624
pub fn coroutine_kind(&self) -> Option<CoroutineKind> {
637625
self.coroutine.as_ref().map(|coroutine| coroutine.coroutine_kind)

Diff for: compiler/rustc_middle/src/mir/visit.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -345,8 +345,11 @@ macro_rules! make_mir_visitor {
345345
ty::InstanceDef::Virtual(_def_id, _) |
346346
ty::InstanceDef::ThreadLocalShim(_def_id) |
347347
ty::InstanceDef::ClosureOnceShim { call_once: _def_id, track_caller: _ } |
348-
ty::InstanceDef::ConstructCoroutineInClosureShim { coroutine_closure_def_id: _def_id, target_kind: _ } |
349-
ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id, target_kind: _ } |
348+
ty::InstanceDef::ConstructCoroutineInClosureShim {
349+
coroutine_closure_def_id: _def_id,
350+
receiver_by_ref: _,
351+
} |
352+
ty::InstanceDef::CoroutineKindShim { coroutine_def_id: _def_id } |
350353
ty::InstanceDef::DropGlue(_def_id, None) => {}
351354

352355
ty::InstanceDef::FnPtrShim(_def_id, ty) |

Diff for: compiler/rustc_middle/src/ty/instance.rs

+11-10
Original file line numberDiff line numberDiff line change
@@ -90,15 +90,19 @@ pub enum InstanceDef<'tcx> {
9090
/// and dispatch to the `FnMut::call_mut` instance for the closure.
9191
ClosureOnceShim { call_once: DefId, track_caller: bool },
9292

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

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

112116
/// Compiler-generated accessor for thread locals which returns a reference to the thread local
113117
/// the `DefId` defines. This is used to export thread locals from dylibs on platforms lacking
@@ -192,9 +196,9 @@ impl<'tcx> InstanceDef<'tcx> {
192196
| InstanceDef::ClosureOnceShim { call_once: def_id, track_caller: _ }
193197
| ty::InstanceDef::ConstructCoroutineInClosureShim {
194198
coroutine_closure_def_id: def_id,
195-
target_kind: _,
199+
receiver_by_ref: _,
196200
}
197-
| ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id, target_kind: _ }
201+
| ty::InstanceDef::CoroutineKindShim { coroutine_def_id: def_id }
198202
| InstanceDef::DropGlue(def_id, _)
199203
| InstanceDef::CloneShim(def_id, _)
200204
| InstanceDef::FnPtrAddrShim(def_id, _) => def_id,
@@ -651,10 +655,7 @@ impl<'tcx> Instance<'tcx> {
651655
Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args })
652656
} else {
653657
Some(Instance {
654-
def: ty::InstanceDef::CoroutineKindShim {
655-
coroutine_def_id,
656-
target_kind: args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
657-
},
658+
def: ty::InstanceDef::CoroutineKindShim { coroutine_def_id },
658659
args,
659660
})
660661
}

Diff for: compiler/rustc_middle/src/ty/sty.rs

+20-1
Original file line numberDiff line numberDiff line change
@@ -483,7 +483,7 @@ impl<'tcx> CoroutineClosureSignature<'tcx> {
483483
self.to_coroutine(
484484
tcx,
485485
parent_args,
486-
Ty::from_closure_kind(tcx, goal_kind),
486+
Ty::from_coroutine_closure_kind(tcx, goal_kind),
487487
coroutine_def_id,
488488
tupled_upvars_ty,
489489
)
@@ -2456,6 +2456,25 @@ impl<'tcx> Ty<'tcx> {
24562456
}
24572457
}
24582458

2459+
/// Like [`Ty::to_opt_closure_kind`], but it caps the "maximum" closure kind
2460+
/// to `FnMut`. This is because although we have three capability states,
2461+
/// `AsyncFn`/`AsyncFnMut`/`AsyncFnOnce`, we only need to distinguish two coroutine
2462+
/// bodies: by-ref and by-value.
2463+
///
2464+
/// See the definition of `AsyncFn` and `AsyncFnMut` and the `CallRefFuture`
2465+
/// associated type for why we don't distinguish [`ty::ClosureKind::Fn`] and
2466+
/// [`ty::ClosureKind::FnMut`] for the purpose of the generated MIR bodies.
2467+
///
2468+
/// This method should be used when constructing a `Coroutine` out of a
2469+
/// `CoroutineClosure`, when the `Coroutine`'s `kind` field is being populated
2470+
/// directly from the `CoroutineClosure`'s `kind`.
2471+
pub fn from_coroutine_closure_kind(tcx: TyCtxt<'tcx>, kind: ty::ClosureKind) -> Ty<'tcx> {
2472+
match kind {
2473+
ty::ClosureKind::Fn | ty::ClosureKind::FnMut => tcx.types.i16,
2474+
ty::ClosureKind::FnOnce => tcx.types.i32,
2475+
}
2476+
}
2477+
24592478
/// Fast path helper for testing if a type is `Sized`.
24602479
///
24612480
/// Returning true means the type is known to be sized. Returning

Diff for: compiler/rustc_mir_transform/src/coroutine/by_move_body.rs

-35
Original file line numberDiff line numberDiff line change
@@ -67,45 +67,10 @@ impl<'tcx> MirPass<'tcx> for ByMoveBody {
6767
by_move_body.source = mir::MirSource {
6868
instance: InstanceDef::CoroutineKindShim {
6969
coroutine_def_id: coroutine_def_id.to_def_id(),
70-
target_kind: ty::ClosureKind::FnOnce,
7170
},
7271
promoted: None,
7372
};
7473
body.coroutine.as_mut().unwrap().by_move_body = Some(by_move_body);
75-
76-
// If this is coming from an `AsyncFn` coroutine-closure, we must also create a by-mut body.
77-
// This is actually just a copy of the by-ref body, but with a different self type.
78-
// FIXME(async_closures): We could probably unify this with the by-ref body somehow.
79-
if coroutine_kind == ty::ClosureKind::Fn {
80-
let by_mut_coroutine_ty = Ty::new_coroutine(
81-
tcx,
82-
coroutine_def_id.to_def_id(),
83-
ty::CoroutineArgs::new(
84-
tcx,
85-
ty::CoroutineArgsParts {
86-
parent_args: args.as_coroutine().parent_args(),
87-
kind_ty: Ty::from_closure_kind(tcx, ty::ClosureKind::FnMut),
88-
resume_ty: args.as_coroutine().resume_ty(),
89-
yield_ty: args.as_coroutine().yield_ty(),
90-
return_ty: args.as_coroutine().return_ty(),
91-
witness: args.as_coroutine().witness(),
92-
tupled_upvars_ty: args.as_coroutine().tupled_upvars_ty(),
93-
},
94-
)
95-
.args,
96-
);
97-
let mut by_mut_body = body.clone();
98-
by_mut_body.local_decls[ty::CAPTURE_STRUCT_LOCAL].ty = by_mut_coroutine_ty;
99-
dump_mir(tcx, false, "coroutine_by_mut", &0, &by_mut_body, |_, _| Ok(()));
100-
by_mut_body.source = mir::MirSource {
101-
instance: InstanceDef::CoroutineKindShim {
102-
coroutine_def_id: coroutine_def_id.to_def_id(),
103-
target_kind: ty::ClosureKind::FnMut,
104-
},
105-
promoted: None,
106-
};
107-
body.coroutine.as_mut().unwrap().by_mut_body = Some(by_mut_body);
108-
}
10974
}
11075
}
11176

Diff for: compiler/rustc_mir_transform/src/pass_manager.rs

-3
Original file line numberDiff line numberDiff line change
@@ -186,9 +186,6 @@ fn run_passes_inner<'tcx>(
186186
if let Some(by_move_body) = coroutine.by_move_body.as_mut() {
187187
run_passes_inner(tcx, by_move_body, passes, phase_change, validate_each);
188188
}
189-
if let Some(by_mut_body) = coroutine.by_mut_body.as_mut() {
190-
run_passes_inner(tcx, by_mut_body, passes, phase_change, validate_each);
191-
}
192189
}
193190
}
194191

0 commit comments

Comments
 (0)