Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
48 changes: 22 additions & 26 deletions src/Compilers/CSharp/Portable/Binder/Binder_Operators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -541,7 +541,8 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Bi
&& left is BoundUnconvertedInterpolatedString or BoundBinaryOperator { IsUnconvertedInterpolatedStringAddition: true }
&& right is BoundUnconvertedInterpolatedString)
{
var stringConstant = FoldBinaryOperator(node, BinaryOperatorKind.StringConcatenation, left, right, SpecialType.System_String, diagnostics);
Debug.Assert(right.Type.SpecialType == SpecialType.System_String);
var stringConstant = FoldBinaryOperator(node, BinaryOperatorKind.StringConcatenation, left, right, right.Type, diagnostics);
return new BoundBinaryOperator(node, BinaryOperatorKind.StringConcatenation, BoundBinaryOperator.UncommonData.UnconvertedInterpolatedStringAddition(stringConstant), LookupResultKind.Empty, left, right, right.Type);
}

Expand Down Expand Up @@ -621,7 +622,7 @@ private BoundExpression BindSimpleBinaryOperator(BinaryExpressionSyntax node, Bi

resultLeft = CreateConversion(left, best.LeftConversion, signature.LeftType, diagnostics);
resultRight = CreateConversion(right, best.RightConversion, signature.RightType, diagnostics);
resultConstant = FoldBinaryOperator(node, resultOperatorKind, resultLeft, resultRight, resultType.SpecialType, diagnostics);
resultConstant = FoldBinaryOperator(node, resultOperatorKind, resultLeft, resultRight, resultType, diagnostics);
}
else
{
Expand Down Expand Up @@ -856,7 +857,7 @@ private BoundExpression BindConditionalLogicalOperator(BinaryExpressionSyntax no
if ((object)left.Type != null && left.Type.SpecialType == SpecialType.System_Boolean &&
(object)right.Type != null && right.Type.SpecialType == SpecialType.System_Boolean)
{
var constantValue = FoldBinaryOperator(node, kind | BinaryOperatorKind.Bool, left, right, SpecialType.System_Boolean, diagnostics);
var constantValue = FoldBinaryOperator(node, kind | BinaryOperatorKind.Bool, left, right, left.Type, diagnostics);

// NOTE: no candidate user-defined operators.
return new BoundBinaryOperator(node, kind | BinaryOperatorKind.Bool, constantValue, methodOpt: null, constrainedToTypeOpt: null,
Expand Down Expand Up @@ -1596,6 +1597,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)
BinaryOperatorKind kind,
BoundExpression left,
BoundExpression right,
TypeSymbol resultTypeSymbol,
BindingDiagnosticBag diagnostics)
{
Debug.Assert(left != null);
Expand Down Expand Up @@ -1628,16 +1630,14 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)

BinaryOperatorKind newKind = kind.Operator().WithType(newLeftOperand.Type!.SpecialType);

SpecialType operatorType = SpecialType.None;

switch (newKind.Operator())
{
case BinaryOperatorKind.Addition:
case BinaryOperatorKind.Subtraction:
case BinaryOperatorKind.And:
case BinaryOperatorKind.Or:
case BinaryOperatorKind.Xor:
operatorType = operandType.SpecialType;
resultTypeSymbol = operandType;
break;

case BinaryOperatorKind.LessThan:
Expand All @@ -1646,16 +1646,16 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)
case BinaryOperatorKind.GreaterThanOrEqual:
case BinaryOperatorKind.Equal:
case BinaryOperatorKind.NotEqual:
operatorType = SpecialType.System_Boolean;
Debug.Assert(resultTypeSymbol.SpecialType == SpecialType.System_Boolean);
break;

default:
throw ExceptionUtilities.UnexpectedValue(newKind.Operator());
}

var constantValue = FoldBinaryOperator(syntax, newKind, newLeftOperand, newRightOperand, operatorType, diagnostics);
var constantValue = FoldBinaryOperator(syntax, newKind, newLeftOperand, newRightOperand, resultTypeSymbol, diagnostics);

if (operatorType != SpecialType.System_Boolean && constantValue != null && !constantValue.IsBad)
if (resultTypeSymbol.SpecialType != SpecialType.System_Boolean && constantValue != null && !constantValue.IsBad)
{
TypeSymbol resultType = kind == BinaryOperatorKind.EnumSubtraction ? underlyingType : enumType;

Expand All @@ -1672,7 +1672,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)
BinaryOperatorKind kind,
BoundExpression left,
BoundExpression right,
SpecialType resultType,
TypeSymbol resultTypeSymbol,
BindingDiagnosticBag diagnostics)
{
Debug.Assert(left != null);
Expand Down Expand Up @@ -1704,7 +1704,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)

