Adjust inline-arrays.md based on LDM decisions (#7177)

This commit is contained in:
AlekseyTs 2023-05-08 15:28:58 -07:00 коммит произвёл GitHub
Родитель ccde954bdd
Коммит 05105f658b
Не найден ключ, соответствующий данной подписи
Идентификатор ключа GPG: 4AEE18F83AFDEB23
1 изменённых файлов: 121 добавлений и 88 удалений

Просмотреть файл

@ -253,6 +253,119 @@ of inline array types.
Regular definite assignment rules are applicable to variables that have an inline array type.
### Collection literals
An inline array type is a valid *constructible collection* target type for a [collection literal](https://github.com/dotnet/csharplang/blob/main/proposals/collection-literals.md).
For example:
``` C#
int[5] a = [1, 2, 3, 4, 5]; // initializes anonymous inline array of length 5
Buffer10<int> b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // initializes user-defined inline array
var d = new int[][2] {[11, 12], [21, 22], [31, 32]}; // regular array with an element type of an anonymous inline array type with element type int and length 2
```
The length of the collection literal must match the length of the target inline array type. If the length of the literal
is known at compile time and it doesn't match the target length, an error is reported. Otherwise, an exception is going
to be thrown at runtime once the mismatch is encountered. The exact exception type is TBD. Some candidates are:
System.NotSupportedException, System.InvalidOperationException.
An instance of an inline array type is a valid expression in a [*spread_element*](https://github.com/dotnet/csharplang/blob/main/proposals/collection-literals.md#detailed-design).
### Validation of the InlineArrayAttribute applications
Compiler will validate the following aspects of the InlineArrayAttribute applications:
- The target type is a struct
- The target type has only one field
- Specified length > 0
- The target struct doesn't have an explicit layout specified
### Inline Array elements in an object initializer
By default, element initialization will not be supported via *initializer_target* of form ```'[' argument_list ']'```
(see https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/expressions.md#117153-object-initializers):
``` C#
static C M2() => new C() { F = {[0] = 111} }; // error CS1913: Member '[0]' cannot be initialized. It is not a field or property.
class C
{
public Buffer10<int> F;
}
```
However, if the inline array type explicitly defines suitable indexer, object initializer will use it:
``` C#
static C M2() => new C() { F = {[0] = 111} }; // Ok, indexer is invoked
class C
{
public Buffer10<int> F;
}
[System.Runtime.CompilerServices.InlineArray(10)]
public struct Buffer10<T>
{
private T _element0;
public T this[int i]
{
get => this[i];
set => this[i] = value;
}
}
```
### The foreach statement
[The foreach statement](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1295-the-foreach-statement) will be adjusted
to allow usage of an inline array type as a collection in a foreach statement.
For example:
``` C#
foreach (var a in getBufferAsValue())
{
WriteLine(a);
}
foreach (var b in getBufferAsWritableVariable())
{
WriteLine(b);
}
foreach (var c in getBufferAsReadonlyVariable())
{
WriteLine(c);
}
Buffer10<int> getBufferAsValue() => default;
ref Buffer10<int> getBufferAsWritableVariable() => default;
ref readonly Buffer10<int> getBufferAsReadonlyVariable() => default;
```
is equivalent to:
``` C#
Buffer10<int> temp = getBufferAsValue();
foreach (var a in (System.ReadOnlySpan<int>)temp)
{
WriteLine(a);
}
foreach (var b in (System.Span<int>)getBufferAsWritableVariable())
{
WriteLine(b);
}
foreach (var c in (System.ReadOnlySpan<int>)getBufferAsReadonlyVariable())
{
WriteLine(c);
}
```
## Open design questions
## Alternatives
### Inline array type syntax
The grammar at https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/types.md#821-general will be adjusted as follows:
@ -365,94 +478,6 @@ var c = new int[][] {{11, 12}, {21, 22}, {31, 32}}; // An error for the nested a
var d = new int[][2] {{11, 12}, {21, 22}, {31, 32}}; // An error for the nested array initializer
```
#### Collection literals
An inline array type is a valid *constructible collection* target type for a [collection literal](https://github.com/dotnet/csharplang/blob/main/proposals/collection-literals.md).
For example:
``` C#
int[5] a = [1, 2, 3, 4, 5]; // initializes anonymous inline array of length 5
Buffer10<int> b = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10]; // initializes user-defined inline array
var d = new int[][2] {[11, 12], [21, 22], [31, 32]}; // regular array with an element type of an anonymous inline array type with element type int and length 2
```
The length of the collection literal must match the length of the target inline array type. If the length of the literal
is known at compile time and it doesn't match the target length, an error is reported. Otherwise, an exception is going
to be thrown at runtime once the mismatch is encountered. The exact exception type is TBD. Some candidates are:
System.NotSupportedException, System.InvalidOperationException.
An instance of an inline array type is a valid expression in a [*spread_element*](https://github.com/dotnet/csharplang/blob/main/proposals/collection-literals.md#detailed-design).
### The foreach statement
[The foreach statement](https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/statements.md#1295-the-foreach-statement) will be adjusted
to allow usage of an inline array type as a collection in a foreach statement.
For example:
``` C#
foreach (var a in getBufferAsValue())
{
WriteLine(a);
}
foreach (var b in getBufferAsWritableVariable())
{
WriteLine(b);
}
foreach (var c in getBufferAsReadonlyVariable())
{
WriteLine(c);
}
Buffer10<int> getBufferAsValue() => default;
ref Buffer10<int> getBufferAsWritableVariable() => default;
ref readonly Buffer10<int> getBufferAsReadonlyVariable() => default;
```
is equivalent to:
``` C#
Buffer10<int> temp = getBufferAsValue();
foreach (var a in (System.ReadOnlySpan<int>)temp)
{
WriteLine(a);
}
foreach (var b in (System.Span<int>)getBufferAsWritableVariable())
{
WriteLine(b);
}
foreach (var c in (System.ReadOnlySpan<int>)getBufferAsReadonlyVariable())
{
WriteLine(c);
}
```
## Open design questions
### Should compiler validate applications of the InlineArrayAttribute?
Possible things we can check:
- The type is a struct (probably just a warning)
- Has only one field
- Specified length > 0
- The struct doesn't have an explicit layout specified
### Should we support initialization of Inline Array elements in an object initializer?
``` C#
static C M2() => new C() { F = {[0] = 111} };
class C
{
public Buffer10<int> F;
}
```
## Alternatives
### Detailed Design (Option 2)
Note, that for the purpose of this proposal a term "fixed-size buffer" refers to a the proposed "safe fixed-size buffer" feature rather than to a buffer described at https://github.com/dotnet/csharpstandard/blob/draft-v8/standard/unsafe-code.md#228-fixed-size-buffers.
@ -680,3 +705,11 @@ but can be made into one if necessary. Heres how that would work:
C/C++ has a different notion of fixed-size buffers. For example, there is a notion of "zero-length fixed sized buffers",
which is often used as a way to indicate that the data is "variable length". It is not a goal of this proposal to be
able to interop with that.
## LDM meetings
- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-03.md#fixed-size-buffers
- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-04-10.md#fixed-size-buffers
- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-01.md#fixed-size-buffers
- https://github.com/dotnet/csharplang/blob/main/meetings/2023/LDM-2023-05-03.md#inline-arrays