Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add polyfills for .NET 9 attributes. #108

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .github/CONTRIBUTING.md
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

Thank you for your interest in contributing to **PolySharp**! Below you'll find some info on how to get started with the project.

> **NOTE:** it is highly recommended to carfully read the [README](/README.md) first to get a general understanding of the library.
> **NOTE:** it is highly recommended to carefully read the [README](/README.md) first to get a general understanding of the library.

## 🙋 Questions, bug reports, feature proposals

Expand Down
2 changes: 1 addition & 1 deletion Directory.Build.props
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project>
<PropertyGroup>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<LangVersion>12.0</LangVersion>
<LangVersion>13</LangVersion>
<Nullable>enable</Nullable>
<TreatWarningsAsErrors>true</TreatWarningsAsErrors>

Expand Down
9 changes: 8 additions & 1 deletion README.md
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ Here's an example of some of the new features that **PolySharp** can enable down
- `[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))
- `[OverloadResolutionPriority]` (needed for [overload resolution priority](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13#overload-resolution-priority))
- `[ParamsCollection]` (needed for [params collection](https://learn.microsoft.com/en-us/dotnet/csharp/whats-new/csharp-13#params-collections))

To leverage them, make sure to bump your C# language version. You can do this by setting the `<LangVersion>` MSBuild property in your project. For instance, by adding `<LangVersion>12.0</LangVersion>` (or your desired C# version) to the first `<PropertyGroup>` 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.

Expand All @@ -64,7 +66,7 @@ It also includes the following optional runtime-supported polyfills:
- `[UnconditionalSuppressMessage]`
- `[RequiresAssemblyFiles]`
- `[StackTraceHidden]` (see [here](https://makolyte.com/csharp-exclude-exception-throw-helper-methods-from-the-stack-trace/))
- `[UnmanagedCallersOnly]` (see [docs](https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute)))
- `[UnmanagedCallersOnly]` (see [docs](https://learn.microsoft.com/dotnet/api/system.runtime.interopservices.unmanagedcallersonlyattribute))
- Platform support annotation attributes (see [docs](https://learn.microsoft.com/dotnet/standard/analyzers/platform-compat-analyzer)):
- `[ObsoletedOSPlatform]`
- `[SupportedOSPlatform]`
Expand All @@ -76,6 +78,11 @@ It also includes the following optional runtime-supported polyfills:
- `[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))
- `[DisableUserUnhandledExceptions]` (see [here](https://github.com/dotnet/runtime/issues/103105))
- Attribute model for feature switches with trimming support (see [docs](https://learn.microsoft.com/en-us/dotnet/core/whats-new/dotnet-9/runtime#attribute-model-for-feature-switches-with-trimming-support)):
- `[FeatureGuard]`
- `[FeatureSwitchDefinition]`
- `[WasmImportLinkage]` (see [here](https://github.com/dotnet/runtime/pull/93823))

# Options ⚙️

Expand Down
2 changes: 1 addition & 1 deletion global.json
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
{
"sdk": {
"version": "8.0.100",
"version": "9.0.100-rc.1.24452.12",
"rollForward": "latestFeature",
"allowPrerelease": false
}
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
// <auto-generated/>
#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
{
/// <summary>
/// Indicates that the specified public static boolean get-only property
/// guards access to the specified feature.
/// </summary>
/// <remarks>
/// Analyzers can use this to prevent warnings on calls to code that is
/// annotated as requiring that feature, when the callsite is guarded by a
/// call to the property.
/// </remarks>
[global::System.AttributeUsage(global::System.AttributeTargets.Property, Inherited = false, AllowMultiple = true)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")]
internal sealed class FeatureGuardAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="FeatureGuardAttribute"/> class
/// with the specified feature type.
/// </summary>
/// <param name="featureType">
/// The type that represents the feature guarded by the property.
/// </param>
public FeatureGuardAttribute(Type featureType)
{
FeatureType = featureType;
}

/// <summary>
/// The type that represents the feature guarded by the property.
/// </summary>
public Type FeatureType { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
// <auto-generated/>
#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
{
/// <summary>
/// Indicates that the specified public static boolean get-only property
/// corresponds to the feature switch specified by name.
/// </summary>
/// <remarks>
/// IL rewriters and compilers can use this to substitute the return value
/// of the specified property with the value of the feature switch.
/// </remarks>
[global::System.AttributeUsage(global::System.AttributeTargets.Property, Inherited = false)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")]
internal sealed class FeatureSwitchDefinitionAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="FeatureSwitchDefinitionAttribute"/> class
/// with the specified feature switch name.
/// </summary>
/// <param name="switchName">
/// The name of the feature switch that provides the value for the specified property.
/// </param>
public FeatureSwitchDefinitionAttribute(string switchName)
{
SwitchName = switchName;
}

/// <summary>
/// The name of the feature switch that provides the value for the specified property.
/// </summary>
public string SwitchName { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
// <auto-generated/>
#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
{
/// <summary>
/// If a .NET Debugger is attached which supports the Debugger.BreakForUserUnhandledException(Exception) API,
/// this attribute will prevent the debugger from breaking on user-unhandled exceptions when the
/// exception is caught by a method with this attribute, unless BreakForUserUnhandledException is called.
/// </summary>
[global::System.AttributeUsage(global::System.AttributeTargets.Method)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")]
internal sealed class DebuggerDisableUserUnhandledExceptionsAttribute : Attribute
{
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
// <auto-generated/>
#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.InteropServices
{
/// <summary>
/// Specifies that the P/Invoke marked with this attribute should be linked in as a WASM import.
/// </summary>
/// <remarks>
/// See https://webassembly.github.io/spec/core/syntax/modules.html#imports.
/// </remarks>
[global::System.AttributeUsage(global::System.AttributeTargets.Method, Inherited = false)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
[global::System.Diagnostics.Conditional("MULTI_TARGETING_SUPPORT_ATTRIBUTES")]
internal sealed class WasmImportLinkageAttribute : Attribute
{
/// <summary>
/// Instance constructor.
/// </summary>
public WasmImportLinkageAttribute() { }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
// <auto-generated/>
#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
{
/// <summary>
/// Specifies the priority of a member in overload resolution. When unspecified, the default priority is 0.
/// </summary>
[global::System.AttributeUsage(
global::System.AttributeTargets.Method |
global::System.AttributeTargets.Constructor |
global::System.AttributeTargets.Property,
AllowMultiple = false,
Inherited = false)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal sealed class OverloadResolutionPriorityAttribute : Attribute
{
/// <summary>
/// Initializes a new instance of the <see cref="OverloadResolutionPriorityAttribute"/> class.
/// </summary>
/// <param name="priority">The priority of the attributed member. Higher numbers are prioritized, lower numbers are deprioritized. 0 is the default if no attribute is present.</param>
public OverloadResolutionPriorityAttribute(int priority)
{
Priority = priority;
}

/// <summary>
/// The priority of the member.
/// </summary>
public int Priority { get; }
}
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
// <auto-generated/>
#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
{
/// <summary>
/// Indicates that a method will allow a variable number of arguments in its invocation.
/// </summary>
[global::System.AttributeUsage(global::System.AttributeTargets.Parameter, Inherited = true, AllowMultiple = false)]
[global::System.Diagnostics.CodeAnalysis.ExcludeFromCodeCoverage]
internal sealed class ParamCollectionAttribute : Attribute
{
}
}
31 changes: 29 additions & 2 deletions tests/PolySharp.Tests/LanguageFeatures.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,7 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Runtime.CompilerServices;
using System.Runtime.Versioning;
Expand Down Expand Up @@ -121,6 +122,8 @@ internal class TestClassWithRequiredMembers
public TestClassWithRequiredMembers()
{
Name = "";
// Dummy piece of code to not trigger IDE0290 (use primary constructor)
Debug.Assert(Name is not null);
}

// CompilerFeatureRequiredAttribute, RequiredMemberAttribute
Expand Down Expand Up @@ -160,11 +163,17 @@ public static ReadOnlySpan<int> TestRange(ReadOnlySpan<int> numbers)
[CollectionBuilder(typeof(CollectionClass), nameof(Create))]
internal class CollectionClass : IEnumerable<int>
{
public CollectionClass Test()
public static CollectionClass Test()
{
Test2(1, 2, 3);
return [1, 2, 3];
}

public static void Test2(params CollectionClass collection)
{

}

public static CollectionClass Create(ReadOnlySpan<int> values)
{
return new();
Expand Down Expand Up @@ -258,4 +267,22 @@ public void Start<TStateMachine>(ref TStateMachine stateMachine)
}
}

#endif
#endif

internal static class OverloadResolutionPriorityTests
{
public static void Test()
{
TestOverload(1);
}

[Obsolete("Do not use", error: true)]
[OverloadResolutionPriority(-1)]
public static void TestOverload(int x)
{
}

public static void TestOverload(int x, int y = 0)
{
}
}
2 changes: 1 addition & 1 deletion tests/PolySharp.Tests/PolySharp.Tests.csproj
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<TargetFrameworks>net472;net48;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0</TargetFrameworks>
<TargetFrameworks>net472;net48;netstandard2.0;netstandard2.1;net6.0;net7.0;net8.0;net9.0</TargetFrameworks>
<PolySharpIncludeRuntimeSupportedAttributes>true</PolySharpIncludeRuntimeSupportedAttributes>
</PropertyGroup>

Expand Down