close
Skip to content

part of Support gen syntax (feature gen_blocks) #16156#21987

Open
asukaminato0721 wants to merge 1 commit intorust-lang:masterfrom
asukaminato0721:16156
Open

part of Support gen syntax (feature gen_blocks) #16156#21987
asukaminato0721 wants to merge 1 commit intorust-lang:masterfrom
asukaminato0721:16156

Conversation

@asukaminato0721
Copy link
Copy Markdown
Contributor

@asukaminato0721 asukaminato0721 commented Apr 7, 2026

part of #16156

add basic supports for gen { } async gen { } gen fn async gen fn

fix some type signature show.

add some tests.

Copilot AI review requested due to automatic review settings April 7, 2026 12:26
@rustbot rustbot added the S-waiting-on-review Status: Awaiting review from the assignee but also interested parties. label Apr 7, 2026
@asukaminato0721 asukaminato0721 force-pushed the 16156 branch 2 times, most recently from b4d4360 to e737273 Compare April 7, 2026 12:28
Copy link
Copy Markdown

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds initial support for the gen / async gen syntax (blocks and functions) across HIR lowering, type inference, and type display, including wiring up an AsyncIterator lang item and adding regression tests.

Changes:

  • Introduce new HIR expression variants for gen {} / async gen {} and lower gen fn / async gen fn bodies into them.
  • Extend type inference / solver interop and type display to represent gen as impl Iterator<Item = ...> and async gen as impl AsyncIterator<Item = ...>.
  • Add AsyncIterator minicore + lang item plumbing and new inference/coercion tests.

Reviewed changes

Copilot reviewed 22 out of 22 changed files in this pull request and generated 1 comment.

Show a summary per file
File Description
crates/test-utils/src/minicore.rs Adds minicore support for core::async_iter::AsyncIterator plus #[lang] wiring for Option/Poll.
crates/intern/src/symbol/symbols.rs Registers new symbols used by the async iterator/lang item plumbing.
crates/hir/src/display.rs Displays gen fn/async gen fn and strips wrapped return types similarly to async fn.
crates/hir-ty/src/tests/simple.rs Adds inference tests for gen/async gen blocks and functions.
crates/hir-ty/src/tests/coercion.rs Adds coercion tests for yield inside gen/async gen blocks.
crates/hir-ty/src/next_solver/interner.rs Updates solver interner to recognize Gen/AsyncGen and map AsyncIterator lang item.
crates/hir-ty/src/mir/lower.rs Explicitly marks gen/async gen blocks as not supported in MIR lowering.
crates/hir-ty/src/infer/mutability.rs Includes Gen/AsyncGen in mutability inference traversal.
crates/hir-ty/src/infer/expr.rs Implements inference + coroutine type lowering for Gen/AsyncGen blocks.
crates/hir-ty/src/infer/closure/analysis.rs Includes Gen/AsyncGen in closure capture analysis traversal.
crates/hir-ty/src/display.rs Displays coroutine types originating from gen/async gen as impl Iterator/AsyncIterator.
crates/hir-ty/src/diagnostics/unsafe_check.rs Traverses Gen/AsyncGen blocks in unsafe diagnostics.
crates/hir-ty/src/diagnostics/expr.rs Validates Gen/AsyncGen blocks like other block expressions.
crates/hir-expand/src/mod_path.rs Adds known path for core::async_iter::AsyncIterator.
crates/hir-def/src/signatures.rs Adds GEN flag and is_gen() on function signatures.
crates/hir-def/src/lang_item.rs Adds AsyncIterator to the lang item table.
crates/hir-def/src/hir.rs Adds Expr::Gen and Expr::AsyncGen HIR variants.
crates/hir-def/src/expr_store/scope.rs Ensures scopes are computed for Gen/AsyncGen blocks.
crates/hir-def/src/expr_store/pretty.rs Pretty-prints gen and async gen blocks.
crates/hir-def/src/expr_store/lower.rs Lowers gen/async gen blocks and wraps gen fn/async gen fn bodies; wraps function return type in Iterator/AsyncIterator impl-trait.
crates/hir-def/src/expr_store/body.rs Threads is_gen_fn into body lowering.
crates/hir-def/src/expr_store.rs Traversal updates to treat Gen/AsyncGen as block-like expressions.

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

View changes since this review

Comment thread crates/hir-ty/src/tests/simple.rs
@rustbot

This comment has been minimized.

@rustbot

This comment has been minimized.

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

I prefer to wait with this until my closure rewrite will be merged, which will mean you will have a rebase to do, but gen blocks/closures will be supported much better. I can also direct you (after I finish my branch of course), we need to follow rustc closely.

@rustbot

This comment has been minimized.

@rustbot
Copy link
Copy Markdown
Collaborator

