提交 4f7bef27 编写于 作者: J Julien Couvreur 提交者: GitHub

Disallow unary and binary operators on default literal, except == and != (#19870)

上级 e2bb591c
......@@ -479,7 +479,6 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Di
bool leftNull = left.IsLiteralNull();
bool rightNull = right.IsLiteralNull();
bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual;
if (isEquality && leftNull && rightNull)
{
return new BoundLiteral(node, ConstantValue.Create(kind == BinaryOperatorKind.Equal), GetSpecialType(SpecialType.System_Boolean, diagnostics, node));
......@@ -625,6 +624,19 @@ private void ReportAssignmentOperatorError(AssignmentExpressionSyntax node, Diag
private static void ReportBinaryOperatorError(ExpressionSyntax node, DiagnosticBag diagnostics, SyntaxToken operatorToken, BoundExpression left, BoundExpression right, LookupResultKind resultKind)
{
if ((operatorToken.Kind() == SyntaxKind.EqualsEqualsToken || operatorToken.Kind() == SyntaxKind.ExclamationEqualsToken) &&
(left.IsLiteralDefault() && right.IsLiteralDefault()))
{
Error(diagnostics, ErrorCode.ERR_AmbigBinaryOpsOnDefault, node, operatorToken.Text);
return;
}
if (left.IsLiteralDefault() || right.IsLiteralDefault())
{
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, operatorToken.Text, "default");
return;
}
ErrorCode errorCode = resultKind == LookupResultKind.Ambiguous ?
ErrorCode.ERR_AmbigBinaryOps : // Operator '{0}' is ambiguous on operands of type '{1}' and '{2}'
ErrorCode.ERR_BadBinaryOps; // Operator '{0}' cannot be applied to operands of type '{1}' and '{2}'
......@@ -1023,6 +1035,13 @@ private TypeSymbol GetBinaryOperatorErrorType(BinaryOperatorKind kind, Diagnosti
private BinaryOperatorAnalysisResult BinaryOperatorOverloadResolution(BinaryOperatorKind kind, BoundExpression left, BoundExpression right, CSharpSyntaxNode node, DiagnosticBag diagnostics, out LookupResultKind resultKind, out ImmutableArray<MethodSymbol> originalUserDefinedOperators)
{
if (!IsDefaultLiteralAllowedInBinaryOperator(kind, left, right))
{
resultKind = LookupResultKind.OverloadResolutionFailure;
originalUserDefinedOperators = default(ImmutableArray<MethodSymbol>);
return default(BinaryOperatorAnalysisResult);
}
var result = BinaryOperatorOverloadResolutionResult.GetInstance();
HashSet<DiagnosticInfo> useSiteDiagnostics = null;
this.OverloadResolution.BinaryOperatorOverloadResolution(kind, left, right, result, ref useSiteDiagnostics);
......@@ -1073,6 +1092,19 @@ private BinaryOperatorAnalysisResult BinaryOperatorOverloadResolution(BinaryOper
return possiblyBest;
}
private bool IsDefaultLiteralAllowedInBinaryOperator(BinaryOperatorKind kind, BoundExpression left, BoundExpression right)
{
bool isEquality = kind == BinaryOperatorKind.Equal || kind == BinaryOperatorKind.NotEqual;
if (isEquality)
{
return !left.IsLiteralDefault() || !right.IsLiteralDefault();
}
else
{
return !left.IsLiteralDefault() && !right.IsLiteralDefault();
}
}
private UnaryOperatorAnalysisResult UnaryOperatorOverloadResolution(
UnaryOperatorKind kind,
BoundExpression operand,
......@@ -2180,12 +2212,12 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper
{
UnaryOperatorKind kind = SyntaxKindToUnaryOperatorKind(node.Kind());
bool isOperandTypeNull = operand.IsLiteralNull();
bool isOperandTypeNull = operand.IsLiteralNull() || operand.IsLiteralDefault();
if (isOperandTypeNull)
{
// Dev10 does not allow unary prefix operators to be applied to the null literal
// (or other typeless expressions).
Error(diagnostics, ErrorCode.ERR_BadUnaryOp, node, operatorText, operand.Display);
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, operatorText, operand.Display);
}
// If the operand is bad, avoid generating cascading errors.
......@@ -3236,7 +3268,16 @@ internal static ConstantValue GetAsOperatorConstantResult(TypeSymbol operandType
private BoundExpression GenerateNullCoalescingBadBinaryOpsError(BinaryExpressionSyntax node, BoundExpression leftOperand, BoundExpression rightOperand, Conversion leftConversion, DiagnosticBag diagnostics)
{
Error(diagnostics, ErrorCode.ERR_BadBinaryOps, node, SyntaxFacts.GetText(node.OperatorToken.Kind()), leftOperand.Display, rightOperand.Display);
if (leftOperand.IsLiteralDefault() || rightOperand.IsLiteralDefault())
{
Error(diagnostics, ErrorCode.ERR_BadOpOnNullOrDefault, node, node.OperatorToken.Text, "default");
}
else
{
Error(diagnostics, ErrorCode.ERR_BadBinaryOps, node, SyntaxFacts.GetText(node.OperatorToken.Kind()), leftOperand.Display, rightOperand.Display);
}
return new BoundNullCoalescingOperator(node, leftOperand, rightOperand,
leftConversion, CreateErrorType(), hasErrors: true);
}
......
......@@ -304,6 +304,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Operator &apos;{0}&apos; is ambiguous on operands &apos;default&apos; and &apos;default&apos;.
/// </summary>
internal static string ERR_AmbigBinaryOpsOnDefault {
get {
return ResourceManager.GetString("ERR_AmbigBinaryOpsOnDefault", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The call is ambiguous between the following methods or properties: &apos;{0}&apos; and &apos;{1}&apos;.
/// </summary>
......@@ -1735,6 +1744,15 @@ internal class CSharpResources {
}
}
/// <summary>
/// Looks up a localized string similar to Operator &apos;{0}&apos; cannot be applied to operand &apos;{1}&apos;.
/// </summary>
internal static string ERR_BadOpOnNullOrDefault {
get {
return ResourceManager.GetString("ERR_BadOpOnNullOrDefault", resourceCulture);
}
}
/// <summary>
/// Looks up a localized string similar to The parameter modifier &apos;out&apos; cannot be used with &apos;this&apos; .
/// </summary>
......
......@@ -426,6 +426,9 @@
<data name="ERR_BadUnaryOp" xml:space="preserve">
<value>Operator '{0}' cannot be applied to operand of type '{1}'</value>
</data>
<data name="ERR_BadOpOnNullOrDefault" xml:space="preserve">
<value>Operator '{0}' cannot be applied to operand '{1}'</value>
</data>
<data name="ERR_ThisInStaticMeth" xml:space="preserve">
<value>Keyword 'this' is not valid in a static property, static method, or static field initializer</value>
</data>
......@@ -450,6 +453,9 @@
<data name="ERR_AmbigBinaryOps" xml:space="preserve">
<value>Operator '{0}' is ambiguous on operands of type '{1}' and '{2}'</value>
</data>
<data name="ERR_AmbigBinaryOpsOnDefault" xml:space="preserve">
<value>Operator '{0}' is ambiguous on operands 'default' and 'default'</value>
</data>
<data name="ERR_AmbigUnaryOp" xml:space="preserve">
<value>Operator '{0}' is ambiguous on an operand of type '{1}'</value>
</data>
......
......@@ -1481,11 +1481,12 @@ internal enum ErrorCode
ERR_NoRefOutWhenRefOnly = 8308,
ERR_NoNetModuleOutputWhenRefOutOrRefOnly = 8309,
// Available = 8310,
ERR_BadOpOnNullOrDefault = 8310,
ERR_BadDynamicMethodArgDefaultLiteral = 8311,
ERR_DefaultLiteralNotValid = 8312,
WRN_DefaultInSwitch = 8313,
ERR_PatternWrongGenericTypeInVersion = 8314,
ERR_AmbigBinaryOpsOnDefault = 8315,
#endregion diagnostics introduced for C# 7.1
}
......
......@@ -1055,19 +1055,27 @@ object M()
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (9,17): error CS0023: Operator '!' cannot be applied to operand of type 'object'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "!q").WithArguments("!", "object"),
// (12,26): error CS0023: Operator '-' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "-null").WithArguments("-", "<null>"),
// (13,19): error CS0023: Operator '!' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "!null").WithArguments("!", "<null>"),
// (14,19): error CS0023: Operator '~' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "~null").WithArguments("~", "<null>"),
// if (!q) // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "!q").WithArguments("!", "object").WithLocation(9, 17),
// (12,26): error CS8310: Operator '-' cannot be applied to operand '<null>'
// object obj = -null; // CS0023
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "-null").WithArguments("-", "<null>").WithLocation(12, 26),
// (13,19): error CS8310: Operator '!' cannot be applied to operand '<null>'
// obj = !null; // CS0023
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "!null").WithArguments("!", "<null>").WithLocation(13, 19),
// (14,19): error CS8310: Operator '~' cannot be applied to operand '<null>'
// obj = ~null; // CS0023
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "~null").WithArguments("~", "<null>").WithLocation(14, 19),
// (16,13): error CS0023: Operator '++' cannot be applied to operand of type 'object'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "obj++").WithArguments("++", "object"),
// obj++; // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "obj++").WithArguments("++", "object").WithLocation(16, 13),
// (17,13): error CS0023: Operator '--' cannot be applied to operand of type 'object'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "--obj").WithArguments("--", "object"),
// (18,20): error CS0023: Operator '+' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadUnaryOp, "+null").WithArguments("+", "<null>"));
// --obj; // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "--obj").WithArguments("--", "object").WithLocation(17, 13),
// (18,20): error CS8310: Operator '+' cannot be applied to operand '<null>'
// return +null; // CS0023
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "+null").WithArguments("+", "<null>").WithLocation(18, 20)
);
}
[WorkItem(539590, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539590")]
......@@ -1092,18 +1100,19 @@ public static void Main()
}
";
CreateStandardCompilation(text).VerifyDiagnostics(
// (6,19): error CS0023: Operator '!' cannot be applied to operand of type '<null>'
// (6,19): error CS8310: Operator '!' cannot be applied to operand '<null>'
// bool? b = !null; // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "!null").WithArguments("!", "<null>"),
// (7,18): error CS0023: Operator '~' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "!null").WithArguments("!", "<null>").WithLocation(6, 19),
// (7,18): error CS8310: Operator '~' cannot be applied to operand '<null>'
// int? n = ~null; // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "~null").WithArguments("~", "<null>"),
// (8,20): error CS0023: Operator '+' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "~null").WithArguments("~", "<null>").WithLocation(7, 18),
// (8,20): error CS8310: Operator '+' cannot be applied to operand '<null>'
// float? f = +null; // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "+null").WithArguments("+", "<null>"),
// (9,19): error CS0023: Operator '-' cannot be applied to operand of type '<null>'
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "+null").WithArguments("+", "<null>").WithLocation(8, 20),
// (9,19): error CS8310: Operator '-' cannot be applied to operand '<null>'
// long? u = -null; // CS0023
Diagnostic(ErrorCode.ERR_BadUnaryOp, "-null").WithArguments("-", "<null>"));
Diagnostic(ErrorCode.ERR_BadOpOnNullOrDefault, "-null").WithArguments("-", "<null>").WithLocation(9, 19)
);
}
[WorkItem(539590, "http://vstfdevdiv:8080/DevDiv2/DevDiv/_workitems/edit/539590")]
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册