PageRenderTime 71ms CodeModel.GetById 12ms app.highlight 49ms RepoModel.GetById 1ms app.codeStats 0ms

/IronPython_2_0/Src/Microsoft.Scripting.Core/Ast/BinaryExpression.cs

#
C# | 1037 lines | 844 code | 86 blank | 107 comment | 257 complexity | 3824fb8da75fb591a3969955b921e3a9 MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1
  2/* ****************************************************************************
  3 *
  4 * Copyright (c) Microsoft Corporation. 
  5 *
  6 * This source code is subject to terms and conditions of the Microsoft Public License. A 
  7 * copy of the license can be found in the License.html file at the root of this distribution. If 
  8 * you cannot locate the  Microsoft Public License, please send an email to 
  9 * dlr@microsoft.com. By using this source code in any fashion, you are agreeing to be bound 
 10 * by the terms of the Microsoft Public License.
 11 *
 12 * You must not remove this notice, or any other, from this software.
 13 *
 14 *
 15 * ***************************************************************************/
 16using System; using Microsoft;
 17
 18
 19using System.Diagnostics;
 20using System.Reflection;
 21using Microsoft.Scripting.Utils;
 22using System.Text;
 23
 24namespace Microsoft.Linq.Expressions {
 25    //CONFORMING
 26    public sealed class BinaryExpression : Expression {
 27        private readonly Expression _left;
 28        private readonly Expression _right;
 29        private readonly MethodInfo _method;
 30        private readonly LambdaExpression _conversion;
 31
 32        internal BinaryExpression(Annotations annotations, ExpressionType nodeType, Expression left, Expression right, Type type)
 33            : this(annotations, nodeType, left, right, type, null, null) {
 34        }
 35
 36        internal BinaryExpression(Annotations annotations, ExpressionType nodeType, Expression left, Expression right, Type type, MethodInfo method)
 37            : this(annotations, nodeType, left, right, type, method, null) {
 38        }
 39
 40        internal BinaryExpression(Annotations annotations,
 41                                  ExpressionType nodeType,
 42                                  Expression left,
 43                                  Expression right,
 44                                  Type type,
 45                                  MethodInfo method,
 46                                  LambdaExpression conversion)
 47
 48            : base(nodeType, type, false, annotations, true, nodeType == ExpressionType.ArrayIndex) {
 49            // Only Coalesce can have a conversion
 50            Debug.Assert(conversion == null || nodeType == ExpressionType.Coalesce);
 51
 52            _left = left;
 53            _right = right;
 54            _method = method;
 55            _conversion = conversion;
 56        }
 57
 58        public Expression Right {
 59            get { return _right; }
 60        }
 61
 62        public Expression Left {
 63            get { return _left; }
 64        }
 65
 66        public MethodInfo Method {
 67            get { return _method; }
 68        }
 69
 70        public LambdaExpression Conversion {
 71            get { return _conversion; }
 72        }
 73
 74        public bool IsLifted {
 75            get {
 76                if (this.NodeType == ExpressionType.Coalesce) {
 77                    return false;
 78                }
 79                bool leftIsNullable = TypeUtils.IsNullableType(_left.Type);
 80                if (_method != null) {
 81                    return leftIsNullable && _method.GetParametersCached()[0].ParameterType != _left.Type;
 82                }
 83                return leftIsNullable;
 84            }
 85        }
 86
 87        public bool IsLiftedToNull {
 88            get {
 89                return this.IsLifted && TypeUtils.IsNullableType(this.Type);
 90            }
 91        }
 92
 93        internal override void BuildString(StringBuilder builder) {
 94            ContractUtils.RequiresNotNull(builder, "builder");
 95
 96            switch (NodeType) {
 97                case ExpressionType.ArrayIndex:
 98                    _left.BuildString(builder);
 99                    builder.Append("[");
100                    _right.BuildString(builder);
101                    builder.Append("]");
102                    break;
103                default:
104                    string op = GetOperator();
105                    if (op != null) {
106                        builder.Append("(");
107                        _left.BuildString(builder);
108                        builder.Append(" ");
109                        builder.Append(op);
110                        builder.Append(" ");
111                        _right.BuildString(builder);
112                        builder.Append(")");
113                    } else {
114                        builder.Append(NodeType);
115                        builder.Append("(");
116                        _left.BuildString(builder);
117                        builder.Append(", ");
118                        _right.BuildString(builder);
119                        builder.Append(")");
120                    }
121                    break;
122            }
123        }
124
125        internal override Expression Accept(ExpressionTreeVisitor visitor) {
126            return visitor.VisitBinary(this);
127        }
128
129        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
130        private string GetOperator() {
131            switch (this.NodeType) {
132                case ExpressionType.Add:
133                case ExpressionType.AddChecked:
134                    return "+";
135                case ExpressionType.Subtract:
136                case ExpressionType.SubtractChecked:
137                    return "-";
138                case ExpressionType.Multiply:
139                case ExpressionType.MultiplyChecked:
140                    return "*";
141                case ExpressionType.Divide:
142                    return "/";
143                case ExpressionType.Modulo:
144                    return "%";
145                case ExpressionType.Power:
146                    return "^";
147                case ExpressionType.And:
148                    if (this.Type == typeof(bool) || this.Type == typeof(bool?)) {
149                        return "And";
150                    }
151                    return "&";
152                case ExpressionType.AndAlso:
153                    return "&&";
154                case ExpressionType.Or:
155                    if (this.Type == typeof(bool) || this.Type == typeof(bool?)) {
156                        return "Or";
157                    }
158                    return "|";
159                case ExpressionType.OrElse:
160                    return "||";
161                case ExpressionType.LessThan:
162                    return "<";
163                case ExpressionType.LessThanOrEqual:
164                    return "<=";
165                case ExpressionType.GreaterThan:
166                    return ">";
167                case ExpressionType.GreaterThanOrEqual:
168                    return ">=";
169                case ExpressionType.Equal:
170                    return "=";
171                case ExpressionType.NotEqual:
172                    return "!=";
173                case ExpressionType.Coalesce:
174                    return "??";
175                case ExpressionType.RightShift:
176                    return ">>";
177                case ExpressionType.LeftShift:
178                    return "<<";
179                case ExpressionType.ExclusiveOr:
180                    return "^";
181            }
182            return null;
183        }
184    }
185
186    public partial class Expression {
187
188        //CONFORMING
189        private static BinaryExpression GetUserDefinedBinaryOperator(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull, Annotations annotations) {
190            // try exact match first
191            MethodInfo method = GetUserDefinedBinaryOperator(binaryType, left.Type, right.Type, name);
192            if (method != null) {
193                return new BinaryExpression(annotations, binaryType, left, right, method.ReturnType, method);
194            }
195            // try lifted call
196            if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type)) {
197                Type nnLeftType = TypeUtils.GetNonNullableType(left.Type);
198                Type nnRightType = TypeUtils.GetNonNullableType(right.Type);
199                method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name);
200                if (method != null && method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) {
201                    if (method.ReturnType != typeof(bool) || liftToNull) {
202                        return new BinaryExpression(annotations, binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method);
203                    } else {
204                        return new BinaryExpression(annotations, binaryType, left, right, typeof(bool), method);
205                    }
206                }
207            }
208            return null;
209        }
210
211        //CONFORMING
212        private static BinaryExpression GetMethodBasedBinaryOperator(ExpressionType binaryType, Expression left, Expression right, MethodInfo method, bool liftToNull, Annotations annotations) {
213            System.Diagnostics.Debug.Assert(method != null);
214            ValidateOperator(method);
215            ParameterInfo[] pms = method.GetParametersCached();
216            if (pms.Length != 2)
217                throw Error.IncorrectNumberOfMethodCallArguments(method);
218            if (ParameterIsAssignable(pms[0], left.Type) && ParameterIsAssignable(pms[1], right.Type)) {
219                ValidateParamswithOperandsOrThrow(pms[0].ParameterType, left.Type, binaryType, method.Name);
220                ValidateParamswithOperandsOrThrow(pms[1].ParameterType, right.Type, binaryType, method.Name);
221                return new BinaryExpression(annotations, binaryType, left, right, method.ReturnType, method);
222
223            }
224            // check for lifted call
225            if (TypeUtils.IsNullableType(left.Type) && TypeUtils.IsNullableType(right.Type) &&
226                ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) &&
227                ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right.Type)) &&
228                method.ReturnType.IsValueType && !TypeUtils.IsNullableType(method.ReturnType)) {
229                if (method.ReturnType != typeof(bool) || liftToNull) {
230                    return new BinaryExpression(annotations, binaryType, left, right, TypeUtils.GetNullableType(method.ReturnType), method);
231                } else {
232                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool), method);
233                }
234            }
235            throw Error.OperandTypesDoNotMatchParameters(binaryType, method.Name);
236        }
237
238        //CONFORMING
239        private static BinaryExpression GetUserDefinedBinaryOperatorOrThrow(ExpressionType binaryType, string name, Expression left, Expression right, bool liftToNull, Annotations annotations) {
240            BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, name, left, right, liftToNull, annotations);
241            if (b != null) {
242                ParameterInfo[] pis = b.Method.GetParametersCached();
243                ValidateParamswithOperandsOrThrow(pis[0].ParameterType, left.Type, binaryType, name);
244                ValidateParamswithOperandsOrThrow(pis[1].ParameterType, right.Type, binaryType, name);
245                return b;
246            }
247            throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type);
248        }
249
250        //CONFORMING
251        private static MethodInfo GetUserDefinedBinaryOperator(ExpressionType binaryType, Type leftType, Type rightType, string name) {
252            // UNDONE: This algorithm is wrong, we should be checking for uniqueness and erroring if
253            // UNDONE: it is defined on both types.
254            Type[] types = new Type[] { leftType, rightType };
255            Type nnLeftType = TypeUtils.GetNonNullableType(leftType);
256            Type nnRightType = TypeUtils.GetNonNullableType(rightType);
257            BindingFlags flags = BindingFlags.Static | BindingFlags.Public | BindingFlags.NonPublic;
258            MethodInfo method = nnLeftType.GetMethod(name, flags, null, types, null);
259            if (method == null && leftType != rightType) {
260                method = nnRightType.GetMethod(name, flags, null, types, null);
261            }
262
263            if (IsLiftingConditionalLogicalOperator(leftType, rightType, method, binaryType)) {
264                method = GetUserDefinedBinaryOperator(binaryType, nnLeftType, nnRightType, name);
265            }
266            return method;
267        }
268
269        //CONFORMING
270        private static bool IsLiftingConditionalLogicalOperator(Type left, Type right, MethodInfo method, ExpressionType binaryType) {
271            return TypeUtils.IsNullableType(right) &&
272                    TypeUtils.IsNullableType(left) &&
273                    method == null &&
274                    (binaryType == ExpressionType.AndAlso || binaryType == ExpressionType.OrElse);
275        }
276
277        //CONFORMING
278        private static bool ParameterIsAssignable(ParameterInfo pi, Type argType) {
279            Type pType = pi.ParameterType;
280            if (pType.IsByRef)
281                pType = pType.GetElementType();
282            return TypeUtils.AreReferenceAssignable(pType, argType);
283        }
284
285        //CONFORMING
286        private static void ValidateParamswithOperandsOrThrow(Type paramType, Type operandType, ExpressionType exprType, string name) {
287            if (TypeUtils.IsNullableType(paramType) && !TypeUtils.IsNullableType(operandType)) {
288                throw Error.OperandTypesDoNotMatchParameters(exprType, name);
289            }
290        }
291
292        //CONFORMING
293        private static void ValidateOperator(MethodInfo method) {
294            System.Diagnostics.Debug.Assert(method != null);
295            ValidateMethodInfo(method);
296            if (!method.IsStatic)
297                throw Error.UserDefinedOperatorMustBeStatic(method);
298            if (method.ReturnType == typeof(void))
299                throw Error.UserDefinedOperatorMustNotBeVoid(method);
300        }
301
302        //TODO: consider moving to utils. It is used in many places.
303        //CONFORMING
304        private static void ValidateMethodInfo(MethodInfo method) {
305            if (method.IsGenericMethodDefinition)
306                throw Error.MethodIsGeneric(method);
307            if (method.ContainsGenericParameters)
308                throw Error.MethodContainsGenericParameters(method);
309        }
310
311        //CONFORMING
312        private static bool IsNullComparison(Expression left, Expression right) {
313            // If we have x==null, x!=null, null==x or null!=x where x is
314            // nullable but not null, then this is treated as a call to x.HasValue
315            // and is legal even if there is no equality operator defined on the
316            // type of x.
317            if (IsNullConstant(left) && !IsNullConstant(right) && TypeUtils.IsNullableType(right.Type)) {
318                return true;
319            }
320            if (IsNullConstant(right) && !IsNullConstant(left) && TypeUtils.IsNullableType(left.Type)) {
321                return true;
322            }
323            return false;
324        }
325
326        //CONFORMING
327        // Note: this has different meaning than ConstantCheck.IsNull
328        // That function attempts to determine if the result of a tree will be
329        // null at runtime. This function is used at tree construction time and
330        // only looks for a ConstantExpression with a null Value. It can't
331        // become "smarter" or that would break tree construction.
332        private static bool IsNullConstant(Expression e) {
333            var c = e as ConstantExpression;
334            return c != null && c.Value == null;
335        }
336
337        //CONFORMING
338        private static void ValidateUserDefinedConditionalLogicOperator(ExpressionType nodeType, Type left, Type right, MethodInfo method) {
339            ValidateOperator(method);
340            ParameterInfo[] pms = method.GetParametersCached();
341            if (pms.Length != 2)
342                throw Error.IncorrectNumberOfMethodCallArguments(method);
343            if (!ParameterIsAssignable(pms[0], left)) {
344                if (!(TypeUtils.IsNullableType(left) && ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left))))
345                    throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name);
346            }
347            if (!ParameterIsAssignable(pms[1], right)) {
348                if (!(TypeUtils.IsNullableType(right) && ParameterIsAssignable(pms[1], TypeUtils.GetNonNullableType(right))))
349                    throw Error.OperandTypesDoNotMatchParameters(nodeType, method.Name);
350            }
351            if (pms[0].ParameterType != pms[1].ParameterType)
352                throw Error.LogicalOperatorMustHaveConsistentTypes(nodeType, method.Name);
353            if (method.ReturnType != pms[0].ParameterType)
354                throw Error.LogicalOperatorMustHaveConsistentTypes(nodeType, method.Name);
355            if (IsValidLiftedConditionalLogicalOperator(left, right, pms)) {
356                left = TypeUtils.GetNonNullableType(left);
357                right = TypeUtils.GetNonNullableType(left);
358            }
359            MethodInfo opTrue = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_True");
360            MethodInfo opFalse = TypeUtils.GetBooleanOperator(method.DeclaringType, "op_False");
361            if (opTrue == null || opTrue.ReturnType != typeof(bool) ||
362                opFalse == null || opFalse.ReturnType != typeof(bool)) {
363                throw Error.LogicalOperatorMustHaveBooleanOperators(nodeType, method.Name);
364            }
365        }
366
367        //CONFORMING
368        private static bool IsValidLiftedConditionalLogicalOperator(Type left, Type right, ParameterInfo[] pms) {
369            return left == right && TypeUtils.IsNullableType(right) && pms[1].ParameterType == TypeUtils.GetNonNullableType(right);
370        }
371
372        //CONFORMING
373        public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right) {
374            return MakeBinary(binaryType, left, right, false, null, null);
375        }
376        //CONFORMING
377        public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method) {
378            return MakeBinary(binaryType, left, right, liftToNull, method, null, null);
379        }
380        //CONFORMING
381        public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion) {
382            return MakeBinary(binaryType, left, right, liftToNull, method, conversion, null);
383        }
384
385        [System.Diagnostics.CodeAnalysis.SuppressMessage("Microsoft.Maintainability", "CA1502:AvoidExcessiveComplexity")]
386        public static BinaryExpression MakeBinary(ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion, Annotations annotations) {
387            switch (binaryType) {
388                case ExpressionType.Add:
389                    return Expression.Add(left, right, method, annotations);
390                case ExpressionType.AddChecked:
391                    return Expression.AddChecked(left, right, method, annotations);
392                case ExpressionType.Subtract:
393                    return Expression.Subtract(left, right, method, annotations);
394                case ExpressionType.SubtractChecked:
395                    return Expression.SubtractChecked(left, right, method, annotations);
396                case ExpressionType.Multiply:
397                    return Expression.Multiply(left, right, method, annotations);
398                case ExpressionType.MultiplyChecked:
399                    return Expression.MultiplyChecked(left, right, method, annotations);
400                case ExpressionType.Divide:
401                    return Expression.Divide(left, right, method, annotations);
402                case ExpressionType.Modulo:
403                    return Expression.Modulo(left, right, method, annotations);
404                case ExpressionType.Power:
405                    return Expression.Power(left, right, method, annotations);
406                case ExpressionType.And:
407                    return Expression.And(left, right, method, annotations);
408                case ExpressionType.AndAlso:
409                    return Expression.AndAlso(left, right, method, annotations);
410                case ExpressionType.Or:
411                    return Expression.Or(left, right, method, annotations);
412                case ExpressionType.OrElse:
413                    return Expression.OrElse(left, right, method, annotations);
414                case ExpressionType.LessThan:
415                    return Expression.LessThan(left, right, liftToNull, method, annotations);
416                case ExpressionType.LessThanOrEqual:
417                    return Expression.LessThanOrEqual(left, right, liftToNull, method, annotations);
418                case ExpressionType.GreaterThan:
419                    return Expression.GreaterThan(left, right, liftToNull, method, annotations);
420                case ExpressionType.GreaterThanOrEqual:
421                    return Expression.GreaterThanOrEqual(left, right, liftToNull, method, annotations);
422                case ExpressionType.Equal:
423                    return Expression.Equal(left, right, liftToNull, method, annotations);
424                case ExpressionType.NotEqual:
425                    return Expression.NotEqual(left, right, liftToNull, method, annotations);
426                case ExpressionType.ExclusiveOr:
427                    return Expression.ExclusiveOr(left, right, method, annotations);
428                case ExpressionType.Coalesce:
429                    return Expression.Coalesce(left, right, conversion, annotations);
430                case ExpressionType.ArrayIndex:
431                    return Expression.ArrayIndex(left, right);
432                case ExpressionType.RightShift:
433                    return Expression.RightShift(left, right, method, annotations);
434                case ExpressionType.LeftShift:
435                    return Expression.LeftShift(left, right, method, annotations);
436                default:
437                    throw Error.UnhandledBinary(binaryType);
438            }
439        }
440
441
442        #region Equality Operators
443
444        //CONFORMING
445        public static BinaryExpression Equal(Expression left, Expression right) {
446            return Equal(left, right, false, null, null);
447        }
448        public static BinaryExpression Equal(Expression left, Expression right, Annotations annotations) {
449            return Equal(left, right, false, null, annotations);
450        }
451        public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method) {
452            return Equal(left, right, liftToNull, method, null);
453        }
454        //CONFORMING
455        public static BinaryExpression Equal(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
456            RequiresCanRead(left, "left");
457            RequiresCanRead(right, "right");
458            if (method == null) {
459                return GetEqualityComparisonOperator(ExpressionType.Equal, "op_Equality", left, right, liftToNull, annotations);
460            }
461            return GetMethodBasedBinaryOperator(ExpressionType.Equal, left, right, method, liftToNull, annotations);
462        }
463
464        public static BinaryExpression NotEqual(Expression left, Expression right) {
465            return NotEqual(left, right, null);
466        }
467        //CONFORMING
468        public static BinaryExpression NotEqual(Expression left, Expression right, Annotations annotations) {
469            return NotEqual(left, right, false, null, annotations);
470        }
471        public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
472            return NotEqual(left, right, liftToNull, method, null);
473        }
474        //CONFORMING
475        public static BinaryExpression NotEqual(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
476            RequiresCanRead(left, "left");
477            RequiresCanRead(right, "right");
478            if (method == null) {
479                return GetEqualityComparisonOperator(ExpressionType.NotEqual, "op_Inequality", left, right, liftToNull, annotations);
480            }
481            return GetMethodBasedBinaryOperator(ExpressionType.NotEqual, left, right, method, liftToNull, annotations);
482        }
483
484        //CONFORMING
485        private static BinaryExpression GetEqualityComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull, Annotations annotations) {
486            // known comparison - numeric types, bools, object, enums
487            if (left.Type == right.Type && (TypeUtils.IsNumeric(left.Type) || 
488                left.Type == typeof(object) || 
489                TypeUtils.IsBool(left.Type) || 
490                TypeUtils.GetNonNullableType(left.Type).IsEnum)) {
491                if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
492                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool?));
493                } else {
494                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool));
495                }
496            }
497            // look for user defined operator
498            BinaryExpression b = GetUserDefinedBinaryOperator(binaryType, opName, left, right, liftToNull, annotations);
499            if (b != null) {
500                return b;
501            }
502            if (TypeUtils.HasBuiltInEqualityOperator(left.Type, right.Type) || IsNullComparison(left, right)) {
503                if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
504                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool?));
505                } else {
506                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool));
507                }
508            }
509            throw Error.BinaryOperatorNotDefined(binaryType, left.Type, right.Type);
510        }
511
512        #endregion
513
514        #region Comparison Expressions
515
516        //CONFORMING
517        public static BinaryExpression GreaterThan(Expression left, Expression right) {
518            return GreaterThan(left, right, false, null);
519        }
520        public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method) {
521            return GreaterThan(left, right, liftToNull, method, null);
522        }
523        //CONFORMING
524        public static BinaryExpression GreaterThan(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
525            RequiresCanRead(left, "left");
526            RequiresCanRead(right, "right");
527            if (method == null) {
528                return GetComparisonOperator(ExpressionType.GreaterThan, "op_GreaterThan", left, right, liftToNull, annotations);
529            }
530            return GetMethodBasedBinaryOperator(ExpressionType.GreaterThan, left, right, method, liftToNull, annotations);
531        }
532
533        //CONFORMING
534        public static BinaryExpression LessThan(Expression left, Expression right) {
535            return LessThan(left, right, false, null);
536        }
537        public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method) {
538            return LessThan(left, right, liftToNull, method, null);
539        }
540        //CONFORMING
541        public static BinaryExpression LessThan(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
542            RequiresCanRead(left, "left");
543            RequiresCanRead(right, "right");
544            if (method == null) {
545                return GetComparisonOperator(ExpressionType.LessThan, "op_LessThan", left, right, liftToNull, annotations);
546            }
547            return GetMethodBasedBinaryOperator(ExpressionType.LessThan, left, right, method, liftToNull, annotations);
548        }
549
550        //CONFORMING
551        public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right) {
552            return GreaterThanOrEqual(left, right, false, null);
553        }
554        public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
555            return GreaterThanOrEqual(left, right, liftToNull, method, null);
556        }
557        //CONFORMING
558        public static BinaryExpression GreaterThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
559            RequiresCanRead(left, "left");
560            RequiresCanRead(right, "right");
561            if (method == null) {
562                return GetComparisonOperator(ExpressionType.GreaterThanOrEqual, "op_GreaterThanOrEqual", left, right, liftToNull, annotations);
563            }
564            return GetMethodBasedBinaryOperator(ExpressionType.GreaterThanOrEqual, left, right, method, liftToNull, annotations);
565        }
566
567        //CONFORMING
568        public static BinaryExpression LessThanOrEqual(Expression left, Expression right) {
569            return LessThanOrEqual(left, right, false, null);
570        }
571        public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method) {
572            return LessThanOrEqual(left, right, liftToNull, method, null);
573        }
574        //CONFORMING
575        public static BinaryExpression LessThanOrEqual(Expression left, Expression right, bool liftToNull, MethodInfo method, Annotations annotations) {
576            RequiresCanRead(left, "left");
577            RequiresCanRead(right, "right");
578            if (method == null) {
579                return GetComparisonOperator(ExpressionType.LessThanOrEqual, "op_LessThanOrEqual", left, right, liftToNull, annotations);
580            }
581            return GetMethodBasedBinaryOperator(ExpressionType.LessThanOrEqual, left, right, method, liftToNull, annotations);
582        }
583
584        //CONFORMING
585        private static BinaryExpression GetComparisonOperator(ExpressionType binaryType, string opName, Expression left, Expression right, bool liftToNull, Annotations annotations) {
586            if (left.Type == right.Type && TypeUtils.IsNumeric(left.Type)) {
587                if (TypeUtils.IsNullableType(left.Type) && liftToNull) {
588                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool?));
589                } else {
590                    return new BinaryExpression(annotations, binaryType, left, right, typeof(bool));
591                }
592            }
593            return GetUserDefinedBinaryOperatorOrThrow(binaryType, opName, left, right, liftToNull, annotations);
594        }
595
596        #endregion
597
598        #region Boolean Expressions
599
600        //CONFORMING
601        public static BinaryExpression AndAlso(Expression left, Expression right) {
602            return AndAlso(left, right, null, null);
603        }
604        //CONFORMING
605        public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method) {
606            return AndAlso(left, right, method, null);
607        }
608        public static BinaryExpression AndAlso(Expression left, Expression right, MethodInfo method, Annotations annotations) {
609            RequiresCanRead(left, "left");
610            RequiresCanRead(right, "right");
611            Type returnType;
612            if (method == null) {
613                if (left.Type == right.Type && TypeUtils.IsBool(left.Type)) {
614                    return new BinaryExpression(annotations, ExpressionType.AndAlso, left, right, left.Type);
615                }
616                method = GetUserDefinedBinaryOperator(ExpressionType.AndAlso, left.Type, right.Type, "op_BitwiseAnd");
617                if (method != null) {
618                    ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method);
619                    returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
620                    return new BinaryExpression(annotations, ExpressionType.AndAlso, left, right, returnType, method);
621                }
622                throw Error.BinaryOperatorNotDefined(ExpressionType.AndAlso, left.Type, right.Type);
623            }
624            ValidateUserDefinedConditionalLogicOperator(ExpressionType.AndAlso, left.Type, right.Type, method);
625            returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
626            return new BinaryExpression(annotations, ExpressionType.AndAlso, left, right, returnType, method);
627        }
628
629        //CONFORMING
630        public static BinaryExpression OrElse(Expression left, Expression right) {
631            return OrElse(left, right, null, null);
632        }
633        //CONFORMING
634        public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method) {
635            return OrElse(left, right, method, null);
636        }
637        public static BinaryExpression OrElse(Expression left, Expression right, MethodInfo method, Annotations annotations) {
638            RequiresCanRead(left, "left");
639            RequiresCanRead(right, "right");
640            Type returnType;
641            if (method == null) {
642                if (left.Type == right.Type && TypeUtils.IsBool(left.Type)) {
643                    return new BinaryExpression(annotations, ExpressionType.OrElse, left, right, left.Type);
644                }
645                method = GetUserDefinedBinaryOperator(ExpressionType.OrElse, left.Type, right.Type, "op_BitwiseOr");
646                if (method != null) {
647                    ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method);
648                    returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
649                    return new BinaryExpression(annotations, ExpressionType.OrElse, left, right, returnType, method);
650                }
651                throw Error.BinaryOperatorNotDefined(ExpressionType.OrElse, left.Type, right.Type);
652            }
653            ValidateUserDefinedConditionalLogicOperator(ExpressionType.OrElse, left.Type, right.Type, method);
654            returnType = (TypeUtils.IsNullableType(left.Type) && method.ReturnType == TypeUtils.GetNonNullableType(left.Type)) ? left.Type : method.ReturnType;
655            return new BinaryExpression(annotations, ExpressionType.OrElse, left, right, returnType, method);
656        }
657
658        #endregion
659
660        #region Coalescing Expressions
661
662        //CONFORMING
663        public static BinaryExpression Coalesce(Expression left, Expression right) {
664            return Coalesce(left, right, null, null);
665        }
666
667        //CONFORMING
668        public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion) {
669            return Coalesce(left, right, conversion, null);
670        }
671
672        public static BinaryExpression Coalesce(Expression left, Expression right, LambdaExpression conversion, Annotations annotations) {
673            RequiresCanRead(left, "left");
674            RequiresCanRead(right, "right");
675
676            if (conversion == null) {
677                Type resultType = ValidateCoalesceArgTypes(left.Type, right.Type);
678                return new BinaryExpression(annotations, ExpressionType.Coalesce, left, right, resultType);
679            }
680
681            if (left.Type.IsValueType && !TypeUtils.IsNullableType(left.Type)) {
682                throw Error.CoalesceUsedOnNonNullType();
683            }
684
685            Type delegateType = conversion.Type;
686            Debug.Assert(TypeUtils.AreAssignable(typeof(System.Delegate), delegateType) && delegateType != typeof(System.Delegate));
687            MethodInfo method = delegateType.GetMethod("Invoke");
688            if (method.ReturnType == typeof(void))
689                throw Error.UserDefinedOperatorMustNotBeVoid(conversion);
690            ParameterInfo[] pms = method.GetParametersCached();
691            Debug.Assert(pms.Length == conversion.Parameters.Count);
692            if (pms.Length != 1)
693                throw Error.IncorrectNumberOfMethodCallArguments(conversion);
694            // The return type must match exactly.
695            // CONSIDER: We could weaken this restriction and
696            // CONSIDER: say that the return type must be assignable to from
697            // CONSIDER: the return type of the lambda.
698            if (method.ReturnType != right.Type) {
699                throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString());
700            }
701            // The parameter of the conversion lambda must either be assignable
702            // from the erased or unerased type of the left hand side.
703            if (!ParameterIsAssignable(pms[0], TypeUtils.GetNonNullableType(left.Type)) &&
704                !ParameterIsAssignable(pms[0], left.Type)) {
705                throw Error.OperandTypesDoNotMatchParameters(ExpressionType.Coalesce, conversion.ToString());
706            }
707            return new BinaryExpression(annotations, ExpressionType.Coalesce, left, right, right.Type, null, conversion);
708        }
709
710        //CONFORMING
711        private static Type ValidateCoalesceArgTypes(Type left, Type right) {
712            Type leftStripped = TypeUtils.GetNonNullableType(left);
713            if (left.IsValueType && !TypeUtils.IsNullableType(left)) {
714                throw Error.CoalesceUsedOnNonNullType();
715            } else if (TypeUtils.IsNullableType(left) && TypeUtils.IsImplicitlyConvertible(right, leftStripped)) {
716                return leftStripped;
717            } else if (TypeUtils.IsImplicitlyConvertible(right, left)) {
718                return left;
719            } else if (TypeUtils.IsImplicitlyConvertible(leftStripped, right)) {
720                return right;
721            } else {
722                throw Error.ArgumentTypesMustMatch();
723            }
724        }
725
726
727
728        #endregion
729
730        #region Arithmetic Expressions
731
732        //CONFORMING
733        public static BinaryExpression Add(Expression left, Expression right) {
734            return Add(left, right, null, null);
735        }
736        //CONFORMING
737        public static BinaryExpression Add(Expression left, Expression right, MethodInfo method) {
738            return Add(left, right, method, null);
739        }        
740        public static BinaryExpression Add(Expression left, Expression right, MethodInfo method, Annotations annotations) {
741            RequiresCanRead(left, "left");
742            RequiresCanRead(right, "right");
743            if (method == null) {
744                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
745                    return new BinaryExpression(annotations, ExpressionType.Add, left, right, left.Type);
746                }
747                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Add, "op_Addition", left, right, true, annotations);
748            }
749            return GetMethodBasedBinaryOperator(ExpressionType.Add, left, right, method, true, annotations);
750        }
751
752        //CONFORMING
753        public static BinaryExpression AddChecked(Expression left, Expression right) {
754            return AddChecked(left, right, null, null);
755        }
756        //CONFORMING
757        public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method) {
758            return AddChecked(left, right, method, null);
759        }
760        public static BinaryExpression AddChecked(Expression left, Expression right, MethodInfo method, Annotations annotations) {
761            RequiresCanRead(left, "left");
762            RequiresCanRead(right, "right");
763            if (method == null) {
764                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
765                    return new BinaryExpression(annotations, ExpressionType.AddChecked, left, right, left.Type);
766                }
767                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.AddChecked, "op_Addition", left, right, false, annotations);
768            }
769            return GetMethodBasedBinaryOperator(ExpressionType.AddChecked, left, right, method, true, annotations);
770        }
771
772        //CONFORMING
773        public static BinaryExpression Subtract(Expression left, Expression right) {
774            return Subtract(left, right, null, null);
775        }
776        //CONFORMING
777        public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method) {
778            return Subtract(left, right, method, null);
779        }
780        public static BinaryExpression Subtract(Expression left, Expression right, MethodInfo method, Annotations annotations) {
781            RequiresCanRead(left, "left");
782            RequiresCanRead(right, "right");
783            if (method == null) {
784                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
785                    return new BinaryExpression(annotations, ExpressionType.Subtract, left, right, left.Type);
786                }
787                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Subtract, "op_Subtraction", left, right, true, annotations);
788            }
789            return GetMethodBasedBinaryOperator(ExpressionType.Subtract, left, right, method, true, annotations);
790        }
791
792        //CONFORMING
793        public static BinaryExpression SubtractChecked(Expression left, Expression right) {
794            return SubtractChecked(left, right, null, null);
795        }
796        //CONFORMING
797        public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method) {
798            return SubtractChecked(left, right, method, null);
799        }
800        public static BinaryExpression SubtractChecked(Expression left, Expression right, MethodInfo method, Annotations annotations) {
801            RequiresCanRead(left, "left");
802            RequiresCanRead(right, "right");
803            if (method == null) {
804                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
805                    return new BinaryExpression(annotations, ExpressionType.SubtractChecked, left, right, left.Type);
806                }
807                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.SubtractChecked, "op_Subtraction", left, right, true, annotations);
808            }
809            return GetMethodBasedBinaryOperator(ExpressionType.SubtractChecked, left, right, method, true, annotations);
810        }
811
812        //CONFORMING
813        public static BinaryExpression Divide(Expression left, Expression right) {
814            return Divide(left, right, null, null);
815        }
816        //CONFORMING
817        public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method) {
818            return Divide(left, right, method, null);
819        }
820        public static BinaryExpression Divide(Expression left, Expression right, MethodInfo method, Annotations annotations) {
821            RequiresCanRead(left, "left");
822            RequiresCanRead(right, "right");
823            if (method == null) {
824                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
825                    return new BinaryExpression(annotations, ExpressionType.Divide, left, right, left.Type);
826                }
827                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Divide, "op_Division", left, right, true, annotations);
828            }
829            return GetMethodBasedBinaryOperator(ExpressionType.Divide, left, right, method, true, annotations);
830        }
831
832        //CONFORMING
833        public static BinaryExpression Modulo(Expression left, Expression right) {
834            return Modulo(left, right, null, null);
835        }
836        //CONFORMING
837        public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method) {
838            return Modulo(left, right, method, null);
839        }
840        public static BinaryExpression Modulo(Expression left, Expression right, MethodInfo method, Annotations annotations) {
841            RequiresCanRead(left, "left");
842            RequiresCanRead(right, "right");
843            if (method == null) {
844                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
845                    return new BinaryExpression(annotations, ExpressionType.Modulo, left, right, left.Type);
846                }
847                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Modulo, "op_Modulus", left, right, true, annotations);
848            }
849            return GetMethodBasedBinaryOperator(ExpressionType.Modulo, left, right, method, true, annotations);
850        }
851
852        //CONFORMING
853        public static BinaryExpression Multiply(Expression left, Expression right) {
854            return Multiply(left, right, null, null);
855        }
856        //CONFORMING
857        public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method) {
858            return Multiply(left, right, method, null);
859        }
860        public static BinaryExpression Multiply(Expression left, Expression right, MethodInfo method, Annotations annotations) {
861            RequiresCanRead(left, "left");
862            RequiresCanRead(right, "right");
863            if (method == null) {
864                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
865                    return new BinaryExpression(annotations, ExpressionType.Multiply, left, right, left.Type);
866                }
867                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.Multiply, "op_Multiply", left, right, true, annotations);
868            }
869            return GetMethodBasedBinaryOperator(ExpressionType.Multiply, left, right, method, true, annotations);
870        }
871
872        //CONFORMING
873        public static BinaryExpression MultiplyChecked(Expression left, Expression right) {
874            return MultiplyChecked(left, right, null, null);
875        }
876        //CONFORMING
877        public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method) {
878            return MultiplyChecked(left, right, method, null);
879        }
880        public static BinaryExpression MultiplyChecked(Expression left, Expression right, MethodInfo method, Annotations annotations) {
881            RequiresCanRead(left, "left");
882            RequiresCanRead(right, "right");
883            if (method == null) {
884                if (left.Type == right.Type && TypeUtils.IsArithmetic(left.Type)) {
885                    return new BinaryExpression(annotations, ExpressionType.MultiplyChecked, left, right, left.Type);
886                }
887                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.MultiplyChecked, "op_Multiply", left, right, true, annotations);
888            }
889            return GetMethodBasedBinaryOperator(ExpressionType.MultiplyChecked, left, right, method, true, annotations);
890        }
891
892        //CONFORMING
893        public static BinaryExpression LeftShift(Expression left, Expression right) {
894            return LeftShift(left, right, null, null);
895        }
896        //CONFORMING
897        public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method) {
898            return LeftShift(left, right, method, null);
899        }
900        public static BinaryExpression LeftShift(Expression left, Expression right, MethodInfo method, Annotations annotations) {
901            RequiresCanRead(left, "left");
902            RequiresCanRead(right, "right");
903            if (method == null) {
904                if (TypeUtils.IsInteger(left.Type) && TypeUtils.GetNonNullableType(right.Type) == typeof(int)) {
905                    return new BinaryExpression(annotations, ExpressionType.LeftShift, left, right, left.Type);
906                }
907                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.LeftShift, "op_LeftShift", left, right, true, annotations);
908            }
909            return GetMethodBasedBinaryOperator(ExpressionType.LeftShift, left, right, method, true, annotations);
910        }
911
912        //CONFORMING
913        public static BinaryExpression RightShift(Expression left, Expression right) {
914            return RightShift(left, right, null, null);
915        }
916        //CONFORMING
917        public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method) {
918            return RightShift(left, right, method, null);
919        }
920        public static BinaryExpression RightShift(Expression left, Expression right, MethodInfo method, Annotations annotations) {
921            RequiresCanRead(left, "left");
922            RequiresCanRead(right, "right");
923            if (method == null) {
924                if (TypeUtils.IsInteger(left.Type) && TypeUtils.GetNonNullableType(right.Type) == typeof(int)) {
925                    return new BinaryExpression(annotations, ExpressionType.RightShift, left, right, left.Type);
926                }
927                return GetUserDefinedBinaryOperatorOrThrow(ExpressionType.RightShift, "op_RightShift", left, right, true, annotations);
928            }
929            return GetMethodBasedBinaryOperator(ExpressionType.RightShift, left, right, method, true, annotations);
930        }
931
932        //CONFORMING
933        public static BinaryExpression And(Expression left, Expression right) {
934         

Large files files are truncated, but you can click here to view the full file