Skip to content

Commit 753f1d2

Browse files
Fix #1924: don't undo the compiler's &&-to-& optimization
ExpressionBuilder printed bitwise & / | on booleans as && / || whenever the right-hand side was pure, but Roslyn lowers && / || to & / | only when the right operand is a bare local or parameter read (LocalRewriter.MakeBinaryOperator, unchanged since 2014). Shapes like (c == 'a') | (c == 'b') can therefore only originate from a bitwise source operator, yet were shown as short-circuiting. Per the discussion in #1545, show the operator the IL actually uses instead of guessing the source form: the reversal is dropped entirely, so Roslyn-compiled "a && b" now decompiles to "a & b", which recompiles to the same IL. Assisted-by: Claude:claude-fable-5:Claude Code
1 parent 3a6b074 commit 753f1d2

3 files changed

Lines changed: 17 additions & 25 deletions

File tree

ICSharpCode.Decompiler.Tests/TestCases/Pretty/ShortCircuit.cs

Lines changed: 13 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -326,13 +326,21 @@ public void EmptyIf()
326326
}
327327
#endif
328328

329-
public void PreferLogicalToBitwise(bool a, bool b, int i, float f)
329+
public void BitwiseBooleanOperators(bool a, bool b, int i, float f)
330330
{
331-
B(a && b);
331+
B(a & b);
332+
B(a & (i == 1));
333+
B((i == 1) & a);
334+
B((i > i - 3) & a);
335+
B((f < 0.1f) & a);
336+
B(a | b);
332337
B(a && i == 1);
333-
B(i == 1 && a);
334-
B(i > i - 3 && a);
335-
B(f < 0.1f && a);
338+
B(a || i == 1);
339+
}
340+
341+
public bool BitwiseOrWithComparisons(char c)
342+
{
343+
return (c == 'a') | (c == 'b');
336344
}
337345
}
338346
}

ICSharpCode.Decompiler.Tests/TestCases/Pretty/Switch.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1282,7 +1282,7 @@ public static void SwitchLoopNesting()
12821282
#if ROSLYN || OPT
12831283
public static void SingleIf1(int i, bool a)
12841284
{
1285-
if (i == 1 || (i == 2 && a))
1285+
if (i == 1 || ((i == 2) & a))
12861286
{
12871287
Console.WriteLine(1);
12881288
}
@@ -1292,7 +1292,7 @@ public static void SingleIf1(int i, bool a)
12921292

12931293
public static void SingleIf2(int i, bool a, bool b)
12941294
{
1295-
if (i == 1 || (i == 2 && a) || (i == 3 && b))
1295+
if (i == 1 || ((i == 2) & a) || ((i == 3) & b))
12961296
{
12971297
Console.WriteLine(1);
12981298
}
@@ -1301,7 +1301,7 @@ public static void SingleIf2(int i, bool a, bool b)
13011301

13021302
public static void SingleIf3(int i, bool a, bool b)
13031303
{
1304-
if (a || i == 1 || (i == 2 && b))
1304+
if (a || i == 1 || ((i == 2) & b))
13051305
{
13061306
Console.WriteLine(1);
13071307
}
@@ -1310,7 +1310,7 @@ public static void SingleIf3(int i, bool a, bool b)
13101310

13111311
public static void SingleIf4(int i, bool a)
13121312
{
1313-
if (i == 1 || i == 2 || (i != 3 && a) || i != 4)
1313+
if (i == 1 || i == 2 || ((i != 3) & a) || i != 4)
13141314
{
13151315
Console.WriteLine(1);
13161316
}

ICSharpCode.Decompiler/CSharp/ExpressionBuilder.cs

Lines changed: 0 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1650,22 +1650,6 @@ TranslatedExpression HandleBinaryNumeric(BinaryNumericInstruction inst, BinaryOp
16501650
right.ResolveResult));
16511651
}
16521652
}
1653-
if (op.IsBitwise()
1654-
&& left.Type.IsKnownType(KnownTypeCode.Boolean)
1655-
&& right.Type.IsKnownType(KnownTypeCode.Boolean)
1656-
&& SemanticHelper.IsPure(inst.Right.Flags))
1657-
{
1658-
// Undo the C# compiler's optimization of "a && b" to "a & b".
1659-
if (op == BinaryOperatorType.BitwiseAnd)
1660-
{
1661-
op = BinaryOperatorType.ConditionalAnd;
1662-
}
1663-
else if (op == BinaryOperatorType.BitwiseOr)
1664-
{
1665-
op = BinaryOperatorType.ConditionalOr;
1666-
}
1667-
}
1668-
16691653
if (op.IsBitwise() && (left.Type.Kind == TypeKind.Enum || right.Type.Kind == TypeKind.Enum))
16701654
{
16711655
left = AdjustConstantExpressionToType(left, right.Type);

0 commit comments

Comments
 (0)