From 6dd3ecd54bedca4e18ee098a1e357561c5b4cef2 Mon Sep 17 00:00:00 2001 From: Andy Gocke Date: Tue, 1 Nov 2016 13:57:30 -0700 Subject: [PATCH] Change visit order for local function definite assignment (#14835) This change visits the parameters before "replaying" reads+writes from calls of local functions for the purposes of definite assignment. This ordering is observable because a variable can be definitely assigned in the argument to the call, and then used inside the call. Fixes #14243 --- .../Portable/FlowAnalysis/DataFlowPass.cs | 6 +++- .../Semantic/FlowAnalysis/LocalFunctions.cs | 32 +++++++++++++++++++ 2 files changed, 37 insertions(+), 1 deletion(-) diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs index e4690f7f9e5..bbfe049f7e5 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/DataFlowPass.cs @@ -1761,12 +1761,16 @@ public override BoundNode VisitLocalDeclaration(BoundLocalDeclaration node) public override BoundNode VisitCall(BoundCall node) { + // Always visit the arguments first + var result = base.VisitCall(node); + if (node.Method.MethodKind == MethodKind.LocalFunction) { var localFunc = (LocalFunctionSymbol)node.Method.OriginalDefinition; ReplayReadsAndWrites(localFunc, node.Syntax, writes: true); } - return base.VisitCall(node); + + return result; } public override BoundNode VisitConversion(BoundConversion node) diff --git a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/LocalFunctions.cs b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/LocalFunctions.cs index c08a835a6ba..8679e0b6e00 100644 --- a/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/LocalFunctions.cs +++ b/src/Compilers/CSharp/Test/Semantic/FlowAnalysis/LocalFunctions.cs @@ -7,6 +7,38 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests [CompilerTrait(CompilerFeature.LocalFunctions)] public class LocalFunctions : FlowTestBase { + [Fact] + [WorkItem(14243, "https://github.com/dotnet/roslyn/issues/14243")] + public void AssignInsideCallToLocalFunc() + { + var comp = CreateCompilationWithMscorlib(@" +class C +{ + public void M() + { + int x; + int Local(int p1) => x++; + + Local(x = 0); + + int z; + int Local2(int p1, int p2) => z++; + Local2(z = 0, z++); + } + + public void M2() + { + int x; + int Local(int p1) => x++; + int Local2(int p1) => Local(p1); + int Local3(int p1) => x + Local2(p1); + + Local3(x = 0); + } +}"); + comp.VerifyDiagnostics(); + } + [Fact] [WorkItem(14046, "https://github.com/dotnet/roslyn/issues/14046")] public void UnreachableAfterThrow() -- GitLab