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

Mark the new tensor APIs as experimental for .NET 9 #105268

Merged
merged 7 commits into from
Jul 24, 2024
Merged
Show file tree
Hide file tree
Changes from 6 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
17 changes: 17 additions & 0 deletions docs/project/list-of-diagnostics.md
Original file line number Diff line number Diff line change
Expand Up @@ -276,3 +276,20 @@ The diagnostic id values reserved for .NET Libraries analyzer warnings are `SYSL
| __`SYSLIBSUPPRESS0001`__ | CA1822 | Do not offer to make methods static when the methods need to be instance methods for a custom marshaller shape. |
| __`SYSLIBSUPPRESS0002`__ | IL2026 | ConfigurationBindingGenerator: suppress RequiresUnreferencedCode diagnostic for binding call that has been intercepted by a generated static variant. |
| __`SYSLIBSUPPRESS0003`__ | IL3050 | ConfigurationBindingGenerator: suppress RequiresDynamicCode diagnostic for binding call that has been intercepted by a generated static variant. |

## Experimental APIs

APIs can be marked as `[Experimental]` if their shape or functionality is included in a release but not yet officially supported. Experimental APIs offer the opportunity to collect customer feedback on these APIs in a major release, usually refining the APIs and removing the `[Experimental]` attribute in the next release. The `[Experimental]` attribute differs from `[RequiresPreviewFeatures]`, wherein:

* `[RequiresPreviewFeatures]` APIs require a corresponding preview feature in another product area such as the compiler or SDK
* `[Experimental]` APIs are entirely self-contained within the libraries and do not require preview features in other parts of the product

The diagnostic id values reserved for experimental APIs are `SYSLIB5001` through `SYSLIB5999`. When marking an API as `[Experimental]`, claim the next three-digit identifier in the `SYSLIB5###` sequence and add it to the list below. The URL template for all experimental APIs is `https://aka.ms/dotnet-warnings/{0}`. The `{0}` placeholder is replaced by the compiler with the `SYSLIB5###` identifier.

### Experimental Diagnostics (`SYSLIB5001` - `SYSLIB5999`)

Diagnostic id values for experimental APIs must not be recycled, as that could silently opt customers into new experimental APIs where they had previously suppressed the ID for a previous usage of the value.

| Diagnostic ID | Introduced | Removed | Description |
| :---------------- | ---------: | ------: | :---------- |
| __`SYSLIB5001`__ | .NET 9 | TBD | `Tensor<T>` and related APIs in System.Numerics.Tensors are experimental in .NET 9 |
25 changes: 25 additions & 0 deletions src/libraries/Common/src/System/Experimentals.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,25 @@
// Licensed to the .NET Foundation under one or more agreements.
// The .NET Foundation licenses this file to you under the MIT license.

