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