Merge pull request #439 from mono-soc-2012/garyb/iconfix
[mono.git] / mcs / class / dlr / Runtime / Microsoft.Scripting.Core / Ast / BinaryExpression.cs
1
2 /* ****************************************************************************
3  *
4  * Copyright (c) Microsoft Corporation. 
5  *
6  * This source code is subject to terms and conditions of the Apache License, Version 2.0. A 
7  * copy of the license can be found in the License.html file at the root of this distribution. If 
8  * you cannot locate the  Apache License, Version 2.0, please send an email to 
9  * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
10  * by the terms of the Apache License, Version 2.0.
11  *
12  * You must not remove this notice, or any other, from this software.
13  *
14  *
15  * ***************************************************************************/
16
17 using System;
18 using System.Collections.Generic;
19 using System.Diagnostics;
20 using System.Dynamic.Utils;
21 using System.Reflection;
22
23 #if !FEATURE_CORE_DLR
24 namespace Microsoft.Scripting.Ast {
25 #else
26 namespace System.Linq.Expressions {
27 #endif
28
29     /// <summary>
30     /// Represents an expression that has a binary operator.
31     /// </summary>
32     [DebuggerTypeProxy(typeof(Expression.BinaryExpressionProxy))]
33     public class BinaryExpression : Expression {
34         private readonly Expression _left;
35         private readonly Expression _right;
36
37         internal BinaryExpression(Expression left, Expression right) {
38             _left = left;
39             _right = right;
40         }
41
42         /// <summary>
43         /// Gets a value that indicates whether the expression tree node can be reduced. 
44         /// </summary>
45         public override bool CanReduce {
46             get {
47                 // Only OpAssignments are reducible.
48                 return IsOpAssignment(NodeType);
49             }
50         }
51
52         private static bool IsOpAssignment(ExpressionType op) {
53             switch (op) {
54                 case ExpressionType.AddAssign:
55                 case ExpressionType.SubtractAssign:
56                 case ExpressionType.MultiplyAssign:
57                 case ExpressionType.AddAssignChecked:
58                 case ExpressionType.SubtractAssignChecked:
59                 case ExpressionType.MultiplyAssignChecked:
60                 case ExpressionType.DivideAssign:
61                 case ExpressionType.ModuloAssign:
62                 case ExpressionType.PowerAssign:
63                 case ExpressionType.AndAssign:
64                 case ExpressionType.OrAssign:
65                 case ExpressionType.RightShiftAssign:
66                 case ExpressionType.LeftShiftAssign:
67                 case ExpressionType.ExclusiveOrAssign:
68                     return true;
69             }
70             return false;
71         }
72
73         /// <summary>
74         /// Gets the right operand of the binary operation.
75         /// </summary>
76         public Expression Right {
77             get { return _right; }
78         }
79
80         /// <summary>
81         /// Gets the left operand of the binary operation.
82         /// </summary>
83         public Expression Left {
84             get { return _left; }
85         }
86
87         /// <summary>
88         /// Gets the implementing method for the binary operation.
89         /// </summary>
90         public MethodInfo Method {
91             get { return GetMethod(); }
92         }
93
94         internal virtual MethodInfo GetMethod() {
95             return null;
96         }
97
98         // Note: takes children in evaluation order, which is also the order
99         // that ExpressionVisitor visits them. Having them this way reduces the
100         // chances people will make a mistake and use an inconsistent order in
101         // derived visitors.
102
103         /// <summary>
104         /// Creates a new expression that is like this one, but using the
105         /// supplied children. If all of the children are the same, it will
106         /// return this expression.
107         /// </summary>
108         /// <param name="left">The <see cref="Left" /> property of the result.</param>
109         /// <param name="conversion">The <see cref="Conversion" /> property of the result.</param>
110         /// <param name="right">The <see cref="Right" /> property of the result.</param>
111         /// <returns>This expression if no children changed, or an expression with the updated children.</returns>
112         public BinaryExpression Update(Expression left, LambdaExpression conversion, Expression right) {
113             if (left == Left && right == Right && conversion == Conversion) {
114                 return this;
115             }
116             if (IsReferenceComparison) {
117                 if (NodeType == ExpressionType.Equal) {
118                     return Expression.ReferenceEqual(left, right);
119                 } else {
120                     return Expression.ReferenceNotEqual(left, right);
121                 }
122             }
123             return Expression.MakeBinary(NodeType, left, right, IsLiftedToNull, Method, conversion);
124         }
125
126         /// <summary>
127         /// Reduces the binary expression node to a simpler expression. 
128         /// If CanReduce returns true, this should return a valid expression.
129         /// This method is allowed to return another node which itself 
130         /// must be reduced.
131         /// </summary>
132         /// <returns>The reduced expression.</returns>
133         public override Expression Reduce() {
134             // Only reduce OpAssignment expressions.
135             if (IsOpAssignment(NodeType)) {
136                 switch (_left.NodeType) {
137                     case ExpressionType.MemberAccess:
138                         return ReduceMember();
139
140                     case ExpressionType.Index:
141                         return ReduceIndex();
142
143                     default:
144                         return ReduceVariable();
145                 }
146             }
147             return this;
148         }
149
150         // Return the corresponding Op of an assignment op.
151         private static ExpressionType GetBinaryOpFromAssignmentOp(ExpressionType op) {
152             Debug.Assert(IsOpAssignment(op));
153             switch (op) {
154                 case ExpressionType.AddAssign:
155                     return ExpressionType.Add;
156                 case ExpressionType.AddAssignChecked:
157                     return ExpressionType.AddChecked;
158                 case ExpressionType.SubtractAssign:
159                     return ExpressionType.Subtract;
160                 case ExpressionType.SubtractAssignChecked:
161                     return ExpressionType.SubtractChecked;
162                 case ExpressionType.MultiplyAssign:
163                     return ExpressionType.Multiply;
164                 case ExpressionType.MultiplyAssignChecked:
165                     return ExpressionType.MultiplyChecked;
166                 case ExpressionType.DivideAssign:
167                     return ExpressionType.Divide;
168                 case ExpressionType.ModuloAssign:
169                     return ExpressionType.Modulo;
170                 case ExpressionType.PowerAssign:
171                     return ExpressionType.Power;
172                 case ExpressionType.AndAssign:
173                     return ExpressionType.And;
174                 case ExpressionType.OrAssign:
175                     return ExpressionType.Or;
176                 case ExpressionType.RightShiftAssign:
177                     return ExpressionType.RightShift;
178                 case ExpressionType.LeftShiftAssign:
179                     return ExpressionType.LeftShift;
180                 case ExpressionType.ExclusiveOrAssign:
181                     return ExpressionType.ExclusiveOr;
182                 default:
183                     // must be an error
184                     throw Error.InvalidOperation("op");
185             }
186
187         }
188
189         private Expression ReduceVariable() {
190             // v (op)= r
191             // ... is reduced into ...
192             // v = v (op) r
193             ExpressionType op = GetBinaryOpFromAssignmentOp(NodeType);
194             Expression r = Expression.MakeBinary(op, _left, _right, false, Method);
195             LambdaExpression conversion = GetConversion();
196             if (conversion != null) {
197                 r = Expression.Invoke(conversion, r);
198             }
199             return Expression.Assign(_left, r);
200         }
201
202         private Expression ReduceMember() {
203             MemberExpression member = (MemberExpression)_left;
204
205             if (member.Expression == null) {
206                 // static member, reduce the same as variable
207                 return ReduceVariable();
208             } else {
209                 // left.b (op)= r
210                 // ... is reduced into ...
211                 // temp1 = left
212                 // temp2 = temp1.b (op) r
213                 // temp1.b = temp2
214                 // temp2
215                 ParameterExpression temp1 = Variable(member.Expression.Type, "temp1");
216
217                 // 1. temp1 = left
218                 Expression e1 = Expression.Assign(temp1, member.Expression);
219
220                 // 2. temp2 = temp1.b (op) r
221                 ExpressionType op = GetBinaryOpFromAssignmentOp(NodeType);
222                 Expression e2 = Expression.MakeBinary(op, Expression.MakeMemberAccess(temp1, member.Member), _right, false, Method);
223                 LambdaExpression conversion = GetConversion();
224                 if (conversion != null) {
225                     e2 = Expression.Invoke(conversion, e2);
226                 }
227                 ParameterExpression temp2 = Variable(e2.Type, "temp2");
228                 e2 = Expression.Assign(temp2, e2);
229
230                 // 3. temp1.b = temp2
231                 Expression e3 = Expression.Assign(Expression.MakeMemberAccess(temp1, member.Member), temp2);
232
233                 // 3. temp2
234                 Expression e4 = temp2;
235
236                 return Expression.Block(
237                     new ParameterExpression[] { temp1, temp2 },
238                     e1, e2, e3, e4
239                 );
240             }
241         }
242
243         private Expression ReduceIndex() {
244             // left[a0, a1, ... aN] (op)= r
245             //
246             // ... is reduced into ...
247             //
248             // tempObj = left
249             // tempArg0 = a0
250             // ...
251             // tempArgN = aN
252             // tempValue = tempObj[tempArg0, ... tempArgN] (op) r
253             // tempObj[tempArg0, ... tempArgN] = tempValue
254
255             var index = (IndexExpression)_left;
256
257             var vars = new List<ParameterExpression>(index.Arguments.Count + 2);
258             var exprs = new List<Expression>(index.Arguments.Count + 3);
259
260             var tempObj = Expression.Variable(index.Object.Type, "tempObj");
261             vars.Add(tempObj);
262             exprs.Add(Expression.Assign(tempObj, index.Object));
263
264             var tempArgs = new List<Expression>(index.Arguments.Count);
265             foreach (var arg in index.Arguments) {
266                 var tempArg = Expression.Variable(arg.Type, "tempArg" + tempArgs.Count);
267                 vars.Add(tempArg);
268                 tempArgs.Add(tempArg);
269                 exprs.Add(Expression.Assign(tempArg, arg));
270             }
271
272             var tempIndex = Expression.MakeIndex(tempObj, index.Indexer, tempArgs);
273
274             // tempValue = tempObj[tempArg0, ... tempArgN] (op) r
275             ExpressionType binaryOp = GetBinaryOpFromAssignmentOp(NodeType);
276             Expression op = Expression.MakeBinary(binaryOp, tempIndex, _right, false, Method);
277             LambdaExpression conversion = GetConversion();
278             if (conversion != null) {
279                 op = Expression.Invoke(conversion, op);
280             }
281             var tempValue = Expression.Variable(op.Type, "tempValue");
282             vars.Add(tempValue);
283             exprs.Add(Expression.Assign(tempValue, op));
284
285             // tempObj[tempArg0, ... tempArgN] = tempValue
286             exprs.Add(Expression.Assign(tempIndex, tempValue));
287
288             return Expression.Block(vars, exprs);
289         }
290
291         /// <summary>
292         /// Gets the type conversion function that is used by a coalescing or compound assignment operation.
293         /// </summary>
294         public LambdaExpression Conversion {
295             get { return GetConversion(); }
296         }
297
298         internal virtual LambdaExpression GetConversion() {
299             return null;
300         }
301
302         /// <summary>
303         /// Gets a value that indicates whether the expression tree node represents a lifted call to an operator.
304         /// </summary>
305         public bool IsLifted {
306             get {
307                 if (NodeType == ExpressionType.Coalesce || NodeType == ExpressionType.Assign) {
308                     return false;
309                 }
310                 if (TypeUtils.IsNullableType(_left.Type)) {
311                     MethodInfo method = GetMethod();
312                     return method == null ||
313                         !TypeUtils.AreEquivalent(method.GetParametersCached()[0].ParameterType.GetNonRefType(), _left.Type);
314                 }
315                 return false;
316             }
317         }
318         /// <summary>
319         /// Gets a value that indicates whether the expression tree node represents a lifted call to an operator whose return type is lifted to a nullable type.
320         /// </summary>
321         public bool IsLiftedToNull {
322             get {
323                 return IsLifted && TypeUtils.IsNullableType(Type);
324             }
325         }
326
327         /// <summary>
328         /// Dispatches to the specific visit method for this node type.
329         /// </summary>
330         protected internal override Expression Accept(ExpressionVisitor visitor) {
331             return visitor.VisitBinary(this);
332         }
333
334         internal static Expression Create(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion) {
335             if (nodeType == ExpressionType.Assign) {
336                 Debug.Assert(method == null && TypeUtils.AreEquivalent(type, left.Type));
337                 return new AssignBinaryExpression(left, right);
338             }
339             if (conversion != null) {
340                 Debug.Assert(method == null && TypeUtils.AreEquivalent(type, right.Type) && nodeType == ExpressionType.Coalesce);
341                 return new CoalesceConversionBinaryExpression(left, right, conversion);
342             }
343             if (method != null) {
344                 return new MethodBinaryExpression(nodeType, left, right, type, method);
345             }
346             if (type == typeof(bool)) {
347                 return new LogicalBinaryExpression(nodeType, left, right);
348             }
349             return new SimpleBinaryExpression(nodeType, left, right, type);
350         }
351
352         internal bool IsLiftedLogical {
353             get {
354                 Type left = _left.Type;
355                 Type right = _right.Type;
356                 MethodInfo method = GetMethod();
357                 ExpressionType kind = NodeType;
358
359                 return
360                     (kind == ExpressionType.AndAlso || kind == ExpressionType.OrElse) &&
361                     TypeUtils.AreEquivalent(right, left) &&
362                     TypeUtils.IsNullableType(left) &&
363                     method != null &&
364                     TypeUtils.AreEquivalent(method.ReturnType, TypeUtils.GetNonNullableType(left));
365             }
366         }
367
368         internal bool IsReferenceComparison {
369             get {
370                 Type left = _left.Type;
371                 Type right = _right.Type;
372                 MethodInfo method = GetMethod();
373                 ExpressionType kind = NodeType;
374
375                 return (kind == ExpressionType.Equal || kind == ExpressionType.NotEqual) &&
376                     method == null && !left.IsValueType && !right.IsValueType;
377             }
378         }
379
380         //
381         // For a userdefined type T which has op_False defined and L, R are
382         // nullable, (L AndAlso R) is computed as:
383         //
384         // L.HasValue
385         //     ? T.op_False(L.GetValueOrDefault())
386         //         ? L
387         //         : R.HasValue 
388         //             ? (T?)(T.op_BitwiseAnd(L.GetValueOrDefault(), R.GetValueOrDefault()))
389         //             : null
390         //     : null
391         //
392         // For a userdefined type T which has op_True defined and L, R are
393         // nullable, (L OrElse R)  is computed as:
394         //
395         // L.HasValue
396         //     ? T.op_True(L.GetValueOrDefault())
397         //         ? L
398         //         : R.HasValue 
399         //             ? (T?)(T.op_BitwiseOr(L.GetValueOrDefault(), R.GetValueOrDefault()))
400         //             : null
401         //     : null
402         //
403         //
404         // This is the same behavior as VB. If you think about it, it makes
405         // sense: it's combining the normal pattern for short-circuiting 
406         // operators, with the normal pattern for lifted operations: if either
407         // of the operands is null, the result is also null.
408         //
409         internal Expression ReduceUserdefinedLifted() {
410             Debug.Assert(IsLiftedLogical);
411
412             var left = Parameter(_left.Type, "left");
413             var right = Parameter(Right.Type, "right");
414             string opName = NodeType == ExpressionType.AndAlso ? "op_False" : "op_True";
415             MethodInfo opTrueFalse = TypeUtils.GetBooleanOperator(Method.DeclaringType, opName);
416             Debug.Assert(opTrueFalse != null);
417
418             return Block(
419                 new[] { left },
420                 Assign(left, _left),
421                 Condition(
422                     Property(left, "HasValue"),
423                     Condition(
424                         Call(opTrueFalse, Call(left, "GetValueOrDefault", null)),
425                         left,
426                         Block(
427                             new[] { right },
428                             Assign(right, _right),
429                             Condition(
430                                 Property(right, "HasValue"),
431                                 Convert(
432                                     Call(
433                                         Method,
434                                         Call(left, "GetValueOrDefault", null),
435                                         Call(right, "GetValueOrDefault", null)
436                                     ),
437                                     Type
438                                 ),
439                                 Constant(null, Type)
440                             )
441                         )
442                     ),
443                     Constant(null, Type)
444                 )
445             );
446         }
447     }
448
449     // Optimized representation of simple logical expressions:
450     // && || == != > < >= <=
451     internal sealed class LogicalBinaryExpression : BinaryExpression {
452         private readonly ExpressionType _nodeType;
453
454         internal LogicalBinaryExpression(ExpressionType nodeType, Expression left, Expression right)
455             : base(left, right) {
456             _nodeType = nodeType;
457         }
458
459         public sealed override Type Type {
460             get { return typeof(bool); }
461         }
462
463         public sealed override ExpressionType NodeType {
464             get { return _nodeType; }
465         }
466     }
467
468     // Optimized assignment node, only holds onto children
469     internal sealed class AssignBinaryExpression : BinaryExpression {
470         internal AssignBinaryExpression(Expression left, Expression right)
471             : base(left, right) {
472         }
473
474         public sealed override Type Type {
475             get { return Left.Type; }
476         }
477
478         public sealed override ExpressionType NodeType {
479             get { return ExpressionType.Assign; }
480         }
481     }
482
483     // Coalesce with conversion
484     // This is not a frequently used node, but rather we want to save every
485     // other BinaryExpression from holding onto the null conversion lambda
486     internal sealed class CoalesceConversionBinaryExpression : BinaryExpression {
487         private readonly LambdaExpression _conversion;
488
489         internal CoalesceConversionBinaryExpression(Expression left, Expression right, LambdaExpression conversion)
490             : base(left, right) {
491             _conversion = conversion;
492         }
493
494         internal override LambdaExpression GetConversion() {
495             return _conversion;
496         }
497
498         public sealed override ExpressionType NodeType {
499             get { return ExpressionType.Coalesce; }
500         }
501
502         public sealed override Type Type {
503             get { return Right.Type; }
504         }
505     }
506
507     // OpAssign with conversion
508     // This is not a frequently used node, but rather we want to save every
509     // other BinaryExpression from holding onto the null conversion lambda
510     internal sealed class OpAssignMethodConversionBinaryExpression : MethodBinaryExpression {
511         private readonly LambdaExpression _conversion;
512
513         internal OpAssignMethodConversionBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method, LambdaExpression conversion)
514             : base(nodeType, left, right, type, method) {
515             _conversion = conversion;
516         }
517
518         internal override LambdaExpression GetConversion() {
519             return _conversion;
520         }
521     }
522
523     // Class that handles most binary expressions
524     // If needed, it can be optimized even more (often Type == left.Type)
525     internal class SimpleBinaryExpression : BinaryExpression {
526         private readonly ExpressionType _nodeType;
527         private readonly Type _type;
528
529         internal SimpleBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type)
530             : base(left, right) {
531             _nodeType = nodeType;
532             _type = type;
533         }
534
535         public sealed override ExpressionType NodeType {
536             get { return _nodeType; }
537         }
538
539         public sealed override Type Type {
540             get { return _type; }
541         }
542     }
543
544     // Class that handles binary expressions with a method
545     // If needed, it can be optimized even more (often Type == method.ReturnType)
546     internal class MethodBinaryExpression : SimpleBinaryExpression {
547         private readonly MethodInfo _method;
548
549         internal MethodBinaryExpression(ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method)
550             : base(nodeType, left, right, type) {
551             _method = method;
552         }
553
554         internal override MethodInfo GetMethod() {
555             return _method;
556         }
557     }
558
559     public partial class Expression {
560
561         #region Assign
562
563         /// <summary>
564         /// Creates a <see cref="BinaryExpression"/> that represents an assignment operation.
565         /// </summary>
566         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
567         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
568         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see ref="F:ExpressionType.Assign"/> 
569         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.
570         /// </returns>
571         public static BinaryExpression Assign(Expression left, Expression right) {
572             RequiresCanWrite(left, "left");
573             RequiresCanRead(right, "right");
574             TypeUtils.ValidateType(left.Type);
575             TypeUtils.ValidateType(right.Type);
576             if (!TypeUtils.AreReferenceAssignable(left.Type, right.Type)) {
577                 throw Error.ExpressionTypeDoesNotMatchAssignment(right.Type, left.Type);
578             }
579             return new AssignBinaryExpression(left, right);
580         }
581
582         #endregion
583
584
585         private static BinaryExpression GetUserDefinedBinaryOperator(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull) {
586             // try exact match first
587             MethodInfo method = GetUserDefinedBinaryOperator(binaryType, left.Type, right.Type, name);
588             if (method != null) {
589                 return new MethodBinaryExpression(binaryType, left, right, method.ReturnType, method);
590             }
591             // try lifted call
592             if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type)) {
593                 Type nnLeftType = TypeUtils.GetNonNullableType(left.Type);
594                 Type nnRightType = TypeUtils.GetNonNullableType(right.Type);
595                 method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name);
596                 if (method != null && method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) {
597                     if (method.ReturnType != typeof(bool) || liftToNull) {
598                         return new MethodBinaryExpression(binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method);
599                     } else {
600                         return new MethodBinaryExpression(binaryType, left, right, typeof(bool), method);
601                     }
602                 }
603             }
604             return null;
605         }
606
607
608         private static BinaryExpression GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, bool liftToNull) {
609             System.Diagnostics.Debug.Assert(method != null);
610             ValidateOperator(method);
611             ParameterInfo[] pms = method.GetParametersCached();
612             if (pms.Length != 2)
613                 throw Error.IncorrectNumberOfMethodCallArguments(method);
614             if (ParameterIsAssignable(pms[0], left.Type) && ParameterIsAssignable(pms[1], right.Type)) {
615                 ValidateParamswithOperandsOrThrow(pms[0].ParameterType, left.Type, binaryType, method.Name);
616                 ValidateParamswithOperandsOrThrow(pms[1].ParameterType, right.Type, binaryType, method.Name);
617                 return new MethodBinaryExpression(binaryType, left, right, method.ReturnType, method);
618
619             }
620             // check for lifted call
621             if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type) &&
622                 ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) &&
623                 ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right.Type)) &&
624                 method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) {
625                 if (method.ReturnType != typeof(bool) || liftToNull) {
626                     return new MethodBinaryExpression(binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method);
627                 } else {
628                     return new MethodBinaryExpression(binaryType, left, right, typeof(bool), method);
629                 }
630             }
631             throw Error.OperandTypesDoNotMatchParameters(binaryType, method.Name);
632         }
633
634         private static BinaryExpression GetMethodBasedAssignOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, LambdaExpression conversion, bool liftToNull) {
635             BinaryExpression b = GetMethodBasedBinaryOperator(binaryType, left, right, method, liftToNull);
636             if (conversion == null) {
637                 // return type must be assignable back to the left type
638                 if (!TypeUtils.AreReferenceAssignable(left.Type, b.Type)) {
639                     throw Error.UserDefinedOpMustHaveValidReturnType(binaryType, b.Method.Name);
640                 }
641             } else {
642                 // add the conversion to the result
643                 ValidateOpAssignConversionLambda(conversion, b.Left, b.Method, b.NodeType);
644                 b = new OpAssignMethodConversionBinaryExpression(b.NodeType, b.Left, b.Right, b.Left.Type, b.Method, conversion);
645             }
646             return b;
647         }
648
649
650         private static BinaryExpression GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull) {
651             BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, name, left, right, liftToNull);
652             if (b != null) {
653                 ParameterInfo[] pis = b.Method.GetParametersCached();
654                 ValidateParamswithOperandsOrThrow(pis[0].ParameterType, left.Type, binaryType, name);
655                 ValidateParamswithOperandsOrThrow(pis[1].ParameterType, right.Type, binaryType, name);
656                 return b;
657             }
658             throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type);
659         }
660
661         private static BinaryExpression GetUserDefinedAssignOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, LambdaExpression conversion, bool liftToNull) {
662             BinaryExpression b = GetUserDefinedBinaryOperatorOrThrow(binaryType, name, left, right, liftToNull);
663             if (conversion == null) {
664                 // return type must be assignable back to the left type
665                 if (!TypeUtils.AreReferenceAssignable(left.Type, b.Type)) {
666                     throw Error.UserDefinedOpMustHaveValidReturnType(binaryType, b.Method.Name);
667                 }
668             } else {
669                 // add the conversion to the result
670                 ValidateOpAssignConversionLambda(conversion, b.Left, b.Method, b.NodeType);
671                 b = new OpAssignMethodConversionBinaryExpression(b.NodeType, b.Left, b.Right, b.Left.Type, b.Method, conversion);
672             }
673             return b;
674         }
675
676
677         private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name) {
678             // UNDONE: This algorithm is wrong, we should be checking for uniqueness and erroring if
679             // UNDONE: it is defined on both types.
680             Type[] types = new Type[] { leftType, rightType };
681             Type nnLeftType = TypeUtils.GetNonNullableType(leftType);
682             Type nnRightType = TypeUtils.GetNonNullableType(rightType);
683             BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
684             MethodInfo method = nnLeftType.GetMethodValidated(name, flags, null, types, null);
685             if (method == null && !TypeUtils.AreEquivalent(leftType, rightType)) {
686                 method = nnRightType.GetMethodValidated(name, flags, null, types, null);
687             }
688
689             if (IsLiftingConditionalLogicalOperator(leftType, rightType, method, binaryType)) {
690                 method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name);
691             }
692             return method;
693         }
694
695
696         private static bool IsLiftingConditionalLogicalOperator(Type left, Type right, MethodInfo method, ExpressionType binaryType) {
697             return TypeUtils.IsNullableType(right) &&
698                     TypeUtils.IsNullableType(left) &&
699                     method == null &&
700                     (binaryType == ExpressionType.AndAlso || binaryType == ExpressionType.OrElse);
701         }
702
703
704         internal static bool ParameterIsAssignable(ParameterInfo pi, Type argType) {
705             Type pType = pi.ParameterType;
706             if (pType.IsByRef)
707                 pType = pType.GetElementType();
708             return TypeUtils.AreReferenceAssignable(pType, argType);
709         }
710
711
712         private static void ValidateParamswithOperandsOrThrow(Type paramType, Type operandType, ExpressionType exprType, string name) {
713             if (TypeUtils.IsNullableType(paramType) && !TypeUtils.IsNullableType(operandType)) {
714                 throw Error.OperandTypesDoNotMatchParameters(exprType, name);
715             }
716         }
717
718
719         private static void ValidateOperator(MethodInfo method) {
720             System.Diagnostics.Debug.Assert(method != null);
721             ValidateMethodInfo(method);
722             if (!method.IsStatic)
723                 throw Error.UserDefinedOperatorMustBeStatic(method);
724             if (method.ReturnType == typeof(void))
725                 throw Error.UserDefinedOperatorMustNotBeVoid(method);
726         }
727
728
729         private static void ValidateMethodInfo(MethodInfo method) {
730             if (method.IsGenericMethodDefinition)
731                 throw Error.MethodIsGeneric(method);
732             if (method.ContainsGenericParameters)
733                 throw Error.MethodContainsGenericParameters(method);
734         }
735
736
737         private static bool IsNullComparison(Expression left, Expression right) {
738             // If we have x==null, x!=null, null==x or null!=x where x is
739             // nullable but not null, then this is treated as a call to x.HasValue
740             // and is legal even if there is no equality operator defined on the
741             // type of x.
742             if (IsNullConstant(left) && !IsNullConstant(right) && TypeUtils.IsNullableType(right.Type)) {
743                 return true;
744             }
745             if (IsNullConstant(right) && !IsNullConstant(left) && TypeUtils.IsNullableType(left.Type)) {
746                 return true;
747             }
748             return false;
749         }
750
751
752         // Note: this has different meaning than ConstantCheck.IsNull
753         // That function attempts to determine if the result of a tree will be
754         // null at runtime. This function is used at tree construction time and
755         // only looks for a ConstantExpression with a null Value. It can't
756         // become "smarter" or that would break tree construction.
757         private static bool IsNullConstant(Expression e) {
758             var c = e as ConstantExpression;
759             return c != null && c.Value == null;
760         }
761
762
763         private static void ValidateUserDefinedConditionalLogicOperator(ExpressionType nodeType, Type left, Type right, MethodInfo method) {
764             ValidateOperator(method);
765             ParameterInfo[] pms = method.GetParametersCached();
766             if (pms.Length != 2)
767                 throw Error.IncorrectNumberOfMethodCallArguments(method);
768             if (!ParameterIsAssignable(pms[0], left)) {
769                 if (!(TypeUtils.IsNullableType(left) && ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left))))
770                     throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name);
771             }
772             if (!ParameterIsAssignable(pms[1], right)) {
773                 if (!(TypeUtils.IsNullableType(right) && ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right))))
774                     throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name);
775             }
776             if (pms[0].ParameterType != pms[1].ParameterType) {
777                 throw Error.UserDefinedOpMustHaveConsistentTypes(nodeType, method.Name);
778             }
779             if (method.ReturnType != pms[0].ParameterType) {
780                 throw Error.UserDefinedOpMustHaveConsistentTypes(nodeType, method.Name);
781             }
782             if (IsValidLiftedConditionalLogicalOperator(left, right, pms)) {
783                 left = TypeUtils.GetNonNullableType(left);
784                 right = TypeUtils.GetNonNullableType(left);
785             }
786             MethodInfo opTrue = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_True");
787             MethodInfo opFalse = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_False");
788             if (opTrue == null || opTrue.ReturnType != typeof(bool) ||
789                 opFalse == null || opFalse.ReturnType != typeof(bool)) {
790                 throw Error.LogicalOperatorMustHaveBooleanOperators(nodeType, method.Name);
791             }
792             VerifyOpTrueFalse(nodeType, left, opFalse);
793             VerifyOpTrueFalse(nodeType, left, opTrue);
794         }
795
796         private static void VerifyOpTrueFalse(ExpressionType nodeType, Type left, MethodInfo opTrue) {
797             ParameterInfo[] pmsOpTrue = opTrue.GetParametersCached();
798             if (pmsOpTrue.Length != 1)
799                 throw Error.IncorrectNumberOfMethodCallArguments(opTrue);
800
801             if (!ParameterIsAssignable(pmsOpTrue[0], left)) {
802                 if (!(TypeUtils.IsNullableType(left) && ParameterIsAssignable(pmsOpTrue[0], TypeUtils.GetNonNullableType(left))))
803                     throw Error.OperandTypesDoNotMatchParameters(nodeType, opTrue.Name);
804             }
805         }
806
807         private static bool IsValidLiftedConditionalLogicalOperator(Type left, Type right, ParameterInfo[] pms) {
808             return TypeUtils.AreEquivalent(left, right) &&
809                    TypeUtils.IsNullableType(right) &&
810                    TypeUtils.AreEquivalent(pms[1].ParameterType, TypeUtils.GetNonNullableType(right));
811         }
812
813
814         /// <summary>
815         /// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method.
816         /// </summary>
817         /// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param>
818         /// <param name="left">An Expression that represents the left operand.</param>
819         /// <param name="right">An Expression that represents the right operand.</param>
820         /// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns>
821         public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right) {
822             return MakeBinary(binaryType, left, right, false, null, null);
823         }
824
825         /// <summary>
826         /// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method.
827         /// </summary>
828         /// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param>
829         /// <param name="left">An Expression that represents the left operand.</param>
830         /// <param name="right">An Expression that represents the right operand.</param>
831         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
832         /// <param name="method">A MethodInfo that specifies the implementing method.</param>
833         /// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns>
834         public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method) {
835             return MakeBinary(binaryType, left, right, liftToNull, method, null);
836         }
837
838         ///
839         /// <summary>
840         /// Creates a BinaryExpression, given the left and right operands, by calling an appropriate factory method.
841         /// </summary>
842         /// <param name="binaryType">The ExpressionType that specifies the type of binary operation.</param>
843         /// <param name="left">An Expression that represents the left operand.</param>
844         /// <param name="right">An Expression that represents the right operand.</param>
845         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
846         /// <param name="method">A MethodInfo that specifies the implementing method.</param>
847         /// <param name="conversion">A LambdaExpression that represents a type conversion function. This parameter is used if binaryType is Coalesce or compound assignment.</param>
848         /// <returns>The BinaryExpression that results from calling the appropriate factory method.</returns>
849         [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
850         public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion) {
851             switch (binaryType) {
852                 case ExpressionType.Add:
853                     return Add(left, right, method);
854                 case ExpressionType.AddChecked:
855                     return AddChecked(left, right, method);
856                 case ExpressionType.Subtract:
857                     return Subtract(left, right, method);
858                 case ExpressionType.SubtractChecked:
859                     return SubtractChecked(left, right, method);
860                 case ExpressionType.Multiply:
861                     return Multiply(left, right, method);
862                 case ExpressionType.MultiplyChecked:
863                     return MultiplyChecked(left, right, method);
864                 case ExpressionType.Divide:
865                     return Divide(left, right, method);
866                 case ExpressionType.Modulo:
867                     return Modulo(left, right, method);
868                 case ExpressionType.Power:
869                     return Power(left, right, method);
870                 case ExpressionType.And:
871                     return And(left, right, method);
872                 case ExpressionType.AndAlso:
873                     return AndAlso(left, right, method);
874                 case ExpressionType.Or:
875                     return Or(left, right, method);
876                 case ExpressionType.OrElse:
877                     return OrElse(left, right, method);
878                 case ExpressionType.LessThan:
879                     return LessThan(left, right, liftToNull, method);
880                 case ExpressionType.LessThanOrEqual:
881                     return LessThanOrEqual(left, right, liftToNull, method);
882                 case ExpressionType.GreaterThan:
883                     return GreaterThan(left, right, liftToNull, method);
884                 case ExpressionType.GreaterThanOrEqual:
885                     return GreaterThanOrEqual(left, right, liftToNull, method);
886                 case ExpressionType.Equal:
887                     return Equal(left, right, liftToNull, method);
888                 case ExpressionType.NotEqual:
889                     return NotEqual(left, right, liftToNull, method);
890                 case ExpressionType.ExclusiveOr:
891                     return ExclusiveOr(left, right, method);
892                 case ExpressionType.Coalesce:
893                     return Coalesce(left, right, conversion);
894                 case ExpressionType.ArrayIndex:
895                     return ArrayIndex(left, right);
896                 case ExpressionType.RightShift:
897                     return RightShift(left, right, method);
898                 case ExpressionType.LeftShift:
899                     return LeftShift(left, right, method);
900                 case ExpressionType.Assign:
901                     return Assign(left, right);
902                 case ExpressionType.AddAssign:
903                     return AddAssign(left, right, method, conversion);
904                 case ExpressionType.AndAssign:
905                     return AndAssign(left, right, method, conversion);
906                 case ExpressionType.DivideAssign:
907                     return DivideAssign(left, right, method, conversion);
908                 case ExpressionType.ExclusiveOrAssign:
909                     return ExclusiveOrAssign(left, right, method, conversion);
910                 case ExpressionType.LeftShiftAssign:
911                     return LeftShiftAssign(left, right, method, conversion);
912                 case ExpressionType.ModuloAssign:
913                     return ModuloAssign(left, right, method, conversion);
914                 case ExpressionType.MultiplyAssign:
915                     return MultiplyAssign(left, right, method, conversion);
916                 case ExpressionType.OrAssign:
917                     return OrAssign(left, right, method, conversion);
918                 case ExpressionType.PowerAssign:
919                     return PowerAssign(left, right, method, conversion);
920                 case ExpressionType.RightShiftAssign:
921                     return RightShiftAssign(left, right, method, conversion);
922                 case ExpressionType.SubtractAssign:
923                     return SubtractAssign(left, right, method, conversion);
924                 case ExpressionType.AddAssignChecked:
925                     return AddAssignChecked(left, right, method, conversion);
926                 case ExpressionType.SubtractAssignChecked:
927                     return SubtractAssignChecked(left, right, method, conversion);
928                 case ExpressionType.MultiplyAssignChecked:
929                     return MultiplyAssignChecked(left, right, method, conversion);
930                 default:
931                     throw Error.UnhandledBinary(binaryType);
932             }
933         }
934
935         #region Equality Operators
936
937
938         /// <summary>
939         /// Creates a <see cref="BinaryExpression"/> that represents an equality comparison.
940         /// </summary>
941         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
942         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
943         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> 
944         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
945         public static BinaryExpression Equal(Expression left, Expression right) {
946             return Equal(left, right, false, null);
947         }
948
949         /// <summary>
950         /// Creates a <see cref="BinaryExpression"/> that represents an equality comparison.
951         /// </summary>
952         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
953         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
954         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
955         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
956         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> 
957         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
958         /// </returns>
959         public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method) {
960             RequiresCanRead(left, "left");
961             RequiresCanRead(right, "right");
962             if (method == null) {
963                 return GetEqualityComparisonOperator(ExpressionType.Equal, "op_Equality", left, right, liftToNull);
964             }
965             return GetMethodBasedBinaryOperator(ExpressionType.Equal, left, right, method, liftToNull);
966         }
967
968         /// <summary>
969         /// Creates a <see cref="BinaryExpression"/> that represents a reference equality comparison.
970         /// </summary>
971         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
972         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
973         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Equal"/> 
974         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.
975         /// </returns>
976         public static BinaryExpression ReferenceEqual(Expression left, Expression right) {
977             RequiresCanRead(left, "left");
978             RequiresCanRead(right, "right");
979             if (TypeUtils.HasReferenceEquality(left.Type, right.Type)) {
980                 return new LogicalBinaryExpression(ExpressionType.Equal, left, right);
981             }
982             throw Error.ReferenceEqualityNotDefined(left.Type, right.Type);
983         }
984
985         /// <summary>
986         /// Creates a <see cref="BinaryExpression"/> that represents an inequality comparison.
987         /// </summary>
988         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
989         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
990         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> 
991         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
992         public static BinaryExpression NotEqual(Expression left, Expression right) {
993             return NotEqual(left, right, false, null);
994         }
995
996         /// <summary>
997         /// Creates a <see cref="BinaryExpression"/> that represents an inequality comparison.
998         /// </summary>
999         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1000         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1001         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
1002         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1003         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> 
1004         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1005         /// </returns>
1006         public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
1007             RequiresCanRead(left, "left");
1008             RequiresCanRead(right, "right");
1009             if (method == null) {
1010                 return GetEqualityComparisonOperator(ExpressionType.NotEqual, "op_Inequality", left, right, liftToNull);
1011             }
1012             return GetMethodBasedBinaryOperator(ExpressionType.NotEqual, left, right, method, liftToNull);
1013         }
1014
1015         /// <summary>
1016         /// Creates a <see cref="BinaryExpression"/> that represents a reference inequality comparison.
1017         /// </summary>
1018         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1019         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1020         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.NotEqual"/> 
1021         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.
1022         /// </returns>
1023         public static BinaryExpression ReferenceNotEqual(Expression left, Expression right) {
1024             RequiresCanRead(left, "left");
1025             RequiresCanRead(right, "right");
1026             if (TypeUtils.HasReferenceEquality(left.Type, right.Type)) {
1027                 return new LogicalBinaryExpression(ExpressionType.NotEqual, left, right);
1028             }
1029             throw Error.ReferenceEqualityNotDefined(left.Type, right.Type);
1030         }
1031
1032         private static BinaryExpression GetEqualityComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull) {
1033             // known comparison - numeric types, bools, object, enums
1034             if (left.Type == right.Type && (TypeUtils.IsNumeric(left.Type) ||
1035                 left.Type == typeof(object) ||
1036                 TypeUtils.IsBool(left.Type) ||
1037                 TypeUtils.GetNonNullableType(left.Type).IsEnum)) {
1038                 if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
1039                     return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?));
1040                 } else {
1041                     return new LogicalBinaryExpression(binaryType, left, right);
1042                 }
1043             }
1044             // look for user defined operator
1045             BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, opName, left, right, liftToNull);
1046             if (b != null) {
1047                 return b;
1048             }
1049             if (TypeUtils.HasBuiltInEqualityOperator(left.Type, right.Type) || IsNullComparison(left, right)) {
1050                 if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
1051                     return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?));
1052                 } else {
1053                     return new LogicalBinaryExpression(binaryType, left, right);
1054                 }
1055             }
1056             throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type);
1057         }
1058
1059         #endregion
1060
1061         #region Comparison Expressions
1062
1063
1064         /// <summary>
1065         /// Creates a <see cref="BinaryExpression"/> that represents a "greater than" numeric comparison.
1066         /// </summary>
1067         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1068         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1069         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThan"/> 
1070         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1071         public static BinaryExpression GreaterThan(Expression left, Expression right) {
1072             return GreaterThan(left, right, false, null);
1073         }
1074
1075         /// <summary>
1076         /// Creates a <see cref="BinaryExpression"/> that represents a "greater than" numeric comparison.
1077         /// </summary>
1078         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1079         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1080         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1081         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
1082         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThan"/> 
1083         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1084         /// </returns>
1085         public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method) {
1086             RequiresCanRead(left, "left");
1087             RequiresCanRead(right, "right");
1088             if (method == null) {
1089                 return GetComparisonOperator(ExpressionType.GreaterThan, "op_GreaterThan", left, right, liftToNull);
1090             }
1091             return GetMethodBasedBinaryOperator(ExpressionType.GreaterThan, left, right, method, liftToNull);
1092         }
1093
1094         /// <summary>
1095         /// Creates a <see cref="BinaryExpression"/> that represents a "less than" numeric comparison.
1096         /// </summary>
1097         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1098         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1099         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThan"/> 
1100         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1101
1102         public static BinaryExpression LessThan(Expression left, Expression right) {
1103             return LessThan(left, right, false, null);
1104         }
1105
1106         /// <summary>
1107         /// Creates a <see cref="BinaryExpression"/> that represents a "less than" numeric comparison.
1108         /// </summary>
1109         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1110         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1111         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1112         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
1113         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThan"/> 
1114         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1115         /// </returns>
1116         public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method) {
1117             RequiresCanRead(left, "left");
1118             RequiresCanRead(right, "right");
1119             if (method == null) {
1120                 return GetComparisonOperator(ExpressionType.LessThan, "op_LessThan", left, right, liftToNull);
1121             }
1122             return GetMethodBasedBinaryOperator(ExpressionType.LessThan, left, right, method, liftToNull);
1123         }
1124
1125
1126         /// <summary>
1127         /// Creates a <see cref="BinaryExpression"/> that represents a "greater than or equal" numeric comparison.
1128         /// </summary>
1129         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1130         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1131         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThanOrEqual"/> 
1132         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1133         public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) {
1134             return GreaterThanOrEqual(left, right, false, null);
1135         }
1136
1137         /// <summary>
1138         /// Creates a <see cref="BinaryExpression"/> that represents a "greater than or equal" numeric comparison.
1139         /// </summary>
1140         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1141         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1142         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1143         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
1144         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.GreaterThanOrEqual"/> 
1145         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1146         /// </returns>
1147         public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
1148             RequiresCanRead(left, "left");
1149             RequiresCanRead(right, "right");
1150             if (method == null) {
1151                 return GetComparisonOperator(ExpressionType.GreaterThanOrEqual, "op_GreaterThanOrEqual", left, right, liftToNull);
1152             }
1153             return GetMethodBasedBinaryOperator(ExpressionType.GreaterThanOrEqual, left, right, method, liftToNull);
1154         }
1155
1156
1157         /// <summary>
1158         /// Creates a <see cref="BinaryExpression"/> that represents a "less than or equal" numeric comparison.
1159         /// </summary>
1160         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1161         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1162         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThanOrEqual"/> 
1163         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1164         public static BinaryExpression LessThanOrEqual(Expression left, Expression right) {
1165             return LessThanOrEqual(left, right, false, null);
1166         }
1167
1168         /// <summary>
1169         /// Creates a <see cref="BinaryExpression"/> that represents a "less than or equal" numeric comparison.
1170         /// </summary>
1171         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1172         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1173         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1174         /// <param name="liftToNull">true to set IsLiftedToNull to true; false to set IsLiftedToNull to false.</param>
1175         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LessThanOrEqual"/> 
1176         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.IsLiftedToNull"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1177         /// </returns>
1178         public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
1179             RequiresCanRead(left, "left");
1180             RequiresCanRead(right, "right");
1181             if (method == null) {
1182                 return GetComparisonOperator(ExpressionType.LessThanOrEqual, "op_LessThanOrEqual", left, right, liftToNull);
1183             }
1184             return GetMethodBasedBinaryOperator(ExpressionType.LessThanOrEqual, left, right, method, liftToNull);
1185         }
1186
1187
1188         private static BinaryExpression GetComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull) {
1189             if (left.Type == right.Type && TypeUtils.IsNumeric(left.Type)) {
1190                 if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
1191                     return new SimpleBinaryExpression(binaryType, left, right, typeof(bool?));
1192                 } else {
1193                     return new LogicalBinaryExpression(binaryType, left, right);
1194                 }
1195             }
1196             return GetUserDefinedBinaryOperatorOrThrow(binaryType, opName, left, right, liftToNull);
1197         }
1198
1199         #endregion
1200
1201         #region Boolean Expressions
1202
1203
1204         /// <summary>
1205         /// Creates a <see cref="BinaryExpression"/> that represents a conditional AND operation that evaluates the second operand only if it has to.
1206         /// </summary>
1207         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1208         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1209         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAlso"/> 
1210         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1211         public static BinaryExpression AndAlso(Expression left, Expression right) {
1212             return AndAlso(left, right, null);
1213         }
1214
1215         /// <summary>
1216         /// Creates a <see cref="BinaryExpression"/> that represents a conditional AND operation that evaluates the second operand only if it has to.
1217         /// </summary>
1218         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1219         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1220         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1221         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAlso"/> 
1222         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1223         /// </returns>
1224         public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method) {
1225             RequiresCanRead(left, "left");
1226             RequiresCanRead(right, "right");
1227             Type returnType;
1228             if (method == null) {
1229                 if (left.Type == right.Type) {
1230                     if (left.Type == typeof(bool)) {
1231                         return new LogicalBinaryExpression(ExpressionType.AndAlso, left, right);
1232                     } else if (left.Type == typeof(bool?)) {
1233                         return new SimpleBinaryExpression(ExpressionType.AndAlso, left, right, left.Type);
1234                     }
1235                 }
1236                 method = GetUserDefinedBinaryOperator(ExpressionType.AndAlso, left.Type, right.Type, "op_BitwiseAnd");
1237                 if (method != null) {
1238                     ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method);
1239                     returnType = (TypeUtils.IsNullableType(left.Type) && TypeUtils.AreEquivalent(method.ReturnType, TypeUtils.GetNonNullableType(left.Type))) ? left.Type : method.ReturnType;
1240                     return new MethodBinaryExpression(ExpressionType.AndAlso, left, right, returnType, method);
1241                 }
1242                 throw Error.BinaryOperatorNotDefined(ExpressionType.AndAlso, left.Type, right.Type);
1243             }
1244             ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method);
1245             returnType = (TypeUtils.IsNullableType(left.Type) && TypeUtils.AreEquivalent(method.ReturnType, TypeUtils.GetNonNullableType(left.Type))) ? left.Type : method.ReturnType;
1246             return new MethodBinaryExpression(ExpressionType.AndAlso, left, right, returnType, method);
1247         }
1248
1249
1250         /// <summary>
1251         /// Creates a <see cref="BinaryExpression"/> that represents a conditional OR operation that evaluates the second operand only if it has to.
1252         /// </summary>
1253         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1254         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1255         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrElse"/> 
1256         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1257         public static BinaryExpression OrElse(Expression left, Expression right) {
1258             return OrElse(left, right, null);
1259         }
1260
1261         /// <summary>
1262         /// Creates a <see cref="BinaryExpression"/> that represents a conditional OR operation that evaluates the second operand only if it has to.
1263         /// </summary>
1264         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1265         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1266         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1267         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrElse"/> 
1268         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1269         /// </returns>
1270         public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method) {
1271             RequiresCanRead(left, "left");
1272             RequiresCanRead(right, "right");
1273             Type returnType;
1274             if (method == null) {
1275                 if (left.Type == right.Type) {
1276                     if (left.Type == typeof(bool)) {
1277                         return new LogicalBinaryExpression(ExpressionType.OrElse, left, right);
1278                     } else if (left.Type == typeof(bool?)) {
1279                         return new SimpleBinaryExpression(ExpressionType.OrElse, left, right, left.Type);
1280                     }
1281                 }
1282                 method = GetUserDefinedBinaryOperator(ExpressionType.OrElse, left.Type, right.Type, "op_BitwiseOr");
1283                 if (method != null) {
1284                     ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method);
1285                     returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
1286                     return new MethodBinaryExpression(ExpressionType.OrElse, left, right, returnType, method);
1287                 }
1288                 throw Error.BinaryOperatorNotDefined(ExpressionType.OrElse, left.Type, right.Type);
1289             }
1290             ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method);
1291             returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
1292             return new MethodBinaryExpression(ExpressionType.OrElse, left, right, returnType, method);
1293         }
1294
1295         #endregion
1296
1297         #region Coalescing Expressions
1298
1299
1300         /// <summary>
1301         /// Creates a BinaryExpression that represents a coalescing operation.
1302         /// </summary>
1303         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1304         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1305         /// <returns>A BinaryExpression that has the NodeType property equal to Coalesce and the Left and Right properties set to the specified values.</returns>
1306         public static BinaryExpression Coalesce(Expression left, Expression right) {
1307             return Coalesce(left, right, null);
1308         }
1309
1310
1311         /// <summary>
1312         /// Creates a BinaryExpression that represents a coalescing operation.
1313         /// </summary>
1314         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1315         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1316         /// <param name="conversion">A LambdaExpression to set the Conversion property equal to.</param>
1317         /// <returns>A BinaryExpression that has the NodeType property equal to Coalesce and the Left, Right and Conversion properties set to the specified values.
1318         /// </returns>
1319         public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion) {
1320             RequiresCanRead(left, "left");
1321             RequiresCanRead(right, "right");
1322
1323             if (conversion == null) {
1324                 Type resultType = ValidateCoalesceArgTypes(left.Type, right.Type);
1325                 return new SimpleBinaryExpression(ExpressionType.Coalesce, left, right, resultType);
1326             }
1327
1328             if (left.Type.IsValueType && !TypeUtils.IsNullableType(left.Type)) {
1329                 throw Error.CoalesceUsedOnNonNullType();
1330             }
1331
1332             Type delegateType = conversion.Type;
1333             Debug.Assert(typeof(System.MulticastDelegate).IsAssignableFrom(delegateType) && delegateType != typeof(System.MulticastDelegate));
1334             MethodInfo method = delegateType.GetMethod("Invoke");
1335             if (method.ReturnType == typeof(void)) {
1336                 throw Error.UserDefinedOperatorMustNotBeVoid(conversion);
1337             }
1338             ParameterInfo[] pms = method.GetParametersCached();
1339             Debug.Assert(pms.Length == conversion.Parameters.Count);
1340             if (pms.Length != 1) {
1341                 throw Error.IncorrectNumberOfMethodCallArguments(conversion);
1342             }
1343             // The return type must match exactly.
1344             // CONSIDER: We could weaken this restriction and
1345             // CONSIDER: say that the return type must be assignable to from
1346             // CONSIDER: the return type of the lambda.
1347             if (!TypeUtils.AreEquivalent(method.ReturnType, right.Type)) {
1348                 throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString());
1349             }
1350             // The parameter of the conversion lambda must either be assignable
1351             // from the erased or unerased type of the left hand side.
1352             if (!ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) &&
1353                 !ParameterIsAssignable(pms[0], left.Type)) {
1354                 throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString());
1355             }
1356             return new CoalesceConversionBinaryExpression(left, right, conversion);
1357         }
1358
1359
1360         private static Type ValidateCoalesceArgTypes(Type left, Type right) {
1361             Type leftStripped = TypeUtils.GetNonNullableType(left);
1362             if (left.IsValueType && !TypeUtils.IsNullableType(left)) {
1363                 throw Error.CoalesceUsedOnNonNullType();
1364             } else if (TypeUtils.IsNullableType(left) && TypeUtils.IsImplicitlyConvertible(right, leftStripped)) {
1365                 return leftStripped;
1366             } else if (TypeUtils.IsImplicitlyConvertible(right, left)) {
1367                 return left;
1368             } else if (TypeUtils.IsImplicitlyConvertible(leftStripped, right)) {
1369                 return right;
1370             } else {
1371                 throw Error.ArgumentTypesMustMatch();
1372             }
1373         }
1374
1375
1376
1377         #endregion
1378
1379         #region Arithmetic Expressions
1380
1381
1382         /// <summary>
1383         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that does not have overflow checking.
1384         /// </summary>
1385         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1386         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1387         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Add"/> 
1388         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1389         public static BinaryExpression Add(Expression left, Expression right) {
1390             return Add(left, right, null);
1391         }
1392
1393         /// <summary>
1394         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that does not have overflow checking.
1395         /// </summary>
1396         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1397         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1398         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1399         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Add"/> 
1400         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1401         /// </returns>
1402         public static BinaryExpression Add(Expression left, Expression right, MethodInfo method) {
1403             RequiresCanRead(left, "left");
1404             RequiresCanRead(right, "right");
1405             if (method == null) {
1406                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1407                     return new SimpleBinaryExpression(ExpressionType.Add, left, right, left.Type);
1408                 }
1409                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true);
1410             }
1411             return GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true);
1412         }
1413
1414
1415         /// <summary>
1416         /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking.
1417         /// </summary>
1418         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1419         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1420         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> 
1421         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1422         public static BinaryExpression AddAssign(Expression left, Expression right) {
1423             return AddAssign(left, right, null, null);
1424         }
1425
1426         /// <summary>
1427         /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking.
1428         /// </summary>
1429         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1430         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1431         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1432         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> 
1433         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1434         /// </returns>
1435         public static BinaryExpression AddAssign(Expression left, Expression right, MethodInfo method) {
1436             return AddAssign(left, right, method, null);
1437         }
1438
1439         /// <summary>
1440         /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that does not have overflow checking.
1441         /// </summary>
1442         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1443         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1444         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1445         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1446         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssign"/> 
1447         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1448         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1449         /// </returns>
1450
1451         public static BinaryExpression AddAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1452             RequiresCanRead(left, "left");
1453             RequiresCanWrite(left, "left");
1454             RequiresCanRead(right, "right");
1455             if (method == null) {
1456                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1457                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1458                     if (conversion != null) {
1459                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1460                     }
1461                     return new SimpleBinaryExpression(ExpressionType.AddAssign, left, right, left.Type);
1462                 }
1463                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AddAssign, "op_Addition", left, right, conversion, true);
1464             }
1465             return GetMethodBasedAssignOperator(ExpressionType.AddAssign, left, right, method, conversion, true);
1466         }
1467
1468         private static void ValidateOpAssignConversionLambda(LambdaExpression conversion, Expression left, MethodInfo method, ExpressionType nodeType) {
1469             Type delegateType = conversion.Type;
1470             Debug.Assert(typeof(System.MulticastDelegate).IsAssignableFrom(delegateType) && delegateType != typeof(System.MulticastDelegate));
1471             MethodInfo mi = delegateType.GetMethod("Invoke");
1472             ParameterInfo[] pms = mi.GetParametersCached();
1473             Debug.Assert(pms.Length == conversion.Parameters.Count);
1474             if (pms.Length != 1) {
1475                 throw Error.IncorrectNumberOfMethodCallArguments(conversion);
1476             }
1477             if (!TypeUtils.AreEquivalent(mi.ReturnType, left.Type)) {
1478                 throw Error.OperandTypesDoNotMatchParameters(nodeType, conversion.ToString());
1479             }
1480             if (method != null) {
1481                 // The parameter type of conversion lambda must be the same as the return type of the overload method
1482                 if (!TypeUtils.AreEquivalent(pms[0].ParameterType, method.ReturnType)) {
1483                     throw Error.OverloadOperatorTypeDoesNotMatchConversionType(nodeType, conversion.ToString());
1484                 }
1485             }
1486         }
1487
1488
1489         /// <summary>
1490         /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking.
1491         /// </summary>
1492         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1493         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1494         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to 
1495         /// <see cref="F:ExpressionType.AddAssignChecked"/> and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> 
1496         /// properties set to the specified values.
1497         /// </returns>
1498         public static BinaryExpression AddAssignChecked(Expression left, Expression right) {
1499             return AddAssignChecked(left, right, null);
1500         }
1501
1502         /// <summary>
1503         /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking.
1504         /// </summary>
1505         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1506         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1507         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1508         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssignChecked"/> 
1509         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1510         /// </returns>
1511         public static BinaryExpression AddAssignChecked(Expression left, Expression right, MethodInfo method) {
1512             return AddAssignChecked(left, right, method, null);
1513         }
1514
1515         /// <summary>
1516         /// Creates a <see cref="BinaryExpression"/> that represents an addition assignment operation that has overflow checking.
1517         /// </summary>
1518         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1519         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1520         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1521         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1522         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddAssignChecked"/> 
1523         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1524         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1525         /// </returns>
1526         public static BinaryExpression AddAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1527             RequiresCanRead(left, "left");
1528             RequiresCanWrite(left, "left");
1529             RequiresCanRead(right, "right");
1530
1531             if (method == null) {
1532                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1533                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1534                     if (conversion != null) {
1535                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1536                     }
1537                     return new SimpleBinaryExpression(ExpressionType.AddAssignChecked, left, right, left.Type);
1538                 }
1539                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AddAssignChecked, "op_Addition", left, right, conversion, true);
1540             }
1541             return GetMethodBasedAssignOperator(ExpressionType.AddAssignChecked, left, right, method, conversion, true);
1542         }
1543
1544
1545         /// <summary>
1546         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that has overflow checking.
1547         /// </summary>
1548         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1549         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1550         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddChecked"/> 
1551         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1552         public static BinaryExpression AddChecked(Expression left, Expression right) {
1553             return AddChecked(left, right, null);
1554         }
1555
1556         /// <summary>
1557         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic addition operation that has overflow checking.
1558         /// </summary>
1559         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1560         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1561         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1562         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AddChecked"/> 
1563         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1564         /// </returns>
1565         public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method) {
1566             RequiresCanRead(left, "left");
1567             RequiresCanRead(right, "right");
1568             if (method == null) {
1569                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1570                     return new SimpleBinaryExpression(ExpressionType.AddChecked, left, right, left.Type);
1571                 }
1572                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.AddChecked, "op_Addition", left, right, false);
1573             }
1574             return GetMethodBasedBinaryOperator(ExpressionType.AddChecked, left, right, method, true);
1575         }
1576
1577
1578         /// <summary>
1579         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that does not have overflow checking.
1580         /// </summary>
1581         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1582         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1583         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Subtract"/> 
1584         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1585         public static BinaryExpression Subtract(Expression left, Expression right) {
1586             return Subtract(left, right, null);
1587         }
1588
1589         /// <summary>
1590         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that does not have overflow checking.
1591         /// </summary>
1592         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1593         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1594         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1595         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Subtract"/> 
1596         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1597         /// </returns>
1598         public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method) {
1599             RequiresCanRead(left, "left");
1600             RequiresCanRead(right, "right");
1601             if (method == null) {
1602                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1603                     return new SimpleBinaryExpression(ExpressionType.Subtract, left, right, left.Type);
1604                 }
1605                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Subtract, "op_Subtraction", left, right, true);
1606             }
1607             return GetMethodBasedBinaryOperator(ExpressionType.Subtract, left, right, method, true);
1608         }
1609
1610
1611         /// <summary>
1612         /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking.
1613         /// </summary>
1614         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1615         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1616         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> 
1617         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1618         public static BinaryExpression SubtractAssign(Expression left, Expression right) {
1619             return SubtractAssign(left, right, null, null);
1620         }
1621
1622         /// <summary>
1623         /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking.
1624         /// </summary>
1625         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1626         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1627         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1628         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> 
1629         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1630         /// </returns>
1631         public static BinaryExpression SubtractAssign(Expression left, Expression right, MethodInfo method) {
1632             return SubtractAssign(left, right, method, null);
1633         }
1634
1635         /// <summary>
1636         /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that does not have overflow checking.
1637         /// </summary>
1638         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1639         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1640         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1641         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1642         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssign"/> 
1643         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1644         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1645         /// </returns>
1646         public static BinaryExpression SubtractAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1647             RequiresCanRead(left, "left");
1648             RequiresCanWrite(left, "left");
1649             RequiresCanRead(right, "right");
1650             if (method == null) {
1651                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1652                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1653                     if (conversion != null) {
1654                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1655                     }
1656                     return new SimpleBinaryExpression(ExpressionType.SubtractAssign, left, right, left.Type);
1657                 }
1658                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.SubtractAssign, "op_Subtraction", left, right, conversion, true);
1659             }
1660             return GetMethodBasedAssignOperator(ExpressionType.SubtractAssign, left, right, method, conversion, true);
1661         }
1662
1663
1664         /// <summary>
1665         /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking.
1666         /// </summary>
1667         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1668         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1669         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> 
1670         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1671         public static BinaryExpression SubtractAssignChecked(Expression left, Expression right) {
1672             return SubtractAssignChecked(left, right, null);
1673         }
1674
1675         /// <summary>
1676         /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking.
1677         /// </summary>
1678         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1679         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1680         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1681         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> 
1682         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1683         /// </returns>
1684         public static BinaryExpression SubtractAssignChecked(Expression left, Expression right, MethodInfo method) {
1685             return SubtractAssignChecked(left, right, method, null);
1686         }
1687
1688         /// <summary>
1689         /// Creates a <see cref="BinaryExpression"/> that represents a subtraction assignment operation that has overflow checking.
1690         /// </summary>
1691         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1692         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1693         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1694         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1695         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractAssignChecked"/> 
1696         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1697         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1698         /// </returns>
1699         public static BinaryExpression SubtractAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1700             RequiresCanRead(left, "left");
1701             RequiresCanWrite(left, "left");
1702             RequiresCanRead(right, "right");
1703             if (method == null) {
1704                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1705                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1706                     if (conversion != null) {
1707                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1708                     }
1709                     return new SimpleBinaryExpression(ExpressionType.SubtractAssignChecked, left, right, left.Type);
1710                 }
1711                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.SubtractAssignChecked, "op_Subtraction", left, right, conversion, true);
1712             }
1713             return GetMethodBasedAssignOperator(ExpressionType.SubtractAssignChecked, left, right, method, conversion, true);
1714         }
1715
1716
1717         /// <summary>
1718         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that has overflow checking.
1719         /// </summary>
1720         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1721         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1722         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractChecked"/> 
1723         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1724         public static BinaryExpression SubtractChecked(Expression left, Expression right) {
1725             return SubtractChecked(left, right, null);
1726         }
1727
1728         /// <summary>
1729         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic subtraction operation that has overflow checking.
1730         /// </summary>
1731         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1732         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1733         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1734         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.SubtractChecked"/> 
1735         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1736         /// </returns>
1737         public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method) {
1738             RequiresCanRead(left, "left");
1739             RequiresCanRead(right, "right");
1740             if (method == null) {
1741                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1742                     return new SimpleBinaryExpression(ExpressionType.SubtractChecked, left, right, left.Type);
1743                 }
1744                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.SubtractChecked, "op_Subtraction", left, right, true);
1745             }
1746             return GetMethodBasedBinaryOperator(ExpressionType.SubtractChecked, left, right, method, true);
1747         }
1748
1749
1750         /// <summary>
1751         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic division operation.
1752         /// </summary>
1753         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1754         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1755         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Divide"/> 
1756         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1757         public static BinaryExpression Divide(Expression left, Expression right) {
1758             return Divide(left, right, null);
1759         }
1760
1761         /// <summary>
1762         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic division operation.
1763         /// </summary>
1764         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1765         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1766         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1767         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Divide"/> 
1768         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1769         /// </returns>
1770         public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method) {
1771             RequiresCanRead(left, "left");
1772             RequiresCanRead(right, "right");
1773             if (method == null) {
1774                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1775                     return new SimpleBinaryExpression(ExpressionType.Divide, left, right, left.Type);
1776                 }
1777                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Divide, "op_Division", left, right, true);
1778             }
1779             return GetMethodBasedBinaryOperator(ExpressionType.Divide, left, right, method, true);
1780         }
1781
1782
1783         /// <summary>
1784         /// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking.
1785         /// </summary>
1786         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1787         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1788         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> 
1789         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1790         public static BinaryExpression DivideAssign(Expression left, Expression right) {
1791             return DivideAssign(left, right, null, null);
1792         }
1793
1794         /// <summary>
1795         /// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking.
1796         /// </summary>
1797         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1798         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1799         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1800         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> 
1801         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1802         /// </returns>
1803         public static BinaryExpression DivideAssign(Expression left, Expression right, MethodInfo method) {
1804             return DivideAssign(left, right, method, null);
1805         }
1806
1807         /// <summary>
1808         /// Creates a <see cref="BinaryExpression"/> that represents a division assignment operation that does not have overflow checking.
1809         /// </summary>
1810         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1811         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1812         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1813         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1814         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.DivideAssign"/> 
1815         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1816         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1817         /// </returns>
1818         public static BinaryExpression DivideAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1819             RequiresCanRead(left, "left");
1820             RequiresCanWrite(left, "left");
1821             RequiresCanRead(right, "right");
1822             if (method == null) {
1823                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1824                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1825                     if (conversion != null) {
1826                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1827                     }
1828                     return new SimpleBinaryExpression(ExpressionType.DivideAssign, left, right, left.Type);
1829                 }
1830                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.DivideAssign, "op_Division", left, right, conversion, true);
1831             }
1832             return GetMethodBasedAssignOperator(ExpressionType.DivideAssign, left, right, method, conversion, true);
1833         }
1834
1835
1836         /// <summary>
1837         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic remainder operation.
1838         /// </summary>
1839         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1840         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1841         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Modulo"/> 
1842         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1843         public static BinaryExpression Modulo(Expression left, Expression right) {
1844             return Modulo(left, right, null);
1845         }
1846
1847         /// <summary>
1848         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic remainder operation.
1849         /// </summary>
1850         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1851         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1852         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1853         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Modulo"/> 
1854         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1855         /// </returns>
1856         public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method) {
1857             RequiresCanRead(left, "left");
1858             RequiresCanRead(right, "right");
1859             if (method == null) {
1860                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1861                     return new SimpleBinaryExpression(ExpressionType.Modulo, left, right, left.Type);
1862                 }
1863                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Modulo, "op_Modulus", left, right, true);
1864             }
1865             return GetMethodBasedBinaryOperator(ExpressionType.Modulo, left, right, method, true);
1866         }
1867
1868
1869         /// <summary>
1870         /// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation.
1871         /// </summary>
1872         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1873         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1874         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> 
1875         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1876         public static BinaryExpression ModuloAssign(Expression left, Expression right) {
1877             return ModuloAssign(left, right, null, null);
1878         }
1879
1880         /// <summary>
1881         /// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation.
1882         /// </summary>
1883         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1884         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1885         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1886         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> 
1887         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1888         /// </returns>
1889         public static BinaryExpression ModuloAssign(Expression left, Expression right, MethodInfo method) {
1890             return ModuloAssign(left, right, method, null);
1891         }
1892
1893         /// <summary>
1894         /// Creates a <see cref="BinaryExpression"/> that represents a remainder assignment operation.
1895         /// </summary>
1896         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1897         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1898         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1899         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1900         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ModuloAssign"/> 
1901         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1902         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1903         /// </returns>
1904         public static BinaryExpression ModuloAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1905             RequiresCanRead(left, "left");
1906             RequiresCanWrite(left, "left");
1907             RequiresCanRead(right, "right");
1908             if (method == null) {
1909                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1910                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1911                     if (conversion != null) {
1912                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1913                     }
1914                     return new SimpleBinaryExpression(ExpressionType.ModuloAssign, left, right, left.Type);
1915                 }
1916                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.ModuloAssign, "op_Modulus", left, right, conversion, true);
1917             }
1918             return GetMethodBasedAssignOperator(ExpressionType.ModuloAssign, left, right, method, conversion, true);
1919         }
1920
1921
1922         /// <summary>
1923         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that does not have overflow checking.
1924         /// </summary>
1925         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1926         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1927         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Multiply"/> 
1928         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1929         public static BinaryExpression Multiply(Expression left, Expression right) {
1930             return Multiply(left, right, null);
1931         }
1932
1933         /// <summary>
1934         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that does not have overflow checking.
1935         /// </summary>
1936         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1937         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1938         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1939         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Multiply"/> 
1940         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1941         /// </returns>
1942         public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method) {
1943             RequiresCanRead(left, "left");
1944             RequiresCanRead(right, "right");
1945             if (method == null) {
1946                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1947                     return new SimpleBinaryExpression(ExpressionType.Multiply, left, right, left.Type);
1948                 }
1949                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Multiply, "op_Multiply", left, right, true);
1950             }
1951             return GetMethodBasedBinaryOperator(ExpressionType.Multiply, left, right, method, true);
1952         }
1953
1954
1955         /// <summary>
1956         /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking.
1957         /// </summary>
1958         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1959         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1960         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> 
1961         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
1962         public static BinaryExpression MultiplyAssign(Expression left, Expression right) {
1963             return MultiplyAssign(left, right, null, null);
1964         }
1965
1966         /// <summary>
1967         /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking.
1968         /// </summary>
1969         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1970         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1971         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1972         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> 
1973         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
1974         /// </returns>
1975         public static BinaryExpression MultiplyAssign(Expression left, Expression right, MethodInfo method) {
1976             return MultiplyAssign(left, right, method, null);
1977         }
1978
1979         /// <summary>
1980         /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that does not have overflow checking.
1981         /// </summary>
1982         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
1983         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
1984         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
1985         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
1986         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssign"/> 
1987         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
1988         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
1989         /// </returns>
1990         public static BinaryExpression MultiplyAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
1991             RequiresCanRead(left, "left");
1992             RequiresCanWrite(left, "left");
1993             RequiresCanRead(right, "right");
1994             if (method == null) {
1995                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
1996                     // conversion is not supported for binary ops on arithmetic types without operator overloading
1997                     if (conversion != null) {
1998                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
1999                     }
2000                     return new SimpleBinaryExpression(ExpressionType.MultiplyAssign, left, right, left.Type);
2001                 }
2002                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.MultiplyAssign, "op_Multiply", left, right, conversion, true);
2003             }
2004             return GetMethodBasedAssignOperator(ExpressionType.MultiplyAssign, left, right, method, conversion, true);
2005         }
2006
2007
2008         /// <summary>
2009         /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking.
2010         /// </summary>
2011         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2012         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2013         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> 
2014         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2015         public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right) {
2016             return MultiplyAssignChecked(left, right, null);
2017         }
2018
2019         /// <summary>
2020         /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking.
2021         /// </summary>
2022         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2023         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2024         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2025         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> 
2026         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2027         /// </returns>
2028         public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right, MethodInfo method) {
2029             return MultiplyAssignChecked(left, right, method, null);
2030         }
2031
2032         /// <summary>
2033         /// Creates a <see cref="BinaryExpression"/> that represents a multiplication assignment operation that has overflow checking.
2034         /// </summary>
2035         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2036         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2037         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2038         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2039         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyAssignChecked"/> 
2040         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2041         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2042         /// </returns>
2043         public static BinaryExpression MultiplyAssignChecked(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2044             RequiresCanRead(left, "left");
2045             RequiresCanWrite(left, "left");
2046             RequiresCanRead(right, "right");
2047             if (method == null) {
2048                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
2049                     // conversion is not supported for binary ops on arithmetic types without operator overloading
2050                     if (conversion != null) {
2051                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
2052                     }
2053                     return new SimpleBinaryExpression(ExpressionType.MultiplyAssignChecked, left, right, left.Type);
2054                 }
2055                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.MultiplyAssignChecked, "op_Multiply", left, right, conversion, true);
2056             }
2057             return GetMethodBasedAssignOperator(ExpressionType.MultiplyAssignChecked, left, right, method, conversion, true);
2058         }
2059
2060
2061         /// <summary>
2062         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that has overflow checking.
2063         /// </summary>
2064         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2065         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2066         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyChecked"/> 
2067         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2068         public static BinaryExpression MultiplyChecked(Expression left, Expression right) {
2069             return MultiplyChecked(left, right, null);
2070         }
2071
2072         /// <summary>
2073         /// Creates a <see cref="BinaryExpression"/> that represents an arithmetic multiplication operation that has overflow checking.
2074         /// </summary>
2075         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2076         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2077         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2078         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.MultiplyChecked"/> 
2079         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2080         /// </returns>
2081         public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method) {
2082             RequiresCanRead(left, "left");
2083             RequiresCanRead(right, "right");
2084             if (method == null) {
2085                 if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
2086                     return new SimpleBinaryExpression(ExpressionType.MultiplyChecked, left, right, left.Type);
2087                 }
2088                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.MultiplyChecked, "op_Multiply", left, right, true);
2089             }
2090             return GetMethodBasedBinaryOperator(ExpressionType.MultiplyChecked, left, right, method, true);
2091         }
2092
2093         private static bool IsSimpleShift(Type left, Type right) {
2094             return TypeUtils.IsInteger(left)
2095                 && TypeUtils.GetNonNullableType(right) == typeof(int);
2096         }
2097
2098         private static Type GetResultTypeOfShift(Type left, Type right) {
2099             if (!left.IsNullableType() && right.IsNullableType()) {
2100                 // lift the result type to Nullable<T>
2101                 return typeof(Nullable<>).MakeGenericType(left);
2102             }
2103             return left;
2104         }
2105
2106
2107         /// <summary>
2108         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise left-shift operation.
2109         /// </summary>
2110         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2111         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2112         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShift"/> 
2113         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2114         public static BinaryExpression LeftShift(Expression left, Expression right) {
2115             return LeftShift(left, right, null);
2116         }
2117
2118         /// <summary>
2119         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise left-shift operation.
2120         /// </summary>
2121         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2122         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2123         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2124         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShift"/> 
2125         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2126         /// </returns>
2127         public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) {
2128             RequiresCanRead(left, "left");
2129             RequiresCanRead(right, "right");
2130             if (method == null) {
2131                 if (IsSimpleShift(left.Type, right.Type)) {
2132                     Type resultType = GetResultTypeOfShift(left.Type, right.Type);
2133                     return new SimpleBinaryExpression(ExpressionType.LeftShift, left, right, resultType);
2134                 }
2135                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.LeftShift, "op_LeftShift", left, right, true);
2136             }
2137             return GetMethodBasedBinaryOperator(ExpressionType.LeftShift, left, right, method, true);
2138         }
2139
2140
2141         /// <summary>
2142         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation.
2143         /// </summary>
2144         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2145         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2146         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> 
2147         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2148         public static BinaryExpression LeftShiftAssign(Expression left, Expression right) {
2149             return LeftShiftAssign(left, right, null, null);
2150         }
2151
2152         /// <summary>
2153         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation.
2154         /// </summary>
2155         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2156         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2157         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2158         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> 
2159         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2160         /// </returns>
2161         public static BinaryExpression LeftShiftAssign(Expression left, Expression right, MethodInfo method) {
2162             return LeftShiftAssign(left, right, method, null);
2163         }
2164
2165         /// <summary>
2166         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise left-shift assignment operation.
2167         /// </summary>
2168         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2169         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2170         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2171         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2172         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.LeftShiftAssign"/> 
2173         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2174         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2175         /// </returns>
2176         public static BinaryExpression LeftShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2177             RequiresCanRead(left, "left");
2178             RequiresCanWrite(left, "left");
2179             RequiresCanRead(right, "right");
2180             if (method == null) {
2181                 if (IsSimpleShift(left.Type, right.Type)) {
2182                     // conversion is not supported for binary ops on arithmetic types without operator overloading
2183                     if (conversion != null) {
2184                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
2185                     }
2186                     Type resultType = GetResultTypeOfShift(left.Type, right.Type);
2187                     return new SimpleBinaryExpression(ExpressionType.LeftShiftAssign, left, right, resultType);
2188                 }
2189                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.LeftShiftAssign, "op_LeftShift", left, right, conversion, true);
2190             }
2191             return GetMethodBasedAssignOperator(ExpressionType.LeftShiftAssign, left, right, method, conversion, true);
2192         }
2193
2194
2195         /// <summary>
2196         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise right-shift operation.
2197         /// </summary>
2198         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2199         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2200         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShift"/> 
2201         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2202         public static BinaryExpression RightShift(Expression left, Expression right) {
2203             return RightShift(left, right, null);
2204         }
2205
2206         /// <summary>
2207         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise right-shift operation.
2208         /// </summary>
2209         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2210         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2211         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2212         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShift"/> 
2213         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2214         /// </returns>
2215         public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) {
2216             RequiresCanRead(left, "left");
2217             RequiresCanRead(right, "right");
2218             if (method == null) {
2219                 if (IsSimpleShift(left.Type, right.Type)) {
2220                     Type resultType = GetResultTypeOfShift(left.Type, right.Type);
2221                     return new SimpleBinaryExpression(ExpressionType.RightShift, left, right, resultType);
2222                 }
2223                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.RightShift, "op_RightShift", left, right, true);
2224             }
2225             return GetMethodBasedBinaryOperator(ExpressionType.RightShift, left, right, method, true);
2226         }
2227
2228
2229         /// <summary>
2230         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation.
2231         /// </summary>
2232         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2233         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2234         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> 
2235         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2236         public static BinaryExpression RightShiftAssign(Expression left, Expression right) {
2237             return RightShiftAssign(left, right, null, null);
2238         }
2239
2240         /// <summary>
2241         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation.
2242         /// </summary>
2243         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2244         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2245         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2246         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> 
2247         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2248         /// </returns>
2249         public static BinaryExpression RightShiftAssign(Expression left, Expression right, MethodInfo method) {
2250             return RightShiftAssign(left, right, method, null);
2251         }
2252
2253         /// <summary>
2254         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise right-shift assignment operation.
2255         /// </summary>
2256         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2257         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2258         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2259         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2260         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.RightShiftAssign"/> 
2261         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2262         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2263         /// </returns>
2264         public static BinaryExpression RightShiftAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2265             RequiresCanRead(left, "left");
2266             RequiresCanWrite(left, "left");
2267             RequiresCanRead(right, "right");
2268             if (method == null) {
2269                 if (IsSimpleShift(left.Type, right.Type)) {
2270                     // conversion is not supported for binary ops on arithmetic types without operator overloading
2271                     if (conversion != null) {
2272                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
2273                     }
2274                     Type resultType = GetResultTypeOfShift(left.Type, right.Type);
2275                     return new SimpleBinaryExpression(ExpressionType.RightShiftAssign, left, right, resultType);
2276                 }
2277                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.RightShiftAssign, "op_RightShift", left, right, conversion, true);
2278             }
2279             return GetMethodBasedAssignOperator(ExpressionType.RightShiftAssign, left, right, method, conversion, true);
2280         }
2281
2282
2283         /// <summary>
2284         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise AND operation.
2285         /// </summary>
2286         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2287         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2288         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.And"/> 
2289         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2290         public static BinaryExpression And(Expression left, Expression right) {
2291             return And(left, right, null);
2292         }
2293
2294         /// <summary>
2295         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise AND operation.
2296         /// </summary>
2297         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2298         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2299         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2300         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.And"/> 
2301         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2302         /// </returns>
2303         public static BinaryExpression And(Expression left, Expression right, MethodInfo method) {
2304             RequiresCanRead(left, "left");
2305             RequiresCanRead(right, "right");
2306             if (method == null) {
2307                 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) {
2308                     return new SimpleBinaryExpression(ExpressionType.And, left, right, left.Type);
2309                 }
2310                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.And, "op_BitwiseAnd", left, right, true);
2311             }
2312             return GetMethodBasedBinaryOperator(ExpressionType.And, left, right, method, true);
2313         }
2314
2315
2316         /// <summary>
2317         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation.
2318         /// </summary>
2319         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2320         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2321         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> 
2322         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2323         public static BinaryExpression AndAssign(Expression left, Expression right) {
2324             return AndAssign(left, right, null, null);
2325         }
2326
2327         /// <summary>
2328         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation.
2329         /// </summary>
2330         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2331         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2332         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2333         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> 
2334         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2335         /// </returns>
2336         public static BinaryExpression AndAssign(Expression left, Expression right, MethodInfo method) {
2337             return AndAssign(left, right, method, null);
2338         }
2339
2340         /// <summary>
2341         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise AND assignment operation.
2342         /// </summary>
2343         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2344         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2345         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2346         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2347         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.AndAssign"/> 
2348         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2349         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2350         /// </returns>
2351         public static BinaryExpression AndAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2352             RequiresCanRead(left, "left");
2353             RequiresCanWrite(left, "left");
2354             RequiresCanRead(right, "right");
2355             if (method == null) {
2356                 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) {
2357                     // conversion is not supported for binary ops on arithmetic types without operator overloading
2358                     if (conversion != null) {
2359                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
2360                     }
2361                     return new SimpleBinaryExpression(ExpressionType.AndAssign, left, right, left.Type);
2362                 }
2363                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.AndAssign, "op_BitwiseAnd", left, right, conversion, true);
2364             }
2365             return GetMethodBasedAssignOperator(ExpressionType.AndAssign, left, right, method, conversion, true);
2366         }
2367
2368
2369         /// <summary>
2370         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise OR operation.
2371         /// </summary>
2372         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2373         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2374         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Or"/> 
2375         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2376         public static BinaryExpression Or(Expression left, Expression right) {
2377             return Or(left, right, null);
2378         }
2379
2380         /// <summary>
2381         /// Creates a <see cref="BinaryExpression"/> that represents an bitwise OR operation.
2382         /// </summary>
2383         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2384         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2385         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2386         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Or"/> 
2387         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2388         /// </returns>
2389         public static BinaryExpression Or(Expression left, Expression right, MethodInfo method) {
2390             RequiresCanRead(left, "left");
2391             RequiresCanRead(right, "right");
2392             if (method == null) {
2393                 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) {
2394                     return new SimpleBinaryExpression(ExpressionType.Or, left, right, left.Type);
2395                 }
2396                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Or, "op_BitwiseOr", left, right, true);
2397             }
2398             return GetMethodBasedBinaryOperator(ExpressionType.Or, left, right, method, true);
2399         }
2400
2401
2402         /// <summary>
2403         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation.
2404         /// </summary>
2405         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2406         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2407         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> 
2408         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2409         public static BinaryExpression OrAssign(Expression left, Expression right) {
2410             return OrAssign(left, right, null, null);
2411         }
2412
2413         /// <summary>
2414         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation.
2415         /// </summary>
2416         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2417         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2418         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2419         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> 
2420         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2421         /// </returns>
2422         public static BinaryExpression OrAssign(Expression left, Expression right, MethodInfo method) {
2423             return OrAssign(left, right, method, null);
2424         }
2425
2426         /// <summary>
2427         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise OR assignment operation.
2428         /// </summary>
2429         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2430         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2431         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2432         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2433         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.OrAssign"/> 
2434         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2435         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2436         /// </returns>
2437         public static BinaryExpression OrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2438             RequiresCanRead(left, "left");
2439             RequiresCanWrite(left, "left");
2440             RequiresCanRead(right, "right");
2441             if (method == null) {
2442                 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) {
2443                     // conversion is not supported for binary ops on arithmetic types without operator overloading
2444                     if (conversion != null) {
2445                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
2446                     }
2447                     return new SimpleBinaryExpression(ExpressionType.OrAssign, left, right, left.Type);
2448                 }
2449                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.OrAssign, "op_BitwiseOr", left, right, conversion, true);
2450             }
2451             return GetMethodBasedAssignOperator(ExpressionType.OrAssign, left, right, method, conversion, true);
2452         }
2453
2454         /// <summary>
2455         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR operation, using op_ExclusiveOr for user-defined types.
2456         /// </summary>
2457         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2458         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2459         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOr"/> 
2460         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2461         public static BinaryExpression ExclusiveOr(Expression left, Expression right) {
2462             return ExclusiveOr(left, right, null);
2463         }
2464
2465         /// <summary>
2466         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR operation, using op_ExclusiveOr for user-defined types.
2467         /// </summary>
2468         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2469         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2470         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2471         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOr"/> 
2472         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2473         /// </returns>
2474         public static BinaryExpression ExclusiveOr(Expression left, Expression right, MethodInfo method) {
2475             RequiresCanRead(left, "left");
2476             RequiresCanRead(right, "right");
2477             if (method == null) {
2478                 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) {
2479                     return new SimpleBinaryExpression(ExpressionType.ExclusiveOr, left, right, left.Type);
2480                 }
2481                 return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.ExclusiveOr, "op_ExclusiveOr", left, right, true);
2482             }
2483             return GetMethodBasedBinaryOperator(ExpressionType.ExclusiveOr, left, right, method, true);
2484         }
2485
2486         /// <summary>
2487         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types.
2488         /// </summary>
2489         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2490         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2491         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> 
2492         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2493         public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right) {
2494             return ExclusiveOrAssign(left, right, null, null);
2495         }
2496
2497         /// <summary>
2498         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types.
2499         /// </summary>
2500         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2501         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2502         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2503         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> 
2504         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2505         /// </returns>
2506         public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right, MethodInfo method) {
2507             return ExclusiveOrAssign(left, right, method, null);
2508         }
2509
2510         /// <summary>
2511         /// Creates a <see cref="BinaryExpression"/> that represents a bitwise or logical XOR assignment operation, using op_ExclusiveOr for user-defined types.
2512         /// </summary>
2513         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2514         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2515         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2516         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2517         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.ExclusiveOrAssign"/> 
2518         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2519         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2520         /// </returns>
2521         public static BinaryExpression ExclusiveOrAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2522             RequiresCanRead(left, "left");
2523             RequiresCanWrite(left, "left");
2524             RequiresCanRead(right, "right");
2525             if (method == null) {
2526                 if (left.Type == right.Type && TypeUtils.IsIntegerOrBool(left.Type)) {
2527                     // conversion is not supported for binary ops on arithmetic types without operator overloading
2528                     if (conversion != null) {
2529                         throw Error.ConversionIsNotSupportedForArithmeticTypes();
2530                     }
2531                     return new SimpleBinaryExpression(ExpressionType.ExclusiveOrAssign, left, right, left.Type);
2532                 }
2533                 return GetUserDefinedAssignOperatorOrThrow(ExpressionType.ExclusiveOrAssign, "op_ExclusiveOr", left, right, conversion, true);
2534             }
2535             return GetMethodBasedAssignOperator(ExpressionType.ExclusiveOrAssign, left, right, method, conversion, true);
2536         }
2537
2538         /// <summary>
2539         /// Creates a <see cref="BinaryExpression"/> that represents raising a number to a power.
2540         /// </summary>
2541         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2542         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2543         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Power"/> 
2544         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2545         public static BinaryExpression Power(Expression left, Expression right) {
2546             return Power(left, right, null);
2547         }
2548
2549         /// <summary>
2550         /// Creates a <see cref="BinaryExpression"/> that represents raising a number to a power.
2551         /// </summary>
2552         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2553         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2554         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2555         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.Power"/> 
2556         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2557         /// </returns>
2558         public static BinaryExpression Power(Expression left, Expression right, MethodInfo method) {
2559             RequiresCanRead(left, "left");
2560             RequiresCanRead(right, "right");
2561             if (method == null) {
2562                 Type mathType = typeof(System.Math);
2563                 method = mathType.GetMethod("Pow", BindingFlags.Static | BindingFlags.Public);
2564                 if (method == null) {
2565                     throw Error.BinaryOperatorNotDefined(ExpressionType.Power, left.Type, right.Type);
2566                 }
2567             }
2568             return GetMethodBasedBinaryOperator(ExpressionType.Power, left, right, method, true);
2569         }
2570
2571
2572         /// <summary>
2573         /// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression.
2574         /// </summary>
2575         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2576         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2577         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> 
2578         /// and the <see cref="P:BinaryExpression.Left"/> and <see cref="P:BinaryExpression.Right"/> properties set to the specified values.</returns>
2579         public static BinaryExpression PowerAssign(Expression left, Expression right) {
2580             return PowerAssign(left, right, null, null);
2581         }
2582
2583         /// <summary>
2584         /// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression.
2585         /// </summary>
2586         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2587         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2588         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2589         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> 
2590         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, and <see cref="P:BinaryExpression.Method"/> properties set to the specified values.
2591         /// </returns>
2592         public static BinaryExpression PowerAssign(Expression left, Expression right, MethodInfo method) {
2593             return PowerAssign(left, right, method, null);
2594         }
2595
2596         /// <summary>
2597         /// Creates a <see cref="BinaryExpression"/> that represents raising an expression to a power and assigning the result back to the expression.
2598         /// </summary>
2599         /// <param name="left">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Left"/> property equal to.</param>
2600         /// <param name="right">An <see cref="Expression"/> to set the <see cref="P:BinaryExpression.Right"/> property equal to.</param>
2601         /// <param name="method">A <see cref="MethodInfo"/> to set the <see cref="P:BinaryExpression.Method"/> property equal to.</param>
2602         /// <param name="conversion">A <see cref="LambdaExpression"/> to set the <see cref="P:BinaryExpression.Conversion"/> property equal to.</param>
2603         /// <returns>A <see cref="BinaryExpression"/> that has the <see cref="P:Expression.NodeType"/> property equal to <see cref="F:ExpressionType.PowerAssign"/> 
2604         /// and the <see cref="P:BinaryExpression.Left"/>, <see cref="P:BinaryExpression.Right"/>, <see cref="P:BinaryExpression.Method"/>,
2605         /// and <see cref="P:BinaryExpression.Conversion"/> properties set to the specified values.
2606         /// </returns>
2607         public static BinaryExpression PowerAssign(Expression left, Expression right, MethodInfo method, LambdaExpression conversion) {
2608             RequiresCanRead(left, "left");
2609             RequiresCanWrite(left, "left");
2610             RequiresCanRead(right, "right");
2611             if (method == null) {
2612                 Type mathType = typeof(System.Math);
2613                 method = mathType.GetMethod("Pow", BindingFlags.Static | BindingFlags.Public);
2614                 if (method == null) {
2615                     throw Error.BinaryOperatorNotDefined(ExpressionType.PowerAssign, left.Type, right.Type);
2616                 }
2617             }
2618             return GetMethodBasedAssignOperator(ExpressionType.PowerAssign, left, right, method, conversion, true);
2619         }
2620
2621         #endregion
2622
2623         #region ArrayIndex Expression
2624
2625
2626         /// <summary>
2627         /// Creates a BinaryExpression that represents applying an array index operator to an array of rank one.
2628         /// </summary>
2629         /// <param name="array">An Expression to set the Left property equal to.</param>
2630         /// <param name="index">An Expression to set the Right property equal to.</param>
2631         /// <returns>A BinaryExpression that has the NodeType property equal to ArrayIndex and the Left and Right properties set to the specified values.</returns>
2632         public static BinaryExpression ArrayIndex(Expression array, Expression index) {
2633             RequiresCanRead(array, "array");
2634             RequiresCanRead(index, "index");
2635             if (index.Type != typeof(int)) {
2636                 throw Error.ArgumentMustBeArrayIndexType();
2637             }
2638
2639             Type arrayType = array.Type;
2640             if (!arrayType.IsArray) {
2641                 throw Error.ArgumentMustBeArray();
2642             }
2643             if (arrayType.GetArrayRank() != 1) {
2644                 throw Error.IncorrectNumberOfIndexes();
2645             }
2646
2647             return new SimpleBinaryExpression(ExpressionType.ArrayIndex, array, index, arrayType.GetElementType());
2648         }
2649
2650         #endregion
2651     }
2652 }