Skip to content

Commit

Permalink
Merge pull request #45104 from dotnet/merges/release/dev16.7-preview3…
Browse files Browse the repository at this point in the history
…-to-release/dev16.7-preview3-vs-deps

Merge release/dev16.7-preview3 to release/dev16.7-preview3-vs-deps
  • Loading branch information
msftbot[bot] authored Jun 12, 2020
2 parents 7869637 + 5cddfce commit ec48412
Show file tree
Hide file tree
Showing 4 changed files with 257 additions and 47 deletions.
16 changes: 9 additions & 7 deletions src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -36,7 +36,7 @@ private BoundExpression BindIsPatternExpression(IsPatternExpressionSyntax node,

Debug.Assert(expression.Type is { });
uint inputValEscape = GetValEscape(expression, LocalScopeDepth);
BoundPattern pattern = BindPattern(node.Pattern, expression.Type, inputValEscape, permitDesignations: true, hasErrors, diagnostics);
BoundPattern pattern = BindPattern(node.Pattern, expression.Type, inputValEscape, permitDesignations: true, hasErrors, diagnostics, underIsPattern: true);
hasErrors |= pattern.HasErrors;
return MakeIsPatternExpression(
node, expression, pattern, GetSpecialType(SpecialType.System_Boolean, diagnostics, node),
Expand Down Expand Up @@ -140,7 +140,8 @@ internal BoundPattern BindPattern(
uint inputValEscape,
bool permitDesignations,
bool hasErrors,
DiagnosticBag diagnostics)
DiagnosticBag diagnostics,
bool underIsPattern = false)
{
return node switch
{
Expand All @@ -149,9 +150,9 @@ internal BoundPattern BindPattern(
ConstantPatternSyntax p => BindConstantPatternWithFallbackToTypePattern(p, inputType, hasErrors, diagnostics),
RecursivePatternSyntax p => BindRecursivePattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics),
VarPatternSyntax p => BindVarPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics),
ParenthesizedPatternSyntax p => BindPattern(p.Pattern, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics),
ParenthesizedPatternSyntax p => BindPattern(p.Pattern, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics, underIsPattern),
BinaryPatternSyntax p => BindBinaryPattern(p, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics),
UnaryPatternSyntax p => BindUnaryPattern(p, inputType, inputValEscape, hasErrors, diagnostics),
UnaryPatternSyntax p => BindUnaryPattern(p, inputType, inputValEscape, hasErrors, diagnostics, underIsPattern),
RelationalPatternSyntax p => BindRelationalPattern(p, inputType, hasErrors, diagnostics),
TypePatternSyntax p => BindTypePattern(p, inputType, hasErrors, diagnostics),
_ => throw ExceptionUtilities.UnexpectedValue(node.Kind()),
Expand Down Expand Up @@ -1315,10 +1316,11 @@ private BoundPattern BindUnaryPattern(
TypeSymbol inputType,
uint inputValEscape,
bool hasErrors,
DiagnosticBag diagnostics)
DiagnosticBag diagnostics,
bool underIsPattern)
{
const bool permitDesignations = false; // prevent designators under 'not'
var subPattern = BindPattern(node.Pattern, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics);
bool permitDesignations = underIsPattern; // prevent designators under 'not' except under an is-pattern
var subPattern = BindPattern(node.Pattern, inputType, inputValEscape, permitDesignations, hasErrors, diagnostics, underIsPattern);
return new BoundNegatedPattern(node, subPattern, inputType: inputType, convertedType: inputType, hasErrors);
}

Expand Down
16 changes: 15 additions & 1 deletion src/Compilers/CSharp/Portable/FlowAnalysis/AbstractFlowPass.cs
Original file line number Diff line number Diff line change
Expand Up @@ -959,7 +959,16 @@ public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node
{
Debug.Assert(!IsConditionalState);
VisitRvalue(node.Expression);
VisitPattern(node.Pattern);

var pattern = node.Pattern;
bool negated = false;
while (pattern is BoundNegatedPattern n)
{
negated = !negated;
pattern = n.Negated;
}

VisitPattern(pattern);
var reachableLabels = node.DecisionDag.ReachableLabels;
if (!reachableLabels.Contains(node.WhenTrueLabel))
{
Expand All @@ -972,6 +981,11 @@ public override BoundNode VisitIsPatternExpression(BoundIsPatternExpression node
SetConditionalState(this.State, UnreachableState());
}

if (negated)
{
SetConditionalState(this.StateWhenFalse, this.StateWhenTrue);
}

return node;
}

Expand Down
17 changes: 9 additions & 8 deletions src/Compilers/CSharp/Test/Emit/Emit/EndToEndTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -154,14 +154,15 @@ public void DeeplyNestedGeneric()
{
int nestingLevel = (ExecutionConditionUtil.Architecture, ExecutionConditionUtil.Configuration) switch
{
(ExecutionArchitecture.x64, ExecutionConfiguration.Debug) when ExecutionConditionUtil.IsMacOS => 200,
(ExecutionArchitecture.x64, ExecutionConfiguration.Release) when ExecutionConditionUtil.IsMacOS => 520,
_ when ExecutionConditionUtil.IsCoreClrUnix => 1200,
_ when ExecutionConditionUtil.IsMonoDesktop => 730,
(ExecutionArchitecture.x86, ExecutionConfiguration.Debug) => 460,
(ExecutionArchitecture.x86, ExecutionConfiguration.Release) => 1350,
(ExecutionArchitecture.x64, ExecutionConfiguration.Debug) => 260,
(ExecutionArchitecture.x64, ExecutionConfiguration.Release) => 750,
// Legacy baselines are indicated by comments
(ExecutionArchitecture.x64, ExecutionConfiguration.Debug) when ExecutionConditionUtil.IsMacOS => 200, // 100
(ExecutionArchitecture.x64, ExecutionConfiguration.Release) when ExecutionConditionUtil.IsMacOS => 520, // 100
_ when ExecutionConditionUtil.IsCoreClrUnix => 1200, // 1200
_ when ExecutionConditionUtil.IsMonoDesktop => 730, // 730
(ExecutionArchitecture.x86, ExecutionConfiguration.Debug) => 460, // 270
(ExecutionArchitecture.x86, ExecutionConfiguration.Release) => 1320, // 1290
(ExecutionArchitecture.x64, ExecutionConfiguration.Debug) => 260, // 170
(ExecutionArchitecture.x64, ExecutionConfiguration.Release) => 750, // 730
_ => throw new Exception($"Unexpected configuration {ExecutionConditionUtil.Architecture} {ExecutionConditionUtil.Configuration}")
};

Expand Down
255 changes: 224 additions & 31 deletions src/Compilers/CSharp/Test/Semantic/Semantics/PatternMatchingTests3.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1950,6 +1950,9 @@ void Good(object o)
if (o is 1 and int x3) { }
if (o is (1 or 2) and int x4) { }
if (o is not (1 or 2) and int x5) { }
if (o is not int x6) { }
if (o is not (1 and int x7)) { }
}
void Bad(object o)
Expand All @@ -1958,11 +1961,9 @@ void Bad(object o)
if (o is int y2 or (1 or 2)) { }
if (o is 1 or int y3) { }
if (o is (1 or 2) or int y4) { }
if (o is not int y5) { }
if (o is not (1 and int y6)) { }
if (o is Point { X: var y7 } or Animal _) { }
if (o is Point(var y8, _) or Animal _) { }
if (o is object or (1 or var y9)) { }
if (o is Point { X: var y5 } or Animal _) { }
if (o is Point(var y6, _) or Animal _) { }
if (o is object or (1 or var y7)) { }
}
void NotBad(object o)
Expand All @@ -1984,36 +1985,30 @@ class Animal { }
";
var compilation = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
compilation.VerifyDiagnostics(
// (16,22): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// (19,22): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is int y1 or 1) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y1").WithLocation(16, 22),
// (17,22): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y1").WithLocation(19, 22),
// (20,22): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is int y2 or (1 or 2)) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y2").WithLocation(17, 22),
// (18,27): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y2").WithLocation(20, 22),
// (21,27): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is 1 or int y3) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y3").WithLocation(18, 27),
// (19,34): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y3").WithLocation(21, 27),
// (22,34): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is (1 or 2) or int y4) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y4").WithLocation(19, 34),
// (20,26): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is not int y5) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y5").WithLocation(20, 26),
// (21,33): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is not (1 and int y6)) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y6").WithLocation(21, 33),
// (22,33): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is Point { X: var y7 } or Animal _) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y7").WithLocation(22, 33),
// (23,28): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is Point(var y8, _) or Animal _) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y8").WithLocation(23, 28),
// (24,13): warning CS8794: An expression of type 'object' always matches the provided pattern.
// if (o is object or (1 or var y9)) { }
Diagnostic(ErrorCode.WRN_IsPatternAlways, "o is object or (1 or var y9)").WithArguments("object").WithLocation(24, 13),
// (24,38): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is object or (1 or var y9)) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y9").WithLocation(24, 38)
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y4").WithLocation(22, 34),
// (23,33): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is Point { X: var y5 } or Animal _) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y5").WithLocation(23, 33),
// (24,28): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is Point(var y6, _) or Animal _) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y6").WithLocation(24, 28),
// (25,13): warning CS8794: An expression of type 'object' always matches the provided pattern.
// if (o is object or (1 or var y7)) { }
Diagnostic(ErrorCode.WRN_IsPatternAlways, "o is object or (1 or var y7)").WithArguments("object").WithLocation(25, 13),
// (25,38): error CS8780: A variable may not be declared within a 'not' or 'or' pattern.
// if (o is object or (1 or var y7)) { }
Diagnostic(ErrorCode.ERR_DesignatorBeneathPatternCombinator, "y7").WithLocation(25, 38)
);
}

