Merge pull request #498 from Unroll-Me/master
[mono.git] / mcs / class / System.Core / System.Linq.Expressions / Expression.cs
index 0715a7a48fea6fc68b018ec74e2400baa0270d4e..bfe939a5cb0901bb47395d82de7a18de15840b68 100644 (file)
@@ -31,6 +31,7 @@ using System;
 using System.Collections;
 using System.Collections.Generic;
 using System.Collections.ObjectModel;
+using System.Globalization;
 using System.Linq;
 using System.Reflection;
 using System.Reflection.Emit;
@@ -42,12 +43,12 @@ namespace System.Linq.Expressions {
                ExpressionType node_type;
                Type type;
 
-               const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance;
-               const BindingFlags NonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance;
-               const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static;
-               const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance;
-               const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static;
-               const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance;
+               internal const BindingFlags PublicInstance = BindingFlags.Public | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
+               internal const BindingFlags NonPublicInstance = BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
+               internal const BindingFlags PublicStatic = BindingFlags.Public | BindingFlags.Static | BindingFlags.FlattenHierarchy;
+               internal const BindingFlags AllInstance = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
+               internal const BindingFlags AllStatic = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.FlattenHierarchy;
+               internal const BindingFlags All = BindingFlags.Public | BindingFlags.NonPublic | BindingFlags.Static | BindingFlags.Instance | BindingFlags.FlattenHierarchy;
 
                public ExpressionType NodeType {
                        get { return node_type; }
@@ -77,7 +78,7 @@ namespace System.Linq.Expressions {
 
                static MethodInfo GetUnaryOperator (string oper_name, Type declaring, Type param, Type ret)
                {
-                       var methods = declaring.GetMethods (PublicStatic);
+                       var methods = declaring.GetNotNullableType ().GetMethods (PublicStatic);
 
                        foreach (var method in methods) {
                                if (method.Name != oper_name)
@@ -87,10 +88,13 @@ namespace System.Linq.Expressions {
                                if (parameters.Length != 1)
                                        continue;
 
-                               if (!IsAssignableToParameterType (param, parameters [0]))
+                               if (method.IsGenericMethod)
                                        continue;
 
-                               if (ret != null && method.ReturnType != GetNotNullableOf (ret))
+                               if (!IsAssignableToParameterType (param.GetNotNullableType (), parameters [0]))
+                                       continue;
+
+                               if (ret != null && method.ReturnType != ret.GetNotNullableType ())
                                        continue;
 
                                return method;
@@ -99,13 +103,28 @@ namespace System.Linq.Expressions {
                        return null;
                }
 
+               internal static MethodInfo GetTrueOperator (Type self)
+               {
+                       return GetBooleanOperator ("op_True", self);
+               }
+
+               internal static MethodInfo GetFalseOperator (Type self)
+               {
+                       return GetBooleanOperator ("op_False", self);
+               }
+
+               static MethodInfo GetBooleanOperator (string op, Type self)
+               {
+                       return GetUnaryOperator (op, self, self, typeof (bool));
+               }
+
                static bool IsAssignableToParameterType (Type type, ParameterInfo param)
                {
                        var ptype = param.ParameterType;
                        if (ptype.IsByRef)
                                ptype = ptype.GetElementType ();
 
-                       return GetNotNullableOf (type).IsAssignableTo (ptype);
+                       return type.GetNotNullableType ().IsAssignableTo (ptype);
                }
 
                static MethodInfo CheckUnaryMethod (MethodInfo method, Type param)
@@ -121,7 +140,7 @@ namespace System.Linq.Expressions {
                        if (parameters.Length != 1)
                                throw new ArgumentException ("Must have only one parameters", "method");
 
-                       if (!IsAssignableToParameterType (param, parameters [0]))
+                       if (!IsAssignableToParameterType (param.GetNotNullableType (), parameters [0]))
                                throw new InvalidOperationException ("left-side argument type does not match expression type");
 
                        return method;
@@ -135,7 +154,7 @@ namespace System.Linq.Expressions {
                        if (method != null)
                                return CheckUnaryMethod (method, expression.Type);
 
-                               var type = GetNotNullableOf (expression.Type);
+                       var type = expression.Type.GetNotNullableType ();
 
                                if (validator (type))
                                        return null;
@@ -162,6 +181,9 @@ namespace System.Linq.Expressions {
                                if (parameters.Length != 2)
                                        continue;
 
+                               if (method.IsGenericMethod)
+                                       continue;
+
                                if (!IsAssignableToParameterType (left.Type, parameters [0]))
                                        continue;
 
@@ -208,8 +230,8 @@ namespace System.Linq.Expressions {
                        } else {
                                Type ltype = left.Type;
                                Type rtype = right.Type;
-                               Type ultype = GetNotNullableOf (ltype);
-                               Type urtype = GetNotNullableOf (rtype);
+                               Type ultype = ltype.GetNotNullableType ();
+                               Type urtype = rtype.GetNotNullableType ();
 
                                if (oper_name == "op_BitwiseOr" || oper_name == "op_BitwiseAnd") {
                                        if (ultype == typeof (bool)) {
@@ -219,7 +241,7 @@ namespace System.Linq.Expressions {
                                }
 
                                // Use IsNumber to avoid expensive reflection.
-                               if (IsNumber (ultype)){
+                               if (IsNumber (ultype)) {
                                        if (ultype == urtype && ltype == rtype)
                                                return null;
 
@@ -236,12 +258,24 @@ namespace System.Linq.Expressions {
                                                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.IsEnum)
+                                               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));
@@ -276,83 +310,112 @@ namespace System.Linq.Expressions {
                        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)
                {
                        bool is_lifted;
+                       Type type;
 
                        if (method == null) {
-                               if (IsNullable (left.Type)) {
-                                       if (!IsNullable (right.Type))
-                                               throw new InvalidOperationException ("Assertion, internal error: left is nullable, requires right to be as well");
+                               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 ()
+                                       && left.Type.GetNotNullableType () == lp.ParameterType
+                                       && right.Type.GetNotNullableType () == 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, GetResultType (left, method), left, right, is_lifted, 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)
                {
                        bool is_lifted;
+                       Type type;
 
                        if (method == null) {
-                               is_lifted = IsNullable (expression.Type);
+                               type = expression.Type;
+                               is_lifted = type.IsNullable ();
                        } else {
-                               // FIXME: implement
-                               is_lifted = false;
+                               var parameter = method.GetParameters () [0];
+
+                               if (IsAssignableToOperatorParameter (expression, parameter)) {
+                                       is_lifted = false;
+                                       type = method.ReturnType;
+                               } else if (expression.Type.IsNullable ()
+                                       && expression.Type.GetNotNullableType () == parameter.ParameterType
+                                       && !method.ReturnType.IsNullable ()) {
+
+                                       is_lifted = true;
+                                       type = method.ReturnType.MakeNullableType ();
+                               } else
+                                       throw new InvalidOperationException ();
                        }
 
-                       return new UnaryExpression (et, expression, GetResultType (expression, method), method, is_lifted);
+                       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 && !rnullable) {
+                               if (!left.Type.IsNullable () && !right.Type.IsNullable ()) {
                                        is_lifted = false;
                                        liftToNull = false;
-                                       result = typeof (bool);
-                               } else if (lnullable && rnullable) {
+                                       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 InvalidOperationException ("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;
+                               var parameters = method.GetParameters ();
 
-                               if (ltype == mltype && rtype == mrtype) {
+                               var lp = parameters [0];
+                               var rp = parameters [1];
+
+                               if (IsAssignableToOperatorParameter (left, lp) && IsAssignableToOperatorParameter (right, rp)) {
                                        is_lifted = false;
                                        liftToNull = false;
-                                       result = method.ReturnType;
-                               } else if (ltype.IsValueType && rtype.IsValueType &&
-                                          ((lnullable && GetNullableOf (ltype) == mltype) ||
-                                               (rnullable && GetNullableOf (rtype) == mrtype))){
+                                       type = method.ReturnType;
+                               } else if (left.Type.IsNullable ()
+                                       && right.Type.IsNullable ()
+                                       && left.Type.GetNotNullableType () == lp.ParameterType
+                                       && right.Type.GetNotNullableType () == 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
@@ -361,16 +424,15 @@ namespace System.Linq.Expressions {
                                                //
                                                // See:
                                                // https://connect.microsoft.com/VisualStudio/feedback/ViewFeedback.aspx?FeedbackID=323139
-                                               result = typeof (Nullable<>).MakeGenericType (method.ReturnType);
-                                       }
-                               } else {
-                                       is_lifted = false;
-                                       liftToNull = 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);
                }
 
                //
@@ -495,7 +557,7 @@ namespace System.Linq.Expressions {
                {
                        method = BinaryCoreCheck (null, left, right, method);
 
-                       if (left.Type != typeof (double))
+                       if (left.Type.GetNotNullableType () != typeof (double))
                                throw new InvalidOperationException ("Power only supports double arguments");
 
                        return MakeSimpleBinary (ExpressionType.Power, left, right, method);
@@ -584,12 +646,20 @@ namespace System.Linq.Expressions {
                        method = BinaryCoreCheck (oper, left, right, method);
 
                        if (method == null) {
-                               if (GetNotNullableOf (left.Type) != typeof (bool))
+                               if (left.Type.GetNotNullableType () != typeof (bool))
                                        throw new InvalidOperationException ("Only booleans are allowed");
                        } else {
+                               var type = left.Type.GetNotNullableType ();
+
                                // The method should have identical parameter and return types.
-                               if (left.Type != right.Type || method.ReturnType != left.Type)
+                               if (left.Type != right.Type || method.ReturnType != type)
                                        throw new ArgumentException ("left, right and return type must match");
+
+                               var optrue = GetTrueOperator (type);
+                               var opfalse = GetFalseOperator (type);
+
+                               if (optrue == null || opfalse == null)
+                                       throw new ArgumentException ("Operators true and false are required but not defined");
                        }
 
                        return method;
@@ -715,25 +785,14 @@ namespace System.Linq.Expressions {
                        return Coalesce (left, right, null);
                }
 
-               public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
+               static BinaryExpression MakeCoalesce (Expression left, Expression right)
                {
-                       if (left == null)
-                               throw new ArgumentNullException ("left");
-                       if (right == null)
-                               throw new ArgumentNullException ("right");
-
-                       //
-                       // First arg must ne nullable (either Nullable<T> or a reference type
-                       //
-                       if (left.Type.IsValueType && !IsNullable (left.Type))
-                               throw new InvalidOperationException ("Left expression can never be null");
-
                        Type result = null;
 
-                       if (IsNullable (left.Type)) {
-                               Type lbase = GetNullableOf (left.Type);
+                       if (left.Type.IsNullable ()) {
+                               Type lbase = left.Type.GetNotNullableType ();
 
-                               if (!IsNullable (right.Type) && right.Type.IsAssignableTo (lbase))
+                               if (!right.Type.IsNullable () && right.Type.IsAssignableTo (lbase))
                                        result = lbase;
                        }
 
@@ -741,17 +800,53 @@ namespace System.Linq.Expressions {
                                result = left.Type;
 
                        if (result == null) {
-                               if (IsNullable (left.Type) && GetNullableOf (left.Type).IsAssignableTo (right.Type))
+                               if (left.Type.IsNullable () && left.Type.GetNotNullableType ().IsAssignableTo (right.Type))
                                        result = right.Type;
                        }
 
                        if (result == null)
                                throw new ArgumentException ("Incompatible argument types");
 
+                       return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, null);
+               }
+
+               static BinaryExpression MakeConvertedCoalesce (Expression left, Expression right, LambdaExpression conversion)
+               {
+                       var invoke = conversion.Type.GetInvokeMethod ();
+
+                       CheckNotVoid (invoke.ReturnType);
+
+                       if (invoke.ReturnType != right.Type)
+                               throw new InvalidOperationException ("Conversion return type doesn't march right type");
+
+                       var parameters = invoke.GetParameters ();
+
+                       if (parameters.Length != 1)
+                               throw new ArgumentException ("Conversion has wrong number of parameters");
+
+                       if (!IsAssignableToParameterType (left.Type, parameters [0]))
+                               throw new InvalidOperationException ("Conversion argument doesn't marcht left type");
+
+                       return new BinaryExpression (ExpressionType.Coalesce, right.Type, left, right, false, false, null, conversion);
+               }
+
+               public static BinaryExpression Coalesce (Expression left, Expression right, LambdaExpression conversion)
+               {
+                       if (left == null)
+                               throw new ArgumentNullException ("left");
+                       if (right == null)
+                               throw new ArgumentNullException ("right");
+
                        //
-                       // FIXME: What do we do with "conversion"?
+                       // First arg must ne nullable (either Nullable<T> or a reference type
                        //
-                       return new BinaryExpression (ExpressionType.Coalesce, result, left, right, false, false, null, conversion);
+                       if (left.Type.IsValueType && !left.Type.IsNullable ())
+                               throw new InvalidOperationException ("Left expression can never be null");
+
+                       if (conversion != null)
+                               return MakeConvertedCoalesce (left, right, conversion);
+
+                       return MakeCoalesce (left, right);
                }
 
                //
@@ -776,6 +871,8 @@ namespace System.Linq.Expressions {
                                return AddChecked (left, right, method);
                        case ExpressionType.AndAlso:
                                return AndAlso (left, right);
+                       case ExpressionType.ArrayIndex:
+                               return ArrayIndex (left, right);
                        case ExpressionType.Coalesce:
                                return Coalesce (left, right, conversion);
                        case ExpressionType.Divide:
@@ -891,6 +988,8 @@ namespace System.Linq.Expressions {
                        if (expression == null)
                                throw new ArgumentNullException ("expression");
 
+                       CheckNonGenericMethod (propertyAccessor);
+
                        var prop = GetAssociatedProperty (propertyAccessor);
                        if (prop == null)
                                throw new ArgumentException ("propertyAccessor");
@@ -926,12 +1025,12 @@ namespace System.Linq.Expressions {
                                throw new ArgumentNullException ("method");
                        if (instance == null && !method.IsStatic)
                                throw new ArgumentNullException ("instance");
+                       if (method.IsStatic && instance != null)
+                               throw new ArgumentException ("instance");
                        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 ();
-
-                       CheckMethodArguments (method, args);
+                       var args = CheckMethodArguments (method, arguments);
 
                        return new MethodCallExpression (instance, method, args);
                }
@@ -946,7 +1045,7 @@ namespace System.Linq.Expressions {
                        if (method == null)
                                return null;
 
-                       if (!method.IsGenericMethod && args == null)
+                       if (!method.IsGenericMethod && (args == null || args.Length == 0))
                                return method;
 
                        if (args.Length == method.GetGenericArguments ().Length)
@@ -965,14 +1064,12 @@ namespace System.Linq.Expressions {
                        var method = TryGetMethod (instance.Type, methodName, AllInstance,
                                CollectTypes (arguments), typeArguments);
 
-                       var args = arguments.ToReadOnlyCollection ();
-
-                       CheckMethodArguments (method, args);
+                       var args = CheckMethodArguments (method, arguments);
 
                        return new MethodCallExpression (instance, method, args);
                }
 
-               static bool MethodMatch (MethodInfo method, string name, Type [] parameterTypes)
+               static bool MethodMatch (MethodInfo method, string name, Type [] parameterTypes, Type [] argumentTypes)
                {
                        if (method.Name != name)
                                return false;
@@ -982,24 +1079,39 @@ namespace System.Linq.Expressions {
                        if (parameters.Length != parameterTypes.Length)
                                return false;
 
-                       if (method.IsGenericMethod) // if it's a generic method, when can't compare its parameters
-                               return true;
+                       if (method.IsGenericMethod && method.IsGenericMethodDefinition) {
+                               var closed = TryMakeGeneric (method, argumentTypes);
+                               if (closed == null)
+                                       return false;
 
-                       for (int i = 0; i < parameters.Length; i++)
-                               if (!IsAssignableToParameterType (parameterTypes [i], parameters [i]))
+                               return MethodMatch (closed, name, parameterTypes, argumentTypes);
+                       } else if (!method.IsGenericMethod && (argumentTypes != null && argumentTypes.Length > 0))
+                               return false;
+
+                       for (int i = 0; i < parameters.Length; i++) {
+                               var type = parameterTypes [i];
+                               var parameter = parameters [i];
+                               if (!IsAssignableToParameterType (type, parameter)
+                                       && !IsExpressionOfParameter (type, parameter.ParameterType))
                                        return false;
+                       }
 
                        return true;
                }
 
+               static bool IsExpressionOfParameter (Type type, Type ptype)
+               {
+                       return ptype.IsGenericInstanceOf (typeof (Expression<>)) && ptype.GetFirstGenericArgument () == type;
+               }
+
                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)
+                                                 where MethodMatch (meth, methodName, parameterTypes, argumentTypes)
                                                  select meth;
 
                        if (methods.Count () > 1)
-                               throw new InvalidOperationException ("Too much method candidates");
+                               throw new InvalidOperationException ("Too many method candidates");
 
                        var method = TryMakeGeneric (methods.FirstOrDefault (), argumentTypes);
                        if (method != null)
@@ -1018,9 +1130,7 @@ namespace System.Linq.Expressions {
                        var method = TryGetMethod (type, methodName, AllStatic,
                                CollectTypes (arguments), typeArguments);
 
-                       var args = arguments.ToReadOnlyCollection ();
-
-                       CheckMethodArguments (method, args);
+                       var args = CheckMethodArguments (method, arguments);
 
                        return new MethodCallExpression (method, args);
                }
@@ -1059,10 +1169,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 ().IsAssignableTo (type))
+                               if (!(type.IsValueType && type.IsNullable ()) && !value.GetType ().IsAssignableTo (type))
                                        throw new ArgumentException ();
 
                        }
@@ -1072,8 +1182,8 @@ namespace System.Linq.Expressions {
 
                static bool IsConvertiblePrimitive (Type type)
                {
-                       var t = GetNotNullableOf (type);
-
+                       var t = type.GetNotNullableType ();
+       
                        if (t == typeof (bool))
                                return false;
 
@@ -1088,6 +1198,12 @@ namespace System.Linq.Expressions {
                        if (type == target)
                                return true;
 
+                       if (type.IsNullable () && target == type.GetNotNullableType ())
+                               return true;
+
+                       if (target.IsNullable () && type == target.GetNotNullableType ())
+                               return true;
+
                        if (IsConvertiblePrimitive (type) && IsConvertiblePrimitive (target))
                                return true;
 
@@ -1099,15 +1215,21 @@ namespace System.Linq.Expressions {
                        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;
 
+                       if (type.IsEnum && target == typeof (Enum))
+                               return true;
+
+                       if (type.IsValueType || target.IsValueType)
+                               return false;
+
+                       if (type.IsAssignableTo (target) || target.IsAssignableTo (type))
+                               return true;
+
                        return false;
                }
 
@@ -1121,6 +1243,10 @@ namespace System.Linq.Expressions {
                        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 ();
 
@@ -1149,12 +1275,12 @@ namespace System.Linq.Expressions {
                static bool IsConvertNodeLifted (MethodInfo method, Expression operand, Type target)
                {
                        if (method == null)
-                               return IsNullable (operand.Type) || IsNullable (target);
+                               return operand.Type.IsNullable () || target.IsNullable ();
 
-                       if (IsNullable (operand.Type) && !ParameterMatch (method, operand.Type))
+                       if (operand.Type.IsNullable () && !ParameterMatch (method, operand.Type))
                                return true;
 
-                       if (IsNullable (target) && !ReturnTypeMatch (method, target))
+                       if (target.IsNullable () && !ReturnTypeMatch (method, target))
                                return true;
 
                        return false;
@@ -1207,14 +1333,12 @@ namespace System.Linq.Expressions {
                                throw new ArgumentNullException ("addMethod");
                        if (arguments == null)
                                throw new ArgumentNullException ("arguments");
-                       if (addMethod.Name.ToLowerInvariant () != "add")
+                       if (addMethod.Name.ToLower (CultureInfo.InvariantCulture) != "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);
+                       var args = CheckMethodArguments (addMethod, arguments);
 
                        return new ElementInit (addMethod, args);
                }
@@ -1228,7 +1352,8 @@ namespace System.Linq.Expressions {
                                        throw new ArgumentNullException ("expression");
                                if (!expression.Type.IsAssignableTo (field.DeclaringType))
                                        throw new ArgumentException ("field");
-                       }
+                       } else if (expression != null)
+                               throw new ArgumentException ("expression");
 
                        return new MemberExpression (expression, field, field.FieldType);
                }
@@ -1341,14 +1466,14 @@ namespace System.Linq.Expressions {
                        var args = arguments.ToReadOnlyCollection ();
                        CheckForNull (args, "arguments");
 
-                       var invoke = type.GetMethod ("Invoke");
+                       var invoke = type.GetInvokeMethod ();
                        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);
+                       args = CheckMethodArguments (invoke, args);
 
                        return new InvocationExpression (expression, invoke.ReturnType, args);
                }
@@ -1362,12 +1487,12 @@ namespace System.Linq.Expressions {
                        return source.IsAssignableTo (target);
                }
 
-               static void CheckLambda (Type delegateType, Expression body, ReadOnlyCollection<ParameterExpression> parameters)
+               static Expression 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);
+                       var invoke = delegateType.GetInvokeMethod ();
                        if (invoke == null)
                                throw new ArgumentException ("delegate must contain an Invoke method", "delegateType");
 
@@ -1376,12 +1501,23 @@ namespace System.Linq.Expressions {
                                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));
+                               var parameter = parameters [i];
+                               if (parameter == null)
+                                       throw new ArgumentNullException ("parameters");
+
+                               if (!CanAssign (parameter.Type, invoke_parameters [i].ParameterType))
+                                       throw new ArgumentException (String.Format ("Can not assign a {0} to a {1}", invoke_parameters [i].ParameterType, parameter.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));
+                       if (invoke.ReturnType != typeof (void)) {
+                               if (!CanAssign (invoke.ReturnType, body.Type)) {
+                                       if (invoke.ReturnType.IsExpression ())
+                                               return Expression.Quote (body);
+
+                                       throw new ArgumentException (String.Format ("body type {0} can not be assigned to {1}", body.Type, invoke.ReturnType));
+                               }
+                       }
+                       return body;
                }
 
                public static Expression<TDelegate> Lambda<TDelegate> (Expression body, params ParameterExpression [] parameters)
@@ -1396,7 +1532,7 @@ namespace System.Linq.Expressions {
 
                        var ps = parameters.ToReadOnlyCollection ();
 
-                       CheckLambda (typeof (TDelegate), body, ps);
+                       body = CheckLambda (typeof (TDelegate), body, ps);
 
                        return new Expression<TDelegate> (body, ps);
                }
@@ -1434,9 +1570,8 @@ namespace System.Linq.Expressions {
 
                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);
+                       return (LambdaExpression) typeof (Expression<>).MakeGenericType (type).GetConstructor (
+                               NonPublicInstance, null, new [] { typeof (Expression), typeof (ReadOnlyCollection<ParameterExpression>) }, null).Invoke (new object [] { body, parameters } );
                }
 
                public static LambdaExpression Lambda (Type delegateType, Expression body, IEnumerable<ParameterExpression> parameters)
@@ -1448,7 +1583,7 @@ namespace System.Linq.Expressions {
 
                        var ps = parameters.ToReadOnlyCollection ();
 
-                       CheckLambda (delegateType, body, ps);
+                       body = CheckLambda (delegateType, body, ps);
 
                        return CreateExpressionOf (delegateType, body, ps);
                }
@@ -1578,7 +1713,7 @@ namespace System.Linq.Expressions {
                        var inits = CheckListInit (newExpression, initializers);
 
                        if (addMethod != null) {
-                               if (addMethod.Name.ToLowerInvariant () != "add")
+                               if (addMethod.Name.ToLower (CultureInfo.InvariantCulture) != "add")
                                        throw new ArgumentException ("addMethod");
 
                                var parameters = addMethod.GetParameters ();
@@ -1734,7 +1869,7 @@ namespace System.Linq.Expressions {
                {
                        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)
@@ -1777,15 +1912,30 @@ namespace System.Linq.Expressions {
                        if (constructor == null)
                                throw new ArgumentNullException ("constructor");
 
-                       var args = arguments.ToReadOnlyCollection ();
-
-                       CheckMethodArguments (constructor, args);
+                       var args = CheckMethodArguments (constructor, arguments);
 
                        return new NewExpression (constructor, args, null);
                }
 
-               static void CheckMethodArguments (MethodBase method, ReadOnlyCollection<Expression> arguments)
+               static IList<Expression> CreateArgumentList (IEnumerable<Expression> arguments)
                {
+                       if (arguments == null)
+                               return arguments.ToReadOnlyCollection ();
+
+                       return arguments.ToList ();
+               }
+
+               static void CheckNonGenericMethod (MethodBase method)
+               {
+                       if (method.IsGenericMethodDefinition || method.ContainsGenericParameters)
+                               throw new ArgumentException ("Can not used open generic methods");
+               }
+
+               static ReadOnlyCollection<Expression> CheckMethodArguments (MethodBase method, IEnumerable<Expression> args)
+               {
+                       CheckNonGenericMethod (method);
+
+                       var arguments = CreateArgumentList (args);
                        var parameters = method.GetParameters ();
 
                        if (arguments.Count != parameters.Length)
@@ -1795,9 +1945,15 @@ namespace System.Linq.Expressions {
                                if (arguments [i] == null)
                                        throw new ArgumentNullException ("arguments");
 
-                               if (!IsAssignableToParameterType (arguments [i].Type, parameters [i]))
-                                       throw new ArgumentException ("arguments");
+                               if (!IsAssignableToParameterType (arguments [i].Type, parameters [i])) {
+                                       if (!parameters [i].ParameterType.IsExpression ())
+                                               throw new ArgumentException ("arguments");
+
+                                       arguments [i] = Expression.Quote (arguments [i]);
+                               }
                        }
+
+                       return arguments.ToReadOnlyCollection ();
                }
 
                public static NewExpression New (ConstructorInfo constructor, IEnumerable<Expression> arguments, params MemberInfo [] members)
@@ -1816,7 +1972,7 @@ namespace System.Linq.Expressions {
                        CheckForNull (args, "arguments");
                        CheckForNull (mmbs, "members");
 
-                       CheckMethodArguments (constructor, args);
+                       args = CheckMethodArguments (constructor, arguments);
 
                        if (args.Count != mmbs.Count)
                                throw new ArgumentException ("Arguments count does not match members count");
@@ -1892,7 +2048,8 @@ namespace System.Linq.Expressions {
                                        throw new ArgumentNullException ("initializers");
 
                                if (!expression.Type.IsAssignableTo (type))
-                                       throw new InvalidOperationException ();
+                                       throw new InvalidOperationException (
+                                               string.Format ("{0} IsAssignableTo {1}, expression [ {2} ] : {3}", expression.Type, type, expression.NodeType, expression));
 
                                // TODO: Quote elements if type == typeof (Expression)
                        }
@@ -1938,12 +2095,19 @@ namespace System.Linq.Expressions {
                        if (propertyAccessor == null)
                                throw new ArgumentNullException ("propertyAccessor");
 
+                       CheckNonGenericMethod (propertyAccessor);
+
                        if (!propertyAccessor.IsStatic) {
                                if (expression == null)
                                        throw new ArgumentNullException ("expression");
                                if (!expression.Type.IsAssignableTo (propertyAccessor.DeclaringType))
                                        throw new ArgumentException ("expression");
                        }
+                       //
+                       // .NET does not mandate that if the property is static, that the expression must be null
+                       // fixes a bug exposed by Orchard's ContentItemRecordAlteration.Alteration
+                       // else if (expression != null)
+                       //              throw new ArgumentException ("expression");
 
                        var prop = GetAssociatedProperty (propertyAccessor);
                        if (prop == null)
@@ -1954,10 +2118,13 @@ namespace System.Linq.Expressions {
 
                static PropertyInfo GetAssociatedProperty (MethodInfo method)
                {
+                       if (method == null)
+                               return null;
+
                        foreach (var prop in method.DeclaringType.GetProperties (All)) {
-                               if (prop.GetGetMethod (true) == method)
+                               if (method.Equals (prop.GetGetMethod (true)))
                                        return prop;
-                               if (prop.GetSetMethod (true) ==  method)
+                               if (method.Equals (prop.GetSetMethod (true)))
                                        return prop;
                        }
 
@@ -1978,7 +2145,8 @@ namespace System.Linq.Expressions {
                                        throw new ArgumentNullException ("expression");
                                if (!expression.Type.IsAssignableTo (property.DeclaringType))
                                        throw new ArgumentException ("expression");
-                       }
+                       } else if (expression != null)
+                               throw new ArgumentException ("expression");
 
                        return new MemberExpression (expression, property, property.PropertyType);
                }
@@ -2027,7 +2195,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);
@@ -2075,12 +2243,7 @@ namespace System.Linq.Expressions {
                        if (IsInt (t))
                                return true;
 
-                       return t == typeof (float) || t == typeof (double) || t == typeof (decimal);
-               }
-
-               internal static bool IsNullable (Type type)
-               {
-                       return type.IsGenericType && type.GetGenericTypeDefinition () == typeof (Nullable<>);
+                       return t == typeof (float) || t == typeof (double);
                }
 
                static bool IsSignedNumber (Type t)
@@ -2101,26 +2264,15 @@ namespace System.Linq.Expressions {
                                t == typeof (byte);
                }
 
-               //
-               // returns the T in a a Nullable<T> type.
-               //
-               internal static Type GetNullableOf (Type type)
-               {
-                       return type.GetFirstGenericArgument ();
-               }
-
-               internal static Type GetNotNullableOf (Type type)
-               {
-                       return IsNullable (type) ? GetNullableOf (type) : type;
-               }
-
                //
                // This method must be overwritten by derived classes to
                // compile the expression
                //
+#if !FULL_AOT_RUNTIME
                internal virtual void Emit (EmitContext ec)
                {
-                       throw new NotImplementedException ();
+                       throw new NotImplementedException (String.Format ("Emit method is not implemented in expression type {0}", GetType ()));
                }
+#endif
        }
 }