2008-06-05 Jb Evain <jbevain@novell.com>
[mono.git] / mcs / class / System.Core / System.Linq.Expressions / Expression.cs
index cc165a218c3e036e80681643f7f311d39440272f..98646167e2c533aa9c355e44c4c5ee3a470c38c7 100644 (file)
 //
 
 using System;
+using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
 using System.Linq;
 using System.Reflection;
+using System.Reflection.Emit;
 
 namespace System.Linq.Expressions {
 
@@ -40,11 +42,12 @@ namespace System.Linq.Expressions {
                ExpressionType node_type;
                Type type;
 
-               static BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
-               static BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
-               static BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
-               static BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
-               static BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
+               internal const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
+               internal const BindingFlags NonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance;
+               internal const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
+               internal const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
+               internal const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
+               internal const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
 
                public ExpressionType NodeType {
                        get { return node_type; }
@@ -65,30 +68,16 @@ namespace System.Linq.Expressions {
                        return ExpressionPrinter.ToString (this);
                }
 
-               static void CheckMethod (MethodInfo m)
-               {
-               }
-
-#region Binary Expressions
-               static bool IsInt (Type t)
-               {
-                       return t == typeof (byte) || t == typeof (sbyte) ||
-                               t == typeof (short) || t == typeof (ushort) ||
-                               t == typeof (int) || t == typeof (uint) ||
-                               t == typeof (long) || t == typeof (ulong);
-               }
+               #region Binary Expressions
 
-               static bool IsNumber (Type t)
+               static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param)
                {
-                       if (IsInt (t))
-                               return true;
-
-                       return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
+                       return GetUnaryOperator (oper_name, declaring, param, null);
                }
 
-               static MethodInfo GetUnaryOperator (string oper_name, Type on_type, Expression expression)
+               static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param, Type ret)
                {
-                       var methods = on_type.GetMethods (PublicStatic);
+                       var methods = GetNotNullableOf (declaring).GetMethods (PublicStatic);
 
                        foreach (var method in methods) {
                                if (method.Name != oper_name)
@@ -98,7 +87,10 @@ namespace System.Linq.Expressions {
                                if (parameters.Length != 1)
                                        continue;
 
-                               if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
+                               if (!IsAssignableToParameterType (GetNotNullableOf (param), parameters [0]))
+                                       continue;
+
+                               if (ret != null && method.ReturnType != GetNotNullableOf (ret))
                                        continue;
 
                                return method;
@@ -107,62 +99,77 @@ namespace System.Linq.Expressions {
                        return null;
                }
 
-               static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method)
+               static bool IsAssignableToParameterType (Type type, ParameterInfo param)
                {
-                       if (expression == null)
-                               throw new ArgumentNullException ("expression");
+                       var ptype = param.ParameterType;
+                       if (ptype.IsByRef)
+                               ptype = ptype.GetElementType ();
 
-                       if (method != null) {
-                               if (method.ReturnType == typeof (void))
-                                       throw new ArgumentException ("Specified method must return a value", "method");
+                       return GetNotNullableOf (type).IsAssignableTo (ptype);
+               }
 
-                               if (!method.IsStatic)
-                                       throw new ArgumentException ("Method must be static", "method");
+               static MethodInfo CheckUnaryMethod (MethodInfo method, Type param)
+               {
+                       if (method.ReturnType == typeof (void))
+                               throw new ArgumentException ("Specified method must return a value", "method");
 
-                               var parameters = method.GetParameters ();
+                       if (!method.IsStatic)
+                               throw new ArgumentException ("Method must be static", "method");
 
-                               if (parameters.Length != 1)
-                                       throw new ArgumentException ("Must have only one parameters", "method");
+                       var parameters = method.GetParameters ();
 
-                               if (!parameters [0].ParameterType.IsAssignableFrom (expression.Type))
-                                       throw new InvalidOperationException ("left-side argument type does not match left expression type");
+                       if (parameters.Length != 1)
+                               throw new ArgumentException ("Must have only one parameters", "method");
 
-                               return method;
-                       } else {
-                               if (IsNumber (expression.Type))
+                       if (!IsAssignableToParameterType (GetNotNullableOf (param), parameters [0]))
+                               throw new InvalidOperationException ("left-side argument type does not match expression type");
+
+                       return method;
+               }
+
+               static MethodInfo UnaryCoreCheck (string oper_name, Expression expression, MethodInfo method, Func<Type, bool> validator)
+               {
+                       if (expression == null)
+                               throw new ArgumentNullException ("expression");
+
+                       if (method != null)
+                               return CheckUnaryMethod (method, expression.Type);
+
+                               var type = GetNotNullableOf (expression.Type);
+
+                               if (validator (type))
                                        return null;
 
                                if (oper_name != null) {
-                                       method = GetUnaryOperator (oper_name, expression.Type, expression);
+                                       method = GetUnaryOperator (oper_name, type, expression.Type);
                                        if (method != null)
                                                return method;
                                }
 
                                throw new InvalidOperationException (
-                                       String.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
-                       }
+                                       string.Format ("Operation {0} not defined for {1}", oper_name != null ? oper_name.Substring (3) : "is", expression.Type));
                }
 
                static MethodInfo GetBinaryOperator (string oper_name, Type on_type, Expression left, Expression right)
                {
                        MethodInfo [] methods = on_type.GetMethods (PublicStatic);
 
-                       foreach (MethodInfo m in methods){
-                               if (m.Name != oper_name)
+                       foreach (var method in methods) {
+                               if (method.Name != oper_name)
                                        continue;
 
-                               ParameterInfo [] pi = m.GetParameters ();
-                               if (pi.Length != 2)
+                               var parameters = method.GetParameters ();
+                               if (parameters.Length != 2)
                                        continue;
 
-                               if (!pi [0].ParameterType.IsAssignableFrom (left.Type))
+                               if (!IsAssignableToParameterType (left.Type, parameters [0]))
                                        continue;
 
-                               if (!pi [1].ParameterType.IsAssignableFrom (right.Type))
+                               if (!IsAssignableToParameterType (right.Type, parameters [1]))
                                        continue;
 
                                // Method has papers in order.
-                               return m;
+                               return method;
                        }
 
                        return null;
@@ -185,65 +192,66 @@ namespace System.Linq.Expressions {
 
                                if (!method.IsStatic)
                                        throw new ArgumentException ("Method must be static", "method");
-                               ParameterInfo [] pi = method.GetParameters ();
 
-                               if (pi.Length != 2)
+                               var parameters = method.GetParameters ();
+
+                               if (parameters.Length != 2)
                                        throw new ArgumentException ("Must have only two parameters", "method");
 
-                               Type ltype = left.Type.IsValueType && IsNullable (left.Type) ? GetNullableOf(left.Type) : left.Type;
-                               Type rtype = left.Type.IsValueType && IsNullable (right.Type) ? GetNullableOf(right.Type) :right.Type;
-                                       
-                               if (ltype != pi [0].ParameterType)
+                               if (!IsAssignableToParameterType (left.Type, parameters [0]))
                                        throw new InvalidOperationException ("left-side argument type does not match left expression type");
 
-                               if (rtype != pi [1].ParameterType)
+                               if (!IsAssignableToParameterType (right.Type, parameters [1]))
                                        throw new InvalidOperationException ("right-side argument type does not match right expression type");
 
                                return method;
                        } else {
                                Type ltype = left.Type;
                                Type rtype = right.Type;
-                               Type ultype = left.Type;
-                               Type urtype = right.Type;
-
-                               if (IsNullable (ltype))
-                                       ultype = GetNullableOf (ltype);
+                               Type ultype = GetNotNullableOf (ltype);
+                               Type urtype = GetNotNullableOf (rtype);
 
-                               if (IsNullable (rtype))
-                                       urtype = GetNullableOf (rtype);
-
-                               if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd"){
-                                       if (ultype == typeof (bool)){
+                               if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
+                                       if (ultype == typeof (bool)) {
                                                if (ultype == urtype && ltype == rtype)
                                                        return null;
                                        }
                                }
-                               
+
                                // Use IsNumber to avoid expensive reflection.
                                if (IsNumber (ultype)){
                                        if (ultype == urtype && ltype == rtype)
-                                               return method;
-                                       
+                                               return null;
+
                                        if (oper_name != null){
-                                               method = GetBinaryOperator (oper_name, rtype, left, right);
+                                               method = GetBinaryOperator (oper_name, urtype, left, right);
                                                if (method != null)
                                                        return method;
                                        }
                                }
-                               
+
                                if (oper_name != null){
-                                       method = GetBinaryOperator (oper_name, ltype, left, right);
+                                       method = GetBinaryOperator (oper_name, ultype, left, right);
                                        if (method != null)
                                                return method;
                                }
 
-                               //
-                               // == and != allow reference types without operators defined.
-                               //
-                               if (!ltype.IsValueType && !rtype.IsValueType &&
-                                   (oper_name == "op_Equality" || oper_name == "op_Inequality"))
-                                       return null;
-                               
+                               if (oper_name == "op_Equality" || oper_name == "op_Inequality") {
+                                       //
+                                       // == and != allow reference types without operators defined.
+                                       //
+                                       if (!ltype.IsValueType && !rtype.IsValueType)
+                                               return null;
+
+                                       if (ltype == rtype && ultype == typeof (bool))
+                                               return null;
+                               }
+
+                               if (oper_name == "op_LeftShift" || oper_name == "op_RightShift") {
+                                       if (IsInt (ultype) && urtype == typeof (int))
+                                               return null;
+                               }
+
                                throw new InvalidOperationException (
                                        String.Format ("Operation {0} not defined for {1} and {2}", oper_name != null ? oper_name.Substring (3) : "is", ltype, rtype));
                        }
@@ -260,91 +268,134 @@ namespace System.Linq.Expressions {
                        if (right == null)
                                throw new ArgumentNullException ("right");
 
-                       if (method == null){
+                       if (method == null) {
                                // avoid reflection shortcut and catches Ints/bools before we check Numbers in general
-                               if (left.Type == right.Type && (left.Type == typeof (bool) || IsInt (left.Type)))
-                                       return method;
+                               if (left.Type == right.Type && IsIntOrBool (left.Type))
+                                       return null;
                        }
 
                        method = BinaryCoreCheck (oper_name, left, right, method);
-                       if (method == null){
-                               //
+                       if (method == null) {
                                // The check in BinaryCoreCheck allows a bit more than we do
                                // (floats and doubles).  Catch this here
-                               //
-                               if (left.Type == typeof(double) || left.Type == typeof(float))
+                               if (left.Type == typeof (double) || left.Type == typeof (float))
                                        throw new InvalidOperationException ("Types not supported");
-                       } 
-                       
+                       }
+
                        return method;
                }
 
+               static Type GetResultType (Expression expression, MethodInfo method)
+               {
+                       return method == null ? expression.Type : method.ReturnType;
+               }
+
                static BinaryExpression MakeSimpleBinary (ExpressionType et, Expression left, Expression right, MethodInfo method)
                {
-                       Type result = method == null ? left.Type : method.ReturnType;
                        bool is_lifted;
-                       
-                       if (method == null){
-                               if (IsNullable (left.Type)){
-                                       if (!IsNullable (right.Type))
-                                               throw new Exception ("Assertion, internal error: left is nullable, requires right to be as well");
+                       Type type;
+
+                       if (method == null) {
+                               is_lifted = left.Type.IsNullable ();
+                               type = left.Type;
+                       } else {
+                               var parameters = method.GetParameters ();
+
+                               var lp = parameters [0];
+                               var rp = parameters [1];
+
+                               if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
+                                       is_lifted = false;
+                                       type = method.ReturnType;
+                               } else if (left.Type.IsNullable ()
+                                       && right.Type.IsNullable ()
+                                       && GetNotNullableOf (left.Type) == lp.ParameterType
+                                       && GetNotNullableOf (right.Type) == rp.ParameterType
+                                       && !method.ReturnType.IsNullable ()) {
+
                                        is_lifted = true;
+                                       type = method.ReturnType.MakeNullableType ();
                                } else
-                                       is_lifted = false;
-                       } else {
-                               //
-                               // FIXME: implement
-                               //
-                               is_lifted = false;
+                                       throw new InvalidOperationException ();
                        }
-                       
-                       return new BinaryExpression (et, result, left, right, false, is_lifted, method, null);
+
+                       return new BinaryExpression (et, type, left, right, is_lifted, is_lifted, method, null);
+               }
+
+               static bool IsAssignableToOperatorParameter (Expression expression, ParameterInfo parameter)
+               {
+                       if (expression.Type == parameter.ParameterType)
+                               return true;
+
+                       if ((!expression.Type.IsNullable () && !parameter.ParameterType.IsNullable ())
+                               && IsAssignableToParameterType (expression.Type, parameter))
+                               return true;
+
+                       return false;
                }
 
                static UnaryExpression MakeSimpleUnary (ExpressionType et, Expression expression, MethodInfo method)
                {
-                       Type result = method == null ? expression.Type : method.ReturnType;
+                       bool is_lifted;
+                       Type type;
+
+                       if (method == null) {
+                               type = expression.Type;
+                               is_lifted = type.IsNullable ();
+                       } else {
+                               var parameter = method.GetParameters () [0];
+
+                               if (IsAssignableToOperatorParameter (expression, parameter)) {
+                                       is_lifted = false;
+                                       type = method.ReturnType;
+                               } else if (expression.Type.IsNullable ()
+                                       && GetNotNullableOf (expression.Type) == parameter.ParameterType
+                                       && !method.ReturnType.IsNullable ()) {
+
+                                       is_lifted = true;
+                                       type = method.ReturnType.MakeNullableType ();
+                               } else
+                                       throw new InvalidOperationException ();
+                       }
 
-                       return new UnaryExpression (et, expression, result, method);
+                       return new UnaryExpression (et, expression, type, method, is_lifted);
                }
 
                static BinaryExpression MakeBoolBinary (ExpressionType et, Expression left, Expression right, bool liftToNull, MethodInfo method)
                {
-                       Type result;
-                       Type ltype = left.Type;
-                       Type rtype = right.Type;
-                       bool lnullable = IsNullable (ltype);
-                       bool rnullable = IsNullable (rtype);
                        bool is_lifted;
+                       Type type;
 
-                       //
-                       // Implement the rules as described in "Expression.Equal" method.  
-                       //
-                       if (method == null){
-                               if (lnullable == false && rnullable == false){
+                       if (method == null) {
+                               if (!left.Type.IsNullable () && !right.Type.IsNullable ()) {
                                        is_lifted = false;
-                                       result = typeof (bool);
-                               } else if (lnullable && rnullable){
+                                       liftToNull = false;
+                                       type = typeof (bool);
+                               } else if (left.Type.IsNullable () && right.Type.IsNullable ()) {
                                        is_lifted = true;
-                                       result = liftToNull ? typeof(bool?) : typeof (bool);
+                                       type = liftToNull ? typeof (bool?) : typeof (bool);
                                } else
-                                       throw new Exception ("Internal error: this should have been caught in BinaryCoreCheck");
+                                       throw new InvalidOperationException ();
                        } else {
-                               ParameterInfo [] pi = method.GetParameters ();
-                               Type mltype = pi [0].ParameterType;
-                               Type mrtype = pi [1].ParameterType;
-                               
-                               if (ltype == mltype && rtype == mrtype){
+                               var parameters = method.GetParameters ();
+
+                               var lp = parameters [0];
+                               var rp = parameters [1];
+
+                               if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
                                        is_lifted = false;
-                                       result = method.ReturnType;
-                               }
-                               else if (ltype.IsValueType && rtype.IsValueType &&
-                                          ((lnullable && GetNullableOf (ltype) == mltype) ||
-                                           (rnullable && GetNullableOf (rtype) == mrtype))){
+                                       liftToNull = false;
+                                       type = method.ReturnType;
+                               } else if (left.Type.IsNullable ()
+                                       && right.Type.IsNullable ()
+                                       && GetNotNullableOf (left.Type) == lp.ParameterType
+                                       && GetNotNullableOf (right.Type) == rp.ParameterType) {
+
                                        is_lifted = true;
-                                       if (method.ReturnType == typeof(bool)){
-                                               result = liftToNull ? typeof(bool?) : typeof(bool);
-                                       } else {
+
+                                       if (method.ReturnType == typeof (bool))
+                                               type = liftToNull ? typeof (bool?) : typeof (bool);
+                                       else if (!method.ReturnType.IsNullable ()) {
                                                //
                                                // This behavior is not documented: what
                                                // happens if the result is not typeof(bool), but
@@ -353,16 +404,15 @@ namespace System.Linq.Expressions {
                                                //
                                                // See:
                                                // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
-                                               result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
-                                                       //Type.GetType ("System.Nullable`1[" + method.ReturnType.ToString () + "]");
-                                       }
-                               } else {
-                                       is_lifted = false;
-                                       result = method.ReturnType;
-                               }
+
+                                               type = method.ReturnType.MakeNullableType ();
+                                       } else
+                                               throw new InvalidOperationException ();
+                               } else
+                                       throw new InvalidOperationException ();
                        }
 
-                       return new BinaryExpression (et, result, left, right, liftToNull, is_lifted, method, null);
+                       return new BinaryExpression (et, type, left, right, liftToNull, is_lifted, method, null);
                }
 
                //
@@ -389,15 +439,10 @@ namespace System.Linq.Expressions {
                {
                        method = BinaryCoreCheck ("op_Addition", left, right, method);
 
-                       //
                        // The check in BinaryCoreCheck allows a bit more than we do
                        // (byte, sbyte).  Catch that here
-                       //
-                       
-                       if (method == null){
-                               Type ltype = left.Type;
-
-                               if (ltype == typeof (byte) || ltype == typeof (sbyte))
+                       if (method == null) {
+                               if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
                                        throw new InvalidOperationException (String.Format ("AddChecked not defined for {0} and {1}", left.Type, right.Type));
                        }
 
@@ -412,6 +457,7 @@ namespace System.Linq.Expressions {
                public static BinaryExpression Subtract (Expression left, Expression right, MethodInfo method)
                {
                        method = BinaryCoreCheck ("op_Subtraction", left, right, method);
+
                        return MakeSimpleBinary (ExpressionType.Subtract, left, right, method);
                }
 
@@ -424,17 +470,13 @@ namespace System.Linq.Expressions {
                {
                        method = BinaryCoreCheck ("op_Subtraction", left, right, method);
 
-                       //
                        // The check in BinaryCoreCheck allows a bit more than we do
                        // (byte, sbyte).  Catch that here
-                       //
-
-                       if (method == null){
-                               Type ltype = left.Type;
-
-                               if (ltype == typeof (byte) || ltype == typeof (sbyte))
+                       if (method == null) {
+                               if (left.Type == typeof (byte) || left.Type == typeof (sbyte))
                                        throw new InvalidOperationException (String.Format ("SubtractChecked not defined for {0} and {1}", left.Type, right.Type));
                        }
+
                        return MakeSimpleBinary (ExpressionType.SubtractChecked, left, right, method);
                }
 
@@ -495,7 +537,7 @@ namespace System.Linq.Expressions {
                {
                        method = BinaryCoreCheck (null, left, right, method);
 
-                       if (left.Type != typeof (double))
+                       if (GetNotNullableOf (left.Type) != typeof (double))
                                throw new InvalidOperationException ("Power only supports double arguments");
 
                        return MakeSimpleBinary (ExpressionType.Power, left, right, method);
@@ -574,30 +616,43 @@ namespace System.Linq.Expressions {
 
                public static BinaryExpression AndAlso (Expression left, Expression right, MethodInfo method)
                {
-                       method = BinaryCoreCheck ("op_BitwiseAnd", left, right, method);
+                       method = ConditionalBinaryCheck ("op_BitwiseAnd", left, right, method);
 
-                       return MakeBoolBinary (ExpressionType.AndAlso, left, right, false, method);
+                       return MakeBoolBinary (ExpressionType.AndAlso, left, right, true, method);
                }
 
-               public static BinaryExpression OrElse (Expression left, Expression right)
+               static MethodInfo ConditionalBinaryCheck (string oper, Expression left, Expression right, MethodInfo method)
                {
-                       return OrElse (left, right, null);
-               }
+                       method = BinaryCoreCheck (oper, left, right, method);
 
-               public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
-               {
-                       method = BinaryCoreCheck ("op_BitwiseOr", left, right, method);
-                       if (method == null){
-                               if (left.Type != typeof (bool))
-                                       throw new InvalidOperationException ("Only booleans are allowed for OrElse");
+                       if (method == null) {
+                               if (GetNotNullableOf (left.Type) != typeof (bool))
+                                       throw new InvalidOperationException ("Only booleans are allowed");
                        } else {
                                // The method should have identical parameter and return types.
-
                                if (left.Type != right.Type || method.ReturnType != left.Type)
                                        throw new ArgumentException ("left, right and return type must match");
+
+                               var optrue = left.Type.GetMethod ("op_True", AllStatic);
+                               var opfalse = left.Type.GetMethod ("op_False", AllStatic);
+
+                               if (optrue == null || opfalse == null)
+                                       throw new ArgumentException ("Operators true and false are required but not defined");
                        }
 
-                       return MakeBoolBinary (ExpressionType.OrElse, left, right, false, method);
+                       return method;
+               }
+
+               public static BinaryExpression OrElse (Expression left, Expression right)
+               {
+                       return OrElse (left, right, null);
+               }
+
+               public static BinaryExpression OrElse (Expression left, Expression right, MethodInfo method)
+               {
+                       method = ConditionalBinaryCheck ("op_BitwiseOr", left, right, method);
+
+                       return MakeBoolBinary (ExpressionType.OrElse, left, right, true, method);
                }
 
                //
@@ -681,7 +736,7 @@ namespace System.Linq.Expressions {
                // Miscelaneous
                //
 
-               static void ArrayCheck (Expression array)
+               static void CheckArray (Expression array)
                {
                        if (array == null)
                                throw new ArgumentNullException ("array");
@@ -691,7 +746,8 @@ namespace System.Linq.Expressions {
 
                public static BinaryExpression ArrayIndex (Expression array, Expression index)
                {
-                       ArrayCheck (array);
+                       CheckArray (array);
+
                        if (index == null)
                                throw new ArgumentNullException ("index");
                        if (array.Type.GetArrayRank () != 1)
@@ -717,25 +773,24 @@ namespace System.Linq.Expressions {
                        //
                        // First arg must ne nullable (either Nullable<T> or a reference type
                        //
-                       if (left.Type.IsValueType && !IsNullable (left.Type))
+                       if (left.Type.IsValueType && !left.Type.IsNullable ())
                                throw new InvalidOperationException ("Left expression can never be null");
-                       
+
                        Type result = null;
 
-                       if (IsNullable (left.Type)){
-                               Type lbase = GetNullableOf (left.Type);
-                               
-                               if (!IsNullable (right.Type) && lbase.IsAssignableFrom (right.Type))
+                       if (left.Type.IsNullable ()) {
+                               Type lbase = GetNullableArgumentType (left.Type);
+
+                               if (!right.Type.IsNullable () && right.Type.IsAssignableTo (lbase))
                                        result = lbase;
                        }
 
-                       if (result == null && left.Type.IsAssignableFrom (right.Type))
+                       if (result == null && right.Type.IsAssignableTo (left.Type))
                                result = left.Type;
 
-                       if (result == null){
-                               if (IsNullable (left.Type) && right.Type.IsAssignableFrom (GetNullableOf (left.Type))){
+                       if (result == null) {
+                               if (left.Type.IsNullable () && GetNullableArgumentType (left.Type).IsAssignableTo (right.Type))
                                        result = right.Type;
-                               }
                        }
 
                        if (result == null)
@@ -814,7 +869,7 @@ namespace System.Linq.Expressions {
                        throw new ArgumentException ("MakeBinary expect a binary node type");
                }
 
-#endregion
+               #endregion
 
                public static MethodCallExpression ArrayIndex (Expression array, params Expression [] indexes)
                {
@@ -823,7 +878,7 @@ namespace System.Linq.Expressions {
 
                public static MethodCallExpression ArrayIndex (Expression array, IEnumerable<Expression> indexes)
                {
-                       ArrayCheck (array);
+                       CheckArray (array);
 
                        if (indexes == null)
                                throw new ArgumentNullException ("indexes");
@@ -871,7 +926,7 @@ namespace System.Linq.Expressions {
                        if (type == null)
                                throw new ArgumentException ("member");
 
-                       if (!type.IsAssignableFrom (expression.Type))
+                       if (!expression.Type.IsAssignableTo (type))
                                throw new ArgumentException ("member");
 
                        return new MemberAssignment (member, expression);
@@ -892,7 +947,7 @@ namespace System.Linq.Expressions {
                        if (setter == null)
                                throw new ArgumentException ("setter");
 
-                       if (!prop.PropertyType.IsAssignableFrom (expression.Type))
+                       if (!expression.Type.IsAssignableTo (prop.PropertyType))
                                throw new ArgumentException ("member");
 
                        return new MemberAssignment (prop, expression);
@@ -919,30 +974,103 @@ namespace System.Linq.Expressions {
                                throw new ArgumentNullException ("method");
                        if (instance == null && !method.IsStatic)
                                throw new ArgumentNullException ("instance");
-                       if (instance != null && !method.DeclaringType.IsAssignableFrom (instance.Type))
+                       if (!method.IsStatic && !instance.Type.IsAssignableTo (method.DeclaringType))
                                throw new ArgumentException ("Type is not assignable to the declaring type of the method");
 
                        var args = arguments.ToReadOnlyCollection ();
-                       var parameters = method.GetParameters ();
 
-                       if (args.Count != parameters.Length)
-                               throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
-
-                       // TODO: check for assignability of the arguments on the parameters
+                       CheckMethodArguments (method, args);
 
                        return new MethodCallExpression (instance, method, args);
                }
 
-               [MonoTODO]
+               static Type [] CollectTypes (IEnumerable<Expression> expressions)
+               {
+                       return (from arg in expressions select arg.Type).ToArray ();
+               }
+
+               static MethodInfo TryMakeGeneric (MethodInfo method, Type [] args)
+               {
+                       if (method == null)
+                               return null;
+
+                       if (!method.IsGenericMethod && args == null)
+                               return method;
+
+                       if (args.Length == method.GetGenericArguments ().Length)
+                               return method.MakeGenericMethod (args);
+
+                       return null;
+               }
+
                public static MethodCallExpression Call (Expression instance, string methodName, Type [] typeArguments, params Expression [] arguments)
                {
-                       throw new NotImplementedException ();
+                       if (instance == null)
+                               throw new ArgumentNullException ("instance");
+                       if (methodName == null)
+                               throw new ArgumentNullException ("methodName");
+
+                       var method = TryGetMethod (instance.Type, methodName, AllInstance,
+                               CollectTypes (arguments), typeArguments);
+
+                       var args = arguments.ToReadOnlyCollection ();
+
+                       CheckMethodArguments (method, args);
+
+                       return new MethodCallExpression (instance, method, args);
+               }
+
+               static bool MethodMatch (MethodInfo method, string name, Type [] parameterTypes)
+               {
+                       if (method.Name != name)
+                               return false;
+
+                       var parameters = method.GetParameters ();
+
+                       if (parameters.Length != parameterTypes.Length)
+                               return false;
+
+                       if (method.IsGenericMethod) // if it's a generic method, when can't compare its parameters
+                               return true;
+
+                       for (int i = 0; i < parameters.Length; i++)
+                               if (!IsAssignableToParameterType (parameterTypes [i], parameters [i]))
+                                       return false;
+
+                       return true;
+               }
+
+               static MethodInfo TryGetMethod (Type type, string methodName, BindingFlags flags, Type [] parameterTypes, Type [] argumentTypes)
+               {
+                       var methods = from meth in type.GetMethods (flags)
+                                                 where MethodMatch (meth, methodName, parameterTypes)
+                                                 select meth;
+
+                       if (methods.Count () > 1)
+                               throw new InvalidOperationException ("Too much method candidates");
+
+                       var method = TryMakeGeneric (methods.FirstOrDefault (), argumentTypes);
+                       if (method != null)
+                               return method;
+
+                       throw new InvalidOperationException ("No such method");
                }
 
-               [MonoTODO]
                public static MethodCallExpression Call (Type type, string methodName, Type [] typeArguments, params Expression [] arguments)
                {
-                       throw new NotImplementedException ();
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+                       if (methodName == null)
+                               throw new ArgumentNullException ("methodName");
+
+                       var method = TryGetMethod (type, methodName, AllStatic,
+                               CollectTypes (arguments), typeArguments);
+
+                       var args = arguments.ToReadOnlyCollection ();
+
+                       CheckMethodArguments (method, args);
+
+                       return new MethodCallExpression (method, args);
                }
 
                public static ConditionalExpression Condition (Expression test, Expression ifTrue, Expression ifFalse)
@@ -979,10 +1107,10 @@ namespace System.Linq.Expressions {
                        // are allowed
                        //
                        if (value == null){
-                               if (type.IsValueType && !IsNullable (type))
+                               if (type.IsValueType && !type.IsNullable ())
                                        throw new ArgumentException ();
                        } else {
-                               if (!(type.IsValueType && IsNullable (type)) && value.GetType () != type)
+                               if (!(type.IsValueType && type.IsNullable ()) && !value.GetType ().IsAssignableTo (type))
                                        throw new ArgumentException ();
 
                        }
@@ -990,40 +1118,157 @@ namespace System.Linq.Expressions {
                        return new ConstantExpression (value, type);
                }
 
-               [MonoTODO]
+               static bool IsConvertiblePrimitive (Type type)
+               {
+                       var t = GetNotNullableOf (type);
+
+                       if (t == typeof (bool))
+                               return false;
+
+                       if (t.IsEnum)
+                               return true;
+
+                       return t.IsPrimitive;
+               }
+
+               internal static bool IsPrimitiveConversion (Type type, Type target)
+               {
+                       if (type == target)
+                               return true;
+
+                       if (IsConvertiblePrimitive (type) && IsConvertiblePrimitive (target))
+                               return true;
+
+                       return false;
+               }
+
+               internal static bool IsReferenceConversion (Type type, Type target)
+               {
+                       if (type == target)
+                               return true;
+
+                       if (type.IsAssignableTo (target) || target.IsAssignableTo (type))
+                               return true;
+
+                       if (type == typeof (object) || target == typeof (object))
+                               return true;
+
+                       if (type.IsInterface || target.IsInterface)
+                               return true;
+
+                       return false;
+               }
+
                public static UnaryExpression Convert (Expression expression, Type type)
                {
-                       throw new NotImplementedException ();
+                       return Convert (expression, type, null);
+               }
+
+               static MethodInfo GetUserConversionMethod (Type type, Type target)
+               {
+                       var method = GetUnaryOperator ("op_Explicit", type, type, target);
+                       if (method == null)
+                               method = GetUnaryOperator ("op_Implicit", type, type, target);
+                       if (method == null)
+                               method = GetUnaryOperator ("op_Explicit", target, type, target);
+                       if (method == null)
+                               method = GetUnaryOperator ("op_Implicit", target, type, target);
+                       if (method == null)
+                               throw new InvalidOperationException ();
+
+                       return method;
                }
 
-               [MonoTODO]
                public static UnaryExpression Convert (Expression expression, Type type, MethodInfo method)
                {
-                       throw new NotImplementedException ();
+                       if (expression == null)
+                               throw new ArgumentNullException ("expression");
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+
+                       var et = expression.Type;
+
+                       if (method != null)
+                               CheckUnaryMethod (method, et);
+                       else if (!IsPrimitiveConversion (et, type) && !IsReferenceConversion (et, type))
+                               method = GetUserConversionMethod (et, type);
+
+                       return new UnaryExpression (ExpressionType.Convert,
+                               expression, type, method,
+                               IsConvertNodeLifted (method, expression, type));
+               }
+
+               static bool IsConvertNodeLifted (MethodInfo method, Expression operand, Type target)
+               {
+                       if (method == null)
+                               return operand.Type.IsNullable () || target.IsNullable ();
+
+                       if (operand.Type.IsNullable () && !ParameterMatch (method, operand.Type))
+                               return true;
+
+                       if (target.IsNullable () && !ReturnTypeMatch (method, target))
+                               return true;
+
+                       return false;
+               }
+
+               static bool ParameterMatch (MethodInfo method, Type type)
+               {
+                       return method.GetParameters () [0].ParameterType == type;
+               }
+
+               static bool ReturnTypeMatch (MethodInfo method, Type type)
+               {
+                       return method.ReturnType == type;
                }
 
-               [MonoTODO]
                public static UnaryExpression ConvertChecked (Expression expression, Type type)
                {
-                       throw new NotImplementedException ();
+                       return ConvertChecked (expression, type, null);
                }
 
-               [MonoTODO]
                public static UnaryExpression ConvertChecked (Expression expression, Type type, MethodInfo method)
                {
-                       throw new NotImplementedException ();
+                       if (expression == null)
+                               throw new ArgumentNullException ("expression");
+                       if (type == null)
+                               throw new ArgumentNullException ("type");
+
+                       var et = expression.Type;
+
+                       if (method != null)
+                               CheckUnaryMethod (method, et);
+                       else if (IsReferenceConversion (et, type))
+                               return Convert (expression, type, method);
+                       else if (!IsPrimitiveConversion (et, type))
+                               method = GetUserConversionMethod (et, type);
+
+                       return new UnaryExpression (ExpressionType.ConvertChecked,
+                               expression, type, method,
+                               IsConvertNodeLifted (method, expression, type));
                }
 
-               [MonoTODO]
                public static ElementInit ElementInit (MethodInfo addMethod, params Expression [] arguments)
                {
-                       throw new NotImplementedException ();
+                       return ElementInit (addMethod, arguments as IEnumerable<Expression>);
                }
 
-               [MonoTODO]
                public static ElementInit ElementInit (MethodInfo addMethod, IEnumerable<Expression> arguments)
                {
-                       throw new NotImplementedException ();
+                       if (addMethod == null)
+                               throw new ArgumentNullException ("addMethod");
+                       if (arguments == null)
+                               throw new ArgumentNullException ("arguments");
+                       if (addMethod.Name.ToLowerInvariant () != "add")
+                               throw new ArgumentException ("addMethod");
+                       if (addMethod.IsStatic)
+                               throw new ArgumentException ("addMethod must be an instance method", "addMethod");
+
+                       var args = arguments.ToReadOnlyCollection ();
+
+                       CheckMethodArguments (addMethod, args);
+
+                       return new ElementInit (addMethod, args);
                }
 
                public static MemberExpression Field (Expression expression, FieldInfo field)
@@ -1033,7 +1278,7 @@ namespace System.Linq.Expressions {
                        if (!field.IsStatic) {
                                if (expression == null)
                                        throw new ArgumentNullException ("expression");
-                               if (!field.DeclaringType.IsAssignableFrom (expression.Type))
+                               if (!expression.Type.IsAssignableTo (field.DeclaringType))
                                        throw new ArgumentException ("field");
                        }
 
@@ -1112,16 +1357,83 @@ namespace System.Linq.Expressions {
                        return func.MakeGenericType (typeArgs);
                }
 
-               [MonoTODO]
                public static InvocationExpression Invoke (Expression expression, params Expression [] arguments)
                {
-                       throw new NotImplementedException ();
+                       return Invoke (expression, arguments as IEnumerable<Expression>);
+               }
+
+               static Type GetInvokableType (Type t)
+               {
+                       if (t.IsAssignableTo (typeof (Delegate)))
+                               return t;
+
+                       return GetGenericType (t, typeof (Expression<>));
+               }
+
+               static Type GetGenericType (Type t, Type def)
+               {
+                       if (t == null)
+                               return null;
+
+                       if (t.IsGenericType && t.GetGenericTypeDefinition () == def)
+                               return t;
+
+                       return GetGenericType (t.BaseType, def);
                }
 
-               [MonoTODO]
                public static InvocationExpression Invoke (Expression expression, IEnumerable<Expression> arguments)
                {
-                       throw new NotImplementedException ();
+                       if (expression == null)
+                               throw new ArgumentNullException ("expression");
+
+                       var type = GetInvokableType (expression.Type);
+                       if (type == null)
+                               throw new ArgumentException ("The type of the expression is not invokable");
+
+                       var args = arguments.ToReadOnlyCollection ();
+                       CheckForNull (args, "arguments");
+
+                       var invoke = type.GetMethod ("Invoke");
+                       if (invoke == null)
+                               throw new ArgumentException ("expression");
+
+                       if (invoke.GetParameters ().Length != args.Count)
+                               throw new InvalidOperationException ("Arguments count doesn't match parameters length");
+
+                       CheckMethodArguments (invoke, args);
+
+                       return new InvocationExpression (expression, invoke.ReturnType, args);
+               }
+
+               static bool CanAssign (Type target, Type source)
+               {
+                       // This catches object and value type mixage, type compatibility is handled later
+                       if (target.IsValueType ^ source.IsValueType)
+                               return false;
+
+                       return source.IsAssignableTo (target);
+               }
+
+               static void CheckLambda (Type delegateType, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
+               {
+                       if (!delegateType.IsSubclassOf (typeof (System.Delegate)))
+                               throw new ArgumentException ("delegateType");
+
+                       var invoke = delegateType.GetMethod ("Invoke", BindingFlags.Instance | BindingFlags.Public);
+                       if (invoke == null)
+                               throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
+
+                       var invoke_parameters = invoke.GetParameters ();
+                       if (invoke_parameters.Length != parameters.Count)
+                               throw new ArgumentException (string.Format ("Different number of arguments in delegate {0}", delegateType), "delegateType");
+
+                       for (int i = 0; i < invoke_parameters.Length; i++) {
+                               if (!CanAssign (parameters [i].Type, invoke_parameters [i].ParameterType))
+                                       throw new ArgumentException (String.Format ("Can not assign a {0} to a {1}", invoke_parameters [i].ParameterType, parameters [i].Type));
+                       }
+
+                       if (invoke.ReturnType != typeof (void) && !CanAssign (invoke.ReturnType, body.Type))
+                               throw new ArgumentException (String.Format ("body type {0} can not be assigned to {1}", body.Type, invoke.ReturnType));
                }
 
                public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
@@ -1134,7 +1446,11 @@ namespace System.Linq.Expressions {
                        if (body == null)
                                throw new ArgumentNullException ("body");
 
-                       return new Expression<TDelegate> (body, parameters.ToReadOnlyCollection ());
+                       var ps = parameters.ToReadOnlyCollection ();
+
+                       CheckLambda (typeof (TDelegate), body, ps);
+
+                       return new Expression<TDelegate> (body, ps);
                }
 
                public static LambdaExpression Lambda (Expression body, params ParameterExpression [] parameters)
@@ -1168,6 +1484,13 @@ namespace System.Linq.Expressions {
                        return Lambda (delegateType, body, parameters as IEnumerable<ParameterExpression>);
                }
 
+               static LambdaExpression CreateExpressionOf (Type type, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
+               {
+                       return (LambdaExpression) Activator.CreateInstance (
+                               typeof (Expression<>).MakeGenericType (type),
+                               NonPublicInstance, null, new object [] { body, parameters }, null);
+               }
+
                public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
                {
                        if (delegateType == null)
@@ -1175,66 +1498,157 @@ namespace System.Linq.Expressions {
                        if (body == null)
                                throw new ArgumentNullException ("body");
 
-                       return new LambdaExpression (delegateType, body, parameters.ToReadOnlyCollection ());
+                       var ps = parameters.ToReadOnlyCollection ();
+
+                       CheckLambda (delegateType, body, ps);
+
+                       return CreateExpressionOf (delegateType, body, ps);
                }
 
                public static MemberListBinding ListBind (MemberInfo member, params ElementInit [] initializers)
                {
-                       throw new NotImplementedException ();
+                       return ListBind (member, initializers as IEnumerable<ElementInit>);
+               }
+
+               static void CheckIsAssignableToIEnumerable (Type t)
+               {
+                       if (!t.IsAssignableTo (typeof (IEnumerable)))
+                               throw new ArgumentException (string.Format ("Type {0} doesn't implemen IEnumerable", t));
                }
 
-               [MonoTODO]
                public static MemberListBinding ListBind (MemberInfo member, IEnumerable<ElementInit> initializers)
                {
-                       throw new NotImplementedException ();
+                       if (member == null)
+                               throw new ArgumentNullException ("member");
+                       if (initializers == null)
+                               throw new ArgumentNullException ("initializers");
+
+                       var inits = initializers.ToReadOnlyCollection ();
+                       CheckForNull (inits, "initializers");
+
+                       member.OnFieldOrProperty (
+                               field => CheckIsAssignableToIEnumerable (field.FieldType),
+                               prop => CheckIsAssignableToIEnumerable (prop.PropertyType));
+
+                       return new MemberListBinding (member, inits);
                }
 
-               [MonoTODO]
                public static MemberListBinding ListBind (MethodInfo propertyAccessor, params ElementInit [] initializers)
                {
-                       throw new NotImplementedException ();
+                       return ListBind (propertyAccessor, initializers as IEnumerable<ElementInit>);
+               }
+
+               static void CheckForNull<T> (ReadOnlyCollection<T> collection, string name) where T : class
+               {
+                       foreach (var t in collection)
+                               if (t == null)
+                                       throw new ArgumentNullException (name);
                }
 
-               [MonoTODO]
                public static MemberListBinding ListBind (MethodInfo propertyAccessor, IEnumerable<ElementInit> initializers)
                {
-                       throw new NotImplementedException ();
+                       if (propertyAccessor == null)
+                               throw new ArgumentNullException ("propertyAccessor");
+                       if (initializers == null)
+                               throw new ArgumentNullException ("initializers");
+
+                       var inits = initializers.ToReadOnlyCollection ();
+                       CheckForNull (inits, "initializers");
+
+                       var prop = GetAssociatedProperty (propertyAccessor);
+                       if (prop == null)
+                               throw new ArgumentException ("propertyAccessor");
+
+                       CheckIsAssignableToIEnumerable (prop.PropertyType);
+
+                       return new MemberListBinding (prop, inits);
                }
 
-               [MonoTODO]
                public static ListInitExpression ListInit (NewExpression newExpression, params ElementInit [] initializers)
                {
-                       throw new NotImplementedException ();
+                       return ListInit (newExpression, initializers as IEnumerable<ElementInit>);
                }
 
-               [MonoTODO]
                public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<ElementInit> initializers)
                {
-                       throw new NotImplementedException ();
+                       var inits = CheckListInit (newExpression, initializers);
+
+                       return new ListInitExpression (newExpression, inits);
                }
 
-               [MonoTODO]
                public static ListInitExpression ListInit (NewExpression newExpression, params Expression [] initializers)
                {
-                       throw new NotImplementedException ();
+                       return ListInit (newExpression, initializers as IEnumerable<Expression>);
                }
 
-               [MonoTODO]
                public static ListInitExpression ListInit (NewExpression newExpression, IEnumerable<Expression> initializers)
                {
-                       throw new NotImplementedException ();
+                       var inits = CheckListInit (newExpression, initializers);
+
+                       var add_method = GetAddMethod (newExpression.Type, inits [0].Type);
+                       if (add_method == null)
+                               throw new InvalidOperationException ("No suitable add method found");
+
+                       return new ListInitExpression (newExpression, CreateInitializers (add_method, inits));
+               }
+
+               static ReadOnlyCollection<ElementInit> CreateInitializers (MethodInfo add_method, ReadOnlyCollection<Expression> initializers)
+               {
+                       return (from init in initializers select Expression.ElementInit (add_method, init)).ToReadOnlyCollection ();
+               }
+
+               static MethodInfo GetAddMethod (Type type, Type arg)
+               {
+                       return type.GetMethod ("Add", PublicInstance | BindingFlags.IgnoreCase, null, new [] { arg }, null);
                }
 
-               [MonoTODO]
                public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, params Expression [] initializers)
                {
-                       throw new NotImplementedException ();
+                       return ListInit (newExpression, addMethod, initializers as IEnumerable<Expression>);
+               }
+
+               static ReadOnlyCollection<T> CheckListInit<T> (NewExpression newExpression, IEnumerable<T> initializers) where T : class
+               {
+                       if (newExpression == null)
+                               throw new ArgumentNullException ("newExpression");
+                       if (initializers == null)
+                               throw new ArgumentNullException ("initializers");
+                       if (!newExpression.Type.IsAssignableTo (typeof (IEnumerable)))
+                               throw new InvalidOperationException ("The type of the new expression does not implement IEnumerable");
+
+                       var inits = initializers.ToReadOnlyCollection ();
+                       if (inits.Count == 0)
+                               throw new ArgumentException ("Empty initializers");
+
+                       CheckForNull (inits, "initializers");
+
+                       return inits;
                }
 
-               [MonoTODO]
                public static ListInitExpression ListInit (NewExpression newExpression, MethodInfo addMethod, IEnumerable<Expression> initializers)
                {
-                       throw new NotImplementedException ();
+                       var inits = CheckListInit (newExpression, initializers);
+
+                       if (addMethod != null) {
+                               if (addMethod.Name.ToLowerInvariant () != "add")
+                                       throw new ArgumentException ("addMethod");
+
+                               var parameters = addMethod.GetParameters ();
+                               if (parameters.Length != 1)
+                                       throw new ArgumentException ("addMethod");
+
+                               foreach (var expression in inits)
+                                       if (!IsAssignableToParameterType (expression.Type, parameters [0]))
+                                               throw new InvalidOperationException ("Initializer not assignable to the add method parameter type");
+                       }
+
+                       if (addMethod == null)
+                               addMethod = GetAddMethod (newExpression.Type, inits [0].Type);
+
+                       if (addMethod == null)
+                               throw new InvalidOperationException ("No suitable add method found");
+
+                       return new ListInitExpression (newExpression, CreateInitializers (addMethod, inits));
                }
 
                public static MemberExpression MakeMemberAccess (Expression expression, MemberInfo member)
@@ -1286,40 +1700,69 @@ namespace System.Linq.Expressions {
                        throw new ArgumentException ("MakeUnary expect an unary operator");
                }
 
-               [MonoTODO]
-               public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] binding)
+               public static MemberMemberBinding MemberBind (MemberInfo member, params MemberBinding [] bindings)
                {
-                       throw new NotImplementedException ();
+                       return MemberBind (member, bindings as IEnumerable<MemberBinding>);
                }
 
-               [MonoTODO]
-               public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> binding)
+               public static MemberMemberBinding MemberBind (MemberInfo member, IEnumerable<MemberBinding> bindings)
                {
-                       throw new NotImplementedException ();
+                       if (member == null)
+                               throw new ArgumentNullException ("member");
+
+                       var type = member.OnFieldOrProperty (
+                               field => field.FieldType,
+                               prop => prop.PropertyType);
+
+                       return new MemberMemberBinding (member, CheckMemberBindings (type, bindings));
                }
 
-               [MonoTODO]
-               public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] binding)
+               public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, params MemberBinding [] bindings)
                {
-                       throw new NotImplementedException ();
+                       return MemberBind (propertyAccessor, bindings as IEnumerable<MemberBinding>);
                }
 
-               [MonoTODO]
-               public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> binding)
+               public static MemberMemberBinding MemberBind (MethodInfo propertyAccessor, IEnumerable<MemberBinding> bindings)
                {
-                       throw new NotImplementedException ();
+                       if (propertyAccessor == null)
+                               throw new ArgumentNullException ("propertyAccessor");
+
+                       var bds = bindings.ToReadOnlyCollection ();
+                       CheckForNull (bds, "bindings");
+
+                       var prop = GetAssociatedProperty (propertyAccessor);
+                       if (prop == null)
+                               throw new ArgumentException ("propertyAccessor");
+
+                       return new MemberMemberBinding (prop, CheckMemberBindings (prop.PropertyType, bindings));
                }
 
-               [MonoTODO]
-               public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] binding)
+               static ReadOnlyCollection<MemberBinding> CheckMemberBindings (Type type, IEnumerable<MemberBinding> bindings)
                {
-                       throw new NotImplementedException ();
+                       if (bindings == null)
+                               throw new ArgumentNullException ("bindings");
+
+                       var bds = bindings.ToReadOnlyCollection ();
+                       CheckForNull (bds, "bindings");
+
+                       foreach (var binding in bds)
+                               if (!type.IsAssignableTo (binding.Member.DeclaringType))
+                                       throw new ArgumentException ("Type not assignable to member type");
+
+                       return bds;
                }
 
-               [MonoTODO]
-               public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> binding)
+               public static MemberInitExpression MemberInit (NewExpression newExpression, params MemberBinding [] bindings)
                {
-                       throw new NotImplementedException ();
+                       return MemberInit (newExpression, bindings as IEnumerable<MemberBinding>);
+               }
+
+               public static MemberInitExpression MemberInit (NewExpression newExpression, IEnumerable<MemberBinding> bindings)
+               {
+                       if (newExpression == null)
+                               throw new ArgumentNullException ("newExpression");
+
+                       return new MemberInitExpression (newExpression, CheckMemberBindings (newExpression.Type, bindings));
                }
 
                public static UnaryExpression Negate (Expression expression)
@@ -1329,7 +1772,7 @@ namespace System.Linq.Expressions {
 
                public static UnaryExpression Negate (Expression expression, MethodInfo method)
                {
-                       method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
+                       method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
 
                        return MakeSimpleUnary (ExpressionType.Negate, expression, method);
                }
@@ -1341,9 +1784,9 @@ namespace System.Linq.Expressions {
 
                public static UnaryExpression NegateChecked (Expression expression, MethodInfo method)
                {
-                       method = UnaryCoreCheck ("op_UnaryNegation", expression, method);
+                       method = UnaryCoreCheck ("op_UnaryNegation", expression, method, type => IsSignedNumber (type));
 
-                       return MakeSimpleUnary (ExpressionType.Negate, expression, method);
+                       return MakeSimpleUnary (ExpressionType.NegateChecked, expression, method);
                }
 
                public static NewExpression New (ConstructorInfo constructor)
@@ -1354,7 +1797,7 @@ namespace System.Linq.Expressions {
                        if (constructor.GetParameters ().Length > 0)
                                throw new ArgumentException ("Constructor must be parameter less");
 
-                       return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection<Expression> (), null);
+                       return new NewExpression (constructor, (null as IEnumerable<Expression>).ToReadOnlyCollection (), null);
                }
 
                public static NewExpression New (Type type)
@@ -1362,10 +1805,18 @@ namespace System.Linq.Expressions {
                        if (type == null)
                                throw new ArgumentNullException ("type");
 
-                       if (type.GetConstructor (Type.EmptyTypes) == null)
+                       CheckNotVoid (type);
+
+                       var args = (null as IEnumerable<Expression>).ToReadOnlyCollection ();
+
+                       if (type.IsValueType)
+                               return new NewExpression (type, args);
+
+                       var ctor = type.GetConstructor (Type.EmptyTypes);
+                       if (ctor == null)
                                throw new ArgumentException ("Type doesn't have a parameter less constructor");
 
-                       return new NewExpression (type, (null as IEnumerable<Expression>).ToReadOnlyCollection<Expression> ());
+                       return new NewExpression (ctor, args, null);
                }
 
                public static NewExpression New (ConstructorInfo constructor, params Expression [] arguments)
@@ -1379,32 +1830,75 @@ namespace System.Linq.Expressions {
                                throw new ArgumentNullException ("constructor");
 
                        var args = arguments.ToReadOnlyCollection ();
-                       var parameters = constructor.GetParameters ();
 
-                       if (args.Count != parameters.Length)
-                               throw new ArgumentException ("arguments");
+                       CheckMethodArguments (constructor, args);
+
+                       return new NewExpression (constructor, args, null);
+               }
+
+               static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
+               {
+                       var parameters = method.GetParameters ();
+
+                       if (arguments.Count != parameters.Length)
+                               throw new ArgumentException ("The number of arguments doesn't match the number of parameters");
 
                        for (int i = 0; i < parameters.Length; i++) {
-                               if (args [i] == null)
+                               if (arguments [i] == null)
                                        throw new ArgumentNullException ("arguments");
 
-                               if (!parameters [i].ParameterType.IsAssignableFrom (args [i].Type))
+                               if (!IsAssignableToParameterType (arguments [i].Type, parameters [i]))
                                        throw new ArgumentException ("arguments");
                        }
-
-                       return new NewExpression (constructor, args, null);
                }
 
-               [MonoTODO]
                public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
                {
-                       throw new NotImplementedException ();
+                       return New (constructor, arguments, members as IEnumerable<MemberInfo>);
                }
 
-               [MonoTODO]
                public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, IEnumerable<MemberInfo> members)
                {
-                       throw new NotImplementedException ();
+                       if (constructor == null)
+                               throw new ArgumentNullException ("constructor");
+
+                       var args = arguments.ToReadOnlyCollection ();
+                       var mmbs = members.ToReadOnlyCollection ();
+
+                       CheckForNull (args, "arguments");
+                       CheckForNull (mmbs, "members");
+
+                       CheckMethodArguments (constructor, args);
+
+                       if (args.Count != mmbs.Count)
+                               throw new ArgumentException ("Arguments count does not match members count");
+
+                       for (int i = 0; i < mmbs.Count; i++) {
+                               var member = mmbs [i];
+                               Type type = null;
+                               switch (member.MemberType) {
+                               case MemberTypes.Field:
+                                       type = (member as FieldInfo).FieldType;
+                                       break;
+                               case MemberTypes.Method:
+                                       type = (member as MethodInfo).ReturnType;
+                                       break;
+                               case MemberTypes.Property:
+                                       var prop = member as PropertyInfo;
+                                       if (prop.GetGetMethod (true) == null)
+                                               throw new ArgumentException ("Property must have a getter");
+
+                                       type = (member as PropertyInfo).PropertyType;
+                                       break;
+                               default:
+                                       throw new ArgumentException ("Member type not allowed");
+                               }
+
+                               if (!args [i].Type.IsAssignableTo (type))
+                                       throw new ArgumentException ("Argument type not assignable to member type");
+                       }
+
+                       return new NewExpression (constructor, args, mmbs);
                }
 
                public static NewArrayExpression NewArrayBounds (Type type, params Expression [] bounds)
@@ -1419,6 +1913,8 @@ namespace System.Linq.Expressions {
                        if (bounds == null)
                                throw new ArgumentNullException ("bounds");
 
+                       CheckNotVoid (type);
+
                        var array_bounds = bounds.ToReadOnlyCollection ();
                        foreach (var expression in array_bounds)
                                if (!IsInt (expression.Type))
@@ -1439,19 +1935,21 @@ namespace System.Linq.Expressions {
                        if (initializers == null)
                                throw new ArgumentNullException ("initializers");
 
-                       var array_initializers = initializers.ToReadOnlyCollection ();
+                       CheckNotVoid (type);
 
-                       foreach (var expression in initializers) {
+                       var inits = initializers.ToReadOnlyCollection ();
+
+                       foreach (var expression in inits) {
                                if (expression == null)
                                        throw new ArgumentNullException ("initializers");
 
-                               if (!type.IsAssignableFrom (expression.Type))
+                               if (!expression.Type.IsAssignableTo (type))
                                        throw new InvalidOperationException ();
 
                                // TODO: Quote elements if type == typeof (Expression)
                        }
 
-                       return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), array_initializers);
+                       return new NewArrayExpression (ExpressionType.NewArrayInit, type.MakeArrayType (), inits);
                }
 
                public static UnaryExpression Not (Expression expression)
@@ -1461,16 +1959,29 @@ namespace System.Linq.Expressions {
 
                public static UnaryExpression Not (Expression expression, MethodInfo method)
                {
-                       method = UnaryCoreCheck ("op_LogicalNot", expression, method);
+                       Func<Type, bool> validator = type => IsIntOrBool (type);
+
+                       method = UnaryCoreCheck ("op_LogicalNot", expression, method, validator);
+
+                       if (method == null)
+                               method = UnaryCoreCheck ("op_OnesComplement", expression, method, validator);
 
                        return MakeSimpleUnary (ExpressionType.Not, expression, method);
                }
 
+               static void CheckNotVoid (Type type)
+               {
+                       if (type == typeof (void))
+                               throw new ArgumentException ("Type can't be void");
+               }
+
                public static ParameterExpression Parameter (Type type, string name)
                {
                        if (type == null)
                                throw new ArgumentNullException ("type");
 
+                       CheckNotVoid (type);
+
                        return new ParameterExpression (type, name);
                }
 
@@ -1482,7 +1993,7 @@ namespace System.Linq.Expressions {
                        if (!propertyAccessor.IsStatic) {
                                if (expression == null)
                                        throw new ArgumentNullException ("expression");
-                               if (!propertyAccessor.DeclaringType.IsAssignableFrom (expression.Type))
+                               if (!expression.Type.IsAssignableTo (propertyAccessor.DeclaringType))
                                        throw new ArgumentException ("expression");
                        }
 
@@ -1517,7 +2028,7 @@ namespace System.Linq.Expressions {
                        if (!getter.IsStatic) {
                                if (expression == null)
                                        throw new ArgumentNullException ("expression");
-                               if (!property.DeclaringType.IsAssignableFrom (expression.Type))
+                               if (!expression.Type.IsAssignableTo (property.DeclaringType))
                                        throw new ArgumentException ("expression");
                        }
 
@@ -1568,7 +2079,7 @@ namespace System.Linq.Expressions {
                                throw new ArgumentNullException ("expression");
                        if (type == null)
                                throw new ArgumentNullException ("type");
-                       if (type.IsValueType && !IsNullable (type))
+                       if (type.IsValueType && !type.IsNullable ())
                                throw new ArgumentException ("TypeAs expect a reference or a nullable type");
 
                        return new UnaryExpression (ExpressionType.TypeAs, expression, type);
@@ -1581,6 +2092,8 @@ namespace System.Linq.Expressions {
                        if (type == null)
                                throw new ArgumentNullException ("type");
 
+                       CheckNotVoid (type);
+
                        return new TypeBinaryExpression (ExpressionType.TypeIs, expression, type, typeof (bool));
                }
 
@@ -1591,36 +2104,70 @@ namespace System.Linq.Expressions {
 
                public static UnaryExpression UnaryPlus (Expression expression, MethodInfo method)
                {
-                       method = UnaryCoreCheck ("op_UnaryPlus", expression, method);
+                       method = UnaryCoreCheck ("op_UnaryPlus", expression, method, type => IsNumber (type));
 
                        return MakeSimpleUnary (ExpressionType.UnaryPlus, expression, method);
                }
 
-               internal static bool IsNullable (Type type)
+               static bool IsInt (Type t)
+               {
+                       return t == typeof (byte) || t == typeof (sbyte) ||
+                               t == typeof (short) || t == typeof (ushort) ||
+                               t == typeof (int) || t == typeof (uint) ||
+                               t == typeof (long) || t == typeof (ulong);
+               }
+
+               static bool IsIntOrBool (Type t)
+               {
+                       return IsInt (t) || t == typeof (bool);
+               }
+
+               static bool IsNumber (Type t)
+               {
+                       if (IsInt (t))
+                               return true;
+
+                       return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
+               }
+
+               static bool IsSignedNumber (Type t)
                {
-                       return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
+                       return IsNumber (t) && !IsUnsigned (t);
                }
 
                internal static bool IsUnsigned (Type t)
                {
+#if !TARGET_JVM
                        if (t.IsPointer)
                                return IsUnsigned (t.GetElementType ());
 
-                       return t == typeof (ushort) || t == typeof (uint) || t == typeof (ulong) || t == typeof (byte);
+#endif
+                       return t == typeof (ushort) ||
+                               t == typeof (uint) ||
+                               t == typeof (ulong) ||
+                               t == typeof (byte);
                }
 
                //
                // returns the T in a a Nullable<T> type.
                //
-               internal static Type GetNullableOf (Type type)
+               internal static Type GetNullableArgumentType (Type type)
                {
-                       return type.GetGenericArguments () [0];
+                       return type.GetFirstGenericArgument ();
                }
-               
+
+               internal static Type GetNotNullableOf (Type type)
+               {
+                       return type.IsNullable () ? GetNullableArgumentType (type) : type;
+               }
+
                //
                // This method must be overwritten by derived classes to
                // compile the expression
                //
-               internal abstract void Emit (EmitContext ec);
+               internal virtual void Emit (EmitContext ec)
+               {
+                       throw new NotImplementedException ();
+               }
        }
 }