From f8c5c70391875bc24c090bac2196fdcf97df7538 Mon Sep 17 00:00:00 2001 From: Sergio Pedri Date: Wed, 22 Nov 2023 20:59:01 +0100 Subject: [PATCH] Add InlineArrayAttribute polyfill --- README.md | 1 + src/PolySharp.Package/README.md | 1 + ...e.CompilerServices.InlineArrayAttribute.cs | 44 +++++++++++++++++++ .../Models/SyntaxFixupType.cs | 8 +++- .../PolyfillsGenerator.Polyfills.cs | 19 ++++++++ tests/PolySharp.Tests/RuntimeSupport.cs | 12 ++++- 6 files changed, 82 insertions(+), 3 deletions(-) create mode 100644 src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.InlineArrayAttribute.cs diff --git a/README.md b/README.md index 3006828..99e942b 100644 --- a/README.md +++ b/README.md @@ -75,6 +75,7 @@ It also includes the following optional runtime-supported polyfills: - `[SuppressGCTransition]` (see [here](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/)) - `[DisableRuntimeMarshalling]` (see [here](https://learn.microsoft.com/dotnet/standard/native-interop/disabled-marshalling)) - `[UnsafeAccessor]` (see [here](https://github.com/dotnet/runtime/issues/81741)) +- `[InlineArray]` (see [here](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-12.0/inline-arrays)) # Options ⚙️ diff --git a/src/PolySharp.Package/README.md b/src/PolySharp.Package/README.md index 3f419dc..3aa6f4c 100644 --- a/src/PolySharp.Package/README.md +++ b/src/PolySharp.Package/README.md @@ -73,6 +73,7 @@ It also includes the following optional runtime-supported polyfills: - `[SuppressGCTransition]` (see [here](https://devblogs.microsoft.com/dotnet/improvements-in-native-code-interop-in-net-5-0/)) - `[DisableRuntimeMarshalling]` (see [here](https://learn.microsoft.com/dotnet/standard/native-interop/disabled-marshalling)) - `[UnsafeAccessor]` (see [here](https://github.com/dotnet/runtime/issues/81741)) +- `[InlineArray]` (see [here](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-12.0/inline-arrays)) # Options ⚙️ diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.InlineArrayAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.InlineArrayAttribute.cs new file mode 100644 index 0000000..6d3ccf0 --- /dev/null +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.InlineArrayAttribute.cs @@ -0,0 +1,44 @@ +// +#pragma warning disable +#nullable enable annotations + +// Licensed to the .NET Foundation under one or more agreements. +// The .NET Foundation licenses this file to you under the MIT license. + +namespace System.Runtime.CompilerServices2 +{ + /// + /// Indicates that the instance's storage is sequentially replicated "length" times. + /// + /// + /// + /// This attribute can be used to annotate a type with a single field. + /// The runtime will replicate that field in the actual type layout as many times as is specified. + /// + /// + /// Here's an example of how an inline array type with 8 values can be declared: + /// + /// [InlineArray(8)] + /// struct Float8InlineArray + /// { + /// private float _value; + /// } + /// + /// + /// + [global::System.AttributeUsage(global::System.AttributeTargets.Struct, AllowMultiple = false)] + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] + public sealed class InlineArrayAttribute : global::System.Attribute + { + /// Creates a new instance with the specified length. + /// The number of sequential fields to replicate in the inline array type. + public InlineArrayAttribute(int length) + { + Length = length; + } + + /// Gets the number of sequential fields to replicate in the inline array type. + public int Length { get; } + } +} \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/Models/SyntaxFixupType.cs b/src/PolySharp.SourceGenerators/Models/SyntaxFixupType.cs index a89f62d..bc37406 100644 --- a/src/PolySharp.SourceGenerators/Models/SyntaxFixupType.cs +++ b/src/PolySharp.SourceGenerators/Models/SyntaxFixupType.cs @@ -27,5 +27,11 @@ internal enum SyntaxFixupType /// Generates the [UnmanagedCallersOnly] type in the InteropServices2 dummy namespace. /// /// This is needed when methods annotated with the attribute have to be assigned to delegates, which Roslyn will otherwise block. - UseInteropServices2ForUnmanagedCallersOnlyAttribute = 1 << 2 + UseInteropServices2ForUnmanagedCallersOnlyAttribute = 1 << 2, + + /// + /// Generates a global using for the [InlineArray] type in the dummy namespace. + /// + /// This is always needed when the type is used, as the usage is entirely blocked in the normal namespace. + EmitGlobalUsingForInlineArrayAttribute = 1 << 3 } diff --git a/src/PolySharp.SourceGenerators/PolyfillsGenerator.Polyfills.cs b/src/PolySharp.SourceGenerators/PolyfillsGenerator.Polyfills.cs index 0895ee8..159a6dd 100644 --- a/src/PolySharp.SourceGenerators/PolyfillsGenerator.Polyfills.cs +++ b/src/PolySharp.SourceGenerators/PolyfillsGenerator.Polyfills.cs @@ -153,6 +153,13 @@ static SyntaxFixupType GetSyntaxFixupType(Compilation compilation, string name) fixupType |= SyntaxFixupType.RemoveMethodImplAttributes; } + // Emit the global using for the dummy [InlineArray] type, if allowed + if (name is "System.Runtime.CompilerServices.InlineArrayAttribute" && + compilation.HasLanguageVersionAtLeastEqualTo(LanguageVersion.CSharp10)) + { + fixupType |= SyntaxFixupType.EmitGlobalUsingForInlineArrayAttribute; + } + return fixupType; } @@ -287,6 +294,18 @@ private void EmitGeneratedType(SourceProductionContext context, GeneratedType ty "System.Runtime.InteropServices2"); } + if ((type.FixupType & SyntaxFixupType.EmitGlobalUsingForInlineArrayAttribute) != 0) + { + // Generate a global using for [InlineArray] + adjustedSource = adjustedSource.Replace( + "namespace System.Runtime.CompilerServices2", + """ + global using InlineArrayAttribute = global::System.Runtime.CompilerServices2.InlineArrayAttribute; + + namespace System.Runtime.CompilerServices2 + """); + } + sourceText = SourceText.From(adjustedSource, Encoding.UTF8); } else diff --git a/tests/PolySharp.Tests/RuntimeSupport.cs b/tests/PolySharp.Tests/RuntimeSupport.cs index 1e34a92..a4593fb 100644 --- a/tests/PolySharp.Tests/RuntimeSupport.cs +++ b/tests/PolySharp.Tests/RuntimeSupport.cs @@ -88,9 +88,9 @@ public void ReferenceSomeAssemblyFile() internal class AccessorApis { -#pragma warning disable IDE0044 +#pragma warning disable CS0169, IDE0044 private int field; -#pragma warning restore IDE0044 +#pragma warning restore CS0169, IDE0044 [StackTraceHidden] public void HideMe() @@ -99,4 +99,12 @@ public void HideMe() [UnsafeAccessor(UnsafeAccessorKind.Field, Name = nameof(field))] public static extern ref int GetField(RandomApis obj); +} + +[InlineArray(16)] +internal struct Int8 +{ +#pragma warning disable CS0169, IDE0044, IDE0051 + private int value0; +#pragma warning restore CS0169, IDE0044, IDE0051 } \ No newline at end of file