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