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