diff --git a/ExpressionEvaluator/Parser/ExpressionHelper.cs b/ExpressionEvaluator/Parser/ExpressionHelper.cs index 6b0194a..1b7d4df 100644 --- a/ExpressionEvaluator/Parser/ExpressionHelper.cs +++ b/ExpressionEvaluator/Parser/ExpressionHelper.cs @@ -1061,11 +1061,8 @@ public static Expression BinaryOperator(Expression le, Expression re, Expression re = TypeConversion.EnumConversion(ref re); le = TypeConversion.EnumConversion(ref le); - var ret = re.Type; - var let = le.Type; - - TypeConversion.ImplicitConversion(ref le, ret); - TypeConversion.ImplicitConversion(ref re, let); + + TypeConversion.ImplicitConversion(ref le, ref re); //TypeConversion.BinaryNumericPromotion(expressionType, ref le, ref re); //le = TypeConversion.DynamicConversion(re, le); return GetBinaryOperator(le, re, expressionType); diff --git a/ExpressionEvaluator/Parser/TypeConversion.cs b/ExpressionEvaluator/Parser/TypeConversion.cs index 3e48e44..f636d02 100644 --- a/ExpressionEvaluator/Parser/TypeConversion.cs +++ b/ExpressionEvaluator/Parser/TypeConversion.cs @@ -137,7 +137,7 @@ internal static void Convert(ref Expression le, ref Expression re) if (Instance._typePrecedence[le.Type] < Instance._typePrecedence[re.Type]) le = Expression.Convert(le, re.Type); } } - + /// /// Performs implicit conversion on an expression against a specified type /// @@ -263,7 +263,7 @@ public static Expression EnumConversion(ref Expression src) public static bool ImplicitConversion(ref Expression src, Type destType) { return src.Type != destType && ( - (destType.IsNumericType() && src.Type.IsNumericType() && ImplicitNumericConversion(ref src, destType)) || + ImplicitNumericConversion(ref src, destType) || NullableConverion(ref src, destType) || NullLiteralConverion(ref src, destType) || ReferenceConversion(ref src, destType) || @@ -273,6 +273,41 @@ public static bool ImplicitConversion(ref Expression src, Type destType) ); } + public static void ImplicitConversion(ref Expression le, ref Expression re) + { + if (le.Type != re.Type) + { + var leType = le.Type.GetNotNullable(); + var reType = re.Type.GetNotNullable(); + Type maxCommonType = null; + if (leType == reType) //the only difference is the nullable + { + maxCommonType = typeof(Nullable<>).MakeGenericType(leType); + } + else if (Instance._typePrecedence.ContainsKey(leType) && Instance._typePrecedence.ContainsKey(reType)) + { + maxCommonType = Instance._typePrecedence[leType] < Instance._typePrecedence[reType] ? reType : leType; + if (le.Type.IsNullable() || re.Type.IsNullable()) + maxCommonType = typeof(Nullable<>).MakeGenericType(maxCommonType); + } + if (maxCommonType != null) + { + ImplicitConversion(ref le, maxCommonType); + ImplicitConversion(ref re, maxCommonType); + return; + } + if (le.Type.IsNullable() || re.Type.IsNullable()) + { + if (!le.Type.IsNullable()) + ImplicitConversion(ref le, typeof(Nullable<>).MakeGenericType(le.Type)); + if (!re.Type.IsNullable()) + ImplicitConversion(ref re, typeof(Nullable<>).MakeGenericType(re.Type)); + } + ImplicitConversion(ref le, re.Type); + ImplicitConversion(ref re, le.Type); + } + } + // 6.1.9 Implicit constant expression conversions public static bool ImplicitConstantConversion(ref Expression src, Type destType) { @@ -283,12 +318,12 @@ public static bool ImplicitConstantConversion(ref Expression src, Type destType) if (src.Type == typeof(int)) { var value = (int)((ConstantExpression)src).Value; - if (destType == typeof (sbyte)) + if (destType == typeof(sbyte)) { if (value >= SByte.MinValue && value <= SByte.MinValue) { src = Expression.Convert(src, typeof(sbyte)); - return true; + return true; } } if (destType == typeof(byte)) @@ -296,7 +331,7 @@ public static bool ImplicitConstantConversion(ref Expression src, Type destType) if (value >= Byte.MinValue && value <= Byte.MaxValue) { src = Expression.Convert(src, typeof(byte)); - return true; + return true; } } if (destType == typeof(short)) @@ -304,7 +339,7 @@ public static bool ImplicitConstantConversion(ref Expression src, Type destType) if (value >= Int16.MinValue && value <= Int16.MaxValue) { src = Expression.Convert(src, typeof(short)); - return true; + return true; } } if (destType == typeof(ushort)) @@ -312,7 +347,7 @@ public static bool ImplicitConstantConversion(ref Expression src, Type destType) if (value >= UInt16.MinValue && value <= UInt16.MaxValue) { src = Expression.Convert(src, typeof(ushort)); - return true; + return true; } } if (destType == typeof(uint)) @@ -320,7 +355,7 @@ public static bool ImplicitConstantConversion(ref Expression src, Type destType) if (value >= UInt32.MinValue && value <= UInt32.MaxValue) { src = Expression.Convert(src, typeof(uint)); - return true; + return true; } } if (destType == typeof(ulong)) @@ -390,9 +425,9 @@ public static bool DynamicConversion(ref Expression src, Type destType) public static bool ImplicitNumericConversion(ref Expression src, Type target) { List allowed; - if (ImplicitNumericConversions.TryGetValue(src.Type, out allowed)) + if (ImplicitNumericConversions.TryGetValue(src.Type.GetNotNullable(), out allowed)) { - if (allowed.Contains(target)) + if (allowed.Contains(target.GetNotNullable())) { src = Expression.Convert(src, target); return true; @@ -413,7 +448,8 @@ public static bool ImplicitNumericConversion(ref Expression src, Type target) {typeof (short), 4}, {typeof (long), 5}, {typeof (float), 6}, - {typeof (double), 7} + {typeof (double), 7}, + {typeof (decimal), 8} }; ImplicitNumericConversions.Add(typeof(sbyte), new List() { typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) }); @@ -426,6 +462,8 @@ public static bool ImplicitNumericConversion(ref Expression src, Type target) ImplicitNumericConversions.Add(typeof(ulong), new List() { typeof(float), typeof(double), typeof(decimal) }); ImplicitNumericConversions.Add(typeof(char), new List() { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) }); ImplicitNumericConversions.Add(typeof(float), new List() { typeof(double) }); + ImplicitNumericConversions.Add(typeof(double), new List() { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(decimal) }); + ImplicitNumericConversions.Add(typeof(decimal), new List() { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double) }); } } } \ No newline at end of file diff --git a/ExpressionEvaluator/Parser/TypeExtensions.cs b/ExpressionEvaluator/Parser/TypeExtensions.cs index c76859d..3161420 100644 --- a/ExpressionEvaluator/Parser/TypeExtensions.cs +++ b/ExpressionEvaluator/Parser/TypeExtensions.cs @@ -28,6 +28,11 @@ public static bool IsNumericType(this Type type) return NumericTypes.Contains(type); } + public static Type GetNotNullable(this Type type) + { + return Nullable.GetUnderlyingType(type) ?? type; + } + public static bool IsDynamicOrObject(this Type type) { return type.GetInterfaces().Contains(typeof(IDynamicMetaObjectProvider)) ||