if (kind.IsEnum() && !kind.IsLifted())
{
return FoldEnumBinaryOperator(syntax, kind, left, right, diagnostics);
return FoldEnumBinaryOperator(syntax, kind, left, right, resultTypeSymbol, diagnostics);
}

// Divisions by zero on integral types and decimal always fail even in an unchecked context.
Expand All @@ -1715,6 +1715,7 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)
}

object? newValue = null;
SpecialType resultType = resultTypeSymbol.SpecialType;

// Certain binary operations never fail; bool & bool, for example. If we are in one of those
// cases, simply fold the operation and return.
Expand Down Expand Up @@ -1765,13 +1766,10 @@ internal static SpecialType GetEnumPromotedType(SpecialType underlyingType)
{
if (CheckOverflowAtCompileTime)
{
Error(diagnostics, ErrorCode.ERR_CheckedOverflow, syntax);
return ConstantValue.Bad;
}
else
{
return null;
Error(diagnostics, ErrorCode.WRN_CompileTimeCheckedOverflow, syntax, resultTypeSymbol);
}

return null;
}

if (newValue != null)
Expand Down Expand Up @@ -2616,7 +2614,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper
var resultOperand = CreateConversion(operand.Syntax, operand, best.Conversion, isCast: false, conversionGroupOpt: null, signature.OperandType, diagnostics);
var resultType = signature.ReturnType;
UnaryOperatorKind resultOperatorKind = signature.Kind;
var resultConstant = FoldUnaryOperator(node, resultOperatorKind, resultOperand, resultType.SpecialType, diagnostics);
var resultConstant = FoldUnaryOperator(node, resultOperatorKind, resultOperand, resultType, diagnostics);

CheckNativeIntegerFeatureAvailability(resultOperatorKind, node, diagnostics);
CheckConstraintLanguageVersionAndRuntimeSupportForOperator(node, signature.Method, signature.ConstrainedToTypeOpt, diagnostics);
Expand Down Expand Up @@ -2653,7 +2651,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper

UnaryOperatorKind newKind = kind.Operator().WithType(upconvertSpecialType);

var constantValue = FoldUnaryOperator(syntax, newKind, operand, upconvertType.SpecialType, diagnostics);
var constantValue = FoldUnaryOperator(syntax, newKind, operand, upconvertType, diagnostics);

// Convert back to the underlying type
if (constantValue != null && !constantValue.IsBad)
Expand All @@ -2671,7 +2669,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper
CSharpSyntaxNode syntax,
UnaryOperatorKind kind,
BoundExpression operand,
SpecialType resultType,
TypeSymbol resultTypeSymbol,
BindingDiagnosticBag diagnostics)
{
Debug.Assert(operand != null);
Expand All @@ -2693,6 +2691,7 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper
return FoldEnumUnaryOperator(syntax, kind, operand, diagnostics);
}

SpecialType resultType = resultTypeSymbol.SpecialType;
var newValue = FoldNeverOverflowUnaryOperator(kind, value);
if (newValue != null)
{
Expand All @@ -2707,13 +2706,10 @@ private BoundExpression BindUnaryOperatorCore(CSharpSyntaxNode node, string oper
{
if (CheckOverflowAtCompileTime)
{
Error(diagnostics, ErrorCode.ERR_CheckedOverflow, syntax);
return ConstantValue.Bad;
}
else
{
return null;
Error(diagnostics, ErrorCode.WRN_CompileTimeCheckedOverflow, syntax, resultTypeSymbol);
}

return null;
}

if (newValue != null)
Expand Down
6 changes: 6 additions & 0 deletions src/Compilers/CSharp/Portable/CSharpResources.resx
Original file line number Diff line number Diff line change
Expand Up @@ -6860,4 +6860,10 @@ To remove the warning, you can use /reference instead (set the Embed Interop Typ
<data name="ERR_LambdaWithAttributesToExpressionTree" xml:space="preserve">
<value>A lambda expression with attributes cannot be converted to an expression tree</value>
</data>
<data name="WRN_CompileTimeCheckedOverflow" xml:space="preserve">
<value>The operation may overflow '{0}' at runtime (use 'unchecked' syntax to override)</value>
</data>
<data name="WRN_CompileTimeCheckedOverflow_Title" xml:space="preserve">
<value>The operation may overflow at runtime (use 'unchecked' syntax to override)</value>
</data>
</root>
6 changes: 5 additions & 1 deletion src/Compilers/CSharp/Portable/CodeGen/EmitOperators.cs
Original file line number Diff line number Diff line change
Expand Up @@ -517,7 +517,7 @@ private void EmitUnaryCheckedOperatorExpression(BoundUnaryOperator expression, b
// then the mathematical negation of x is not representable within the operand type. If this occurs within a checked context,
// a System.OverflowException is thrown; if it occurs within an unchecked context,
// the result is the value of the operand and the overflow is not reported.
Debug.Assert(type == UnaryOperatorKind.Int || type == UnaryOperatorKind.Long);
Debug.Assert(type == UnaryOperatorKind.Int || type == UnaryOperatorKind.Long || type == UnaryOperatorKind.NInt);

// ldc.i4.0
// conv.i8 (when the operand is 64bit)
Expand All @@ -530,6 +530,10 @@ private void EmitUnaryCheckedOperatorExpression(BoundUnaryOperator expression, b
{
_builder.EmitOpCode(ILOpCode.Conv_i8);
}
else if (type == UnaryOperatorKind.NInt)
{
_builder.EmitOpCode(ILOpCode.Conv_i);
}

EmitExpression(expression.Operand, used: true);
_builder.EmitOpCode(ILOpCode.Sub_ovf);
Expand Down
2 changes: 2 additions & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorCode.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1997,6 +1997,8 @@ internal enum ErrorCode
WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters = 8971,
ERR_LambdaWithAttributesToExpressionTree = 8972,

WRN_CompileTimeCheckedOverflow = 8973,

#endregion

// Note: you will need to re-generate compiler code after adding warnings (eng\generate-compiler-code.cmd)
Expand Down
1 change: 1 addition & 0 deletions src/Compilers/CSharp/Portable/Errors/ErrorFacts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -484,6 +484,7 @@ internal static int GetWarningLevel(ErrorCode code)
case ErrorCode.WRN_CallerArgumentExpressionAttributeSelfReferential:
case ErrorCode.WRN_ParameterOccursAfterInterpolatedStringHandlerParameter:
case ErrorCode.WRN_InterpolatedStringHandlerArgumentAttributeIgnoredOnLambdaParameters:
case ErrorCode.WRN_CompileTimeCheckedOverflow:
return 1;
default:
return 0;
Expand Down

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.cs.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.de.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.es.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.fr.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.it.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

10 changes: 10 additions & 0 deletions src/Compilers/CSharp/Portable/xlf/CSharpResources.ja.xlf

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

Loading