1
Fork 0

Auto merge of #118457 - eholk:genfn, r=compiler-errors

Add support for `gen fn`

This builds on #116447 to add support for `gen fn` functions. For the most part we follow the same approach as desugaring `async fn`, but replacing `Future` with `Iterator` and `async {}` with `gen {}` for the body.

The version implemented here uses the return type of a `gen fn` as the yield type. For example:

```rust
gen fn count_to_three() -> i32 {
    yield 1;
    yield 2;
    yield 3;
}
```

In the future, I think we should experiment with a syntax like `gen fn count_to_three() yield i32 { ... }`, but that can go in another PR.

cc `@oli-obk` `@compiler-errors`
This commit is contained in:
bors 2023-12-05 18:37:15 +00:00
commit 56278a6e28
36 changed files with 417 additions and 234 deletions

View file

@ -156,7 +156,10 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
fn visit_fn(&mut self, fn_kind: FnKind<'a>, span: Span, _: NodeId) {
if let FnKind::Fn(_, _, sig, _, generics, body) = fn_kind {
if let Async::Yes { closure_id, .. } = sig.header.asyncness {
if let Some(
CoroutineKind::Async { closure_id, .. } | CoroutineKind::Gen { closure_id, .. },
) = sig.header.coro_kind
{
self.visit_generics(generics);
// For async functions, we need to create their inner defs inside of a
@ -281,11 +284,12 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> {
// Async closures desugar to closures inside of closures, so
// we must create two defs.
let closure_def = self.create_def(expr.id, kw::Empty, DefKind::Closure, expr.span);
match closure.asyncness {
Async::Yes { closure_id, .. } => {
self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span)
}
Async::No => closure_def,
match closure.coro_kind {
Some(
CoroutineKind::Async { closure_id, .. }
| CoroutineKind::Gen { closure_id, .. },
) => self.create_def(closure_id, kw::Empty, DefKind::Closure, expr.span),
None => closure_def,
}
}
ExprKind::Gen(_, _, _) => {

View file

@ -916,8 +916,10 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&sig.decl.output,
);
if let Some((async_node_id, _)) = sig.header.asyncness.opt_return_id() {
this.record_lifetime_params_for_impl_trait(async_node_id);
if let Some((coro_node_id, _)) =
sig.header.coro_kind.map(|coro_kind| coro_kind.return_id())
{
this.record_lifetime_params_for_impl_trait(coro_node_id);
}
},
);
@ -940,12 +942,13 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
this.visit_generics(generics);
let declaration = &sig.decl;
let async_node_id = sig.header.asyncness.opt_return_id();
let coro_node_id =
sig.header.coro_kind.map(|coro_kind| coro_kind.return_id());
this.with_lifetime_rib(
LifetimeRibKind::AnonymousCreateParameter {
binder: fn_id,
report_in_path: async_node_id.is_some(),
report_in_path: coro_node_id.is_some(),
},
|this| {
this.resolve_fn_signature(
@ -958,7 +961,7 @@ impl<'a: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'a, '_, 'ast,
&declaration.output,
);
if let Some((async_node_id, _)) = async_node_id {
if let Some((async_node_id, _)) = coro_node_id {
this.record_lifetime_params_for_impl_trait(async_node_id);
}
},
@ -4288,8 +4291,10 @@ impl<'a: 'ast, 'b, 'ast, 'tcx> LateResolutionVisitor<'a, 'b, 'ast, 'tcx> {
// `async |x| ...` gets desugared to `|x| async {...}`, so we need to
// resolve the arguments within the proper scopes so that usages of them inside the
// closure are detected as upvars rather than normal closure arg usages.
//
// Similarly, `gen |x| ...` gets desugared to `|x| gen {...}`, so we handle that too.
ExprKind::Closure(box ast::Closure {
asyncness: Async::Yes { .. },
coro_kind: Some(_),
ref fn_decl,
ref body,
..