Skip to content

Fully raise Roslyn ForEachLoopOperation.ChildOperationsCount #9969

Closed

Description

@richlander

dotnet-inspect builds robust, capable .NET inspection features that provide foundational capabilities or compelling experiences and are conventionally sound, delightfully new or unique, or both.

Goal

Fully raise Roslyn's
Microsoft.CodeAnalysis.Operations.ForEachLoopOperation.ChildOperationsCount
to its authored four-term count expression, without synthetic stack-slot or
struct-receiver temporaries.

This is a focused successor to #9946 and part of the printer-thinning program
tracked by #9371. #9946 should remain bounded to preserving the slot's correct
System.Int32 identity.

Source oracle

The Microsoft.CodeAnalysis.Common 5.0.0 Portable PDB maps the property to
Roslyn commit 6c4a46a31302167b425d5e0a31ea83c9a9aa1d09; dotnet-inspect verifies the
fetched bytes against the PDB checksum.

=>
    (LoopControlVariable is null ? 0 : 1) +
    (Collection is null ? 0 : 1) +
    NextVariables.Length +
    (Body is null ? 0 : 1);

https://github.com/dotnet/roslyn/blob/6c4a46a31302167b425d5e0a31ea83c9a9aa1d09/src/Compilers/Core/Portable/Generated/Operations.Generated.cs#L4213-L4217

Current output after #9946

int S_256 = (LoopControlVariable is not null ? 1 : 0)
    + (Collection is not null ? 1 : 0);
ImmutableArray<IOperation> V_0 = NextVariables;
return S_256 + V_0.Length
    + (base.Body is not null ? 1 : 0);

#9946 removes the incorrect Boolean split and preserves the actual integer
count. Two source-shape gaps remain:

  1. the now-correct, single-use arithmetic stack value S_256 is not inlined
    into the return expression;
  2. the ImmutableArray<IOperation> receiver temporary V_0 is not
    reconstructed as NextVariables.Length.

Proof obligations

  • Preserve the authored evaluation order and one evaluation of each property.
  • Prove that removing S_256 cannot duplicate, reorder, or narrow the
    multi-term integer computation.
  • Prove that reconstructing NextVariables.Length preserves the value-type
    receiver and defensive-copy behavior represented by the IL.
  • Keep the rule narrow and typed; do not add printer guesses or broad
    single-use-local elimination.
  • Identify the normative pass owner and pipeline position. In particular,
    determine whether identity-preserving passes must be followed by another
    bounded inlining opportunity rather than rerunning a broad early pass.

Acceptance criteria

  • The pinned Roslyn 5.0.0 property decompiles as one direct four-term return
    expression with no S_256 or V_0 declaration. Equivalent inverted null
    ternaries are acceptable.
  • Scenario-adjacent tests separately gate arithmetic-stack inlining and the
    value-type property-receiver reconstruction.
  • Tests demonstrate decline when inlining could duplicate evaluation, change
    order, or alter struct receiver behavior.
  • Focused Release tests and the fixed 14-assembly corpus show no unrelated
    residual, fidelity, or validity regression.
  • The owning design records the bounded rule and explicit exclusions.

The remaining Boolean-to-ArgumentRefKind split in
TypeRef.FunctionPointerParameterText is a separate enum-identity problem and
is outside this issue.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions