Skip to content

Commit ff29688

Browse files
Return an enum from the sequential store offset matcher
The bool-plus-out-abortTransform contract encoded three outcomes in two flags, so false meant either 'sequence ended' or 'reject the transform' depending on the flag. A three-value enum names each outcome at the return site, and passing minExpectedOffset by ref makes visible that only the binary.add path advances the expected offset (the bare ldloc path previously echoed it back through an out parameter). Assisted-by: Claude:claude-fable-5:Claude Code
1 parent 3bbc6d9 commit ff29688

1 file changed

Lines changed: 22 additions & 23 deletions

File tree

ICSharpCode.Decompiler/IL/Transforms/TransformArrayInitializers.cs

Lines changed: 22 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -462,13 +462,11 @@ unsafe bool HandleSequentialLocAllocInitializer(Block block, int pos, ILVariable
462462
{
463463
break;
464464
}
465-
if (!TryGetSequentialStoreOffset(target, store, elementType, minExpectedOffset, out var offset, out var abortTransform))
466-
{
467-
if (abortTransform)
468-
return false;
465+
var match = GetSequentialStoreOffset(target, store, elementType, ref minExpectedOffset);
466+
if (match == SequentialStoreMatch.Abort)
467+
return false;
468+
if (match != SequentialStoreMatch.Matched)
469469
break;
470-
}
471-
minExpectedOffset = offset;
472470
if (values == null)
473471
{
474472
var countInstruction = PointerArithmeticOffset.Detect(lengthInstruction, elementType, checkForOverflow: true);
@@ -529,34 +527,35 @@ void HandleLocAllocInitializerPrefix(Block block, ref int pos, ILVariable store,
529527
}
530528
}
531529

532-
static bool TryGetSequentialStoreOffset(ILInstruction target, ILVariable store, IType elementType, long minExpectedOffset, out long offset, out bool abortTransform)
530+
enum SequentialStoreMatch
533531
{
534-
offset = 0;
535-
abortTransform = false;
532+
// The store belongs to the initializer sequence.
533+
Matched,
534+
// The store is not part of the sequence; it ends the scan, keeping what was matched.
535+
SequenceEnd,
536+
// The store's shape is unexpected; reject the whole transform.
537+
Abort,
538+
}
536539

540+
static SequentialStoreMatch GetSequentialStoreOffset(ILInstruction target, ILVariable store, IType elementType, ref long minExpectedOffset)
541+
{
537542
// stobj T(ldloc store, value) writes at the current expected offset, initially 0.
538543
if (target.MatchLdLoc(store))
539-
{
540-
offset = minExpectedOffset;
541-
return true;
542-
}
544+
return SequentialStoreMatch.Matched;
543545

544546
// stobj T(binary.add(ldloc store, offset), value)
545547
// The offset is either sizeof(T) or an element index multiplied by sizeof(T).
546548
if (!target.MatchBinaryNumericInstruction(BinaryNumericOperator.Add, out var left, out var right))
547-
{
548-
abortTransform = true;
549-
return false;
550-
}
549+
return SequentialStoreMatch.Abort;
551550
if (!left.MatchLdLoc(store))
552-
return false;
551+
return SequentialStoreMatch.SequenceEnd;
553552
var offsetInst = PointerArithmeticOffset.Detect(right, elementType, ((BinaryNumericInstruction)target).CheckForOverflow);
554553
if (offsetInst == null)
555-
{
556-
abortTransform = true;
557-
return false;
558-
}
559-
return offsetInst.MatchLdcI(out offset) && offset >= 0 && offset >= minExpectedOffset;
554+
return SequentialStoreMatch.Abort;
555+
if (!offsetInst.MatchLdcI(out long offset) || offset < 0 || offset < minExpectedOffset)
556+
return SequentialStoreMatch.SequenceEnd;
557+
minExpectedOffset = offset;
558+
return SequentialStoreMatch.Matched;
560559
}
561560

562561
ILInstruction RewrapStore(ILVariable target, StObj storeInstruction, IType type)

0 commit comments

Comments
 (0)