diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs index 98a3179932f70..216cca9ee6d9e 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.Analysis.cs @@ -246,9 +246,13 @@ private void InlineThisOnlyEnvironments() } else { - // Class-based 'this' closures can move member functions - // to the top-level type and environments which capture - // the 'this' environment can capture 'this' directly + // Class-based 'this' closures can move member functions to + // the top-level type and environments which capture the 'this' + // environment can capture 'this' directly. + // Note: the top-level type is treated as the initial containing + // environment, so by removing the 'this' environment, all + // nested environments which captured a pointer to the 'this' + // environment will now capture 'this' RemoveEnv(); VisitClosures(ScopeTree, (scope, closure) => { @@ -257,35 +261,6 @@ private void InlineThisOnlyEnvironments() closure.ContainingEnvironmentOpt = null; } }); - - // Find all environments in the scope below that could - // capture the parent. If there are any, add 'this' to - // the list of captured variables and remove the parent - // link - VisitFirstLevelScopes(ScopeTree); - void VisitFirstLevelScopes(Scope scope) - { - var classEnvs = scope.DeclaredEnvironments.Where(e => !e.IsStruct); - if (classEnvs.IsEmpty()) - { - // Keep looking for nested environments - foreach (var nested in scope.NestedScopes) - { - VisitFirstLevelScopes(nested); - } - } - else - { - foreach (var declEnv in classEnvs) - { - if (declEnv.CapturesParent) - { - declEnv.CapturedVariables.Insert(0, thisParam); - declEnv.CapturesParent = false; - } - } - } - } } void RemoveEnv() diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs index 1e4c9b4c98d11..9a8c3dc5de783 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs @@ -187,8 +187,7 @@ public MappedLocalFunction(SynthesizedLambdaMethod symbol, ClosureKind closureKi _assignLocals = assignLocals; _currentTypeParameters = method.TypeParameters; _currentLambdaBodyTypeMap = TypeMap.Empty; - _innermostFramePointer = null; - _currentFrameThis = thisParameterOpt; + _innermostFramePointer = _currentFrameThis = thisParameterOpt; _framePointers[thisType] = thisParameterOpt; _seenBaseCall = method.MethodKind != MethodKind.Constructor; // only used for ctors _synthesizedFieldNameIdDispenser = 1; diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs index 653af28ed10ed..efc27dfc74c8f 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenLocalFunctionTests.cs @@ -30,6 +30,72 @@ public static IMethodSymbol FindLocalFunction(this CompilationVerifier verifier, [CompilerTrait(CompilerFeature.LocalFunctions)] public class CodeGenLocalFunctionTests : CSharpTestBase { + [Fact] + public void CaptureThisInDifferentScopes() + { + CompileAndVerify(@" +using System; +class C +{ + int _x; + void M() + { + { + int y = 0; + Func f1 = () => _x + y; + } + { + int y = 0; + Func f2 = () => _x + y; + } + } +}"); + } + + [Fact] + public void CaptureThisInDifferentScopes2() + { + CompileAndVerify(@" +using System; +class C +{ + int _x; + void M() + { + { + int y = 0; + int L1() => _x + y; + } + { + int y = 0; + int L2() => _x + y; + } + } +}"); + } + + [Fact] + public void CaptureFramePointerInDifferentScopes() + { + CompileAndVerify(@" +using System; +class C +{ + void M(int x) + { + Func f1 = () => x; + { + int z = 0; + Func f2 = () => x + z; + } + { + int z = 0; + Func f3 = () => x + z; + } + } +}"); + } + [Fact] public void EnvironmentChainContainsStructEnvironment() {