#4135·ILSpy

Bool-to-int conditional is inlined into every use instead of kept in its local

Author: siegfriedpammerCreated Sep 13, 2026Updated Sep 14, 2026
LabelsDecompilerC#

Input code

csharp
public static byte ShiftTwice(byte frequency, bool scale)
{
    int n = (scale ? 1 : 0);
    return (byte)(frequency + n >> n);
}

Compiled with Roslyn, -o+, net8.0.

Erroneous output

Current master (dbf23c6e4) keeps the local:

csharp
public static byte ShiftTwice(byte frequency, bool scale)
{
    int num = (scale ? 1 : 0);
    return (byte)(frequency + num >> num);
}

With #4091 (6fcb387ff) the local is dropped and the conditional is printed once per use, plus an (int) cast on the other operand:

csharp
public static byte ShiftTwice(byte frequency, bool scale)
{
    return (byte)((int)frequency + (scale ? 1 : 0) >> (scale ? 1 : 0));
}

The output is still correct, it just repeats a subexpression the original code had factored out. A loop bound shows the same effect:

csharp
// input
int lo = (skipFirst ? 1 : 0);
int i = rules.Length - 1;
while (i >= lo && rules[i] == null)
    i--;

// with #4091
int num = rules.Length - 1;
while (num >= (skipFirst ? 1 : 0) && rules[num] == null)
    num--;

Real-world instances found by diffing #4091 against its merge base over the top-200 nuget.org packages: SharpCompress.Compressors.PPMd.I1.Model.Refresh (prints (scale ? 1 : 0) three times in one method) and Humanizer.Vocabulary.

Details

  • Product in use: ICSharpCode.Decompiler, built from source
  • Version in use: not reproducible on master (dbf23c6e4); introduced somewhere in #4091, measured at 6fcb387ff against merge base 712ad1aed

Filed by an AI agent (Claude) on Siegfried's behalf.