dotnet / dotnet/roslyn

C# compiler incorrectly generates arrays for `params` of an enumerable of a `ref struct` type

Closed
#77,827 3 comments 0 reactions 1 assignee Claimed by @RikkiGibson View on GitHub
Area-Compilers Area-Language Design Bug Feature - Collection Expressions
Dominant language
C#
Stars
20.7k
Forks
4.3k
PR merge metrics
PR metrics pending

Description

/cc @RikkiGibson

**Version Used**: Sharplab.io

**Steps to Reproduce**:

```csharp
using System;
using System.Collections.Generic;
using System.Linq;
public class C
{
public void M(params IEnumerable> a)
{
M([1], [1, 2]);
}
}
```

[link](https://sharplab.io/#v2:EYLgxg9gTgpgtADwGwBYA+ABATARgLABQGADAAQY4oDchJ5OAdADICWAdgI41EDM5WpAMKEA3oVITyfDClIBZABQAHAIZQVAWwDO9HgB4AyqrZ72AFwB8F0ioCU4yWIKSX8hQG0cAXQA0pT35YXrbcLgC+hGFAA=)

This gets emitted as
```csharp
Span[] array = new Span[2];
int reference = 1;
array[0] = new Span(ref reference);
<>y__InlineArray2 buffer = default(<>y__InlineArray2);
.InlineArrayElementRef<<>y__InlineArray2, int>(ref buffer, 0) = 1;
.InlineArrayElementRef<<>y__InlineArray2, int>(ref buffer, 1) = 2;
array[1] = .InlineArrayAsSpan<<>y__InlineArray2, int>(ref buffer, 2);
M(new <>z__ReadOnlyArray>(array));
```

Note the first line is already illegal, as it's allocating an array of spans.

**Diagnostic Id**:

There should be an error, but there is none.

**Expected Behavior**:

Doesn't compile.

OR

Compiles to something very different.

You could probably make some cases, like this one work, for Span/ReadOnlySpan, but in general it is not possible to emit such things. E.g., for this one, you could lower the `[1], [1, 2]` to a span enumeration wrapper that converts a `<>z__ReadOnlyArray` to something that is `IEnumerable>`, but you definitely cannot do this sort of thing with arbitrary Span values (unless you emit some more crazy code, e.g., doing something with `Span*` referring to the values which are stored on the stack or something like that, but I'm not convinced the lifetimes would work properly to allow this to work as expected for general usage of `IEnumerable`s, e.g., you wouldn't be able to pass that across threads, nor keep using the `IEnumerable` value past the function call which took it as `params` - not that you probably want to emit this anyway, just thought I'd mention the theoretical option).

**Actual Behavior**:

Compiles and produces invalid code. This ends up giving `TypeLoadException` at runtime.

Contributor guide

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.