diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index eb61acd..8e1d3f3 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -228,7 +228,7 @@ private Expression ParseAssignment() NextToken(); var right = ParseAssignment(); - var promoted = ExpressionUtils.PromoteExpression(right, left.Type, true); + var promoted = ExpressionUtils.PromoteExpression(right, left.Type); if (promoted == null) throw ParseException.Create(_token.pos, ErrorMessages.CannotConvertValue, TypeUtils.GetTypeName(right.Type), TypeUtils.GetTypeName(left.Type)); @@ -336,8 +336,8 @@ private Expression ParseComparison() { var left = ParseTypeTesting(); while (_token.id == TokenId.DoubleEqual || _token.id == TokenId.ExclamationEqual || - _token.id == TokenId.GreaterThan || _token.id == TokenId.GreaterThanEqual || - _token.id == TokenId.LessThan || _token.id == TokenId.LessThanEqual) + _token.id == TokenId.GreaterThan || _token.id == TokenId.GreaterThanEqual || + _token.id == TokenId.LessThan || _token.id == TokenId.LessThanEqual) { var op = _token; NextToken(); @@ -424,7 +424,7 @@ private Expression ParseTypeTesting() { var left = ParseShift(); while (_token.text == ParserConstants.KeywordIs - || _token.text == ParserConstants.KeywordAs) + || _token.text == ParserConstants.KeywordAs) { var typeOperator = _token.text; @@ -523,7 +523,7 @@ private Expression ParseMultiplicative() { var left = ParseUnary(); while (_token.id == TokenId.Asterisk || _token.id == TokenId.Slash || - _token.id == TokenId.Percent) + _token.id == TokenId.Percent) { var op = _token; NextToken(); @@ -1053,7 +1053,7 @@ private Expression ParseIdentifier() return ParseMemberAccess(thisParameterExpression); } } - catch(ParseException) + catch (ParseException) { // ignore } @@ -1116,14 +1116,14 @@ private Expression ParseDefaultOperator() private Expression GenerateConditional(Expression test, Expression expr1, Expression expr2, int errorPos) { if (IsDynamicExpression(test)) - return GenerateConditionalDynamic(test, expr1, expr2,errorPos); + return GenerateConditionalDynamic(test, expr1, expr2, errorPos); if (test.Type != typeof(bool)) throw ParseException.Create(errorPos, ErrorMessages.FirstExprMustBeBool); if (expr1.Type != expr2.Type) { - var expr1As2 = expr2 != ParserConstants.NullLiteralExpression ? ExpressionUtils.PromoteExpression(expr1, expr2.Type, true) : null; - var expr2As1 = expr1 != ParserConstants.NullLiteralExpression ? ExpressionUtils.PromoteExpression(expr2, expr1.Type, true) : null; + var expr1As2 = expr2 != ParserConstants.NullLiteralExpression ? ExpressionUtils.PromoteExpression(expr1, expr2.Type) : null; + var expr2As1 = expr1 != ParserConstants.NullLiteralExpression ? ExpressionUtils.PromoteExpression(expr2, expr1.Type) : null; if (expr1As2 != null && expr2As1 == null) { expr1 = expr1As2; @@ -1838,7 +1838,7 @@ private Expression ParseElementAccess(Expression expr) for (int i = 0; i < args.Length; i++) { - args[i] = ExpressionUtils.PromoteExpression(args[i], typeof(int), true); + args[i] = ExpressionUtils.PromoteExpression(args[i], typeof(int)); if (args[i] == null) throw ParseException.Create(errorPos, ErrorMessages.InvalidIndex); } @@ -1959,8 +1959,6 @@ private Expression GenerateGreaterThan(Expression left, Expression right) return GenerateBinary(ExpressionType.GreaterThan, left, right); } - - private Expression GenerateGreaterThanEqual(Expression left, Expression right) { if (left.Type == typeof(string)) diff --git a/src/DynamicExpresso.Core/Resolution/ExpressionUtils.cs b/src/DynamicExpresso.Core/Resolution/ExpressionUtils.cs index c640ff2..5acf98b 100644 --- a/src/DynamicExpresso.Core/Resolution/ExpressionUtils.cs +++ b/src/DynamicExpresso.Core/Resolution/ExpressionUtils.cs @@ -7,19 +7,15 @@ namespace DynamicExpresso.Resolution { internal static class ExpressionUtils { - public static Expression PromoteExpression(Expression expr, Type type, bool exact) + public static Expression PromoteExpression(Expression expr, Type type) { if (expr.Type == type) return expr; - if (expr is ConstantExpression) + if (expr is ConstantExpression ce && ce == ParserConstants.NullLiteralExpression) { - var ce = (ConstantExpression)expr; - if (ce == ParserConstants.NullLiteralExpression) - { - if (type.ContainsGenericParameters) - return null; - if (!type.IsValueType || TypeUtils.IsNullableType(type)) - return Expression.Constant(null, type); - } + if (type.ContainsGenericParameters) + return null; + if (!type.IsValueType || TypeUtils.IsNullableType(type)) + return Expression.Constant(null, type); } if (expr is InterpreterExpression ie) @@ -40,13 +36,9 @@ public static Expression PromoteExpression(Expression expr, Type type, bool exac return Expression.Convert(expr, genericType); } - if (TypeUtils.IsCompatibleWith(expr.Type, type) || expr is DynamicExpression) + if (TypeUtils.IsCompatibleWith(expr.Type, type)) { - if (type.IsValueType || exact) - { - return Expression.Convert(expr, type); - } - return expr; + return Expression.Convert(expr, type); } return null; diff --git a/src/DynamicExpresso.Core/Resolution/MethodResolution.cs b/src/DynamicExpresso.Core/Resolution/MethodResolution.cs index 3d99d81..acc19ed 100644 --- a/src/DynamicExpresso.Core/Resolution/MethodResolution.cs +++ b/src/DynamicExpresso.Core/Resolution/MethodResolution.cs @@ -1,10 +1,9 @@ using System; using System.Collections.Generic; -using System.Linq.Expressions; using System.Linq; +using System.Linq.Expressions; using System.Reflection; using System.Security; -using System.Text; using DynamicExpresso.Exceptions; using DynamicExpresso.Parsing; using DynamicExpresso.Reflection; @@ -93,7 +92,7 @@ public static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expr continue; } - var promoted = ExpressionUtils.PromoteExpression(currentArgument, parameterType, true); + var promoted = ExpressionUtils.PromoteExpression(currentArgument, parameterType); if (promoted != null) { promotedArgs.Add(promoted); @@ -111,7 +110,7 @@ public static bool CheckIfMethodIsApplicableAndPrepareIt(MethodData method, Expr continue; } - var promoted = ExpressionUtils.PromoteExpression(currentArgument, paramsArrayElementType, true); + var promoted = ExpressionUtils.PromoteExpression(currentArgument, paramsArrayElementType); if (promoted != null) { paramsArrayPromotedArgument = paramsArrayPromotedArgument ?? new List(); diff --git a/test/DynamicExpresso.UnitTest/GithubIssues.cs b/test/DynamicExpresso.UnitTest/GithubIssues.cs index bb0f544..82e03ee 100644 --- a/test/DynamicExpresso.UnitTest/GithubIssues.cs +++ b/test/DynamicExpresso.UnitTest/GithubIssues.cs @@ -1,12 +1,12 @@ -using DynamicExpresso.Exceptions; -using NUnit.Framework; using System; using System.Collections; using System.Collections.Generic; +using System.Dynamic; using System.Linq; using System.Reflection; using System.Text.RegularExpressions; -using System.Dynamic; +using DynamicExpresso.Exceptions; +using NUnit.Framework; // ReSharper disable SpecifyACultureInStringConversionExplicitly @@ -775,7 +775,9 @@ public void GitHub_Issue_292() } [Test] - public void GitHub_Issue_295() { + [Ignore("The fix suggested in #296 break other use cases, so let's ignore this test for now")] + public void GitHub_Issue_295() + { var evaluator = new Interpreter(); // create path helper functions in expressions... @@ -787,10 +789,10 @@ public void GitHub_Issue_295() { globalSettings.MyTestPath = "C:\\delme\\"; evaluator.SetVariable("GlobalSettings", globalSettings); - var works = (string) evaluator.Eval("StringConcat((string)GlobalSettings.MyTestPath,\"test.txt\")"); + var works = (string)evaluator.Eval("StringConcat((string)GlobalSettings.MyTestPath,\"test.txt\")"); Assert.That(works, Is.EqualTo("C:\\delme\\test.txt")); - var doesntWork = (string) evaluator.Eval("StringConcat(GlobalSettings.MyTestPath,\"test.txt\")"); + var doesntWork = (string)evaluator.Eval("StringConcat(GlobalSettings.MyTestPath,\"test.txt\")"); Assert.That(doesntWork, Is.EqualTo("C:\\delme\\test.txt")); } @@ -848,6 +850,21 @@ public void GitHub_Issue_314() var exception2 = Assert.Throws(() => interpreter.Eval("b > 1")); Assert.AreEqual("b", exception2.Identifier); } + + [Test] + public void GitHub_Issue_325() + { + var options = InterpreterOptions.Default | InterpreterOptions.LateBindObject; + var interpreter = new Interpreter(options); + + var input = new + { + Prop1 = 4, + }; + + var expressionDelegate = interpreter.ParseAsDelegate>($"input.Prop1 == null", "input"); + Assert.IsFalse(expressionDelegate(input)); + } } internal static class GithubIssuesTestExtensionsMethods