提交 629c6070 编写于 作者: A AlekseyTs

Variable declared within a while’ condition should be in scope only within the loop.

Related to #15630.
上级 e287d6e0
......@@ -274,8 +274,6 @@ internal BoundStatement BindPossibleEmbeddedStatement(StatementSyntax node, Diag
switch (node.Kind())
{
case SyntaxKind.ExpressionStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.LockStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.YieldReturnStatement:
......
......@@ -37,8 +37,6 @@ internal abstract class ExpressionVariableFinder<TFieldOrLocalSymbol> : CSharpSy
case SyntaxKind.ReturnStatement:
case SyntaxKind.YieldReturnStatement:
case SyntaxKind.ExpressionStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.LockStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.SwitchStatement:
......@@ -166,16 +164,6 @@ public override void VisitExpressionStatement(ExpressionStatementSyntax node)
VisitNodeToBind(node.Expression);
}
public override void VisitWhileStatement(WhileStatementSyntax node)
{
VisitNodeToBind(node.Condition);
}
public override void VisitDoStatement(DoStatementSyntax node)
{
VisitNodeToBind(node.Condition);
}
public override void VisitLockStatement(LockStatementSyntax node)
{
VisitNodeToBind(node.Expression);
......
......@@ -740,8 +740,6 @@ private Binder GetBinderForPossibleEmbeddedStatement(StatementSyntax statement,
// but we still want to bind it.
case SyntaxKind.ExpressionStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.LockStatement:
case SyntaxKind.IfStatement:
case SyntaxKind.YieldReturnStatement:
......
......@@ -199,11 +199,9 @@ protected ImmutableArray<LocalSymbol> BuildLocals(SyntaxList<StatementSyntax> st
ExpressionVariableFinder.FindExpressionVariables(this, locals, innerStatement, enclosingBinder.GetBinder(switchStatement.Expression) ?? enclosingBinder);
break;
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.LockStatement:
Binder statementBinder = enclosingBinder.GetBinder(innerStatement);
Debug.Assert(statementBinder != null); // Lock, Do and while loops always have binders.
Debug.Assert(statementBinder != null); // Lock always has a binder.
ExpressionVariableFinder.FindExpressionVariables(this, locals, innerStatement, statementBinder);
break;
......
......@@ -3,6 +3,7 @@
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
using Microsoft.CodeAnalysis.Text;
using Roslyn.Utilities;
using System.Diagnostics;
using System.Collections.Immutable;
......@@ -25,8 +26,8 @@ internal override BoundWhileStatement BindWhileParts(DiagnosticBag diagnostics,
var condition = originalBinder.BindBooleanExpression(node.Condition, diagnostics);
var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics);
Debug.Assert(this.Locals.IsDefaultOrEmpty);
return new BoundWhileStatement(node, condition, body, this.BreakLabel, this.ContinueLabel);
Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node));
return new BoundWhileStatement(node, this.Locals, condition, body, this.BreakLabel, this.ContinueLabel);
}
internal override BoundDoStatement BindDoParts(DiagnosticBag diagnostics, Binder originalBinder)
......@@ -35,8 +36,52 @@ internal override BoundDoStatement BindDoParts(DiagnosticBag diagnostics, Binder
var condition = originalBinder.BindBooleanExpression(node.Condition, diagnostics);
var body = originalBinder.BindPossibleEmbeddedStatement(node.Statement, diagnostics);
Debug.Assert(this.Locals.IsDefaultOrEmpty);
return new BoundDoStatement(node, condition, body, this.BreakLabel, this.ContinueLabel);
Debug.Assert(this.Locals == this.GetDeclaredLocalsForScope(node));
return new BoundDoStatement(node, this.Locals, condition, body, this.BreakLabel, this.ContinueLabel);
}
override protected ImmutableArray<LocalSymbol> BuildLocals()
{
var locals = ArrayBuilder<LocalSymbol>.GetInstance();
ExpressionSyntax condition;
switch (_syntax.Kind())
{
case SyntaxKind.WhileStatement:
condition = ((WhileStatementSyntax)_syntax).Condition;
break;
case SyntaxKind.DoStatement:
condition = ((DoStatementSyntax)_syntax).Condition;
break;
default:
throw ExceptionUtilities.UnexpectedValue(_syntax.Kind());
}
ExpressionVariableFinder.FindExpressionVariables(this, locals, node: condition);
return locals.ToImmutableAndFree();
}
internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(SyntaxNode scopeDesignator)
{
if (_syntax == scopeDesignator)
{
return this.Locals;
}
throw ExceptionUtilities.Unreachable;
}
internal override ImmutableArray<LocalFunctionSymbol> GetDeclaredLocalFunctionsForScope(CSharpSyntaxNode scopeDesignator)
{
throw ExceptionUtilities.Unreachable;
}
internal override SyntaxNode ScopeDesignator
{
get
{
return _syntax;
}
}
}
}
......@@ -849,11 +849,13 @@
</AbstractNode>
<Node Name="BoundDoStatement" Base="BoundLoopStatement">
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Body" Type="BoundStatement"/>
</Node>
<Node Name="BoundWhileStatement" Base="BoundLoopStatement">
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<Field Name="Condition" Type="BoundExpression"/>
<Field Name="Body" Type="BoundStatement"/>
</Node>
......
......@@ -1582,13 +1582,17 @@ public override BoundNode VisitForStatement(BoundForStatement node)
public override BoundNode VisitDoStatement(BoundDoStatement node)
{
DeclareVariables(node.Locals);
var result = base.VisitDoStatement(node);
ReportUnusedVariables(node.Locals);
return result;
}
public override BoundNode VisitWhileStatement(BoundWhileStatement node)
{
DeclareVariables(node.Locals);
var result = base.VisitWhileStatement(node);
ReportUnusedVariables(node.Locals);
return result;
}
......
......@@ -183,19 +183,9 @@ public override BoundExpression InstrumentWhileStatementCondition(BoundWhileStat
return Previous.InstrumentWhileStatementCondition(original, rewrittenCondition, factory);
}
public override BoundStatement InstrumentWhileStatementConditionalGotoStart(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
public override BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
{
return Previous.InstrumentWhileStatementConditionalGotoStart(original, ifConditionGotoStart);
}
public override BoundStatement InstrumentWhileStatementGotoContinue(BoundWhileStatement original, BoundStatement gotoContinue)
{
return Previous.InstrumentWhileStatementGotoContinue(original, gotoContinue);
}
public override BoundStatement InstrumentForEachStatementGotoContinue(BoundForEachStatement original, BoundStatement gotoContinue)
{
return Previous.InstrumentForEachStatementGotoContinue(original, gotoContinue);
return Previous.InstrumentWhileStatementConditionalGotoStartOrBreak(original, ifConditionGotoStart);
}
public override BoundExpression InstrumentCatchClauseFilter(BoundCatchBlock original, BoundExpression rewrittenFilter, SyntheticBoundNodeFactory factory)
......
......@@ -170,14 +170,14 @@ public override BoundStatement InstrumentDoStatementConditionalGotoStart(BoundDo
return new BoundSequencePointWithSpan(doSyntax, base.InstrumentDoStatementConditionalGotoStart(original, ifConditionGotoStart), span);
}
public override BoundStatement InstrumentWhileStatementConditionalGotoStart(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
public override BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
{
WhileStatementSyntax whileSyntax = (WhileStatementSyntax)original.Syntax;
TextSpan conditionSequencePointSpan = TextSpan.FromBounds(
whileSyntax.WhileKeyword.SpanStart,
whileSyntax.CloseParenToken.Span.End);
return new BoundSequencePointWithSpan(whileSyntax, base.InstrumentWhileStatementConditionalGotoStart(original, ifConditionGotoStart), conditionSequencePointSpan);
return new BoundSequencePointWithSpan(whileSyntax, base.InstrumentWhileStatementConditionalGotoStartOrBreak(original, ifConditionGotoStart), conditionSequencePointSpan);
}
private static BoundExpression AddConditionSequencePoint(BoundExpression condition, BoundStatement containingStatement, SyntheticBoundNodeFactory factory)
......@@ -399,16 +399,6 @@ public override BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement
base.InstrumentUsingTargetCapture(original, usingTargetCapture));
}
public override BoundStatement InstrumentForEachStatementGotoContinue(BoundForEachStatement original, BoundStatement gotoContinue)
{
return new BoundSequencePoint(null, base.InstrumentForEachStatementGotoContinue(original, gotoContinue));
}
public override BoundStatement InstrumentWhileStatementGotoContinue(BoundWhileStatement original, BoundStatement gotoContinue)
{
return new BoundSequencePoint(null, base.InstrumentWhileStatementGotoContinue(original, gotoContinue));
}
public override BoundExpression InstrumentCatchClauseFilter(BoundCatchBlock original, BoundExpression rewrittenFilter, SyntheticBoundNodeFactory factory)
{
rewrittenFilter = base.InstrumentCatchClauseFilter(original, rewrittenFilter, factory);
......
......@@ -190,9 +190,9 @@ public override BoundStatement InstrumentIfStatement(BoundIfStatement original,
return AddDynamicAnalysis(original, base.InstrumentIfStatement(original, rewritten));
}
public override BoundStatement InstrumentWhileStatementConditionalGotoStart(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
public override BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
{
return AddDynamicAnalysis(original, base.InstrumentWhileStatementConditionalGotoStart(original, ifConditionGotoStart));
return AddDynamicAnalysis(original, base.InstrumentWhileStatementConditionalGotoStartOrBreak(original, ifConditionGotoStart));
}
public override BoundStatement InstrumentLocalInitialization(BoundLocalDeclaration original, BoundStatement rewritten)
......
......@@ -121,7 +121,7 @@ public virtual BoundStatement InstrumentDoStatementConditionalGotoStart(BoundDoS
return ifConditionGotoStart;
}
public virtual BoundStatement InstrumentWhileStatementConditionalGotoStart(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
public virtual BoundStatement InstrumentWhileStatementConditionalGotoStartOrBreak(BoundWhileStatement original, BoundStatement ifConditionGotoStart)
{
Debug.Assert(!original.WasCompilerGenerated);
Debug.Assert(original.Syntax.Kind() == SyntaxKind.WhileStatement);
......@@ -262,20 +262,6 @@ public virtual BoundStatement InstrumentUsingTargetCapture(BoundUsingStatement o
return usingTargetCapture;
}
public virtual BoundStatement InstrumentWhileStatementGotoContinue(BoundWhileStatement original, BoundStatement gotoContinue)
{
Debug.Assert(!original.WasCompilerGenerated);
Debug.Assert(original.Syntax.Kind() == SyntaxKind.WhileStatement);
return gotoContinue;
}
public virtual BoundStatement InstrumentForEachStatementGotoContinue(BoundForEachStatement original, BoundStatement gotoContinue)
{
Debug.Assert(!original.WasCompilerGenerated);
Debug.Assert(original.Syntax is CommonForEachStatementSyntax);
return gotoContinue;
}
public virtual BoundExpression InstrumentCatchClauseFilter(BoundCatchBlock original, BoundExpression rewrittenFilter, SyntheticBoundNodeFactory factory)
{
Debug.Assert(!original.WasCompilerGenerated);
......
......@@ -49,11 +49,23 @@ public override BoundNode VisitDoStatement(BoundDoStatement node)
// }
// break:
if (node.Locals.IsEmpty)
{
return BoundStatementList.Synthesized(syntax, node.HasErrors,
new BoundLabelStatement(syntax, startLabel),
rewrittenBody,
new BoundLabelStatement(syntax, node.ContinueLabel),
ifConditionGotoStart,
new BoundLabelStatement(syntax, node.BreakLabel));
}
return BoundStatementList.Synthesized(syntax, node.HasErrors,
new BoundLabelStatement(syntax, startLabel),
rewrittenBody,
new BoundLabelStatement(syntax, node.ContinueLabel),
ifConditionGotoStart,
new BoundBlock(syntax,
node.Locals,
ImmutableArray.Create<BoundStatement>(rewrittenBody,
new BoundLabelStatement(syntax, node.ContinueLabel),
ifConditionGotoStart)),
new BoundLabelStatement(syntax, node.BreakLabel));
}
}
......
......@@ -27,6 +27,7 @@ public override BoundNode VisitWhileStatement(BoundWhileStatement node)
return RewriteWhileStatement(
node,
node.Locals,
rewrittenCondition,
rewrittenBody,
node.BreakLabel,
......@@ -43,26 +44,6 @@ public override BoundNode VisitWhileStatement(BoundWhileStatement node)
bool hasErrors)
{
Debug.Assert(loop.Kind == BoundKind.WhileStatement || loop.Kind == BoundKind.ForEachStatement);
SyntaxNode syntax = loop.Syntax;
var startLabel = new GeneratedLabelSymbol("start");
BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel);
if (this.Instrument && !loop.WasCompilerGenerated)
{
switch (loop.Kind)
{
case BoundKind.WhileStatement:
ifConditionGotoStart = _instrumenter.InstrumentWhileStatementConditionalGotoStart((BoundWhileStatement)loop, ifConditionGotoStart);
break;
case BoundKind.ForEachStatement:
ifConditionGotoStart = _instrumenter.InstrumentForEachStatementConditionalGotoStart((BoundForEachStatement)loop, ifConditionGotoStart);
break;
default:
throw ExceptionUtilities.UnexpectedValue(loop.Kind);
}
}
// while (condition)
// body;
......@@ -78,25 +59,31 @@ public override BoundNode VisitWhileStatement(BoundWhileStatement node)
// }
// break:
SyntaxNode syntax = loop.Syntax;
var startLabel = new GeneratedLabelSymbol("start");
BoundStatement ifConditionGotoStart = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, true, startLabel);
BoundStatement gotoContinue = new BoundGotoStatement(syntax, continueLabel);
if (this.Instrument && !loop.WasCompilerGenerated)
{
// mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This
// jump may be a target of another jump (for example if loops are nested) and that would give the
// impression that the previous statement is being re-executed.
switch (loop.Kind)
{
case BoundKind.WhileStatement:
gotoContinue = _instrumenter.InstrumentWhileStatementGotoContinue((BoundWhileStatement)loop, gotoContinue);
ifConditionGotoStart = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak((BoundWhileStatement)loop, ifConditionGotoStart);
break;
case BoundKind.ForEachStatement:
gotoContinue = _instrumenter.InstrumentForEachStatementGotoContinue((BoundForEachStatement)loop, gotoContinue);
ifConditionGotoStart = _instrumenter.InstrumentForEachStatementConditionalGotoStart((BoundForEachStatement)loop, ifConditionGotoStart);
break;
default:
throw ExceptionUtilities.UnexpectedValue(loop.Kind);
}
// mark the initial jump as hidden. We do it to tell that this is not a part of previous statement. This
// jump may be a target of another jump (for example if loops are nested) and that would give the
// impression that the previous statement is being re-executed.
gotoContinue = new BoundSequencePoint(null, gotoContinue);
}
return BoundStatementList.Synthesized(syntax, hasErrors,
......@@ -107,5 +94,56 @@ public override BoundNode VisitWhileStatement(BoundWhileStatement node)
ifConditionGotoStart,
new BoundLabelStatement(syntax, breakLabel));
}
private BoundStatement RewriteWhileStatement(
BoundWhileStatement loop,
ImmutableArray<LocalSymbol> locals,
BoundExpression rewrittenCondition,
BoundStatement rewrittenBody,
GeneratedLabelSymbol breakLabel,
GeneratedLabelSymbol continueLabel,
bool hasErrors)
{
if (locals.IsEmpty)
{
return RewriteWhileStatement(loop, rewrittenCondition, rewrittenBody, breakLabel, continueLabel, hasErrors);
}
// We need to enter scope-block from the top, that is where an instance of a display class will be created
// if any local is captured within a lambda.
// while (condition)
// body;
//
// becomes
//
// continue:
// {
// GotoIfFalse condition break;
// body
// goto continue;
// }
// break:
SyntaxNode syntax = loop.Syntax;
BoundStatement continueLabelStatement = new BoundLabelStatement(syntax, continueLabel);
BoundStatement ifNotConditionGotoBreak = new BoundConditionalGoto(rewrittenCondition.Syntax, rewrittenCondition, false, breakLabel);
if (this.Instrument && !loop.WasCompilerGenerated)
{
ifNotConditionGotoBreak = _instrumenter.InstrumentWhileStatementConditionalGotoStartOrBreak(loop, ifNotConditionGotoBreak);
continueLabelStatement = new BoundSequencePoint(null, continueLabelStatement);
}
return BoundStatementList.Synthesized(syntax, hasErrors,
continueLabelStatement,
new BoundBlock(syntax,
locals,
ImmutableArray.Create(
ifNotConditionGotoBreak,
rewrittenBody,
new BoundGotoStatement(syntax, continueLabel))),
new BoundLabelStatement(syntax, breakLabel));
}
}
}
......@@ -166,6 +166,22 @@ public override BoundNode VisitForStatement(BoundForStatement node)
return node.Update(newOuterLocals, initializer, condition, increment, body, node.BreakLabel, node.ContinueLabel);
}
public override BoundNode VisitDoStatement(BoundDoStatement node)
{
var newLocals = RewriteLocals(node.Locals);
BoundExpression condition = (BoundExpression)this.Visit(node.Condition);
BoundStatement body = (BoundStatement)this.Visit(node.Body);
return node.Update(newLocals, condition, body, node.BreakLabel, node.ContinueLabel);
}
public override BoundNode VisitWhileStatement(BoundWhileStatement node)
{
var newLocals = RewriteLocals(node.Locals);
BoundExpression condition = (BoundExpression)this.Visit(node.Condition);
BoundStatement body = (BoundStatement)this.Visit(node.Body);
return node.Update(newLocals, condition, body, node.BreakLabel, node.ContinueLabel);
}
public override BoundNode VisitUsingStatement(BoundUsingStatement node)
{
var newLocals = RewriteLocals(node.Locals);
......
......@@ -3163,8 +3163,6 @@ private static bool HasNonConstantInitializer(ArrayBuilder<ImmutableArray<FieldO
case SyntaxKind.ReturnStatement:
case SyntaxKind.ThrowStatement:
case SyntaxKind.SwitchStatement:
case SyntaxKind.WhileStatement:
case SyntaxKind.DoStatement:
case SyntaxKind.LockStatement:
ExpressionFieldFinder.FindExpressionVariables(builder.NonTypeNonIndexerMembers,
innerStatement,
......
......@@ -1632,8 +1632,6 @@ public static void Main()
System.Console.WriteLine(x1);
f = false;
}
System.Console.WriteLine(x1);
}
static bool Dummy(bool x, object y, object z)
......@@ -1647,7 +1645,6 @@ static bool Dummy(bool x, object y, object z)
CompileAndVerify(compilation, expectedOutput:
@"1
1
2
2");
var tree = compilation.SyntaxTrees.Single();
......@@ -1656,7 +1653,7 @@ static bool Dummy(bool x, object y, object z)
var x1Decl = GetPatternDeclarations(tree, "x1").ToArray();
var x1Ref = GetReferences(tree, "x1").ToArray();
Assert.Equal(1, x1Decl.Length);
Assert.Equal(3, x1Ref.Length);
Assert.Equal(2, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl[0], x1Ref);
}
......@@ -1705,6 +1702,170 @@ static bool Dummy(bool x, object y, object z)
VerifyModelForDeclarationPattern(model, x1Decl[1], x1Ref[1]);
}
[Fact]
public void While_03()
{
var source =
@"
public class X
{
public static void Main()
{
int f = 1;
var l = new System.Collections.Generic.List<System.Action>();
while (Dummy(f < 3, f is var x1, x1))
{
l.Add(() => System.Console.WriteLine(x1));
f++;
}
System.Console.WriteLine(""--"");
foreach (var d in l)
{
d();
}
}
static bool Dummy(bool x, object y, object z)
{
System.Console.WriteLine(z);
return x;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
CompileAndVerify(compilation, expectedOutput:
@"1
2
3
--
1
2
");
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x1Decl = GetPatternDeclarations(tree, "x1").ToArray();
var x1Ref = GetReferences(tree, "x1").ToArray();
Assert.Equal(1, x1Decl.Length);
Assert.Equal(2, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl[0], x1Ref);
}
[Fact]
public void While_04()
{
var source =
@"
public class X
{
public static void Main()
{
int f = 1;
var l = new System.Collections.Generic.List<System.Action>();
while (Dummy(f < 3, f is var x1, x1, l, () => System.Console.WriteLine(x1)))
{
f++;
}
System.Console.WriteLine(""--"");
foreach (var d in l)
{
d();
}
}
static bool Dummy(bool x, object y, object z, System.Collections.Generic.List<System.Action> l, System.Action d)
{
l.Add(d);
System.Console.WriteLine(z);
return x;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
CompileAndVerify(compilation, expectedOutput:
@"1
2
3
--
1
2
3
");
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x1Decl = GetPatternDeclarations(tree, "x1").ToArray();
var x1Ref = GetReferences(tree, "x1").ToArray();
Assert.Equal(1, x1Decl.Length);
Assert.Equal(2, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl[0], x1Ref);
}
[Fact]
public void While_05()
{
var source =
@"
public class X
{
public static void Main()
{
int f = 1;
var l = new System.Collections.Generic.List<System.Action>();
while (Dummy(f < 3, f is var x1, x1, l, () => System.Console.WriteLine(x1)))
{
l.Add(() => System.Console.WriteLine(x1));
f++;
}
System.Console.WriteLine(""--"");
foreach (var d in l)
{
d();
}
}
static bool Dummy(bool x, object y, object z, System.Collections.Generic.List<System.Action> l, System.Action d)
{
l.Add(d);
System.Console.WriteLine(z);
return x;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: TestOptions.Regular);
CompileAndVerify(compilation, expectedOutput:
@"1
2
3
--
1
1
2
2
3
");
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x1Decl = GetPatternDeclarations(tree, "x1").ToArray();
var x1Ref = GetReferences(tree, "x1").ToArray();
Assert.Equal(1, x1Decl.Length);
Assert.Equal(3, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl[0], x1Ref);
}
[Fact]
public void Do_01()
{
......@@ -1721,8 +1882,6 @@ public static void Main()
f = false;
}
while (Dummy(f, (f ? 1 : 2) is var x1, x1));
System.Console.WriteLine(x1);
}
static bool Dummy(bool x, object y, object z)
......@@ -1733,8 +1892,7 @@ static bool Dummy(bool x, object y, object z)
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: @"2
2");
CompileAndVerify(compilation, expectedOutput: @"2");
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
......@@ -1742,7 +1900,7 @@ static bool Dummy(bool x, object y, object z)
var x1Decl = GetPatternDeclarations(tree, "x1").ToArray();
var x1Ref = GetReferences(tree, "x1").ToArray();
Assert.Equal(1, x1Decl.Length);
Assert.Equal(2, x1Ref.Length);
Assert.Equal(1, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl[0], x1Ref);
}
......@@ -1793,6 +1951,59 @@ static bool Dummy(bool x, object y, object z)
VerifyModelForDeclarationPattern(model, x1Decl[1], x1Ref[1]);
}
[Fact]
public void Do_03()
{
var source =
@"
public class X
{
public static void Main()
{
int f = 1;
var l = new System.Collections.Generic.List<System.Action>();
do
{
;
}
while (Dummy(f < 3, (f++) is var x1, x1, l, () => System.Console.WriteLine(x1)));
System.Console.WriteLine(""--"");
foreach (var d in l)
{
d();
}
}
static bool Dummy(bool x, object y, object z, System.Collections.Generic.List<System.Action> l, System.Action d)
{
l.Add(d);
System.Console.WriteLine(z);
return x;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe);
CompileAndVerify(compilation, expectedOutput: @"1
2
3
--
1
2
3");
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x1Decl = GetPatternDeclarations(tree, "x1").ToArray();
var x1Ref = GetReferences(tree, "x1").ToArray();
Assert.Equal(1, x1Decl.Length);
Assert.Equal(2, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl[0], x1Ref);
}
[Fact]
public void For_01()
{
......
......@@ -6864,7 +6864,7 @@ void Test4()
var x4 = 11;
Dummy(x4);
while (true is var x4 && x4 > 0)
while (true is var x4 && x4)
Dummy(x4);
}
......@@ -6947,18 +6947,18 @@ void Test14()
// (87,13): error CS1023: Embedded statement cannot be a declaration or labeled statement
// var y12 = 12;
Diagnostic(ErrorCode.ERR_BadEmbeddedStmt, "var y12 = 12;").WithLocation(87, 13),
// (29,28): error CS0128: A local variable named 'x4' is already defined in this scope
// while (true is var x4 && x4 > 0)
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x4").WithArguments("x4").WithLocation(29, 28),
// (29,28): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// while (true is var x4 && x4)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x4").WithArguments("x4").WithLocation(29, 28),
// (35,16): error CS0841: Cannot use local variable 'x6' before it is declared
// while (x6 && true is var x6)
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x6").WithArguments("x6").WithLocation(35, 16),
// (43,17): error CS0136: A local or parameter named 'x7' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// var x7 = 12;
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x7").WithArguments("x7").WithLocation(43, 17),
// (60,19): error CS0841: Cannot use local variable 'x9' before it is declared
// Dummy(x9);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x9").WithArguments("x9").WithLocation(60, 19),
// (53,34): error CS0103: The name 'x8' does not exist in the current context
// System.Console.WriteLine(x8);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x8").WithArguments("x8").WithLocation(53, 34),
// (61,32): error CS0136: A local or parameter named 'x9' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// while (true is var x9 && x9) // 2
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x9").WithArguments("x9").WithLocation(61, 32),
......@@ -6971,7 +6971,7 @@ void Test14()
// (87,17): warning CS0219: The variable 'y12' is assigned but its value is never used
// var y12 = 12;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "y12").WithArguments("y12").WithLocation(87, 17),
// (99,31): error CS0128: A local variable named 'x14' is already defined in this scope
// (99,31): error CS0128: A local variable or function named 'x14' is already defined in this scope
// 2 is var x14,
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x14").WithArguments("x14").WithLocation(99, 31)
);
......@@ -6993,9 +6993,7 @@ void Test14()
var x4Ref = GetReferences(tree, "x4").ToArray();
Assert.Equal(3, x4Ref.Length);
VerifyNotAPatternLocal(model, x4Ref[0]);
VerifyNotAPatternLocal(model, x4Ref[1]);
VerifyNotAPatternLocal(model, x4Ref[2]);
VerifyModelForDeclarationPatternDuplicateInSameScope(model, x4Decl);
VerifyModelForDeclarationPattern(model, x4Decl, x4Ref[1], x4Ref[2]);
var x6Decl = GetPatternDeclarations(tree, "x6").Single();
var x6Ref = GetReferences(tree, "x6").ToArray();
......@@ -7011,14 +7009,15 @@ void Test14()
var x8Decl = GetPatternDeclarations(tree, "x8").Single();
var x8Ref = GetReferences(tree, "x8").ToArray();
Assert.Equal(3, x8Ref.Length);
VerifyModelForDeclarationPattern(model, x8Decl, x8Ref);
VerifyModelForDeclarationPattern(model, x8Decl, x8Ref[0], x8Ref[1]);
VerifyNotInScope(model, x8Ref[2]);
var x9Decl = GetPatternDeclarations(tree, "x9").ToArray();
var x9Ref = GetReferences(tree, "x9").ToArray();
Assert.Equal(2, x9Decl.Length);
Assert.Equal(4, x9Ref.Length);
VerifyModelForDeclarationPattern(model, x9Decl[0], x9Ref[0]);
VerifyModelForDeclarationPattern(model, x9Decl[1], x9Ref[1], x9Ref[2], x9Ref[3]);
VerifyModelForDeclarationPattern(model, x9Decl[0], x9Ref[0], x9Ref[1]);
VerifyModelForDeclarationPattern(model, x9Decl[1], x9Ref[2], x9Ref[3]);
var y10Ref = GetReferences(tree, "y10").ToArray();
Assert.Equal(2, y10Ref.Length);
......@@ -7154,7 +7153,7 @@ void Test4()
do
Dummy(x4);
while (true is var x4 && x4 > 0);
while (true is var x4 && x4);
}
void Test6()
......@@ -7252,9 +7251,12 @@ void Test14()
// (22,19): error CS0841: Cannot use local variable 'x2' before it is declared
// Dummy(x2);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x2").WithArguments("x2").WithLocation(22, 19),
// (33,28): error CS0128: A local variable named 'x4' is already defined in this scope
// while (true is var x4 && x4 > 0);
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x4").WithArguments("x4").WithLocation(33, 28),
// (33,28): error CS0136: A local or parameter named 'x4' cannot be declared in this scope because that name is used in an enclosing local scope to define a local or parameter
// while (true is var x4 && x4);
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x4").WithArguments("x4").WithLocation(33, 28),
// (32,19): error CS0841: Cannot use local variable 'x4' before it is declared
// Dummy(x4);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x4").WithArguments("x4").WithLocation(32, 19),
// (40,16): error CS0841: Cannot use local variable 'x6' before it is declared
// while (x6 && true is var x6);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x6").WithArguments("x6").WithLocation(40, 16),
......@@ -7267,6 +7269,9 @@ void Test14()
// (56,19): error CS0841: Cannot use local variable 'x8' before it is declared
// Dummy(x8);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x8").WithArguments("x8").WithLocation(56, 19),
// (59,34): error CS0103: The name 'x8' does not exist in the current context
// System.Console.WriteLine(x8);
Diagnostic(ErrorCode.ERR_NameNotInContext, "x8").WithArguments("x8").WithLocation(59, 34),
// (66,19): error CS0841: Cannot use local variable 'x9' before it is declared
// Dummy(x9);
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x9").WithArguments("x9").WithLocation(66, 19),
......@@ -7285,7 +7290,7 @@ void Test14()
// (97,17): warning CS0219: The variable 'y12' is assigned but its value is never used
// var y12 = 12;
Diagnostic(ErrorCode.WRN_UnreferencedVarAssg, "y12").WithArguments("y12").WithLocation(97, 17),
// (115,31): error CS0128: A local variable named 'x14' is already defined in this scope
// (115,31): error CS0128: A local variable or function named 'x14' is already defined in this scope
// 2 is var x14,
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x14").WithArguments("x14").WithLocation(115, 31),
// (112,19): error CS0841: Cannot use local variable 'x14' before it is declared
......@@ -7310,9 +7315,7 @@ void Test14()
var x4Ref = GetReferences(tree, "x4").ToArray();
Assert.Equal(3, x4Ref.Length);
VerifyNotAPatternLocal(model, x4Ref[0]);
VerifyNotAPatternLocal(model, x4Ref[1]);
VerifyNotAPatternLocal(model, x4Ref[2]);
VerifyModelForDeclarationPatternDuplicateInSameScope(model, x4Decl);
VerifyModelForDeclarationPattern(model, x4Decl, x4Ref[1], x4Ref[2]);
var x6Decl = GetPatternDeclarations(tree, "x6").Single();
var x6Ref = GetReferences(tree, "x6").ToArray();
......@@ -7328,14 +7331,15 @@ void Test14()
var x8Decl = GetPatternDeclarations(tree, "x8").Single();
var x8Ref = GetReferences(tree, "x8").ToArray();
Assert.Equal(3, x8Ref.Length);
VerifyModelForDeclarationPattern(model, x8Decl, x8Ref);
VerifyModelForDeclarationPattern(model, x8Decl, x8Ref[0], x8Ref[1]);
VerifyNotInScope(model, x8Ref[2]);
var x9Decl = GetPatternDeclarations(tree, "x9").ToArray();
var x9Ref = GetReferences(tree, "x9").ToArray();
Assert.Equal(2, x9Decl.Length);
Assert.Equal(4, x9Ref.Length);
VerifyModelForDeclarationPattern(model, x9Decl[0], x9Ref[0], x9Ref[1], x9Ref[2]);
VerifyModelForDeclarationPattern(model, x9Decl[1], x9Ref[3]);
VerifyModelForDeclarationPattern(model, x9Decl[0], x9Ref[1], x9Ref[2]);
VerifyModelForDeclarationPattern(model, x9Decl[1], x9Ref[0], x9Ref[3]);
var y10Ref = GetReferences(tree, "y10").ToArray();
Assert.Equal(2, y10Ref.Length);
......@@ -11323,12 +11327,17 @@ static void Test(int val)
switch (val)
{
case 1 when Dummy(123, Data is var x1):
while (Dummy(x1 is var y1)) break;
System.Console.WriteLine(y1);
while (Dummy(x1 is var y1) && Print(y1)) break;
break;
}
}
static bool Print(int x)
{
System.Console.WriteLine(x);
return true;
}
static bool Dummy(params object[] data)
{
return true;
......@@ -11368,12 +11377,17 @@ static void Test(int val)
case 1 when Dummy(123, Data is var x1):
do
val = 0;
while (Dummy(x1 is var y1) && false);
System.Console.WriteLine(y1);
while (Dummy(x1 is var y1) && Print(y1));
break;
}
}
static bool Print(int x)
{
System.Console.WriteLine(x);
return false;
}
static bool Dummy(params object[] data)
{
return true;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册