Exemplo n.º 1
0
 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);
         }
     }
 }
Exemplo n.º 2
0
        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;
            }
        }
Exemplo n.º 3
0
 internal static CompilationError BinaryOperationError(BinaryExpr expr, BinaryOperatorKind kind, BindOptions options)
 {
     return(expr.Error(ErrorCode.BinaryOperationNotFound, BinaryOperatorSymbol.OperatorSymbol(kind), expr.Left.Datatype, expr.Right.Datatype));
 }
Exemplo n.º 4
0
        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]);
                }
            }
        }
Exemplo n.º 5
0
 internal BinaryOperatorSymbolWithType(BinaryOperatorSymbol op, TypeSymbol type) : base(op.Kind, op.OpType, op.ResType)
 {
     Type = type;
 }
Exemplo n.º 6
0
        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
        }
Exemplo n.º 7
0
        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);
        }
Exemplo n.º 8
0
        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();
            }
        }