Expand Down Expand Up @@ -5641,5 +5636,203 @@ public void M() {
Diagnostic(ErrorCode.ERR_IntDivByZero, "0/0").WithLocation(4, 22)
);
}

[Fact]
public void IsNot_01()
{
var source =
@"using System;
class C
{
static void Main()
{
object o = ""s"";
if (o is not string s) return;
Console.WriteLine(s);
}
}";
string expectedOutput = "s";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularWithPatternCombinators);
compilation.VerifyDiagnostics(
);
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}

[Fact]
public void IsNot_02()
{
var source =
@"using System;
class C
{
static void Main()
{
object o = ""s"";
if (o is (not (string s))) return;
Console.WriteLine(s);
}
}";
string expectedOutput = "s";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularWithPatternCombinators);
compilation.VerifyDiagnostics(
);
var compVerifier = CompileAndVerify(compilation, expectedOutput: expectedOutput);
}

[Fact]
public void IsNot_03()
{
var source =
@"class C
{
static void Main()
{
object o = ""s"";
{
if (o is string s)
_ = s;
else
_ = s; // 1
}
{
if (o is not string s)
_ = s; // 2
else
_ = s;
}
{
if (o is not not string s)
_ = s;
else
_ = s; // 3
}
{
if (o is not not not string s)
_ = s; // 4
else
_ = s;
}
}
}";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularWithPatternCombinators);
compilation.VerifyDiagnostics(
// (10,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 1
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(10, 21),
// (14,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 2
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(14, 21),
// (22,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 3
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(22, 21),
// (26,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 4
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(26, 21)
);
}

