Skip to content

Conversation

@moreal
Copy link
Contributor

@moreal moreal commented Jan 22, 2026

This pull request updates types module to v3.14.2. While doing it, it fixes also async-related feature. This pull request's base is generated by #6827.

Summary by CodeRabbit

  • New Features
    • Improved support for coroutines in await expressions
    • Enhanced compatibility for yield-from operations with wrapped coroutines

✏️ Tip: You can customize this high-level summary in your review settings.

Co-Authored-By: CPython Developers <>
@coderabbitai
Copy link
Contributor

coderabbitai bot commented Jan 22, 2026

📝 Walkthrough

Walkthrough

This PR introduces the ITERABLE_COROUTINE flag to the bytecode layer and adds support for generators marked with this flag to be treated as awaitable in async contexts and usable in yield-from statements, integrating flag checks across compiler and VM components.

Changes

Cohort / File(s) Summary
Bytecode flag extension
crates/compiler-core/src/bytecode.rs
Added ITERABLE_COROUTINE = 0x0100 constant to CodeFlags bitflags, extending available code object behavior flags.
Awaitable resolution for async generators
crates/vm/src/builtins/asyncgenerator.rs
Extended PyAnextAwaitable.get_awaitable_iter to recognize PyGenerator instances with CO_ITERABLE_COROUTINE flag; if present, returns the generator directly as the awaitable iterator; otherwise delegates to __await__ or raises TypeError.
Frame execution for await and yield-from
crates/vm/src/frame.rs
Modified GetAwaitable to permit awaiting generators with CO_ITERABLE_COROUTINE flag; modified GetYieldFromIter to accept both COROUTINE and ITERABLE_COROUTINE flags when yielding from coroutine objects in coroutine contexts.

Estimated code review effort

🎯 3 (Moderate) | ⏱️ ~22 minutes

Possibly related PRs

  • Remove _dis module #6690: Modifies CodeFlags bitflags in bytecode.rs—the retrieved PR involves renaming coroutine-related flags while this PR adds the new ITERABLE_COROUTINE flag and uses it throughout the VM.
  • traverse for generator #6760: Modifies the same PyAnextAwaitable type to add manual GC traversal, intersecting with awaitable resolution changes in this PR.
  • sys.set_asyncgen_hook #6439: Modifies awaitable resolution and async-generator handling in frame and asyncgenerator paths, overlapping with the awaitable and yield-from logic updates in this PR.

Suggested reviewers

  • youknowone

Poem

🐰 A flag appears, both old and new,
To let coroutines find their due,
Through async paths and yields so keen,
Where generators join the scene!
types.coroutine hops with glee,
At last, awaitable it can be! 🌟

