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