From 188e4557c140d5e37f90bc1bc6defce6846b5385 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 06:52:44 +0000 Subject: [PATCH 1/4] Initial plan From 553ade5f881d0820b9fd254c21b0868994f930a7 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 07:06:25 +0000 Subject: [PATCH 2/4] Fix CSharp output: add discard '_ = ' for non-void calls/invocations in if-block bodies Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/29dfe7a7-ddfe-48ea-be43-eafbc23b9e5c Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com> --- .../FastExpressionCompiler.cs | 15 +++++++++++---- ...gen_for_comparison_of_nullable_type_to_null.cs | 2 ++ 2 files changed, 13 insertions(+), 4 deletions(-) diff --git a/src/FastExpressionCompiler/FastExpressionCompiler.cs b/src/FastExpressionCompiler/FastExpressionCompiler.cs index 24caf5dd..60ba9a9a 100644 --- a/src/FastExpressionCompiler/FastExpressionCompiler.cs +++ b/src/FastExpressionCompiler/FastExpressionCompiler.cs @@ -10927,6 +10927,12 @@ private static StringBuilder ToCSharpBlock(this Expression expr, StringBuilder s else { sb.NewLineIndent(lineIndent + indentSpaces); + var nodeType = expr?.NodeType ?? ExpressionType.Default; + var needsDiscard = expr != null && expr.Type != typeof(void) + && (nodeType == ExpressionType.Call | nodeType == ExpressionType.Invoke + | nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce); + if (needsDiscard) // it requires some assignment target to avoid error or warning + sb.Append("_ = "); sb = expr?.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref ctx, lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode) ?? sb.Append("null"); sb.AppendSemicolonOnce(expr); @@ -11149,9 +11155,10 @@ private static StringBuilder BlockToCSharpString(this BlockExpression b, StringB { sb.NewLineIndent(lineIndent); var nodeType = expr.NodeType; - var returningCondOrCoalesce = expr.Type != typeof(void) - && nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce; - if (returningCondOrCoalesce) // it requires some assignment target to avoid error or warning + var returningCondOrCoalesceOrCall = expr.Type != typeof(void) + && (nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce + | nodeType == ExpressionType.Call | nodeType == ExpressionType.Invoke); + if (returningCondOrCoalesceOrCall) // it requires some assignment target to avoid error or warning sb.Append("_ = "); expr.ToCSharpString(sb, EnclosedIn.Block, ref ctx, @@ -11160,7 +11167,7 @@ private static StringBuilder BlockToCSharpString(this BlockExpression b, StringB // Preventing the `};` kind of situation and separating the conditional block with empty line if (nodeType.IsBlockLikeOrConditional()) { - sb = returningCondOrCoalesce ? sb.AppendSemicolonOnce() : sb; + sb = returningCondOrCoalesceOrCall ? sb.AppendSemicolonOnce() : sb; sb.NewLineIndent(lineIndent); } else if (nodeType != ExpressionType.Label & nodeType != ExpressionType.Default) diff --git a/test/FastExpressionCompiler.IssueTests/Issue252_Bad_code_gen_for_comparison_of_nullable_type_to_null.cs b/test/FastExpressionCompiler.IssueTests/Issue252_Bad_code_gen_for_comparison_of_nullable_type_to_null.cs index 3bb70e7a..a46963b2 100644 --- a/test/FastExpressionCompiler.IssueTests/Issue252_Bad_code_gen_for_comparison_of_nullable_type_to_null.cs +++ b/test/FastExpressionCompiler.IssueTests/Issue252_Bad_code_gen_for_comparison_of_nullable_type_to_null.cs @@ -53,6 +53,8 @@ public void Equal_in_void_Handler_should_work() var expr = Lambda(callIfNotNull, parameterExpr); expr.PrintCSharp(); + Asserts.Contains("_ = ((int?)null).ToString();", expr.ToCSharpString()); + var fs = expr.CompileSys(); fs.PrintIL(); From f973bd3168684cb0dd48f6d77a686cf1b8d8607d Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 07:56:18 +0000 Subject: [PATCH 3/4] Refactor: extract NeedsDiscardWhenUsedAsStatement helper to unify nodeType checks Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/300f0816-a25b-4415-9b93-9e8044d8b0b0 Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com> --- .../FastExpressionCompiler.cs | 20 ++++++++++++------- 1 file changed, 13 insertions(+), 7 deletions(-) diff --git a/src/FastExpressionCompiler/FastExpressionCompiler.cs b/src/FastExpressionCompiler/FastExpressionCompiler.cs index 60ba9a9a..30a30d0e 100644 --- a/src/FastExpressionCompiler/FastExpressionCompiler.cs +++ b/src/FastExpressionCompiler/FastExpressionCompiler.cs @@ -8235,6 +8235,17 @@ internal static bool IsBlockLikeOrConditional(this ExpressionType nodeType) => nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce || IsBracedBlockLike(nodeType); + // Returns true when a non-void expression used as a statement needs a `_ = ` discard prefix + // to suppress CS0201 / produce valid, unambiguous C# output. + [MethodImpl((MethodImplOptions)256)] + internal static bool NeedsDiscardWhenUsedAsStatement(this Expression expr) + { + var nodeType = expr.NodeType; + return expr.Type != typeof(void) + && (nodeType == ExpressionType.Call | nodeType == ExpressionType.Invoke + | nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce); + } + [MethodImpl((MethodImplOptions)256)] internal static bool IsReturnable(this Expression expr) { @@ -10927,10 +10938,7 @@ private static StringBuilder ToCSharpBlock(this Expression expr, StringBuilder s else { sb.NewLineIndent(lineIndent + indentSpaces); - var nodeType = expr?.NodeType ?? ExpressionType.Default; - var needsDiscard = expr != null && expr.Type != typeof(void) - && (nodeType == ExpressionType.Call | nodeType == ExpressionType.Invoke - | nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce); + var needsDiscard = expr != null && expr.NeedsDiscardWhenUsedAsStatement(); if (needsDiscard) // it requires some assignment target to avoid error or warning sb.Append("_ = "); sb = expr?.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref ctx, @@ -11155,9 +11163,7 @@ private static StringBuilder BlockToCSharpString(this BlockExpression b, StringB { sb.NewLineIndent(lineIndent); var nodeType = expr.NodeType; - var returningCondOrCoalesceOrCall = expr.Type != typeof(void) - && (nodeType == ExpressionType.Conditional | nodeType == ExpressionType.Coalesce - | nodeType == ExpressionType.Call | nodeType == ExpressionType.Invoke); + var returningCondOrCoalesceOrCall = expr.NeedsDiscardWhenUsedAsStatement(); if (returningCondOrCoalesceOrCall) // it requires some assignment target to avoid error or warning sb.Append("_ = "); From 4a54b458100fcdbced7eda579aae0c934f946a75 Mon Sep 17 00:00:00 2001 From: "copilot-swe-agent[bot]" <198982749+Copilot@users.noreply.github.com> Date: Sun, 12 Apr 2026 08:46:43 +0000 Subject: [PATCH 4/4] Simplify discard call sites: inline single-use bool vars, remove redundant comments Agent-Logs-Url: https://github.com/dadhi/FastExpressionCompiler/sessions/efa537b8-0c0e-4172-9ba3-1401feacbf6a Co-authored-by: dadhi <39516+dadhi@users.noreply.github.com> --- src/FastExpressionCompiler/FastExpressionCompiler.cs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/src/FastExpressionCompiler/FastExpressionCompiler.cs b/src/FastExpressionCompiler/FastExpressionCompiler.cs index 30a30d0e..8b3c5013 100644 --- a/src/FastExpressionCompiler/FastExpressionCompiler.cs +++ b/src/FastExpressionCompiler/FastExpressionCompiler.cs @@ -10938,8 +10938,7 @@ private static StringBuilder ToCSharpBlock(this Expression expr, StringBuilder s else { sb.NewLineIndent(lineIndent + indentSpaces); - var needsDiscard = expr != null && expr.NeedsDiscardWhenUsedAsStatement(); - if (needsDiscard) // it requires some assignment target to avoid error or warning + if (expr != null && expr.NeedsDiscardWhenUsedAsStatement()) sb.Append("_ = "); sb = expr?.ToCSharpString(sb, EnclosedIn.ParensByDefault, ref ctx, lineIndent + indentSpaces, stripNamespace, printType, indentSpaces, notRecognizedToCode) ?? sb.Append("null"); @@ -11164,7 +11163,7 @@ private static StringBuilder BlockToCSharpString(this BlockExpression b, StringB sb.NewLineIndent(lineIndent); var nodeType = expr.NodeType; var returningCondOrCoalesceOrCall = expr.NeedsDiscardWhenUsedAsStatement(); - if (returningCondOrCoalesceOrCall) // it requires some assignment target to avoid error or warning + if (returningCondOrCoalesceOrCall) sb.Append("_ = "); expr.ToCSharpString(sb, EnclosedIn.Block, ref ctx,