Skip to content

Fix #3908: use the async iterator element type for yield#3911

Merged
siegfriedpammer merged 1 commit into
icsharpcode:masterfrom
sailro:fix-3908-constrained-async-yield
Jul 25, 2026
Merged

Fix #3908: use the async iterator element type for yield#3911
siegfriedpammer merged 1 commit into
icsharpcode:masterfrom
sailro:fix-3908-constrained-async-yield

Conversation

@sailro

@sailro sailro commented Jul 24, 2026

Copy link
Copy Markdown
Contributor

Fixes #3908.

Problem

StatementBuilder.VisitYieldReturn derives the target element type from IEnumerable<T> /
IEnumerator<T>. For an async iterator, that lookup returns an unknown type even though
AsyncAwaitDecompiler has already recovered the element type.

Without the target type, the compiler-generated box T used to store a constrained generic value
in the async iterator's current field remains visible as (object)value. The resulting
yield return fails with CS0266 when the iterator returns an interface constraint.

Solution

Use ILFunction.AsyncReturnType as the element type for async iterators, falling back to the
existing synchronous enumerable lookup.

The existing expression conversion logic can then remove compiler boxing when an implicit
conversion to the recovered element type exists. No async-state-machine-specific cast rewrite is
needed.

Tests

Extended the AsyncStreams Pretty fixture with:

  • a constrained generic async iterator returning its interface constraint;
  • synchronous and asynchronous object iterators yielding boxed bool, char, and enum values,
    ensuring their source values remain intact.

Validation:

  • AsyncStreams Pretty matrix: 6 passed

  • runtime-async AsyncStreams matrix: 2 passed

  • full Pretty suite: 1,913 passed, 5 existing skips

  • Release solution build: 0 warnings, 0 errors

  • full solution test suite: 4,921 passed, 15 existing skips

  • At least one test covering the code changed

Yield translation derived its target type only from synchronous enumerable
interfaces, leaving async iterator yields untyped and preserving compiler
boxing casts. Use the element type already recovered by the async decompiler.

Assisted-by: Copilot:gpt-5.6-sol:GitHub Copilot CLI
Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
Copilot-Session: 86d2918e-5a24-48b4-9a86-41d331ec3720
@siegfriedpammer
siegfriedpammer merged commit 3dc3f84 into icsharpcode:master Jul 25, 2026
7 checks passed
@siegfriedpammer

Copy link
Copy Markdown
Member

Thank you for your contribution!

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.

Constrained generic async iterator yield is emitted as object (CS0266)

2 participants