Browse Source

Fix #3891: don't reduce nesting when there is no else block

ReduceNesting walks an else-if chain to its innermost if and asks
ShouldReduceNesting whether to extract the else block, which ExtractElseBlock
does by casting the block to Block. A chain with no trailing else reaches this
with a bare Nop, yet the heuristic still approved it (its stats count a Nop as
one statement), so the cast threw InvalidCastException. Take a Block in
ShouldReduceNesting and skip the reduction at the call site when the else is
absent.

Assisted-by: Claude:claude-opus-4-8:Claude Code
pull/3901/head
Siegfried Pammer 2 months ago committed by Siegfried Pammer
parent
commit
6ba7d59cae
  1. 12
      ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs

12
ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs

@ -254,7 +254,9 @@ namespace ICSharpCode.Decompiler.IL @@ -254,7 +254,9 @@ namespace ICSharpCode.Decompiler.IL
ifInst = elseIfInst;
}
if (!ShouldReduceNesting(ifInst.FalseInst, maxStatements, maxDepth))
// A chain with no trailing else has no block to reduce: ifInst.FalseInst is a bare Nop.
// Guarding here keeps the else-block cast in ExtractElseBlock safe (#3891).
if (ifInst.FalseInst is not Block falseBlock || !ShouldReduceNesting(falseBlock, maxStatements, maxDepth))
return false;
// extract the else block and insert exit points all the way up the else-if tree
@ -582,16 +584,16 @@ namespace ICSharpCode.Decompiler.IL @@ -582,16 +584,16 @@ namespace ICSharpCode.Decompiler.IL
/// <summary>
/// Heuristic to determine whether it is worth duplicating exits into the preceeding sibling blocks (then/else-if/case)
/// in order to reduce the nesting of inst by 1
/// in order to reduce the nesting of block by 1
/// </summary>
/// <param name="inst">The instruction heading the nested candidate block</param>
/// <param name="block">The nested candidate block (an else or default block)</param>
/// <param name="maxStatements">The number of statements in the largest sibling block</param>
/// <param name="maxDepth">The relative depth of the most nested statement in the sibling blocks</param>
/// <returns></returns>
private bool ShouldReduceNesting(ILInstruction inst, int maxStatements, int maxDepth)
private bool ShouldReduceNesting(Block block, int maxStatements, int maxDepth)
{
int maxStatements2 = 0, maxDepth2 = 0;
UpdateStats(inst, ref maxStatements2, ref maxDepth2);
UpdateStats(block, ref maxStatements2, ref maxDepth2);
// if the max depth is 2, always reduce nesting (total depth 3 or more)
// if the max depth is 1, reduce nesting if this block is the largest
// otherwise reduce nesting only if this block is twice as large as any other

Loading…
Cancel
Save