Skip to content

Commit 6a12c64

Browse files
More comments, final tweaks
1 parent 95279ca commit 6a12c64

File tree

20 files changed

+169
-42
lines changed

20 files changed

+169
-42
lines changed

compiler/rustc_ast_lowering/src/expr.rs

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1075,6 +1075,9 @@ impl<'hir> LoweringContext<'_, 'hir> {
10751075
body,
10761076
fn_decl_span: self.lower_span(fn_decl_span),
10771077
fn_arg_span: Some(self.lower_span(fn_arg_span)),
1078+
// Lower this as a `CoroutineClosure`. That will ensure that HIR typeck
1079+
// knows that a `FnDecl` output type like `-> &str` actually means
1080+
// "coroutine that returns &str", rather than directly returning a `&str`.
10781081
kind: hir::ClosureKind::CoroutineClosure(hir::CoroutineDesugaring::Async),
10791082
constness: hir::Constness::NotConst,
10801083
});

compiler/rustc_borrowck/src/type_check/input_output.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -61,6 +61,8 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
6161
)),
6262
"this needs to be modified if we're lowering non-async closures"
6363
);
64+
// Make sure to use the args from `DefiningTy` so the right NLL region vids are prepopulated
65+
// into the type.
6466
let args = args.as_coroutine_closure();
6567
let tupled_upvars_ty = ty::CoroutineClosureSignature::tupled_upvars_by_closure_kind(
6668
self.tcx(),
@@ -87,11 +89,13 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
8789
ty::CoroutineArgsParts {
8890
parent_args: args.parent_args(),
8991
kind_ty: Ty::from_closure_kind(self.tcx(), args.kind()),
92+
return_ty: user_provided_sig.output(),
93+
tupled_upvars_ty,
94+
// For async closures, none of these can be annotated, so just fill
95+
// them with fresh ty vars.
9096
resume_ty: next_ty_var(),
9197
yield_ty: next_ty_var(),
9298
witness: next_ty_var(),
93-
return_ty: user_provided_sig.output(),
94-
tupled_upvars_ty: tupled_upvars_ty,
9599
},
96100
)
97101
.args,

compiler/rustc_borrowck/src/universal_regions.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -720,6 +720,14 @@ impl<'cx, 'tcx> UniversalRegionsBuilder<'cx, 'tcx> {
720720
ty::Binder::dummy(inputs_and_output)
721721
}
722722

