Skip to content

It looks like collection expressions make unnecessary copies of structures which could be big. #75143

Open
@AlekseyTs

Description

@AlekseyTs
using System.Collections.Generic;

class Program
{
    static int[] Test(MyArray x) => [ ..x];
}

struct MyArray
{
    public IEnumerator<int> GetEnumerator() => null;
    public int Length => 0;
}

Observed:
Compiler copies parameter of Test into a local and then uses that local for the purpose of populating resulting array.
It feels like the copy is not necessary and the parameter can be used directly.

IL for Test method:

    .method private hidebysig static 
        int32[] Test (
            valuetype MyArray x
        ) cil managed 
    {
        // Method begins at RVA 0x2050
        // Code size 66 (0x42)
        .maxstack 3
        .locals init (
            [0] valuetype MyArray,
            [1] int32,
            [2] int32[],
            [3] class [System.Runtime]System.Collections.Generic.IEnumerator`1<int32>,
            [4] int32
        )

        IL_0000: ldarg.0
        IL_0001: stloc.0
        IL_0002: ldc.i4.0
        IL_0003: stloc.1
        IL_0004: ldloca.s 0
        IL_0006: call instance int32 MyArray::get_Length()
        IL_000b: newarr [System.Runtime]System.Int32
        IL_0010: stloc.2
        IL_0011: ldloca.s 0
        IL_0013: call instance class [System.Runtime]System.Collections.Generic.IEnumerator`1<int32> MyArray::GetEnumerator()
        IL_0018: stloc.3
        .try
        {
            // sequence point: hidden
            IL_0019: br.s IL_002c
            // loop start (head: IL_002c)
                IL_001b: ldloc.3
                IL_001c: callvirt instance !0 class [System.Runtime]System.Collections.Generic.IEnumerator`1<int32>::get_Current()
                IL_0021: stloc.s 4
                IL_0023: ldloc.2
                IL_0024: ldloc.1
                IL_0025: ldloc.s 4
                IL_0027: stelem.i4
                IL_0028: ldloc.1
                IL_0029: ldc.i4.1
                IL_002a: add
                IL_002b: stloc.1

                IL_002c: ldloc.3
                IL_002d: callvirt instance bool [System.Runtime]System.Collections.IEnumerator::MoveNext()
                IL_0032: brtrue.s IL_001b
            // end loop

            IL_0034: leave.s IL_0040
        } // end .try
        finally
        {
            // sequence point: hidden
            IL_0036: ldloc.3
            IL_0037: brfalse.s IL_003f

            IL_0039: ldloc.3
            IL_003a: callvirt instance void [System.Runtime]System.IDisposable::Dispose()

            // sequence point: hidden
            IL_003f: endfinally
        } // end handler

        // sequence point: hidden
        IL_0040: ldloc.2
        IL_0041: ret
    } // end of method Program::Test

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions