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