From 6532d371bf69fe11ea243ab8687010c6f8f8dcd7 Mon Sep 17 00:00:00 2001 From: Nick Nassiri Date: Tue, 16 Jun 2026 11:35:02 -0700 Subject: [PATCH] Fix un-buildable main: convert ParameterInfo[] to Type[] in generator instance-stub DC init MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit EmitGeneratorFunctionDCInit takes `Type[]? paramTypes` (it boxes value-type params with these), but the generator and async-generator instance stub methods pass their `paramTypes` local, which #786 (#720) changed to `methodBuilder.GetParameters()` (a ParameterInfo[], the method's actual IL signature) while #769 (#724/#725) independently added the call passing a Type[]. Each PR compiled in isolation; merged together without a rebase, a ParameterInfo[] flows into a Type[]? parameter and main fails to compile (CS1503) at ILCompiler.Generators.cs:557 and ILCompiler.AsyncGenerators.cs:376. Convert at the two call sites with `.Select(p => p.ParameterType).ToArray()` — the dominant codebase idiom for GetParameters() -> Type[] — preserving #720's "box from the actual IL signature" behavior so private/all-object and #737-widened slots are not spuriously boxed (matching the field-seeding loop just above each call). Re-enables the compiled default/optional-parameter cluster from #787; the #723/#737/ #738/#739 repros are verified green (compiled == interpreted) and the full unit suite is 13352 passed / 0 failed. Filed #790 (different-arity override dispatch) and #792 (defaulted + captured generator parameter) as pre-existing gaps surfaced while verifying. Fixes #723, #737, #738, #739. --- Compilation/ILCompiler.AsyncGenerators.cs | 7 +++++-- Compilation/ILCompiler.Generators.cs | 7 +++++-- 2 files changed, 10 insertions(+), 4 deletions(-) diff --git a/Compilation/ILCompiler.AsyncGenerators.cs b/Compilation/ILCompiler.AsyncGenerators.cs index 4a9cab79..3ea3d2d8 100644 --- a/Compilation/ILCompiler.AsyncGenerators.cs +++ b/Compilation/ILCompiler.AsyncGenerators.cs @@ -371,9 +371,12 @@ private void EmitAsyncGeneratorInstanceStubMethod( // #725: instantiate the function display class and seed any captured-and-mutated parameter // into it (instance methods carry 'this' at arg 0, so user params start at arg 1). The stub - // params are typed, so value types are boxed before the store. No-op when no function DC. + // params are typed, so value types are boxed before the store. No-op when no function DC. Pass + // the CLR boxing types from the method's ACTUAL IL signature (same source as the field-seeding + // loop above), so widened/all-object slots are not spuriously boxed. if (funcDCKey != null) - EmitGeneratorFunctionDCInit(il, smBuilder.FunctionDCField, method, funcDCKey, paramOffset: 1, paramTypes); + EmitGeneratorFunctionDCInit(il, smBuilder.FunctionDCField, method, funcDCKey, paramOffset: 1, + paramTypes.Select(p => p.ParameterType).ToArray()); // Return the state machine (which implements IAsyncEnumerable) il.Emit(OpCodes.Ret); diff --git a/Compilation/ILCompiler.Generators.cs b/Compilation/ILCompiler.Generators.cs index f3e94b71..48aaf4fe 100644 --- a/Compilation/ILCompiler.Generators.cs +++ b/Compilation/ILCompiler.Generators.cs @@ -552,9 +552,12 @@ private void EmitGeneratorInstanceStubMethod( // into it so an arrow that writes that parameter shares the generator's storage. Instance // methods carry 'this' at arg 0, so user params start at arg 1 (paramOffset: 1). The stub // params are typed, so EmitGeneratorFunctionDCInit boxes value types before the store. No-op - // when the method has no function DC. + // when the method has no function DC. Pass the CLR boxing types from the method's ACTUAL IL + // signature (same source as the field-seeding loop above), so widened/all-object slots are not + // spuriously boxed. if (funcDCKey != null) - EmitGeneratorFunctionDCInit(il, smBuilder.FunctionDCField, method, funcDCKey, paramOffset: 1, paramTypes); + EmitGeneratorFunctionDCInit(il, smBuilder.FunctionDCField, method, funcDCKey, paramOffset: 1, + paramTypes.Select(p => p.ParameterType).ToArray()); // Captured outer-scope variables are NOT copied into the state machine (#541): see the // free-function stub above. MoveNext reads/writes them live from their backing storage,