rustbot commented Apr 20, 2026

This PR was rebased onto a different master commit. Here's a range-diff highlighting what actually changed.

Rebasing is a normal part of keeping PRs up to date, so no action is needed—this note is just to help reviewers.

@ChayimFriedman2
Copy link
Copy Markdown
Contributor

So: my PR was merged, what you need to do now is complete the things:

  • Some things are called async blocks/closures, you need to generalize the name to coroutines/coroutine closures respectively. Some will also need to know the kind. E.g. ExprCollector::lower_async_block_with_moved_arguments(), ExprCollector::async_block(). Lowering gen blocks is just like lowering async blocks, and gen closures are just like async closures. Similarly for async gen.
  • hir_def::ClosureKind is tricky. I think it will be the best as the following:
#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum CoroutineKind {
    Async,
    Gen,
    AsyncGen,
}

#[derive(Debug, Clone, Copy, PartialEq, Eq)]
pub enum ClosureKind {
    Closure,
    OldCoroutine(Movability), // `#[coroutine]`, previously this variant was called `Coroutine`. I don't have a better name :(
    Coroutine { kind: CoroutineKind, source: CoroutineSource }, // Previously `AsyncBlock`
    CoroutineClosure(CoroutineKind), // Previously `AsyncClosure`
}
  • In hir-ty/src/infer/closure.rs, inside infer_closure(), it was copied (and adjusted of course) from https://github.com/rust-lang/rust/blob/main/compiler/rustc_hir_typeck/src/closure.rs, but I removed the parts of gen and async gen closure. The structure is preserved, though: look at how we handle async blocks and async closures, and look at that rustc file, and copy the rest.
  • Add the lang items and fill the minicore as needed.
  • In hir-ty/src/display.rs, almost nothing needs to change, but when printing coroutines/coroutine closures, you will need to print gen or async gen instead of async when needed.

That's it I think! Feel free to ask me questions.

update based on comment
Copy link
Copy Markdown
Contributor

@ChayimFriedman2 ChayimFriedman2 left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I have a suspect that you're using AI tools for code generation without disclosing that.

Please note that we require disclosure for AI usage, and properly understanding and reviewing their output.

View changes since this review

// all async closures would default to `FnOnce` as their calling mode.
CaptureBy::Ref,
let capture_by = match kind {
// Async closures use by-ref by default so they don't all collapse to `FnOnce`.
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Nope, gen and async gen closures also need CaptureBy::Ref.

const EXPLICIT_SAFE = 1 << 11;
const HAS_LEGACY_CONST_GENERICS = 1 << 12;
const RUSTC_INTRINSIC = 1 << 13;
const GEN = 1 << 14;
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Put it near ASYNC?

let body = this.collect_expr_opt(expr);
if awaitable == Awaitable::Yes {
this.lower_async_block_with_moved_arguments(params, body, CoroutineSource::Fn)
if is_gen_fn {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This should also just call lower_coroutine_with_moved_arguments().

fn desugared_coroutine_expr(
&mut self,
source: CoroutineSource,
closure_kind: ClosureKind,
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Take instead CoroutineKind and CoroutineSource?

};
ClosureKind::Coroutine(movability)
let closure_kind = if let Some(kind) =
if e.async_token().is_some() && e.gen_token().is_some()
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I don't like the nested if here. Split it into a local.

// would naturally unify these two trait hierarchies in the most
// general way.
let call_trait_choices = if self.shallow_resolve(adjusted_ty).is_coroutine_closure() {
let prefer_async_fn_traits = match self.shallow_resolve(adjusted_ty).kind() {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

rustc doesn't do this and keeps the old self.shallow_resolve(adjusted_ty).is_coroutine_closure() check, so it's good enough for us.

ClosureKind::Coroutine(_) => self.table.next_ty_var(),
ClosureKind::AsyncBlock { .. } => self.types.types.unit,
ClosureKind::OldCoroutine(_)
| ClosureKind::Coroutine { kind: CoroutineKind::Gen | CoroutineKind::AsyncGen, .. } => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Did you look at the rustc code I linked? That's not what it does.

.async_fn_trait_kind_from_def_id(trait_def_id)
.or_else(|| self.fn_trait_kind_from_def_id(trait_def_id)),
ClosureKind::CoroutineClosure(CoroutineKind::Gen)
| ClosureKind::CoroutineClosure(CoroutineKind::AsyncGen) => {
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is again not what rustc does. Look carefully.

{
self.extract_sig_from_projection_and_future_bound(projection)
}
ClosureKind::CoroutineClosure(CoroutineKind::Gen | CoroutineKind::AsyncGen)
Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

And here too.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

S-waiting-on-review Status: Awaiting review from the assignee but also interested parties.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants