Skip to content

Commit

Permalink
Do not permit default literals in relational patterns (#45375)
Browse files Browse the repository at this point in the history
Fixes #45292
  • Loading branch information
Neal Gafter authored Jun 23, 2020
1 parent 35b67f8 commit 430056a
Show file tree
Hide file tree
Showing 3 changed files with 102 additions and 3 deletions.
26 changes: 25 additions & 1 deletion src/Compilers/CSharp/Portable/Binder/Binder_Patterns.cs
Original file line number Diff line number Diff line change
Expand Up @@ -180,7 +180,7 @@ internal BoundPattern BindConstantPatternWithFallbackToTypePattern(
bool hasErrors,
DiagnosticBag diagnostics)
{
ExpressionSyntax innerExpression = expression.SkipParens();
ExpressionSyntax innerExpression = SkipParensAndNullSuppressions(expression);
if (innerExpression.Kind() == SyntaxKind.DefaultLiteralExpression)
{
diagnostics.Add(ErrorCode.ERR_DefaultPattern, innerExpression.Location);
Expand All @@ -204,6 +204,24 @@ internal BoundPattern BindConstantPatternWithFallbackToTypePattern(
}
}

private ExpressionSyntax SkipParensAndNullSuppressions(ExpressionSyntax e)
{
while (true)
{
switch (e)
{
case ParenthesizedExpressionSyntax p:
e = p.Expression;
break;
case PostfixUnaryExpressionSyntax { RawKind: (int)SyntaxKind.SuppressNullableWarningExpression } p:
e = p.Operand;
break;
default:
return e;
}
}
}

/// <summary>
/// Binds the expression for a pattern. Sets <paramref name="wasExpression"/> if it was a type rather than an expression,
/// and in that case it returns a <see cref="BoundTypeExpression"/>.
Expand Down Expand Up @@ -1239,6 +1257,12 @@ private BoundPattern BindRelationalPattern(
DiagnosticBag diagnostics)
{
BoundExpression value = BindExpressionForPattern(inputType, node.Expression, ref hasErrors, diagnostics, out var constantValueOpt, out _);
ExpressionSyntax innerExpression = SkipParensAndNullSuppressions(node.Expression);
if (innerExpression.Kind() == SyntaxKind.DefaultLiteralExpression)
{
diagnostics.Add(ErrorCode.ERR_DefaultPattern, innerExpression.Location);
hasErrors = true;
}
RoslynDebug.Assert(value.Type is { });
BinaryOperatorKind operation = tokenKindToBinaryOperatorKind(node.OperatorToken.Kind());
if (operation == BinaryOperatorKind.Equal)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -237,7 +237,6 @@ private BoundSwitchLabel BindSwitchSectionLabel(
case SyntaxKind.CaseSwitchLabel:
{
var caseLabelSyntax = (CaseSwitchLabelSyntax)node;
SyntaxNode innerExpression = caseLabelSyntax.Value.SkipParens();
bool hasErrors = node.HasErrors;
BoundPattern pattern = sectionBinder.BindConstantPatternWithFallbackToTypePattern(
caseLabelSyntax.Value, caseLabelSyntax.Value, SwitchGoverningType, hasErrors, diagnostics);
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -347,6 +347,22 @@ public static void Main()
switch (i) { case default: break; } // error 3
switch (i) { case default when true: break; } // error 4
switch ((1, 2)) { case (1, default): break; } // error 5
if (i is < default) {} // error 6
switch (i) { case < default: break; } // error 7
if (i is < ((default))) {} // error 8
switch (i) { case < ((default)): break; } // error 9
if (i is default!) {} // error 10
if (i is (default!)) {} // error 11
if (i is < ((default)!)) {} // error 12
if (i is default!!) {} // error 13
if (i is (default!!)) {} // error 14
if (i is < ((default)!!)) {} // error 15
// These are not accepted by the parser. See https://github.com/dotnet/roslyn/issues/45387
if (i is (default)!) {} // error 16
if (i is ((default)!)) {} // error 17
}
}";
var compilation = CreatePatternCompilation(source);
Expand All @@ -365,7 +381,67 @@ public static void Main()
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(9, 27),
// (10,36): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// switch ((1, 2)) { case (1, default): break; } // error 5
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(10, 36)
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(10, 36),
// (12,20): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is < default) {} // error 6
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(12, 20),
// (13,29): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// switch (i) { case < default: break; } // error 7
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(13, 29),
// (14,22): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is < ((default))) {} // error 8
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(14, 22),
// (15,31): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// switch (i) { case < ((default)): break; } // error 9
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(15, 31),
// (17,18): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is default!) {} // error 10
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(17, 18),
// (18,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is (default!)) {} // error 11
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(18, 19),
// (19,22): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is < ((default)!)) {} // error 12
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(19, 22),
// (20,18): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is default!!) {} // error 13
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(20, 18),
// (21,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is (default!!)) {} // error 14
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(21, 19),
// (22,22): error CS8715: Duplicate null suppression operator ('!')
// if (i is < ((default)!!)) {} // error 15
Diagnostic(ErrorCode.ERR_DuplicateNullSuppression, "default").WithLocation(22, 22),
// (22,22): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is < ((default)!!)) {} // error 15
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(22, 22),
// (25,19): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is (default)!) {} // error 16
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(25, 19),
// (25,27): error CS1026: ) expected
// if (i is (default)!) {} // error 16
Diagnostic(ErrorCode.ERR_CloseParenExpected, "!").WithLocation(25, 27),
// (25,28): error CS1525: Invalid expression term ')'
// if (i is (default)!) {} // error 16
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(25, 28),
// (25,28): error CS1002: ; expected
// if (i is (default)!) {} // error 16
Diagnostic(ErrorCode.ERR_SemicolonExpected, ")").WithLocation(25, 28),
// (25,28): error CS1513: } expected
// if (i is (default)!) {} // error 16
Diagnostic(ErrorCode.ERR_RbraceExpected, ")").WithLocation(25, 28),
// (26,18): error CS8129: No suitable 'Deconstruct' instance or extension method was found for type 'int', with 2 out parameters and a void return type.
// if (i is ((default)!)) {} // error 17
Diagnostic(ErrorCode.ERR_MissingDeconstruct, "((default)!)").WithArguments("int", "2").WithLocation(26, 18),
// (26,20): error CS8505: A default literal 'default' is not valid as a pattern. Use another literal (e.g. '0' or 'null') as appropriate. To match everything, use a discard pattern '_'.
// if (i is ((default)!)) {} // error 17
Diagnostic(ErrorCode.ERR_DefaultPattern, "default").WithLocation(26, 20),
// (26,28): error CS1003: Syntax error, ',' expected
// if (i is ((default)!)) {} // error 17
Diagnostic(ErrorCode.ERR_SyntaxError, "!").WithArguments(",", "!").WithLocation(26, 28),
// (26,29): error CS1525: Invalid expression term ')'
// if (i is ((default)!)) {} // error 17
Diagnostic(ErrorCode.ERR_InvalidExprTerm, ")").WithArguments(")").WithLocation(26, 29)
);
}

Expand Down

0 comments on commit 430056a

Please sign in to comment.