未验证 提交 85edae87 编写于 作者: C Charles Stoner 提交者: GitHub

Increment and decrement operators (#41380)

上级 a1bcd597
......@@ -1150,7 +1150,6 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
// The int is converted to float and stored internally as the double 214783648, even though the
// fully precise int would fit into a double.
// PROTOTYPE: Test all cases.
unchecked
{
switch (value.Discriminator)
......@@ -1168,6 +1167,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)byteValue;
case SpecialType.System_Int32: return (int)byteValue;
case SpecialType.System_Int64: return (long)byteValue;
case SpecialType.System_IntPtr: return (int)byteValue;
case SpecialType.System_UIntPtr: return (uint)byteValue;
case SpecialType.System_Single:
case SpecialType.System_Double: return (double)byteValue;
case SpecialType.System_Decimal: return (decimal)byteValue;
......@@ -1186,6 +1187,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)charValue;
case SpecialType.System_Int32: return (int)charValue;
case SpecialType.System_Int64: return (long)charValue;
case SpecialType.System_IntPtr: return (int)charValue;
case SpecialType.System_UIntPtr: return (uint)charValue;
case SpecialType.System_Single:
case SpecialType.System_Double: return (double)charValue;
case SpecialType.System_Decimal: return (decimal)charValue;
......@@ -1204,6 +1207,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)uint16Value;
case SpecialType.System_Int32: return (int)uint16Value;
case SpecialType.System_Int64: return (long)uint16Value;
case SpecialType.System_IntPtr: return (int)uint16Value;
case SpecialType.System_UIntPtr: return (uint)uint16Value;
case SpecialType.System_Single:
case SpecialType.System_Double: return (double)uint16Value;
case SpecialType.System_Decimal: return (decimal)uint16Value;
......@@ -1222,6 +1227,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)uint32Value;
case SpecialType.System_Int32: return (int)uint32Value;
case SpecialType.System_Int64: return (long)uint32Value;
case SpecialType.System_IntPtr: return (int)uint32Value;
case SpecialType.System_UIntPtr: return (uint)uint32Value;
case SpecialType.System_Single: return (double)(float)uint32Value;
case SpecialType.System_Double: return (double)uint32Value;
case SpecialType.System_Decimal: return (decimal)uint32Value;
......@@ -1240,11 +1247,32 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)uint64Value;
case SpecialType.System_Int32: return (int)uint64Value;
case SpecialType.System_Int64: return (long)uint64Value;
case SpecialType.System_IntPtr: return (int)uint64Value;
case SpecialType.System_UIntPtr: return (uint)uint64Value;
case SpecialType.System_Single: return (double)(float)uint64Value;
case SpecialType.System_Double: return (double)uint64Value;
case SpecialType.System_Decimal: return (decimal)uint64Value;
default: throw ExceptionUtilities.UnexpectedValue(destinationType);
}
case ConstantValueTypeDiscriminator.NUInt:
uint nuintValue = value.UInt32Value;
switch (destinationType)
{
case SpecialType.System_Byte: return (byte)nuintValue;
case SpecialType.System_Char: return (char)nuintValue;
case SpecialType.System_UInt16: return (ushort)nuintValue;
case SpecialType.System_UInt32: return (uint)nuintValue;
case SpecialType.System_UInt64: return (ulong)nuintValue;
case SpecialType.System_SByte: return (sbyte)nuintValue;
case SpecialType.System_Int16: return (short)nuintValue;
case SpecialType.System_Int32: return (int)nuintValue;
case SpecialType.System_Int64: return (long)nuintValue;
case SpecialType.System_IntPtr: return (int)nuintValue;
case SpecialType.System_Single: return (double)(float)nuintValue;
case SpecialType.System_Double: return (double)nuintValue;
case SpecialType.System_Decimal: return (decimal)nuintValue;
default: throw ExceptionUtilities.UnexpectedValue(destinationType);
}
case ConstantValueTypeDiscriminator.SByte:
sbyte sbyteValue = value.SByteValue;
switch (destinationType)
......@@ -1258,6 +1286,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)sbyteValue;
case SpecialType.System_Int32: return (int)sbyteValue;
case SpecialType.System_Int64: return (long)sbyteValue;
case SpecialType.System_IntPtr: return (int)sbyteValue;
case SpecialType.System_UIntPtr: return (uint)sbyteValue;
case SpecialType.System_Single:
case SpecialType.System_Double: return (double)sbyteValue;
case SpecialType.System_Decimal: return (decimal)sbyteValue;
......@@ -1276,6 +1306,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)int16Value;
case SpecialType.System_Int32: return (int)int16Value;
case SpecialType.System_Int64: return (long)int16Value;
case SpecialType.System_IntPtr: return (int)int16Value;
case SpecialType.System_UIntPtr: return (uint)int16Value;
case SpecialType.System_Single:
case SpecialType.System_Double: return (double)int16Value;
case SpecialType.System_Decimal: return (decimal)int16Value;
......@@ -1314,11 +1346,33 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)int64Value;
case SpecialType.System_Int32: return (int)int64Value;
case SpecialType.System_Int64: return (long)int64Value;
case SpecialType.System_IntPtr: return (int)int64Value;
case SpecialType.System_UIntPtr: return (uint)int64Value;
case SpecialType.System_Single: return (double)(float)int64Value;
case SpecialType.System_Double: return (double)int64Value;
case SpecialType.System_Decimal: return (decimal)int64Value;
default: throw ExceptionUtilities.UnexpectedValue(destinationType);
}
case ConstantValueTypeDiscriminator.NInt:
int nintValue = value.Int32Value;
switch (destinationType)
{
case SpecialType.System_Byte: return (byte)nintValue;
case SpecialType.System_Char: return (char)nintValue;
case SpecialType.System_UInt16: return (ushort)nintValue;
case SpecialType.System_UInt32: return (uint)nintValue;
case SpecialType.System_UInt64: return (ulong)nintValue;
case SpecialType.System_SByte: return (sbyte)nintValue;
case SpecialType.System_Int16: return (short)nintValue;
case SpecialType.System_Int32: return (int)nintValue;
case SpecialType.System_Int64: return (long)nintValue;
case SpecialType.System_IntPtr: return (int)nintValue;
case SpecialType.System_UIntPtr: return (uint)nintValue;
case SpecialType.System_Single: return (double)(float)nintValue;
case SpecialType.System_Double: return (double)nintValue;
case SpecialType.System_Decimal: return (decimal)nintValue;
default: throw ExceptionUtilities.UnexpectedValue(destinationType);
}
case ConstantValueTypeDiscriminator.Single:
case ConstantValueTypeDiscriminator.Double:
// When converting from a floating-point type to an integral type, if the checked conversion would
......@@ -1336,6 +1390,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)doubleValue;
case SpecialType.System_Int32: return (int)doubleValue;
case SpecialType.System_Int64: return (long)doubleValue;
case SpecialType.System_IntPtr: return (int)doubleValue;
case SpecialType.System_UIntPtr: return (uint)doubleValue;
case SpecialType.System_Single: return (double)(float)doubleValue;
case SpecialType.System_Double: return (double)doubleValue;
case SpecialType.System_Decimal: return (value.Discriminator == ConstantValueTypeDiscriminator.Single) ? (decimal)(float)doubleValue : (decimal)doubleValue;
......@@ -1354,6 +1410,8 @@ private static object DoUncheckedConversion(SpecialType destinationType, Constan
case SpecialType.System_Int16: return (short)decimalValue;
case SpecialType.System_Int32: return (int)decimalValue;
case SpecialType.System_Int64: return (long)decimalValue;
case SpecialType.System_IntPtr: return (int)decimalValue;
case SpecialType.System_UIntPtr: return (uint)decimalValue;
case SpecialType.System_Single: return (double)(float)decimalValue;
case SpecialType.System_Double: return (double)decimalValue;
case SpecialType.System_Decimal: return (decimal)decimalValue;
......@@ -1436,11 +1494,13 @@ private static object CanonicalizeConstant(ConstantValue value)
case ConstantValueTypeDiscriminator.Int16: return (decimal)value.Int16Value;
case ConstantValueTypeDiscriminator.Int32: return (decimal)value.Int32Value;
case ConstantValueTypeDiscriminator.Int64: return (decimal)value.Int64Value;
case ConstantValueTypeDiscriminator.NInt: return (decimal)value.Int32Value;
case ConstantValueTypeDiscriminator.Byte: return (decimal)value.ByteValue;
case ConstantValueTypeDiscriminator.Char: return (decimal)value.CharValue;
case ConstantValueTypeDiscriminator.UInt16: return (decimal)value.UInt16Value;
case ConstantValueTypeDiscriminator.UInt32: return (decimal)value.UInt32Value;
case ConstantValueTypeDiscriminator.UInt64: return (decimal)value.UInt64Value;
case ConstantValueTypeDiscriminator.NUInt: return (decimal)value.UInt32Value;
case ConstantValueTypeDiscriminator.Single:
case ConstantValueTypeDiscriminator.Double: return value.DoubleValue;
case ConstantValueTypeDiscriminator.Decimal: return value.DecimalValue;
......
......@@ -76,6 +76,8 @@ internal enum UnaryOperatorKind
UIntPostfixIncrement = UInt | PostfixIncrement,
LongPostfixIncrement = Long | PostfixIncrement,
ULongPostfixIncrement = ULong | PostfixIncrement,
NIntPostfixIncrement = NInt | PostfixIncrement,
NUIntPostfixIncrement = NUInt | PostfixIncrement,
CharPostfixIncrement = Char | PostfixIncrement,
FloatPostfixIncrement = Float | PostfixIncrement,
DoublePostfixIncrement = Double | PostfixIncrement,
......@@ -90,6 +92,8 @@ internal enum UnaryOperatorKind
LiftedUIntPostfixIncrement = Lifted | UInt | PostfixIncrement,
LiftedLongPostfixIncrement = Lifted | Long | PostfixIncrement,
LiftedULongPostfixIncrement = Lifted | ULong | PostfixIncrement,
LiftedNIntPostfixIncrement = Lifted | NInt | PostfixIncrement,
LiftedNUIntPostfixIncrement = Lifted | NUInt | PostfixIncrement,
LiftedCharPostfixIncrement = Lifted | Char | PostfixIncrement,
LiftedFloatPostfixIncrement = Lifted | Float | PostfixIncrement,
LiftedDoublePostfixIncrement = Lifted | Double | PostfixIncrement,
......@@ -107,6 +111,8 @@ internal enum UnaryOperatorKind
UIntPrefixIncrement = UInt | PrefixIncrement,
LongPrefixIncrement = Long | PrefixIncrement,
ULongPrefixIncrement = ULong | PrefixIncrement,
NIntPrefixIncrement = NInt | PrefixIncrement,
NUIntPrefixIncrement = NUInt | PrefixIncrement,
CharPrefixIncrement = Char | PrefixIncrement,
FloatPrefixIncrement = Float | PrefixIncrement,
DoublePrefixIncrement = Double | PrefixIncrement,
......@@ -121,6 +127,8 @@ internal enum UnaryOperatorKind
LiftedUIntPrefixIncrement = Lifted | UInt | PrefixIncrement,
LiftedLongPrefixIncrement = Lifted | Long | PrefixIncrement,
LiftedULongPrefixIncrement = Lifted | ULong | PrefixIncrement,
LiftedNIntPrefixIncrement = Lifted | NInt | PrefixIncrement,
LiftedNUIntPrefixIncrement = Lifted | NUInt | PrefixIncrement,
LiftedCharPrefixIncrement = Lifted | Char | PrefixIncrement,
LiftedFloatPrefixIncrement = Lifted | Float | PrefixIncrement,
LiftedDoublePrefixIncrement = Lifted | Double | PrefixIncrement,
......@@ -138,6 +146,8 @@ internal enum UnaryOperatorKind
UIntPostfixDecrement = UInt | PostfixDecrement,
LongPostfixDecrement = Long | PostfixDecrement,
ULongPostfixDecrement = ULong | PostfixDecrement,
NIntPostfixDecrement = NInt | PostfixDecrement,
NUIntPostfixDecrement = NUInt | PostfixDecrement,
CharPostfixDecrement = Char | PostfixDecrement,
FloatPostfixDecrement = Float | PostfixDecrement,
DoublePostfixDecrement = Double | PostfixDecrement,
......@@ -152,6 +162,8 @@ internal enum UnaryOperatorKind
LiftedUIntPostfixDecrement = Lifted | UInt | PostfixDecrement,
LiftedLongPostfixDecrement = Lifted | Long | PostfixDecrement,
LiftedULongPostfixDecrement = Lifted | ULong | PostfixDecrement,
LiftedNIntPostfixDecrement = Lifted | NInt | PostfixDecrement,
LiftedNUIntPostfixDecrement = Lifted | NUInt | PostfixDecrement,
LiftedCharPostfixDecrement = Lifted | Char | PostfixDecrement,
LiftedFloatPostfixDecrement = Lifted | Float | PostfixDecrement,
LiftedDoublePostfixDecrement = Lifted | Double | PostfixDecrement,
......@@ -169,6 +181,8 @@ internal enum UnaryOperatorKind
UIntPrefixDecrement = UInt | PrefixDecrement,
LongPrefixDecrement = Long | PrefixDecrement,
ULongPrefixDecrement = ULong | PrefixDecrement,
NIntPrefixDecrement = NInt | PrefixDecrement,
NUIntPrefixDecrement = NUInt | PrefixDecrement,
CharPrefixDecrement = Char | PrefixDecrement,
FloatPrefixDecrement = Float | PrefixDecrement,
DoublePrefixDecrement = Double | PrefixDecrement,
......@@ -183,6 +197,8 @@ internal enum UnaryOperatorKind
LiftedUIntPrefixDecrement = Lifted | UInt | PrefixDecrement,
LiftedLongPrefixDecrement = Lifted | Long | PrefixDecrement,
LiftedULongPrefixDecrement = Lifted | ULong | PrefixDecrement,
LiftedNIntPrefixDecrement = Lifted | NInt | PrefixDecrement,
LiftedNUIntPrefixDecrement = Lifted | NUInt | PrefixDecrement,
LiftedCharPrefixDecrement = Lifted | Char | PrefixDecrement,
LiftedFloatPrefixDecrement = Lifted | Float | PrefixDecrement,
LiftedDoublePrefixDecrement = Lifted | Double | PrefixDecrement,
......@@ -196,6 +212,8 @@ internal enum UnaryOperatorKind
UIntUnaryPlus = UInt | UnaryPlus,
LongUnaryPlus = Long | UnaryPlus,
ULongUnaryPlus = ULong | UnaryPlus,
NIntUnaryPlus = NInt | UnaryPlus,
NUIntUnaryPlus = NUInt | UnaryPlus,
FloatUnaryPlus = Float | UnaryPlus,
DoubleUnaryPlus = Double | UnaryPlus,
DecimalUnaryPlus = Decimal | UnaryPlus,
......@@ -204,6 +222,8 @@ internal enum UnaryOperatorKind
LiftedUIntUnaryPlus = Lifted | UInt | UnaryPlus,
LiftedLongUnaryPlus = Lifted | Long | UnaryPlus,
LiftedULongUnaryPlus = Lifted | ULong | UnaryPlus,
LiftedNIntUnaryPlus = Lifted | NInt | UnaryPlus,
LiftedNUIntUnaryPlus = Lifted | NUInt | UnaryPlus,
LiftedFloatUnaryPlus = Lifted | Float | UnaryPlus,
LiftedDoubleUnaryPlus = Lifted | Double | UnaryPlus,
LiftedDecimalUnaryPlus = Lifted | Decimal | UnaryPlus,
......@@ -212,12 +232,14 @@ internal enum UnaryOperatorKind
IntUnaryMinus = Int | UnaryMinus,
LongUnaryMinus = Long | UnaryMinus,
NIntUnaryMinus = NInt | UnaryMinus,
FloatUnaryMinus = Float | UnaryMinus,
DoubleUnaryMinus = Double | UnaryMinus,
DecimalUnaryMinus = Decimal | UnaryMinus,
UserDefinedUnaryMinus = UserDefined | UnaryMinus,
LiftedIntUnaryMinus = Lifted | Int | UnaryMinus,
LiftedLongUnaryMinus = Lifted | Long | UnaryMinus,
LiftedNIntUnaryMinus = Lifted | NInt | UnaryMinus,
LiftedFloatUnaryMinus = Lifted | Float | UnaryMinus,
LiftedDoubleUnaryMinus = Lifted | Double | UnaryMinus,
LiftedDecimalUnaryMinus = Lifted | Decimal | UnaryMinus,
......@@ -234,12 +256,16 @@ internal enum UnaryOperatorKind
UIntBitwiseComplement = UInt | BitwiseComplement,
LongBitwiseComplement = Long | BitwiseComplement,
ULongBitwiseComplement = ULong | BitwiseComplement,
NIntBitwiseComplement = NInt | BitwiseComplement,
NUIntBitwiseComplement = NUInt | BitwiseComplement,
EnumBitwiseComplement = Enum | BitwiseComplement,
UserDefinedBitwiseComplement = UserDefined | BitwiseComplement,
LiftedIntBitwiseComplement = Lifted | Int | BitwiseComplement,
LiftedUIntBitwiseComplement = Lifted | UInt | BitwiseComplement,
LiftedLongBitwiseComplement = Lifted | Long | BitwiseComplement,
LiftedULongBitwiseComplement = Lifted | ULong | BitwiseComplement,
LiftedNIntBitwiseComplement = Lifted | NInt | BitwiseComplement,
LiftedNUIntBitwiseComplement = Lifted | NUInt | BitwiseComplement,
LiftedEnumBitwiseComplement = Lifted | Enum | BitwiseComplement,
LiftedUserDefinedBitwiseComplement = Lifted | UserDefined | BitwiseComplement,
DynamicBitwiseComplement = Dynamic | BitwiseComplement,
......
......@@ -104,6 +104,8 @@ public static bool IsIntegral(this UnaryOperatorKind kind)
case UnaryOperatorKind.UInt:
case UnaryOperatorKind.Long:
case UnaryOperatorKind.ULong:
case UnaryOperatorKind.NInt:
case UnaryOperatorKind.NUInt:
case UnaryOperatorKind.Char:
case UnaryOperatorKind.Enum:
case UnaryOperatorKind.Pointer:
......
......@@ -46,8 +46,8 @@ internal static class UnopEasyOut
private static readonly UnaryOperatorKind[] s_increment =
//obj str bool chr i08 i16 i32 i64 u08 u16 u32 u64 nint nuint r32 r64 dec
{ ERR, ERR, ERR, CHR, I08, I16, I32, I64, U08, U16, U32, U64, ERR, ERR, R32, R64, DEC,
/* lifted */ ERR, LCHR, LI08, LI16, LI32, LI64, LU08, LU16, LU32, LU64, ERR, ERR, LR32, LR64, LDEC };
{ ERR, ERR, ERR, CHR, I08, I16, I32, I64, U08, U16, U32, U64, NIN, NUI, R32, R64, DEC,
/* lifted */ ERR, LCHR, LI08, LI16, LI32, LI64, LU08, LU16, LU32, LU64, LNI, LNU, LR32, LR64, LDEC };
private static readonly UnaryOperatorKind[] s_plus =
//obj str bool chr i08 i16 i32 i64 u08 u16 u32 u64 nint nuint r32 r64 dec
......
......@@ -58,6 +58,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.UIntPostfixIncrement,
(int)UnaryOperatorKind.LongPostfixIncrement,
(int)UnaryOperatorKind.ULongPostfixIncrement,
(int)UnaryOperatorKind.NIntPostfixIncrement,
(int)UnaryOperatorKind.NUIntPostfixIncrement,
(int)UnaryOperatorKind.CharPostfixIncrement,
(int)UnaryOperatorKind.FloatPostfixIncrement,
(int)UnaryOperatorKind.DoublePostfixIncrement,
......@@ -70,6 +72,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.LiftedUIntPostfixIncrement,
(int)UnaryOperatorKind.LiftedLongPostfixIncrement,
(int)UnaryOperatorKind.LiftedULongPostfixIncrement,
(int)UnaryOperatorKind.LiftedNIntPostfixIncrement,
(int)UnaryOperatorKind.LiftedNUIntPostfixIncrement,
(int)UnaryOperatorKind.LiftedCharPostfixIncrement,
(int)UnaryOperatorKind.LiftedFloatPostfixIncrement,
(int)UnaryOperatorKind.LiftedDoublePostfixIncrement,
......@@ -85,6 +89,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.UIntPostfixDecrement,
(int)UnaryOperatorKind.LongPostfixDecrement,
(int)UnaryOperatorKind.ULongPostfixDecrement,
(int)UnaryOperatorKind.NIntPostfixDecrement,
(int)UnaryOperatorKind.NUIntPostfixDecrement,
(int)UnaryOperatorKind.CharPostfixDecrement,
(int)UnaryOperatorKind.FloatPostfixDecrement,
(int)UnaryOperatorKind.DoublePostfixDecrement,
......@@ -97,6 +103,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.LiftedUIntPostfixDecrement,
(int)UnaryOperatorKind.LiftedLongPostfixDecrement,
(int)UnaryOperatorKind.LiftedULongPostfixDecrement,
(int)UnaryOperatorKind.LiftedNIntPostfixDecrement,
(int)UnaryOperatorKind.LiftedNUIntPostfixDecrement,
(int)UnaryOperatorKind.LiftedCharPostfixDecrement,
(int)UnaryOperatorKind.LiftedFloatPostfixDecrement,
(int)UnaryOperatorKind.LiftedDoublePostfixDecrement,
......@@ -112,6 +120,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.UIntPrefixIncrement,
(int)UnaryOperatorKind.LongPrefixIncrement,
(int)UnaryOperatorKind.ULongPrefixIncrement,
(int)UnaryOperatorKind.NIntPrefixIncrement,
(int)UnaryOperatorKind.NUIntPrefixIncrement,
(int)UnaryOperatorKind.CharPrefixIncrement,
(int)UnaryOperatorKind.FloatPrefixIncrement,
(int)UnaryOperatorKind.DoublePrefixIncrement,
......@@ -124,6 +134,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.LiftedUIntPrefixIncrement,
(int)UnaryOperatorKind.LiftedLongPrefixIncrement,
(int)UnaryOperatorKind.LiftedULongPrefixIncrement,
(int)UnaryOperatorKind.LiftedNIntPrefixIncrement,
(int)UnaryOperatorKind.LiftedNUIntPrefixIncrement,
(int)UnaryOperatorKind.LiftedCharPrefixIncrement,
(int)UnaryOperatorKind.LiftedFloatPrefixIncrement,
(int)UnaryOperatorKind.LiftedDoublePrefixIncrement,
......@@ -137,6 +149,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.UShortPrefixDecrement,
(int)UnaryOperatorKind.IntPrefixDecrement,
(int)UnaryOperatorKind.UIntPrefixDecrement,
(int)UnaryOperatorKind.NIntPrefixDecrement,
(int)UnaryOperatorKind.NUIntPrefixDecrement,
(int)UnaryOperatorKind.LongPrefixDecrement,
(int)UnaryOperatorKind.ULongPrefixDecrement,
(int)UnaryOperatorKind.CharPrefixDecrement,
......@@ -151,6 +165,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.LiftedUIntPrefixDecrement,
(int)UnaryOperatorKind.LiftedLongPrefixDecrement,
(int)UnaryOperatorKind.LiftedULongPrefixDecrement,
(int)UnaryOperatorKind.LiftedNIntPrefixDecrement,
(int)UnaryOperatorKind.LiftedNUIntPrefixDecrement,
(int)UnaryOperatorKind.LiftedCharPrefixDecrement,
(int)UnaryOperatorKind.LiftedFloatPrefixDecrement,
(int)UnaryOperatorKind.LiftedDoublePrefixDecrement,
......@@ -162,6 +178,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.UIntUnaryPlus,
(int)UnaryOperatorKind.LongUnaryPlus,
(int)UnaryOperatorKind.ULongUnaryPlus,
(int)UnaryOperatorKind.NIntUnaryPlus,
(int)UnaryOperatorKind.NUIntUnaryPlus,
(int)UnaryOperatorKind.FloatUnaryPlus,
(int)UnaryOperatorKind.DoubleUnaryPlus,
(int)UnaryOperatorKind.DecimalUnaryPlus,
......@@ -169,6 +187,8 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.LiftedUIntUnaryPlus,
(int)UnaryOperatorKind.LiftedLongUnaryPlus,
(int)UnaryOperatorKind.LiftedULongUnaryPlus,
(int)UnaryOperatorKind.LiftedNIntUnaryPlus,
(int)UnaryOperatorKind.LiftedNUIntUnaryPlus,
(int)UnaryOperatorKind.LiftedFloatUnaryPlus,
(int)UnaryOperatorKind.LiftedDoubleUnaryPlus,
(int)UnaryOperatorKind.LiftedDecimalUnaryPlus,
......@@ -177,11 +197,13 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
{
(int)UnaryOperatorKind.IntUnaryMinus,
(int)UnaryOperatorKind.LongUnaryMinus,
(int)UnaryOperatorKind.NIntUnaryMinus,
(int)UnaryOperatorKind.FloatUnaryMinus,
(int)UnaryOperatorKind.DoubleUnaryMinus,
(int)UnaryOperatorKind.DecimalUnaryMinus,
(int)UnaryOperatorKind.LiftedIntUnaryMinus,
(int)UnaryOperatorKind.LiftedLongUnaryMinus,
(int)UnaryOperatorKind.LiftedNIntUnaryMinus,
(int)UnaryOperatorKind.LiftedFloatUnaryMinus,
(int)UnaryOperatorKind.LiftedDoubleUnaryMinus,
(int)UnaryOperatorKind.LiftedDecimalUnaryMinus,
......@@ -197,10 +219,14 @@ internal void GetSimpleBuiltInOperators(UnaryOperatorKind kind, ArrayBuilder<Una
(int)UnaryOperatorKind.UIntBitwiseComplement,
(int)UnaryOperatorKind.LongBitwiseComplement,
(int)UnaryOperatorKind.ULongBitwiseComplement,
(int)UnaryOperatorKind.NIntBitwiseComplement,
(int)UnaryOperatorKind.NUIntBitwiseComplement,
(int)UnaryOperatorKind.LiftedIntBitwiseComplement,
(int)UnaryOperatorKind.LiftedUIntBitwiseComplement,
(int)UnaryOperatorKind.LiftedLongBitwiseComplement,
(int)UnaryOperatorKind.LiftedULongBitwiseComplement,
(int)UnaryOperatorKind.LiftedNIntBitwiseComplement,
(int)UnaryOperatorKind.LiftedNUIntBitwiseComplement,
}),
// No built-in operator true or operator false
ImmutableArray<UnaryOperatorSignature>.Empty,
......
......@@ -687,16 +687,15 @@ private BoundExpression MakeBuiltInIncrementOperator(BoundIncrementOperator node
BinaryOperatorKind binaryOperatorKind = GetCorrespondingBinaryOperator(node);
binaryOperatorKind |= IsIncrement(node) ? BinaryOperatorKind.Addition : BinaryOperatorKind.Subtraction;
// The input/output type of the binary operand. "int" in the example.
// The "1" in the example above.
ConstantValue constantOne = GetConstantOneForBinOp(binaryOperatorKind);
(TypeSymbol binaryOperandType, ConstantValue constantOne) = GetConstantOneForIncrement(_compilation, binaryOperatorKind);
Debug.Assert(constantOne != null);
Debug.Assert(constantOne.SpecialType != SpecialType.None);
Debug.Assert(binaryOperandType.SpecialType != SpecialType.None);
Debug.Assert(binaryOperatorKind.OperandTypes() != 0);
// The input/output type of the binary operand. "int" in the example.
TypeSymbol binaryOperandType = _compilation.GetSpecialType(constantOne.SpecialType);
// 1
BoundExpression boundOne = MakeLiteral(
syntax: node.Syntax,
......@@ -900,6 +899,12 @@ private TypeSymbol GetUnaryOperatorType(BoundIncrementOperator node)
case UnaryOperatorKind.ULong:
specialType = SpecialType.System_UInt64;
break;
case UnaryOperatorKind.NInt:
specialType = SpecialType.System_IntPtr;
break;
case UnaryOperatorKind.NUInt:
specialType = SpecialType.System_UIntPtr;
break;
case UnaryOperatorKind.Float:
specialType = SpecialType.System_Single;
break;
......@@ -955,6 +960,12 @@ private static BinaryOperatorKind GetCorrespondingBinaryOperator(BoundIncrementO
case UnaryOperatorKind.ULong:
result = BinaryOperatorKind.ULong;
break;
case UnaryOperatorKind.NInt:
result = BinaryOperatorKind.NInt;
break;
case UnaryOperatorKind.NUInt:
result = BinaryOperatorKind.NUInt;
break;
case UnaryOperatorKind.Float:
result = BinaryOperatorKind.Float;
break;
......@@ -1015,6 +1026,8 @@ private static BinaryOperatorKind GetCorrespondingBinaryOperator(BoundIncrementO
case BinaryOperatorKind.Int:
case BinaryOperatorKind.ULong:
case BinaryOperatorKind.Long:
case BinaryOperatorKind.NUInt:
case BinaryOperatorKind.NInt:
case BinaryOperatorKind.PointerAndInt:
result |= (BinaryOperatorKind)unaryOperatorKind.OverflowChecks();
break;
......@@ -1028,29 +1041,45 @@ private static BinaryOperatorKind GetCorrespondingBinaryOperator(BoundIncrementO
return result;
}
private static ConstantValue GetConstantOneForBinOp(
private static (TypeSymbol, ConstantValue) GetConstantOneForIncrement(
CSharpCompilation compilation,
BinaryOperatorKind binaryOperatorKind)
{
ConstantValue constantOne;
switch (binaryOperatorKind.OperandTypes())
{
case BinaryOperatorKind.PointerAndInt:
case BinaryOperatorKind.Int:
return ConstantValue.Create(1);
constantOne = ConstantValue.Create(1);
break;
case BinaryOperatorKind.UInt:
return ConstantValue.Create(1U);
constantOne = ConstantValue.Create(1U);
break;
case BinaryOperatorKind.Long:
return ConstantValue.Create(1L);
constantOne = ConstantValue.Create(1L);
break;
case BinaryOperatorKind.ULong:
return ConstantValue.Create(1LU);
constantOne = ConstantValue.Create(1LU);
break;
case BinaryOperatorKind.NInt:
constantOne = ConstantValue.Create(1);
return (compilation.GetSpecialType(SpecialType.System_IntPtr).AsNativeInt(true), constantOne);
case BinaryOperatorKind.NUInt:
constantOne = ConstantValue.Create(1U);
return (compilation.GetSpecialType(SpecialType.System_UIntPtr).AsNativeInt(true), constantOne);
case BinaryOperatorKind.Float:
return ConstantValue.Create(1f);
constantOne = ConstantValue.Create(1f);
break;
case BinaryOperatorKind.Double:
return ConstantValue.Create(1.0);
constantOne = ConstantValue.Create(1.0);
break;
case BinaryOperatorKind.Decimal:
return ConstantValue.Create(1m);
constantOne = ConstantValue.Create(1m);
break;
default:
throw ExceptionUtilities.UnexpectedValue(binaryOperatorKind.OperandTypes());
}
return (compilation.GetSpecialType(constantOne.SpecialType), constantOne);
}
}
}
......@@ -41,7 +41,7 @@ public static bool CanBeConst(this TypeSymbol typeSymbol)
{
RoslynDebug.Assert((object)typeSymbol != null);
return typeSymbol.IsReferenceType || typeSymbol.IsEnumType() || typeSymbol.SpecialType.CanBeConst();
return typeSymbol.IsReferenceType || typeSymbol.IsEnumType() || typeSymbol.SpecialType.CanBeConst() || (typeSymbol as NamedTypeSymbol)?.IsNativeInt == true;
}
/// <summary>
......@@ -476,6 +476,8 @@ public static MethodSymbol DelegateInvokeMethod(this TypeSymbol type)
case SpecialType.System_UInt32:
case SpecialType.System_Int64:
case SpecialType.System_UInt64:
case SpecialType.System_IntPtr when ((NamedTypeSymbol)type).IsNativeInt:
case SpecialType.System_UIntPtr when ((NamedTypeSymbol)type).IsNativeInt:
case SpecialType.System_Char:
case SpecialType.System_Boolean:
case SpecialType.System_Single:
......
......@@ -3,6 +3,7 @@
// See the LICENSE file in the project root for more information.
using System;
using System.Collections.Immutable;
using System.Linq;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.CSharp.Syntax;
......@@ -548,12 +549,48 @@ public void SizeOf_04()
Diagnostic(ErrorCode.ERR_NotConstantExpression, "sizeof(nuint)").WithArguments("Program.D").WithLocation(6, 19));
}
// PROTOTYPE: PEVerify: "[ : MyInt::ToString][mdToken=0x6000005][offset 0x00000001] Cannot change initonly field outside its .ctor."
// CodeGenerator.EmitCallExpression() is not expecting a System.ValueType without an overload of ToString().
[Fact(Skip = "PEVerify failure")]
public void ReadOnlyField_VirtualMethods()
{
string source =
@"class MyInt
{
private readonly nint _i;
internal MyInt(nint i) => _i = i;
public override string ToString() => _i.ToString();
}
class Program
{
static void Main()
{
var m = new MyInt(42);
System.Console.WriteLine(m);
}
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
var verifier = CompileAndVerify(comp, expectedOutput: "42");
verifier.VerifyIL("MyInt.ToString",
@"{
// Code size 15 (0xf)
.maxstack 1
.locals init (System.IntPtr V_0)
IL_0000: ldarg.0
IL_0001: ldfld ""System.IntPtr MyInt._i""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""string System.IntPtr.ToString()""
IL_000e: ret
}");
}
/// <summary>
/// Verify there is exactly one built in operator for { nint, nuint, nint?, nuint? }
/// Verify there is the number of built in operators for { nint, nuint, nint?, nuint? }
/// for each operator kind.
/// </summary>
[Fact]
public void BinaryOperators_BuiltInOperators()
public void BuiltInOperators()
{
var source = "";
......@@ -567,7 +604,18 @@ public void BinaryOperators_BuiltInOperators()
static void verifyOperators(CSharpCompilation comp)
{
var operatorKinds = new[]
var unaryOperators = new[]
{
UnaryOperatorKind.PostfixIncrement,
UnaryOperatorKind.PostfixDecrement,
UnaryOperatorKind.PrefixIncrement,
UnaryOperatorKind.PrefixDecrement,
UnaryOperatorKind.UnaryPlus,
UnaryOperatorKind.UnaryMinus,
UnaryOperatorKind.BitwiseComplement,
};
var binaryOperators = new[]
{
BinaryOperatorKind.Addition,
BinaryOperatorKind.Subtraction,
......@@ -587,15 +635,29 @@ static void verifyOperators(CSharpCompilation comp)
BinaryOperatorKind.Xor,
};
foreach (var operatorKind in operatorKinds)
foreach (var operatorKind in unaryOperators)
{
var builder = ArrayBuilder<UnaryOperatorSignature>.GetInstance();
comp.builtInOperators.GetSimpleBuiltInOperators(operatorKind, builder);
var operators = builder.ToImmutableAndFree();
int expectedUnsigned = (operatorKind == UnaryOperatorKind.UnaryMinus) ? 0 : 1;
verifyOperators(operators, (op, signed) => isNativeInt(op.OperandType, signed), 1, expectedUnsigned);
verifyOperators(operators, (op, signed) => isNullableNativeInt(op.OperandType, signed), 1, expectedUnsigned);
}
foreach (var operatorKind in binaryOperators)
{
var builder = ArrayBuilder<BinaryOperatorSignature>.GetInstance();
comp.builtInOperators.GetSimpleBuiltInOperators(operatorKind, builder);
var operators = builder.ToImmutableAndFree();
_ = operators.Single(op => isNativeInt(op.LeftType, signed: true));
_ = operators.Single(op => isNativeInt(op.LeftType, signed: false));
_ = operators.Single(op => isNullableNativeInt(op.LeftType, signed: true));
_ = operators.Single(op => isNullableNativeInt(op.LeftType, signed: false));
verifyOperators(operators, (op, signed) => isNativeInt(op.LeftType, signed), 1, 1);
verifyOperators(operators, (op, signed) => isNullableNativeInt(op.LeftType, signed), 1, 1);
}
static void verifyOperators<T>(ImmutableArray<T> operators, Func<T, bool, bool> predicate, int expectedSigned, int expectedUnsigned)
{
Assert.Equal(expectedSigned, operators.Count(op => predicate(op, true)));
Assert.Equal(expectedUnsigned, operators.Count(op => predicate(op, false)));
}
static bool isNativeInt(TypeSymbol underlyingType, bool signed)
......@@ -611,6 +673,628 @@ static bool isNullableNativeInt(TypeSymbol underlyingType, bool signed)
}
}
[Theory]
[InlineData("")]
[InlineData("unchecked")]
[InlineData("checked")]
public void ConstantConversions_ToNativeInt(string context)
{
var source =
$@"#pragma warning disable 219
class Program
{{
static void F1()
{{
nint i;
{context}
{{
i = sbyte.MaxValue;
i = byte.MaxValue;
i = char.MaxValue;
i = short.MaxValue;
i = ushort.MaxValue;
i = int.MaxValue;
i = uint.MaxValue;
i = long.MaxValue;
i = ulong.MaxValue;
i = float.MaxValue;
i = double.MaxValue;
i = (decimal)int.MaxValue;
i = (nint)int.MaxValue;
i = (nuint)uint.MaxValue;
}}
}}
static void F2()
{{
nuint u;
{context}
{{
u = sbyte.MaxValue;
u = byte.MaxValue;
u = char.MaxValue;
u = short.MaxValue;
u = ushort.MaxValue;
u = int.MaxValue;
u = uint.MaxValue;
u = long.MaxValue;
u = ulong.MaxValue;
u = float.MaxValue;
u = double.MaxValue;
u = (decimal)uint.MaxValue;
u = (nint)int.MaxValue;
u = (nuint)uint.MaxValue;
}}
}}
}}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (15,17): error CS0266: Cannot implicitly convert type 'uint' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = uint.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "uint.MaxValue").WithArguments("uint", "nint").WithLocation(15, 17),
// (16,17): error CS0266: Cannot implicitly convert type 'long' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = long.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "long.MaxValue").WithArguments("long", "nint").WithLocation(16, 17),
// (17,17): error CS0266: Cannot implicitly convert type 'ulong' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = ulong.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "ulong.MaxValue").WithArguments("ulong", "nint").WithLocation(17, 17),
// (18,17): error CS0266: Cannot implicitly convert type 'float' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = float.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "float.MaxValue").WithArguments("float", "nint").WithLocation(18, 17),
// (19,17): error CS0266: Cannot implicitly convert type 'double' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = double.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "double.MaxValue").WithArguments("double", "nint").WithLocation(19, 17),
// (20,17): error CS0266: Cannot implicitly convert type 'decimal' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = (decimal)int.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(decimal)int.MaxValue").WithArguments("decimal", "nint").WithLocation(20, 17),
// (22,17): error CS0266: Cannot implicitly convert type 'nuint' to 'nint'. An explicit conversion exists (are you missing a cast?)
// i = (nuint)uint.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(nuint)uint.MaxValue").WithArguments("nuint", "nint").WithLocation(22, 17),
// (37,17): error CS0266: Cannot implicitly convert type 'long' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// u = long.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "long.MaxValue").WithArguments("long", "nuint").WithLocation(37, 17),
// (38,17): error CS0266: Cannot implicitly convert type 'ulong' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// u = ulong.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "ulong.MaxValue").WithArguments("ulong", "nuint").WithLocation(38, 17),
// (39,17): error CS0266: Cannot implicitly convert type 'float' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// u = float.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "float.MaxValue").WithArguments("float", "nuint").WithLocation(39, 17),
// (40,17): error CS0266: Cannot implicitly convert type 'double' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// u = double.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "double.MaxValue").WithArguments("double", "nuint").WithLocation(40, 17),
// (41,17): error CS0266: Cannot implicitly convert type 'decimal' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// u = (decimal)uint.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(decimal)uint.MaxValue").WithArguments("decimal", "nuint").WithLocation(41, 17),
// (42,17): error CS0266: Cannot implicitly convert type 'nint' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// u = (nint)int.MaxValue;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "(nint)int.MaxValue").WithArguments("nint", "nuint").WithLocation(42, 17));
}
[Theory]
[InlineData("")]
[InlineData("unchecked")]
[InlineData("checked")]
public void ConstantConversions_FromNativeInt(string context)
{
var source =
$@"#pragma warning disable 219
class Program
{{
static void F1()
{{
const nint n = (nint)int.MaxValue;
{context}
{{
sbyte sb = n;
byte b = n;
char c = n;
short s = n;
ushort us = n;
int i = n;
uint u = n;
long l = n;
ulong ul = n;
float f = n;
double d = n;
decimal dec = n;
nuint nu = n;
}}
}}
static void F2()
{{
const nuint nu = (nuint)uint.MaxValue;
{context}
{{
sbyte sb = nu;
byte b = nu;
char c = nu;
short s = nu;
ushort us = nu;
int i = nu;
uint u = nu;
long l = nu;
ulong ul = nu;
float f = nu;
double d = nu;
decimal dec = nu;
nint n = nu;
}}
}}
}}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (9,24): error CS0266: Cannot implicitly convert type 'nint' to 'sbyte'. An explicit conversion exists (are you missing a cast?)
// sbyte sb = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "sbyte").WithLocation(9, 24),
// (10,22): error CS0266: Cannot implicitly convert type 'nint' to 'byte'. An explicit conversion exists (are you missing a cast?)
// byte b = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "byte").WithLocation(10, 22),
// (11,22): error CS0266: Cannot implicitly convert type 'nint' to 'char'. An explicit conversion exists (are you missing a cast?)
// char c = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "char").WithLocation(11, 22),
// (12,23): error CS0266: Cannot implicitly convert type 'nint' to 'short'. An explicit conversion exists (are you missing a cast?)
// short s = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "short").WithLocation(12, 23),
// (13,25): error CS0266: Cannot implicitly convert type 'nint' to 'ushort'. An explicit conversion exists (are you missing a cast?)
// ushort us = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "ushort").WithLocation(13, 25),
// (14,21): error CS0266: Cannot implicitly convert type 'nint' to 'int'. An explicit conversion exists (are you missing a cast?)
// int i = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "int").WithLocation(14, 21),
// (15,22): error CS0266: Cannot implicitly convert type 'nint' to 'uint'. An explicit conversion exists (are you missing a cast?)
// uint u = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "uint").WithLocation(15, 22),
// (17,24): error CS0266: Cannot implicitly convert type 'nint' to 'ulong'. An explicit conversion exists (are you missing a cast?)
// ulong ul = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "ulong").WithLocation(17, 24),
// (21,24): error CS0266: Cannot implicitly convert type 'nint' to 'nuint'. An explicit conversion exists (are you missing a cast?)
// nuint nu = n;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "n").WithArguments("nint", "nuint").WithLocation(21, 24),
// (29,24): error CS0266: Cannot implicitly convert type 'nuint' to 'sbyte'. An explicit conversion exists (are you missing a cast?)
// sbyte sb = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "sbyte").WithLocation(29, 24),
// (30,22): error CS0266: Cannot implicitly convert type 'nuint' to 'byte'. An explicit conversion exists (are you missing a cast?)
// byte b = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "byte").WithLocation(30, 22),
// (31,22): error CS0266: Cannot implicitly convert type 'nuint' to 'char'. An explicit conversion exists (are you missing a cast?)
// char c = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "char").WithLocation(31, 22),
// (32,23): error CS0266: Cannot implicitly convert type 'nuint' to 'short'. An explicit conversion exists (are you missing a cast?)
// short s = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "short").WithLocation(32, 23),
// (33,25): error CS0266: Cannot implicitly convert type 'nuint' to 'ushort'. An explicit conversion exists (are you missing a cast?)
// ushort us = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "ushort").WithLocation(33, 25),
// (34,21): error CS0266: Cannot implicitly convert type 'nuint' to 'int'. An explicit conversion exists (are you missing a cast?)
// int i = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "int").WithLocation(34, 21),
// (35,22): error CS0266: Cannot implicitly convert type 'nuint' to 'uint'. An explicit conversion exists (are you missing a cast?)
// uint u = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "uint").WithLocation(35, 22),
// (36,22): error CS0266: Cannot implicitly convert type 'nuint' to 'long'. An explicit conversion exists (are you missing a cast?)
// long l = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "long").WithLocation(36, 22),
// (41,22): error CS0266: Cannot implicitly convert type 'nuint' to 'nint'. An explicit conversion exists (are you missing a cast?)
// nint n = nu;
Diagnostic(ErrorCode.ERR_NoImplicitConvCast, "nu").WithArguments("nuint", "nint").WithLocation(41, 22));
}
[Fact]
public void Constants_NInt()
{
string source =
$@"class Program
{{
static void Main()
{{
F(default);
F(int.MinValue);
F({short.MinValue - 1});
F(short.MinValue);
F(sbyte.MinValue);
F(-2);
F(-1);
F(0);
F(1);
F(2);
F(3);
F(4);
F(5);
F(6);
F(7);
F(8);
F(9);
F(sbyte.MaxValue);
F(byte.MaxValue);
F(short.MaxValue);
F(char.MaxValue);
F(ushort.MaxValue);
F({ushort.MaxValue + 1});
F(int.MaxValue);
}}
static void F(nint n)
{{
System.Console.WriteLine(n);
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
string expectedOutput =
@"0
-2147483648
-32769
-32768
-128
-2
-1
0
1
2
3
4
5
6
7
8
9
127
255
32767
65535
65535
65536
2147483647";
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
string expectedIL =
@"{
// Code size 209 (0xd1)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: conv.i
IL_0002: call ""void Program.F(nint)""
IL_0007: ldc.i4 0x80000000
IL_000c: conv.i
IL_000d: call ""void Program.F(nint)""
IL_0012: ldc.i4 0xffff7fff
IL_0017: conv.i
IL_0018: call ""void Program.F(nint)""
IL_001d: ldc.i4 0xffff8000
IL_0022: conv.i
IL_0023: call ""void Program.F(nint)""
IL_0028: ldc.i4.s -128
IL_002a: conv.i
IL_002b: call ""void Program.F(nint)""
IL_0030: ldc.i4.s -2
IL_0032: conv.i
IL_0033: call ""void Program.F(nint)""
IL_0038: ldc.i4.m1
IL_0039: conv.i
IL_003a: call ""void Program.F(nint)""
IL_003f: ldc.i4.0
IL_0040: conv.i
IL_0041: call ""void Program.F(nint)""
IL_0046: ldc.i4.1
IL_0047: conv.i
IL_0048: call ""void Program.F(nint)""
IL_004d: ldc.i4.2
IL_004e: conv.i
IL_004f: call ""void Program.F(nint)""
IL_0054: ldc.i4.3
IL_0055: conv.i
IL_0056: call ""void Program.F(nint)""
IL_005b: ldc.i4.4
IL_005c: conv.i
IL_005d: call ""void Program.F(nint)""
IL_0062: ldc.i4.5
IL_0063: conv.i
IL_0064: call ""void Program.F(nint)""
IL_0069: ldc.i4.6
IL_006a: conv.i
IL_006b: call ""void Program.F(nint)""
IL_0070: ldc.i4.7
IL_0071: conv.i
IL_0072: call ""void Program.F(nint)""
IL_0077: ldc.i4.8
IL_0078: conv.i
IL_0079: call ""void Program.F(nint)""
IL_007e: ldc.i4.s 9
IL_0080: conv.i
IL_0081: call ""void Program.F(nint)""
IL_0086: ldc.i4.s 127
IL_0088: conv.i
IL_0089: call ""void Program.F(nint)""
IL_008e: ldc.i4 0xff
IL_0093: conv.i
IL_0094: call ""void Program.F(nint)""
IL_0099: ldc.i4 0x7fff
IL_009e: conv.i
IL_009f: call ""void Program.F(nint)""
IL_00a4: ldc.i4 0xffff
IL_00a9: conv.i
IL_00aa: call ""void Program.F(nint)""
IL_00af: ldc.i4 0xffff
IL_00b4: conv.i
IL_00b5: call ""void Program.F(nint)""
IL_00ba: ldc.i4 0x10000
IL_00bf: conv.i
IL_00c0: call ""void Program.F(nint)""
IL_00c5: ldc.i4 0x7fffffff
IL_00ca: conv.i
IL_00cb: call ""void Program.F(nint)""
IL_00d0: ret
}";
verifier.VerifyIL("Program.Main", expectedIL);
}
[Fact]
public void Constants_NUInt()
{
string source =
$@"class Program
{{
static void Main()
{{
F(default);
F(0);
F(1);
F(2);
F(3);
F(4);
F(5);
F(6);
F(7);
F(8);
F(9);
F(sbyte.MaxValue);
F(byte.MaxValue);
F(short.MaxValue);
F(char.MaxValue);
F(ushort.MaxValue);
F(int.MaxValue);
F({(uint)int.MaxValue + 1});
F(uint.MaxValue);
}}
static void F(nuint n)
{{
System.Console.WriteLine(n);
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
string expectedOutput =
@"0
0
1
2
3
4
5
6
7
8
9
127
255
32767
65535
65535
2147483647
2147483648
4294967295";
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
string expectedIL =
@"{
// Code size 160 (0xa0)
.maxstack 1
IL_0000: ldc.i4.0
IL_0001: conv.i
IL_0002: call ""void Program.F(nuint)""
IL_0007: ldc.i4.0
IL_0008: conv.i
IL_0009: call ""void Program.F(nuint)""
IL_000e: ldc.i4.1
IL_000f: conv.i
IL_0010: call ""void Program.F(nuint)""
IL_0015: ldc.i4.2
IL_0016: conv.i
IL_0017: call ""void Program.F(nuint)""
IL_001c: ldc.i4.3
IL_001d: conv.i
IL_001e: call ""void Program.F(nuint)""
IL_0023: ldc.i4.4
IL_0024: conv.i
IL_0025: call ""void Program.F(nuint)""
IL_002a: ldc.i4.5
IL_002b: conv.i
IL_002c: call ""void Program.F(nuint)""
IL_0031: ldc.i4.6
IL_0032: conv.i
IL_0033: call ""void Program.F(nuint)""
IL_0038: ldc.i4.7
IL_0039: conv.i
IL_003a: call ""void Program.F(nuint)""
IL_003f: ldc.i4.8
IL_0040: conv.i
IL_0041: call ""void Program.F(nuint)""
IL_0046: ldc.i4.s 9
IL_0048: conv.i
IL_0049: call ""void Program.F(nuint)""
IL_004e: ldc.i4.s 127
IL_0050: conv.i
IL_0051: call ""void Program.F(nuint)""
IL_0056: ldc.i4 0xff
IL_005b: conv.i
IL_005c: call ""void Program.F(nuint)""
IL_0061: ldc.i4 0x7fff
IL_0066: conv.i
IL_0067: call ""void Program.F(nuint)""
IL_006c: ldc.i4 0xffff
IL_0071: conv.i
IL_0072: call ""void Program.F(nuint)""
IL_0077: ldc.i4 0xffff
IL_007c: conv.i
IL_007d: call ""void Program.F(nuint)""
IL_0082: ldc.i4 0x7fffffff
IL_0087: conv.i
IL_0088: call ""void Program.F(nuint)""
IL_008d: ldc.i4 0x80000000
IL_0092: conv.u
IL_0093: call ""void Program.F(nuint)""
IL_0098: ldc.i4.m1
IL_0099: conv.u
IL_009a: call ""void Program.F(nuint)""
IL_009f: ret
}";
verifier.VerifyIL("Program.Main", expectedIL);
}
[Fact]
public void Constants_Locals()
{
var source =
@"#pragma warning disable 219
class Program
{
static void Main()
{
const System.IntPtr a = default;
const nint b = default;
const System.UIntPtr c = default;
const nuint d = default;
}
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (6,15): error CS0283: The type 'IntPtr' cannot be declared const
// const System.IntPtr a = default;
Diagnostic(ErrorCode.ERR_BadConstType, "System.IntPtr").WithArguments("System.IntPtr").WithLocation(6, 15),
// (8,15): error CS0283: The type 'UIntPtr' cannot be declared const
// const System.UIntPtr c = default;
Diagnostic(ErrorCode.ERR_BadConstType, "System.UIntPtr").WithArguments("System.UIntPtr").WithLocation(8, 15));
}
[Fact]
public void Constants_Fields_01()
{
var source =
@"class Program
{
const System.IntPtr A = default(System.IntPtr);
const nint B = default(nint);
const System.UIntPtr C = default(System.UIntPtr);
const nuint D = default(nuint);
}";
var comp = CreateCompilation(source, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(
// (3,5): error CS0283: The type 'IntPtr' cannot be declared const
// const System.IntPtr A = default(System.IntPtr);
Diagnostic(ErrorCode.ERR_BadConstType, "const").WithArguments("System.IntPtr").WithLocation(3, 5),
// (3,29): error CS0133: The expression being assigned to 'Program.A' must be constant
// const System.IntPtr A = default(System.IntPtr);
Diagnostic(ErrorCode.ERR_NotConstantExpression, "default(System.IntPtr)").WithArguments("Program.A").WithLocation(3, 29),
// (5,5): error CS0283: The type 'UIntPtr' cannot be declared const
// const System.UIntPtr C = default(System.UIntPtr);
Diagnostic(ErrorCode.ERR_BadConstType, "const").WithArguments("System.UIntPtr").WithLocation(5, 5),
// (5,30): error CS0133: The expression being assigned to 'Program.C' must be constant
// const System.UIntPtr C = default(System.UIntPtr);
Diagnostic(ErrorCode.ERR_NotConstantExpression, "default(System.UIntPtr)").WithArguments("Program.C").WithLocation(5, 30));
}
[Fact]
public void Constants_Fields_02()
{
var source0 =
@"public class A
{
public const nint C1 = -42;
public const nuint C2 = 42;
}";
var comp = CreateCompilation(source0, parseOptions: TestOptions.RegularPreview);
var ref0 = comp.EmitToImageReference();
var source1 =
@"using System;
class B
{
static void Main()
{
Console.WriteLine(A.C1);
Console.WriteLine(A.C2);
}
}";
comp = CreateCompilation(source1, references: new[] { ref0 }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
CompileAndVerify(comp, expectedOutput:
@"-42
42");
}
[Fact]
public void Constants_ParameterDefaults()
{
var source0 =
@"public class A
{
public static System.IntPtr F1(System.IntPtr i = default) => i;
public static nint F2(nint i = -42) => i;
public static System.UIntPtr F3(System.UIntPtr u = default) => u;
public static nuint F4(nuint u = 42) => u;
}";
var comp = CreateCompilation(source0, parseOptions: TestOptions.RegularPreview);
var ref0 = comp.EmitToImageReference();
var source1 =
@"using System;
class B
{
static void Main()
{
Console.WriteLine(A.F1());
Console.WriteLine(A.F2());
Console.WriteLine(A.F3());
Console.WriteLine(A.F4());
}
}";
comp = CreateCompilation(source1, references: new[] { ref0 }, parseOptions: TestOptions.RegularPreview, options: TestOptions.ReleaseExe);
CompileAndVerify(comp, expectedOutput:
@"0
-42
0
42");
}
[Fact]
public void Constants_FromMetadata()
{
var source0 =
@"public class Constants
{
public const nint NIntMin = int.MinValue;
public const nint NIntMax = int.MaxValue;
public const nuint NUIntMin = uint.MinValue;
public const nuint NUIntMax = uint.MaxValue;
}";
var comp = CreateCompilation(source0, parseOptions: TestOptions.RegularPreview);
var ref0 = comp.EmitToImageReference();
var source1 =
@"using System;
class Program
{
static void Main()
{
const nint nintMin = Constants.NIntMin;
const nint nintMax = Constants.NIntMax;
const nuint nuintMin = Constants.NUIntMin;
const nuint nuintMax = Constants.NUIntMax;
Console.WriteLine(nintMin);
Console.WriteLine(nintMax);
Console.WriteLine(nuintMin);
Console.WriteLine(nuintMax);
}
}";
comp = CreateCompilation(source1, references: new[] { ref0 }, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
CompileAndVerify(comp, expectedOutput:
@"-2147483648
2147483647
0
4294967295");
}
[Fact]
public void Conversions()
{
......@@ -670,7 +1354,7 @@ .maxstack 1
}}";
void conversions(string sourceType, string destType, string expectedImplicitIL, string expectedExplicitIL, string expectedCheckedIL = null)
{
Convert(
convert(
sourceType,
destType,
expectedImplicitIL,
......@@ -680,7 +1364,7 @@ void conversions(string sourceType, string destType, string expectedImplicitIL,
expectedImplicitIL is null ?
expectedExplicitIL is null ? ErrorCode.ERR_NoImplicitConv : ErrorCode.ERR_NoImplicitConvCast :
0);
Convert(
convert(
sourceType,
destType,
expectedExplicitIL,
......@@ -689,7 +1373,7 @@ void conversions(string sourceType, string destType, string expectedImplicitIL,
useChecked: false,
expectedExplicitIL is null ? ErrorCode.ERR_NoExplicitConv : 0);
expectedCheckedIL ??= expectedExplicitIL;
Convert(
convert(
sourceType,
destType,
expectedCheckedIL,
......@@ -1617,62 +2301,60 @@ .maxstack 1
}");
conversions(sourceType: "nuint?", destType: "System.IntPtr?", expectedImplicitIL: null, expectedExplicitIL: null);
conversions(sourceType: "nuint?", destType: "System.UIntPtr?", expectedImplicitIL: convNone, expectedExplicitIL: convNone);
}
private void Convert(string sourceType,
string destType,
string expectedIL,
bool skipTypeChecks,
bool useExplicitCast,
bool useChecked,
ErrorCode expectedErrorCode)
{
bool useUnsafeContext = useUnsafe(sourceType) || useUnsafe(destType);
string value = "value";
if (useExplicitCast)
{
value = $"({destType})value";
}
var expectedDiagnostics = expectedErrorCode == 0 ?
Array.Empty<DiagnosticDescription>() :
new[] { Diagnostic(expectedErrorCode, value).WithArguments(sourceType, destType) };
if (useChecked)
void convert(string sourceType,
string destType,
string expectedIL,
bool skipTypeChecks,
bool useExplicitCast,
bool useChecked,
ErrorCode expectedErrorCode)
{
value = $"checked({value})";
}
string source =
$@"class Program
bool useUnsafeContext = useUnsafe(sourceType) || useUnsafe(destType);
string value = "value";
if (useExplicitCast)
{
value = $"({destType})value";
}
var expectedDiagnostics = expectedErrorCode == 0 ?
Array.Empty<DiagnosticDescription>() :
new[] { Diagnostic(expectedErrorCode, value).WithArguments(sourceType, destType) };
if (useChecked)
{
value = $"checked({value})";
}
string source =
$@"class Program
{{
static {(useUnsafeContext ? "unsafe " : "")}{destType} Convert({sourceType} value)
{{
return {value};
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(useUnsafeContext), parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(useUnsafeContext), parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression;
var underlyingTypeInfo = model.GetTypeInfo(expr);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<ReturnStatementSyntax>().Single().Expression;
var typeInfo = model.GetTypeInfo(expr);
if (!skipTypeChecks)
{
Assert.Equal(sourceType, underlyingTypeInfo.Type.ToString());
Assert.Equal(destType, underlyingTypeInfo.ConvertedType.ToString());
}
if (!skipTypeChecks)
{
Assert.Equal(sourceType, typeInfo.Type.ToString());
Assert.Equal(destType, typeInfo.ConvertedType.ToString());
}
if (expectedIL != null)
{
var verifier = CompileAndVerify(comp, verify: useUnsafeContext ? Verification.Skipped : Verification.Passes);
verifier.VerifyIL("Program.Convert", expectedIL);
}
if (expectedIL != null)
{
var verifier = CompileAndVerify(comp, verify: useUnsafeContext ? Verification.Skipped : Verification.Passes);
verifier.VerifyIL("Program.Convert", expectedIL);
}
static bool useUnsafe(string underlyingType) => underlyingType == "void*";
static bool useUnsafe(string type) => type == "void*";
}
}
// PROTOTYPE:Test pre- and postfix increment and decrement. See UnopEasyOut.s_increment.
// PROTOTYPE: Test unary operator- with `static IntPtr operator-(IntPtr)` defined on System.IntPtr. (Should be ignored for `nint`.)
[Fact]
......@@ -1694,7 +2376,7 @@ void unaryOp(string op, string opType, string expectedSymbol = null, string oper
diagnostic = Diagnostic(ErrorCode.ERR_BadUnaryOp, $"{op}operand").WithArguments(op, opType);
}
UnaryOperator(op, opType, opType, expectedSymbol, operand, expectedResult, expectedIL, diagnostic != null ? new[] { diagnostic } : Array.Empty<DiagnosticDescription>());
unaryOperator(op, opType, opType, expectedSymbol, operand, expectedResult, expectedIL, diagnostic != null ? new[] { diagnostic } : Array.Empty<DiagnosticDescription>());
}
unaryOp("+", "nint", "nint nint.op_UnaryPlus(nint value)", "3", "3",
......@@ -1711,8 +2393,8 @@ .maxstack 1
IL_0000: ldarg.0
IL_0001: ret
}");
unaryOp("+", "System.IntPtr");
unaryOp("+", "System.UIntPtr");
//unaryOp("+", "System.IntPtr"); // PROTOTYPE: Not handled.
//unaryOp("+", "System.UIntPtr"); // PROTOTYPE: Not handled.
unaryOp("-", "nint", "nint nint.op_UnaryNegation(nint value)", "3", "-3",
@"{
// Code size 3 (0x3)
......@@ -1722,7 +2404,7 @@ .maxstack 1
IL_0002: ret
}");
unaryOp("-", "nuint", null, null, null, null, Diagnostic(ErrorCode.ERR_AmbigUnaryOp, "-operand").WithArguments("-", "nuint")); // PROTOTYPE: Should report ERR_BadUnaryOp.
unaryOp("-", "System.IntPtr");
//unaryOp("-", "System.IntPtr"); // PROTOTYPE: Not handled.
unaryOp("-", "System.UIntPtr");
unaryOp("!", "nint");
unaryOp("!", "nuint");
......@@ -1744,8 +2426,8 @@ .maxstack 1
IL_0001: not
IL_0002: ret
}");
unaryOp("~", "System.IntPtr");
unaryOp("~", "System.UIntPtr");
//unaryOp("~", "System.IntPtr"); // PROTOTYPE: Not handled.
//unaryOp("~", "System.UIntPtr"); // PROTOTYPE: Not handled.
unaryOp("+", "nint?", "nint nint.op_UnaryPlus(nint value)", "3", "3",
@"{
......@@ -1787,8 +2469,8 @@ .maxstack 1
IL_001c: newobj ""nuint?..ctor(nuint)""
IL_0021: ret
}");
unaryOp("+", "System.IntPtr?");
unaryOp("+", "System.UIntPtr?");
//unaryOp("+", "System.IntPtr?"); // PROTOTYPE: Not handled.
//unaryOp("+", "System.UIntPtr?"); // PROTOTYPE: Not handled.
unaryOp("-", "nint?", "nint nint.op_UnaryNegation(nint value)", "3", "-3",
@"{
// Code size 35 (0x23)
......@@ -1811,7 +2493,7 @@ .maxstack 1
IL_0022: ret
}");
unaryOp("-", "nuint?", null, null, null, null, Diagnostic(ErrorCode.ERR_AmbigUnaryOp, "-operand").WithArguments("-", "nuint?")); // PROTOTYPE: Should report ERR_BadUnaryOp.
unaryOp("-", "System.IntPtr?");
//unaryOp("-", "System.IntPtr?"); // PROTOTYPE: Not handled.
unaryOp("-", "System.UIntPtr?");
unaryOp("!", "nint?");
unaryOp("!", "nuint?");
......@@ -1859,14 +2541,13 @@ .maxstack 1
IL_001d: newobj ""nuint?..ctor(nuint)""
IL_0022: ret
}");
unaryOp("~", "System.IntPtr?");
unaryOp("~", "System.UIntPtr?");
}
//unaryOp("~", "System.IntPtr?"); // PROTOTYPE: Not handled.
//unaryOp("~", "System.UIntPtr?"); // PROTOTYPE: Not handled.
private void UnaryOperator(string op, string opType, string resultType, string expectedSymbol, string operand, string expectedResult, string expectedIL, DiagnosticDescription[] expectedDiagnostics)
{
string source =
$@"class Program
void unaryOperator(string op, string opType, string resultType, string expectedSymbol, string operand, string expectedResult, string expectedIL, DiagnosticDescription[] expectedDiagnostics)
{
string source =
$@"class Program
{{
static {resultType} Evaluate({opType} operand)
{{
......@@ -1877,97 +2558,1471 @@ static void Main()
System.Console.WriteLine(Evaluate({operand}));
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<PrefixUnaryExpressionSyntax>().Single();
var symbolInfo = model.GetSymbolInfo(expr);
Assert.Equal(expectedSymbol, symbolInfo.Symbol?.ToDisplayString(SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<PrefixUnaryExpressionSyntax>().Single();
var symbolInfo = model.GetSymbolInfo(expr);
Assert.Equal(expectedSymbol, symbolInfo.Symbol?.ToDisplayString(SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)));
if (expectedDiagnostics.Length == 0)
{
var verifier = CompileAndVerify(comp, expectedOutput: expectedResult);
verifier.VerifyIL("Program.Evaluate", expectedIL);
if (expectedDiagnostics.Length == 0)
{
var verifier = CompileAndVerify(comp, expectedOutput: expectedResult);
verifier.VerifyIL("Program.Evaluate", expectedIL);
}
}
}
[Fact]
public void BinaryOperators()
public void IncrementOperators()
{
void binaryOps(string op, string leftType, string rightType, string expectedSymbol1 = null, string expectedSymbol2 = "", DiagnosticDescription[] diagnostics1 = null, DiagnosticDescription[] diagnostics2 = null)
void incrementOps(string op, string opType, string expectedSymbol = null, bool useChecked = false, string values = null, string expectedResult = null, string expectedIL = "", string expectedLiftedIL = "", DiagnosticDescription diagnostic = null)
{
binaryOp(op, leftType, rightType, expectedSymbol1, diagnostics1);
binaryOp(op, rightType, leftType, expectedSymbol2 == "" ? expectedSymbol1 : expectedSymbol2, diagnostics2 ?? diagnostics1);
}
incrementOperator(op, opType, isPrefix: true, expectedSymbol, useChecked, values, expectedResult, expectedIL, getDiagnostics(opType, isPrefix: true, diagnostic));
incrementOperator(op, opType, isPrefix: false, expectedSymbol, useChecked, values, expectedResult, expectedIL, getDiagnostics(opType, isPrefix: false, diagnostic));
opType += "?";
incrementOperator(op, opType, isPrefix: true, expectedSymbol, useChecked, values, expectedResult, expectedLiftedIL, getDiagnostics(opType, isPrefix: true, diagnostic));
incrementOperator(op, opType, isPrefix: false, expectedSymbol, useChecked, values, expectedResult, expectedLiftedIL, getDiagnostics(opType, isPrefix: false, diagnostic));
void binaryOp(string op, string leftType, string rightType, string expectedSymbol, DiagnosticDescription[] diagnostics)
{
if (expectedSymbol == null && diagnostics == null)
DiagnosticDescription[] getDiagnostics(string opType, bool isPrefix, DiagnosticDescription diagnostic)
{
diagnostics = new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {op} y").WithArguments(op, leftType, rightType) };
if (expectedSymbol == null && diagnostic == null)
{
diagnostic = Diagnostic(ErrorCode.ERR_BadUnaryOp, isPrefix ? op + "operand" : "operand" + op).WithArguments(op, opType);
}
return diagnostic != null ? new[] { diagnostic } : Array.Empty<DiagnosticDescription>();
}
BinaryOperator(op, leftType, rightType, expectedSymbol, diagnostics ?? Array.Empty<DiagnosticDescription>());
}
var arithmeticOperators = new[]
{
("-", "op_Subtraction"),
("*", "op_Multiply"),
("/", "op_Division"),
("%", "op_Modulus"),
};
var additionOperators = new[]
{
("+", "op_Addition"),
};
var comparisonOperators = new[]
{
("<", "op_LessThan"),
("<=", "op_LessThanOrEqual"),
(">", "op_GreaterThan"),
(">=", "op_GreaterThanOrEqual"),
};
var shiftOperators = new[]
{
("<<", "op_LeftShift"),
(">>", "op_RightShift"),
};
var equalityOperators = new[]
{
("==", "op_Equality"),
("!=", "op_Inequality"),
};
var logicalOperators = new[]
{
("&", "op_BitwiseAnd"),
("|", "op_BitwiseOr"),
("^", "op_ExclusiveOr"),
};
foreach ((string symbol, string name) in arithmeticOperators)
{
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint", "string");
// PROTOTYPE: Test all:
if (symbol == "*") binaryOps(symbol, "nint", "void*", null, null, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "nint", "void*"), Diagnostic(ErrorCode.ERR_VoidError, $"x {symbol} y") }, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "void*", "nint"), Diagnostic(ErrorCode.ERR_VoidError, $"x {symbol} y") });
binaryOps(symbol, "nint", "bool");
binaryOps(symbol, "nint", "char", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "sbyte", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "byte", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "short", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "ushort", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "int", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "uint", $"long long.{name}(long left, long right)");
binaryOps(symbol, "nint", "nint", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "nuint", null, null, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "nint", "nuint") }, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "nuint", "nint") });
binaryOps(symbol, "nint", "long", $"long long.{name}(long left, long right)");
binaryOps(symbol, "nint", "ulong", null, null, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "nint", "ulong") }, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "ulong", "nint") });
binaryOps(symbol, "nint", "float", $"float float.{name}(float left, float right)");
incrementOps("++", "nint", "nint nint.op_Increment(nint value)", useChecked: false,
values: $"{int.MinValue}, -1, 0, {int.MaxValue - 1}, {int.MaxValue}",
expectedResult: $"-2147483647, 0, 1, 2147483647, {(IntPtr.Size == 4 ? "-2147483648" : "2147483648")}",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: add
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nint nint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: add
IL_001f: newobj ""nint?..ctor(nint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
incrementOps("++", "nuint", "nuint nuint.op_Increment(nuint value)", useChecked: false,
values: $"0, {int.MaxValue}, {uint.MaxValue - 1}, {uint.MaxValue}",
expectedResult: $"1, 2147483648, 4294967295, {(IntPtr.Size == 4 ? "0" : "4294967296")}",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: add
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nuint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nuint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nuint nuint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: add
IL_001f: newobj ""nuint?..ctor(nuint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
//incrementOps("++", "System.IntPtr"); // PROTOTYPE: Not handled.
//incrementOps("++", "System.UIntPtr"); // PROTOTYPE: Not handled.
incrementOps("--", "nint", "nint nint.op_Decrement(nint value)", useChecked: false,
values: $"{int.MinValue}, {int.MinValue + 1}, 0, 1, {int.MaxValue}",
expectedResult: $"{(IntPtr.Size == 4 ? "2147483647" : "-2147483649")}, -2147483648, -1, 0, 2147483646",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: sub
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nint nint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: sub
IL_001f: newobj ""nint?..ctor(nint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
incrementOps("--", "nuint", "nuint nuint.op_Decrement(nuint value)", useChecked: false,
values: $"0, 1, {uint.MaxValue}",
expectedResult: $"{(IntPtr.Size == 4 ? uint.MaxValue.ToString() : ulong.MaxValue.ToString())}, 0, 4294967294",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: sub
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nuint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nuint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nuint nuint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: sub
IL_001f: newobj ""nuint?..ctor(nuint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
//incrementOps("--", "System.IntPtr"); // PROTOTYPE: Not handled.
//incrementOps("--", "System.UIntPtr"); // PROTOTYPE: Not handled.
incrementOps("++", "nint", "nint nint.op_Increment(nint value)", useChecked: true,
values: $"{int.MinValue}, -1, 0, {int.MaxValue - 1}, {int.MaxValue}",
expectedResult: $"-2147483647, 0, 1, 2147483647, {(IntPtr.Size == 4 ? "System.OverflowException" : "2147483648")}",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: add.ovf
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nint nint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: add.ovf
IL_001f: newobj ""nint?..ctor(nint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
incrementOps("++", "nuint", "nuint nuint.op_Increment(nuint value)", useChecked: true,
values: $"0, {int.MaxValue}, {uint.MaxValue - 1}, {uint.MaxValue}",
expectedResult: $"1, 2147483648, 4294967295, {(IntPtr.Size == 4 ? "System.OverflowException" : "4294967296")}",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: add.ovf.un
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nuint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nuint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nuint nuint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: add.ovf.un
IL_001f: newobj ""nuint?..ctor(nuint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
incrementOps("--", "nint", "nint nint.op_Decrement(nint value)", useChecked: true,
values: $"{int.MinValue}, {int.MinValue + 1}, 0, 1, {int.MaxValue}",
expectedResult: $"{(IntPtr.Size == 4 ? "System.OverflowException" : "-2147483649")}, -2147483648, -1, 0, 2147483646",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: sub.ovf
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nint nint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: sub.ovf
IL_001f: newobj ""nint?..ctor(nint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
incrementOps("--", "nuint", "nuint nuint.op_Decrement(nuint value)", useChecked: true,
values: $"0, 1, {uint.MaxValue}",
expectedResult: $"System.OverflowException, 0, 4294967294",
@"{
// Code size 7 (0x7)
.maxstack 2
IL_0000: ldarg.0
IL_0001: ldc.i4.1
IL_0002: sub.ovf.un
IL_0003: starg.s V_0
IL_0005: ldarg.0
IL_0006: ret
}",
@"{
// Code size 40 (0x28)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: stloc.0
IL_0002: ldloca.s V_0
IL_0004: call ""bool nuint?.HasValue.get""
IL_0009: brtrue.s IL_0016
IL_000b: ldloca.s V_1
IL_000d: initobj ""nuint?""
IL_0013: ldloc.1
IL_0014: br.s IL_0024
IL_0016: ldloca.s V_0
IL_0018: call ""nuint nuint?.GetValueOrDefault()""
IL_001d: ldc.i4.1
IL_001e: sub.ovf.un
IL_001f: newobj ""nuint?..ctor(nuint)""
IL_0024: starg.s V_0
IL_0026: ldarg.0
IL_0027: ret
}");
void incrementOperator(string op, string opType, bool isPrefix, string expectedSymbol, bool useChecked, string values, string expectedResult, string expectedIL, DiagnosticDescription[] expectedDiagnostics)
{
var source =
$@"using System;
class Program
{{
static {opType} Evaluate({opType} operand)
{{
{(useChecked ? "checked" : "unchecked")}
{{
{(isPrefix ? op + "operand" : "operand" + op)};
return operand;
}}
}}
static void EvaluateAndReport({opType} operand)
{{
object result;
try
{{
result = Evaluate(operand);
}}
catch (Exception e)
{{
result = e.GetType();
}}
Console.Write(result);
}}
static void Main()
{{
bool separator = false;
foreach (var value in new {opType}[] {{ {values} }})
{{
if (separator) Console.Write("", "");
separator = true;
EvaluateAndReport(value);
}}
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var kind = (op == "++") ?
isPrefix ? SyntaxKind.PreIncrementExpression : SyntaxKind.PostIncrementExpression :
isPrefix ? SyntaxKind.PreDecrementExpression : SyntaxKind.PostDecrementExpression;
var expr = tree.GetRoot().DescendantNodes().Single(n => n.Kind() == kind);
var symbolInfo = model.GetSymbolInfo(expr);
Assert.Equal(expectedSymbol, symbolInfo.Symbol?.ToDisplayString(SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)));
if (expectedDiagnostics.Length == 0)
{
var verifier = CompileAndVerify(comp, expectedOutput: expectedResult);
verifier.VerifyIL("Program.Evaluate", expectedIL);
}
}
}
[Fact]
public void IncrementOperators_RefOperand()
{
void incrementOps(string op, string opType, string expectedSymbol = null, string values = null, string expectedResult = null, string expectedIL = "", string expectedLiftedIL = "", DiagnosticDescription diagnostic = null)
{
incrementOperator(op, opType, expectedSymbol, values, expectedResult, expectedIL, getDiagnostics(opType, diagnostic));
opType += "?";
incrementOperator(op, opType, expectedSymbol, values, expectedResult, expectedLiftedIL, getDiagnostics(opType, diagnostic));
DiagnosticDescription[] getDiagnostics(string opType, DiagnosticDescription diagnostic)
{
if (expectedSymbol == null && diagnostic == null)
{
diagnostic = Diagnostic(ErrorCode.ERR_BadUnaryOp, op + "operand").WithArguments(op, opType);
}
return diagnostic != null ? new[] { diagnostic } : Array.Empty<DiagnosticDescription>();
}
}
incrementOps("++", "nint", "nint nint.op_Increment(nint value)",
values: $"{int.MinValue}, -1, 0, {int.MaxValue - 1}, {int.MaxValue}",
expectedResult: $"-2147483647, 0, 1, 2147483647, {(IntPtr.Size == 4 ? "-2147483648" : "2147483648")}",
@"{
// Code size 7 (0x7)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldind.i
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stind.i
IL_0006: ret
}",
@"{
// Code size 48 (0x30)
.maxstack 3
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldobj ""nint?""
IL_0007: stloc.0
IL_0008: ldloca.s V_0
IL_000a: call ""bool nint?.HasValue.get""
IL_000f: brtrue.s IL_001c
IL_0011: ldloca.s V_1
IL_0013: initobj ""nint?""
IL_0019: ldloc.1
IL_001a: br.s IL_002a
IL_001c: ldloca.s V_0
IL_001e: call ""nint nint?.GetValueOrDefault()""
IL_0023: ldc.i4.1
IL_0024: add
IL_0025: newobj ""nint?..ctor(nint)""
IL_002a: stobj ""nint?""
IL_002f: ret
}");
incrementOps("++", "nuint", "nuint nuint.op_Increment(nuint value)",
values: $"0, {int.MaxValue}, {uint.MaxValue - 1}, {uint.MaxValue}",
expectedResult: $"1, 2147483648, 4294967295, {(IntPtr.Size == 4 ? "0" : "4294967296")}",
@"{
// Code size 7 (0x7)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldind.i
IL_0003: ldc.i4.1
IL_0004: add
IL_0005: stind.i
IL_0006: ret
}",
@"{
// Code size 48 (0x30)
.maxstack 3
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldobj ""nuint?""
IL_0007: stloc.0
IL_0008: ldloca.s V_0
IL_000a: call ""bool nuint?.HasValue.get""
IL_000f: brtrue.s IL_001c
IL_0011: ldloca.s V_1
IL_0013: initobj ""nuint?""
IL_0019: ldloc.1
IL_001a: br.s IL_002a
IL_001c: ldloca.s V_0
IL_001e: call ""nuint nuint?.GetValueOrDefault()""
IL_0023: ldc.i4.1
IL_0024: add
IL_0025: newobj ""nuint?..ctor(nuint)""
IL_002a: stobj ""nuint?""
IL_002f: ret
}");
incrementOps("--", "nint", "nint nint.op_Decrement(nint value)",
values: $"{int.MinValue}, {int.MinValue + 1}, 0, 1, {int.MaxValue}",
expectedResult: $"{(IntPtr.Size == 4 ? "2147483647" : "-2147483649")}, -2147483648, -1, 0, 2147483646",
@"{
// Code size 7 (0x7)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldind.i
IL_0003: ldc.i4.1
IL_0004: sub
IL_0005: stind.i
IL_0006: ret
}",
@"{
// Code size 48 (0x30)
.maxstack 3
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldobj ""nint?""
IL_0007: stloc.0
IL_0008: ldloca.s V_0
IL_000a: call ""bool nint?.HasValue.get""
IL_000f: brtrue.s IL_001c
IL_0011: ldloca.s V_1
IL_0013: initobj ""nint?""
IL_0019: ldloc.1
IL_001a: br.s IL_002a
IL_001c: ldloca.s V_0
IL_001e: call ""nint nint?.GetValueOrDefault()""
IL_0023: ldc.i4.1
IL_0024: sub
IL_0025: newobj ""nint?..ctor(nint)""
IL_002a: stobj ""nint?""
IL_002f: ret
}");
incrementOps("--", "nuint", "nuint nuint.op_Decrement(nuint value)",
values: $"0, 1, {uint.MaxValue}",
expectedResult: $"{(IntPtr.Size == 4 ? uint.MaxValue.ToString() : ulong.MaxValue.ToString())}, 0, 4294967294",
@"{
// Code size 7 (0x7)
.maxstack 3
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldind.i
IL_0003: ldc.i4.1
IL_0004: sub
IL_0005: stind.i
IL_0006: ret
}",
@"{
// Code size 48 (0x30)
.maxstack 3
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: ldarg.0
IL_0002: ldobj ""nuint?""
IL_0007: stloc.0
IL_0008: ldloca.s V_0
IL_000a: call ""bool nuint?.HasValue.get""
IL_000f: brtrue.s IL_001c
IL_0011: ldloca.s V_1
IL_0013: initobj ""nuint?""
IL_0019: ldloc.1
IL_001a: br.s IL_002a
IL_001c: ldloca.s V_0
IL_001e: call ""nuint nuint?.GetValueOrDefault()""
IL_0023: ldc.i4.1
IL_0024: sub
IL_0025: newobj ""nuint?..ctor(nuint)""
IL_002a: stobj ""nuint?""
IL_002f: ret
}");
void incrementOperator(string op, string opType, string expectedSymbol, string values, string expectedResult, string expectedIL, DiagnosticDescription[] expectedDiagnostics)
{
string source =
$@"using System;
class Program
{{
static void Evaluate(ref {opType} operand)
{{
{op}operand;
}}
static void EvaluateAndReport({opType} operand)
{{
object result;
try
{{
Evaluate(ref operand);
result = operand;
}}
catch (Exception e)
{{
result = e.GetType();
}}
Console.Write(result);
}}
static void Main()
{{
bool separator = false;
foreach (var value in new {opType}[] {{ {values} }})
{{
if (separator) Console.Write("", "");
separator = true;
EvaluateAndReport(value);
}}
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var kind = (op == "++") ? SyntaxKind.PreIncrementExpression : SyntaxKind.PreDecrementExpression;
var expr = tree.GetRoot().DescendantNodes().Single(n => n.Kind() == kind);
var symbolInfo = model.GetSymbolInfo(expr);
Assert.Equal(expectedSymbol, symbolInfo.Symbol?.ToDisplayString(SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)));
if (expectedDiagnostics.Length == 0)
{
var verifier = CompileAndVerify(comp, expectedOutput: expectedResult);
verifier.VerifyIL("Program.Evaluate", expectedIL);
}
}
}
[Fact]
public void UnaryOperators_UserDefinedConversions_NInt()
{
// PROTOTYPE: Declare _i readonly. See ReadOnlyField_VirtualMethods().
string source =
@"using System;
class MyInt
{
private nint _i;
internal MyInt(nint i) => _i = i;
public static implicit operator nint(MyInt i) => i._i;
public static implicit operator MyInt(nint i) => new MyInt(i);
public override string ToString() => _i.ToString();
}
class Program
{
static void Main()
{
// ++i;
Evaluate(int.MinValue, PrefixIncrement);
Evaluate(-1, PrefixIncrement);
Evaluate(0, PrefixIncrement);
// i++;
Evaluate(int.MinValue, PostfixIncrement);
Evaluate(-1, PostfixIncrement);
Evaluate(0, PostfixIncrement);
// --i;
Evaluate(int.MaxValue, PrefixDecrement);
Evaluate(1, PrefixDecrement);
Evaluate(0, PrefixDecrement);
// i--;
Evaluate(int.MaxValue, PostfixDecrement);
Evaluate(1, PostfixDecrement);
Evaluate(0, PostfixDecrement);
// +i;
Evaluate(int.MinValue, Plus);
Evaluate(0, Plus);
Evaluate(int.MaxValue, Plus);
// -i;
Evaluate(int.MinValue, Minus);
Evaluate(0, Minus);
Evaluate(int.MaxValue, Minus);
// ~i;
Evaluate(int.MinValue, Complement);
Evaluate(0, Complement);
Evaluate(int.MaxValue, Complement);
}
static void Evaluate(nint i, Func<MyInt, MyInt> f)
{
MyInt m = f(new MyInt(i));
Console.WriteLine(m);
}
static MyInt PrefixIncrement(MyInt i) => ++i;
static MyInt PostfixIncrement(MyInt i) { i++; return i; }
static MyInt PrefixDecrement(MyInt i) => --i;
static MyInt PostfixDecrement(MyInt i) { i--; return i; }
static MyInt Plus(MyInt i) => +i;
static MyInt Minus(MyInt i) => -i;
static MyInt Complement(MyInt i) => ~i;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
string expectedOutput =
$@"-2147483647
0
1
-2147483647
0
1
2147483646
0
-1
2147483646
0
-1
-2147483648
0
2147483647
{(IntPtr.Size == 4 ? "-2147483648" : "2147483648")}
0
-2147483647
2147483647
-1
-2147483648";
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
verifier.VerifyIL("Program.PrefixIncrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: add
IL_0008: call ""MyInt MyInt.op_Implicit(nint)""
IL_000d: dup
IL_000e: starg.s V_0
IL_0010: ret
}");
verifier.VerifyIL("Program.PostfixIncrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: add
IL_0008: call ""MyInt MyInt.op_Implicit(nint)""
IL_000d: starg.s V_0
IL_000f: ldarg.0
IL_0010: ret
}");
verifier.VerifyIL("Program.PrefixDecrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: call ""MyInt MyInt.op_Implicit(nint)""
IL_000d: dup
IL_000e: starg.s V_0
IL_0010: ret
}");
verifier.VerifyIL("Program.PostfixDecrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: call ""MyInt MyInt.op_Implicit(nint)""
IL_000d: starg.s V_0
IL_000f: ldarg.0
IL_0010: ret
}");
verifier.VerifyIL("Program.Plus",
@"{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: call ""MyInt MyInt.op_Implicit(nint)""
IL_000b: ret
}");
verifier.VerifyIL("Program.Minus",
@"{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: neg
IL_0007: call ""MyInt MyInt.op_Implicit(nint)""
IL_000c: ret
}");
verifier.VerifyIL("Program.Complement",
@"{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""nint MyInt.op_Implicit(MyInt)""
IL_0006: not
IL_0007: call ""MyInt MyInt.op_Implicit(nint)""
IL_000c: ret
}");
}
[Fact]
public void UnaryOperators_UserDefinedConversions_NUInt()
{
// PROTOTYPE: Declare _i readonly. See ReadOnlyField_VirtualMethods().
string source =
@"using System;
class MyInt
{
private nuint _i;
internal MyInt(nuint i) => _i = i;
public static implicit operator nuint(MyInt i) => i._i;
public static implicit operator MyInt(nuint i) => new MyInt(i);
public override string ToString() => _i.ToString();
}
class Program
{
static void Main()
{
// ++i;
Evaluate(0, PrefixIncrement);
Evaluate(uint.MaxValue - 1, PrefixIncrement);
// i++;
Evaluate(0, PostfixIncrement);
Evaluate(uint.MaxValue - 1, PostfixIncrement);
// --i;
Evaluate(1, PrefixDecrement);
Evaluate(uint.MaxValue, PrefixDecrement);
// i--;
Evaluate(1, PostfixDecrement);
Evaluate(uint.MaxValue, PostfixDecrement);
// +i;
Evaluate(0, Plus);
Evaluate(uint.MaxValue, Plus);
// ~i;
Evaluate(0, Complement);
Evaluate(uint.MaxValue, Complement);
}
static void Evaluate(nuint i, Func<MyInt, MyInt> f)
{
MyInt m = f(new MyInt(i));
Console.WriteLine(m);
}
static MyInt PrefixIncrement(MyInt i) => ++i;
static MyInt PostfixIncrement(MyInt i) { i++; return i; }
static MyInt PrefixDecrement(MyInt i) => --i;
static MyInt PostfixDecrement(MyInt i) { i--; return i; }
static MyInt Plus(MyInt i) => +i;
static MyInt Complement(MyInt i) => ~i;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
string expectedOutput =
$@"1
4294967295
1
4294967295
0
4294967294
0
4294967294
0
4294967295
{(IntPtr.Size == 4 ? "4294967295" : "18446744073709551615")}
{(IntPtr.Size == 4 ? "0" : "18446744069414584320")}";
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
verifier.VerifyIL("Program.PrefixIncrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nuint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: add
IL_0008: call ""MyInt MyInt.op_Implicit(nuint)""
IL_000d: dup
IL_000e: starg.s V_0
IL_0010: ret
}");
verifier.VerifyIL("Program.PostfixIncrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nuint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: add
IL_0008: call ""MyInt MyInt.op_Implicit(nuint)""
IL_000d: starg.s V_0
IL_000f: ldarg.0
IL_0010: ret
}");
verifier.VerifyIL("Program.PrefixDecrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nuint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: call ""MyInt MyInt.op_Implicit(nuint)""
IL_000d: dup
IL_000e: starg.s V_0
IL_0010: ret
}");
verifier.VerifyIL("Program.PostfixDecrement",
@"{
// Code size 17 (0x11)
.maxstack 2
IL_0000: ldarg.0
IL_0001: call ""nuint MyInt.op_Implicit(MyInt)""
IL_0006: ldc.i4.1
IL_0007: sub
IL_0008: call ""MyInt MyInt.op_Implicit(nuint)""
IL_000d: starg.s V_0
IL_000f: ldarg.0
IL_0010: ret
}");
verifier.VerifyIL("Program.Plus",
@"{
// Code size 12 (0xc)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""nuint MyInt.op_Implicit(MyInt)""
IL_0006: call ""MyInt MyInt.op_Implicit(nuint)""
IL_000b: ret
}");
verifier.VerifyIL("Program.Complement",
@"{
// Code size 13 (0xd)
.maxstack 1
IL_0000: ldarg.0
IL_0001: call ""nuint MyInt.op_Implicit(MyInt)""
IL_0006: not
IL_0007: call ""MyInt MyInt.op_Implicit(nuint)""
IL_000c: ret
}");
}
[Fact]
public void UnaryOperators_UserDefinedConversions_LiftedNInt()
{
string source =
@"using System;
class MyInt
{
private readonly nint? _i;
internal MyInt(nint? i) => _i = i;
public static implicit operator nint?(MyInt i) => i._i;
public static implicit operator MyInt(nint? i) => new MyInt(i);
public override string ToString() => _i.ToString();
}
class Program
{
static void Main()
{
// ++i;
Evaluate(int.MinValue, PrefixIncrement);
Evaluate(-1, PrefixIncrement);
Evaluate(0, PrefixIncrement);
// i++;
Evaluate(int.MinValue, PostfixIncrement);
Evaluate(-1, PostfixIncrement);
Evaluate(0, PostfixIncrement);
// --i;
Evaluate(int.MaxValue, PrefixDecrement);
Evaluate(1, PrefixDecrement);
Evaluate(0, PrefixDecrement);
// i--;
Evaluate(int.MaxValue, PostfixDecrement);
Evaluate(1, PostfixDecrement);
Evaluate(0, PostfixDecrement);
// +i;
Evaluate(int.MinValue, Plus);
Evaluate(0, Plus);
Evaluate(int.MaxValue, Plus);
// -i;
Evaluate(int.MinValue, Minus);
Evaluate(0, Minus);
Evaluate(int.MaxValue, Minus);
// ~i;
Evaluate(int.MinValue, Complement);
Evaluate(0, Complement);
Evaluate(int.MaxValue, Complement);
}
static void Evaluate(nint i, Func<MyInt, MyInt> f)
{
MyInt m = f(new MyInt(i));
Console.WriteLine(m);
}
static MyInt PrefixIncrement(MyInt i) => ++i;
static MyInt PostfixIncrement(MyInt i) { i++; return i; }
static MyInt PrefixDecrement(MyInt i) => --i;
static MyInt PostfixDecrement(MyInt i) { i--; return i; }
static MyInt Plus(MyInt i) => +i;
static MyInt Minus(MyInt i) => -i;
static MyInt Complement(MyInt i) => ~i;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
string expectedOutput =
$@"-2147483647
0
1
-2147483647
0
1
2147483646
0
-1
2147483646
0
-1
-2147483648
0
2147483647
{(IntPtr.Size == 4 ? "-2147483648" : "2147483648")}
0
-2147483647
2147483647
-1
-2147483648";
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
verifier.VerifyIL("Program.PrefixIncrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: add
IL_0024: newobj ""nint?..ctor(nint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002e: dup
IL_002f: starg.s V_0
IL_0031: ret
}");
verifier.VerifyIL("Program.PostfixIncrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: add
IL_0024: newobj ""nint?..ctor(nint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002e: starg.s V_0
IL_0030: ldarg.0
IL_0031: ret
}");
verifier.VerifyIL("Program.PrefixDecrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: sub
IL_0024: newobj ""nint?..ctor(nint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002e: dup
IL_002f: starg.s V_0
IL_0031: ret
}");
verifier.VerifyIL("Program.PostfixDecrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: sub
IL_0024: newobj ""nint?..ctor(nint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002e: starg.s V_0
IL_0030: ldarg.0
IL_0031: ret
}");
verifier.VerifyIL("Program.Plus",
@"{
// Code size 45 (0x2d)
.maxstack 1
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0027
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: newobj ""nint?..ctor(nint)""
IL_0027: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002c: ret
}");
verifier.VerifyIL("Program.Minus",
@"{
// Code size 46 (0x2e)
.maxstack 1
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0028
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: neg
IL_0023: newobj ""nint?..ctor(nint)""
IL_0028: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002d: ret
}");
verifier.VerifyIL("Program.Complement",
@"{
// Code size 46 (0x2e)
.maxstack 1
.locals init (nint? V_0,
nint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0028
IL_001b: ldloca.s V_0
IL_001d: call ""nint nint?.GetValueOrDefault()""
IL_0022: not
IL_0023: newobj ""nint?..ctor(nint)""
IL_0028: call ""MyInt MyInt.op_Implicit(nint?)""
IL_002d: ret
}");
}
[Fact]
public void UnaryOperators_UserDefinedConversions_LiftedNUInt()
{
string source =
@"using System;
class MyInt
{
private readonly nuint? _i;
internal MyInt(nuint? i) => _i = i;
public static implicit operator nuint?(MyInt i) => i._i;
public static implicit operator MyInt(nuint? i) => new MyInt(i);
public override string ToString() => _i.ToString();
}
class Program
{
static void Main()
{
// ++i;
Evaluate(0, PrefixIncrement);
Evaluate(uint.MaxValue - 1, PrefixIncrement);
// i++;
Evaluate(0, PostfixIncrement);
Evaluate(uint.MaxValue - 1, PostfixIncrement);
// --i;
Evaluate(1, PrefixDecrement);
Evaluate(uint.MaxValue, PrefixDecrement);
// i--;
Evaluate(1, PostfixDecrement);
Evaluate(uint.MaxValue, PostfixDecrement);
// +i;
Evaluate(0, Plus);
Evaluate(uint.MaxValue, Plus);
// ~i;
Evaluate(0, Complement);
Evaluate(uint.MaxValue, Complement);
}
static void Evaluate(nuint i, Func<MyInt, MyInt> f)
{
MyInt m = f(new MyInt(i));
Console.WriteLine(m);
}
static MyInt PrefixIncrement(MyInt i) => ++i;
static MyInt PostfixIncrement(MyInt i) { i++; return i; }
static MyInt PrefixDecrement(MyInt i) => --i;
static MyInt PostfixDecrement(MyInt i) { i--; return i; }
static MyInt Plus(MyInt i) => +i;
static MyInt Complement(MyInt i) => ~i;
}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview);
string expectedOutput =
$@"1
4294967295
1
4294967295
0
4294967294
0
4294967294
0
4294967295
{(IntPtr.Size == 4 ? "4294967295" : "18446744073709551615")}
{(IntPtr.Size == 4 ? "0" : "18446744069414584320")}";
var verifier = CompileAndVerify(comp, expectedOutput: expectedOutput);
verifier.VerifyIL("Program.PrefixIncrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nuint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nuint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nuint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nuint nuint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: add
IL_0024: newobj ""nuint?..ctor(nuint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nuint?)""
IL_002e: dup
IL_002f: starg.s V_0
IL_0031: ret
}");
verifier.VerifyIL("Program.PostfixIncrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nuint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nuint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nuint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nuint nuint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: add
IL_0024: newobj ""nuint?..ctor(nuint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nuint?)""
IL_002e: starg.s V_0
IL_0030: ldarg.0
IL_0031: ret
}");
verifier.VerifyIL("Program.PrefixDecrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nuint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nuint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nuint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nuint nuint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: sub
IL_0024: newobj ""nuint?..ctor(nuint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nuint?)""
IL_002e: dup
IL_002f: starg.s V_0
IL_0031: ret
}");
verifier.VerifyIL("Program.PostfixDecrement",
@"{
// Code size 50 (0x32)
.maxstack 2
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nuint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nuint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nuint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0029
IL_001b: ldloca.s V_0
IL_001d: call ""nuint nuint?.GetValueOrDefault()""
IL_0022: ldc.i4.1
IL_0023: sub
IL_0024: newobj ""nuint?..ctor(nuint)""
IL_0029: call ""MyInt MyInt.op_Implicit(nuint?)""
IL_002e: starg.s V_0
IL_0030: ldarg.0
IL_0031: ret
}");
verifier.VerifyIL("Program.Plus",
@"{
// Code size 45 (0x2d)
.maxstack 1
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nuint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nuint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nuint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0027
IL_001b: ldloca.s V_0
IL_001d: call ""nuint nuint?.GetValueOrDefault()""
IL_0022: newobj ""nuint?..ctor(nuint)""
IL_0027: call ""MyInt MyInt.op_Implicit(nuint?)""
IL_002c: ret
}");
verifier.VerifyIL("Program.Complement",
@"{
// Code size 46 (0x2e)
.maxstack 1
.locals init (nuint? V_0,
nuint? V_1)
IL_0000: ldarg.0
IL_0001: call ""nuint? MyInt.op_Implicit(MyInt)""
IL_0006: stloc.0
IL_0007: ldloca.s V_0
IL_0009: call ""bool nuint?.HasValue.get""
IL_000e: brtrue.s IL_001b
IL_0010: ldloca.s V_1
IL_0012: initobj ""nuint?""
IL_0018: ldloc.1
IL_0019: br.s IL_0028
IL_001b: ldloca.s V_0
IL_001d: call ""nuint nuint?.GetValueOrDefault()""
IL_0022: not
IL_0023: newobj ""nuint?..ctor(nuint)""
IL_0028: call ""MyInt MyInt.op_Implicit(nuint?)""
IL_002d: ret
}");
}
[Fact]
public void BinaryOperators()
{
void binaryOps(string op, string leftType, string rightType, string expectedSymbol1 = null, string expectedSymbol2 = "", DiagnosticDescription[] diagnostics1 = null, DiagnosticDescription[] diagnostics2 = null)
{
binaryOp(op, leftType, rightType, expectedSymbol1, diagnostics1);
binaryOp(op, rightType, leftType, expectedSymbol2 == "" ? expectedSymbol1 : expectedSymbol2, diagnostics2 ?? diagnostics1);
}
void binaryOp(string op, string leftType, string rightType, string expectedSymbol, DiagnosticDescription[] diagnostics)
{
if (expectedSymbol == null && diagnostics == null)
{
diagnostics = new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {op} y").WithArguments(op, leftType, rightType) };
}
binaryOperator(op, leftType, rightType, expectedSymbol, diagnostics ?? Array.Empty<DiagnosticDescription>());
}
var arithmeticOperators = new[]
{
("-", "op_Subtraction"),
("*", "op_Multiply"),
("/", "op_Division"),
("%", "op_Modulus"),
};
var additionOperators = new[]
{
("+", "op_Addition"),
};
var comparisonOperators = new[]
{
("<", "op_LessThan"),
("<=", "op_LessThanOrEqual"),
(">", "op_GreaterThan"),
(">=", "op_GreaterThanOrEqual"),
};
var shiftOperators = new[]
{
("<<", "op_LeftShift"),
(">>", "op_RightShift"),
};
var equalityOperators = new[]
{
("==", "op_Equality"),
("!=", "op_Inequality"),
};
var logicalOperators = new[]
{
("&", "op_BitwiseAnd"),
("|", "op_BitwiseOr"),
("^", "op_ExclusiveOr"),
};
foreach ((string symbol, string name) in arithmeticOperators)
{
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint", "string");
// PROTOTYPE: Test all:
if (symbol == "*") binaryOps(symbol, "nint", "void*", null, null, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "nint", "void*"), Diagnostic(ErrorCode.ERR_VoidError, $"x {symbol} y") }, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "void*", "nint"), Diagnostic(ErrorCode.ERR_VoidError, $"x {symbol} y") });
binaryOps(symbol, "nint", "bool");
binaryOps(symbol, "nint", "char", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "sbyte", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "byte", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "short", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "ushort", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "int", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "uint", $"long long.{name}(long left, long right)");
binaryOps(symbol, "nint", "nint", $"nint nint.{name}(nint left, nint right)");
binaryOps(symbol, "nint", "nuint", null, null, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "nint", "nuint") }, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "nuint", "nint") });
binaryOps(symbol, "nint", "long", $"long long.{name}(long left, long right)");
binaryOps(symbol, "nint", "ulong", null, null, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "nint", "ulong") }, new[] { Diagnostic(ErrorCode.ERR_AmbigBinaryOps, $"x {symbol} y").WithArguments(symbol, "ulong", "nint") });
binaryOps(symbol, "nint", "float", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr");
binaryOps(symbol, "nint", "bool?");
binaryOps(symbol, "nint", "char?", $"nint nint.{name}(nint left, nint right)");
......@@ -1984,7 +4039,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float?", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr?");
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint?", "string");
......@@ -2005,7 +4060,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr");
binaryOps(symbol, "nint?", "bool?");
binaryOps(symbol, "nint?", "char?", $"nint nint.{name}(nint left, nint right)");
......@@ -2022,7 +4077,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float?", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr?");
binaryOps(symbol, "nuint", "object");
binaryOps(symbol, "nuint", "string");
......@@ -2044,7 +4099,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr");
//getArgs(builder, symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint", "bool?");
binaryOps(symbol, "nuint", "char?", $"nuint nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint", "sbyte?", $"nuint nuint.{name}(nuint left, nuint right)");
......@@ -2061,7 +4116,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr?");
//getArgs(builder, symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "object");
binaryOps(symbol, "nuint?", "string");
// PROTOTYPE: Test all:
......@@ -2082,7 +4137,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "bool?");
binaryOps(symbol, "nuint?", "char?", $"nuint nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint?", "sbyte?", $"nuint nuint.{name}(nuint left, nuint right)");
......@@ -2099,7 +4154,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr?");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
}
foreach ((string symbol, string name) in comparisonOperators)
......@@ -2122,7 +4177,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr");
binaryOps(symbol, "nint", "bool?");
binaryOps(symbol, "nint", "char?", $"bool nint.{name}(nint left, nint right)");
......@@ -2139,7 +4194,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float?", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr?");
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint?", "string");
......@@ -2159,7 +4214,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr");
binaryOps(symbol, "nint?", "bool?");
binaryOps(symbol, "nint?", "char?", $"bool nint.{name}(nint left, nint right)");
......@@ -2176,7 +4231,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float?", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr?");
binaryOps(symbol, "nuint", "object");
binaryOps(symbol, "nuint", "string");
......@@ -2197,7 +4252,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr");
//getArgs(builder, symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint", "bool?");
binaryOps(symbol, "nuint", "char?", $"bool nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint", "sbyte?", $"bool nuint.{name}(nuint left, nuint right)");
......@@ -2214,7 +4269,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr?");
//getArgs(builder, symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "object");
binaryOps(symbol, "nuint?", "string");
binaryOps(symbol, "nuint?", "void*", null, null, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "nuint?", "void*") }, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "void*", "nuint?") });
......@@ -2234,7 +4289,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "bool?");
binaryOps(symbol, "nuint?", "char?", $"bool nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint?", "sbyte?", $"bool nuint.{name}(nuint left, nuint right)");
......@@ -2251,7 +4306,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr?");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
}
foreach ((string symbol, string name) in additionOperators)
......@@ -2274,7 +4329,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr");
binaryOps(symbol, "nint", "bool?");
binaryOps(symbol, "nint", "char?", $"nint nint.{name}(nint left, nint right)");
......@@ -2291,7 +4346,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float?", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr?");
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint?", "string", $"string string.{name}(object left, string right)", $"string string.{name}(string left, object right)");
......@@ -2311,7 +4366,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr");
binaryOps(symbol, "nint?", "bool?");
binaryOps(symbol, "nint?", "char?", $"nint nint.{name}(nint left, nint right)");
......@@ -2328,7 +4383,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float?", $"float float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr?");
binaryOps(symbol, "nuint", "object");
binaryOps(symbol, "nuint", "string", $"string string.{name}(object left, string right)", $"string string.{name}(string left, object right)");
......@@ -2349,7 +4404,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr");
//getArgs(builder, symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint", "bool?");
binaryOps(symbol, "nuint", "char?", $"nuint nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint", "sbyte?", $"nuint nuint.{name}(nuint left, nuint right)");
......@@ -2366,7 +4421,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr?");
//getArgs(builder, symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "object");
binaryOps(symbol, "nuint?", "string", $"string string.{name}(object left, string right)", $"string string.{name}(string left, object right)");
binaryOps(symbol, "nuint?", "void*", null, null, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, "x + y").WithArguments(symbol, "nuint?", "void*"), Diagnostic(ErrorCode.ERR_VoidError, "x + y") }, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, "x + y").WithArguments(symbol, "void*", "nuint?"), Diagnostic(ErrorCode.ERR_VoidError, "x + y") });
......@@ -2386,7 +4441,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "bool?");
binaryOps(symbol, "nuint?", "char?", $"nuint nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint?", "sbyte?", $"nuint nuint.{name}(nuint left, nuint right)");
......@@ -2403,7 +4458,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double?", $"double double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal?", $"decimal decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr?");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
}
foreach ((string symbol, string name) in shiftOperators)
......@@ -2578,7 +4633,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr");
binaryOps(symbol, "nint", "bool?");
binaryOps(symbol, "nint", "char?", $"bool nint.{name}(nint left, nint right)");
......@@ -2595,7 +4650,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float?", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr?");
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint?", "string");
......@@ -2615,7 +4670,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr");
binaryOps(symbol, "nint?", "bool?");
binaryOps(symbol, "nint?", "char?", $"bool nint.{name}(nint left, nint right)");
......@@ -2632,7 +4687,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float?", $"bool float.{name}(float left, float right)");
binaryOps(symbol, "nint?", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nint?", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
//getArgs(builder, symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr?");
binaryOps(symbol, "nuint", "object");
binaryOps(symbol, "nuint", "string");
......@@ -2653,7 +4708,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr");
//getArgs(builder, symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint", "bool?");
binaryOps(symbol, "nuint", "char?", $"bool nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint", "sbyte?", $"bool nuint.{name}(nuint left, nuint right)");
......@@ -2670,7 +4725,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint", "System.IntPtr?");
//getArgs(builder, symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "object");
binaryOps(symbol, "nuint?", "string");
binaryOps(symbol, "nuint?", "void*", null, null, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "nuint?", "void*") }, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "void*", "nuint?") });
......@@ -2690,7 +4745,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "bool?");
binaryOps(symbol, "nuint?", "char?", $"bool nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint?", "sbyte?", $"bool nuint.{name}(nuint left, nuint right)");
......@@ -2707,7 +4762,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double?", $"bool double.{name}(double left, double right)");
binaryOps(symbol, "nuint?", "decimal?", $"bool decimal.{name}(decimal left, decimal right)");
binaryOps(symbol, "nuint?", "System.IntPtr?");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
}
foreach ((string symbol, string name) in logicalOperators)
......@@ -2730,7 +4785,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float");
binaryOps(symbol, "nint", "double");
binaryOps(symbol, "nint", "decimal");
//getArgs(builder, symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr");
binaryOps(symbol, "nint", "bool?");
binaryOps(symbol, "nint", "char?", $"nint nint.{name}(nint left, nint right)");
......@@ -2747,7 +4802,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint", "float?");
binaryOps(symbol, "nint", "double?");
binaryOps(symbol, "nint", "decimal?");
//getArgs(builder, symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint", "System.UIntPtr?");
binaryOps(symbol, "nint", "object");
binaryOps(symbol, "nint?", "string");
......@@ -2767,7 +4822,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float");
binaryOps(symbol, "nint?", "double");
binaryOps(symbol, "nint?", "decimal");
//getArgs(builder, symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr");
binaryOps(symbol, "nint?", "bool?");
binaryOps(symbol, "nint?", "char?", $"nint nint.{name}(nint left, nint right)");
......@@ -2784,7 +4839,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nint?", "float?");
binaryOps(symbol, "nint?", "double?");
binaryOps(symbol, "nint?", "decimal?");
//getArgs(builder, symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nint?", "System.IntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nint?", "System.UIntPtr?");
binaryOps(symbol, "nuint", "object");
binaryOps(symbol, "nuint", "string");
......@@ -2805,7 +4860,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double");
binaryOps(symbol, "nuint", "decimal");
binaryOps(symbol, "nuint", "System.IntPtr");
//getArgs(builder, symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint", "bool?");
binaryOps(symbol, "nuint", "char?", $"nuint nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint", "sbyte?", $"nuint nuint.{name}(nuint left, nuint right)");
......@@ -2822,7 +4877,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint", "double?");
binaryOps(symbol, "nuint", "decimal?");
binaryOps(symbol, "nuint", "System.IntPtr?");
//getArgs(builder, symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint", "System.UIntPtr?"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "object");
binaryOps(symbol, "nuint?", "string");
binaryOps(symbol, "nuint?", "void*", null, null, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "nuint?", "void*"), Diagnostic(ErrorCode.ERR_VoidError, $"x {symbol} y") }, new[] { Diagnostic(ErrorCode.ERR_BadBinaryOps, $"x {symbol} y").WithArguments(symbol, "void*", "nuint?"), Diagnostic(ErrorCode.ERR_VoidError, $"x {symbol} y") });
......@@ -2842,7 +4897,7 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double");
binaryOps(symbol, "nuint?", "decimal");
binaryOps(symbol, "nuint?", "System.IntPtr");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr"); // PROTOTYPE: Not handled.
binaryOps(symbol, "nuint?", "bool?");
binaryOps(symbol, "nuint?", "char?", $"nuint nuint.{name}(nuint left, nuint right)");
binaryOps(symbol, "nuint?", "sbyte?", $"nuint nuint.{name}(nuint left, nuint right)");
......@@ -2859,36 +4914,36 @@ void binaryOp(string op, string leftType, string rightType, string expectedSymbo
binaryOps(symbol, "nuint?", "double?");
binaryOps(symbol, "nuint?", "decimal?");
binaryOps(symbol, "nuint?", "System.IntPtr?");
//getArgs(builder, symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
//binaryOps(symbol, "nuint?", "System.UIntPtr?"); // PROTOTYPE: Not handled.
}
}
private void BinaryOperator(string op, string leftType, string rightType, string expectedSymbol, DiagnosticDescription[] expectedDiagnostics)
{
bool useUnsafeContext = useUnsafe(leftType) || useUnsafe(rightType);
string source =
$@"class Program
void binaryOperator(string op, string leftType, string rightType, string expectedSymbol, DiagnosticDescription[] expectedDiagnostics)
{
bool useUnsafeContext = useUnsafe(leftType) || useUnsafe(rightType);
string source =
$@"class Program
{{
static {(useUnsafeContext ? "unsafe " : "")}object Evaluate({leftType} x, {rightType} y)
{{
return x {op} y;
}}
}}";
var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(useUnsafeContext), parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var comp = CreateCompilation(source, options: TestOptions.ReleaseDll.WithAllowUnsafe(useUnsafeContext), parseOptions: TestOptions.RegularPreview);
comp.VerifyDiagnostics(expectedDiagnostics);
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Single();
var symbolInfo = model.GetSymbolInfo(expr);
Assert.Equal(expectedSymbol, symbolInfo.Symbol?.ToDisplayString(SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)));
var tree = comp.SyntaxTrees[0];
var model = comp.GetSemanticModel(tree);
var expr = tree.GetRoot().DescendantNodes().OfType<BinaryExpressionSyntax>().Single();
var symbolInfo = model.GetSymbolInfo(expr);
Assert.Equal(expectedSymbol, symbolInfo.Symbol?.ToDisplayString(SymbolDisplayFormat.TestFormat.WithMiscellaneousOptions(SymbolDisplayMiscellaneousOptions.UseSpecialTypes)));
if (expectedDiagnostics.Length == 0)
{
CompileAndVerify(comp);
}
if (expectedDiagnostics.Length == 0)
{
CompileAndVerify(comp);
}
static bool useUnsafe(string underlyingType) => underlyingType == "void*";
static bool useUnsafe(string type) => type == "void*";
}
}
[Fact]
......
......@@ -597,6 +597,12 @@ internal void EmitConstantValue(ConstantValue value)
case ConstantValueTypeDiscriminator.UInt64:
EmitLongConstant(value.Int64Value);
break;
case ConstantValueTypeDiscriminator.NInt:
EmitNativeIntConstant(value.Int32Value);
break;
case ConstantValueTypeDiscriminator.NUInt:
EmitNativeIntConstant(value.UInt32Value);
break;
case ConstantValueTypeDiscriminator.Single:
EmitSingleConstant(value.SingleValue);
break;
......@@ -695,6 +701,24 @@ internal void EmitLongConstant(long value)
}
}
internal void EmitNativeIntConstant(long value)
{
if (value >= int.MinValue && value <= int.MaxValue)
{
EmitIntConstant((int)value);
EmitOpCode(ILOpCode.Conv_i);
}
else if (value >= uint.MinValue && value <= uint.MaxValue)
{
EmitIntConstant(unchecked((int)value));
EmitOpCode(ILOpCode.Conv_u);
}
else
{
throw ExceptionUtilities.UnexpectedValue(value);
}
}
internal void EmitSingleConstant(float value)
{
EmitOpCode(ILOpCode.Ldc_r4);
......
......@@ -233,6 +233,34 @@ public static ConstantValue Create(UInt64 value)
return new ConstantValueI64(value);
}
public static ConstantValue CreateNativeInt(Int32 value)
{
if (value == 0)
{
return ConstantValueDefault.NInt;
}
else if (value == 1)
{
return ConstantValueOne.NInt;
}
return new ConstantValueNativeInt(value);
}
public static ConstantValue CreateNativeUInt(UInt32 value)
{
if (value == 0)
{
return ConstantValueDefault.NUInt;
}
else if (value == 1)
{
return ConstantValueOne.NUInt;
}
return new ConstantValueNativeInt(value);
}
public static ConstantValue Create(bool value)
{
if (value)
......@@ -345,8 +373,8 @@ public static ConstantValue Create(object value, ConstantValueTypeDiscriminator
case ConstantValueTypeDiscriminator.UInt32: return Create((uint)value);
case ConstantValueTypeDiscriminator.Int64: return Create((long)value);
case ConstantValueTypeDiscriminator.UInt64: return Create((ulong)value);
case ConstantValueTypeDiscriminator.NInt: return Create((int)value);
case ConstantValueTypeDiscriminator.NUInt: return Create((uint)value);
case ConstantValueTypeDiscriminator.NInt: return CreateNativeInt((int)value);
case ConstantValueTypeDiscriminator.NUInt: return CreateNativeUInt((uint)value);
case ConstantValueTypeDiscriminator.Char: return Create((char)value);
case ConstantValueTypeDiscriminator.Boolean: return Create((bool)value);
case ConstantValueTypeDiscriminator.Single:
......@@ -384,6 +412,8 @@ public static ConstantValue Default(ConstantValueTypeDiscriminator discriminator
case ConstantValueTypeDiscriminator.UInt32: return ConstantValueDefault.UInt32;
case ConstantValueTypeDiscriminator.Int64: return ConstantValueDefault.Int64;
case ConstantValueTypeDiscriminator.UInt64: return ConstantValueDefault.UInt64;
case ConstantValueTypeDiscriminator.NInt: return ConstantValueDefault.NInt;
case ConstantValueTypeDiscriminator.NUInt: return ConstantValueDefault.NUInt;
case ConstantValueTypeDiscriminator.Char: return ConstantValueDefault.Char;
case ConstantValueTypeDiscriminator.Boolean: return ConstantValueDefault.Boolean;
case ConstantValueTypeDiscriminator.Single: return ConstantValueDefault.Single;
......@@ -464,6 +494,8 @@ private static SpecialType GetSpecialType(ConstantValueTypeDiscriminator discrim
case ConstantValueTypeDiscriminator.UInt32: return Boxes.Box(UInt32Value);
case ConstantValueTypeDiscriminator.Int64: return Boxes.Box(Int64Value);
case ConstantValueTypeDiscriminator.UInt64: return Boxes.Box(UInt64Value);
case ConstantValueTypeDiscriminator.NInt: return Boxes.Box(Int32Value);
case ConstantValueTypeDiscriminator.NUInt: return Boxes.Box(UInt32Value);
case ConstantValueTypeDiscriminator.Char: return Boxes.Box(CharValue);
case ConstantValueTypeDiscriminator.Boolean: return Boxes.Box(BooleanValue);
case ConstantValueTypeDiscriminator.Single: return Boxes.Box(SingleValue);
......
......@@ -303,6 +303,8 @@ private class ConstantValueDefault : ConstantValueDiscriminated
public static readonly ConstantValueDefault UInt32 = new ConstantValueDefault(ConstantValueTypeDiscriminator.UInt32);
public static readonly ConstantValueDefault Int64 = new ConstantValueDefault(ConstantValueTypeDiscriminator.Int64);
public static readonly ConstantValueDefault UInt64 = new ConstantValueDefault(ConstantValueTypeDiscriminator.UInt64);
public static readonly ConstantValueDefault NInt = new ConstantValueDefault(ConstantValueTypeDiscriminator.NInt);
public static readonly ConstantValueDefault NUInt = new ConstantValueDefault(ConstantValueTypeDiscriminator.NUInt);
public static readonly ConstantValueDefault Char = new ConstantValueDefault(ConstantValueTypeDiscriminator.Char);
public static readonly ConstantValueDefault Single = new ConstantValueSingleZero();
public static readonly ConstantValueDefault Double = new ConstantValueDoubleZero();
......@@ -475,6 +477,8 @@ private class ConstantValueOne : ConstantValueDiscriminated
public static readonly ConstantValueOne UInt32 = new ConstantValueOne(ConstantValueTypeDiscriminator.UInt32);
public static readonly ConstantValueOne Int64 = new ConstantValueOne(ConstantValueTypeDiscriminator.Int64);
public static readonly ConstantValueOne UInt64 = new ConstantValueOne(ConstantValueTypeDiscriminator.UInt64);
public static readonly ConstantValueOne NInt = new ConstantValueOne(ConstantValueTypeDiscriminator.NInt);
public static readonly ConstantValueOne NUInt = new ConstantValueOne(ConstantValueTypeDiscriminator.NUInt);
public static readonly ConstantValueOne Single = new ConstantValueOne(ConstantValueTypeDiscriminator.Single);
public static readonly ConstantValueOne Double = new ConstantValueOne(ConstantValueTypeDiscriminator.Double);
public static readonly ConstantValueOne Decimal = new ConstantValueDecimalOne();
......@@ -754,6 +758,50 @@ public override bool Equals(ConstantValue? other)
}
}
private sealed class ConstantValueNativeInt : ConstantValueDiscriminated
{
// Constants are limited to 32-bit for portability.
private readonly int _value;
public ConstantValueNativeInt(int value)
: base(ConstantValueTypeDiscriminator.NInt)
{
_value = value;
}
public ConstantValueNativeInt(uint value)
: base(ConstantValueTypeDiscriminator.NUInt)
{
_value = unchecked((int)value);
}
public override int Int32Value
{
get
{
return _value;
}
}
public override uint UInt32Value
{
get
{
return unchecked((uint)_value);
}
}
public override int GetHashCode()
{
return Hash.Combine(base.GetHashCode(), _value.GetHashCode());
}
public override bool Equals(ConstantValue? other)
{
return base.Equals(other) && _value == other.Int32Value;
}
}
private sealed class ConstantValueDouble : ConstantValueDiscriminated
{
private readonly double _value;
......
Markdown is supported
0% .
You are about to add 0 people to the discussion. Proceed with caution.
先完成此消息的编辑!
想要评论请 注册