提交 dd7bf968 编写于 作者: A AlekseyTs

Test/fix scoping rules for pattern locals declared within a catch filter.

Related to #8817, #8814.
上级 0da15194
......@@ -3411,9 +3411,10 @@ private BoundCatchBlock BindCatchBlock(CatchClauseSyntax node, ArrayBuilder<Boun
BoundExpression exceptionSource = null;
LocalSymbol local = this.Locals.FirstOrDefault();
if ((object)local != null)
if (local?.DeclarationKind == LocalDeclarationKind.CatchVariable)
{
Debug.Assert(this.Locals.Length == 1);
Debug.Assert(local.Type.IsErrorType() || (local.Type == type));
// Check for local variable conflicts in the *enclosing* binder, not the *current* binder;
// obviously we will find a local of the given name in the current binder.
......@@ -3423,22 +3424,17 @@ private BoundCatchBlock BindCatchBlock(CatchClauseSyntax node, ArrayBuilder<Boun
}
var block = BindEmbeddedBlock(node.Block, diagnostics);
Debug.Assert((object)local == null || local.DeclarationKind == LocalDeclarationKind.CatchVariable);
Debug.Assert((object)local == null || local.Type.IsErrorType() || (local.Type == type));
return new BoundCatchBlock(node, local, exceptionSource, type, boundFilter, block, hasError);
return new BoundCatchBlock(node, this.Locals, exceptionSource, type, boundFilter, block, hasError);
}
private BoundExpression BindCatchFilter(CatchFilterClauseSyntax filter, DiagnosticBag diagnostics)
{
// TODO: should pattern variables declared in a catch filter be available in the catch block?
PatternVariableBinder patternBinder = new PatternVariableBinder(filter, filter.FilterExpression, this);
BoundExpression boundFilter = patternBinder.BindBooleanExpression(filter.FilterExpression, diagnostics);
BoundExpression boundFilter = this.BindBooleanExpression(filter.FilterExpression, diagnostics);
if (boundFilter.ConstantValue != ConstantValue.NotAvailable)
{
Error(diagnostics, ErrorCode.WRN_FilterIsConstant, filter.FilterExpression);
}
boundFilter = patternBinder.WrapWithVariablesIfAny(boundFilter);
boundFilter = new BoundSequencePointExpression(filter, boundFilter, boundFilter.Type);
return boundFilter;
}
......
......@@ -21,20 +21,20 @@ public CatchClauseBinder(Binder enclosing, CatchClauseSyntax syntax)
override protected ImmutableArray<LocalSymbol> BuildLocals()
{
SourceLocalSymbol local = null;
var locals = ArrayBuilder<LocalSymbol>.GetInstance();
var declarationOpt = _syntax.Declaration;
if ((declarationOpt != null) && (declarationOpt.Identifier.Kind() != SyntaxKind.None))
{
local = SourceLocalSymbol.MakeLocal(this.ContainingMemberOrLambda, this, RefKind.None, declarationOpt.Type, declarationOpt.Identifier, LocalDeclarationKind.CatchVariable);
locals.Add(SourceLocalSymbol.MakeLocal(this.ContainingMemberOrLambda, this, RefKind.None, declarationOpt.Type, declarationOpt.Identifier, LocalDeclarationKind.CatchVariable));
}
if ((object)local != null)
if (_syntax.Filter != null)
{
return ImmutableArray.Create<LocalSymbol>(local);
BuildAndAddPatternVariables(locals, _syntax.Filter.FilterExpression);
}
return ImmutableArray<LocalSymbol>.Empty;
return locals.ToImmutableAndFree();
}
internal override ImmutableArray<LocalSymbol> GetDeclaredLocalsForScope(CSharpSyntaxNode node)
......
......@@ -840,13 +840,13 @@
<Node Name="BoundCatchBlock" Base="BoundNode">
<!--
Local symbol owned by the catch block.
Null if the catch syntax doesn't declare a local variable.
Local symbols owned by the catch block.
Empty if the catch syntax doesn't declare a local variable.
In the initial bound tree this is the exception variable (if present).
After the node is lowered it might be another variable or null.
In the initial bound tree the first variable is the exception variable (if present).
After the node is lowered it might be another variable.
-->
<Field Name="LocalOpt" Type="LocalSymbol" Null="allow"/>
<Field Name="Locals" Type="ImmutableArray&lt;LocalSymbol&gt;"/>
<!--
Refers to the location where the exception object is stored.
......
// 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 System;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Semantics;
using System.Collections.Immutable;
using System.Linq;
using System.Runtime.CompilerServices;
using Microsoft.CodeAnalysis.Semantics;
using Roslyn.Utilities;
namespace Microsoft.CodeAnalysis.CSharp
{
......@@ -445,7 +445,14 @@ internal partial class BoundCatchBlock : ICatchClause
IOperation ICatchClause.Filter => this.ExceptionFilterOpt;
ILocalSymbol ICatchClause.ExceptionLocal => this.LocalOpt;
ILocalSymbol ICatchClause.ExceptionLocal
{
get
{
var local = this.Locals.FirstOrDefault();
return local?.DeclarationKind == LocalDeclarationKind.CatchVariable ? local : null;
}
}
OperationKind IOperation.Kind => OperationKind.CatchClause;
......
......@@ -926,11 +926,11 @@ private void EmitCatchBlock(BoundCatchBlock catchBlock)
_builder.MarkLabel(typeCheckPassedLabel);
}
if ((object)catchBlock.LocalOpt != null)
foreach (var local in catchBlock.Locals)
{
var declaringReferences = catchBlock.LocalOpt.DeclaringSyntaxReferences;
var declaringReferences = local.DeclaringSyntaxReferences;
var localSyntax = !declaringReferences.IsEmpty ? (CSharpSyntaxNode)declaringReferences[0].GetSyntax() : catchBlock.Syntax;
DefineLocal(catchBlock.LocalOpt, localSyntax);
DefineLocal(local, localSyntax);
}
var exceptionSourceOpt = catchBlock.ExceptionSourceOpt;
......
......@@ -1489,13 +1489,8 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
EnsureOnlyEvalStack();
var local = node.LocalOpt;
var exceptionSourceOpt = node.ExceptionSourceOpt;
if ((object)local != null)
{
DeclareLocal(local, stack: 0);
}
DeclareLocals(node.Locals, stack: 0);
if (exceptionSourceOpt != null)
{
......@@ -1512,6 +1507,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
int prevStack = StackDepth();
exceptionSourceOpt = VisitExpression(exceptionSourceOpt, ExprContext.AssignmentTarget);
_assignmentLocal = null; // not using this for exceptionSource
SetStackDepth(prevStack);
}
......@@ -1539,7 +1535,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
var boundBlock = (BoundBlock)this.Visit(node.Body);
var exceptionTypeOpt = this.VisitType(node.ExceptionTypeOpt);
return node.Update(local, exceptionSourceOpt, exceptionTypeOpt, boundFilter, boundBlock, node.IsSynthesizedAsyncCatchAll);
return node.Update(node.Locals, exceptionSourceOpt, exceptionTypeOpt, boundFilter, boundBlock, node.IsSynthesizedAsyncCatchAll);
}
public override BoundNode VisitStackAllocArrayCreation(BoundStackAllocArrayCreation node)
......@@ -2040,7 +2036,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
body = (BoundBlock)this.Visit(body);
type = this.VisitType(type);
return node.Update(node.LocalOpt, exceptionSource, type, filter, body, node.IsSynthesizedAsyncCatchAll);
return node.Update(node.Locals, exceptionSource, type, filter, body, node.IsSynthesizedAsyncCatchAll);
}
}
......
......@@ -1977,10 +1977,7 @@ protected override void VisitCatchBlock(BoundCatchBlock catchBlock, ref LocalSta
private void VisitCatchBlockInternal(BoundCatchBlock catchBlock, ref LocalState finallyState)
{
if ((object)catchBlock.LocalOpt != null)
{
DeclareVariable(catchBlock.LocalOpt);
}
DeclareVariables(catchBlock.Locals);
var exceptionSource = catchBlock.ExceptionSourceOpt;
if (exceptionSource != null)
......@@ -1990,9 +1987,9 @@ private void VisitCatchBlockInternal(BoundCatchBlock catchBlock, ref LocalState
base.VisitCatchBlock(catchBlock, ref finallyState);
if ((object)catchBlock.LocalOpt != null)
foreach (var local in catchBlock.Locals)
{
ReportIfUnused(catchBlock.LocalOpt, assigned: false);
ReportIfUnused(local, assigned: local.DeclarationKind != LocalDeclarationKind.CatchVariable);
}
}
......
......@@ -143,9 +143,8 @@ private Symbol GetNodeSymbol(BoundNode node)
case BoundKind.CatchBlock:
{
var local = ((BoundCatchBlock)node).LocalOpt;
Debug.Assert((object)local == null || local.DeclarationKind == LocalDeclarationKind.CatchVariable);
return (object)local != null ? local : null;
var local = ((BoundCatchBlock)node).Locals.FirstOrDefault();
return local?.DeclarationKind == LocalDeclarationKind.CatchVariable ? local : null;
}
case BoundKind.ForEachStatement:
......
......@@ -114,11 +114,10 @@ protected override void VisitCatchBlock(BoundCatchBlock catchBlock, ref LocalSta
{
if (IsInside)
{
var local = catchBlock.LocalOpt;
var local = catchBlock.Locals.FirstOrDefault();
if ((object)local != null)
if (local?.DeclarationKind == LocalDeclarationKind.CatchVariable)
{
Debug.Assert(local.DeclarationKind == LocalDeclarationKind.CatchVariable);
_variablesDeclared.Add(local);
}
}
......
......@@ -541,7 +541,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
// catchNo = X;
// }
BoundCatchBlock catchAndPend;
var handlerLocals = ImmutableArray<LocalSymbol>.Empty;
ImmutableArray<LocalSymbol> handlerLocals;
var filterOpt = node.ExceptionFilterOpt;
if (filterOpt == null)
......@@ -549,7 +549,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
// store pending exception
// as the first statement in a catch
catchAndPend = node.Update(
catchTemp,
ImmutableArray.Create(catchTemp),
_F.Local(catchTemp),
catchType,
exceptionFilterOpt: null,
......@@ -560,18 +560,17 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
isSynthesizedAsyncCatchAll: node.IsSynthesizedAsyncCatchAll);
// catch locals live on the synthetic catch handler block
if ((object)node.LocalOpt != null)
{
handlerLocals = ImmutableArray.Create(node.LocalOpt);
}
handlerLocals = node.Locals;
}
else
{
handlerLocals = ImmutableArray<LocalSymbol>.Empty;
// catch locals move up into hoisted locals
// since we might need to access them from both the filter and the catch
if ((object)node.LocalOpt != null)
foreach (var local in node.Locals)
{
currentAwaitCatchFrame.HoistLocal(node.LocalOpt, _F);
currentAwaitCatchFrame.HoistLocal(local, _F);
}
// store pending exception
......@@ -588,7 +587,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
rewrittenFilter);
catchAndPend = node.Update(
catchTemp,
ImmutableArray.Create(catchTemp),
_F.Local(catchTemp),
catchType,
exceptionFilterOpt: newFilter,
......
......@@ -139,7 +139,7 @@ internal void GenerateMoveNext(BoundStatement body, MethodSymbol moveNextMethod)
F.CatchBlocks(
new BoundCatchBlock(
F.Syntax,
exceptionLocal,
ImmutableArray.Create(exceptionLocal),
F.Local(exceptionLocal),
exceptionLocal.Type,
exceptionFilterOpt: null,
......
......@@ -356,14 +356,14 @@ private int BlockDepth(BoundNode node)
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
var local = node.LocalOpt;
var locals = node.Locals;
if ((object)local == null)
if (locals.IsEmpty)
{
return base.VisitCatchBlock(node);
}
var previousBlock = PushBlock(node, ImmutableArray.Create(local));
var previousBlock = PushBlock(node, locals);
var result = base.VisitCatchBlock(node);
PopBlock(previousBlock);
return node;
......
......@@ -909,28 +909,8 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
private BoundNode RewriteCatch(BoundCatchBlock node, ArrayBuilder<BoundExpression> prologue, ArrayBuilder<LocalSymbol> newLocals)
{
LocalSymbol newLocal;
if ((object)node.LocalOpt != null && TryRewriteLocal(node.LocalOpt, out newLocal))
{
newLocals.Add(newLocal);
}
LocalSymbol rewrittenCatchLocal;
if (newLocals.Count > 0)
{
// If the original LocalOpt was lifted into a closure,
// the newLocals will contain a frame reference. In this case,
// instead of an actual local, catch will own the frame reference.
Debug.Assert((object)node.LocalOpt != null && newLocals.Count == 1);
rewrittenCatchLocal = newLocals[0];
}
else
{
Debug.Assert((object)node.LocalOpt == null);
rewrittenCatchLocal = null;
}
RewriteLocals(node.Locals, newLocals);
var rewrittenCatchLocals = newLocals.ToImmutableAndFree();
// If exception variable got lifted, IntroduceFrame will give us frame init prologue.
// It needs to run before the exception variable is accessed.
......@@ -962,7 +942,6 @@ private BoundNode RewriteCatch(BoundCatchBlock node, ArrayBuilder<BoundExpressio
}
// done with this.
newLocals.Free();
prologue.Free();
// rewrite filter and body
......@@ -971,7 +950,7 @@ private BoundNode RewriteCatch(BoundCatchBlock node, ArrayBuilder<BoundExpressio
var rewrittenBlock = (BoundBlock)this.Visit(node.Body);
return node.Update(
rewrittenCatchLocal,
rewrittenCatchLocals,
rewrittenExceptionSource,
exceptionTypeOpt,
rewrittenFilter,
......
......@@ -87,7 +87,7 @@ public override BoundNode VisitCatchBlock(BoundCatchBlock node)
// EnC: We need to insert a hidden sequence point to handle function remapping in case
// the containing method is edited while methods invoked in the condition are being executed.
return node.Update(
node.LocalOpt,
node.Locals,
rewrittenExceptionSourceOpt,
rewrittenExceptionTypeOpt,
AddConditionSequencePoint(rewrittenFilter, node),
......
......@@ -109,15 +109,14 @@ private ImmutableArray<LocalSymbol> RewriteLocals(ImmutableArray<LocalSymbol> lo
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
if ((object)node.LocalOpt != null)
if (!node.Locals.IsDefaultOrEmpty)
{
// Yield/await aren't supported in catch block atm, but we need to rewrite the type
// of the variable owned by the catch block. Note that this variable might be a closure frame reference.
LocalSymbol newLocal;
TryRewriteLocal(node.LocalOpt, out newLocal);
// of the variables owned by the catch block. Note that one of these variables might be a closure frame reference.
var newLocals = RewriteLocals(node.Locals);
return node.Update(
newLocal,
newLocals,
(BoundExpression)this.Visit(node.ExceptionSourceOpt),
this.VisitType(node.ExceptionTypeOpt),
(BoundExpression)this.Visit(node.ExceptionFilterOpt),
......
......@@ -338,7 +338,7 @@ private void AddVariables(ImmutableArray<LocalSymbol> locals)
public override BoundNode VisitCatchBlock(BoundCatchBlock node)
{
AddVariable(node.LocalOpt);
AddVariables(node.Locals);
return base.VisitCatchBlock(node);
}
......
......@@ -1133,14 +1133,14 @@ internal BoundExpression Default(TypeSymbol type)
BoundBlock block)
{
var source = Local(local);
return new BoundCatchBlock(Syntax, local, source, source.Type, exceptionFilterOpt: null, body: block, isSynthesizedAsyncCatchAll: false);
return new BoundCatchBlock(Syntax, ImmutableArray.Create(local), source, source.Type, exceptionFilterOpt: null, body: block, isSynthesizedAsyncCatchAll: false);
}
internal BoundCatchBlock Catch(
BoundExpression source,
BoundBlock block)
{
return new BoundCatchBlock(Syntax, null, source, source.Type, exceptionFilterOpt: null, body: block, isSynthesizedAsyncCatchAll: false);
return new BoundCatchBlock(Syntax, ImmutableArray<LocalSymbol>.Empty, source, source.Type, exceptionFilterOpt: null, body: block, isSynthesizedAsyncCatchAll: false);
}
internal BoundTryStatement Fault(BoundBlock tryBlock, BoundBlock faultBlock)
......
......@@ -11523,5 +11523,373 @@ public class Odd
False
False");
}
[Fact]
public void ScopeOfPatternVariables_Catch_01()
{
var source =
@"
public class X
{
public static void Main()
{
}
bool Dummy(params object[] x) {return true;}
void Test1()
{
try {}
catch when (true is var x1 && x1)
{
Dummy(x1);
}
}
void Test4()
{
var x4 = 11;
Dummy(x4);
try {}
catch when (true is var x4 && x4)
{
Dummy(x4);
}
}
void Test6()
{
try {}
catch when (x6 && true is var x6)
{
Dummy(x6);
}
}
void Test7()
{
try {}
catch when (true is var x7 && x7)
{
var x7 = 12;
Dummy(x7);
}
}
void Test8()
{
try {}
catch when (true is var x8 && x8)
{
Dummy(x8);
}
System.Console.WriteLine(x8);
}
void Test9()
{
try {}
catch when (true is var x9 && x9)
{
Dummy(x9);
try {}
catch when (true is var x9 && x9) // 2
{
Dummy(x9);
}
}
}
void Test10()
{
try {}
catch when (y10 is var x10)
{
var y10 = 12;
Dummy(y10);
}
}
void Test11()
{
try {}
catch when (y11 is var x11)
{
let y11 = 12;
Dummy(y11);
}
}
void Test14()
{
try {}
catch when (Dummy(1 is var x14,
2 is var x14,
x14))
{
Dummy(x14);
}
}
void Test15()
{
try {}
catch (System.Exception x15)
when (Dummy(1 is var x15, x15))
{
Dummy(x15);
}
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
compilation.VerifyDiagnostics(
// (25,33): 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
// catch when (true is var x4 && x4)
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x4").WithArguments("x4").WithLocation(25, 33),
// (34,21): error CS0841: Cannot use local variable 'x6' before it is declared
// catch when (x6 && true is var x6)
Diagnostic(ErrorCode.ERR_VariableUsedBeforeDeclaration, "x6").WithArguments("x6").WithLocation(34, 21),
// (45,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(45, 17),
// (58,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(58, 34),
// (68,37): 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
// catch when (true is var x9 && x9) // 2
Diagnostic(ErrorCode.ERR_LocalIllegallyOverrides, "x9").WithArguments("x9").WithLocation(68, 37),
// (78,21): error CS0103: The name 'y10' does not exist in the current context
// catch when (y10 is var x10)
Diagnostic(ErrorCode.ERR_NameNotInContext, "y10").WithArguments("y10").WithLocation(78, 21),
// (88,21): error CS0103: The name 'y11' does not exist in the current context
// catch when (y11 is var x11)
Diagnostic(ErrorCode.ERR_NameNotInContext, "y11").WithArguments("y11").WithLocation(88, 21),
// (99,36): error CS0128: A local variable named 'x14' is already defined in this scope
// 2 is var x14,
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x14").WithArguments("x14").WithLocation(99, 36),
// (110,36): error CS0128: A local variable named 'x15' is already defined in this scope
// when (Dummy(1 is var x15, x15))
Diagnostic(ErrorCode.ERR_LocalDuplicate, "x15").WithArguments("x15").WithLocation(110, 36)
);
var tree = compilation.SyntaxTrees.Single();
var model = compilation.GetSemanticModel(tree);
var x1Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x1").Single();
var x1Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x1").ToArray();
Assert.Equal(2, x1Ref.Length);
VerifyModelForDeclarationPattern(model, x1Decl, x1Ref);
var x4Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x4").Single();
var x4Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x4").ToArray();
Assert.Equal(3, x4Ref.Length);
VerifyNotAPatternLocal(model, x4Ref[0]);
VerifyModelForDeclarationPattern(model, x4Decl, x4Ref[1], x4Ref[2]);
var x6Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x6").Single();
var x6Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x6").ToArray();
Assert.Equal(2, x6Ref.Length);
VerifyModelForDeclarationPattern(model, x6Decl, x6Ref);
var x7Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x7").Single();
var x7Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x7").ToArray();
Assert.Equal(2, x7Ref.Length);
VerifyModelForDeclarationPattern(model, x7Decl, x7Ref[0]);
VerifyNotAPatternLocal(model, x7Ref[1]);
var x8Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x8").Single();
var x8Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x8").ToArray();
Assert.Equal(3, x8Ref.Length);
VerifyModelForDeclarationPattern(model, x8Decl, x8Ref[0], x8Ref[1]);
VerifyNotInScope(model, x8Ref[2]);
var x9Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x9").ToArray();
var x9Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x9").ToArray();
Assert.Equal(2, x9Decl.Length);
Assert.Equal(4, x9Ref.Length);
VerifyModelForDeclarationPattern(model, x9Decl[0], x9Ref[0], x9Ref[1]);
VerifyModelForDeclarationPattern(model, x9Decl[1], x9Ref[2], x9Ref[3]);
var y10Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y10").ToArray();
Assert.Equal(2, y10Ref.Length);
VerifyNotInScope(model, y10Ref[0]);
VerifyNotAPatternLocal(model, y10Ref[1]);
var y11Decl = tree.GetRoot().DescendantNodes().OfType<LetStatementSyntax>().Where(p => p.Identifier.ValueText == "y11").Single();
var y11Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "y11").ToArray();
Assert.Equal(2, y11Ref.Length);
VerifyNotInScope(model, y11Ref[0]);
VerifyModelForDeclarationPattern(model, y11Decl, y11Ref[1]);
var x14Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x14").ToArray();
var x14Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x14").ToArray();
Assert.Equal(2, x14Decl.Length);
Assert.Equal(2, x14Ref.Length);
VerifyModelForDeclarationPattern(model, x14Decl[0], x14Ref);
VerifyModelForDeclarationPatternDuplicateInSameScope(model, x14Decl[1]);
var x15Decl = tree.GetRoot().DescendantNodes().OfType<DeclarationPatternSyntax>().Where(p => p.Identifier.ValueText == "x15").Single();
var x15Ref = tree.GetRoot().DescendantNodes().OfType<IdentifierNameSyntax>().Where(id => id.Identifier.ValueText == "x15").ToArray();
Assert.Equal(2, x15Ref.Length);
VerifyModelForDeclarationPatternDuplicateInSameScope(model, x15Decl);
VerifyNotAPatternLocal(model, x15Ref[0]);
VerifyNotAPatternLocal(model, x15Ref[1]);
}
[Fact]
public void Catch_01()
{
var source =
@"
public class X
{
public static void Main()
{
try
{
throw new System.InvalidOperationException();
}
catch (System.Exception e) when (Dummy(e is var x1, x1))
{
System.Console.WriteLine(x1.GetType());
}
}
static bool Dummy(object y, object z)
{
System.Console.WriteLine(z.GetType());
return true;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
CompileAndVerify(compilation, expectedOutput:
@"System.InvalidOperationException
System.InvalidOperationException");
}
[Fact]
public void Catch_02()
{
var source =
@"
public class X
{
public static void Main()
{
try
{
throw new System.InvalidOperationException();
}
catch (System.Exception e) when (Dummy(e is var x1, x1))
{
System.Action d = () =>
{
System.Console.WriteLine(x1.GetType());
};
System.Console.WriteLine(x1.GetType());
d();
}
}
static bool Dummy(object y, object z)
{
System.Console.WriteLine(z.GetType());
return true;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
CompileAndVerify(compilation, expectedOutput:
@"System.InvalidOperationException
System.InvalidOperationException
System.InvalidOperationException");
}
[Fact]
public void Catch_03()
{
var source =
@"
public class X
{
public static void Main()
{
try
{
throw new System.InvalidOperationException();
}
catch (System.Exception e) when (Dummy(e is var x1, x1))
{
System.Action d = () =>
{
e = new System.NullReferenceException();
System.Console.WriteLine(x1.GetType());
};
System.Console.WriteLine(x1.GetType());
d();
System.Console.WriteLine(e.GetType());
}
}
static bool Dummy(object y, object z)
{
System.Console.WriteLine(z.GetType());
return true;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
CompileAndVerify(compilation, expectedOutput:
@"System.InvalidOperationException
System.InvalidOperationException
System.InvalidOperationException
System.NullReferenceException");
}
[Fact]
public void Catch_04()
{
var source =
@"
public class X
{
public static void Main()
{
try
{
throw new System.InvalidOperationException();
}
catch (System.Exception e) when (Dummy(e is var x1, x1))
{
System.Action d = () =>
{
e = new System.NullReferenceException();
};
System.Console.WriteLine(x1.GetType());
d();
System.Console.WriteLine(e.GetType());
}
}
static bool Dummy(object y, object z)
{
System.Console.WriteLine(z.GetType());
return true;
}
}
";
var compilation = CreateCompilationWithMscorlib45(source, options: TestOptions.DebugExe, parseOptions: patternParseOptions);
CompileAndVerify(compilation, expectedOutput:
@"System.InvalidOperationException
System.InvalidOperationException
System.NullReferenceException");
}
}
}
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册