[Fact]
public void IsNot_04()
{
var source =
@"class C
{
static void Main()
{
object o = ""s"";
{
if (o is (string s))
_ = s;
else
_ = s; // 1
}
{
if (o is (not (string s)))
_ = s; // 2
else
_ = s;
}
{
if (o is (not (not (string s))))
_ = s;
else
_ = s; // 3
}
{
if (o is (not (not (not (string s)))))
_ = s; // 4
else
_ = s;
}
}
}";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularWithPatternCombinators);
compilation.VerifyDiagnostics(
// (10,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 1
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(10, 21),
// (14,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 2
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(14, 21),
// (22,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 3
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(22, 21),
// (26,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 4
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(26, 21)
);
}

[Fact]
public void IsNot_05()
{
var source =
@"class C
{
static void Main()
{
(object, object) o = (1, 2);
{
if (o is (1, string s))
_ = s;
else
_ = s; // 1
}
{
if (o is (not (1, string s)))
_ = s; // 2
else
_ = s;
}
{
if (o is (not (not (1, string s))))
_ = s;
else
_ = s; // 3
}
{
if (o is (not (not (not (1, string s)))))
_ = s; // 4
else
_ = s;
}
}
}";
var compilation = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularWithPatternCombinators);
compilation.VerifyDiagnostics(
// (10,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 1
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(10, 21),
// (14,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 2
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(14, 21),
// (22,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 3
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(22, 21),
// (26,21): error CS0165: Use of unassigned local variable 's'
// _ = s; // 4
Diagnostic(ErrorCode.ERR_UseDefViolation, "s").WithArguments("s").WithLocation(26, 21)
);
}
}
}

0 comments on commit ec48412

Please sign in to comment.