static void ApplyBinaryOperator(ref Expr left, ref Expr right, BinaryOperatorSymbol op) { if (op is BinaryOperatorSymbolWithMethod) { var mop = (BinaryOperatorSymbolWithMethod)op; var parameters = mop.Method.Method.GetParameters(); var lconv = mop.ConvLeft; if (lconv != null && lconv.Kind != ConversionKind.Identity) { Convert(ref left, FindType(parameters[0].ParameterType), lconv); } var rconv = mop.ConvRight; if (rconv != null && rconv.Kind != ConversionKind.Identity) { Convert(ref right, FindType(parameters[1].ParameterType), rconv); } } }
internal static void EmitCheckedBinaryOperator(ILGenerator ilg, BinaryOperatorSymbol op, TypeSymbol type) { switch (op.Kind) { case BinaryOperatorKind.Addition: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Add_Ovf_Un); } else { ilg.Emit(OpCodes.Add_Ovf); } break; case BinaryOperatorKind.Subtraction: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Sub_Ovf_Un); } else { ilg.Emit(OpCodes.Sub_Ovf); } break; case BinaryOperatorKind.Multiplication: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Mul_Ovf_Un); } else { ilg.Emit(OpCodes.Mul_Ovf); } break; default: EmitBinaryOperator(ilg, op, type); break; } }
internal static CompilationError BinaryOperationError(BinaryExpr expr, BinaryOperatorKind kind, BindOptions options) { return(expr.Error(ErrorCode.BinaryOperationNotFound, BinaryOperatorSymbol.OperatorSymbol(kind), expr.Left.Datatype, expr.Right.Datatype)); }
static BinaryOperatorEasyOut() { const OperandType ERR = OperandType.Error; const OperandType OBJ = OperandType.Object; const OperandType INT = OperandType.Int; const OperandType UIN = OperandType.UInt; const OperandType LNG = OperandType.Long; const OperandType ULG = OperandType.ULong; const OperandType FLT = OperandType.Float; const OperandType DBL = OperandType.Double; const OperandType DEC = OperandType.Decimal; const OperandType BOL = OperandType.Bool; // Overload resolution for Y * / - % < > <= >= X OperandType[,] arithmetic = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* i08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i32 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, FLT, DBL, DEC }, /* u08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u32 */ { ERR, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, FLT, DBL, DEC }, /* u64 */ { ERR, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, FLT, DBL, DEC }, /* r32 */ { ERR, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, DBL, ERR }, /* r64 */ { ERR, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, ERR }, /* dec */ { ERR, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, ERR, ERR, DEC }, }; // Overload resolution for Y + X OperandType[,] addition = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* i08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i32 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, FLT, DBL, DEC }, /* u08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u32 */ { ERR, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, FLT, DBL, DEC }, /* u64 */ { ERR, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, FLT, DBL, DEC }, /* r32 */ { ERR, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, DBL, ERR }, /* r64 */ { ERR, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, ERR }, /* dec */ { ERR, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, ERR, ERR, DEC }, }; // Overload resolution for Y << >> X OperandType[,] shift = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i08 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i16 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i32 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, ERR, LNG, LNG, ERR, ERR, ERR, ERR, ERR }, /* u08 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* u16 */ { ERR, INT, INT, INT, INT, ERR, INT, INT, ERR, ERR, ERR, ERR, ERR }, /* u32 */ { ERR, UIN, UIN, UIN, UIN, ERR, UIN, UIN, ERR, ERR, ERR, ERR, ERR }, /* u64 */ { ERR, ULG, ULG, ULG, ULG, ERR, ULG, ULG, ERR, ERR, ERR, ERR, ERR }, /* r32 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* r64 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* dec */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, }; // Overload resolution for Y == != X // Note that these are the overload resolution rules; overload resolution might pick an invalid operator. // For example, overload resolution on object == decimal chooses the object/object overload, which then // is not legal because decimal must be a reference type. But we don't know to give that error *until* // overload resolution has chosen the reference equality operator. OperandType[,] equality = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { BOL, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ, OBJ }, /* chr */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* i08 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i16 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i32 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, FLT, DBL, DEC }, /* i64 */ { OBJ, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, FLT, DBL, DEC }, /* u08 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u16 */ { OBJ, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, FLT, DBL, DEC }, /* u32 */ { OBJ, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, FLT, DBL, DEC }, /* u64 */ { OBJ, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, FLT, DBL, DEC }, /* r32 */ { OBJ, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, FLT, DBL, OBJ }, /* r64 */ { OBJ, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, DBL, OBJ }, /* dec */ { OBJ, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, DEC, OBJ, OBJ, DEC }, }; // Overload resolution for Y | & ^ || && X OperandType[,] logical = { // bool chr i08 i16 i32 i64 u08 u16 u32 u64 r32 r64 dec /* bool */ { BOL, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* chr */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, ERR, ERR, ERR }, /* i08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, ERR, ERR, ERR }, /* i16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, ERR, ERR, ERR }, /* i32 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, LNG, ERR, ERR, ERR, ERR }, /* i64 */ { ERR, LNG, LNG, LNG, LNG, LNG, LNG, LNG, LNG, ERR, ERR, ERR, ERR }, /* u08 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, ERR, ERR, ERR }, /* u16 */ { ERR, INT, INT, INT, INT, LNG, INT, INT, UIN, ULG, ERR, ERR, ERR }, /* u32 */ { ERR, UIN, LNG, LNG, LNG, LNG, UIN, UIN, UIN, ULG, ERR, ERR, ERR }, /* u64 */ { ERR, ULG, ERR, ERR, ERR, ERR, ULG, ULG, ULG, ULG, ERR, ERR, ERR }, /* r32 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* r64 */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, /* dec */ { ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR, ERR }, }; var ops = (BinaryOperatorKind[])Enum.GetValues(typeof(BinaryOperatorKind)); s_binOp = new BinaryOperatorSymbol[ops.Length][, ]; s_binOp[(int)BinaryOperatorKind.Error] = new BinaryOperatorSymbol[28, 28]; for (int i = 0; i < 28; i++) { for (int j = 0; j < 28; j++) { s_binOp[(int)BinaryOperatorKind.Error][i, j] = BinaryOperatorSymbol.Create(BinaryOperatorKind.Error, OperandType.Error); } } for (int i = ((int)BinaryOperatorKind.Error) + 1; i < ops.Length; i++) { s_binOp[i] = s_binOp[(int)BinaryOperatorKind.Error]; } Func <BinaryOperatorKind, OperandType[, ], BinaryOperatorSymbol[, ]> expandTable = (k, x) => { var res = new BinaryOperatorSymbol[28, 28]; for (int i = 0; i < 13; i++) { for (int j = 0; j < 13; j++) { var t = x[i, j]; var nt = OperandTypeHelper.IsNullable(t + OperandTypeHelper.NullableDelta) ? t + OperandTypeHelper.NullableDelta : t; res[i + 2, j + 2] = BinaryOperatorSymbol.Create(k, t); res[i + 2 + 13, j + 2] = BinaryOperatorSymbol.Create(k, nt); res[i + 2, j + 2 + 13] = BinaryOperatorSymbol.Create(k, nt); res[i + 2 + 13, j + 2 + 13] = BinaryOperatorSymbol.Create(k, nt); } } bool eq = k == BinaryOperatorKind.Equal || k == BinaryOperatorKind.NotEqual || k == BinaryOperatorKind.ExactEqual; bool add = k == BinaryOperatorKind.Addition; var op_o = eq ? BinaryOperatorSymbol.Create(k, OperandType.Object) : BinaryOperatorSymbol.Create(BinaryOperatorKind.Error, OperandType.Error); var op_ss = (eq || add) ? BinaryOperatorSymbol.Create(k, OperandType.String) : op_o; var op_so = (eq || add) ? BinaryOperatorSymbol.Create(k, OperandType.StringAndObject) : op_o; var op_os = (eq || add) ? BinaryOperatorSymbol.Create(k, OperandType.ObjectAndString) : op_o; for (int i = 0; i < 28; i++) { if (i == 1) { // str res[1, 1] = op_ss; } else { // obj res[0, i] = op_o; res[i, 0] = op_o; // str res[1, i] = op_so; res[i, 1] = op_os; } } return(res); }; var tables = new[] { arithmetic, addition, shift, equality, logical }; Func <BinaryOperatorKind, int> tableIndex = k => { if (k == BinaryOperatorKind.Multiplication || k == BinaryOperatorKind.Subtraction || k == BinaryOperatorKind.Division || k == BinaryOperatorKind.Remainder || k == BinaryOperatorKind.Exponent) { return(0); } if (k == BinaryOperatorKind.Addition) { return(1); } if (k == BinaryOperatorKind.LeftShift || k == BinaryOperatorKind.RightShift) { return(2); } if (k == BinaryOperatorKind.Equal || k == BinaryOperatorKind.NotEqual || k == BinaryOperatorKind.ExactEqual) { return(3); } if (k == BinaryOperatorKind.GreaterThan || k == BinaryOperatorKind.LessThan || k == BinaryOperatorKind.GreaterThanOrEqual || k == BinaryOperatorKind.LessThanOrEqual || k == BinaryOperatorKind.And || k == BinaryOperatorKind.Xor || k == BinaryOperatorKind.Or) { return(4); } if (k == BinaryOperatorKind.Substr || k == BinaryOperatorKind.DefaultValue) { return(-1); } return(-1); }; for (int i = ((int)BinaryOperatorKind.Error) + 1; i < ops.Length; i++) { var k = (BinaryOperatorKind)i; var ti = tableIndex(k); if (ti >= 0) { s_binOp[i] = expandTable(k, tables[ti]); } } }
internal BinaryOperatorSymbolWithType(BinaryOperatorSymbol op, TypeSymbol type) : base(op.Kind, op.OpType, op.ResType) { Type = type; }
static BinaryOperatorSymbol() { var ops = (BinaryOperatorKind[])Enum.GetValues(typeof(BinaryOperatorKind)); var opTypes = (OperandType[])Enum.GetValues(typeof(OperandType)); int maxOp = 0; foreach (var o in ops) { if (o < BinaryOperatorKind.OpBase && (int)o > maxOp) { maxOp = (int)o; } } simpleOp = new BinaryOperatorSymbol[maxOp + 1, opTypes.Length]; var op = new BinaryOperatorKind[maxOp + 1, opTypes.Length]; var opr = new OperandType[maxOp + 1, opTypes.Length]; foreach (var o in ops) { if (o > BinaryOperatorKind.OpBase) { var ok = (int)o & (int)BinaryOperatorKind.OpMask; var ot = ((int)o / (int)BinaryOperatorKind.OpBase) & (int)BinaryOperatorKind.OpMask; var or = (OperandType)(((int)o / (int)BinaryOperatorKind.OpResBase) & (int)BinaryOperatorKind.OpMask); op[ok, ot] = o; opr[ok, ot] = or; } } foreach (var o in ops) { if (o < BinaryOperatorKind.OpBase) { foreach (var c in opTypes) { if (o != BinaryOperatorKind.Error && c != OperandType.Error) { var ti = (int)c; if (op[(int)o, ti] == BinaryOperatorKind.Error) { ti = 0; } var k = op[(int)o, ti]; if (k == BinaryOperatorKind.Error) { k = o; } var r = opr[(int)o, ti]; if (r == OperandType.Error) { r = c; } simpleOp[(int)o, (int)c] = new BinaryOperatorSymbol(k, c, r); } } } } #if DEBUG /* * foreach (var o in ops) * { * if (o != BinaryOperatorKind.Error && o < BinaryOperatorKind.OpTypeBase) * Debug.Assert(OperatorName(o) != null); * } */ #endif }
internal static BinaryOperatorSymbol UserDefinedBinaryOperator(BinaryOperatorKind kind, ref Expr left, ref Expr right, BindOptions options) { MethodSymbol mop = null; ConversionSymbol lconv = null; ConversionSymbol rconv = null; bool hasUsual = left.Datatype.NativeType == NativeType.Usual || right.Datatype.NativeType == NativeType.Usual; if (options.HasFlag(BindOptions.AllowInexactComparisons)) { bool hasString = left.Datatype.NativeType == NativeType.String || right.Datatype.NativeType == NativeType.String; bool bothStrings = left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String; switch (kind) { case BinaryOperatorKind.Equal: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringEquals), ref mop, ref lconv, ref rconv, options); } else if (hasString) { ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactEquals), ref mop, ref lconv, ref rconv, options); } break; case BinaryOperatorKind.NotEqual: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringNotEquals), ref mop, ref lconv, ref rconv, options); } else if (hasString) { ResolveBinaryOperator(left, right, Compilation.Get(NativeType.Usual).Lookup(OperatorNames.__UsualInExactNotEquals), ref mop, ref lconv, ref rconv, options); } break; case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThanOrEqual: if (bothStrings) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions___StringCompare), ref mop, ref lconv, ref rconv, options); } break; } } else { switch (kind) { case BinaryOperatorKind.Equal: case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.LessThan: case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.LessThanOrEqual: if (left.Datatype.NativeType == NativeType.String && right.Datatype.NativeType == NativeType.String) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.System_String_CompareOrdinal), ref mop, ref lconv, ref rconv, options); } break; } } if (mop == null) { var name = BinaryOperatorSymbol.OperatorName(kind); if (name != null) { ResolveBinaryOperator(left, right, left.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special); ResolveBinaryOperator(left, right, right.Datatype.Lookup(name), ref mop, ref lconv, ref rconv, options | BindOptions.Special); } } if (mop == null && kind == BinaryOperatorKind.Exponent) { ResolveBinaryOperator(left, right, Compilation.Get(WellKnownMembers.XSharp_RT_Functions_POW), ref mop, ref lconv, ref rconv, options); if (hasUsual) { ResolveBinaryOperator(left, right, left.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options); ResolveBinaryOperator(left, right, right.Datatype.Lookup(OperatorNames.__UsualExponent), ref mop, ref lconv, ref rconv, options); } } if (mop != null) { var op = BinaryOperatorSymbol.Create(kind, mop, lconv, rconv); ApplyBinaryOperator(ref left, ref right, op); return(op); } return(null); }
internal static void EmitBinaryOperator(ILGenerator ilg, BinaryOperatorSymbol op, TypeSymbol type) { switch (op.Kind) { case BinaryOperatorKind.Concat: ilg.Emit(OpCodes.Call, (Compilation.Get(WellKnownMembers.System_String_Concat) as MethodSymbol).Method); break; case BinaryOperatorKind.ConcatStringObject: case BinaryOperatorKind.ConcatObjectString: ilg.Emit(OpCodes.Call, (Compilation.Get(WellKnownMembers.System_String_Concat_Object) as MethodSymbol).Method); break; case BinaryOperatorKind.Addition: ilg.Emit(OpCodes.Add); break; case BinaryOperatorKind.Subtraction: ilg.Emit(OpCodes.Sub); break; case BinaryOperatorKind.Multiplication: ilg.Emit(OpCodes.Mul); break; case BinaryOperatorKind.Division: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Div_Un); } else { ilg.Emit(OpCodes.Div); } break; case BinaryOperatorKind.Remainder: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Rem_Un); } else { ilg.Emit(OpCodes.Rem); } break; case BinaryOperatorKind.LeftShift: ilg.Emit(OpCodes.Shl); break; case BinaryOperatorKind.RightShift: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Shr_Un); } else { ilg.Emit(OpCodes.Shr); } break; case BinaryOperatorKind.And: ilg.Emit(OpCodes.And); break; case BinaryOperatorKind.Xor: ilg.Emit(OpCodes.Xor); break; case BinaryOperatorKind.Or: ilg.Emit(OpCodes.Or); break; case BinaryOperatorKind.GreaterThan: case BinaryOperatorKind.GreaterThanAny: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Cgt_Un); } else { ilg.Emit(OpCodes.Cgt); } break; case BinaryOperatorKind.LessThan: case BinaryOperatorKind.LessThanAny: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Clt_Un); } else { ilg.Emit(OpCodes.Clt); } break; case BinaryOperatorKind.GreaterThanOrEqual: case BinaryOperatorKind.GreaterThanOrEqualAny: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Clt_Un); } else { ilg.Emit(OpCodes.Clt); } ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); break; case BinaryOperatorKind.LessThanOrEqual: case BinaryOperatorKind.LessThanOrEqualAny: if (type.NativeType.IsUnsigned()) { ilg.Emit(OpCodes.Cgt_Un); } else { ilg.Emit(OpCodes.Cgt); } ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); break; case BinaryOperatorKind.ExactEqual: case BinaryOperatorKind.Equal: case BinaryOperatorKind.ExactEqualAny: case BinaryOperatorKind.EqualAny: ilg.Emit(OpCodes.Ceq); break; case BinaryOperatorKind.NotEqual: case BinaryOperatorKind.NotEqualAny: ilg.Emit(OpCodes.Ceq); ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); break; case BinaryOperatorKind.EqString: case BinaryOperatorKind.EeqString: ilg.Emit(OpCodes.Call, (Compilation.Get(WellKnownMembers.System_String_Equals) as MethodSymbol).Method); break; case BinaryOperatorKind.NeqString: ilg.Emit(OpCodes.Call, (Compilation.Get(WellKnownMembers.System_String_Equals) as MethodSymbol).Method); ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); break; case BinaryOperatorKind.EqObject: case BinaryOperatorKind.EqStringObject: case BinaryOperatorKind.EqObjectString: case BinaryOperatorKind.EeqObject: case BinaryOperatorKind.EeqStringObject: case BinaryOperatorKind.EeqObjectString: ilg.Emit(OpCodes.Call, (Compilation.Get(WellKnownMembers.System_Object_Equals) as MethodSymbol).Method); break; case BinaryOperatorKind.NeqObject: case BinaryOperatorKind.NeqStringObject: case BinaryOperatorKind.NeqObjectString: ilg.Emit(OpCodes.Call, (Compilation.Get(WellKnownMembers.System_Object_Equals) as MethodSymbol).Method); ilg.Emit(OpCodes.Ldc_I4_0); ilg.Emit(OpCodes.Ceq); break; case BinaryOperatorKind.Exponent: case BinaryOperatorKind.Substr: case BinaryOperatorKind.DefaultValue: default: throw new InternalError(); } }