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