Skip to content

Collapse dual-constant guard-returns to the bare condition, not c && true#617

Merged
richlander merged 1 commit into
mainfrom
feature/decompiler-ternaries
Jun 18, 2026
Merged

Collapse dual-constant guard-returns to the bare condition, not c && true#617
richlander merged 1 commit into
mainfrom
feature/decompiler-ternaries

Conversation

@richlander

Copy link
Copy Markdown
Owner

What

FoldGuardReturn folds if (c) return A; return B; into a short-circuit boolean when either arm is a bool constant. When both arms are constants it still ran the generic formula, appending the then literal as a dead term:

  • BothPositive (if (a > 0) { if (b > 0) return true; } return false;) folded to return a > 0 && b > 0 && true;
  • the dual if (c) return false; return true; to return !c || false;

How

When the two arms are opposite bool constants, the condition itself is the result — if (c) return true; return false; is return c;, and the dual is return !c;. Special-case that ahead of the generic fold and reuse the (already detached) condition directly: no extra &&/|| term, and the condition is still evaluated, so the rewrite is sound even when it has side effects.

Equal-constant arms (the dead if (c) return true; return true;) fall through to the generic path; they do not arise in compiled code.

Soundness / scope

This is an output-fidelity fix. BothPositive already diverges from its fixture's nested-if-to-literal IL — an intentional, idiomatic boolean-fold over-render (the same policy that renders IsNullOrEmpty as return value is null || value.Length == 0;). It stays on the compile-back docket as before, but now renders the idiomatic return a > 0 && b > 0; instead of the noisy && true.

Numbers

  • Compile-back fixture counts unchanged: exact 157, docket 8, recompile-fail 537 (System.Linq unchanged).
  • Decompiler tests 440 to 441 (new BothPositive fold test).
  • Main suite 1140 green.

Found via the #604 --compile-back oracle while reviewing the ternary/branch-sense docket.

… true`

`FoldGuardReturn` rewrites `if (c) return A; return B;` into a short-circuit
boolean when either arm is a bool constant. When BOTH arms are constants it
still ran the generic `tail`-constant formula, appending the `then` literal as
a dead term: `if (a > 0) { if (b > 0) return true; } return false;` folded to
`return a > 0 && b > 0 && true;` (the `BothPositive` fixture), and the dual
`if (c) return false; return true;` to `return !c || false;`.

When the two arms are opposite bool constants the condition itself is the
result — `if (c) return true; return false;` is `return c;` and the dual is
`return !c;` — so special-case that ahead of the generic fold and reuse the
detached condition directly (no extra term, condition still evaluated, so
sound even if it has side effects). Equal-constant arms (dead `if (c) return
true; return true;`) are left to the generic path; they do not arise in
compiled code.

This is an output-fidelity fix: `BothPositive` already diverged from its
fixture's nested-if-to-literal IL (an intentional, idiomatic boolean-fold
over-render, like the IsNullOrEmpty corpus form), and stays on the compile-back
docket as before — but now renders the idiomatic `return a > 0 && b > 0;`
instead of the noisy `&& true`. Compile-back fixture counts unchanged
(exact 157, docket 8, recompile-fail 537; System.Linq unchanged). Decompiler
tests 440 -> 441; main suite 1140 green.

Co-authored-by: Copilot <223556219+Copilot@users.noreply.github.com>
@richlander richlander merged commit 201d9ef into main Jun 18, 2026
10 checks passed
@richlander richlander deleted the feature/decompiler-ternaries branch June 18, 2026 14:21
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant