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