namespace System
{
internal static class Experimentals
{
internal const string SharedUrlFormat = "https://aka.ms/dotnet-warnings/{0}";

// Please see docs\project\list-of-diagnostics.md for instructions on the steps required
// to introduce an experimental API, claim a diagnostic id, and ensure the
// "aka.ms/dotnet-warnings/{0}" URL points to documentation for the API.
// The diagnostic IDs reserved for experimental APIs are SYSLIB5### (SYSLIB5001 - SYSLIB5999).

// When an API is no longer marked as experimental, the diagnostic ID should be removed from this file
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If we're using the markdown file as the source of truth for claiming new diagnostic IDs, what's the need for also consolidating them in source? IIRC we don't do this for other diagnostics.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We do this with Obsoletions as well. I assert that it has helped keep the process discoverable and consistent.

// but retained in the table in docs\project\list-of-diagnostics.md to prevent reuse. Be sure to remove
// suppressions from the codebase as well.

// Tensor<T> and related APIs are marked as [Experimental] in .NET 9
internal const string TensorTDiagId = "SYSLIB5001";

// When adding a new diagnostic ID, add it to the table in docs\project\list-of-diagnostics.md as well.
// Keep new const identifiers above this comment.
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@

namespace System.Buffers
{
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public readonly partial struct NIndex : System.IEquatable<System.Buffers.NIndex>
{
private readonly int _dummyPrimitive;
Expand All @@ -29,6 +30,7 @@ namespace System.Buffers
public System.Index ToIndexUnchecked() { throw null; }
public override string ToString() { throw null; }
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public readonly partial struct NRange : System.IEquatable<System.Buffers.NRange>
{
private readonly int _dummyPrimitive;
Expand All @@ -53,6 +55,7 @@ namespace System.Buffers
}
namespace System.Numerics.Tensors
{
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable where TSelf : System.Numerics.Tensors.IReadOnlyTensor<TSelf, T>
{
static abstract TSelf? Empty { get; }
Expand Down Expand Up @@ -80,6 +83,7 @@ public partial interface IReadOnlyTensor<TSelf, T> : System.Collections.Generic.
bool TryCopyTo(scoped System.Numerics.Tensors.TensorSpan<T> destination);
bool TryFlattenTo(scoped System.Span<T> destination);
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public partial interface ITensor<TSelf, T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor<TSelf, T> where TSelf : System.Numerics.Tensors.ITensor<TSelf, T>
{
bool IsReadOnly { get; }
Expand All @@ -98,6 +102,7 @@ public partial interface ITensor<TSelf, T> : System.Collections.Generic.IEnumera
void Fill(T value);
new ref T GetPinnableReference();
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public readonly ref partial struct ReadOnlyTensorSpan<T>
{
private readonly object _dummy;
Expand Down Expand Up @@ -157,6 +162,7 @@ public ref partial struct Enumerator
public bool MoveNext() { throw null; }
}
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public static partial class Tensor
{
public static System.Numerics.Tensors.Tensor<T> Abs<T>(in System.Numerics.Tensors.ReadOnlyTensorSpan<T> x) where T : System.Numerics.INumberBase<T> { throw null; }
Expand Down Expand Up @@ -674,6 +680,7 @@ public static void Truncate<T>(System.ReadOnlySpan<T> x, System.Span<T> destinat
public static void Xor<T>(System.ReadOnlySpan<T> x, System.ReadOnlySpan<T> y, System.Span<T> destination) where T : System.Numerics.IBitwiseOperators<T, T, T> { }
public static void Xor<T>(System.ReadOnlySpan<T> x, T y, System.Span<T> destination) where T : System.Numerics.IBitwiseOperators<T, T, T> { }
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public readonly ref partial struct TensorSpan<T>
{
private readonly object _dummy;
Expand Down Expand Up @@ -735,6 +742,7 @@ public ref partial struct Enumerator
public bool MoveNext() { throw null; }
}
}
[System.Diagnostics.CodeAnalysis.Experimental("SYSLIB5001", UrlFormat = "https://aka.ms/dotnet-warnings/{0}")]
public sealed partial class Tensor<T> : System.Collections.Generic.IEnumerable<T>, System.Collections.IEnumerable, System.Numerics.Tensors.IReadOnlyTensor<System.Numerics.Tensors.Tensor<T>, T>, System.Numerics.Tensors.ITensor<System.Numerics.Tensors.Tensor<T>, T>
{
internal Tensor() { }
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,12 +7,15 @@
<PackageDescription>Provides support for operating over tensors.</PackageDescription>
<GenAPIExcludeApiList>ReferenceAssemblyExclusions.txt</GenAPIExcludeApiList>
<ApiCompatValidateAssemblies>true</ApiCompatValidateAssemblies>
<!-- SYSLIB5001: Tensor<T> and related APIs are Experimental in .NET 9 -->
<NoWarn>$(NoWarn);SYSLIB5001</NoWarn>
</PropertyGroup>

<ItemGroup>
<Compile Include="System\Numerics\Tensors\TensorPrimitives.Single.cs" />
<Compile Include="System\Numerics\Tensors\TensorPrimitives.Helpers.cs" />
<Compile Include="System\ThrowHelper.cs" />
<Compile Include="$(CommonPath)System\Experimentals.cs" Link="Common\System\Experimentals.cs" />
</ItemGroup>

<ItemGroup Condition="'$(TargetFrameworkIdentifier)' == '.NETCoreApp'">
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Numerics.Tensors/src/System/NIndex.cs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ namespace System.Buffers
/// int lastElement = someArray[^1]; // lastElement = 5
/// </code>
/// </remarks>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public readonly struct NIndex : IEquatable<NIndex>
{
private readonly nint _value;
Expand Down
1 change: 1 addition & 0 deletions src/libraries/System.Numerics.Tensors/src/System/NRange.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,6 +15,7 @@ namespace System.Buffers
/// int[] subArray2 = someArray[1..^0]; // { 2, 3, 4, 5 }
/// </code>
/// </remarks>
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public readonly struct NRange : IEquatable<NRange>
{
/// <summary>Represent the inclusive start NIndex of the NRange.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

namespace System.Numerics.Tensors
{
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface IReadOnlyTensor<TSelf, T> : IEnumerable<T>
where TSelf : IReadOnlyTensor<TSelf, T>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,11 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Buffers;
using System.Diagnostics.CodeAnalysis;

namespace System.Numerics.Tensors
{
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public interface ITensor<TSelf, T>
: IReadOnlyTensor<TSelf, T>
where TSelf : ITensor<TSelf, T>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace System.Numerics.Tensors
/// </summary>
[DebuggerTypeProxy(typeof(TensorSpanDebugView<>))]
[DebuggerDisplay("{ToString(),raw}")]
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public readonly ref struct ReadOnlyTensorSpan<T>
{
/// <summary>A byref or a native ptr.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Collections.Generic;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;
using Microsoft.VisualBasic;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,7 @@
using System.Collections;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection.Metadata.Ecma335;
using System.Runtime.CompilerServices;
Expand All @@ -17,6 +18,7 @@

namespace System.Numerics.Tensors
{
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public sealed class Tensor<T>
: ITensor<Tensor<T>, T>
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,12 +11,14 @@
using static System.Runtime.InteropServices.JavaScript.JSType;
using System.Security.Cryptography;
using System.Runtime.Serialization;
using System.Diagnostics.CodeAnalysis;

#pragma warning disable CS8601 // Possible null reference assignment.
#pragma warning disable CS8618 // Non-nullable field must contain a non-null value when exiting constructor. Consider declaring as nullable.

namespace System.Numerics.Tensors
{
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public static partial class Tensor
{
#region AsReadOnlySpan
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,11 +2,13 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Runtime.InteropServices;

namespace System.Numerics.Tensors
{
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why do we need to mark internal types?

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's just the way the analyzer currently works. Presumably to ensure that consumers of those internal types are also aware that its using experimental features

internal static class TensorHelpers
{

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,8 @@

namespace System.Numerics.Tensors
{

[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
internal readonly struct TensorShape
{
// Used to determine when we need to allocate a metadata array
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ namespace System.Numerics.Tensors
/// </summary>
[DebuggerTypeProxy(typeof(TensorSpanDebugView<>))]
[DebuggerDisplay("{ToString(),raw}")]
[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
public readonly ref struct TensorSpan<T>
{
/// <summary>A byref or a native ptr.</summary>
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,12 @@
// The .NET Foundation licenses this file to you under the MIT license.

using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;

namespace System.Numerics.Tensors
{

[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
internal sealed class TensorSpanDebugView<T>
{
private readonly T[] _array;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -4,12 +4,15 @@
using System.Buffers;
using System.Collections.Specialized;
using System.Diagnostics;
using System.Diagnostics.CodeAnalysis;
using System.Linq;
using System.Reflection;
using System.Runtime.CompilerServices;

namespace System.Numerics.Tensors
{

[Experimental(Experimentals.TensorTDiagId, UrlFormat = Experimentals.SharedUrlFormat)]
internal static partial class TensorSpanHelpers
{
internal static bool AreShapesTheSame<T>(ReadOnlyTensorSpan<T> tensor1, ReadOnlyTensorSpan<T> tensor2)
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,8 @@
<PropertyGroup>
<TargetFrameworks>$(NetCoreAppCurrent);$(NetFrameworkMinimum)</TargetFrameworks>
<AllowUnsafeBlocks>true</AllowUnsafeBlocks>
<!-- SYSLIB5001: Tensor<T> and related APIs are Experimental in .NET 9 -->
<NoWarn>$(NoWarn);SYSLIB5001</NoWarn>
</PropertyGroup>

<PropertyGroup>
Expand Down
Loading