🚥 Pre-merge checks | ✅ 3
✅ Passed checks (3 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title 'Update types from v3.14.2' is partially related to the changeset. While the PR does update the types module, the title omits the significant async-related fixes (CO_ITERABLE_COROUTINE flag support, frame validation updates, and awaitable handling changes) that represent substantial portions of the actual changes.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing touches
  • 📝 Generate docstrings

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

@github-actions
Copy link
Contributor

Code has been automatically formatted

The code in this PR has been formatted using:

  • cargo fmt --all
    Please pull the latest changes before pushing again:
git pull origin update-3.14.2-types

@github-actions
Copy link
Contributor

github-actions bot commented Jan 22, 2026

📦 Library Dependencies

The following Lib/ modules were modified. Here are their dependencies:

Click to expand dependency information
[+] lib: cpython/Lib/_opcode_metadata.py
soft_deps:
- [ ] _opcode_metadata

[+] lib: cpython/Lib/pydoc_data
soft_deps:
- [ ] pydoc_data

[+] lib: cpython/Lib/types.py
[+] test: cpython/Lib/test/test_types.py
soft_deps:
- [x] types

Legend:

  • [+] path exists in CPython
  • [x] up-to-date, [ ] outdated
  • native: Rust/C extension modules

@moreal moreal force-pushed the update-3.14.2-types branch from 1e5e723 to b25479a Compare January 22, 2026 06:22
moreal and others added 4 commits January 22, 2026 17:52
- Add ITERABLE_COROUTINE (0x0100) to CodeFlags in bytecode.rs
- Update frame.rs to check for both COROUTINE and ITERABLE_COROUTINE flags
  when validating 'yield from' on coroutine objects
- Remove False and workaround in types.coroutine() now that the flag is supported
- Remove @unittest.expectedFailure from test_async_def and test_genfunc

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Generators decorated with @types.coroutine have the CO_ITERABLE_COROUTINE
flag set, making them awaitable. The GetAwaitable instruction now properly
handles this case instead of only checking for __await__ method.

This fixes the "object generator can't be used in 'await' expression" error
that occurred with asyncio.sleep(0) which uses @types.coroutine decorated
__sleep0() generator internally.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
Generators decorated with @types.coroutine have the CO_ITERABLE_COROUTINE
flag and can be used in await expressions. The PyAnextAwaitable's
get_awaitable_iter method was missing this check, causing builtin anext()
to fail with "object generator can't be used in 'await' expression" when
used with such generators.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
For generators without CO_ITERABLE_COROUTINE flag, try to get __await__
method instead of returning an error immediately. This matches CPython's
_PyCoro_GetAwaitableIter behavior which allows generator subclasses that
define __await__ to be used in await expressions.

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
@moreal moreal force-pushed the update-3.14.2-types branch from df2a9ce to b76dde1 Compare January 22, 2026 08:52
@moreal moreal marked this pull request as ready for review January 22, 2026 10:25
Copy link
Contributor

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

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

Actionable comments posted: 0

Caution

Some comments are outside the diff and can’t be posted inline due to platform limitations.

⚠️ Outside diff range comments (1)
crates/vm/src/frame.rs (1)

1008-1032: Allow generator subclasses with __await__ to be awaited.

The current code uses downcast_ref::<PyGenerator>() which matches any generator, including subclasses, then immediately returns a TypeError if the ITERABLE_COROUTINE flag is absent. This blocks generator subclasses that implement __await__, preventing the fallback __await__ lookup.

Only generators that fail to have the ITERABLE_COROUTINE flag AND lack an __await__ method should error. The check should be restructured to only apply the generator-specific logic when the flag is actually set, allowing non-flagged generators to fall through to the __await__ fallback.

🔧 Suggested fix (preserve __await__ fallback for non-flagged generators)
-                } else if let Some(generator) = awaited_obj.downcast_ref::<PyGenerator>() {
-                    // Generator with CO_ITERABLE_COROUTINE flag can be awaited
-                    // (e.g., generators decorated with `@types.coroutine`)
-                    if generator
-                        .as_coro()
-                        .frame()
-                        .code
-                        .flags
-                        .contains(bytecode::CodeFlags::ITERABLE_COROUTINE)
-                    {
-                        awaited_obj
-                    } else {
-                        return Err(vm.new_type_error(format!(
-                            "object {} can't be used in 'await' expression",
-                            awaited_obj.class().name(),
-                        )));
-                    }
-                } else {
+                } else if awaited_obj
+                    .downcast_ref::<PyGenerator>()
+                    .is_some_and(|generator| {
+                        generator
+                            .as_coro()
+                            .frame()
+                            .code
+                            .flags
+                            .contains(bytecode::CodeFlags::ITERABLE_COROUTINE)
+                    })
+                {
+                    awaited_obj
+                } else {
                     let await_method = vm.get_method_or_type_error(
                         awaited_obj.clone(),
                         identifier!(vm, __await__),
                         || {
                             format!(
                                 "object {} can't be used in 'await' expression",
                                 awaited_obj.class().name(),
                             )
                         },
                     )?;
                     let result = await_method.call((), vm)?;
                     // Check that __await__ returned an iterator
                     if !PyIter::check(&result) {
                         return Err(vm.new_type_error(format!(
                             "__await__() returned non-iterator of type '{}'",
                             result.class().name()
                         )));
                     }
                     result
                 };

@moreal moreal marked this pull request as draft January 22, 2026 10:34
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant