Skip to content

Cast lost when ternary with mismatched branch types is hoisted to object local #3736

@OpenSourcereR-dev

Description

@OpenSourcereR-dev

When a ?:'s two branches have different stack types and ILSpy can't find a common type tighter than object, it hoists the conditional into an if/else with an object obj local — but drops the explicit cast that was present in the source. The dropped cast can re-bind to a different overload on recompile.

Repro

using System.Collections.Generic;
using System.Linq;

public class Repro
{
    public IEnumerator<byte> Bug(byte[] data, bool reversed)
        => (reversed ? ((IEnumerable<byte>)data).Reverse() : (IEnumerable<byte>)data).GetEnumerator();
}

ilspycmd 10.0.1.8346 output

public IEnumerator<byte> Bug(byte[] data, bool reversed)
{
    object obj;
    if (!reversed)
    {
        obj = data;
    }
    else
    {
        obj = data.Reverse();  // (IEnumerable<byte>) cast lost
    }
    return ((IEnumerable<byte>)obj).GetEnumerator();
}

When a project-local void Reverse(this byte[]) (or similar shadowing extension) is in scope, data.Reverse() re-binds to it on recompile → CS0029 ("Cannot implicitly convert type 'void' to 'object'"). Even without a shadow, the decompile is semantically lossy.

dotPeek emits the inline ternary form with both casts preserved.

Related

#1501, #1614, #3322, #3464, #793 are all in the same family (ILSpy dropping a needed cast); none is exactly this ?:if/else hoist variant.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions