diff --git a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs index 4a86f5648839f..6b4e91294d033 100644 --- a/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs +++ b/src/Compilers/CSharp/Portable/Lowering/LocalRewriter/LocalRewriter_Conversion.cs @@ -39,17 +39,25 @@ public override BoundNode VisitConversion(BoundConversion node) var rewrittenType = VisitType(node.Type); - // special handling for stackalloc converted to ROS - if (node.Operand is BoundConvertedStackAllocExpression stackAllocExpression && - TypeSymbol.Equals(rewrittenType.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.ConsiderEverything)) + // special handling for initializers converted to ROS + if (TypeSymbol.Equals(rewrittenType.OriginalDefinition, _compilation.GetWellKnownType(WellKnownType.System_ReadOnlySpan_T), TypeCompareKind.ConsiderEverything)) { - bool hasCreateSpanHelper = _compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpan_T) is not null; - var elementType = stackAllocExpression.ElementType; - var initializerOpt = stackAllocExpression.InitializerOpt; - if (CodeGen.CodeGenerator.UseCreateSpanForReadOnlyStackAlloc(hasCreateSpanHelper, elementType, initializerOpt, - /* TODO: how to find out if this is ENC? */ supportsPrivateImplClass: true)) + if (node.Operand is BoundConvertedStackAllocExpression or BoundArrayCreation) { - return new BoundConvertedStackAllocExpression(stackAllocExpression.Syntax, elementType, VisitExpression(stackAllocExpression.Count), initializerOpt, rewrittenType); + bool hasCreateSpanHelper = _compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__CreateSpan_T) is not null; + + var (elementType, initializerOpt, count) = node.Operand switch + { + BoundConvertedStackAllocExpression stackAlloc => (stackAlloc.ElementType, stackAlloc.InitializerOpt, VisitExpression(stackAlloc.Count)), + BoundArrayCreation arrayCreation => (((ArrayTypeSymbol)arrayCreation.Type).ElementType, arrayCreation.InitializerOpt, /* need some dummy expression */ _factory.Literal(0)), + _ => throw ExceptionUtilities.Unreachable + }; + + if (CodeGen.CodeGenerator.UseCreateSpanForReadOnlyStackAlloc(hasCreateSpanHelper, elementType, initializerOpt, + /* TODO: how to find out if this is ENC? */ supportsPrivateImplClass: true)) + { + return new BoundConvertedStackAllocExpression(node.Operand.Syntax, elementType, count, initializerOpt, rewrittenType); + } } } diff --git a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs index 1e7aa583c3678..07b54e958ad4b 100644 --- a/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs +++ b/src/Compilers/CSharp/Test/Emit/CodeGen/CodeGenStackAllocInitializerTests.cs @@ -987,6 +987,36 @@ .maxstack 4 "); } + [Fact] + public void TestArray() + { + var comp = CreateCompilation(new[] { @" +using System; +static class C +{ + static void Main(int i) + { + ReadOnlySpan p = new int[] { 1, 2, 3 }; + Write(p); + } + + static void Write(ReadOnlySpan span) {} +} +", CreateSpanDefinition }, targetFramework: TargetFramework.Net50); + CompileAndVerify(comp, verify: Verification.Fails) + .VerifyIL("C.Main", +@" +{ + // Code size 16 (0x10) + .maxstack 1 + IL_0000: ldtoken "".__StaticArrayInitTypeSize=12 .4636993D3E1DA4E9D6B8F87B79E8F7C6D018580D52661950EABC3845C5897A4D"" + IL_0005: call ""System.ReadOnlySpan System.Runtime.CompilerServices.RuntimeHelpers.CreateSpan(System.RuntimeFieldHandle)"" + IL_000a: call ""void C.Write(System.ReadOnlySpan)"" + IL_000f: ret +} +"); + } + private static string GetSource(string pointerType) => $@" using System; using T = {pointerType};