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