Skip to content
This repository was archived by the owner on May 28, 2025. It is now read-only.

Commit 881b6b5

Browse files
Bless tests, add comments
1 parent 427896d commit 881b6b5

File tree

28 files changed

+201
-126
lines changed

28 files changed

+201
-126
lines changed

compiler/rustc_borrowck/src/type_check/input_output.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,9 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
4747
user_provided_sig,
4848
);
4949

50-
// FIXME(async_closures): We must apply the same transformation to our
51-
// signature here as we do during closure checking.
50+
// FIXME(async_closures): It's kind of wacky that we must apply this
51+
// transformation here, since we do the same thing in HIR typeck.
52+
// Maybe we could just fix up the canonicalized signature during HIR typeck?
5253
if let DefiningTy::CoroutineClosure(_, args) =
5354
self.borrowck_context.universal_regions.defining_ty
5455
{

compiler/rustc_borrowck/src/universal_regions.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -98,7 +98,10 @@ pub enum DefiningTy<'tcx> {
9898
Coroutine(DefId, GenericArgsRef<'tcx>),
9999

100100
/// The MIR is a special kind of closure that returns coroutines.
101-
/// TODO: describe how to make the sig...
101+
///
102+
/// See the documentation on `CoroutineClosureSignature` for details
103+
/// on how to construct the callable signature of the coroutine from
104+
/// its args.
102105
CoroutineClosure(DefId, GenericArgsRef<'tcx>),
103106

104107
/// The MIR is a fn item with the given `DefId` and args. The signature

compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs

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

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

compiler/rustc_middle/src/mir/mod.rs

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -262,8 +262,16 @@ pub struct CoroutineInfo<'tcx> {
262262
/// Coroutine drop glue. This field is populated after the state transform pass.
263263
pub coroutine_drop: Option<Body<'tcx>>,
264264

265-
/// The body of the coroutine, modified to take its upvars by move.
266-
/// TODO:
265+
/// The body of the coroutine, modified to take its upvars by move rather than by ref.
266+
///
267+
/// This is used by coroutine-closures, which must return a different flavor of coroutine
268+
/// when called using `AsyncFnOnce::call_once`. It is produced by the `ByMoveBody` which
269+
/// is run right after building the initial MIR, and will only be populated for coroutines
270+
/// which come out of the async closure desugaring.
271+
///
272+
/// This body should be processed in lockstep with the containing body -- any optimization
273+
/// passes, etc, should be applied to this body as well. This is done automatically if
274+
/// using `run_passes`.
267275
pub by_move_body: Option<Body<'tcx>>,
268276

269277
/// The layout of a coroutine. This field is populated after the state transform pass.

compiler/rustc_middle/src/query/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -756,7 +756,7 @@ rustc_queries! {
756756
}
757757

758758
query coroutine_for_closure(def_id: DefId) -> DefId {
759-
desc { |_tcx| "TODO" }
759+
desc { |_tcx| "Given a coroutine-closure def id, return the def id of the coroutine returned by it" }
760760
separate_provide_extern
761761
}
762762

compiler/rustc_middle/src/traits/select.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,9 @@ pub enum SelectionCandidate<'tcx> {
138138
/// generated for an `async ||` expression.
139139
AsyncClosureCandidate,
140140

141-
// TODO:
141+
/// Implementation of the the `AsyncFnKindHelper` helper trait, which
142+
/// is used internally to delay computation for async closures until after
143+
/// upvar analysis is performed in HIR typeck.
142144
AsyncFnKindHelperCandidate,
143145

144146
/// Implementation of a `Coroutine` trait by one of the anonymous types

compiler/rustc_middle/src/ty/instance.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -101,7 +101,10 @@ pub enum InstanceDef<'tcx> {
101101
target_kind: ty::ClosureKind,
102102
},
103103

104-
/// TODO:
104+
/// `<[coroutine] as Future>::poll`, but for coroutines produced when `AsyncFnOnce`
105+
/// is called on a coroutine-closure whose closure kind is not `FnOnce`. This
106+
/// will select the body that is produced by the `ByMoveBody` transform, and thus
107+
/// take and use all of its upvars by-move rather than by-ref.
105108
CoroutineByMoveShim { coroutine_def_id: DefId },
106109

107110
/// Compiler-generated accessor for thread locals which returns a reference to the thread local

compiler/rustc_middle/src/ty/print/pretty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -877,7 +877,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write {
877877
ty::CoroutineClosure(did, args) => {
878878
p!(write("{{"));
879879
if !self.should_print_verbose() {
880-
p!(write("coroutine closure"));
880+
p!(write("coroutine-closure"));
881881
// FIXME(eddyb) should use `def_span`.
882882
if let Some(did) = did.as_local() {
883883
if self.tcx().sess.opts.unstable_opts.span_free_formats {

compiler/rustc_middle/src/ty/sty.rs

Lines changed: 34 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -276,11 +276,31 @@ pub struct CoroutineClosureArgs<'tcx> {
276276
}
277277

278278
pub struct CoroutineClosureArgsParts<'tcx> {
279+
/// This is the args of the typeck root.
279280
pub parent_args: &'tcx [GenericArg<'tcx>],
281+
/// Represents the maximum calling capability of the closure.
280282
pub closure_kind_ty: Ty<'tcx>,
283+
/// Represents all of the relevant parts of the coroutine returned by this
284+
/// coroutine-closure. This signature parts type will have the general
285+
/// shape of `fn(tupled_inputs, resume_ty) -> (return_ty, yield_ty)`, where
286+
/// `resume_ty`, `return_ty`, and `yield_ty` are the respective types for the
287+
/// coroutine returned by the coroutine-closure.
288+
///
289+
/// Use `coroutine_closure_sig` to break up this type rather than using it
290+
/// yourself.
281291
pub signature_parts_ty: Ty<'tcx>,
292+
/// The upvars captured by the closure. Remains an inference variable
293+
/// until the upvar analysis, which happens late in HIR typeck.
282294
pub tupled_upvars_ty: Ty<'tcx>,
295+
/// a function pointer that has the shape `for<'env> fn() -> (&'env T, ...)`.
296+
/// This allows us to represent the binder of the self-captures of the closure.
297+
///
298+
/// For example, if the coroutine returned by the closure borrows `String`
299+
/// from the closure's upvars, this will be `for<'env> fn() -> (&'env String,)`,
300+
/// while the `tupled_upvars_ty`, representing the by-move version of the same
301+
/// captures, will be `(String,)`.
283302
pub coroutine_captures_by_ref_ty: Ty<'tcx>,
303+
/// Witness type returned by the generator produced by this coroutine-closure.
284304
pub coroutine_witness_ty: Ty<'tcx>,
285305
}
286306

@@ -496,15 +516,27 @@ pub struct CoroutineArgs<'tcx> {
496516
pub struct CoroutineArgsParts<'tcx> {
497517
/// This is the args of the typeck root.
498518
pub parent_args: &'tcx [GenericArg<'tcx>],
499-
// TODO: why
519+
520+
/// The coroutines returned by a coroutine-closure's `AsyncFnOnce`/`AsyncFnMut`
521+
/// implementations must be distinguished since the former takes the closure's
522+
/// upvars by move, and the latter takes the closure's upvars by ref.
523+
///
524+
/// This field distinguishes these fields so that codegen can select the right
525+
/// body for the coroutine. This has the same type representation as the closure
526+
/// kind: `i8`/`i16`/`i32`.
527+
///
528+
/// For regular coroutines, this field will always just be `()`.
500529
pub kind_ty: Ty<'tcx>,
530+
501531
pub resume_ty: Ty<'tcx>,
502532
pub yield_ty: Ty<'tcx>,
503533
pub return_ty: Ty<'tcx>,
534+
504535
/// The interior type of the coroutine.
505536
/// Represents all types that are stored in locals
506537
/// in the coroutine's body.
507538
pub witness: Ty<'tcx>,
539+
508540
/// The upvars captured by the closure. Remains an inference variable
509541
/// until the upvar analysis, which happens late in HIR typeck.
510542
pub tupled_upvars_ty: Ty<'tcx>,
@@ -556,7 +588,7 @@ impl<'tcx> CoroutineArgs<'tcx> {
556588
self.split().parent_args
557589
}
558590

559-
// TODO:
591+
// Returns the kind of the coroutine. See docs on the `kind_ty` field.
560592
pub fn kind_ty(self) -> Ty<'tcx> {
561593
self.split().kind_ty
562594
}

compiler/rustc_smir/src/rustc_smir/convert/mir.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -539,7 +539,7 @@ impl<'tcx> Stable<'tcx> for mir::AggregateKind<'tcx> {
539539
)
540540
}
541541
mir::AggregateKind::CoroutineClosure(..) => {
542-
todo!("FIXME(async_closure): Lower these to SMIR")
542+
todo!("FIXME(async_closures): Lower these to SMIR")
543543
}
544544
}
545545
}

