From 0c9e4b9bfc1f39c7f75da609afae8013b33a20f7 Mon Sep 17 00:00:00 2001 From: metoule Date: Sat, 6 Sep 2025 15:51:29 +0200 Subject: [PATCH] Fix 367: generate proper expression for null-coalescing operators on nullable types --- src/DynamicExpresso.Core/Parsing/Parser.cs | 21 ++++++++++++++++++- test/DynamicExpresso.UnitTest/GithubIssues.cs | 10 +++++++++ 2 files changed, 30 insertions(+), 1 deletion(-) diff --git a/src/DynamicExpresso.Core/Parsing/Parser.cs b/src/DynamicExpresso.Core/Parsing/Parser.cs index c43264e..faa0445 100644 --- a/src/DynamicExpresso.Core/Parsing/Parser.cs +++ b/src/DynamicExpresso.Core/Parsing/Parser.cs @@ -249,7 +249,16 @@ private Expression ParseConditional() { NextToken(); var exprRight = ParseExpressionSegment(); - expr = GenerateConditional(GenerateEqual(expr, ParserConstants.NullLiteralExpression), exprRight, expr, errorPos); + if (TypeUtils.IsNullableType(expr.Type)) + { + // expr.HasValue ? expr.Value : exprRight + expr = GenerateConditional(GenerateGetNullableHasValue(expr), GenerateGetNullableValue(expr), exprRight, errorPos); + } + else + { + // expr == null ? exprRight : expr + expr = GenerateConditional(GenerateEqual(expr, ParserConstants.NullLiteralExpression), exprRight, expr, errorPos); + } } else if (_token.id == TokenId.Question) { @@ -734,6 +743,16 @@ private Expression ParsePrimary() return expr; } + /// + /// Generate a call to the HasValue property of the Nullable type */ + /// + private Expression GenerateGetNullableHasValue(Expression expr) + { + if (!TypeUtils.IsNullableType(expr.Type)) + return expr; + return GeneratePropertyOrFieldExpression(expr.Type, expr, _token.pos, "HasValue"); + } + /// /// Generate a call to the Value property of the Nullable type */ /// diff --git a/test/DynamicExpresso.UnitTest/GithubIssues.cs b/test/DynamicExpresso.UnitTest/GithubIssues.cs index ea32bab..ed4997c 100644 --- a/test/DynamicExpresso.UnitTest/GithubIssues.cs +++ b/test/DynamicExpresso.UnitTest/GithubIssues.cs @@ -891,6 +891,16 @@ public void GitHub_Issue_354() Assert.That(interpreter.Eval("b.ReturnsGuid()"), Is.EqualTo(Guid.Empty)); } + + [Test] + public void GitHub_Issue_367() + { + var interpreter = new DynamicExpresso.Interpreter(); + interpreter.SetVariable("MyValue", null, typeof(int?)); + + var result = interpreter.Eval("MyValue ?? 10"); + Assert.That(result, Is.EqualTo(10)); + } } internal static class GithubIssuesTestExtensionsMethods