723+
// Construct the signature of the CoroutineClosure for the purposes of borrowck.
724+
// This is pretty straightforward -- we:
725+
// 1. first grab the `coroutine_closure_sig`,
726+
// 2. compute the self type (`&`/`&mut`/no borrow),
727+
// 3. flatten the tupled_input_tys,
728+
// 4. construct the correct generator type to return with
729+
// `CoroutineClosureSignature::to_coroutine_given_kind_and_upvars`.
730+
// Then we wrap it all up into a list of inputs and output.
723731
DefiningTy::CoroutineClosure(def_id, args) => {
724732
assert_eq!(self.mir_def.to_def_id(), def_id);
725733
let closure_sig = args.as_coroutine_closure().coroutine_closure_sig();

compiler/rustc_hir_analysis/src/collect.rs

Lines changed: 2 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -1533,15 +1533,8 @@ fn coroutine_kind(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Option<hir::CoroutineK
15331533
}
15341534

15351535
fn coroutine_for_closure(tcx: TyCtxt<'_>, def_id: LocalDefId) -> DefId {
1536-
let Node::Expr(&hir::Expr {
1537-
kind:
1538-
hir::ExprKind::Closure(&rustc_hir::Closure {
1539-
kind: hir::ClosureKind::CoroutineClosure(_),
1540-
body,
1541-
..
1542-
}),
1543-
..
1544-
}) = tcx.hir_node_by_def_id(def_id)
1536+
let &rustc_hir::Closure { kind: hir::ClosureKind::CoroutineClosure(_), body, .. } =
1537+
tcx.hir_node_by_def_id(def_id).expect_closure()
15451538
else {
15461539
bug!()
15471540
};

compiler/rustc_hir_typeck/src/callee.rs

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -165,6 +165,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
165165
return Some(CallStep::DeferredClosure(def_id, closure_sig));
166166
}
167167

168+
// When calling a `CoroutineClosure` that is local to the body, we will
169+
// not know what its `closure_kind` is yet. Instead, just fill in the
170+
// signature with an infer var for the `tupled_upvars_ty` of the coroutine,
171+
// and record a deferred call resolution which will constrain that var
172+
// as part of `AsyncFn*` trait confirmation.
168173
ty::CoroutineClosure(def_id, args) if self.closure_kind(adjusted_ty).is_none() => {
169174
let def_id = def_id.expect_local();
170175
let closure_args = args.as_coroutine_closure();
@@ -182,6 +187,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
182187
coroutine_closure_sig.to_coroutine(
183188
self.tcx,
184189
closure_args.parent_args(),
190+
// Inherit the kind ty of the closure, since we're calling this
191+
// coroutine with the most relaxed `AsyncFn*` trait that we can.
192+
// We don't necessarily need to do this here, but it saves us
193+
// computing one more infer var that will get constrained later.
185194
closure_args.kind_ty(),
186195
self.tcx.coroutine_for_closure(def_id),
187196
tupled_upvars_ty,

compiler/rustc_hir_typeck/src/closure.rs

Lines changed: 27 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -175,6 +175,10 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
175175
interior,
176176
));
177177

178+
// Coroutines that come from coroutine closures have not yet determined
179+
// their kind ty, so make a fresh infer var which will be constrained
180+
// later during upvar analysis. Regular coroutines always have the kind
181+
// ty of `().`
178182
let kind_ty = match kind {
179183
hir::CoroutineKind::Desugared(_, hir::CoroutineSource::Closure) => self
180184
.next_ty_var(TypeVariableOrigin {
@@ -203,6 +207,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
203207
)
204208
}
205209
hir::ClosureKind::CoroutineClosure(kind) => {
210+
// async closures always return the type ascribed after the `->` (if present),
211+
// and yield `()`.
206212
let (bound_return_ty, bound_yield_ty) = match kind {
207213
hir::CoroutineDesugaring::Async => {
208214
(bound_sig.skip_binder().output(), tcx.types.unit)
@@ -211,6 +217,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
211217
todo!("`gen` and `async gen` closures not supported yet")
212218
}
213219
};
220+
// Compute all of the variables that will be used to populate the coroutine.
214221
let resume_ty = self.next_ty_var(TypeVariableOrigin {
215222
kind: TypeVariableOriginKind::ClosureSynthetic,
216223
span: expr_span,
@@ -258,20 +265,28 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
258265
kind: TypeVariableOriginKind::ClosureSynthetic,
259266
span: expr_span,
260267
});
268+
269+
// We need to turn the liberated signature that we got from HIR, which
270+
// looks something like `|Args...| -> T`, into a signature that is suitable
271+
// for type checking the inner body of the closure, which always returns a
272+
// coroutine. To do so, we use the `CoroutineClosureSignature` to compute
273+
// the coroutine type, filling in the tupled_upvars_ty and kind_ty with infer
274+
// vars which will get constrained during upvar analysis.
275+
let coroutine_output_ty = tcx.liberate_late_bound_regions(
276+
expr_def_id.to_def_id(),
277+
closure_args.coroutine_closure_sig().map_bound(|sig| {
278+
sig.to_coroutine(
279+
tcx,
280+
parent_args,
281+
closure_kind_ty,
282+
tcx.coroutine_for_closure(expr_def_id),
283+
coroutine_upvars_ty,
284+
)
285+
}),
286+
);
261287
liberated_sig = tcx.mk_fn_sig(
262288
liberated_sig.inputs().iter().copied(),
263-
tcx.liberate_late_bound_regions(
264-
expr_def_id.to_def_id(),
265-
closure_args.coroutine_closure_sig().map_bound(|sig| {
266-
sig.to_coroutine(
267-
tcx,
268-
parent_args,
269-
closure_kind_ty,
270-
tcx.coroutine_for_closure(expr_def_id),
271-
coroutine_upvars_ty,
272-
)
273-
}),
274-
),
289+
coroutine_output_ty,
275290
liberated_sig.c_variadic,
276291
liberated_sig.unsafety,
277292
liberated_sig.abi,

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -333,7 +333,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
333333
continue;
334334
}
335335

336-
// For this check, we do *not* want to treat async coroutine-closures (async blocks)
336+
// For this check, we do *not* want to treat async coroutine closures (async blocks)
337337
// as proper closures. Doing so would regress type inference when feeding
338338
// the return value of an argument-position async block to an argument-position
339339
// closure wrapped in a block.

compiler/rustc_hir_typeck/src/upvar.rs

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
336336
}
337337
}
338338

339+
// For coroutine-closures, we additionally must compute the
340+
// `coroutine_captures_by_ref_ty` type, which is used to generate the by-ref
341+
// version of the coroutine-closure's output coroutine.
339342
if let UpvarArgs::CoroutineClosure(args) = args {
340343
let closure_env_region: ty::Region<'_> = ty::Region::new_bound(
341344
self.tcx,
@@ -353,7 +356,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
353356
self.tcx.coroutine_for_closure(closure_def_id).expect_local(),
354357
)
355358
// Skip the captures that are just moving the closure's args
356-
// into the coroutine. These are always by move.
359+
// into the coroutine. These are always by move, and we append
360+
// those later in the `CoroutineClosureSignature` helper functions.
357361
.skip(
358362
args.as_coroutine_closure()
359363
.coroutine_closure_sig()
@@ -365,6 +369,9 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
365369
.map(|captured_place| {
366370
let upvar_ty = captured_place.place.ty();
367371
let capture = captured_place.info.capture_kind;
372+
// Not all upvars are captured by ref, so use
373+
// `apply_capture_kind_on_capture_ty` to ensure that we
374+
// compute the right captured type.
368375
apply_capture_kind_on_capture_ty(
369376
self.tcx,
370377
upvar_ty,
@@ -394,6 +401,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
394401
coroutine_captures_by_ref_ty,
395402
);
396403

404+
// Additionally, we can now constrain the coroutine's kind type.
397405
let ty::Coroutine(_, coroutine_args) =
398406
*self.typeck_results.borrow().expr_ty(body.value).kind()
399407
else {

compiler/rustc_middle/src/ty/flags.rs

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -145,11 +145,11 @@ impl FlagComputation {
145145
self.flags -= TypeFlags::STILL_FURTHER_SPECIALIZABLE;
146146
}
147147

148-
self.add_ty(args.signature_parts_ty());
149-
self.add_ty(args.coroutine_witness_ty());
150-
self.add_ty(args.coroutine_captures_by_ref_ty());
151148
self.add_ty(args.kind_ty());
149+
self.add_ty(args.signature_parts_ty());
152150
self.add_ty(args.tupled_upvars_ty());
151+
self.add_ty(args.coroutine_captures_by_ref_ty());
152+
self.add_ty(args.coroutine_witness_ty());
153153
}
154154

155155
&ty::Bound(debruijn, _) => {

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -646,9 +646,16 @@ impl<'tcx> Instance<'tcx> {
646646
bug!()
647647
};
648648

649+
// If the closure's kind ty disagrees with the identity closure's kind ty,
650+
// then this must be a coroutine generated by one of the `ConstructCoroutineInClosureShim`s.
649651
if args.as_coroutine().kind_ty() == id_args.as_coroutine().kind_ty() {
650652
Some(Instance { def: ty::InstanceDef::Item(coroutine_def_id), args })
651653
} else {
654+
assert_eq!(
655+
args.as_coroutine().kind_ty().to_opt_closure_kind().unwrap(),
656+
ty::ClosureKind::FnOnce,
657+
"FIXME(async_closures): Generate a by-mut body here."
658+
);
652659
Some(Instance {
653660
def: ty::InstanceDef::CoroutineByMoveShim { coroutine_def_id },
654661
args,

0 commit comments

Comments
 (0)