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