compiler/rustc_smir/src/rustc_smir/convert/ty.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,7 @@ impl<'tcx> Stable<'tcx> for ty::TyKind<'tcx> {
383383
tables.closure_def(*def_id),
384384
generic_args.stable(tables),
385385
)),
386-
ty::CoroutineClosure(..) => todo!("/* TODO */"),
386+
ty::CoroutineClosure(..) => todo!("FIXME(async_closures): Lower these to SMIR"),
387387
ty::Coroutine(def_id, generic_args) => TyKind::RigidTy(RigidTy::Coroutine(
388388
tables.coroutine_def(*def_id),
389389
generic_args.stable(tables),

compiler/rustc_span/src/symbol.rs

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -321,6 +321,7 @@ symbols! {
321321
TyCtxt,
322322
TyKind,
323323
Unknown,
324+
Upvars,
324325
Vec,
325326
VecDeque,
326327
Wrapper,

compiler/rustc_trait_selection/src/solve/assembly/mod.rs

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -190,7 +190,9 @@ pub(super) trait GoalKind<'tcx>:
190190
kind: ty::ClosureKind,
191191
) -> QueryResult<'tcx>;
192192

193-
/// TODO:
193+
/// Compute the built-in logic of the `AsyncFnKindHelper` helper trait, which
194+
/// is used internally to delay computation for async closures until after
195+
/// upvar analysis is performed in HIR typeck.
194196
fn consider_builtin_async_fn_kind_helper_candidate(
195197
ecx: &mut EvalCtxt<'_, 'tcx>,
196198
goal: Goal<'tcx, Self>,

compiler/rustc_trait_selection/src/solve/assembly/structural_traits.rs

Lines changed: 7 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,7 @@ use rustc_middle::traits::solve::Goal;
88
use rustc_middle::ty::{
99
self, ToPredicate, Ty, TyCtxt, TypeFoldable, TypeFolder, TypeSuperFoldable, TypeVisitableExt,
1010
};
11+
use rustc_span::sym;
1112

1213
use crate::solve::EvalCtxt;
1314

@@ -274,7 +275,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_callable<'tcx>(
274275
Ok(Some(closure_args.sig().map_bound(|sig| (sig.inputs()[0], sig.output()))))
275276
}
276277

277-
// Coroutine closures don't implement `Fn` traits the normal way.
278+
// Coroutine-closures don't implement `Fn` traits the normal way.
278279
ty::CoroutineClosure(..) => Err(NoSolution),
279280

280281
ty::Bool
@@ -341,11 +342,11 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
341342
vec![],
342343
))
343344
} else {
344-
let helper_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
345-
// FIXME(async_closures): Make this into a lang item.
345+
let async_fn_kind_trait_def_id =
346+
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
346347
let upvars_projection_def_id = tcx
347-
.associated_items(helper_trait_def_id)
348-
.in_definition_order()
348+
.associated_items(async_fn_kind_trait_def_id)
349+
.filter_by_name_unhygienic(sym::Upvars)
349350
.next()
350351
.unwrap()
351352
.def_id;
@@ -375,7 +376,7 @@ pub(in crate::solve) fn extract_tupled_inputs_and_output_from_async_callable<'tc
375376
vec![
376377
ty::TraitRef::new(
377378
tcx,
378-
helper_trait_def_id,
379+
async_fn_kind_trait_def_id,
379380
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
380381
)
381382
.to_predicate(tcx),

compiler/rustc_trait_selection/src/traits/project.rs

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -2461,12 +2461,13 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
24612461
let goal_kind =
24622462
tcx.async_fn_trait_kind_from_def_id(obligation.predicate.trait_def_id(tcx)).unwrap();
24632463

2464-
let helper_trait_def_id = tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
2464+
let async_fn_kind_helper_trait_def_id =
2465+
tcx.require_lang_item(LangItem::AsyncFnKindHelper, None);
24652466
nested.push(obligation.with(
24662467
tcx,
24672468
ty::TraitRef::new(
24682469
tcx,
2469-
helper_trait_def_id,
2470+
async_fn_kind_helper_trait_def_id,
24702471
[kind_ty, Ty::from_closure_kind(tcx, goal_kind)],
24712472
),
24722473
));
@@ -2476,9 +2477,12 @@ fn confirm_async_closure_candidate<'cx, 'tcx>(
24762477
ty::ClosureKind::FnOnce => tcx.lifetimes.re_static,
24772478
};
24782479

2479-
// FIXME(async_closures): Make this into a lang item.
2480-
let upvars_projection_def_id =
2481-
tcx.associated_items(helper_trait_def_id).in_definition_order().next().unwrap().def_id;
2480+
let upvars_projection_def_id = tcx
2481+
.associated_items(async_fn_kind_helper_trait_def_id)
2482+
.filter_by_name_unhygienic(sym::Upvars)
2483+
.next()
2484+
.unwrap()
2485+
.def_id;
24822486

24832487
// FIXME(async_closures): Confirmation is kind of a mess here. Ideally,
24842488
// we'd short-circuit when we know that the goal_kind >= closure_kind, and not

compiler/rustc_type_ir/src/ty_kind.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -202,7 +202,11 @@ pub enum TyKind<I: Interner> {
202202
/// `ClosureArgs` for more details.
203203
Closure(I::DefId, I::GenericArgs),
204204

205-
/// TODO
205+
/// The anonymous type of a closure. Used to represent the type of `async |a| a`.
206+
///
207+
/// Coroutine-closure args contain both the - potentially substituted - generic
208+
/// parameters of its parent and some synthetic parameters. See the documentation
209+
/// for `CoroutineClosureArgs` for more details.
206210
CoroutineClosure(I::DefId, I::GenericArgs),
207211

208212
/// The anonymous type of a coroutine. Used to represent the type of

library/core/src/ops/async_function.rs

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,26 @@ mod impls {
108108
}
109109

110110
mod internal_implementation_detail {
111-
// TODO: needs a detailed explanation
111+
/// A helper trait that is used to enforce that the `ClosureKind` of a goal
112+
/// is within the capabilities of a `CoroutineClosure`, and which allows us
113+
/// to delay the projection of the tupled upvar types until after upvar
114+
/// analysis is complete.
115+
///
116+
/// The `Self` type is expected to be the `kind_ty` of the coroutine-closure,
117+
/// and thus either `?0` or `i8`/`i16`/`i32` (see docs for `ClosureKind`
118+
/// for an explanation of that). The `GoalKind` is also the same type, but
119+
/// representing the kind of the trait that the closure is being called with.
112120
#[cfg_attr(not(bootstrap), lang = "async_fn_kind_helper")]
113121
trait AsyncFnKindHelper<GoalKind> {
114-
type Assoc<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>;
122+
// Projects a set of closure inputs (arguments), a region, and a set of upvars
123+
// (by move and by ref) to the upvars that we expect the coroutine to have
124+
// according to the `GoalKind` parameter above.
125+
//
126+
// The `Upvars` parameter should be the upvars of the parent coroutine-closure,
127+
// and the `BorrowedUpvarsAsFnPtr` will be a function pointer that has the shape
128+
// `for<'env> fn() -> (&'env T, ...)`. This allows us to represent the binder
129+
// of the closure's self-capture, and these upvar types will be instantiated with
130+
// the `'closure_env` region provided to the associated type.
131+
type Upvars<'closure_env, Inputs, Upvars, BorrowedUpvarsAsFnPtr>;
115132
}
116133
}

tests/ui/async-await/async-borrowck-escaping-closure-error.rs

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,8 @@
44
fn foo() -> Box<dyn std::future::Future<Output = u32>> {
55
let x = 0u32;
66
Box::new((async || x)())
7-
//~^ ERROR closure may outlive the current function, but it borrows `x`, which is owned by the current function
7+
//~^ ERROR cannot return value referencing local variable `x`
8+
//~| ERROR cannot return value referencing temporary value
89
}
910

1011
fn main() {
Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,21 +1,21 @@
1-
error[E0373]: closure may outlive the current function, but it borrows `x`, which is owned by the current function
2-
--> $DIR/async-borrowck-escaping-closure-error.rs:6:15
1+
error[E0515]: cannot return value referencing local variable `x`
2+
--> $DIR/async-borrowck-escaping-closure-error.rs:6:5
33
|
44
LL | Box::new((async || x)())
5-
| ^^^^^^^^ - `x` is borrowed here
6-
| |
7-
| may outlive borrowed value `x`
8-
|
9-
note: closure is returned here
5+
| ^^^^^^^^^------------^^^
6+
| | |
7+
| | `x` is borrowed here
8+
| returns a value referencing data owned by the current function
9+
10+
error[E0515]: cannot return value referencing temporary value
1011
--> $DIR/async-borrowck-escaping-closure-error.rs:6:5
1112
|
1213
LL | Box::new((async || x)())
13-
| ^^^^^^^^^^^^^^^^^^^^^^^^
14-
help: to force the closure to take ownership of `x` (and any other referenced variables), use the `move` keyword
15-
|
16-
LL | Box::new((async move || x)())
17-
| ++++
14+
| ^^^^^^^^^------------^^^
15+
| | |
16+
| | temporary value created here
17+
| returns a value referencing data owned by the current function
1818

19-
error: aborting due to 1 previous error
19+
error: aborting due to 2 previous errors
2020

21-
For more information about this error, try `rustc --explain E0373`.
21+
For more information about this error, try `rustc --explain E0515`.
Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,10 @@
11
// edition:2021
2+
// check-pass
23

34
#![feature(async_closure)]
45

56
fn main() {
67
let x = async move |x: &str| {
7-
//~^ ERROR lifetime may not live long enough
8-
// This error is proof that the `&str` type is higher-ranked.
9-
// This won't work until async closures are fully impl'd.
108
println!("{x}");
119
};
1210
}

tests/ui/async-await/async-closures/higher-ranked.stderr

Lines changed: 0 additions & 17 deletions
This file was deleted.

0 commit comments

Comments
 (0)