Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion Compilation/AsyncArrowMoveNextEmitter.ArrowFunctions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -66,7 +66,7 @@ private void EmitCapturingArrowInAsyncArrow(Expr.ArrowFunction af, MethodBuilder
{
_il.Emit(OpCodes.Dup); // Keep display class instance on stack

// Load the captured variable using the same logic as LoadVariable
// Load the captured variable using the capture-population loader
LoadVariableForCapture(capturedVar);

_il.Emit(OpCodes.Stfld, field);
Expand Down
85 changes: 1 addition & 84 deletions Compilation/AsyncArrowMoveNextEmitter.Variables.cs
Original file line number Diff line number Diff line change
Expand Up @@ -140,89 +140,6 @@ protected override void EmitAssign(Expr.Assign a)

protected override void EmitStoreVariable(string name) => StoreVariable(name);

private void LoadVariable(string name)
{
// Check if it's a parameter of this arrow
if (_builder.ParameterFields.TryGetValue(name, out var paramField))
{
_il.Emit(OpCodes.Ldarg_0);
_il.Emit(OpCodes.Ldfld, paramField);
SetStackUnknown();
return;
}

// Check if it's a hoisted local of this arrow
if (_builder.LocalFields.TryGetValue(name, out var localField))
{
_il.Emit(OpCodes.Ldarg_0);
_il.Emit(OpCodes.Ldfld, localField);
SetStackUnknown();
return;
}

// Check if it's captured from outer scope
if (_builder.IsCaptured(name) && _builder.CapturedFieldMap.TryGetValue(name, out var outerField))
{
// Load through outer reference
// Use Unbox (not Unbox_Any) to get a pointer to the boxed struct, then load field
_il.Emit(OpCodes.Ldarg_0);
_il.Emit(OpCodes.Ldfld, _builder.OuterStateMachineField!);

// Check if this is a transitive capture (needs extra indirection through parent's outer)
if (_builder.TransitiveCaptures.Contains(name) &&
_builder.ParentOuterStateMachineField != null &&
_builder.GrandparentStateMachineType != null)
{
// First unbox to parent, then load parent's outer reference
_il.Emit(OpCodes.Unbox, _builder.OuterStateMachineType!);
_il.Emit(OpCodes.Ldfld, _builder.ParentOuterStateMachineField);
_il.Emit(OpCodes.Unbox, _builder.GrandparentStateMachineType);
}
else
{
_il.Emit(OpCodes.Unbox, _builder.OuterStateMachineType!);
}

_il.Emit(OpCodes.Ldfld, outerField);
SetStackUnknown();
return;
}

// Check for non-hoisted local variable
if (_locals.TryGetValue(name, out var local))
{
_il.Emit(OpCodes.Ldloc, local);
SetStackUnknown();
return;
}

// Check if it's an imported value (from another module) - must check BEFORE Functions
// because cross-module function references need to go through the import field
if (_ctx?.TopLevelStaticVars?.TryGetValue(name, out var topLevelField) == true)
{
_il.Emit(OpCodes.Ldsfld, topLevelField);
SetStackUnknown();
return;
}

// Check if it's a global function
if (_ctx?.Functions.TryGetValue(_ctx.ResolveFunctionName(name), out var funcMethod) == true)
{
// Load function reference
_il.Emit(OpCodes.Ldnull);
_il.Emit(OpCodes.Ldtoken, funcMethod);
_il.Emit(OpCodes.Call, Types.MethodBaseGetMethodFromHandle);
_il.Emit(OpCodes.Castclass, typeof(MethodInfo));
_il.Emit(OpCodes.Newobj, _ctx.Runtime!.TSFunctionCtor);
SetStackUnknown();
return;
}

// Fallback: null
_il.Emit(OpCodes.Ldnull);
SetStackType(StackType.Null);
}

private void StoreVariable(string name)
{
// A capture promoted into the enclosing function's display class (#625) is stored through
Expand Down Expand Up @@ -325,7 +242,7 @@ private void StoreVariable(string name)

/// <summary>
/// Loads a variable value for populating a capture in a non-async arrow's display class.
/// This is similar to LoadVariable but designed for capture population.
/// This is similar to the EmitVariable override but designed for capture population.
/// </summary>
private void LoadVariableForCapture(string name)
{
Expand Down
Loading