f79156284c2ef6e037613f1117aa09b5d698b815
[mono.git] / mcs / class / System.Core / System.Linq.Expressions / Expression.cs
1 //
2 // Expression.cs
3 //
4 // Author:
5 //   Jb Evain (jbevain@novell.com)
6 //   Miguel de Icaza (miguel@novell.com)
7 //
8 // (C) 2008 Novell, Inc. (http://www.novell.com)
9 //
10 // Permission is hereby granted, free of charge, to any person obtaining
11 // a copy of this software and associated documentation files (the
12 // "Software"), to deal in the Software without restriction, including
13 // without limitation the rights to use, copy, modify, merge, publish,
14 // distribute, sublicense, and/or sell copies of the Software, and to
15 // permit persons to whom the Software is furnished to do so, subject to
16 // the following conditions:
17 //
18 // The above copyright notice and this permission notice shall be
19 // included in all copies or substantial portions of the Software.
20 //
21 // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 // EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 // MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 // NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 // LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 // OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 // WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
28 //
29
30 using System;
31 using System.Collections;
32 using System.Collections.Generic;
33 using System.Collections.ObjectModel;
34 using System.Globalization;
35 using System.Linq;
36 using System.Reflection;
37 #if !FULL_AOT_RUNTIME
38 using System.Reflection.Emit;
39 #endif
40
41 namespace System.Linq.Expressions {
42
43         public abstract class Expression {
44
45                 ExpressionType node_type;
46                 Type type;
47
48                 internal const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
49                 internal const BindingFlags NonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
50                 internal const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
51                 internal const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
52                 internal const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy;
53                 internal const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
54
55                 public ExpressionType NodeType {
56                         get { return node_type; }
57                 }
58
59                 public Type Type {
60                         get { return type; }
61                 }
62
63                 protected Expression (ExpressionType node_type, Type type)
64                 {
65                         this.node_type = node_type;
66                         this.type = type;
67                 }
68
69                 public override string ToString ()
70                 {
71                         return ExpressionPrinter.ToString (this);
72                 }
73
74                 #region Binary Expressions
75
76                 static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param)
77                 {
78                         return GetUnaryOperator (oper_name, declaring, param, null);
79                 }
80
81                 static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param, Type ret)
82                 {
83                         var methods = declaring.GetNotNullableType ().GetMethods (PublicStatic);
84
85                         foreach (var method in methods) {
86                                 if (method.Name != oper_name)
87                                         continue;
88
89                                 var parameters = method.GetParameters ();
90                                 if (parameters.Length != 1)
91                                         continue;
92
93                                 if (method.IsGenericMethod)
94                                         continue;
95
96                                 if (!IsAssignableToParameterType (param.GetNotNullableType (), parameters [0]))
97                                         continue;
98
99                                 if (ret != null && method.ReturnType != ret.GetNotNullableType ())
100                                         continue;
101
102                                 return method;
103                         }
104
105                         return null;
106                 }
107
108                 internal static MethodInfo GetTrueOperator (Type self)
109                 {
110                         return GetBooleanOperator ("op_True", self);
111                 }
112
113                 internal static MethodInfo GetFalseOperator (Type self)
114                 {
115                         return GetBooleanOperator ("op_False", self);
116                 }
117
118                 static MethodInfo GetBooleanOperator (string op, Type self)
119                 {
120                         return GetUnaryOperator (op, self, self, typeof (bool));
121                 }
122
123                 static bool IsAssignableToParameterType (Type type, ParameterInfo param)
124                 {
125                         var ptype = param.ParameterType;
126                         if (ptype.IsByRef)
127                                 ptype = ptype.GetElementType ();
128
129                         return type.GetNotNullableType ().IsAssignableTo (ptype);
130                 }
131
132                 static MethodInfo CheckUnaryMethod (MethodInfo method, Type param)
133                 {
134                         if (method.ReturnType == typeof (void))
135                                 throw new ArgumentException ("Specified method must return a value", "method");
136
137                         if (!method.IsStatic)
138                                 throw new ArgumentException ("Method must be static", "method");
139
140                         var parameters = method.GetParameters ();
141
142                         if (parameters.Length != 1)
143                                 throw new ArgumentException ("Must have only one parameters", "method");
144
145                         if (!IsAssignableToParameterType (param.GetNotNullableType (), parameters [0]))
146                                 throw new InvalidOperationException ("left-side argument type does not match expression type");
147
148                         return method;
149                 }
150
151                 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method, Func<Type, bool> validator)
152                 {
153                         if (expression == null)
154                                 throw new ArgumentNullException ("expression");
155
156                         if (method != null)
157                                 return CheckUnaryMethod (method, expression.Type);
158
159                         var type = expression.Type.GetNotNullableType ();
160
161                                 if (validator (type))
162                                         return null;
163
164                                 if (oper_name != null) {
165                                         method = GetUnaryOperator (oper_name, type, expression.Type);
166                                         if (method != null)
167                                                 return method;
168                                 }
169
170                                 throw new InvalidOperationException (
171                                         string.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
172                 }
173
174                 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
175                 {
176                         MethodInfo [] methods = on_type.GetMethods (PublicStatic);
177
178                         foreach (var method in methods) {
179                                 if (method.Name != oper_name)
180                                         continue;
181
182                                 var parameters = method.GetParameters ();
183                                 if (parameters.Length != 2)
184                                         continue;
185
186                                 if (method.IsGenericMethod)
187                                         continue;
188
189                                 if (!IsAssignableToParameterType (left.Type, parameters [0]))
190                                         continue;
191
192                                 if (!IsAssignableToParameterType (right.Type, parameters [1]))
193                                         continue;
194
195                                 // Method has papers in order.
196                                 return method;
197                         }
198
199                         return null;
200                 }
201
202                 //
203                 // Performs basic checks on the incoming expressions for binary expressions
204                 // and any provided MethodInfo.
205                 //
206                 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
207                 {
208                         if (left == null)
209                                 throw new ArgumentNullException ("left");
210                         if (right == null)
211                                 throw new ArgumentNullException ("right");
212
213                         if (method != null){
214                                 if (method.ReturnType == typeof (void))
215                                         throw new ArgumentException ("Specified method must return a value", "method");
216
217                                 if (!method.IsStatic)
218                                         throw new ArgumentException ("Method must be static", "method");
219
220                                 var parameters = method.GetParameters ();
221
222                                 if (parameters.Length != 2)
223                                         throw new ArgumentException ("Must have only two parameters", "method");
224
225                                 if (!IsAssignableToParameterType (left.Type, parameters [0]))
226                                         throw new InvalidOperationException ("left-side argument type does not match left expression type");
227
228                                 if (!IsAssignableToParameterType (right.Type, parameters [1]))
229                                         throw new InvalidOperationException ("right-side argument type does not match right expression type");
230
231                                 return method;
232                         } else {
233                                 Type ltype = left.Type;
234                                 Type rtype = right.Type;
235                                 Type ultype = ltype.GetNotNullableType ();
236                                 Type urtype = rtype.GetNotNullableType ();
237
238                                 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
239                                         if (ultype == typeof (bool)) {
240                                                 if (ultype == urtype && ltype == rtype)
241                                                         return null;
242                                         }
243                                 }
244
245                                 // Use IsNumber to avoid expensive reflection.
246                                 if (IsNumber (ultype)) {
247                                         if (ultype == urtype && ltype == rtype)
248                                                 return null;
249
250                                         if (oper_name != null){
251                                                 method = GetBinaryOperator (oper_name, urtype, left, right);
252                                                 if (method != null)
253                                                         return method;
254                                         }
255                                 }
256
257                                 if (oper_name != null){
258                                         method = GetBinaryOperator (oper_name, ultype, left, right);
259                                         if (method != null)
260                                                 return method;
261                                 }
262
263                                 if (oper_name == "op_Equality" || oper_name == "op_Inequality") {
264                                         //
265                                         // == and != allow reference types without operators defined.
266                                         //
267                                         if (!ltype.IsValueType && !rtype.IsValueType)
268                                                 return null;
269
270                                         if (ltype == rtype && ultype.IsEnum)
271                                                 return null;
272
273                                         if (ltype == rtype && ultype == typeof (bool))
274                                                 return null;
275                                 }
276
277                                 if (oper_name == "op_LeftShift" || oper_name == "op_RightShift") {
278                                         if (IsInt (ultype) && urtype == typeof (int))
279                                                 return null;
280                                 }
281
282                                 throw new InvalidOperationException (
283                                         String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
284                         }
285                 }
286
287                 //
288                 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
289                 // only ints and bools are allowed
290                 //
291                 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
292                 {
293                         if (left == null)
294                                 throw new ArgumentNullException ("left");
295                         if (right == null)
296                                 throw new ArgumentNullException ("right");
297
298                         if (method == null) {
299                                 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
300                                 if (left.Type == right.Type && IsIntOrBool (left.Type))
301                                         return null;
302                         }
303
304                         method = BinaryCoreCheck (oper_name, left, right, method);
305                         if (method == null) {
306                                 // The check in BinaryCoreCheck allows a bit more than we do
307                                 // (floats and doubles).  Catch this here
308                                 if (left.Type == typeof (double) || left.Type == typeof (float))
309                                         throw new InvalidOperationException ("Types not supported");
310                         }
311
312                         return method;
313                 }
314
315                 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
316                 {
317                         bool is_lifted;
318                         Type type;
319
320                         if (method == null) {
321                                 is_lifted = left.Type.IsNullable ();
322                                 type = left.Type;
323                         } else {
324                                 var parameters = method.GetParameters ();
325
326                                 var lp = parameters [0];
327                                 var rp = parameters [1];
328
329                                 if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
330                                         is_lifted = false;
331                                         type = method.ReturnType;
332                                 } else if (left.Type.IsNullable ()
333                                         && right.Type.IsNullable ()
334                                         && left.Type.GetNotNullableType () == lp.ParameterType
335                                         && right.Type.GetNotNullableType () == rp.ParameterType
336                                         && !method.ReturnType.IsNullable ()) {
337
338                                         is_lifted = true;
339                                         type = method.ReturnType.MakeNullableType ();
340                                 } else
341                                         throw new InvalidOperationException ();
342                         }
343
344                         return new BinaryExpression (et, type, left, right, is_lifted, is_lifted, method, null);
345                 }
346
347                 static bool IsAssignableToOperatorParameter (Expression expression, ParameterInfo parameter)
348                 {
349                         if (expression.Type == parameter.ParameterType)
350                                 return true;
351
352                         if ((!expression.Type.IsNullable () && !parameter.ParameterType.IsNullable ())
353                                 && IsAssignableToParameterType (expression.Type, parameter))
354                                 return true;
355
356                         return false;
357                 }
358
359                 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
360                 {
361                         bool is_lifted;
362                         Type type;
363
364                         if (method == null) {
365                                 type = expression.Type;
366                                 is_lifted = type.IsNullable ();
367                         } else {
368                                 var parameter = method.GetParameters () [0];
369
370                                 if (IsAssignableToOperatorParameter (expression, parameter)) {
371                                         is_lifted = false;
372                                         type = method.ReturnType;
373                                 } else if (expression.Type.IsNullable ()
374                                         && expression.Type.GetNotNullableType () == parameter.ParameterType
375                                         && !method.ReturnType.IsNullable ()) {
376
377                                         is_lifted = true;
378                                         type = method.ReturnType.MakeNullableType ();
379                                 } else
380                                         throw new InvalidOperationException ();
381                         }
382
383                         return new UnaryExpression (et, expression, type, method, is_lifted);
384                 }
385
386                 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
387                 {
388                         bool is_lifted;
389                         Type type;
390
391                         if (method == null) {
392                                 if (!left.Type.IsNullable () && !right.Type.IsNullable ()) {
393                                         is_lifted = false;
394                                         liftToNull = false;
395                                         type = typeof (bool);
396                                 } else if (left.Type.IsNullable () && right.Type.IsNullable ()) {
397                                         is_lifted = true;
398                                         type = liftToNull ? typeof (bool?) : typeof (bool);
399                                 } else
400                                         throw new InvalidOperationException ();
401                         } else {
402                                 var parameters = method.GetParameters ();
403
404                                 var lp = parameters [0];
405                                 var rp = parameters [1];
406
407                                 if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
408                                         is_lifted = false;
409                                         liftToNull = false;
410                                         type = method.ReturnType;
411                                 } else if (left.Type.IsNullable ()
412                                         && right.Type.IsNullable ()
413                                         && left.Type.GetNotNullableType () == lp.ParameterType
414                                         && right.Type.GetNotNullableType () == rp.ParameterType) {
415
416                                         is_lifted = true;
417
418                                         if (method.ReturnType == typeof (bool))
419                                                 type = liftToNull ? typeof (bool?) : typeof (bool);
420                                         else if (!method.ReturnType.IsNullable ()) {
421                                                 //
422                                                 // This behavior is not documented: what
423                                                 // happens if the result is not typeof(bool), but
424                                                 // the parameters are nullable: the result
425                                                 // becomes nullable<returntype>
426                                                 //
427                                                 // See:
428                                                 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
429
430                                                 type = method.ReturnType.MakeNullableType ();
431                                         } else
432                                                 throw new InvalidOperationException ();
433                                 } else
434                                         throw new InvalidOperationException ();
435                         }
436
437                         return new BinaryExpression (et, type, left, right, liftToNull, is_lifted, method, null);
438                 }
439
440                 //
441                 // Arithmetic
442                 //
443                 public static BinaryExpression Add (Expression left, Expression right)
444                 {
445                         return Add (left, right, null);
446                 }
447
448                 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
449                 {
450                         method = BinaryCoreCheck ("op_Addition", left, right, method);
451
452                         return MakeSimpleBinary (ExpressionType.Add, left, right, method);
453                 }
454
455                 public static BinaryExpression AddChecked (Expression left, Expression right)
456                 {
457                         return AddChecked (left, right, null);
458                 }
459
460                 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
461                 {
462                         method = BinaryCoreCheck ("op_Addition", left, right, method);
463
464                         // The check in BinaryCoreCheck allows a bit more than we do
465                         // (byte, sbyte).  Catch that here
466                         if (method == null) {
467                                 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
468                                         throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
469                         }
470
471                         return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
472                 }
473
474                 public static BinaryExpression Subtract (Expression left, Expression right)
475                 {
476                         return Subtract (left, right, null);
477                 }
478
479                 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
480                 {
481                         method = BinaryCoreCheck ("op_Subtraction", left, right, method);
482
483                         return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
484                 }
485
486                 public static BinaryExpression SubtractChecked (Expression left, Expression right)
487                 {
488                         return SubtractChecked (left, right, null);
489                 }
490
491                 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
492                 {
493                         method = BinaryCoreCheck ("op_Subtraction", left, right, method);
494
495                         // The check in BinaryCoreCheck allows a bit more than we do
496                         // (byte, sbyte).  Catch that here
497                         if (method == null) {
498                                 if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
499                                         throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
500                         }
501
502                         return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
503                 }
504
505                 public static BinaryExpression Modulo (Expression left, Expression right)
506                 {
507                         return Modulo (left, right, null);
508                 }
509
510                 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
511                 {
512                         method = BinaryCoreCheck ("op_Modulus", left, right, method);
513
514                         return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
515                 }
516
517                 public static BinaryExpression Multiply (Expression left, Expression right)
518                 {
519                         return Multiply (left, right, null);
520                 }
521
522                 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
523                 {
524                         method = BinaryCoreCheck ("op_Multiply", left, right, method);
525
526                         return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
527                 }
528
529                 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
530                 {
531                         return MultiplyChecked (left, right, null);
532                 }
533
534                 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
535                 {
536                         method = BinaryCoreCheck ("op_Multiply", left, right, method);
537
538                         return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
539                 }
540
541                 public static BinaryExpression Divide (Expression left, Expression right)
542                 {
543                         return Divide (left, right, null);
544                 }
545
546                 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
547                 {
548                         method = BinaryCoreCheck ("op_Division", left, right, method);
549
550                         return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
551                 }
552
553                 public static BinaryExpression Power (Expression left, Expression right)
554                 {
555                         return Power (left, right, null);
556                 }
557
558                 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
559                 {
560                         method = BinaryCoreCheck (null, left, right, method);
561
562                         if (left.Type.GetNotNullableType () != typeof (double))
563                                 throw new InvalidOperationException ("Power only supports double arguments");
564
565                         return MakeSimpleBinary (ExpressionType.Power, left, right, method);
566                 }
567
568                 //
569                 // Bitwise
570                 //
571                 public static BinaryExpression And (Expression left, Expression right)
572                 {
573                         return And (left, right, null);
574                 }
575
576                 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
577                 {
578                         method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
579
580                         return MakeSimpleBinary (ExpressionType.And, left, right, method);
581                 }
582
583                 public static BinaryExpression Or (Expression left, Expression right)
584                 {
585                         return Or (left, right, null);
586                 }
587
588                 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
589                 {
590                         method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
591
592                         return MakeSimpleBinary (ExpressionType.Or, left, right, method);
593                 }
594
595                 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
596                 {
597                         return ExclusiveOr (left, right, null);
598                 }
599
600                 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
601                 {
602                         method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
603
604                         return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
605                 }
606
607                 public static BinaryExpression LeftShift (Expression left, Expression right)
608                 {
609                         return LeftShift (left, right, null);
610                 }
611
612                 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
613                 {
614                         method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
615
616                         return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
617                 }
618
619                 public static BinaryExpression RightShift (Expression left, Expression right)
620                 {
621                         return RightShift (left, right, null);
622                 }
623
624                 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
625                 {
626                         method = BinaryCoreCheck ("op_RightShift", left, right, method);
627
628                         return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
629                 }
630
631                 //
632                 // Short-circuit
633                 //
634                 public static BinaryExpression AndAlso (Expression left, Expression right)
635                 {
636                         return AndAlso (left, right, null);
637                 }
638
639                 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
640                 {
641                         method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
642
643                         return MakeBoolBinary (ExpressionType.AndAlso, left, right, true, method);
644                 }
645
646                 static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
647                 {
648                         method = BinaryCoreCheck (oper, left, right, method);
649
650                         if (method == null) {
651                                 if (left.Type.GetNotNullableType () != typeof (bool))
652                                         throw new InvalidOperationException ("Only booleans are allowed");
653                         } else {
654                                 var type = left.Type.GetNotNullableType ();
655
656                                 // The method should have identical parameter and return types.
657                                 if (left.Type != right.Type || method.ReturnType != type)
658                                         throw new ArgumentException ("left, right and return type must match");
659
660                                 var optrue = GetTrueOperator (type);
661                                 var opfalse = GetFalseOperator (type);
662
663                                 if (optrue == null || opfalse == null)
664                                         throw new ArgumentException ("Operators true and false are required but not defined");
665                         }
666
667                         return method;
668                 }
669
670                 public static BinaryExpression OrElse (Expression left, Expression right)
671                 {
672                         return OrElse (left, right, null);
673                 }
674
675                 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
676                 {
677                         method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
678
679                         return MakeBoolBinary (ExpressionType.OrElse, left, right, true, method);
680                 }
681
682                 //
683                 // Comparison
684                 //
685                 public static BinaryExpression Equal (Expression left, Expression right)
686                 {
687                         return Equal (left, right, false, null);
688                 }
689
690                 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
691                 {
692                         method = BinaryCoreCheck ("op_Equality", left, right, method);
693
694                         return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
695                 }
696
697                 public static BinaryExpression NotEqual (Expression left, Expression right)
698                 {
699                         return NotEqual (left, right, false, null);
700                 }
701
702
703                 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
704                 {
705                         method = BinaryCoreCheck ("op_Inequality", left, right, method);
706
707                         return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
708                 }
709
710                 public static BinaryExpression GreaterThan (Expression left, Expression right)
711                 {
712                         return GreaterThan (left, right, false, null);
713                 }
714
715                 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
716                 {
717                         method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
718
719                         return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
720                 }
721
722                 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
723                 {
724                         return GreaterThanOrEqual (left, right, false, null);
725                 }
726
727
728                 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
729                 {
730                         method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
731
732                         return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
733                 }
734
735                 public static BinaryExpression LessThan (Expression left, Expression right)
736                 {
737                         return LessThan (left, right, false, null);
738                 }
739
740                 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
741                 {
742                         method = BinaryCoreCheck ("op_LessThan", left, right, method);
743
744                         return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
745                 }
746
747                 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
748                 {
749                         return LessThanOrEqual (left, right, false, null);
750                 }
751
752                 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
753                 {
754                         method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
755
756                         return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
757                 }
758
759                 //
760                 // Miscelaneous
761                 //
762
763                 static void CheckArray (Expression array)
764                 {
765                         if (array == null)
766                                 throw new ArgumentNullException ("array");
767                         if (!array.Type.IsArray)
768                                 throw new ArgumentException ("The array argument must be of type array");
769                 }
770
771                 public static BinaryExpression ArrayIndex (Expression array, Expression index)
772                 {
773                         CheckArray (array);
774
775                         if (index == null)
776                                 throw new ArgumentNullException ("index");
777                         if (array.Type.GetArrayRank () != 1)
778                                 throw new ArgumentException ("The array argument must be a single dimensional array");
779                         if (index.Type != typeof (int))
780                                 throw new ArgumentException ("The index must be of type int");
781
782                         return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
783                 }
784
785                 public static BinaryExpression Coalesce (Expression left, Expression right)
786                 {
787                         return Coalesce (left, right, null);
788                 }
789
790                 static BinaryExpression MakeCoalesce (Expression left, Expression right)
791                 {
792                         Type result = null;
793
794                         if (left.Type.IsNullable ()) {
795                                 Type lbase = left.Type.GetNotNullableType ();
796
797                                 if (!right.Type.IsNullable () && right.Type.IsAssignableTo (lbase))
798                                         result = lbase;
799                         }
800
801                         if (result == null && right.Type.IsAssignableTo (left.Type))
802                                 result = left.Type;
803
804                         if (result == null) {
805                                 if (left.Type.IsNullable () && left.Type.GetNotNullableType ().IsAssignableTo (right.Type))
806                                         result = right.Type;
807                         }
808
809                         if (result == null)
810                                 throw new ArgumentException ("Incompatible argument types");
811
812                         return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, null);
813                 }
814
815                 static BinaryExpression MakeConvertedCoalesce (Expression left, Expression right, LambdaExpression conversion)
816                 {
817                         var invoke = conversion.Type.GetInvokeMethod ();
818
819                         CheckNotVoid (invoke.ReturnType);
820
821                         if (invoke.ReturnType != right.Type)
822                                 throw new InvalidOperationException ("Conversion return type doesn't march right type");
823
824                         var parameters = invoke.GetParameters ();
825
826                         if (parameters.Length != 1)
827                                 throw new ArgumentException ("Conversion has wrong number of parameters");
828
829                         if (!IsAssignableToParameterType (left.Type, parameters [0]))
830                                 throw new InvalidOperationException ("Conversion argument doesn't marcht left type");
831
832                         return new BinaryExpression (ExpressionType.Coalesce, right.Type, left, right, false, false, null, conversion);
833                 }
834
835                 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
836                 {
837                         if (left == null)
838                                 throw new ArgumentNullException ("left");
839                         if (right == null)
840                                 throw new ArgumentNullException ("right");
841
842                         //
843                         // First arg must ne nullable (either Nullable<T> or a reference type
844                         //
845                         if (left.Type.IsValueType && !left.Type.IsNullable ())
846                                 throw new InvalidOperationException ("Left expression can never be null");
847
848                         if (conversion != null)
849                                 return MakeConvertedCoalesce (left, right, conversion);
850
851                         return MakeCoalesce (left, right);
852                 }
853
854                 //
855                 // MakeBinary constructors
856                 //
857                 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
858                 {
859                         return MakeBinary (binaryType, left, right, false, null);
860                 }
861
862                 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
863                 {
864                         return MakeBinary (binaryType, left, right, liftToNull, method, null);
865                 }
866
867                 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
868                 {
869                         switch (binaryType) {
870                         case ExpressionType.Add:
871                                 return Add (left, right, method);
872                         case ExpressionType.AddChecked:
873                                 return AddChecked (left, right, method);
874                         case ExpressionType.AndAlso:
875                                 return AndAlso (left, right);
876                         case ExpressionType.ArrayIndex:
877                                 return ArrayIndex (left, right);
878                         case ExpressionType.Coalesce:
879                                 return Coalesce (left, right, conversion);
880                         case ExpressionType.Divide:
881                                 return Divide (left, right, method);
882                         case ExpressionType.Equal:
883                                 return Equal (left, right, liftToNull, method);
884                         case ExpressionType.ExclusiveOr:
885                                 return ExclusiveOr (left, right, method);
886                         case ExpressionType.GreaterThan:
887                                 return GreaterThan (left, right, liftToNull, method);
888                         case ExpressionType.GreaterThanOrEqual:
889                                 return GreaterThanOrEqual (left, right, liftToNull, method);
890                         case ExpressionType.LeftShift:
891                                 return LeftShift (left, right, method);
892                         case ExpressionType.LessThan:
893                                 return LessThan (left, right, liftToNull, method);
894                         case ExpressionType.LessThanOrEqual:
895                                 return LessThanOrEqual (left, right, liftToNull, method);
896                         case ExpressionType.Modulo:
897                                 return Modulo (left, right, method);
898                         case ExpressionType.Multiply:
899                                 return Multiply (left, right, method);
900                         case ExpressionType.MultiplyChecked:
901                                 return MultiplyChecked (left, right, method);
902                         case ExpressionType.NotEqual:
903                                 return NotEqual (left, right, liftToNull, method);
904                         case ExpressionType.OrElse:
905                                 return OrElse (left, right);
906                         case ExpressionType.Power:
907                                 return Power (left, right, method);
908                         case ExpressionType.RightShift:
909                                 return RightShift (left, right, method);
910                         case ExpressionType.Subtract:
911                                 return Subtract (left, right, method);
912                         case ExpressionType.SubtractChecked:
913                                 return SubtractChecked (left, right, method);
914                         case ExpressionType.And:
915                                 return And (left, right, method);
916                         case ExpressionType.Or:
917                                 return Or (left, right, method);
918                         }
919
920                         throw new ArgumentException ("MakeBinary expect a binary node type");
921                 }
922
923                 #endregion
924
925                 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
926                 {
927                         return ArrayIndex (array, indexes as IEnumerable<Expression>);
928                 }
929
930                 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
931                 {
932                         CheckArray (array);
933
934                         if (indexes == null)
935                                 throw new ArgumentNullException ("indexes");
936
937                         var args = indexes.ToReadOnlyCollection ();
938                         if (array.Type.GetArrayRank () != args.Count)
939                                 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
940
941                         foreach (var arg in args)
942                                 if (arg.Type != typeof (int))
943                                         throw new ArgumentException ("The index must be of type int");
944
945                         return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
946                 }
947
948                 public static UnaryExpression ArrayLength (Expression array)
949                 {
950                         if (array == null)
951                                 throw new ArgumentNullException ("array");
952                         if (!array.Type.IsArray)
953                                 throw new ArgumentException ("The type of the expression must me Array");
954                         if (array.Type.GetArrayRank () != 1)
955                                 throw new ArgumentException ("The array must be a single dimensional array");
956
957                         return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
958                 }
959
960                 public static MemberAssignment Bind (MemberInfo member, Expression expression)
961                 {
962                         if (member == null)
963                                 throw new ArgumentNullException ("member");
964                         if (expression == null)
965                                 throw new ArgumentNullException ("expression");
966
967                         Type type = null;
968
969                         var prop = member as PropertyInfo;
970                         if (prop != null && prop.GetSetMethod (true) != null)
971                                 type = prop.PropertyType;
972
973                         var field = member as FieldInfo;
974                         if (field != null)
975                                 type = field.FieldType;
976
977                         if (type == null)
978                                 throw new ArgumentException ("member");
979
980                         if (!expression.Type.IsAssignableTo (type))
981                                 throw new ArgumentException ("member");
982
983                         return new MemberAssignment (member, expression);
984                 }
985
986                 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
987                 {
988                         if (propertyAccessor == null)
989                                 throw new ArgumentNullException ("propertyAccessor");
990                         if (expression == null)
991                                 throw new ArgumentNullException ("expression");
992
993                         CheckNonGenericMethod (propertyAccessor);
994
995                         var prop = GetAssociatedProperty (propertyAccessor);
996                         if (prop == null)
997                                 throw new ArgumentException ("propertyAccessor");
998
999                         var setter = prop.GetSetMethod (true);
1000                         if (setter == null)
1001                                 throw new ArgumentException ("setter");
1002
1003                         if (!expression.Type.IsAssignableTo (prop.PropertyType))
1004                                 throw new ArgumentException ("member");
1005
1006                         return new MemberAssignment (prop, expression);
1007                 }
1008
1009                 public static MethodCallExpression Call (Expression instance, MethodInfo method)
1010                 {
1011                         return Call (instance, method, null as IEnumerable<Expression>);
1012                 }
1013
1014                 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
1015                 {
1016                         return Call (null, method, arguments as IEnumerable<Expression>);
1017                 }
1018
1019                 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
1020                 {
1021                         return Call (instance, method, arguments as IEnumerable<Expression>);
1022                 }
1023
1024                 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
1025                 {
1026                         if (method == null)
1027                                 throw new ArgumentNullException ("method");
1028                         if (instance == null && !method.IsStatic)
1029                                 throw new ArgumentNullException ("instance");
1030                         if (method.IsStatic && instance != null)
1031                                 throw new ArgumentException ("instance");
1032                         if (!method.IsStatic && !instance.Type.IsAssignableTo (method.DeclaringType))
1033                                 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
1034
1035                         var args = CheckMethodArguments (method, arguments);
1036
1037                         return new MethodCallExpression (instance, method, args);
1038                 }
1039
1040                 static Type [] CollectTypes (IEnumerable<Expression> expressions)
1041                 {
1042                         return (from arg in expressions select arg.Type).ToArray ();
1043                 }
1044
1045                 static MethodInfo TryMakeGeneric (MethodInfo method, Type [] args)
1046                 {
1047                         if (method == null)
1048                                 return null;
1049
1050                         if (!method.IsGenericMethod && (args == null || args.Length == 0))
1051                                 return method;
1052
1053                         if (args.Length == method.GetGenericArguments ().Length)
1054                                 return method.MakeGenericMethod (args);
1055
1056                         return null;
1057                 }
1058
1059                 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
1060                 {
1061                         if (instance == null)
1062                                 throw new ArgumentNullException ("instance");
1063                         if (methodName == null)
1064                                 throw new ArgumentNullException ("methodName");
1065
1066                         var method = TryGetMethod (instance.Type, methodName, AllInstance,
1067                                 CollectTypes (arguments), typeArguments);
1068
1069                         var args = CheckMethodArguments (method, arguments);
1070
1071                         return new MethodCallExpression (instance, method, args);
1072                 }
1073
1074                 static bool MethodMatch (MethodInfo method, string name, Type [] parameterTypes, Type [] argumentTypes)
1075                 {
1076                         if (method.Name != name)
1077                                 return false;
1078
1079                         var parameters = method.GetParameters ();
1080
1081                         if (parameters.Length != parameterTypes.Length)
1082                                 return false;
1083
1084                         if (method.IsGenericMethod && method.IsGenericMethodDefinition) {
1085                                 var closed = TryMakeGeneric (method, argumentTypes);
1086                                 if (closed == null)
1087                                         return false;
1088
1089                                 return MethodMatch (closed, name, parameterTypes, argumentTypes);
1090                         } else if (!method.IsGenericMethod && (argumentTypes != null && argumentTypes.Length > 0))
1091                                 return false;
1092
1093                         for (int i = 0; i < parameters.Length; i++) {
1094                                 var type = parameterTypes [i];
1095                                 var parameter = parameters [i];
1096                                 if (!IsAssignableToParameterType (type, parameter)
1097                                         && !IsExpressionOfParameter (type, parameter.ParameterType))
1098                                         return false;
1099                         }
1100
1101                         return true;
1102                 }
1103
1104                 static bool IsExpressionOfParameter (Type type, Type ptype)
1105                 {
1106                         return ptype.IsGenericInstanceOf (typeof (Expression<>)) && ptype.GetFirstGenericArgument () == type;
1107                 }
1108
1109                 static MethodInfo TryGetMethod (Type type, string methodName, BindingFlags flags, Type [] parameterTypes, Type [] argumentTypes)
1110                 {
1111                         var methods = from meth in type.GetMethods (flags)
1112                                                   where MethodMatch (meth, methodName, parameterTypes, argumentTypes)
1113                                                   select meth;
1114
1115                         if (methods.Count () > 1)
1116                                 throw new InvalidOperationException ("Too many method candidates");
1117
1118                         var method = TryMakeGeneric (methods.FirstOrDefault (), argumentTypes);
1119                         if (method != null)
1120                                 return method;
1121
1122                         throw new InvalidOperationException ("No such method");
1123                 }
1124
1125                 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
1126                 {
1127                         if (type == null)
1128                                 throw new ArgumentNullException ("type");
1129                         if (methodName == null)
1130                                 throw new ArgumentNullException ("methodName");
1131
1132                         var method = TryGetMethod (type, methodName, AllStatic,
1133                                 CollectTypes (arguments), typeArguments);
1134
1135                         var args = CheckMethodArguments (method, arguments);
1136
1137                         return new MethodCallExpression (method, args);
1138                 }
1139
1140                 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
1141                 {
1142                         if (test == null)
1143                                 throw new ArgumentNullException ("test");
1144                         if (ifTrue == null)
1145                                 throw new ArgumentNullException ("ifTrue");
1146                         if (ifFalse == null)
1147                                 throw new ArgumentNullException ("ifFalse");
1148                         if (test.Type != typeof (bool))
1149                                 throw new ArgumentException ("Test expression should be of type bool");
1150                         if (ifTrue.Type != ifFalse.Type)
1151                                 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
1152
1153                         return new ConditionalExpression (test, ifTrue, ifFalse);
1154                 }
1155
1156                 public static ConstantExpression Constant (object value)
1157                 {
1158                         if (value == null)
1159                                 return new ConstantExpression (null, typeof (object));
1160
1161                         return Constant (value, value.GetType ());
1162                 }
1163
1164                 public static ConstantExpression Constant (object value, Type type)
1165                 {
1166                         if (type == null)
1167                                 throw new ArgumentNullException ("type");
1168
1169                         //
1170                         // value must be compatible with type, no conversions
1171                         // are allowed
1172                         //
1173                         if (value == null){
1174                                 if (type.IsValueType && !type.IsNullable ())
1175                                         throw new ArgumentException ();
1176                         } else {
1177                                 if (!(type.IsValueType && type.IsNullable ()) && !value.GetType ().IsAssignableTo (type))
1178                                         throw new ArgumentException ();
1179
1180                         }
1181
1182                         return new ConstantExpression (value, type);
1183                 }
1184
1185                 static bool IsConvertiblePrimitive (Type type)
1186                 {
1187                         var t = type.GetNotNullableType ();
1188         
1189                         if (t == typeof (bool))
1190                                 return false;
1191
1192                         if (t.IsEnum)
1193                                 return true;
1194
1195                         return t.IsPrimitive;
1196                 }
1197
1198                 internal static bool IsPrimitiveConversion (Type type, Type target)
1199                 {
1200                         if (type == target)
1201                                 return true;
1202
1203                         if (type.IsNullable () && target == type.GetNotNullableType ())
1204                                 return true;
1205
1206                         if (target.IsNullable () && type == target.GetNotNullableType ())
1207                                 return true;
1208
1209                         if (IsConvertiblePrimitive (type) && IsConvertiblePrimitive (target))
1210                                 return true;
1211
1212                         return false;
1213                 }
1214
1215                 internal static bool IsReferenceConversion (Type type, Type target)
1216                 {
1217                         if (type == target)
1218                                 return true;
1219
1220                         if (type == typeof (object) || target == typeof (object))
1221                                 return true;
1222
1223                         if (type.IsInterface || target.IsInterface)
1224                                 return true;
1225
1226                         if (type.IsEnum && target == typeof (Enum))
1227                                 return true;
1228
1229                         if (type.IsValueType || target.IsValueType)
1230                                 return false;
1231
1232                         if (type.IsAssignableTo (target) || target.IsAssignableTo (type))
1233                                 return true;
1234
1235                         return false;
1236                 }
1237
1238                 public static UnaryExpression Convert (Expression expression, Type type)
1239                 {
1240                         return Convert (expression, type, null);
1241                 }
1242
1243                 static MethodInfo GetUserConversionMethod (Type type, Type target)
1244                 {
1245                         var method = GetUnaryOperator ("op_Explicit", type, type, target);
1246                         if (method == null)
1247                                 method = GetUnaryOperator ("op_Implicit", type, type, target);
1248                         if (method == null)
1249                                 method = GetUnaryOperator ("op_Explicit", target, type, target);
1250                         if (method == null)
1251                                 method = GetUnaryOperator ("op_Implicit", target, type, target);
1252                         if (method == null)
1253                                 throw new InvalidOperationException ();
1254
1255                         return method;
1256                 }
1257
1258                 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1259                 {
1260                         if (expression == null)
1261                                 throw new ArgumentNullException ("expression");
1262                         if (type == null)
1263                                 throw new ArgumentNullException ("type");
1264
1265                         var et = expression.Type;
1266
1267                         if (method != null)
1268                                 CheckUnaryMethod (method, et);
1269                         else if (!IsPrimitiveConversion (et, type) && !IsReferenceConversion (et, type))
1270                                 method = GetUserConversionMethod (et, type);
1271
1272                         return new UnaryExpression (ExpressionType.Convert,
1273                                 expression, type, method,
1274                                 IsConvertNodeLifted (method, expression, type));
1275                 }
1276
1277                 static bool IsConvertNodeLifted (MethodInfo method, Expression operand, Type target)
1278                 {
1279                         if (method == null)
1280                                 return operand.Type.IsNullable () || target.IsNullable ();
1281
1282                         if (operand.Type.IsNullable () && !ParameterMatch (method, operand.Type))
1283                                 return true;
1284
1285                         if (target.IsNullable () && !ReturnTypeMatch (method, target))
1286                                 return true;
1287
1288                         return false;
1289                 }
1290
1291                 static bool ParameterMatch (MethodInfo method, Type type)
1292                 {
1293                         return method.GetParameters () [0].ParameterType == type;
1294                 }
1295
1296                 static bool ReturnTypeMatch (MethodInfo method, Type type)
1297                 {
1298                         return method.ReturnType == type;
1299                 }
1300
1301                 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1302                 {
1303                         return ConvertChecked (expression, type, null);
1304                 }
1305
1306                 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1307                 {
1308                         if (expression == null)
1309                                 throw new ArgumentNullException ("expression");
1310                         if (type == null)
1311                                 throw new ArgumentNullException ("type");
1312
1313                         var et = expression.Type;
1314
1315                         if (method != null)
1316                                 CheckUnaryMethod (method, et);
1317                         else if (IsReferenceConversion (et, type))
1318                                 return Convert (expression, type, method);
1319                         else if (!IsPrimitiveConversion (et, type))
1320                                 method = GetUserConversionMethod (et, type);
1321
1322                         return new UnaryExpression (ExpressionType.ConvertChecked,
1323                                 expression, type, method,
1324                                 IsConvertNodeLifted (method, expression, type));
1325                 }
1326
1327                 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1328                 {
1329                         return ElementInit (addMethod, arguments as IEnumerable<Expression>);
1330                 }
1331
1332                 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1333                 {
1334                         if (addMethod == null)
1335                                 throw new ArgumentNullException ("addMethod");
1336                         if (arguments == null)
1337                                 throw new ArgumentNullException ("arguments");
1338                         if (addMethod.Name.ToLowerInvariant () != "add")
1339                                 throw new ArgumentException ("addMethod");
1340                         if (addMethod.IsStatic)
1341                                 throw new ArgumentException ("addMethod must be an instance method", "addMethod");
1342
1343                         var args = CheckMethodArguments (addMethod, arguments);
1344
1345                         return new ElementInit (addMethod, args);
1346                 }
1347
1348                 public static MemberExpression Field (Expression expression, FieldInfo field)
1349                 {
1350                         if (field == null)
1351                                 throw new ArgumentNullException ("field");
1352                         if (!field.IsStatic) {
1353                                 if (expression == null)
1354                                         throw new ArgumentNullException ("expression");
1355                                 if (!expression.Type.IsAssignableTo (field.DeclaringType))
1356                                         throw new ArgumentException ("field");
1357                         } else if (expression != null)
1358                                 throw new ArgumentException ("expression");
1359
1360                         return new MemberExpression (expression, field, field.FieldType);
1361                 }
1362
1363                 public static MemberExpression Field (Expression expression, string fieldName)
1364                 {
1365                         if (expression == null)
1366                                 throw new ArgumentNullException ("expression");
1367
1368                         var field = expression.Type.GetField (fieldName, AllInstance);
1369                         if (field == null)
1370                                 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1371
1372                         return new MemberExpression (expression, field, field.FieldType);
1373                 }
1374
1375                 public static Type GetActionType (params Type [] typeArgs)
1376                 {
1377                         if (typeArgs == null)
1378                                 throw new ArgumentNullException ("typeArgs");
1379
1380                         if (typeArgs.Length > 4)
1381                                 throw new ArgumentException ("No Action type of this arity");
1382
1383                         if (typeArgs.Length == 0)
1384                                 return typeof (Action);
1385
1386                         Type action = null;
1387                         switch (typeArgs.Length) {
1388                         case 1:
1389                                 action = typeof (Action<>);
1390                                 break;
1391                         case 2:
1392                                 action = typeof (Action<,>);
1393                                 break;
1394                         case 3:
1395                                 action = typeof (Action<,,>);
1396                                 break;
1397                         case 4:
1398                                 action = typeof (Action<,,,>);
1399                                 break;
1400                         }
1401
1402                         return action.MakeGenericType (typeArgs);
1403                 }
1404
1405                 public static Type GetFuncType (params Type [] typeArgs)
1406                 {
1407                         if (typeArgs == null)
1408                                 throw new ArgumentNullException ("typeArgs");
1409
1410                         if (typeArgs.Length < 1 || typeArgs.Length > 5)
1411                                 throw new ArgumentException ("No Func type of this arity");
1412
1413                         Type func = null;
1414                         switch (typeArgs.Length) {
1415                         case 1:
1416                                 func = typeof (Func<>);
1417                                 break;
1418                         case 2:
1419                                 func = typeof (Func<,>);
1420                                 break;
1421                         case 3:
1422                                 func = typeof (Func<,,>);
1423                                 break;
1424                         case 4:
1425                                 func = typeof (Func<,,,>);
1426                                 break;
1427                         case 5:
1428                                 func = typeof (Func<,,,,>);
1429                                 break;
1430                         }
1431
1432                         return func.MakeGenericType (typeArgs);
1433                 }
1434
1435                 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1436                 {
1437                         return Invoke (expression, arguments as IEnumerable<Expression>);
1438                 }
1439
1440                 static Type GetInvokableType (Type t)
1441                 {
1442                         if (t.IsAssignableTo (typeof (Delegate)))
1443                                 return t;
1444
1445                         return GetGenericType (t, typeof (Expression<>));
1446                 }
1447
1448                 static Type GetGenericType (Type t, Type def)
1449                 {
1450                         if (t == null)
1451                                 return null;
1452
1453                         if (t.IsGenericType && t.GetGenericTypeDefinition () == def)
1454                                 return t;
1455
1456                         return GetGenericType (t.BaseType, def);
1457                 }
1458
1459                 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1460                 {
1461                         if (expression == null)
1462                                 throw new ArgumentNullException ("expression");
1463
1464                         var type = GetInvokableType (expression.Type);
1465                         if (type == null)
1466                                 throw new ArgumentException ("The type of the expression is not invokable");
1467
1468                         var args = arguments.ToReadOnlyCollection ();
1469                         CheckForNull (args, "arguments");
1470
1471                         var invoke = type.GetInvokeMethod ();
1472                         if (invoke == null)
1473                                 throw new ArgumentException ("expression");
1474
1475                         if (invoke.GetParameters ().Length != args.Count)
1476                                 throw new InvalidOperationException ("Arguments count doesn't match parameters length");
1477
1478                         args = CheckMethodArguments (invoke, args);
1479
1480                         return new InvocationExpression (expression, invoke.ReturnType, args);
1481                 }
1482
1483                 static bool CanAssign (Type target, Type source)
1484                 {
1485                         // This catches object and value type mixage, type compatibility is handled later
1486                         if (target.IsValueType ^ source.IsValueType)
1487                                 return false;
1488
1489                         return source.IsAssignableTo (target);
1490                 }
1491
1492                 static Expression CheckLambda (Type delegateType, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
1493                 {
1494                         if (!delegateType.IsSubclassOf (typeof (System.Delegate)))
1495                                 throw new ArgumentException ("delegateType");
1496
1497                         var invoke = delegateType.GetInvokeMethod ();
1498                         if (invoke == null)
1499                                 throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
1500
1501                         var invoke_parameters = invoke.GetParameters ();
1502                         if (invoke_parameters.Length != parameters.Count)
1503                                 throw new ArgumentException (string.Format ("Different number of arguments in delegate {0}", delegateType), "delegateType");
1504
1505                         for (int i = 0; i < invoke_parameters.Length; i++) {
1506                                 var parameter = parameters [i];
1507                                 if (parameter == null)
1508                                         throw new ArgumentNullException ("parameters");
1509
1510                                 if (!CanAssign (parameter.Type, invoke_parameters [i].ParameterType))
1511                                         throw new ArgumentException (String.Format ("Can not assign a {0} to a {1}", invoke_parameters [i].ParameterType, parameter.Type));
1512                         }
1513
1514                         if (invoke.ReturnType != typeof (void)) {
1515                                 if (!CanAssign (invoke.ReturnType, body.Type)) {
1516                                         if (invoke.ReturnType.IsExpression ())
1517                                                 return Expression.Quote (body);
1518
1519                                         throw new ArgumentException (String.Format ("body type {0} can not be assigned to {1}", body.Type, invoke.ReturnType));
1520                                 }
1521                         }
1522                         return body;
1523                 }
1524
1525                 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1526                 {
1527                         return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1528                 }
1529
1530                 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1531                 {
1532                         if (body == null)
1533                                 throw new ArgumentNullException ("body");
1534
1535                         var ps = parameters.ToReadOnlyCollection ();
1536
1537                         body = CheckLambda (typeof (TDelegate), body, ps);
1538
1539                         return new Expression<TDelegate> (body, ps);
1540                 }
1541
1542                 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1543                 {
1544                         if (body == null)
1545                                 throw new ArgumentNullException ("body");
1546                         if (parameters.Length > 4)
1547                                 throw new ArgumentException ("Too many parameters");
1548
1549                         return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1550                 }
1551
1552                 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1553                 {
1554                         if (parameters == null)
1555                                 parameters = new ParameterExpression [0];
1556
1557                         if (return_type == typeof (void))
1558                                 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1559
1560                         var types = new Type [parameters.Length + 1];
1561                         for (int i = 0; i < types.Length - 1; i++)
1562                                 types [i] = parameters [i].Type;
1563
1564                         types [types.Length - 1] = return_type;
1565                         return GetFuncType (types);
1566                 }
1567
1568                 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1569                 {
1570                         return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1571                 }
1572
1573                 static LambdaExpression CreateExpressionOf (Type type, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
1574                 {
1575                         return (LambdaExpression) typeof (Expression<>).MakeGenericType (type).GetConstructor (
1576                                 NonPublicInstance, null, new [] { typeof (Expression), typeof (ReadOnlyCollection<ParameterExpression>) }, null).Invoke (new object [] { body, parameters } );
1577                 }
1578
1579                 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1580                 {
1581                         if (delegateType == null)
1582                                 throw new ArgumentNullException ("delegateType");
1583                         if (body == null)
1584                                 throw new ArgumentNullException ("body");
1585
1586                         var ps = parameters.ToReadOnlyCollection ();
1587
1588                         body = CheckLambda (delegateType, body, ps);
1589
1590                         return CreateExpressionOf (delegateType, body, ps);
1591                 }
1592
1593                 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1594                 {
1595                         return ListBind (member, initializers as IEnumerable<ElementInit>);
1596                 }
1597
1598                 static void CheckIsAssignableToIEnumerable (Type t)
1599                 {
1600                         if (!t.IsAssignableTo (typeof (IEnumerable)))
1601                                 throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t));
1602                 }
1603
1604                 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1605                 {
1606                         if (member == null)
1607                                 throw new ArgumentNullException ("member");
1608                         if (initializers == null)
1609                                 throw new ArgumentNullException ("initializers");
1610
1611                         var inits = initializers.ToReadOnlyCollection ();
1612                         CheckForNull (inits, "initializers");
1613
1614                         member.OnFieldOrProperty (
1615                                 field => CheckIsAssignableToIEnumerable (field.FieldType),
1616                                 prop => CheckIsAssignableToIEnumerable (prop.PropertyType));
1617
1618                         return new MemberListBinding (member, inits);
1619                 }
1620
1621                 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1622                 {
1623                         return ListBind (propertyAccessor, initializers as IEnumerable<ElementInit>);
1624                 }
1625
1626                 static void CheckForNull<T> (ReadOnlyCollection<T> collection, string name) where T : class
1627                 {
1628                         foreach (var t in collection)
1629                                 if (t == null)
1630                                         throw new ArgumentNullException (name);
1631                 }
1632
1633                 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1634                 {
1635                         if (propertyAccessor == null)
1636                                 throw new ArgumentNullException ("propertyAccessor");
1637                         if (initializers == null)
1638                                 throw new ArgumentNullException ("initializers");
1639
1640                         var inits = initializers.ToReadOnlyCollection ();
1641                         CheckForNull (inits, "initializers");
1642
1643                         var prop = GetAssociatedProperty (propertyAccessor);
1644                         if (prop == null)
1645                                 throw new ArgumentException ("propertyAccessor");
1646
1647                         CheckIsAssignableToIEnumerable (prop.PropertyType);
1648
1649                         return new MemberListBinding (prop, inits);
1650                 }
1651
1652                 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1653                 {
1654                         return ListInit (newExpression, initializers as IEnumerable<ElementInit>);
1655                 }
1656
1657                 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1658                 {
1659                         var inits = CheckListInit (newExpression, initializers);
1660
1661                         return new ListInitExpression (newExpression, inits);
1662                 }
1663
1664                 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1665                 {
1666                         return ListInit (newExpression, initializers as IEnumerable<Expression>);
1667                 }
1668
1669                 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1670                 {
1671                         var inits = CheckListInit (newExpression, initializers);
1672
1673                         var add_method = GetAddMethod (newExpression.Type, inits [0].Type);
1674                         if (add_method == null)
1675                                 throw new InvalidOperationException ("No suitable add method found");
1676
1677                         return new ListInitExpression (newExpression, CreateInitializers (add_method, inits));
1678                 }
1679
1680                 static ReadOnlyCollection<ElementInit> CreateInitializers (MethodInfo add_method, ReadOnlyCollection<Expression> initializers)
1681                 {
1682                         return (from init in initializers select Expression.ElementInit (add_method, init)).ToReadOnlyCollection ();
1683                 }
1684
1685                 static MethodInfo GetAddMethod (Type type, Type arg)
1686                 {
1687                         return type.GetMethod ("Add", PublicInstance | BindingFlags.IgnoreCase, null, new [] { arg }, null);
1688                 }
1689
1690                 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1691                 {
1692                         return ListInit (newExpression, addMethod, initializers as IEnumerable<Expression>);
1693                 }
1694
1695                 static ReadOnlyCollection<T> CheckListInit<T> (NewExpression newExpression, IEnumerable<T> initializers) where T : class
1696                 {
1697                         if (newExpression == null)
1698                                 throw new ArgumentNullException ("newExpression");
1699                         if (initializers == null)
1700                                 throw new ArgumentNullException ("initializers");
1701                         if (!newExpression.Type.IsAssignableTo (typeof (IEnumerable)))
1702                                 throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
1703
1704                         var inits = initializers.ToReadOnlyCollection ();
1705                         if (inits.Count == 0)
1706                                 throw new ArgumentException ("Empty initializers");
1707
1708                         CheckForNull (inits, "initializers");
1709
1710                         return inits;
1711                 }
1712
1713                 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1714                 {
1715                         var inits = CheckListInit (newExpression, initializers);
1716
1717                         if (addMethod != null) {
1718                                 if (addMethod.Name.ToLowerInvariant () != "add")
1719                                         throw new ArgumentException ("addMethod");
1720
1721                                 var parameters = addMethod.GetParameters ();
1722                                 if (parameters.Length != 1)
1723                                         throw new ArgumentException ("addMethod");
1724
1725                                 foreach (var expression in inits)
1726                                         if (!IsAssignableToParameterType (expression.Type, parameters [0]))
1727                                                 throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
1728                         }
1729
1730                         if (addMethod == null)
1731                                 addMethod = GetAddMethod (newExpression.Type, inits [0].Type);
1732
1733                         if (addMethod == null)
1734                                 throw new InvalidOperationException ("No suitable add method found");
1735
1736                         return new ListInitExpression (newExpression, CreateInitializers (addMethod, inits));
1737                 }
1738
1739                 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1740                 {
1741                         if (expression == null)
1742                                 throw new ArgumentNullException ("expression");
1743                         if (member == null)
1744                                 throw new ArgumentNullException ("member");
1745
1746                         var field = member as FieldInfo;
1747                         if (field != null)
1748                                 return Field (expression, field);
1749
1750                         var property = member as PropertyInfo;
1751                         if (property != null)
1752                                 return Property (expression, property);
1753
1754                         throw new ArgumentException ("Member should either be a field or a property");
1755                 }
1756
1757                 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1758                 {
1759                         return MakeUnary (unaryType, operand, type, null);
1760                 }
1761
1762                 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1763                 {
1764                         switch (unaryType) {
1765                         case ExpressionType.ArrayLength:
1766                                 return ArrayLength (operand);
1767                         case ExpressionType.Convert:
1768                                 return Convert (operand, type, method);
1769                         case ExpressionType.ConvertChecked:
1770                                 return ConvertChecked (operand, type, method);
1771                         case ExpressionType.Negate:
1772                                 return Negate (operand, method);
1773                         case ExpressionType.NegateChecked:
1774                                 return NegateChecked (operand, method);
1775                         case ExpressionType.Not:
1776                                 return Not (operand, method);
1777                         case ExpressionType.Quote:
1778                                 return Quote (operand);
1779                         case ExpressionType.TypeAs:
1780                                 return TypeAs (operand, type);
1781                         case ExpressionType.UnaryPlus:
1782                                 return UnaryPlus (operand, method);
1783                         }
1784
1785                         throw new ArgumentException ("MakeUnary expect an unary operator");
1786                 }
1787
1788                 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] bindings)
1789                 {
1790                         return MemberBind (member, bindings as IEnumerable<MemberBinding>);
1791                 }
1792
1793                 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> bindings)
1794                 {
1795                         if (member == null)
1796                                 throw new ArgumentNullException ("member");
1797
1798                         var type = member.OnFieldOrProperty (
1799                                 field => field.FieldType,
1800                                 prop => prop.PropertyType);
1801
1802                         return new MemberMemberBinding (member, CheckMemberBindings (type, bindings));
1803                 }
1804
1805                 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] bindings)
1806                 {
1807                         return MemberBind (propertyAccessor, bindings as IEnumerable<MemberBinding>);
1808                 }
1809
1810                 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> bindings)
1811                 {
1812                         if (propertyAccessor == null)
1813                                 throw new ArgumentNullException ("propertyAccessor");
1814
1815                         var bds = bindings.ToReadOnlyCollection ();
1816                         CheckForNull (bds, "bindings");
1817
1818                         var prop = GetAssociatedProperty (propertyAccessor);
1819                         if (prop == null)
1820                                 throw new ArgumentException ("propertyAccessor");
1821
1822                         return new MemberMemberBinding (prop, CheckMemberBindings (prop.PropertyType, bindings));
1823                 }
1824
1825                 static ReadOnlyCollection<MemberBinding> CheckMemberBindings (Type type, IEnumerable<MemberBinding> bindings)
1826                 {
1827                         if (bindings == null)
1828                                 throw new ArgumentNullException ("bindings");
1829
1830                         var bds = bindings.ToReadOnlyCollection ();
1831                         CheckForNull (bds, "bindings");
1832
1833                         foreach (var binding in bds)
1834                                 if (!type.IsAssignableTo (binding.Member.DeclaringType))
1835                                         throw new ArgumentException ("Type not assignable to member type");
1836
1837                         return bds;
1838                 }
1839
1840                 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] bindings)
1841                 {
1842                         return MemberInit (newExpression, bindings as IEnumerable<MemberBinding>);
1843                 }
1844
1845                 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> bindings)
1846                 {
1847                         if (newExpression == null)
1848                                 throw new ArgumentNullException ("newExpression");
1849
1850                         return new MemberInitExpression (newExpression, CheckMemberBindings (newExpression.Type, bindings));
1851                 }
1852
1853                 public static UnaryExpression Negate (Expression expression)
1854                 {
1855                         return Negate (expression, null);
1856                 }
1857
1858                 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1859                 {
1860                         method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1861
1862                         return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1863                 }
1864
1865                 public static UnaryExpression NegateChecked (Expression expression)
1866                 {
1867                         return NegateChecked (expression, null);
1868                 }
1869
1870                 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1871                 {
1872                         method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
1873
1874                         return MakeSimpleUnary (ExpressionType.NegateChecked, expression, method);
1875                 }
1876
1877                 public static NewExpression New (ConstructorInfo constructor)
1878                 {
1879                         if (constructor == null)
1880                                 throw new ArgumentNullException ("constructor");
1881
1882                         if (constructor.GetParameters ().Length > 0)
1883                                 throw new ArgumentException ("Constructor must be parameter less");
1884
1885                         return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection (), null);
1886                 }
1887
1888                 public static NewExpression New (Type type)
1889                 {
1890                         if (type == null)
1891                                 throw new ArgumentNullException ("type");
1892
1893                         CheckNotVoid (type);
1894
1895                         var args = (null as IEnumerable<Expression>).ToReadOnlyCollection ();
1896
1897                         if (type.IsValueType)
1898                                 return new NewExpression (type, args);
1899
1900                         var ctor = type.GetConstructor (Type.EmptyTypes);
1901                         if (ctor == null)
1902                                 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1903
1904                         return new NewExpression (ctor, args, null);
1905                 }
1906
1907                 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1908                 {
1909                         return New (constructor, arguments as IEnumerable<Expression>);
1910                 }
1911
1912                 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1913                 {
1914                         if (constructor == null)
1915                                 throw new ArgumentNullException ("constructor");
1916
1917                         var args = CheckMethodArguments (constructor, arguments);
1918
1919                         return new NewExpression (constructor, args, null);
1920                 }
1921
1922                 static IList<Expression> CreateArgumentList (IEnumerable<Expression> arguments)
1923                 {
1924                         if (arguments == null)
1925                                 return arguments.ToReadOnlyCollection ();
1926
1927                         return arguments.ToList ();
1928                 }
1929
1930                 static void CheckNonGenericMethod (MethodBase method)
1931                 {
1932                         if (method.IsGenericMethodDefinition || method.ContainsGenericParameters)
1933                                 throw new ArgumentException ("Can not used open generic methods");
1934                 }
1935
1936                 static ReadOnlyCollection<Expression> CheckMethodArguments (MethodBase method, IEnumerable<Expression> args)
1937                 {
1938                         CheckNonGenericMethod (method);
1939
1940                         var arguments = CreateArgumentList (args);
1941                         var parameters = method.GetParameters ();
1942
1943                         if (arguments.Count != parameters.Length)
1944                                 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1945
1946                         for (int i = 0; i < parameters.Length; i++) {
1947                                 if (arguments [i] == null)
1948                                         throw new ArgumentNullException ("arguments");
1949
1950                                 if (!IsAssignableToParameterType (arguments [i].Type, parameters [i])) {
1951                                         if (!parameters [i].ParameterType.IsExpression ())
1952                                                 throw new ArgumentException ("arguments");
1953
1954                                         arguments [i] = Expression.Quote (arguments [i]);
1955                                 }
1956                         }
1957
1958                         return arguments.ToReadOnlyCollection ();
1959                 }
1960
1961                 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1962                 {
1963                         return New (constructor, arguments, members as IEnumerable<MemberInfo>);
1964                 }
1965
1966                 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1967                 {
1968                         if (constructor == null)
1969                                 throw new ArgumentNullException ("constructor");
1970
1971                         var args = arguments.ToReadOnlyCollection ();
1972                         var mmbs = members.ToReadOnlyCollection ();
1973
1974                         CheckForNull (args, "arguments");
1975                         CheckForNull (mmbs, "members");
1976
1977                         args = CheckMethodArguments (constructor, arguments);
1978
1979                         if (args.Count != mmbs.Count)
1980                                 throw new ArgumentException ("Arguments count does not match members count");
1981
1982                         for (int i = 0; i < mmbs.Count; i++) {
1983                                 var member = mmbs [i];
1984                                 Type type = null;
1985                                 switch (member.MemberType) {
1986                                 case MemberTypes.Field:
1987                                         type = (member as FieldInfo).FieldType;
1988                                         break;
1989                                 case MemberTypes.Method:
1990                                         type = (member as MethodInfo).ReturnType;
1991                                         break;
1992                                 case MemberTypes.Property:
1993                                         var prop = member as PropertyInfo;
1994                                         if (prop.GetGetMethod (true) == null)
1995                                                 throw new ArgumentException ("Property must have a getter");
1996
1997                                         type = (member as PropertyInfo).PropertyType;
1998                                         break;
1999                                 default:
2000                                         throw new ArgumentException ("Member type not allowed");
2001                                 }
2002
2003                                 if (!args [i].Type.IsAssignableTo (type))
2004                                         throw new ArgumentException ("Argument type not assignable to member type");
2005                         }
2006
2007                         return new NewExpression (constructor, args, mmbs);
2008                 }
2009
2010                 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
2011                 {
2012                         return NewArrayBounds (type, bounds as IEnumerable<Expression>);
2013                 }
2014
2015                 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
2016                 {
2017                         if (type == null)
2018                                 throw new ArgumentNullException ("type");
2019                         if (bounds == null)
2020                                 throw new ArgumentNullException ("bounds");
2021
2022                         CheckNotVoid (type);
2023
2024                         var array_bounds = bounds.ToReadOnlyCollection ();
2025                         foreach (var expression in array_bounds)
2026                                 if (!IsInt (expression.Type))
2027                                         throw new ArgumentException ("The bounds collection can only contain expression of integers types");
2028
2029                         return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
2030                 }
2031
2032                 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
2033                 {
2034                         return NewArrayInit (type, initializers as IEnumerable<Expression>);
2035                 }
2036
2037                 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
2038                 {
2039                         if (type == null)
2040                                 throw new ArgumentNullException ("type");
2041                         if (initializers == null)
2042                                 throw new ArgumentNullException ("initializers");
2043
2044                         CheckNotVoid (type);
2045
2046                         var inits = initializers.ToReadOnlyCollection ();
2047
2048                         foreach (var expression in inits) {
2049                                 if (expression == null)
2050                                         throw new ArgumentNullException ("initializers");
2051
2052                                 if (!expression.Type.IsAssignableTo (type))
2053                                         throw new InvalidOperationException (
2054                                                 string.Format ("{0} IsAssignableTo {1}, expression [ {2} ] : {3}", expression.Type, type, expression.NodeType, expression));
2055
2056                                 // TODO: Quote elements if type == typeof (Expression)
2057                         }
2058
2059                         return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), inits);
2060                 }
2061
2062                 public static UnaryExpression Not (Expression expression)
2063                 {
2064                         return Not (expression, null);
2065                 }
2066
2067                 public static UnaryExpression Not (Expression expression, MethodInfo method)
2068                 {
2069                         Func<Type, bool> validator = type => IsIntOrBool (type);
2070
2071                         method = UnaryCoreCheck ("op_LogicalNot", expression, method, validator);
2072
2073                         if (method == null)
2074                                 method = UnaryCoreCheck ("op_OnesComplement", expression, method, validator);
2075
2076                         return MakeSimpleUnary (ExpressionType.Not, expression, method);
2077                 }
2078
2079                 static void CheckNotVoid (Type type)
2080                 {
2081                         if (type == typeof (void))
2082                                 throw new ArgumentException ("Type can't be void");
2083                 }
2084
2085                 public static ParameterExpression Parameter (Type type, string name)
2086                 {
2087                         if (type == null)
2088                                 throw new ArgumentNullException ("type");
2089
2090                         CheckNotVoid (type);
2091
2092                         return new ParameterExpression (type, name);
2093                 }
2094
2095                 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
2096                 {
2097                         if (propertyAccessor == null)
2098                                 throw new ArgumentNullException ("propertyAccessor");
2099
2100                         CheckNonGenericMethod (propertyAccessor);
2101
2102                         if (!propertyAccessor.IsStatic) {
2103                                 if (expression == null)
2104                                         throw new ArgumentNullException ("expression");
2105                                 if (!expression.Type.IsAssignableTo (propertyAccessor.DeclaringType))
2106                                         throw new ArgumentException ("expression");
2107                         }
2108                         //
2109                         // .NET does not mandate that if the property is static, that the expression must be null
2110                         // fixes a bug exposed by Orchard's ContentItemRecordAlteration.Alteration
2111                         // else if (expression != null)
2112                         //              throw new ArgumentException ("expression");
2113
2114                         var prop = GetAssociatedProperty (propertyAccessor);
2115                         if (prop == null)
2116                                 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
2117
2118                         return new MemberExpression (expression, prop, prop.PropertyType);
2119                 }
2120
2121                 static PropertyInfo GetAssociatedProperty (MethodInfo method)
2122                 {
2123                         if (method == null)
2124                                 return null;
2125
2126                         foreach (var prop in method.DeclaringType.GetProperties (All)) {
2127                                 if (method.Equals (prop.GetGetMethod (true)))
2128                                         return prop;
2129                                 if (method.Equals (prop.GetSetMethod (true)))
2130                                         return prop;
2131                         }
2132
2133                         return null;
2134                 }
2135
2136                 public static MemberExpression Property (Expression expression, PropertyInfo property)
2137                 {
2138                         if (property == null)
2139                                 throw new ArgumentNullException ("property");
2140
2141                         var getter = property.GetGetMethod (true);
2142                         if (getter == null)
2143                                 throw new ArgumentException ("getter");
2144
2145                         if (!getter.IsStatic) {
2146                                 if (expression == null)
2147                                         throw new ArgumentNullException ("expression");
2148                                 if (!expression.Type.IsAssignableTo (property.DeclaringType))
2149                                         throw new ArgumentException ("expression");
2150                         } else if (expression != null)
2151                                 throw new ArgumentException ("expression");
2152
2153                         return new MemberExpression (expression, property, property.PropertyType);
2154                 }
2155
2156                 public static MemberExpression Property (Expression expression, string propertyName)
2157                 {
2158                         if (expression == null)
2159                                 throw new ArgumentNullException ("expression");
2160
2161                         var prop = expression.Type.GetProperty (propertyName, AllInstance);
2162                         if (prop == null)
2163                                 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
2164
2165                         return new MemberExpression (expression, prop, prop.PropertyType);
2166                 }
2167
2168                 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
2169                 {
2170                         if (expression == null)
2171                                 throw new ArgumentNullException ("expression");
2172                         if (propertyOrFieldName == null)
2173                                 throw new ArgumentNullException ("propertyOrFieldName");
2174
2175                         var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
2176                         if (prop != null)
2177                                 return new MemberExpression (expression, prop, prop.PropertyType);
2178
2179                         var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
2180                         if (field != null)
2181                                 return new MemberExpression (expression, field, field.FieldType);
2182
2183                         throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
2184                 }
2185
2186                 public static UnaryExpression Quote (Expression expression)
2187                 {
2188                         if (expression == null)
2189                                 throw new ArgumentNullException ("expression");
2190
2191                         return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
2192                 }
2193
2194                 public static UnaryExpression TypeAs (Expression expression, Type type)
2195                 {
2196                         if (expression == null)
2197                                 throw new ArgumentNullException ("expression");
2198                         if (type == null)
2199                                 throw new ArgumentNullException ("type");
2200                         if (type.IsValueType && !type.IsNullable ())
2201                                 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
2202
2203                         return new UnaryExpression (ExpressionType.TypeAs, expression, type);
2204                 }
2205
2206                 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
2207                 {
2208                         if (expression == null)
2209                                 throw new ArgumentNullException ("expression");
2210                         if (type == null)
2211                                 throw new ArgumentNullException ("type");
2212
2213                         CheckNotVoid (type);
2214
2215                         return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
2216                 }
2217
2218                 public static UnaryExpression UnaryPlus (Expression expression)
2219                 {
2220                         return UnaryPlus (expression, null);
2221                 }
2222
2223                 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
2224                 {
2225                         method = UnaryCoreCheck ("op_UnaryPlus", expression, method, type => IsNumber (type));
2226
2227                         return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
2228                 }
2229
2230                 static bool IsInt (Type t)
2231                 {
2232                         return t == typeof (byte) || t == typeof (sbyte) ||
2233                                 t == typeof (short) || t == typeof (ushort) ||
2234                                 t == typeof (int) || t == typeof (uint) ||
2235                                 t == typeof (long) || t == typeof (ulong);
2236                 }
2237
2238                 static bool IsIntOrBool (Type t)
2239                 {
2240                         return IsInt (t) || t == typeof (bool);
2241                 }
2242
2243                 static bool IsNumber (Type t)
2244                 {
2245                         if (IsInt (t))
2246                                 return true;
2247
2248                         return t == typeof (float) || t == typeof (double);
2249                 }
2250
2251                 static bool IsSignedNumber (Type t)
2252                 {
2253                         return IsNumber (t) && !IsUnsigned (t);
2254                 }
2255
2256                 internal static bool IsUnsigned (Type t)
2257                 {
2258 #if !TARGET_JVM
2259                         if (t.IsPointer)
2260                                 return IsUnsigned (t.GetElementType ());
2261
2262 #endif
2263                         return t == typeof (ushort) ||
2264                                 t == typeof (uint) ||
2265                                 t == typeof (ulong) ||
2266                                 t == typeof (byte);
2267                 }
2268
2269                 //
2270                 // This method must be overwritten by derived classes to
2271                 // compile the expression
2272                 //
2273 #if !FULL_AOT_RUNTIME
2274                 internal virtual void Emit (EmitContext ec)
2275                 {
2276                         throw new NotImplementedException (String.Format ("Emit method is not implemented in expression type {0}", GetType ()));
2277                 }
2278 #endif
2279         }
2280 }