Browse Source

Merge pull request #4080 from icsharpcode/fix-3714-local-function-scope

Fix #3714: declare a local function in its innermost capture scope
pull/4085/head
Siegfried Pammer 2 weeks ago committed by GitHub
parent
commit
48bf055809
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
  1. 25
      ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs
  2. 15
      ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

25
ICSharpCode.Decompiler.Tests/TestCases/Pretty/LocalFunctions.cs

@ -877,5 +877,30 @@ namespace LocalFunctions @@ -877,5 +877,30 @@ namespace LocalFunctions
static extern int EnumWindows(long hWnd, long lParam);
}
#endif
public int Issue3714_LocalFunctionInsideLambda()
{
int outer = 1;
#if !OPT
Action action = () => {
#else
((Action)(() => {
#endif
int inner = 2;
Local(3);
Console.WriteLine(inner);
void Local(int d)
{
inner += d;
outer += d;
}
#if !OPT
};
action();
#else
}))();
#endif
return outer;
}
}
}

15
ICSharpCode.Decompiler/IL/Transforms/LocalFunctionDecompiler.cs

@ -732,8 +732,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms @@ -732,8 +732,21 @@ namespace ICSharpCode.Decompiler.IL.Transforms
}
if (function.DeclarationScope == null)
function.DeclarationScope = closureVar.CaptureScope;
else if (!IsInNestedLocalFunction(function.DeclarationScope, closureVar.CaptureScope.Ancestors.OfType<ILFunction>().First()))
else if (closureVar.CaptureScope.IsDescendantOf(function.DeclarationScope))
{
// The closures captured by one local function are nested in one another: a
// local function declared inside a lambda still reaches the enclosing method's
// closure, but not the other way round. Where one capture scope contains the
// other, the declaration belongs in the inner one; taking the common ancestor
// would move the function out of the lambda owning the deeper closure and
// leave the variables captured there out of scope.
function.DeclarationScope = closureVar.CaptureScope;
}
else if (!function.DeclarationScope.IsDescendantOf(closureVar.CaptureScope)
&& !IsInNestedLocalFunction(function.DeclarationScope, closureVar.CaptureScope.Ancestors.OfType<ILFunction>().First()))
{
function.DeclarationScope = FindCommonAncestorInstruction<BlockContainer>(function.DeclarationScope, closureVar.CaptureScope);
}
return true;
ILInstruction GetClosureInitializer(ILVariable variable)

Loading…
Cancel
Save