Skip to content

Commit

Permalink
managed TypeConversion.ImplicitConversion on GetBinaryOperator to det…
Browse files Browse the repository at this point in the history
…ect the common type of two expressions.

Now can use a expression P1 / P2 where P1 : double and P2: nullable<decimal>
  • Loading branch information
davideciarmiello committed Dec 7, 2016
1 parent 0607ded commit 076e605
Show file tree
Hide file tree
Showing 3 changed files with 56 additions and 16 deletions.
7 changes: 2 additions & 5 deletions ExpressionEvaluator/Parser/ExpressionHelper.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
60 changes: 49 additions & 11 deletions ExpressionEvaluator/Parser/TypeConversion.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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);
}
}

/// <summary>
/// Performs implicit conversion on an expression against a specified type
/// </summary>
Expand Down Expand Up @@ -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) ||
Expand All @@ -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)
{
Expand All @@ -283,44 +318,44 @@ 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))
{
if (value >= Byte.MinValue && value <= Byte.MaxValue)
{
src = Expression.Convert(src, typeof(byte));
return true;
return true;
}
}
if (destType == typeof(short))
{
if (value >= Int16.MinValue && value <= Int16.MaxValue)
{
src = Expression.Convert(src, typeof(short));
return true;
return true;
}
}
if (destType == typeof(ushort))
{
if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
{
src = Expression.Convert(src, typeof(ushort));
return true;
return true;
}
}
if (destType == typeof(uint))
{
if (value >= UInt32.MinValue && value <= UInt32.MaxValue)
{
src = Expression.Convert(src, typeof(uint));
return true;
return true;
}
}
if (destType == typeof(ulong))
Expand Down Expand Up @@ -390,9 +425,9 @@ public static bool DynamicConversion(ref Expression src, Type destType)
public static bool ImplicitNumericConversion(ref Expression src, Type target)
{
List<Type> 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;
Expand All @@ -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<Type>() { typeof(short), typeof(int), typeof(long), typeof(float), typeof(double), typeof(decimal) });
Expand All @@ -426,6 +462,8 @@ public static bool ImplicitNumericConversion(ref Expression src, Type target)
ImplicitNumericConversions.Add(typeof(ulong), new List<Type>() { typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(char), new List<Type>() { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(float), new List<Type>() { typeof(double) });
ImplicitNumericConversions.Add(typeof(double), new List<Type>() { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(decimal) });
ImplicitNumericConversions.Add(typeof(decimal), new List<Type>() { typeof(ushort), typeof(int), typeof(uint), typeof(long), typeof(ulong), typeof(float), typeof(double) });
}
}
}
5 changes: 5 additions & 0 deletions ExpressionEvaluator/Parser/TypeExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -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)) ||
Expand Down

0 comments on commit 076e605

Please sign in to comment.