diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs index 179d7905b8cd1..37a91b1c877bf 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_CollectionExpression.cs @@ -66,7 +66,7 @@ private BoundExpression VisitArrayOrSpanCollectionExpression(BoundCollectionExpr Debug.Assert(collectionTypeKind is CollectionExpressionTypeKind.Span or CollectionExpressionTypeKind.ReadOnlySpan); Debug.Assert(spanType.OriginalDefinition.Equals(_compilation.GetWellKnownType( - collectionTypeKind == CollectionExpressionTypeKind.Span ? WellKnownType.System_Span_T : WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions)); + collectionTypeKind == CollectionExpressionTypeKind.Span ? WellKnownType.System_Span_T : WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.AllIgnoreOptions)); Debug.Assert(elementType.Equals(spanType.TypeArgumentsWithAnnotationsNoUseSiteDiagnostics[0], TypeCompareKind.AllIgnoreOptions)); if (ShouldUseInlineArray(node) && diff --git a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs b/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs index b222de82bff46..1df81dcc8785d 100644 --- a/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs +++ b/src/Compilers/CSharp/Test/Emit2/Semantics/CollectionExpressionTests.cs @@ -11052,6 +11052,178 @@ .locals init (R V_0, //r """); } + [Fact] + public void SpanAssignment_FieldInitializer_01() + { + string source = """ + using System; + ref struct R + { + public ReadOnlySpan F = [1, 2, 3]; + public R() { } + } + """; + var comp = CreateCompilation(source, targetFramework: TargetFramework.Net80); + comp.VerifyEmitDiagnostics( + // (4,37): error CS9202: A collection expression of type 'ReadOnlySpan' cannot be used in this context because it may be exposed outside of the current scope. + // public ReadOnlySpan F = [1, 2, 3]; + Diagnostic(ErrorCode.ERR_CollectionExpressionEscape, "[1, 2, 3]").WithArguments("System.ReadOnlySpan").WithLocation(4, 37)); + } + + [Fact] + public void SpanAssignment_FieldInitializer_02() + { + string source = """ + using System; + class Program + { + static T[] FromSpan(Span s) => s.ToArray(); + static int[] F = FromSpan([1, 2, 3]); + static void Main() + { + F.Report(); + } + } + """; + var verifier = CompileAndVerify( + new[] { source, s_collectionExtensionsWithSpan }, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + // PROTOTYPE: Use inline array. + verifier.VerifyIL("Program..cctor", """ + { + // Code size 33 (0x21) + .maxstack 3 + IL_0000: ldc.i4.3 + IL_0001: newarr "int" + IL_0006: dup + IL_0007: ldtoken ".__StaticArrayInitTypeSize=12 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D" + IL_000c: call "void System.Runtime.CompilerServices.RuntimeHelpers.InitializeArray(System.Array, System.RuntimeFieldHandle)" + IL_0011: newobj "System.Span..ctor(int[])" + IL_0016: call "int[] Program.FromSpan(System.Span)" + IL_001b: stsfld "int[] Program.F" + IL_0020: ret + } + """); + } + + [Fact] + public void SpanAssignment_FieldInitializer_03() + { + string source = """ + using System; + class C + { + static T[] FromSpan(ReadOnlySpan s) => s.ToArray(); + public object[] F = FromSpan([1, 2, 3]); + } + class Program + { + static void Main() + { + (new C()).F.Report(); + } + } + """; + var verifier = CompileAndVerify( + new[] { source, s_collectionExtensionsWithSpan }, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + // PROTOTYPE: Use inline array. + verifier.VerifyIL("C..ctor", """ + { + // Code size 56 (0x38) + .maxstack 5 + IL_0000: ldarg.0 + IL_0001: ldc.i4.3 + IL_0002: newarr "object" + IL_0007: dup + IL_0008: ldc.i4.0 + IL_0009: ldc.i4.1 + IL_000a: box "int" + IL_000f: stelem.ref + IL_0010: dup + IL_0011: ldc.i4.1 + IL_0012: ldc.i4.2 + IL_0013: box "int" + IL_0018: stelem.ref + IL_0019: dup + IL_001a: ldc.i4.2 + IL_001b: ldc.i4.3 + IL_001c: box "int" + IL_0021: stelem.ref + IL_0022: newobj "System.ReadOnlySpan..ctor(object[])" + IL_0027: call "object[] C.FromSpan(System.ReadOnlySpan)" + IL_002c: stfld "object[] C.F" + IL_0031: ldarg.0 + IL_0032: call "object..ctor()" + IL_0037: ret + } + """); + } + + [Fact] + public void SpanAssignment_FieldInitializer_04() + { + string source = """ + using System; + struct S + { + static T[] FromSpan(ReadOnlySpan s) => s.ToArray(); + public object[] F = FromSpan([1, 2, 3]); + public S() { } + } + class Program + { + static void Main() + { + (new S()).F.Report(); + } + } + """; + var verifier = CompileAndVerify( + new[] { source, s_collectionExtensionsWithSpan }, + targetFramework: TargetFramework.Net80, + verify: Verification.Skipped, + expectedOutput: IncludeExpectedOutput("[1, 2, 3], ")); + verifier.VerifyIL("S..ctor", """ + { + // Code size 73 (0x49) + .maxstack 3 + .locals init (<>y__InlineArray3 V_0) + IL_0000: ldarg.0 + IL_0001: ldloca.s V_0 + IL_0003: initobj "<>y__InlineArray3" + IL_0009: ldloca.s V_0 + IL_000b: ldc.i4.0 + IL_000c: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_0011: ldc.i4.1 + IL_0012: box "int" + IL_0017: stind.ref + IL_0018: ldloca.s V_0 + IL_001a: ldc.i4.1 + IL_001b: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_0020: ldc.i4.2 + IL_0021: box "int" + IL_0026: stind.ref + IL_0027: ldloca.s V_0 + IL_0029: ldc.i4.2 + IL_002a: call "InlineArrayElementRef<<>y__InlineArray3, object>(ref <>y__InlineArray3, int)" + IL_002f: ldc.i4.3 + IL_0030: box "int" + IL_0035: stind.ref + IL_0036: ldloca.s V_0 + IL_0038: ldc.i4.3 + IL_0039: call "InlineArrayAsReadOnlySpan<<>y__InlineArray3, object>(in <>y__InlineArray3, int)" + IL_003e: call "object[] S.FromSpan(System.ReadOnlySpan)" + IL_0043: stfld "object[] S.F" + IL_0048: ret + } + """); + } + [CombinatorialData] [Theory] public void SpanAssignment_RefLocal([CombinatorialValues(TargetFramework.Net70, TargetFramework.Net80)] TargetFramework targetFramework)