/// <summary>
        /// Reduces the expression node to a simpler expression.
        /// </summary>
        /// <returns>The reduced expression.</returns>
        public override Expression Reduce()
        {
            var functionalOp = new Func<Expression, Expression>(lhs =>
            {
                var operation = default(ExpressionType);

                switch (OperationNodeType)
                {
                    case CSharpExpressionType.PreIncrementAssign:
                    case CSharpExpressionType.PreIncrementAssignChecked:
                    case CSharpExpressionType.PostIncrementAssign:
                    case CSharpExpressionType.PostIncrementAssignChecked:
                        operation = ExpressionType.Increment;
                        break;
                    case CSharpExpressionType.PreDecrementAssign:
                    case CSharpExpressionType.PreDecrementAssignChecked:
                    case CSharpExpressionType.PostDecrementAssign:
                    case CSharpExpressionType.PostDecrementAssignChecked:
                        operation = ExpressionType.Decrement;
                        break;

                    default:
                        throw ContractUtils.Unreachable;
                }

                var args = new[]
                {
                    CSharpArgumentInfo.Create(Operand.Flags, null)
                };

                var binder = Binder.UnaryOperation(Flags, operation, Context, args);
                var dynamic = DynamicHelpers.MakeDynamic(typeof(object), binder, new[] { lhs }, new[] { lhs.Type });

                // NB: no conversion needed in the unary case

                return dynamic;
            });

            var flags = Flags | CSharpBinderFlags.ValueFromCompoundAssignment;

            var res = DynamicHelpers.ReduceDynamicAssignment(Operand, functionalOp, flags, IsPrefix);

            return res;
        }
        private Expression ReduceCore(DynamicCSharpArgument left)
        {
            var functionalOp = new Func<Expression, Expression>(lhs =>
            {
                var operation = default(ExpressionType);

                switch (OperationNodeType)
                {
                    case CSharpExpressionType.AddAssign:
                    case CSharpExpressionType.AddAssignChecked:
                        operation = ExpressionType.AddAssign;
                        break;
                    case CSharpExpressionType.SubtractAssign:
                    case CSharpExpressionType.SubtractAssignChecked:
                        operation = ExpressionType.SubtractAssign;
                        break;
                    case CSharpExpressionType.MultiplyAssign:
                    case CSharpExpressionType.MultiplyAssignChecked:
                        operation = ExpressionType.MultiplyAssign;
                        break;
                    case CSharpExpressionType.DivideAssign:
                        operation = ExpressionType.DivideAssign;
                        break;
                    case CSharpExpressionType.ModuloAssign:
                        operation = ExpressionType.ModuloAssign;
                        break;
                    case CSharpExpressionType.AndAssign:
                        operation = ExpressionType.AndAssign;
                        break;
                    case CSharpExpressionType.OrAssign:
                        operation = ExpressionType.OrAssign;
                        break;
                    case CSharpExpressionType.ExclusiveOrAssign:
                        operation = ExpressionType.ExclusiveOrAssign;
                        break;
                    case CSharpExpressionType.LeftShiftAssign:
                        operation = ExpressionType.LeftShiftAssign;
                        break;
                    case CSharpExpressionType.RightShiftAssign:
                        operation = ExpressionType.RightShiftAssign;
                        break;

                    default:
                        throw ContractUtils.Unreachable;
                }

                var args = new[]
                {
                    CSharpArgumentInfo.Create(GetArgumentInfoFlags(Left), null),
                    CSharpArgumentInfo.Create(GetArgumentInfoFlags(Right), null),
                };

                var binder = Binder.BinaryOperation(Flags, operation, Context, args);
                var dynamic = DynamicHelpers.MakeDynamic(typeof(object), binder, new[] { lhs, Right.Expression }, new[] { lhs.Type, Right.Expression.Type });

                var leftType = Left.Expression.Type;
                if (leftType != dynamic.Type)
                {
                    var convert = Binder.Convert(CSharpBinderFlags.ConvertExplicit, leftType, Context);
                    dynamic = DynamicHelpers.MakeDynamic(leftType, convert, new[] { dynamic }, null);
                }

                return dynamic;
            });

            var flags = Flags | CSharpBinderFlags.ValueFromCompoundAssignment;

            var res = DynamicHelpers.ReduceDynamicAssignment(left, functionalOp, flags);

            return res;
        }
        private Expression WithEventCheck(GetMemberDynamicCSharpExpression member, string accessor)
        {
            var obj = member.Object;
            var name = member.Name;
            var args = member.Arguments;

            Debug.Assert(args.Count == 0);

            var lhs = Expression.Parameter(obj.Type, "__objTemp");
            var left = Left.Update(member.Update(lhs, args));

            var isEventBinder = Binder.IsEvent(CSharpBinderFlags.None, name, Context);
            var isEventCheck = DynamicHelpers.MakeDynamic(typeof(bool), isEventBinder, new[] { lhs }, null);

            var accessorName = accessor + name;
            var accessorArgs = new[]
            {
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
                CSharpArgumentInfo.Create(CSharpArgumentInfoFlags.None, null),
            };

            var invokeAccessorBinder = Binder.InvokeMember(CSharpBinderFlags.InvokeSpecialName | CSharpBinderFlags.ResultDiscarded, accessorName, null, Context, accessorArgs);
            var invokeAccessor = DynamicHelpers.MakeDynamic(typeof(object), invokeAccessorBinder, new[] { lhs, Right.Expression }, null);

            var ifNotEvent = ReduceCore(left);

            var res =
                Expression.Block(
                    new[] { lhs },
                    Expression.Assign(lhs, obj),
                    Expression.Condition(isEventCheck, invokeAccessor, ifNotEvent)
                );

            return res;
        }