diff --git a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs index efeed6c6ab811a450dfc6a548c3f8d70d7b0db0e..104792c183d678d26a29616f070c3327b6c7e115 100644 --- a/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs +++ b/src/Compilers/CSharp/Portable/BoundTree/UnboundLambda.cs @@ -367,7 +367,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) } else { - block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol, _unboundLambda.Syntax); + block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol); } } diff --git a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs index 72f2190c0a8df16a92cec072c475fdf42d193c4f..a785848806066e6de3277b390de6129e6c36d6d8 100644 --- a/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs +++ b/src/Compilers/CSharp/Portable/CodeGen/EmitStatement.cs @@ -634,7 +634,7 @@ private bool ShouldUseIndirectReturn() private bool CanHandleReturnLabel(BoundReturnStatement boundReturnStatement) { return boundReturnStatement.WasCompilerGenerated && - (boundReturnStatement.Syntax.Kind() == SyntaxKind.Block || (((object)_method != null) && _method.IsImplicitConstructor)) && + (boundReturnStatement.Syntax.IsKind(SyntaxKind.Block) || _method?.IsImplicitConstructor == true) && !_builder.InExceptionHandler; } diff --git a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs index 7aa4555a815ea2489d2e7bfee0c0bea41d56f668..6c7ae7b507230e8579437757f1dbea8129257e62 100644 --- a/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs +++ b/src/Compilers/CSharp/Portable/FlowAnalysis/FlowAnalysisPass.cs @@ -31,8 +31,7 @@ internal class FlowAnalysisPass // we don't analyze synthesized void methods. if (method.IsImplicitlyDeclared || Analyze(compilation, method, block, diagnostics)) { - var sourceMethod = method as SourceMethodSymbol; - block = AppendImplicitReturn(block, method, ((object)sourceMethod != null) ? sourceMethod.BodySyntax as BlockSyntax : null); + block = AppendImplicitReturn(block, method, (CSharpSyntaxNode)(method as SourceMethodSymbol)?.BodySyntax); } } else if (!method.IsScriptInitializer && Analyze(compilation, method, block, diagnostics)) @@ -56,42 +55,41 @@ internal class FlowAnalysisPass // insert the implicit "return" statement at the end of the method body // Normally, we wouldn't bother attaching syntax trees to compiler-generated nodes, but these // ones are going to have sequence points. - internal static BoundBlock AppendImplicitReturn(BoundStatement node, MethodSymbol method, CSharpSyntaxNode syntax = null) + internal static BoundBlock AppendImplicitReturn(BoundBlock body, MethodSymbol method, CSharpSyntaxNode syntax = null) { + Debug.Assert(body != null); Debug.Assert(method != null); if (syntax == null) { - syntax = node.Syntax; + syntax = body.Syntax; } + Debug.Assert(body.WasCompilerGenerated || syntax.IsKind(SyntaxKind.Block) || syntax.IsKind(SyntaxKind.ArrowExpressionClause)); + BoundStatement ret = method.IsIterator ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax) : BoundReturnStatement.Synthesized(syntax, null); - if (syntax.Kind() == SyntaxKind.Block) + // Implicitly added return for async method does not need sequence points since lowering would add one. + if (syntax.IsKind(SyntaxKind.Block) && !method.IsAsync) { - // Implicitly added return for async method does not need sequence points since lowering would add one. - if (!method.IsAsync) - { - var blockSyntax = (BlockSyntax)syntax; + var blockSyntax = (BlockSyntax)syntax; - ret = new BoundSequencePointWithSpan( - blockSyntax, - ret, - blockSyntax.CloseBraceToken.Span) - { WasCompilerGenerated = true }; - } + ret = new BoundSequencePointWithSpan( + blockSyntax, + ret, + blockSyntax.CloseBraceToken.Span) + { WasCompilerGenerated = true }; } - switch (node.Kind) + switch (body.Kind) { case BoundKind.Block: - var block = (BoundBlock)node; - return block.Update(block.Locals, block.Statements.Add(ret)); + return body.Update(body.Locals, body.Statements.Add(ret)); default: - return new BoundBlock(syntax, ImmutableArray.Empty, ImmutableArray.Create(ret, node)); + return new BoundBlock(syntax, ImmutableArray.Empty, ImmutableArray.Create(ret, body)); } } diff --git a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs index ce2a5cf49736fcd4b7a7c316827e6eebaf9e7a58..c278116d84a3580f6f4b4e18944aef0b9865a3ea 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LambdaRewriter/LambdaRewriter.cs @@ -312,8 +312,9 @@ private LambdaFrame GetFrameForScope(BoundNode scope, ArrayBuilderc.b__2_0", @" { - // Code size 11 (0xb) + // Code size 9 (0x9) .maxstack 1 IL_0000: nop IL_0001: ldc.i4.1 IL_0002: call ""void System.Console.WriteLine(int)"" IL_0007: nop - IL_0008: br.s IL_000a - IL_000a: ret + IL_0008: ret }"); var diff2 = compilation2.EmitDifference( @@ -1311,7 +1310,7 @@ .maxstack 1 // lambda body updated: diff2.VerifyIL("C.<>c.b__2_0", @" { - // Code size 18 (0x12) + // Code size 16 (0x10) .maxstack 1 IL_0000: nop IL_0001: ldc.i4.1 @@ -1320,8 +1319,7 @@ .maxstack 1 IL_0008: ldc.i4.2 IL_0009: call ""void System.Console.WriteLine(int)"" IL_000e: nop - IL_000f: br.s IL_0011 - IL_0011: ret + IL_000f: ret }"); } diff --git a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs index 8cb302c3fc8c31e7dccb6cf9e71296cd6e4e5822..9e7ff84b8ced554305bfd101d86def7fc9da0c74 100644 --- a/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs +++ b/src/Compilers/CSharp/Test/Emit/Emit/EditAndContinue/LocalSlotMappingTests.cs @@ -2722,7 +2722,7 @@ static void M() var v0 = CompileAndVerify(compilation0); v0.VerifyIL("C.<>c.b__1_0()", @" { - // Code size 36 (0x24) + // Code size 34 (0x22) .maxstack 2 .locals init (object V_0, bool V_1) @@ -2750,8 +2750,7 @@ .maxstack 2 IL_001f: nop IL_0020: endfinally } - IL_0021: br.s IL_0023 - IL_0023: ret + IL_0021: ret }"); #if TODO // identify the lambda in a semantic edit diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBConstantTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBConstantTests.cs index b1649a4ad79039c396f362de2da0c7b280716f07..2af0ec97b7b2f8306d20eaa8ad92056df6015413 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBConstantTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBConstantTests.cs @@ -107,9 +107,9 @@ void M(Action a) - + - + diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBDynamicLocalsTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBDynamicLocalsTests.cs index dd3eae0a5f168908158d4c59e1f524204aa6b46e..6896629b4f20a679a53cd3744b26e91284003119 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBDynamicLocalsTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBDynamicLocalsTests.cs @@ -994,10 +994,10 @@ public static void Main(string[] args) - + - - + + diff --git a/src/Compilers/CSharp/Test/Emit/PDB/PDBLambdaTests.cs b/src/Compilers/CSharp/Test/Emit/PDB/PDBLambdaTests.cs index 63e4b13fd482ff559c6ae3dd8d12bed791225261..38d2e5daf5304b639a20b02f088e5ead0cef9038 100644 --- a/src/Compilers/CSharp/Test/Emit/PDB/PDBLambdaTests.cs +++ b/src/Compilers/CSharp/Test/Emit/PDB/PDBLambdaTests.cs @@ -1330,5 +1330,89 @@ static void F() "); } + + [Fact] + public void IfStatement1() + { + string source = @" +class C +{ + static void F() + { + new System.Action(() => + { + bool result = false; + if (result) + System.Console.WriteLine(1); + })(); + } +} +"; + var v = CompileAndVerify(source, options: TestOptions.DebugDll); + + v.VerifyIL("C.<>c.b__0_0", @" +{ + // Code size 16 (0x10) + .maxstack 1 + .locals init (bool V_0, //result + bool V_1) + -IL_0000: nop + -IL_0001: ldc.i4.0 + IL_0002: stloc.0 + -IL_0003: ldloc.0 + IL_0004: stloc.1 + ~IL_0005: ldloc.1 + IL_0006: brfalse.s IL_000f + -IL_0008: ldc.i4.1 + IL_0009: call ""void System.Console.WriteLine(int)"" + IL_000e: nop + -IL_000f: ret +} +", sequencePoints: "C+<>c.b__0_0"); + } + + [Fact] + public void IfStatement2() + { + string source = @" +class C +{ + static void F() + { + new System.Action(() => + { + { + bool result = false; + if (result) + System.Console.WriteLine(1); + } + })(); + } +} +"; + var v = CompileAndVerify(source, options: TestOptions.DebugDll); + + v.VerifyIL("C.<>c.b__0_0", @" +{ + // Code size 18 (0x12) + .maxstack 1 + .locals init (bool V_0, //result + bool V_1) + -IL_0000: nop + -IL_0001: nop + -IL_0002: ldc.i4.0 + IL_0003: stloc.0 + -IL_0004: ldloc.0 + IL_0005: stloc.1 + ~IL_0006: ldloc.1 + IL_0007: brfalse.s IL_0010 + -IL_0009: ldc.i4.1 + IL_000a: call ""void System.Console.WriteLine(int)"" + IL_000f: nop + -IL_0010: nop + -IL_0011: ret +} +", sequencePoints: "C+<>c.b__0_0"); + } } }