revert fix
[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.Generic;
32 using System.Collections.ObjectModel;
33 using System.Linq;
34 using System.Reflection;
35
36 namespace System.Linq.Expressions {
37
38         public abstract class Expression {
39
40                 ExpressionType node_type;
41                 Type type;
42
43                 static BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
44                 static BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
45                 static BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
46                 static BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
47                 static BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
48
49                 public ExpressionType NodeType {
50                         get { return node_type; }
51                 }
52
53                 public Type Type {
54                         get { return type; }
55                 }
56
57                 protected Expression (ExpressionType node_type, Type type)
58                 {
59                         this.node_type = node_type;
60                         this.type = type;
61                 }
62
63                 public override string ToString ()
64                 {
65                         return ExpressionPrinter.ToString (this);
66                 }
67
68                 static void CheckMethod (MethodInfo m)
69                 {
70                 }
71
72 #region Binary Expressions
73                 static bool IsInt (Type t)
74                 {
75                         return t == typeof (byte) || t == typeof (sbyte) ||
76                                 t == typeof (short) || t == typeof (ushort) ||
77                                 t == typeof (int) || t == typeof (uint) ||
78                                 t == typeof (long) || t == typeof (ulong);
79                 }
80
81                 static bool IsNumber (Type t)
82                 {
83                         if (IsInt (t))
84                                 return true;
85
86                         return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
87                 }
88
89                 static MethodInfo GetUnaryOperator (string oper_name, Type on_type, Expression expression)
90                 {
91                         var methods = on_type.GetMethods (PublicStatic);
92
93                         foreach (var method in methods) {
94                                 if (method.Name != oper_name)
95                                         continue;
96
97                                 var parameters = method.GetParameters ();
98                                 if (parameters.Length != 1)
99                                         continue;
100
101                                 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
102                                         continue;
103
104                                 return method;
105                         }
106
107                         return null;
108                 }
109
110                 static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method)
111                 {
112                         if (expression == null)
113                                 throw new ArgumentNullException ("expression");
114
115                         if (method != null) {
116                                 if (method.ReturnType == typeof (void))
117                                         throw new ArgumentException ("Specified method must return a value", "method");
118
119                                 if (!method.IsStatic)
120                                         throw new ArgumentException ("Method must be static", "method");
121
122                                 var parameters = method.GetParameters ();
123
124                                 if (parameters.Length != 1)
125                                         throw new ArgumentException ("Must have only one parameters", "method");
126
127                                 if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
128                                         throw new InvalidOperationException ("left-side argument type does not match left expression type");
129
130                                 return method;
131                         } else {
132                                 if (IsNumber (expression.Type))
133                                         return null;
134
135                                 if (oper_name != null) {
136                                         method = GetUnaryOperator (oper_name, expression.Type, expression);
137                                         if (method != null)
138                                                 return method;
139                                 }
140
141                                 throw new InvalidOperationException (
142                                         String.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
143                         }
144                 }
145
146                 static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
147                 {
148                         MethodInfo [] methods = on_type.GetMethods (PublicStatic);
149
150                         foreach (MethodInfo m in methods){
151                                 if (m.Name != oper_name)
152                                         continue;
153
154                                 ParameterInfo [] pi = m.GetParameters ();
155                                 if (pi.Length != 2)
156                                         continue;
157
158                                 if (!pi [0].ParameterType.IsAssignableFrom (left.Type))
159                                         continue;
160
161                                 if (!pi [1].ParameterType.IsAssignableFrom (right.Type))
162                                         continue;
163
164                                 // Method has papers in order.
165                                 return m;
166                         }
167
168                         return null;
169                 }
170
171                 //
172                 // Performs basic checks on the incoming expressions for binary expressions
173                 // and any provided MethodInfo.
174                 //
175                 static MethodInfo BinaryCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
176                 {
177                         if (left == null)
178                                 throw new ArgumentNullException ("left");
179                         if (right == null)
180                                 throw new ArgumentNullException ("right");
181
182                         if (method != null){
183                                 if (method.ReturnType == typeof (void))
184                                         throw new ArgumentException ("Specified method must return a value", "method");
185
186                                 if (!method.IsStatic)
187                                         throw new ArgumentException ("Method must be static", "method");
188                                 ParameterInfo [] pi = method.GetParameters ();
189
190                                 if (pi.Length != 2)
191                                         throw new ArgumentException ("Must have only two parameters", "method");
192
193                                 Type ltype = left.Type.IsValueType && IsNullable (left.Type) ? GetNullableOf(left.Type) : left.Type;
194                                 Type rtype = left.Type.IsValueType && IsNullable (right.Type) ? GetNullableOf(right.Type) :right.Type;
195
196                                 if (ltype != pi [0].ParameterType)
197                                         throw new InvalidOperationException ("left-side argument type does not match left expression type");
198
199                                 if (rtype != pi [1].ParameterType)
200                                         throw new InvalidOperationException ("right-side argument type does not match right expression type");
201
202                                 return method;
203                         } else {
204                                 Type ltype = left.Type;
205                                 Type rtype = right.Type;
206                                 Type ultype = left.Type;
207                                 Type urtype = right.Type;
208
209                                 if (IsNullable (ltype))
210                                         ultype = GetNullableOf (ltype);
211
212                                 if (IsNullable (rtype))
213                                         urtype = GetNullableOf (rtype);
214
215                                 if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd"){
216                                         if (ultype == typeof (bool)){
217                                                 if (ultype == urtype && ltype == rtype)
218                                                         return null;
219                                         }
220                                 }
221
222                                 // Use IsNumber to avoid expensive reflection.
223                                 if (IsNumber (ultype)){
224                                         if (ultype == urtype && ltype == rtype)
225                                                 return method;
226
227                                         if (oper_name != null){
228                                                 method = GetBinaryOperator (oper_name, rtype, left, right);
229                                                 if (method != null)
230                                                         return method;
231                                         }
232                                 }
233
234                                 if (oper_name != null){
235                                         method = GetBinaryOperator (oper_name, ltype, left, right);
236                                         if (method != null)
237                                                 return method;
238                                 }
239
240                                 //
241                                 // == and != allow reference types without operators defined.
242                                 //
243                                 if (!ltype.IsValueType && !rtype.IsValueType &&
244                                         (oper_name == "op_Equality" || oper_name == "op_Inequality"))
245                                         return null;
246
247                                 throw new InvalidOperationException (
248                                         String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
249                         }
250                 }
251
252                 //
253                 // This is like BinaryCoreCheck, but if no method is used adds the restriction that
254                 // only ints and bools are allowed
255                 //
256                 static MethodInfo BinaryBitwiseCoreCheck (string oper_name, Expression left, Expression right, MethodInfo method)
257                 {
258                         if (left == null)
259                                 throw new ArgumentNullException ("left");
260                         if (right == null)
261                                 throw new ArgumentNullException ("right");
262
263                         if (method == null){
264                                 // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
265                                 if (left.Type == right.Type && (left.Type == typeof (bool) || IsInt (left.Type)))
266                                         return method;
267                         }
268
269                         method = BinaryCoreCheck (oper_name, left, right, method);
270                         if (method == null){
271                                 //
272                                 // The check in BinaryCoreCheck allows a bit more than we do
273                                 // (floats and doubles).  Catch this here
274                                 //
275                                 if (left.Type == typeof(double) || left.Type == typeof(float))
276                                         throw new InvalidOperationException ("Types not supported");
277                         }
278
279                         return method;
280                 }
281
282                 static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
283                 {
284                         Type result = method == null ? left.Type : method.ReturnType;
285                         bool is_lifted;
286
287                         if (method == null){
288                                 if (IsNullable (left.Type)){
289                                         if (!IsNullable (right.Type))
290                                                 throw new Exception ("Assertion, internal error: left is nullable, requires right to be as well");
291                                         is_lifted = true;
292                                 } else
293                                         is_lifted = false;
294                         } else {
295                                 //
296                                 // FIXME: implement
297                                 //
298                                 is_lifted = false;
299                         }
300
301                         return new BinaryExpression (et, result, left, right, false, is_lifted, method, null);
302                 }
303
304                 static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
305                 {
306                         Type result = method == null ? expression.Type : method.ReturnType;
307
308                         return new UnaryExpression (et, expression, result, method);
309                 }
310
311                 static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
312                 {
313                         Type result;
314                         Type ltype = left.Type;
315                         Type rtype = right.Type;
316                         bool lnullable = IsNullable (ltype);
317                         bool rnullable = IsNullable (rtype);
318                         bool is_lifted;
319
320                         //
321                         // Implement the rules as described in "Expression.Equal" method.
322                         //
323                         if (method == null){
324                                 if (lnullable == false && rnullable == false){
325                                         is_lifted = false;
326                                         result = typeof (bool);
327                                 } else if (lnullable && rnullable){
328                                         is_lifted = true;
329                                         result = liftToNull ? typeof(bool?) : typeof (bool);
330                                 } else
331                                         throw new Exception ("Internal error: this should have been caught in BinaryCoreCheck");
332                         } else {
333                                 ParameterInfo [] pi = method.GetParameters ();
334                                 Type mltype = pi [0].ParameterType;
335                                 Type mrtype = pi [1].ParameterType;
336
337                                 if (ltype == mltype && rtype == mrtype){
338                                         is_lifted = false;
339                                         result = method.ReturnType;
340                                 }
341                                 else if (ltype.IsValueType && rtype.IsValueType &&
342                                            ((lnullable && GetNullableOf (ltype) == mltype) ||
343                                                 (rnullable && GetNullableOf (rtype) == mrtype))){
344                                         is_lifted = true;
345                                         if (method.ReturnType == typeof(bool)){
346                                                 result = liftToNull ? typeof(bool?) : typeof(bool);
347                                         } else {
348                                                 //
349                                                 // This behavior is not documented: what
350                                                 // happens if the result is not typeof(bool), but
351                                                 // the parameters are nullable: the result
352                                                 // becomes nullable<returntype>
353                                                 //
354                                                 // See:
355                                                 // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
356                                                 result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
357                                                         //Type.GetType ("System.Nullable`1[" + method.ReturnType.ToString () + "]");
358                                         }
359                                 } else {
360                                         is_lifted = false;
361                                         result = method.ReturnType;
362                                 }
363                         }
364
365                         return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
366                 }
367
368                 //
369                 // Arithmetic
370                 //
371                 public static BinaryExpression Add (Expression left, Expression right)
372                 {
373                         return Add (left, right, null);
374                 }
375
376                 public static BinaryExpression Add (Expression left, Expression right, MethodInfo method)
377                 {
378                         method = BinaryCoreCheck ("op_Addition", left, right, method);
379
380                         return MakeSimpleBinary (ExpressionType.Add, left, right, method);
381                 }
382
383                 public static BinaryExpression AddChecked (Expression left, Expression right)
384                 {
385                         return AddChecked (left, right, null);
386                 }
387
388                 public static BinaryExpression AddChecked (Expression left, Expression right, MethodInfo method)
389                 {
390                         method = BinaryCoreCheck ("op_Addition", left, right, method);
391
392                         //
393                         // The check in BinaryCoreCheck allows a bit more than we do
394                         // (byte, sbyte).  Catch that here
395                         //
396
397                         if (method == null){
398                                 Type ltype = left.Type;
399
400                                 if (ltype == typeof (byte) || ltype == typeof (sbyte))
401                                         throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
402                         }
403
404                         return MakeSimpleBinary (ExpressionType.AddChecked, left, right, method);
405                 }
406
407                 public static BinaryExpression Subtract (Expression left, Expression right)
408                 {
409                         return Subtract (left, right, null);
410                 }
411
412                 public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
413                 {
414                         method = BinaryCoreCheck ("op_Subtraction", left, right, method);
415                         return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
416                 }
417
418                 public static BinaryExpression SubtractChecked (Expression left, Expression right)
419                 {
420                         return SubtractChecked (left, right, null);
421                 }
422
423                 public static BinaryExpression SubtractChecked (Expression left, Expression right, MethodInfo method)
424                 {
425                         method = BinaryCoreCheck ("op_Subtraction", left, right, method);
426
427                         //
428                         // The check in BinaryCoreCheck allows a bit more than we do
429                         // (byte, sbyte).  Catch that here
430                         //
431
432                         if (method == null){
433                                 Type ltype = left.Type;
434
435                                 if (ltype == typeof (byte) || ltype == typeof (sbyte))
436                                         throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
437                         }
438                         return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
439                 }
440
441                 public static BinaryExpression Modulo (Expression left, Expression right)
442                 {
443                         return Modulo (left, right, null);
444                 }
445
446                 public static BinaryExpression Modulo (Expression left, Expression right, MethodInfo method)
447                 {
448                         method = BinaryCoreCheck ("op_Modulus", left, right, method);
449
450                         return MakeSimpleBinary (ExpressionType.Modulo, left, right, method);
451                 }
452
453                 public static BinaryExpression Multiply (Expression left, Expression right)
454                 {
455                         return Multiply (left, right, null);
456                 }
457
458                 public static BinaryExpression Multiply (Expression left, Expression right, MethodInfo method)
459                 {
460                         method = BinaryCoreCheck ("op_Multiply", left, right, method);
461
462                         return MakeSimpleBinary (ExpressionType.Multiply, left, right, method);
463                 }
464
465                 public static BinaryExpression MultiplyChecked (Expression left, Expression right)
466                 {
467                         return MultiplyChecked (left, right, null);
468                 }
469
470                 public static BinaryExpression MultiplyChecked (Expression left, Expression right, MethodInfo method)
471                 {
472                         method = BinaryCoreCheck ("op_Multiply", left, right, method);
473
474                         return MakeSimpleBinary (ExpressionType.MultiplyChecked, left, right, method);
475                 }
476
477                 public static BinaryExpression Divide (Expression left, Expression right)
478                 {
479                         return Divide (left, right, null);
480                 }
481
482                 public static BinaryExpression Divide (Expression left, Expression right, MethodInfo method)
483                 {
484                         method = BinaryCoreCheck ("op_Division", left, right, method);
485
486                         return MakeSimpleBinary (ExpressionType.Divide, left, right, method);
487                 }
488
489                 public static BinaryExpression Power (Expression left, Expression right)
490                 {
491                         return Power (left, right, null);
492                 }
493
494                 public static BinaryExpression Power (Expression left, Expression right, MethodInfo method)
495                 {
496                         method = BinaryCoreCheck (null, left, right, method);
497
498                         if (left.Type != typeof (double))
499                                 throw new InvalidOperationException ("Power only supports double arguments");
500
501                         return MakeSimpleBinary (ExpressionType.Power, left, right, method);
502                 }
503
504                 //
505                 // Bitwise
506                 //
507                 public static BinaryExpression And (Expression left, Expression right)
508                 {
509                         return And (left, right, null);
510                 }
511
512                 public static BinaryExpression And (Expression left, Expression right, MethodInfo method)
513                 {
514                         method = BinaryBitwiseCoreCheck ("op_BitwiseAnd", left, right, method);
515
516                         return MakeSimpleBinary (ExpressionType.And, left, right, method);
517                 }
518
519                 public static BinaryExpression Or (Expression left, Expression right)
520                 {
521                         return Or (left, right, null);
522                 }
523
524                 public static BinaryExpression Or (Expression left, Expression right, MethodInfo method)
525                 {
526                         method = BinaryBitwiseCoreCheck ("op_BitwiseOr", left, right, method);
527
528                         return MakeSimpleBinary (ExpressionType.Or, left, right, method);
529                 }
530
531                 public static BinaryExpression ExclusiveOr (Expression left, Expression right)
532                 {
533                         return ExclusiveOr (left, right, null);
534                 }
535
536                 public static BinaryExpression ExclusiveOr (Expression left, Expression right, MethodInfo method)
537                 {
538                         method = BinaryBitwiseCoreCheck ("op_ExclusiveOr", left, right, method);
539
540                         return MakeSimpleBinary (ExpressionType.ExclusiveOr, left, right, method);
541                 }
542
543                 public static BinaryExpression LeftShift (Expression left, Expression right)
544                 {
545                         return LeftShift (left, right, null);
546                 }
547
548                 public static BinaryExpression LeftShift (Expression left, Expression right, MethodInfo method)
549                 {
550                         method = BinaryBitwiseCoreCheck ("op_LeftShift", left, right, method);
551
552                         return MakeSimpleBinary (ExpressionType.LeftShift, left, right, method);
553                 }
554
555                 public static BinaryExpression RightShift (Expression left, Expression right)
556                 {
557                         return RightShift (left, right, null);
558                 }
559
560                 public static BinaryExpression RightShift (Expression left, Expression right, MethodInfo method)
561                 {
562                         method = BinaryCoreCheck ("op_RightShift", left, right, method);
563
564                         return MakeSimpleBinary (ExpressionType.RightShift, left, right, method);
565                 }
566
567                 //
568                 // Short-circuit
569                 //
570                 public static BinaryExpression AndAlso (Expression left, Expression right)
571                 {
572                         return AndAlso (left, right, null);
573                 }
574
575                 public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
576                 {
577                         method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
578
579                         return MakeBoolBinary (ExpressionType.AndAlso, left, right, false, method);
580                 }
581
582                 static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
583                 {
584                         method = BinaryCoreCheck (oper, left, right, method);
585
586                         if (method == null) {
587                                 if (left.Type != typeof (bool))
588                                         throw new InvalidOperationException ("Only booleans are allowed");
589                         } else {
590                                 // The method should have identical parameter and return types.
591
592                                 if (left.Type != right.Type || method.ReturnType != left.Type)
593                                         throw new ArgumentException ("left, right and return type must match");
594                         }
595
596                         return method;
597                 }
598
599                 public static BinaryExpression OrElse (Expression left, Expression right)
600                 {
601                         return OrElse (left, right, null);
602                 }
603
604                 public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
605                 {
606                         method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
607
608                         return MakeBoolBinary (ExpressionType.OrElse, left, right, false, method);
609                 }
610
611                 //
612                 // Comparison
613                 //
614                 public static BinaryExpression Equal (Expression left, Expression right)
615                 {
616                         return Equal (left, right, false, null);
617                 }
618
619                 public static BinaryExpression Equal (Expression left, Expression right, bool liftToNull, MethodInfo method)
620                 {
621                         method = BinaryCoreCheck ("op_Equality", left, right, method);
622
623                         return MakeBoolBinary (ExpressionType.Equal, left, right, liftToNull, method);
624                 }
625
626                 public static BinaryExpression NotEqual (Expression left, Expression right)
627                 {
628                         return NotEqual (left, right, false, null);
629                 }
630
631
632                 public static BinaryExpression NotEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
633                 {
634                         method = BinaryCoreCheck ("op_Inequality", left, right, method);
635
636                         return MakeBoolBinary (ExpressionType.NotEqual, left, right, liftToNull, method);
637                 }
638
639                 public static BinaryExpression GreaterThan (Expression left, Expression right)
640                 {
641                         return GreaterThan (left, right, false, null);
642                 }
643
644                 public static BinaryExpression GreaterThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
645                 {
646                         method = BinaryCoreCheck ("op_GreaterThan", left, right, method);
647
648                         return MakeBoolBinary (ExpressionType.GreaterThan, left, right, liftToNull, method);
649                 }
650
651                 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right)
652                 {
653                         return GreaterThanOrEqual (left, right, false, null);
654                 }
655
656
657                 public static BinaryExpression GreaterThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
658                 {
659                         method = BinaryCoreCheck ("op_GreaterThanOrEqual", left, right, method);
660
661                         return MakeBoolBinary (ExpressionType.GreaterThanOrEqual, left, right, liftToNull, method);
662                 }
663
664                 public static BinaryExpression LessThan (Expression left, Expression right)
665                 {
666                         return LessThan (left, right, false, null);
667                 }
668
669                 public static BinaryExpression LessThan (Expression left, Expression right, bool liftToNull, MethodInfo method)
670                 {
671                         method = BinaryCoreCheck ("op_LessThan", left, right, method);
672
673                         return MakeBoolBinary (ExpressionType.LessThan, left, right, liftToNull, method);
674                 }
675
676                 public static BinaryExpression LessThanOrEqual (Expression left, Expression right)
677                 {
678                         return LessThanOrEqual (left, right, false, null);
679                 }
680
681                 public static BinaryExpression LessThanOrEqual (Expression left, Expression right, bool liftToNull, MethodInfo method)
682                 {
683                         method = BinaryCoreCheck ("op_LessThanOrEqual", left, right, method);
684
685                         return MakeBoolBinary (ExpressionType.LessThanOrEqual, left, right, liftToNull, method);
686                 }
687
688                 //
689                 // Miscelaneous
690                 //
691
692                 static void ArrayCheck (Expression array)
693                 {
694                         if (array == null)
695                                 throw new ArgumentNullException ("array");
696                         if (!array.Type.IsArray)
697                                 throw new ArgumentException ("The array argument must be of type array");
698                 }
699
700                 public static BinaryExpression ArrayIndex (Expression array, Expression index)
701                 {
702                         ArrayCheck (array);
703                         if (index == null)
704                                 throw new ArgumentNullException ("index");
705                         if (array.Type.GetArrayRank () != 1)
706                                 throw new ArgumentException ("The array argument must be a single dimensional array");
707                         if (index.Type != typeof (int))
708                                 throw new ArgumentException ("The index must be of type int");
709
710                         return new BinaryExpression (ExpressionType.ArrayIndex, array.Type.GetElementType (), array, index);
711                 }
712
713                 public static BinaryExpression Coalesce (Expression left, Expression right)
714                 {
715                         return Coalesce (left, right, null);
716                 }
717
718                 public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
719                 {
720                         if (left == null)
721                                 throw new ArgumentNullException ("left");
722                         if (right == null)
723                                 throw new ArgumentNullException ("right");
724
725                         //
726                         // First arg must ne nullable (either Nullable<T> or a reference type
727                         //
728                         if (left.Type.IsValueType && !IsNullable (left.Type))
729                                 throw new InvalidOperationException ("Left expression can never be null");
730
731                         Type result = null;
732
733                         if (IsNullable (left.Type)){
734                                 Type lbase = GetNullableOf (left.Type);
735
736                                 if (!IsNullable (right.Type) && lbase.IsAssignableFrom (right.Type))
737                                         result = lbase;
738                         }
739
740                         if (result == null && left.Type.IsAssignableFrom (right.Type))
741                                 result = left.Type;
742
743                         if (result == null){
744                                 if (IsNullable (left.Type) && right.Type.IsAssignableFrom (GetNullableOf (left.Type))){
745                                         result = right.Type;
746                                 }
747                         }
748
749                         if (result == null)
750                                 throw new ArgumentException ("Incompatible argument types");
751
752                         //
753                         // FIXME: What do we do with "conversion"?
754                         //
755                         return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
756                 }
757
758                 //
759                 // MakeBinary constructors
760                 //
761                 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right)
762                 {
763                         return MakeBinary (binaryType, left, right, false, null);
764                 }
765
766                 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method)
767                 {
768                         return MakeBinary (binaryType, left, right, liftToNull, method, null);
769                 }
770
771                 public static BinaryExpression MakeBinary (ExpressionType binaryType, Expression left, Expression right, bool liftToNull, MethodInfo method, LambdaExpression conversion)
772                 {
773                         switch (binaryType) {
774                         case ExpressionType.Add:
775                                 return Add (left, right, method);
776                         case ExpressionType.AddChecked:
777                                 return AddChecked (left, right, method);
778                         case ExpressionType.AndAlso:
779                                 return AndAlso (left, right);
780                         case ExpressionType.Coalesce:
781                                 return Coalesce (left, right, conversion);
782                         case ExpressionType.Divide:
783                                 return Divide (left, right, method);
784                         case ExpressionType.Equal:
785                                 return Equal (left, right, liftToNull, method);
786                         case ExpressionType.ExclusiveOr:
787                                 return ExclusiveOr (left, right, method);
788                         case ExpressionType.GreaterThan:
789                                 return GreaterThan (left, right, liftToNull, method);
790                         case ExpressionType.GreaterThanOrEqual:
791                                 return GreaterThanOrEqual (left, right, liftToNull, method);
792                         case ExpressionType.LeftShift:
793                                 return LeftShift (left, right, method);
794                         case ExpressionType.LessThan:
795                                 return LessThan (left, right, liftToNull, method);
796                         case ExpressionType.LessThanOrEqual:
797                                 return LessThanOrEqual (left, right, liftToNull, method);
798                         case ExpressionType.Modulo:
799                                 return Modulo (left, right, method);
800                         case ExpressionType.Multiply:
801                                 return Multiply (left, right, method);
802                         case ExpressionType.MultiplyChecked:
803                                 return MultiplyChecked (left, right, method);
804                         case ExpressionType.NotEqual:
805                                 return NotEqual (left, right, liftToNull, method);
806                         case ExpressionType.OrElse:
807                                 return OrElse (left, right);
808                         case ExpressionType.Power:
809                                 return Power (left, right, method);
810                         case ExpressionType.RightShift:
811                                 return RightShift (left, right, method);
812                         case ExpressionType.Subtract:
813                                 return Subtract (left, right, method);
814                         case ExpressionType.SubtractChecked:
815                                 return SubtractChecked (left, right, method);
816                         case ExpressionType.And:
817                                 return And (left, right, method);
818                         case ExpressionType.Or:
819                                 return Or (left, right, method);
820                         }
821
822                         throw new ArgumentException ("MakeBinary expect a binary node type");
823                 }
824
825 #endregion
826
827                 public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
828                 {
829                         return ArrayIndex (array, indexes as IEnumerable<Expression>);
830                 }
831
832                 public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
833                 {
834                         ArrayCheck (array);
835
836                         if (indexes == null)
837                                 throw new ArgumentNullException ("indexes");
838
839                         var args = indexes.ToReadOnlyCollection ();
840                         if (array.Type.GetArrayRank () != args.Count)
841                                 throw new ArgumentException ("The number of arguments doesn't match the rank of the array");
842
843                         foreach (var arg in args)
844                                 if (arg.Type != typeof (int))
845                                         throw new ArgumentException ("The index must be of type int");
846
847                         return Call (array, array.Type.GetMethod ("Get", PublicInstance), args);
848                 }
849
850                 public static UnaryExpression ArrayLength (Expression array)
851                 {
852                         if (array == null)
853                                 throw new ArgumentNullException ("array");
854                         if (!array.Type.IsArray)
855                                 throw new ArgumentException ("The type of the expression must me Array");
856                         if (array.Type.GetArrayRank () != 1)
857                                 throw new ArgumentException ("The array must be a single dimensional array");
858
859                         return new UnaryExpression (ExpressionType.ArrayLength, array, typeof (int));
860                 }
861
862                 public static MemberAssignment Bind (MemberInfo member, Expression expression)
863                 {
864                         if (member == null)
865                                 throw new ArgumentNullException ("member");
866                         if (expression == null)
867                                 throw new ArgumentNullException ("expression");
868
869                         Type type = null;
870
871                         var prop = member as PropertyInfo;
872                         if (prop != null && prop.GetSetMethod (true) != null)
873                                 type = prop.PropertyType;
874
875                         var field = member as FieldInfo;
876                         if (field != null)
877                                 type = field.FieldType;
878
879                         if (type == null)
880                                 throw new ArgumentException ("member");
881
882                         if (!type.IsAssignableFrom (expression.Type))
883                                 throw new ArgumentException ("member");
884
885                         return new MemberAssignment (member, expression);
886                 }
887
888                 public static MemberAssignment Bind (MethodInfo propertyAccessor, Expression expression)
889                 {
890                         if (propertyAccessor == null)
891                                 throw new ArgumentNullException ("propertyAccessor");
892                         if (expression == null)
893                                 throw new ArgumentNullException ("expression");
894
895                         var prop = GetAssociatedProperty (propertyAccessor);
896                         if (prop == null)
897                                 throw new ArgumentException ("propertyAccessor");
898
899                         var setter = prop.GetSetMethod (true);
900                         if (setter == null)
901                                 throw new ArgumentException ("setter");
902
903                         if (!prop.PropertyType.IsAssignableFrom (expression.Type))
904                                 throw new ArgumentException ("member");
905
906                         return new MemberAssignment (prop, expression);
907                 }
908
909                 public static MethodCallExpression Call (Expression instance, MethodInfo method)
910                 {
911                         return Call (instance, method, null as IEnumerable<Expression>);
912                 }
913
914                 public static MethodCallExpression Call (MethodInfo method, params Expression [] arguments)
915                 {
916                         return Call (null, method, arguments as IEnumerable<Expression>);
917                 }
918
919                 public static MethodCallExpression Call (Expression instance, MethodInfo method, params Expression [] arguments)
920                 {
921                         return Call (instance, method, arguments as IEnumerable<Expression>);
922                 }
923
924                 public static MethodCallExpression Call (Expression instance, MethodInfo method, IEnumerable<Expression> arguments)
925                 {
926                         if (method == null)
927                                 throw new ArgumentNullException ("method");
928                         if (instance == null && !method.IsStatic)
929                                 throw new ArgumentNullException ("instance");
930                         if (instance != null && !method.DeclaringType.IsAssignableFrom (instance.Type))
931                                 throw new ArgumentException ("Type is not assignable to the declaring type of the method");
932
933                         var args = arguments.ToReadOnlyCollection ();
934
935                         CheckMethodArguments (method, args);
936
937                         return new MethodCallExpression (instance, method, args);
938                 }
939
940                 public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
941                 {
942                         if (instance == null)
943                                 throw new ArgumentNullException ("instance");
944                         if (methodName == null)
945                                 throw new ArgumentNullException ("methodName");
946
947                         if (typeArguments == null)
948                                 typeArguments = new Type [0];
949
950                         var method = instance.Type.GetMethod (methodName, AllInstance, null, typeArguments, null);
951                         if (method == null)
952                                 throw new InvalidOperationException ("No such method");
953
954                         var args = arguments.ToReadOnlyCollection ();
955                         if (typeArguments.Length != args.Count)
956                                 throw new InvalidOperationException ("Argument count doesn't match parameters length");
957
958                         return new MethodCallExpression (instance, method, args);
959                 }
960
961                 public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
962                 {
963                         if (type == null)
964                                 throw new ArgumentNullException ("type");
965                         if (methodName == null)
966                                 throw new ArgumentNullException ("methodName");
967
968                         if (typeArguments == null)
969                                 typeArguments = new Type [0];
970
971                         var method = type.GetMethod (methodName, AllStatic, null, typeArguments, null);
972                         if (method == null)
973                                 throw new InvalidOperationException ("No such method");
974
975                         var args = arguments.ToReadOnlyCollection ();
976                         if (typeArguments.Length != args.Count)
977                                 throw new InvalidOperationException ("Argument count doesn't match parameters length");
978
979                         return new MethodCallExpression (method, args);
980                 }
981
982                 public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
983                 {
984                         if (test == null)
985                                 throw new ArgumentNullException ("test");
986                         if (ifTrue == null)
987                                 throw new ArgumentNullException ("ifTrue");
988                         if (ifFalse == null)
989                                 throw new ArgumentNullException ("ifFalse");
990                         if (test.Type != typeof (bool))
991                                 throw new ArgumentException ("Test expression should be of type bool");
992                         if (ifTrue.Type != ifFalse.Type)
993                                 throw new ArgumentException ("The ifTrue and ifFalse type do not match");
994
995                         return new ConditionalExpression (test, ifTrue, ifFalse);
996                 }
997
998                 public static ConstantExpression Constant (object value)
999                 {
1000                         if (value == null)
1001                                 return new ConstantExpression (null, typeof (object));
1002
1003                         return Constant (value, value.GetType ());
1004                 }
1005
1006                 public static ConstantExpression Constant (object value, Type type)
1007                 {
1008                         if (type == null)
1009                                 throw new ArgumentNullException ("type");
1010
1011                         //
1012                         // value must be compatible with type, no conversions
1013                         // are allowed
1014                         //
1015                         if (value == null){
1016                                 if (type.IsValueType && !IsNullable (type))
1017                                         throw new ArgumentException ();
1018                         } else {
1019                                 if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
1020                                         throw new ArgumentException ();
1021
1022                         }
1023
1024                         return new ConstantExpression (value, type);
1025                 }
1026
1027                 [MonoTODO]
1028                 public static UnaryExpression Convert (Expression expression, Type type)
1029                 {
1030                         throw new NotImplementedException ();
1031                 }
1032
1033                 [MonoTODO]
1034                 public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
1035                 {
1036                         throw new NotImplementedException ();
1037                 }
1038
1039                 [MonoTODO]
1040                 public static UnaryExpression ConvertChecked (Expression expression, Type type)
1041                 {
1042                         throw new NotImplementedException ();
1043                 }
1044
1045                 [MonoTODO]
1046                 public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
1047                 {
1048                         throw new NotImplementedException ();
1049                 }
1050
1051                 [MonoTODO]
1052                 public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
1053                 {
1054                         throw new NotImplementedException ();
1055                 }
1056
1057                 [MonoTODO]
1058                 public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
1059                 {
1060                         throw new NotImplementedException ();
1061                 }
1062
1063                 public static MemberExpression Field (Expression expression, FieldInfo field)
1064                 {
1065                         if (field == null)
1066                                 throw new ArgumentNullException ("field");
1067                         if (!field.IsStatic) {
1068                                 if (expression == null)
1069                                         throw new ArgumentNullException ("expression");
1070                                 if (!field.DeclaringType.IsAssignableFrom (expression.Type))
1071                                         throw new ArgumentException ("field");
1072                         }
1073
1074                         return new MemberExpression (expression, field, field.FieldType);
1075                 }
1076
1077                 public static MemberExpression Field (Expression expression, string fieldName)
1078                 {
1079                         if (expression == null)
1080                                 throw new ArgumentNullException ("expression");
1081
1082                         var field = expression.Type.GetField (fieldName, AllInstance);
1083                         if (field == null)
1084                                 throw new ArgumentException (string.Format ("No field named {0} on {1}", fieldName, expression.Type));
1085
1086                         return new MemberExpression (expression, field, field.FieldType);
1087                 }
1088
1089                 public static Type GetActionType (params Type [] typeArgs)
1090                 {
1091                         if (typeArgs == null)
1092                                 throw new ArgumentNullException ("typeArgs");
1093
1094                         if (typeArgs.Length > 4)
1095                                 throw new ArgumentException ("No Action type of this arity");
1096
1097                         if (typeArgs.Length == 0)
1098                                 return typeof (Action);
1099
1100                         Type action = null;
1101                         switch (typeArgs.Length) {
1102                         case 1:
1103                                 action = typeof (Action<>);
1104                                 break;
1105                         case 2:
1106                                 action = typeof (Action<,>);
1107                                 break;
1108                         case 3:
1109                                 action = typeof (Action<,,>);
1110                                 break;
1111                         case 4:
1112                                 action = typeof (Action<,,,>);
1113                                 break;
1114                         }
1115
1116                         return action.MakeGenericType (typeArgs);
1117                 }
1118
1119                 public static Type GetFuncType (params Type [] typeArgs)
1120                 {
1121                         if (typeArgs == null)
1122                                 throw new ArgumentNullException ("typeArgs");
1123
1124                         if (typeArgs.Length < 1 || typeArgs.Length > 5)
1125                                 throw new ArgumentException ("No Func type of this arity");
1126
1127                         Type func = null;
1128                         switch (typeArgs.Length) {
1129                         case 1:
1130                                 func = typeof (Func<>);
1131                                 break;
1132                         case 2:
1133                                 func = typeof (Func<,>);
1134                                 break;
1135                         case 3:
1136                                 func = typeof (Func<,,>);
1137                                 break;
1138                         case 4:
1139                                 func = typeof (Func<,,,>);
1140                                 break;
1141                         case 5:
1142                                 func = typeof (Func<,,,,>);
1143                                 break;
1144                         }
1145
1146                         return func.MakeGenericType (typeArgs);
1147                 }
1148
1149                 [MonoTODO]
1150                 public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
1151                 {
1152                         throw new NotImplementedException ();
1153                 }
1154
1155                 [MonoTODO]
1156                 public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
1157                 {
1158                         throw new NotImplementedException ();
1159                 }
1160
1161                 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
1162                 {
1163                         return Lambda<TDelegate> (body, parameters as IEnumerable<ParameterExpression>);
1164                 }
1165
1166                 public static Expression<TDelegate> Lambda<TDelegate> (Expression body, IEnumerable<ParameterExpression> parameters)
1167                 {
1168                         if (body == null)
1169                                 throw new ArgumentNullException ("body");
1170
1171                         return new Expression<TDelegate> (body, parameters.ToReadOnlyCollection ());
1172                 }
1173
1174                 public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
1175                 {
1176                         if (body == null)
1177                                 throw new ArgumentNullException ("body");
1178                         if (parameters.Length > 4)
1179                                 throw new ArgumentException ("Too many parameters");
1180
1181                         return Lambda (GetDelegateType (body.Type, parameters), body, parameters);
1182                 }
1183
1184                 static Type GetDelegateType (Type return_type, ParameterExpression [] parameters)
1185                 {
1186                         if (parameters == null)
1187                                 parameters = new ParameterExpression [0];
1188
1189                         if (return_type == typeof (void))
1190                                 return GetActionType (parameters.Select (p => p.Type).ToArray ());
1191
1192                         var types = new Type [parameters.Length + 1];
1193                         for (int i = 0; i < types.Length - 1; i++)
1194                                 types [i] = parameters [i].Type;
1195
1196                         types [types.Length - 1] = return_type;
1197                         return GetFuncType (types);
1198                 }
1199
1200                 public static LambdaExpression Lambda (Type delegateType, Expression body, params ParameterExpression [] parameters)
1201                 {
1202                         return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
1203                 }
1204
1205                 public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
1206                 {
1207                         if (delegateType == null)
1208                                 throw new ArgumentNullException ("delegateType");
1209                         if (body == null)
1210                                 throw new ArgumentNullException ("body");
1211
1212                         return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
1213                 }
1214
1215                 public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
1216                 {
1217                         throw new NotImplementedException ();
1218                 }
1219
1220                 [MonoTODO]
1221                 public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
1222                 {
1223                         throw new NotImplementedException ();
1224                 }
1225
1226                 [MonoTODO]
1227                 public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
1228                 {
1229                         throw new NotImplementedException ();
1230                 }
1231
1232                 [MonoTODO]
1233                 public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
1234                 {
1235                         throw new NotImplementedException ();
1236                 }
1237
1238                 [MonoTODO]
1239                 public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
1240                 {
1241                         throw new NotImplementedException ();
1242                 }
1243
1244                 [MonoTODO]
1245                 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
1246                 {
1247                         throw new NotImplementedException ();
1248                 }
1249
1250                 [MonoTODO]
1251                 public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
1252                 {
1253                         throw new NotImplementedException ();
1254                 }
1255
1256                 [MonoTODO]
1257                 public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
1258                 {
1259                         throw new NotImplementedException ();
1260                 }
1261
1262                 [MonoTODO]
1263                 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
1264                 {
1265                         throw new NotImplementedException ();
1266                 }
1267
1268                 [MonoTODO]
1269                 public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
1270                 {
1271                         throw new NotImplementedException ();
1272                 }
1273
1274                 public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
1275                 {
1276                         if (expression == null)
1277                                 throw new ArgumentNullException ("expression");
1278                         if (member == null)
1279                                 throw new ArgumentNullException ("member");
1280
1281                         var field = member as FieldInfo;
1282                         if (field != null)
1283                                 return Field (expression, field);
1284
1285                         var property = member as PropertyInfo;
1286                         if (property != null)
1287                                 return Property (expression, property);
1288
1289                         throw new ArgumentException ("Member should either be a field or a property");
1290                 }
1291
1292                 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type)
1293                 {
1294                         return MakeUnary (unaryType, operand, type, null);
1295                 }
1296
1297                 public static UnaryExpression MakeUnary (ExpressionType unaryType, Expression operand, Type type, MethodInfo method)
1298                 {
1299                         switch (unaryType) {
1300                         case ExpressionType.ArrayLength:
1301                                 return ArrayLength (operand);
1302                         case ExpressionType.Convert:
1303                                 return Convert (operand, type, method);
1304                         case ExpressionType.ConvertChecked:
1305                                 return ConvertChecked (operand, type, method);
1306                         case ExpressionType.Negate:
1307                                 return Negate (operand, method);
1308                         case ExpressionType.NegateChecked:
1309                                 return NegateChecked (operand, method);
1310                         case ExpressionType.Not:
1311                                 return Not (operand, method);
1312                         case ExpressionType.Quote:
1313                                 return Quote (operand);
1314                         case ExpressionType.TypeAs:
1315                                 return TypeAs (operand, type);
1316                         case ExpressionType.UnaryPlus:
1317                                 return UnaryPlus (operand, method);
1318                         }
1319
1320                         throw new ArgumentException ("MakeUnary expect an unary operator");
1321                 }
1322
1323                 [MonoTODO]
1324                 public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] binding)
1325                 {
1326                         throw new NotImplementedException ();
1327                 }
1328
1329                 [MonoTODO]
1330                 public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> binding)
1331                 {
1332                         throw new NotImplementedException ();
1333                 }
1334
1335                 [MonoTODO]
1336                 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] binding)
1337                 {
1338                         throw new NotImplementedException ();
1339                 }
1340
1341                 [MonoTODO]
1342                 public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> binding)
1343                 {
1344                         throw new NotImplementedException ();
1345                 }
1346
1347                 [MonoTODO]
1348                 public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] binding)
1349                 {
1350                         throw new NotImplementedException ();
1351                 }
1352
1353                 [MonoTODO]
1354                 public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> binding)
1355                 {
1356                         throw new NotImplementedException ();
1357                 }
1358
1359                 public static UnaryExpression Negate (Expression expression)
1360                 {
1361                         return Negate (expression, null);
1362                 }
1363
1364                 public static UnaryExpression Negate (Expression expression, MethodInfo method)
1365                 {
1366                         method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1367
1368                         return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1369                 }
1370
1371                 public static UnaryExpression NegateChecked (Expression expression)
1372                 {
1373                         return NegateChecked (expression, null);
1374                 }
1375
1376                 public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
1377                 {
1378                         method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
1379
1380                         return MakeSimpleUnary (ExpressionType.Negate, expression, method);
1381                 }
1382
1383                 public static NewExpression New (ConstructorInfo constructor)
1384                 {
1385                         if (constructor == null)
1386                                 throw new ArgumentNullException ("constructor");
1387
1388                         if (constructor.GetParameters ().Length > 0)
1389                                 throw new ArgumentException ("Constructor must be parameter less");
1390
1391                         return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection<Expression> (), null);
1392                 }
1393
1394                 public static NewExpression New (Type type)
1395                 {
1396                         if (type == null)
1397                                 throw new ArgumentNullException ("type");
1398
1399                         if (type.GetConstructor (Type.EmptyTypes) == null)
1400                                 throw new ArgumentException ("Type doesn't have a parameter less constructor");
1401
1402                         return new NewExpression (type, (null as IEnumerable<Expression>).ToReadOnlyCollection<Expression> ());
1403                 }
1404
1405                 public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
1406                 {
1407                         return New (constructor, arguments as IEnumerable<Expression>);
1408                 }
1409
1410                 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments)
1411                 {
1412                         if (constructor == null)
1413                                 throw new ArgumentNullException ("constructor");
1414
1415                         var args = arguments.ToReadOnlyCollection ();
1416
1417                         CheckMethodArguments (constructor, args);
1418
1419                         return new NewExpression (constructor, args, null);
1420                 }
1421
1422                 static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
1423                 {
1424                         var parameters = method.GetParameters ();
1425
1426                         if (arguments.Count != parameters.Length)
1427                                 throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
1428
1429                         for (int i = 0; i < parameters.Length; i++) {
1430                                 if (arguments [i] == null)
1431                                         throw new ArgumentNullException ("arguments");
1432
1433                                 if (!parameters [i].ParameterType.IsAssignableFrom (arguments [i].Type))
1434                                         throw new ArgumentException ("arguments");
1435                         }
1436                 }
1437
1438                 [MonoTODO]
1439                 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
1440                 {
1441                         throw new NotImplementedException ();
1442                 }
1443
1444                 [MonoTODO]
1445                 public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
1446                 {
1447                         throw new NotImplementedException ();
1448                 }
1449
1450                 public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
1451                 {
1452                         return NewArrayBounds (type, bounds as IEnumerable<Expression>);
1453                 }
1454
1455                 public static NewArrayExpression NewArrayBounds (Type type, IEnumerable<Expression> bounds)
1456                 {
1457                         if (type == null)
1458                                 throw new ArgumentNullException ("type");
1459                         if (bounds == null)
1460                                 throw new ArgumentNullException ("bounds");
1461
1462                         var array_bounds = bounds.ToReadOnlyCollection ();
1463                         foreach (var expression in array_bounds)
1464                                 if (!IsInt (expression.Type))
1465                                         throw new ArgumentException ("The bounds collection can only contain expression of integers types");
1466
1467                         return new NewArrayExpression (ExpressionType.NewArrayBounds, type.MakeArrayType (array_bounds.Count), array_bounds);
1468                 }
1469
1470                 public static NewArrayExpression NewArrayInit (Type type, params Expression [] initializers)
1471                 {
1472                         return NewArrayInit (type, initializers as IEnumerable<Expression>);
1473                 }
1474
1475                 public static NewArrayExpression NewArrayInit (Type type, IEnumerable<Expression> initializers)
1476                 {
1477                         if (type == null)
1478                                 throw new ArgumentNullException ("type");
1479                         if (initializers == null)
1480                                 throw new ArgumentNullException ("initializers");
1481
1482                         var array_initializers = initializers.ToReadOnlyCollection ();
1483
1484                         foreach (var expression in initializers) {
1485                                 if (expression == null)
1486                                         throw new ArgumentNullException ("initializers");
1487
1488                                 if (!type.IsAssignableFrom (expression.Type))
1489                                         throw new InvalidOperationException ();
1490
1491                                 // TODO: Quote elements if type == typeof (Expression)
1492                         }
1493
1494                         return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), array_initializers);
1495                 }
1496
1497                 public static UnaryExpression Not (Expression expression)
1498                 {
1499                         return Not (expression, null);
1500                 }
1501
1502                 public static UnaryExpression Not (Expression expression, MethodInfo method)
1503                 {
1504                         method = UnaryCoreCheck ("op_LogicalNot", expression, method);
1505
1506                         return MakeSimpleUnary (ExpressionType.Not, expression, method);
1507                 }
1508
1509                 public static ParameterExpression Parameter (Type type, string name)
1510                 {
1511                         if (type == null)
1512                                 throw new ArgumentNullException ("type");
1513
1514                         return new ParameterExpression (type, name);
1515                 }
1516
1517                 public static MemberExpression Property (Expression expression, MethodInfo propertyAccessor)
1518                 {
1519                         if (propertyAccessor == null)
1520                                 throw new ArgumentNullException ("propertyAccessor");
1521
1522                         if (!propertyAccessor.IsStatic) {
1523                                 if (expression == null)
1524                                         throw new ArgumentNullException ("expression");
1525                                 if (!propertyAccessor.DeclaringType.IsAssignableFrom (expression.Type))
1526                                         throw new ArgumentException ("expression");
1527                         }
1528
1529                         var prop = GetAssociatedProperty (propertyAccessor);
1530                         if (prop == null)
1531                                 throw new ArgumentException (string.Format ("Method {0} has no associated property", propertyAccessor));
1532
1533                         return new MemberExpression (expression, prop, prop.PropertyType);
1534                 }
1535
1536                 static PropertyInfo GetAssociatedProperty (MethodInfo method)
1537                 {
1538                         foreach (var prop in method.DeclaringType.GetProperties (All)) {
1539                                 if (prop.GetGetMethod (true) == method)
1540                                         return prop;
1541                                 if (prop.GetSetMethod (true) ==  method)
1542                                         return prop;
1543                         }
1544
1545                         return null;
1546                 }
1547
1548                 public static MemberExpression Property (Expression expression, PropertyInfo property)
1549                 {
1550                         if (property == null)
1551                                 throw new ArgumentNullException ("property");
1552
1553                         var getter = property.GetGetMethod (true);
1554                         if (getter == null)
1555                                 throw new ArgumentException ("getter");
1556
1557                         if (!getter.IsStatic) {
1558                                 if (expression == null)
1559                                         throw new ArgumentNullException ("expression");
1560                                 if (!property.DeclaringType.IsAssignableFrom (expression.Type))
1561                                         throw new ArgumentException ("expression");
1562                         }
1563
1564                         return new MemberExpression (expression, property, property.PropertyType);
1565                 }
1566
1567                 public static MemberExpression Property (Expression expression, string propertyName)
1568                 {
1569                         if (expression == null)
1570                                 throw new ArgumentNullException ("expression");
1571
1572                         var prop = expression.Type.GetProperty (propertyName, AllInstance);
1573                         if (prop == null)
1574                                 throw new ArgumentException (string.Format ("No property named {0} on {1}", propertyName, expression.Type));
1575
1576                         return new MemberExpression (expression, prop, prop.PropertyType);
1577                 }
1578
1579                 public static MemberExpression PropertyOrField (Expression expression, string propertyOrFieldName)
1580                 {
1581                         if (expression == null)
1582                                 throw new ArgumentNullException ("expression");
1583                         if (propertyOrFieldName == null)
1584                                 throw new ArgumentNullException ("propertyOrFieldName");
1585
1586                         var prop = expression.Type.GetProperty (propertyOrFieldName, AllInstance);
1587                         if (prop != null)
1588                                 return new MemberExpression (expression, prop, prop.PropertyType);
1589
1590                         var field = expression.Type.GetField (propertyOrFieldName, AllInstance);
1591                         if (field != null)
1592                                 return new MemberExpression (expression, field, field.FieldType);
1593
1594                         throw new ArgumentException (string.Format ("No field or property named {0} on {1}", propertyOrFieldName, expression.Type));
1595                 }
1596
1597                 public static UnaryExpression Quote (Expression expression)
1598                 {
1599                         if (expression == null)
1600                                 throw new ArgumentNullException ("expression");
1601
1602                         return new UnaryExpression (ExpressionType.Quote, expression, expression.GetType ());
1603                 }
1604
1605                 public static UnaryExpression TypeAs (Expression expression, Type type)
1606                 {
1607                         if (expression == null)
1608                                 throw new ArgumentNullException ("expression");
1609                         if (type == null)
1610                                 throw new ArgumentNullException ("type");
1611                         if (type.IsValueType && !IsNullable (type))
1612                                 throw new ArgumentException ("TypeAs expect a reference or a nullable type");
1613
1614                         return new UnaryExpression (ExpressionType.TypeAs, expression, type);
1615                 }
1616
1617                 public static TypeBinaryExpression TypeIs (Expression expression, Type type)
1618                 {
1619                         if (expression == null)
1620                                 throw new ArgumentNullException ("expression");
1621                         if (type == null)
1622                                 throw new ArgumentNullException ("type");
1623
1624                         return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
1625                 }
1626
1627                 public static UnaryExpression UnaryPlus (Expression expression)
1628                 {
1629                         return UnaryPlus (expression, null);
1630                 }
1631
1632                 public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
1633                 {
1634                         method = UnaryCoreCheck ("op_UnaryPlus", expression, method);
1635
1636                         return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
1637                 }
1638
1639                 internal static bool IsNullable (Type type)
1640                 {
1641                         return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
1642                 }
1643
1644                 internal static bool IsUnsigned (Type t)
1645                 {
1646                         if (t.IsPointer)
1647                                 return IsUnsigned (t.GetElementType ());
1648
1649                         return t == typeof (ushort) || t == typeof (uint) || t == typeof (ulong) || t == typeof (byte);
1650                 }
1651
1652                 //
1653                 // returns the T in a a Nullable<T> type.
1654                 //
1655                 internal static Type GetNullableOf (Type type)
1656                 {
1657                         return type.GetGenericArguments () [0];
1658                 }
1659
1660                 //
1661                 // This method must be overwritten by derived classes to
1662                 // compile the expression
1663                 //
1664                 internal abstract void Emit (EmitContext ec);
1665         }
1666 }