From 4ab0cc3776da329b9c89af801168e1db010b3376 Mon Sep 17 00:00:00 2001 From: Siegfried Pammer Date: Mon, 20 Jul 2026 18:44:33 +0200 Subject: [PATCH] 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 --- .../IL/Transforms/ReduceNestingTransform.cs | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) diff --git a/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs b/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs index 66f431809e..21ec3becd7 100644 --- a/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs +++ b/ICSharpCode.Decompiler/IL/Transforms/ReduceNestingTransform.cs @@ -254,7 +254,9 @@ private bool ReduceNesting(Block block, IfInstruction ifInst, ILInstruction exit 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 @@ private void ComputeStats(ILInstruction inst, ref int numStatements, ref int max /// /// 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 /// - /// The instruction heading the nested candidate block + /// The nested candidate block (an else or default block) /// The number of statements in the largest sibling block /// The relative depth of the most nested statement in the sibling blocks /// - 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