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