From eb6d341866a5fbaacad072c8a8f49afbf813c9f7 Mon Sep 17 00:00:00 2001 From: Sebastien Lebreton Date: Fri, 24 Jul 2026 18:10:21 +0200 Subject: [PATCH] Fix #3908: use the async iterator element type for yield 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 --- .../TestCases/Pretty/AsyncStreams.cs | 33 +++++++++++++++++++ .../CSharp/StatementBuilder.cs | 3 +- 2 files changed, 35 insertions(+), 1 deletion(-) diff --git a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs index f7ea3f010..0cd334e4f 100644 --- a/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs +++ b/ICSharpCode.Decompiler.Tests/TestCases/Pretty/AsyncStreams.cs @@ -6,6 +6,12 @@ using System.Threading.Tasks; namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty { + public enum AsyncStreamColor + { + Red, + Green + } + public class AsyncStreams { public static async IAsyncEnumerable CountTo(int until) @@ -85,6 +91,33 @@ namespace ICSharpCode.Decompiler.Tests.TestCases.Pretty await Task.Yield(); } } + + public static async IAsyncEnumerable ConstrainedGenericYield(IAsyncEnumerable items) where T : IAsyncStreamEntry + { + await foreach (T item in items) + { + yield return item; + } + } + + public static IEnumerable BoxedValues() + { + yield return true; + yield return 'a'; + yield return AsyncStreamColor.Green; + } + + public static async IAsyncEnumerable BoxedValuesAsync() + { + yield return true; + await Task.Yield(); + yield return 'a'; + yield return AsyncStreamColor.Green; + } + } + + public interface IAsyncStreamEntry + { } public struct TestStruct diff --git a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs index da0646022..5686389b3 100644 --- a/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs +++ b/ICSharpCode.Decompiler/CSharp/StatementBuilder.cs @@ -433,7 +433,8 @@ namespace ICSharpCode.Decompiler.CSharp protected internal override TranslatedStatement VisitYieldReturn(YieldReturn inst) { - var elementType = currentFunction.ReturnType.GetElementTypeFromIEnumerable(typeSystem, true, out var isGeneric); + var elementType = currentFunction.AsyncReturnType + ?? currentFunction.ReturnType.GetElementTypeFromIEnumerable(typeSystem, true, out _); var expr = exprBuilder.Translate(inst.Value, typeHint: elementType) .ConvertTo(elementType, exprBuilder, allowImplicitConversion: true); return new YieldReturnStatement {