diff --git a/Directory.Build.props b/Directory.Build.props index 023b02b..4d7793f 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,7 +1,7 @@ true - 11.0 + 12.0 enable true diff --git a/PolySharp.sln b/PolySharp.sln index 3f99876..b933183 100644 --- a/PolySharp.sln +++ b/PolySharp.sln @@ -6,7 +6,9 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolySharp.SourceGenerators" EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Projects", "Projects", "{8DAA0C71-4529-44EB-8994-DE331A3ADC52}" ProjectSection(SolutionItems) = preProject + src\PolySharp.Package\icon.png = src\PolySharp.Package\icon.png src\PolySharp.Package\PolySharp.Package.msbuildproj = src\PolySharp.Package\PolySharp.Package.msbuildproj + src\PolySharp.Package\README.md = src\PolySharp.Package\README.md EndProjectSection EndProject Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Tests", "Tests", "{D65D0307-1D0F-499D-945B-E33E71F251A4}" @@ -37,7 +39,7 @@ Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolySharp.MinimumCSharpVers EndProject Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolySharp.PolySharpUseTypeAliasForUnmanagedCallersOnlyAttribute.Tests", "tests\PolySharp.PolySharpUseTypeAliasForUnmanagedCallersOnlyAttribute.Tests\PolySharp.PolySharpUseTypeAliasForUnmanagedCallersOnlyAttribute.Tests.csproj", "{C865CEDE-2DC9-4E1E-BB58-529E6E2A9DBB}" EndProject -Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "PolySharp.TypeForwards.Tests", "tests\PolySharp.TypeForwards.Tests\PolySharp.TypeForwards.Tests.csproj", "{AAF3B574-66F1-4EF0-936A-82390E30D539}" +Project("{9A19103F-16F7-4668-BE54-9A1E7A4F7556}") = "PolySharp.TypeForwards.Tests", "tests\PolySharp.TypeForwards.Tests\PolySharp.TypeForwards.Tests.csproj", "{AAF3B574-66F1-4EF0-936A-82390E30D539}" EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution diff --git a/README.md b/README.md index 829185a..99e942b 100644 --- a/README.md +++ b/README.md @@ -8,7 +8,7 @@ # TLDR? What is this for? ✨ -Put simply: are you working on .NET Framework, or UWP, or some other older .NET runtime and still would like to use all the cool new features that C# 11 has? Well this library lets you do just that! It will generate for you all the "magic types" that the C# compiler needs to "see" in order for it to allow using new language features even if you're not using the latest framework out there. +Put simply: are you working on .NET Framework, or UWP, or some other older .NET runtime and still would like to use all the cool new features that C# 12 has? Well this library lets you do just that! It will generate for you all the "magic types" that the C# compiler needs to "see" in order for it to allow using new language features even if you're not using the latest framework out there. Here's an example of some of the new features that **PolySharp** can enable downlevel: @@ -49,8 +49,11 @@ Here's an example of some of the new features that **PolySharp** can enable down - `[AsyncMethodBuilder]` (needed for [custom method builder types](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-10.0/async-method-builders)) - `[StringSyntax]` (needed to enable [syntax highlight in the IDE](https://github.com/dotnet/runtime/issues/62505)) - `[ModuleInitializer]` (needed to enable [custom module initializers](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-9.0/module-initializers)) +- `[RequiresLocation]` (needed to enable [ref readonly parameters](https://github.com/dotnet/csharplang/issues/6010)) +- `[CollectionBuilder]` (needed for [collection expressions](https://github.com/dotnet/csharplang/issues/5354)) +- `[Experimental]` (needed for [experimental features](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/experimental-attribute)) -To leverage them, make sure to bump your C# language version. You can do this by setting the `` MSBuild property in your project. For instance, by adding `11.0` (or your desired C# version) to the first `` of your .csproj file. For more info on this, [see here](https://sergiopedri.medium.com/enabling-and-using-c-9-features-on-older-and-unsupported-runtimes-ce384d8debb), but remember that you don't need to manually copy polyfills anymore: simply adding a reference to **PolySharp** will do this for you automatically. +To leverage them, make sure to bump your C# language version. You can do this by setting the `` MSBuild property in your project. For instance, by adding `12.0` (or your desired C# version) to the first `` of your .csproj file. For more info on this, [see here](https://sergiopedri.medium.com/enabling-and-using-c-9-features-on-older-and-unsupported-runtimes-ce384d8debb), but remember that you don't need to manually copy polyfills anymore: simply adding a reference to **PolySharp** will do this for you automatically. It also includes the following optional runtime-supported polyfills: - Reflection annotation attributes (see [docs](https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming)): @@ -71,6 +74,8 @@ It also includes the following optional runtime-supported polyfills: - `[UnsupportedOSPlatformGuard]` - `[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/global.json b/global.json new file mode 100644 index 0000000..789bff3 --- /dev/null +++ b/global.json @@ -0,0 +1,7 @@ +{ + "sdk": { + "version": "8.0.100", + "rollForward": "latestFeature", + "allowPrerelease": false + } +} \ No newline at end of file diff --git a/src/PolySharp.Package/README.md b/src/PolySharp.Package/README.md index 8423e6e..3aa6f4c 100644 --- a/src/PolySharp.Package/README.md +++ b/src/PolySharp.Package/README.md @@ -6,7 +6,7 @@ # TLDR? What is this for? ✨ -Put simply: are you working on .NET Framework, or UWP, or some other older .NET runtime and still would like to use all the cool new features that C# 11 has? Well this library lets you do just that! It will generate for you all the "magic types" that the C# compiler needs to "see" in order for it to allow using new language features even if you're not using the latest framework out there. +Put simply: are you working on .NET Framework, or UWP, or some other older .NET runtime and still would like to use all the cool new features that C# 12 has? Well this library lets you do just that! It will generate for you all the "magic types" that the C# compiler needs to "see" in order for it to allow using new language features even if you're not using the latest framework out there. Here's an example of some of the new features that **PolySharp** can enable downlevel: @@ -47,8 +47,11 @@ Here's an example of some of the new features that **PolySharp** can enable down - `[AsyncMethodBuilder]` (needed for [custom method builder types](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-10.0/async-method-builders)) - `[StringSyntax]` (needed to enable [syntax highlight in the IDE](https://github.com/dotnet/runtime/issues/62505)) - `[ModuleInitializer]` (needed to enable [custom module initializers](https://learn.microsoft.com/dotnet/csharp/language-reference/proposals/csharp-9.0/module-initializers)) +- `[RequiresLocation]` (needed to enable [ref readonly parameters](https://github.com/dotnet/csharplang/issues/6010)) +- `[CollectionBuilder]` (needed for [collection expressions](https://github.com/dotnet/csharplang/issues/5354)) +- `[Experimental]` (needed for [experimental features](https://learn.microsoft.com/en-us/dotnet/csharp/language-reference/proposals/csharp-12.0/experimental-attribute)) -To leverage them, make sure to bump your C# language version. You can do this by setting the `` MSBuild property in your project. For instance, by adding `11.0` (or your desired C# version) to the first `` of your .csproj file. For more info on this, [see here](https://sergiopedri.medium.com/enabling-and-using-c-9-features-on-older-and-unsupported-runtimes-ce384d8debb), but remember that you don't need to manually copy polyfills anymore: simply adding a reference to **PolySharp** will do this for you automatically. +To leverage them, make sure to bump your C# language version. You can do this by setting the `` MSBuild property in your project. For instance, by adding `12.0` (or your desired C# version) to the first `` of your .csproj file. For more info on this, [see here](https://sergiopedri.medium.com/enabling-and-using-c-9-features-on-older-and-unsupported-runtimes-ce384d8debb), but remember that you don't need to manually copy polyfills anymore: simply adding a reference to **PolySharp** will do this for you automatically. It also includes the following optional runtime-supported polyfills: - Reflection annotation attributes (see [docs](https://learn.microsoft.com/dotnet/core/deploying/trimming/prepare-libraries-for-trimming)): @@ -69,6 +72,8 @@ It also includes the following optional runtime-supported polyfills: - `[UnsupportedOSPlatformGuard]` - `[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/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.UnsafeAccessorAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.UnsafeAccessorAttribute.cs new file mode 100644 index 0000000..0a2591c --- /dev/null +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.UnsafeAccessorAttribute.cs @@ -0,0 +1,80 @@ +// +#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.CompilerServices +{ + /// + /// Provides access to an inaccessible member of a specific type. + /// + /// + /// This attribute may be applied to an extern static method. + /// The implementation of the extern static method annotated with + /// this attribute will be provided by the runtime based on the information in + /// the attribute and the signature of the method that the attribute is applied to. + /// The runtime will try to find the matching method or field and forward the call + /// to it. If the matching method or field is not found, the body of the extern + /// method will throw or . + /// Only the specific type defined will be examined for inaccessible members. The type hierarchy + /// is not walked looking for a match. + /// + /// For , + /// , + /// , + /// and , the type of + /// the first argument of the annotated extern method identifies the owning type. + /// The value of the first argument is treated as this pointer for instance fields and methods. + /// The first argument must be passed as ref for instance fields and methods on structs. + /// The value of the first argument is not used by the implementation for static fields and methods. + /// + /// Return type is considered for the signature match. modreqs and modopts are initially not considered for + /// the signature match. However, if an ambiguity exists ignoring modreqs and modopts, a precise match + /// is attempted. If an ambiguity still exists is thrown. + /// + /// By default, the attributed method's name dictates the name of the method/field. This can cause confusion + /// in some cases since language abstractions, like C# local functions, generate mangled IL names. The + /// solution to this is to use the nameof mechanism and define the property. + /// + /// + /// public void Method(Class c) + /// { + /// PrivateMethod(c); + /// + /// [UnsafeAccessor(UnsafeAccessorKind.Method, Name = nameof(PrivateMethod))] + /// extern static void PrivateMethod(Class c); + /// } + /// + /// + [global::System.AttributeUsage(global::System.AttributeTargets.Method, AllowMultiple = false, Inherited = false)] + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + [global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] + internal sealed class UnsafeAccessorAttribute : global::System.Attribute + { + /// + /// Instantiates an + /// providing access to a member of kind . + /// + /// The kind of the target to which access is provided. + public UnsafeAccessorAttribute(global::System.Runtime.CompilerServices.UnsafeAccessorKind kind) + { + Kind = kind; + } + + /// + /// Gets the kind of member to which access is provided. + /// + public global::System.Runtime.CompilerServices.UnsafeAccessorKind Kind { get; } + + /// + /// Gets or sets the name of the member to which access is provided. + /// + /// + /// The name defaults to the annotated method name if not specified. + /// The name must be unset/null for . + /// + public string? Name { get; set; } + } +} \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.UnsafeAccessorKind.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.UnsafeAccessorKind.cs new file mode 100644 index 0000000..7cb4fc3 --- /dev/null +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.CompilerServices.UnsafeAccessorKind.cs @@ -0,0 +1,40 @@ +// +#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.CompilerServices +{ + /// + /// Specifies the kind of target to which an is providing access. + /// + internal enum UnsafeAccessorKind + { + /// + /// Provide access to a constructor. + /// + Constructor, + + /// + /// Provide access to a method. + /// + Method, + + /// + /// Provide access to a static method. + /// + StaticMethod, + + /// + /// Provide access to a field. + /// + Field, + + /// + /// Provide access to a static field. + /// + StaticField + } +} \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs index 7cdf153..a2b1b22 100644 --- a/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/RuntimeSupported/System.Runtime.InteropServices.UnmanagedCallersOnlyAttribute.cs @@ -23,10 +23,6 @@ namespace System.Runtime.InteropServices [global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")] internal sealed class UnmanagedCallersOnlyAttribute : global::System.Attribute { - public UnmanagedCallersOnlyAttribute() - { - } - /// /// Optional. If omitted, the runtime will use the default platform calling convention. /// diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Diagnostics.CodeAnalysis.ExperimentalAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Diagnostics.CodeAnalysis.ExperimentalAttribute.cs new file mode 100644 index 0000000..0ffefc8 --- /dev/null +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Diagnostics.CodeAnalysis.ExperimentalAttribute.cs @@ -0,0 +1,62 @@ +// +#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.Diagnostics.CodeAnalysis +{ + /// + /// Indicates that an API is experimental and it may change in the future. + /// + /// + /// This attribute allows call sites to be flagged with a diagnostic that indicates that an experimental + /// feature is used. Authors can use this attribute to ship preview features in their assemblies. + /// + [global::System.AttributeUsage( + global::System.AttributeTargets.Assembly | + global::System.AttributeTargets.Module | + global::System.AttributeTargets.Class | + global::System.AttributeTargets.Struct | + global::System.AttributeTargets.Enum | + global::System.AttributeTargets.Constructor | + global::System.AttributeTargets.Method | + global::System.AttributeTargets.Property | + global::System.AttributeTargets.Field | + global::System.AttributeTargets.Event | + global::System.AttributeTargets.Interface | + global::System.AttributeTargets.Delegate, + Inherited = false)] + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal sealed class ExperimentalAttribute : global::System.Attribute + { + /// + /// Initializes a new instance of the class, + /// specifying the ID that the compiler will use when reporting a use of the API the attribute applies to. + /// + /// The ID that the compiler will use when reporting a use of the API the attribute applies to. + public ExperimentalAttribute(string diagnosticId) + { + DiagnosticId = diagnosticId; + } + + /// + /// Gets the ID that the compiler will use when reporting a use of the API the attribute applies to. + /// + /// The unique diagnostic ID. + /// + /// The diagnostic ID is shown in build output for warnings and errors. + /// This property represents the unique ID that can be used to suppress the warnings or errors, if needed. + /// + public string DiagnosticId { get; } + + /// + /// Gets or sets the URL for corresponding documentation. + /// The API accepts a format string instead of an actual URL, creating a generic URL that includes the diagnostic ID. + /// + /// The format string that represents a URL to corresponding documentation. + /// An example format string is https://contoso.com/obsoletion-warnings/{0}. + public string? UrlFormat { get; set; } + } +} \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.CollectionBuilderAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.CollectionBuilderAttribute.cs new file mode 100644 index 0000000..d1a037e --- /dev/null +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.CollectionBuilderAttribute.cs @@ -0,0 +1,48 @@ +// +#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.CompilerServices +{ + [global::System.AttributeUsage( + global::System.AttributeTargets.Class | + global::System.AttributeTargets.Struct | + global::System.AttributeTargets.Interface, + Inherited = false)] + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal sealed class CollectionBuilderAttribute : Attribute + { + /// + /// Initialize the attribute to refer to the method on the type. + /// + /// The type of the builder to use to construct the collection. + /// The name of the method on the builder to use to construct the collection. + /// + /// must refer to a static method that accepts a single parameter of + /// type and returns an instance of the collection being built containing + /// a copy of the data from that span. In future releases of .NET, additional patterns may be supported. + /// + public CollectionBuilderAttribute(Type builderType, string methodName) + { + BuilderType = builderType; + MethodName = methodName; + } + + /// + /// Gets the type of the builder to use to construct the collection. + /// + public Type BuilderType { get; } + + /// + /// Gets the name of the method on the builder to use to construct the collection. + /// + /// + /// This should match the metadata name of the target method. + /// For example, this might be ".ctor" if targeting the type's constructor. + /// + public string MethodName { get; } + } +} \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.ModuleInitializerAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.ModuleInitializerAttribute.cs index d2cc394..19711cc 100644 --- a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.ModuleInitializerAttribute.cs +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.ModuleInitializerAttribute.cs @@ -31,8 +31,5 @@ namespace System.Runtime.CompilerServices [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] internal sealed class ModuleInitializerAttribute : global::System.Attribute { - public ModuleInitializerAttribute() - { - } } } \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.RequiresLocationAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.RequiresLocationAttribute.cs new file mode 100644 index 0000000..53ea973 --- /dev/null +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.CompilerServices.RequiresLocationAttribute.cs @@ -0,0 +1,20 @@ +// +#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.CompilerServices +{ + /// + /// Reserved for use by a compiler for tracking metadata. + /// This attribute should not be used by developers in source code. + /// + [global::System.AttributeUsage(global::System.AttributeTargets.Parameter, Inherited = false)] + [global::System.ComponentModel.EditorBrowsable(global::System.ComponentModel.EditorBrowsableState.Never)] + [global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage] + internal sealed class RequiresLocationAttribute : global::System.Attribute + { + } +} \ No newline at end of file diff --git a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.Versioning.RequiresPreviewFeaturesAttribute.cs b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.Versioning.RequiresPreviewFeaturesAttribute.cs index 9e27d93..153f0ca 100644 --- a/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.Versioning.RequiresPreviewFeaturesAttribute.cs +++ b/src/PolySharp.SourceGenerators/EmbeddedResources/System.Runtime.Versioning.RequiresPreviewFeaturesAttribute.cs @@ -26,7 +26,9 @@ internal sealed class RequiresPreviewFeaturesAttribute : global::System.Attribut /// /// Initializes a new instance of the class. /// - public RequiresPreviewFeaturesAttribute() { } + public RequiresPreviewFeaturesAttribute() + { + } /// /// Initializes a new instance of the class with the specified message. diff --git a/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs b/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs index 74b57dc..95eb9af 100644 --- a/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs +++ b/src/PolySharp.SourceGenerators/Helpers/EquatableArray{T}.cs @@ -33,22 +33,14 @@ public static EquatableArray AsEquatableArray(this ImmutableArray array /// An imutable, equatable array. This is equivalent to but with value equality support. /// /// The type of values in the array. -internal readonly struct EquatableArray : IEquatable>, IEnumerable +/// The input to wrap. +internal readonly struct EquatableArray(ImmutableArray array) : IEquatable>, IEnumerable where T : IEquatable { /// /// The underlying array. /// - private readonly T[]? array; - - /// - /// Creates a new instance. - /// - /// The input to wrap. - public EquatableArray(ImmutableArray array) - { - this.array = Unsafe.As, T[]?>(ref array); - } + private readonly T[]? array = Unsafe.As, T[]?>(ref array); /// /// Gets a reference to an item at a specified position within the array. @@ -144,7 +136,7 @@ public static EquatableArray FromImmutableArray(ImmutableArray array) /// A wrapping the current items. public ReadOnlySpan AsSpan() { - return AsImmutableArray().AsSpan(); + return new(this.array); } /// @@ -153,7 +145,7 @@ public ReadOnlySpan AsSpan() /// The newly instantiated array. public T[] ToArray() { - return AsImmutableArray().ToArray(); + return [.. AsSpan()]; } /// 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 b826c9b..eec140e 100644 --- a/src/PolySharp.SourceGenerators/PolyfillsGenerator.Polyfills.cs +++ b/src/PolySharp.SourceGenerators/PolyfillsGenerator.Polyfills.cs @@ -154,6 +154,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; } @@ -288,6 +295,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/src/PolySharp.SourceGenerators/PolyfillsGenerator.TypeForwards.cs b/src/PolySharp.SourceGenerators/PolyfillsGenerator.TypeForwards.cs index 2740694..afb6f35 100644 --- a/src/PolySharp.SourceGenerators/PolyfillsGenerator.TypeForwards.cs +++ b/src/PolySharp.SourceGenerators/PolyfillsGenerator.TypeForwards.cs @@ -17,7 +17,8 @@ partial class PolyfillsGenerator private static readonly ImmutableArray ModreqCandidateFullyQualifiedTypeNames = ImmutableArray.Create( "System.Index", "System.Range", - "System.Runtime.CompilerServices.IsExternalInit"); + "System.Runtime.CompilerServices.IsExternalInit", + "System.Runtime.CompilerServices.RequiresLocationAttribute"); /// /// Gets the types from the BCL that should potentially receive type forwards. diff --git a/tests/PolySharp.NuGet/PolySharp.NuGet.csproj b/tests/PolySharp.NuGet/PolySharp.NuGet.csproj index 9797912..6580709 100644 --- a/tests/PolySharp.NuGet/PolySharp.NuGet.csproj +++ b/tests/PolySharp.NuGet/PolySharp.NuGet.csproj @@ -1,7 +1,7 @@ - net472;net48;net481;netstandard2.0;net6.0;net7.0 + net472;net48;net481;netstandard2.0;net6.0;net7.0;net8.0 https://api.nuget.org/v3/index.json; ..\..\artifacts; diff --git a/tests/PolySharp.Tests/LanguageFeatures.cs b/tests/PolySharp.Tests/LanguageFeatures.cs index 498eb1b..b7fd966 100644 --- a/tests/PolySharp.Tests/LanguageFeatures.cs +++ b/tests/PolySharp.Tests/LanguageFeatures.cs @@ -1,4 +1,6 @@ using System; +using System.Collections; +using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.CompilerServices; using System.Runtime.Versioning; @@ -101,6 +103,15 @@ public void TakeRegex([StringSyntax(StringSyntaxAttribute.Regex)] string pattern public static void InitializeModule() { } + + public void RefReadonlyMethod(ref readonly int x) + { + } + + [Experimental("PS0001")] + public void ExperimentalMethod() + { + } } internal class TestClassWithRequiredMembers @@ -146,6 +157,30 @@ public static ReadOnlySpan TestRange(ReadOnlySpan numbers) } } +[CollectionBuilder(typeof(CollectionClass), nameof(Create))] +internal class CollectionClass : IEnumerable +{ + public CollectionClass Test() + { + return [1, 2, 3]; + } + + public static CollectionClass Create(ReadOnlySpan values) + { + return new(); + } + + IEnumerator IEnumerable.GetEnumerator() + { + return null!; + } + + IEnumerator IEnumerable.GetEnumerator() + { + return null!; + } +} + internal class AnotherTestClass { // CallerArgumentExpressionAttribute diff --git a/tests/PolySharp.Tests/PolySharp.Tests.csproj b/tests/PolySharp.Tests/PolySharp.Tests.csproj index 3a77e03..bce7973 100644 --- a/tests/PolySharp.Tests/PolySharp.Tests.csproj +++ b/tests/PolySharp.Tests/PolySharp.Tests.csproj @@ -1,7 +1,7 @@ - net472;net48;netstandard2.0;netstandard2.1;net6.0;net7.0 + net472;net48;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0 true diff --git a/tests/PolySharp.Tests/RuntimeSupport.cs b/tests/PolySharp.Tests/RuntimeSupport.cs index 211cfaa..a4593fb 100644 --- a/tests/PolySharp.Tests/RuntimeSupport.cs +++ b/tests/PolySharp.Tests/RuntimeSupport.cs @@ -84,4 +84,27 @@ public void MakeUpSomeNewType() public void ReferenceSomeAssemblyFile() { } +} + +internal class AccessorApis +{ +#pragma warning disable CS0169, IDE0044 + private int field; +#pragma warning restore CS0169, IDE0044 + + [StackTraceHidden] + 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 diff --git a/tests/PolySharp.TypeForwards.Tests/PolySharp.TypeForwards.Tests.csproj b/tests/PolySharp.TypeForwards.Tests/PolySharp.TypeForwards.Tests.csproj index a93070c..3b176d6 100644 --- a/tests/PolySharp.TypeForwards.Tests/PolySharp.TypeForwards.Tests.csproj +++ b/tests/PolySharp.TypeForwards.Tests/PolySharp.TypeForwards.Tests.csproj @@ -1,7 +1,7 @@ - net472;net48;net6.0;net7.0 + net472;net48;net6.0;net7.0;net8.0 $(NoWarn);CS1591 true @@ -11,9 +11,9 @@ - - - + + + diff --git a/tests/PolySharp.TypeForwards.Tests/TypeForwardTests.cs b/tests/PolySharp.TypeForwards.Tests/TypeForwardTests.cs index 8379ffe..a9990ef 100644 --- a/tests/PolySharp.TypeForwards.Tests/TypeForwardTests.cs +++ b/tests/PolySharp.TypeForwards.Tests/TypeForwardTests.cs @@ -1,4 +1,5 @@ using System; +using System.Linq; using System.Reflection; #if NET6_0_OR_GREATER using System.Runtime.CompilerServices; @@ -58,5 +59,32 @@ public void IsExternalInit_IsForwarded() #endif } + [TestMethod] + public void RequiresLocationAttribute_IsForwarded() + { + MethodInfo method = typeof(TypeForwardTests).GetMethod(nameof(MethodWithRefReadonlyParameter), BindingFlags.Static | BindingFlags.NonPublic)!; + ParameterInfo parameter = method.GetParameters()[0]; + CustomAttributeData attribute = parameter.CustomAttributes.Last(); + + Assert.AreEqual("System.Runtime.CompilerServices.RequiresLocationAttribute", attribute.AttributeType.FullName); + +#if NET8_0_OR_GREATER + Assert.AreEqual(typeof(object).Assembly, typeof(RequiresLocationAttribute).Assembly); + + string requiresLocationAttributeAssemblyName = typeof(RequiresLocationAttribute).Assembly.GetName().Name!; + + // Verify the type has been forwarded correctly + Assert.AreEqual(requiresLocationAttributeAssemblyName, attribute.AttributeType.Assembly.GetName().Name); + Assert.AreEqual(requiresLocationAttributeAssemblyName, typeof(TypeForwardTests).Assembly.GetType("System.Runtime.CompilerServices.RequiresLocationAttribute")!.Assembly.GetName().Name); +#else + // If RequiresLocationAttribute is not available, it should be polyfilled in this project + Assert.AreEqual("PolySharp.TypeForwards.Tests", attribute.AttributeType.Assembly.GetName().Name); +#endif + } + private sealed record Person(string Name); + + private static void MethodWithRefReadonlyParameter(ref readonly int x) + { + } }