提交 338174ad 编写于 作者: A Andy Gocke 提交者: GitHub

Alter definite assignment for async and iterator local functions (#14096)

This PR both adds the missing branches (yield/await) for async and iterator
local functions and also incorporates the implicit branch before the first
statement of an iterator local function.

Fixes #13762
上级 4fa67069
// Copyright (c) Microsoft. All Rights Reserved. Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Roslyn.Utilities;
using System;
using System.Collections.Immutable;
using System.Diagnostics;
......@@ -107,6 +108,14 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen
if (!localFunc.WasCompilerGenerated) EnterParameters(localFunc.Symbol.Parameters);
var oldPending2 = SavePending();
// If this is an iterator, there's an implicit branch before the first statement
// of the function where the enumerable is returned.
if (localFunc.Symbol.IsIterator)
{
PendingBranches.Add(new PendingBranch(null, this.State));
}
VisitAlways(localFunc.Body);
RestorePending(oldPending2); // process any forward branches within the lambda body
ImmutableArray<PendingBranch> pendingReturns = RemoveReturns();
......@@ -126,17 +135,10 @@ public override BoundNode VisitLocalFunctionStatement(BoundLocalFunctionStatemen
{
this.State = pending.State;
BoundNode branch = pending.Branch;
if (branch.Kind == BoundKind.ReturnStatement)
{
// ensure out parameters are definitely assigned at each return
LeaveParameters(localFunc.Symbol.Parameters, branch.Syntax,
branch.WasCompilerGenerated ? location : null);
IntersectWith(ref stateAtReturn, ref this.State);
}
else
{
// other ways of branching out of a lambda are errors, previously reported in control-flow analysis
}
LeaveParameters(localFunc.Symbol.Parameters, branch?.Syntax,
branch?.WasCompilerGenerated == true
? location : null);
IntersectWith(ref stateAtReturn, ref this.State);
}
// Check for changes to the read and write sets
......
using Microsoft.CodeAnalysis.Test.Utilities;
using Roslyn.Test.Utilities;
using Xunit;
namespace Microsoft.CodeAnalysis.CSharp.UnitTests
......@@ -6,6 +7,135 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests
[CompilerTrait(CompilerFeature.LocalFunctions)]
public class LocalFunctions : FlowTestBase
{
[Fact]
public void InvalidBranchOutOfLocalFunc()
{
var comp = CreateCompilationWithMscorlib(@"
class C
{
public static void M()
{
label1:
L();
L2();
L3();
void L()
{
goto label1;
}
void L2()
{
break;
}
void L3()
{
continue;
}
}
}");
comp.VerifyDiagnostics(
// (14,13): error CS0159: No such label 'label1' within the scope of the goto statement
// goto label1;
Diagnostic(ErrorCode.ERR_LabelNotFound, "goto").WithArguments("label1").WithLocation(14, 13),
// (19,13): error CS0139: No enclosing loop out of which to break or continue
// break;
Diagnostic(ErrorCode.ERR_NoBreakOrCont, "break;").WithLocation(19, 13),
// (24,13): error CS0139: No enclosing loop out of which to break or continue
// continue;
Diagnostic(ErrorCode.ERR_NoBreakOrCont, "continue;").WithLocation(24, 13),
// (6,9): warning CS0164: This label has not been referenced
// label1:
Diagnostic(ErrorCode.WRN_UnreferencedLabel, "label1").WithLocation(6, 9));
}
[Fact]
[WorkItem(13762, "https://github.com/dotnet/roslyn/issues/13762")]
public void AssignsInAsync()
{
var comp = CreateCompilationWithMscorlib46(@"
using System.Threading.Tasks;
class C
{
public static void M2()
{
int a=0, x, y, z;
L1();
a++;
x++;
y++;
z++;
async void L1()
{
x = 0;
await Task.Delay(0);
y = 0;
}
}
}");
comp.VerifyDiagnostics(
// (12,9): error CS0165: Use of unassigned local variable 'y'
// y++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y").WithArguments("y").WithLocation(12, 9),
// (13,9): error CS0165: Use of unassigned local variable 'z'
// z++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "z").WithArguments("z").WithLocation(13, 9));
}
[Fact]
[WorkItem(13762, "https://github.com/dotnet/roslyn/issues/13762")]
public void AssignsInIterator()
{
var comp = CreateCompilationWithMscorlib46(@"
using System.Collections.Generic;
class C
{
public static void M2()
{
int a=0, w, x, y, z;
L1();
a++;
w++;
x++;
y++;
z++;
IEnumerable<bool> L1()
{
w = 0;
yield return false;
x = 0;
yield break;
y = 0;
}
}
}");
comp.VerifyDiagnostics(
// (24,13): warning CS0162: Unreachable code detected
// y = 0;
Diagnostic(ErrorCode.WRN_UnreachableCode, "y").WithLocation(24, 13),
// (13,9): error CS0165: Use of unassigned local variable 'w'
// w++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "w").WithArguments("w").WithLocation(13, 9),
// (14,9): error CS0165: Use of unassigned local variable 'x'
// x++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "x").WithArguments("x").WithLocation(14, 9),
// (15,9): error CS0165: Use of unassigned local variable 'y'
// y++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "y").WithArguments("y").WithLocation(15, 9),
// (16,9): error CS0165: Use of unassigned local variable 'z'
// z++;
Diagnostic(ErrorCode.ERR_UseDefViolation, "z").WithArguments("z").WithLocation(16, 9));
}
[Fact]
public void SimpleForwardCall()
{
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册