Skip to content

Surprising codegen for passing collection spread to span/readonlyspan taking method. #76488

Closed as duplicate of#75863
@CyrusNajmabadi

Description

Consider this code:

using System;
using System.Collections.Generic;

class C
{
    void Main(IEnumerable<string> values)
    {
        Goo([.. values, .. values]);
    }

    void Goo(ReadOnlySpan<string> spans)
    {
    }
}

Sharplab: https://sharplab.io/#v2:C4LglgNgNAJiDUAfAAgJgIwFgBQyAMABMugCwDcOOaBAwjgN44HNEkECyAhmAHYAUxAMwAeYngB8BAG6cIAVwCmAZwCUTFo2wttBAOIB7fXwDaAOlPTZipVALnL85QF0VFLSwC+ld82RsDRgBKCpwwAPI8EACeAMoADpw8ougSBEoJPKrqzJraXtgeQA

We generate the equivalent of:

	List<string> list = new List<string>();
	list.AddRange(values);
	list.AddRange(values);
	Goo(new ReadOnlySpan<string>(list.ToArray()));

The copy to an array seems unnecessary here, and more ideal codegen would seem to be:

	List<string> list = new List<string>();
	list.AddRange(values);
	list.AddRange(values);
	Goo(System.Runtime.InteropServices.CollectionsMarshal.AsSpan(list));

This would prevent a needless copy. Note that this should be entirely safe as:

  1. The backing list is an impl detail hidden from the user (they cannot mutate it).
  2. writing back into the list through the span would continue to be supported, but would also continue to be pointless.

This seems like a safe, and desirable change to make (as long as CollectionsMarshal.AsSpan is available) whenever we are targetting a span/read-only-span with a variable length number of elements.

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions