private static TypeCode GetConvertTypeCode(TypeCode lhsTypeCode, TypeCode rhsTypeCode)
{
/* C# ECMA Spec V2
* 14.2.6.2 Binary numeric promotions
* This clause is informative.
* Binary numeric promotion occurs for the operands of the predefined +, ?, *, /, %, &, |, ^, ==, !=, >, <, >=,
* and <= binary operators. Binary numeric promotion implicitly converts both operands to a common type
* which, in case of the non-relational operators, also becomes the result type of the operation. Binary numeric
* promotion consists of applying the following rules, in the order they appear here:
* � If either operand is of type decimal, the other operand is converted to type decimal, or a compiletime
* error occurs if the other operand is of type float or double.
* � Otherwise, if either operand is of type double, the other operand is converted to type double.
* � Otherwise, if either operand is of type float, the other operand is converted to type float.
* � Otherwise, if either operand is of type ulong, the other operand is converted to type ulong, or a
* compile-time error occurs if the other operand is of type sbyte, short, int, or long.
* � Otherwise, if either operand is of type long, the other operand is converted to type long.
* � Otherwise, if either operand is of type uint and the other operand is of type sbyte, short, or int,
* both operands are converted to type long.
* � Otherwise, if either operand is of type uint, the other operand is converted to type uint.
* � Otherwise, both operands are converted to type int.
* [Note: The first rule disallows any operations that mix the decimal type with the double and float types.
* The rule follows from the fact that there are no implicit conversions between the decimal type and the
* double and float types. end note]
* [Note: Also note that it is not possible for an operand to be of type ulong when the other operand is of a
* signed integral type. The reason is that no integral type exists that can represent the full range of ulong as
* well as the signed integral types. end note]
* In both of the above cases, a cast expression can be used to explicitly convert one operand to a type that is
* compatible with the other operand.
*/
if (TypeCode.Decimal == lhsTypeCode || TypeCode.Decimal == rhsTypeCode)
{
return TypeCode.Decimal; // not per ECMA spec
}
if (TypeCode.Double == lhsTypeCode || TypeCode.Double == rhsTypeCode)
{
return TypeCode.Double;
}
if (TypeCode.Single == lhsTypeCode || TypeCode.Single == rhsTypeCode)
{
return TypeCode.Single;
}
if (TypeCode.UInt64 == lhsTypeCode)
{
if (TypeCode.SByte == rhsTypeCode || TypeCode.Int16 == rhsTypeCode ||
TypeCode.Int32 == rhsTypeCode || TypeCode.Int64 == rhsTypeCode)
{
// throw new ArgumentException("ulong <op> " + rhsTypeCode);
return TypeCode.Int64; // not per Ecma spec
}
return TypeCode.UInt64;
}
if (TypeCode.UInt64 == rhsTypeCode)
{
if (TypeCode.SByte == lhsTypeCode || TypeCode.Int16 == lhsTypeCode ||
TypeCode.Int32 == lhsTypeCode || TypeCode.Int64 == lhsTypeCode)
{
// throw new ArgumentException(lhsTypeCode + " <op> ulong");
return TypeCode.Int64; // not per Ecma spec
}
return TypeCode.UInt64;
}
if (TypeCode.Int64 == lhsTypeCode || TypeCode.Int64 == rhsTypeCode)
{
return TypeCode.Int64;
}
if (TypeCode.UInt32 == lhsTypeCode)
{
if (TypeCode.SByte == rhsTypeCode || TypeCode.Int16 == rhsTypeCode ||
TypeCode.Int32 == rhsTypeCode)
{
return TypeCode.Int64;
}
return TypeCode.UInt32;
}
if (TypeCode.UInt32 == rhsTypeCode)
{
if (TypeCode.SByte == lhsTypeCode || TypeCode.Int16 == lhsTypeCode ||
TypeCode.Int32 == lhsTypeCode)
{
return TypeCode.Int64;
}
return TypeCode.UInt32;
}
return TypeCode.Int32;
}