From d1ae6dea0b477342fd0c452c7d0e4496c81c46b5 Mon Sep 17 00:00:00 2001 From: metoule Date: Sun, 19 Feb 2023 10:41:07 +0100 Subject: [PATCH] No longer promote generic types if their arguments aren't compatible --- src/DynamicExpresso.Core/Parsing/Parser.cs | 19 +++++++++++++++++-- test/DynamicExpresso.UnitTest/GithubIssues.cs | 9 +++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index 320afe9..a483c49 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -2452,7 +2452,7 @@ private static Expression PromoteExpression(Expression expr, Type type, bool exa if (type.IsGenericType && !IsNumericType(type)) { - var genericType = FindAssignableGenericType(expr.Type, type.GetGenericTypeDefinition()); + var genericType = FindAssignableGenericType(expr.Type, type); if (genericType != null) return Expression.Convert(expr, genericType); } @@ -2476,6 +2476,11 @@ private static bool IsCompatibleWith(Type source, Type target) return true; } + if (target.IsGenericParameter) + { + return true; + } + if (!target.IsValueType) { return target.IsAssignableFrom(source); @@ -2626,8 +2631,9 @@ private static bool IsWritable(Expression expression) } // from http://stackoverflow.com/a/1075059/209727 - private static Type FindAssignableGenericType(Type givenType, Type genericTypeDefinition) + private static Type FindAssignableGenericType(Type givenType, Type constructedGenericType) { + var genericTypeDefinition = constructedGenericType.GetGenericTypeDefinition(); var interfaceTypes = givenType.GetInterfaces(); foreach (var it in interfaceTypes) @@ -2639,7 +2645,16 @@ private static Type FindAssignableGenericType(Type givenType, Type genericTypeDe } if (givenType.IsGenericType && givenType.GetGenericTypeDefinition() == genericTypeDefinition) + { + // the given type has the same generic type of the fully constructed generic type + // => check if the generic arguments are compatible (e.g. Nullable and Nullable: int is not compatible with DateTime) + var givenTypeGenericsArgs = givenType.GenericTypeArguments; + var constructedGenericsArgs = constructedGenericType.GenericTypeArguments; + if (givenTypeGenericsArgs.Zip(constructedGenericsArgs, (g, c) => IsCompatibleWith(g, c)).Any(compatible => !compatible)) + return null; + return givenType; + } var baseType = givenType.BaseType; if (baseType == null) diff --git a/test/DynamicExpresso.UnitTest/GithubIssues.cs b/test/DynamicExpresso.UnitTest/GithubIssues.cs index acd48c1..efdcaf3 100644 --- a/test/DynamicExpresso.UnitTest/GithubIssues.cs +++ b/test/DynamicExpresso.UnitTest/GithubIssues.cs @@ -719,6 +719,15 @@ public void GitHub_Issue_263(string paramsArguments) var result = interpreter.Eval($"Utils.ParamArrayObjects({paramsArguments})"); Assert.AreEqual(4, result); } + + [Test] + public void GitHub_Issue_276() + { + var interpreter = new Interpreter(); + + var result = interpreter.Eval("((int?)5)>((double?)4)"); + Assert.IsTrue(result); + } } internal static class GithubIssuesTestExtensionsMethods