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