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