提交 9ac1e621 编写于 作者: T Tomas Matousek

Fix syntax associated with bound implicit return statement

上级 5ef9ff2f
...@@ -367,7 +367,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType) ...@@ -367,7 +367,7 @@ private BoundLambda ReallyBind(NamedTypeSymbol delegateType)
} }
else else
{ {
block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol, _unboundLambda.Syntax); block = FlowAnalysisPass.AppendImplicitReturn(block, lambdaSymbol);
} }
} }
......
...@@ -634,7 +634,7 @@ private bool ShouldUseIndirectReturn() ...@@ -634,7 +634,7 @@ private bool ShouldUseIndirectReturn()
private bool CanHandleReturnLabel(BoundReturnStatement boundReturnStatement) private bool CanHandleReturnLabel(BoundReturnStatement boundReturnStatement)
{ {
return boundReturnStatement.WasCompilerGenerated && return boundReturnStatement.WasCompilerGenerated &&
(boundReturnStatement.Syntax.Kind() == SyntaxKind.Block || (((object)_method != null) && _method.IsImplicitConstructor)) && (boundReturnStatement.Syntax.IsKind(SyntaxKind.Block) || _method?.IsImplicitConstructor == true) &&
!_builder.InExceptionHandler; !_builder.InExceptionHandler;
} }
......
...@@ -31,8 +31,7 @@ internal class FlowAnalysisPass ...@@ -31,8 +31,7 @@ internal class FlowAnalysisPass
// we don't analyze synthesized void methods. // we don't analyze synthesized void methods.
if (method.IsImplicitlyDeclared || Analyze(compilation, method, block, diagnostics)) if (method.IsImplicitlyDeclared || Analyze(compilation, method, block, diagnostics))
{ {
var sourceMethod = method as SourceMethodSymbol; block = AppendImplicitReturn(block, method, (CSharpSyntaxNode)(method as SourceMethodSymbol)?.BodySyntax);
block = AppendImplicitReturn(block, method, ((object)sourceMethod != null) ? sourceMethod.BodySyntax as BlockSyntax : null);
} }
} }
else if (!method.IsScriptInitializer && Analyze(compilation, method, block, diagnostics)) else if (!method.IsScriptInitializer && Analyze(compilation, method, block, diagnostics))
...@@ -56,42 +55,41 @@ internal class FlowAnalysisPass ...@@ -56,42 +55,41 @@ internal class FlowAnalysisPass
// insert the implicit "return" statement at the end of the method body // 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 // Normally, we wouldn't bother attaching syntax trees to compiler-generated nodes, but these
// ones are going to have sequence points. // 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); Debug.Assert(method != null);
if (syntax == 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 ret = method.IsIterator
? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax) ? (BoundStatement)BoundYieldBreakStatement.Synthesized(syntax)
: BoundReturnStatement.Synthesized(syntax, null); : 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. var blockSyntax = (BlockSyntax)syntax;
if (!method.IsAsync)
{
var blockSyntax = (BlockSyntax)syntax;
ret = new BoundSequencePointWithSpan( ret = new BoundSequencePointWithSpan(
blockSyntax, blockSyntax,
ret, ret,
blockSyntax.CloseBraceToken.Span) blockSyntax.CloseBraceToken.Span)
{ WasCompilerGenerated = true }; { WasCompilerGenerated = true };
}
} }
switch (node.Kind) switch (body.Kind)
{ {
case BoundKind.Block: case BoundKind.Block:
var block = (BoundBlock)node; return body.Update(body.Locals, body.Statements.Add(ret));
return block.Update(block.Locals, block.Statements.Add(ret));
default: default:
return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create(ret, node)); return new BoundBlock(syntax, ImmutableArray<LocalSymbol>.Empty, ImmutableArray.Create(ret, body));
} }
} }
......
...@@ -312,8 +312,9 @@ private LambdaFrame GetFrameForScope(BoundNode scope, ArrayBuilder<ClosureDebugI ...@@ -312,8 +312,9 @@ private LambdaFrame GetFrameForScope(BoundNode scope, ArrayBuilder<ClosureDebugI
CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(this.ContainingType, frame); CompilationState.ModuleBuilderOpt.AddSynthesizedDefinition(this.ContainingType, frame);
CompilationState.AddSynthesizedMethod( CompilationState.AddSynthesizedMethod(
frame.Constructor, frame.Constructor,
FlowAnalysisPass.AppendImplicitReturn(MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null), FlowAnalysisPass.AppendImplicitReturn(
frame.Constructor)); MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null),
frame.Constructor));
} }
return frame; return frame;
...@@ -358,8 +359,9 @@ private LambdaFrame GetStaticFrame(DiagnosticBag diagnostics, BoundNode lambda) ...@@ -358,8 +359,9 @@ private LambdaFrame GetStaticFrame(DiagnosticBag diagnostics, BoundNode lambda)
// add its ctor // add its ctor
CompilationState.AddSynthesizedMethod( CompilationState.AddSynthesizedMethod(
frame.Constructor, frame.Constructor,
FlowAnalysisPass.AppendImplicitReturn(MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null), FlowAnalysisPass.AppendImplicitReturn(
frame.Constructor)); MethodCompiler.BindMethodBody(frame.Constructor, CompilationState, null),
frame.Constructor));
// associate the frame with the first lambda that caused it to exist. // associate the frame with the first lambda that caused it to exist.
// we need to associate this with some syntax. // we need to associate this with some syntax.
......
...@@ -1289,14 +1289,13 @@ private void F() ...@@ -1289,14 +1289,13 @@ private void F()
// lambda body unchanged: // lambda body unchanged:
diff1.VerifyIL("C.<>c.<F>b__2_0", @" diff1.VerifyIL("C.<>c.<F>b__2_0", @"
{ {
// Code size 11 (0xb) // Code size 9 (0x9)
.maxstack 1 .maxstack 1
IL_0000: nop IL_0000: nop
IL_0001: ldc.i4.1 IL_0001: ldc.i4.1
IL_0002: call ""void System.Console.WriteLine(int)"" IL_0002: call ""void System.Console.WriteLine(int)""
IL_0007: nop IL_0007: nop
IL_0008: br.s IL_000a IL_0008: ret
IL_000a: ret
}"); }");
var diff2 = compilation2.EmitDifference( var diff2 = compilation2.EmitDifference(
...@@ -1311,7 +1310,7 @@ .maxstack 1 ...@@ -1311,7 +1310,7 @@ .maxstack 1
// lambda body updated: // lambda body updated:
diff2.VerifyIL("C.<>c.<F>b__2_0", @" diff2.VerifyIL("C.<>c.<F>b__2_0", @"
{ {
// Code size 18 (0x12) // Code size 16 (0x10)
.maxstack 1 .maxstack 1
IL_0000: nop IL_0000: nop
IL_0001: ldc.i4.1 IL_0001: ldc.i4.1
...@@ -1320,8 +1319,7 @@ .maxstack 1 ...@@ -1320,8 +1319,7 @@ .maxstack 1
IL_0008: ldc.i4.2 IL_0008: ldc.i4.2
IL_0009: call ""void System.Console.WriteLine(int)"" IL_0009: call ""void System.Console.WriteLine(int)""
IL_000e: nop IL_000e: nop
IL_000f: br.s IL_0011 IL_000f: ret
IL_0011: ret
}"); }");
} }
......
...@@ -2722,7 +2722,7 @@ static void M() ...@@ -2722,7 +2722,7 @@ static void M()
var v0 = CompileAndVerify(compilation0); var v0 = CompileAndVerify(compilation0);
v0.VerifyIL("C.<>c.<M>b__1_0()", @" v0.VerifyIL("C.<>c.<M>b__1_0()", @"
{ {
// Code size 36 (0x24) // Code size 34 (0x22)
.maxstack 2 .maxstack 2
.locals init (object V_0, .locals init (object V_0,
bool V_1) bool V_1)
...@@ -2750,8 +2750,7 @@ .maxstack 2 ...@@ -2750,8 +2750,7 @@ .maxstack 2
IL_001f: nop IL_001f: nop
IL_0020: endfinally IL_0020: endfinally
} }
IL_0021: br.s IL_0023 IL_0021: ret
IL_0023: ret
}"); }");
#if TODO // identify the lambda in a semantic edit #if TODO // identify the lambda in a semantic edit
......
...@@ -107,9 +107,9 @@ void M(Action a) ...@@ -107,9 +107,9 @@ void M(Action a)
<entry offset=""0x0"" startLine=""10"" startColumn=""9"" endLine=""10"" endColumn=""10"" /> <entry offset=""0x0"" startLine=""10"" startColumn=""9"" endLine=""10"" endColumn=""10"" />
<entry offset=""0x1"" startLine=""12"" startColumn=""13"" endLine=""12"" endColumn=""14"" /> <entry offset=""0x1"" startLine=""12"" startColumn=""13"" endLine=""12"" endColumn=""14"" />
<entry offset=""0x2"" startLine=""14"" startColumn=""13"" endLine=""14"" endColumn=""14"" /> <entry offset=""0x2"" startLine=""14"" startColumn=""13"" endLine=""14"" endColumn=""14"" />
<entry offset=""0x5"" startLine=""15"" startColumn=""9"" endLine=""15"" endColumn=""10"" /> <entry offset=""0x3"" startLine=""15"" startColumn=""9"" endLine=""15"" endColumn=""10"" />
</sequencePoints> </sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x6""> <scope startOffset=""0x0"" endOffset=""0x4"">
<constant name=""y"" value=""2"" type=""Int32"" /> <constant name=""y"" value=""2"" type=""Int32"" />
<scope startOffset=""0x1"" endOffset=""0x3""> <scope startOffset=""0x1"" endOffset=""0x3"">
<constant name=""z"" value=""3"" type=""Int32"" /> <constant name=""z"" value=""3"" type=""Int32"" />
......
...@@ -994,10 +994,10 @@ public static void Main(string[] args) ...@@ -994,10 +994,10 @@ public static void Main(string[] args)
<sequencePoints> <sequencePoints>
<entry offset=""0x0"" startLine=""10"" startColumn=""32"" endLine=""10"" endColumn=""33"" /> <entry offset=""0x0"" startLine=""10"" startColumn=""32"" endLine=""10"" endColumn=""33"" />
<entry offset=""0x1"" startLine=""10"" startColumn=""46"" endLine=""10"" endColumn=""54"" /> <entry offset=""0x1"" startLine=""10"" startColumn=""46"" endLine=""10"" endColumn=""54"" />
<entry offset=""0x5"" startLine=""10"" startColumn=""55"" endLine=""10"" endColumn=""56"" /> <entry offset=""0x3"" startLine=""10"" startColumn=""55"" endLine=""10"" endColumn=""56"" />
</sequencePoints> </sequencePoints>
<scope startOffset=""0x0"" endOffset=""0x6""> <scope startOffset=""0x0"" endOffset=""0x4"">
<local name=""d5"" il_index=""0"" il_start=""0x0"" il_end=""0x6"" attributes=""0"" /> <local name=""d5"" il_index=""0"" il_start=""0x0"" il_end=""0x4"" attributes=""0"" />
</scope> </scope>
</method> </method>
<method containingType=""Test+&lt;&gt;c"" name=""&lt;Main&gt;b__2_2"" parameterNames=""d6""> <method containingType=""Test+&lt;&gt;c"" name=""&lt;Main&gt;b__2_2"" parameterNames=""d6"">
......
...@@ -1330,5 +1330,89 @@ static void F() ...@@ -1330,5 +1330,89 @@ static void F()
</symbols> </symbols>
"); ");
} }
[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.<F>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.<F>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.<F>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.<F>b__0_0");
}
} }
} }
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册