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