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

[API Proposal]: update API signatures to leverage ref readonly parameters #85911

Closed
Sergio0694 opened this issue May 8, 2023 · 10 comments · Fixed by #89736
Closed

[API Proposal]: update API signatures to leverage ref readonly parameters #85911

Sergio0694 opened this issue May 8, 2023 · 10 comments · Fixed by #89736
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.CompilerServices
Milestone

Comments

@Sergio0694
Copy link
Contributor

Sergio0694 commented May 8, 2023

Background and motivation

Note: supersedes #73608.

This issue tracks updating the signatures of all methods that can benefit from either the new ref readonly parameters (see dotnet/csharplang#6010), as well as the additional flexibility from the compiler allowing changes in ref-ness for method parameters without it being a breaking change (also see speclet at dotnet/csharplang#7165). Needs Roslyn changes first.

API Proposal

namespace System
{
    public static class Nullable
    {
-       public static ref readonly T GetValueRefOrDefaultRef<T>(in T? nullable) where T : struct;
+       public static ref readonly T GetValueRefOrDefaultRef<T>(ref readonly T? nullable) where T : struct;
    }

    public readonly ref struct ReadOnlySpan<T>
    {
-       public ReadOnlySpan(in T reference);
+       public ReadOnlySpan(ref readonly T reference);
    }
}

namespace System.Runtime.CompilerServices
{
    public static class Unsafe
    {
-       public static bool AreSame<T>(ref T left, ref T right);
+       public static bool AreSame<T>(ref readonly T left, ref readonly T right);
-       public static ref T AsRef<T>(in T source);
+       public static ref T AsRef<T>(ref readonly T source);
-       public static nint ByteOffset<T>(ref T origin, ref T target);
+       public static nint ByteOffset<T>(ref readonly T origin, ref readonly T target);
-       public static void Copy<T>(void* destination, ref T source);
+       public static void Copy<T>(void* destination, ref readonly T source);
-       public static void CopyBlock(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount);
-       public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlockUnaligned(ref byte destination, ref readonly byte source, uint byteCount);
-       public static bool IsAddressGreaterThan<T>(ref T left, ref T right);
+       public static bool IsAddressGreaterThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsAddressLessThan<T>(ref T left, ref T right);
+       public static bool IsAddressLessThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsNullRef<T>(ref T source);
+       public static bool IsNullRef<T>(ref readonly T source);
-       public static T ReadUnaligned<T>(ref byte source);
+       public static T ReadUnaligned<T>(ref readonly byte source);
    }
}

namespace namespace System.Runtime.InteropServices
{
    public static class Marshal
    {
-       public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+       public static int QueryInterface(IntPtr pUnk, in Guid iid, out IntPtr ppv);
    }

    public static class MemoryMarshal
    {
-       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length);
+       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref readonly T reference, int length);
-       public static unsafe void Write<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe void Write<T>(Span<byte> destination, in T value) where T : struct;
-       public static unsafe bool TryWrite<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe bool TryWrite<T>(Span<byte> destination, in T value) where T : struct;
    }
}

namespace System.Threading
{
    public static class Volatile
    {
-       public static bool Read(ref bool location);
+       public static bool Read(ref readonly bool location);
-       public static byte Read(ref byte location);
+       public static byte Read(ref readonly byte location);
-       public static double Read(ref double location);
+       public static double Read(ref readonly double location);
-       public static short Read(ref short location);
+       public static short Read(ref readonly short location);
-       public static int Read(ref int location);
+       public static int Read(ref readonly int location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
-       public static IntPtr Read(ref IntPtr location);
+       public static IntPtr Read(ref readonly IntPtr location);
-       public static sbyte Read(ref sbyte location);
+       public static sbyte Read(ref readonly sbyte location);
-       public static float Read(ref float location);
+       public static float Read(ref readonly float location);
-       public static ushort Read(ref ushort location);
+       public static ushort Read(ref readonly ushort location);
-       public static uint Read(ref uint location);
+       public static uint Read(ref readonly uint location);
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static UIntPtr Read(ref UIntPtr location);
+       public static UIntPtr Read(ref readonly UIntPtr location);
-       public static T Read<T>(ref T location) where T : class?;
+       public static T Read<T>(ref readonly T location) where T : class?;
    }

    public static class Interlocked
    {
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
    }
}

namespace System.Numerics
{
    public static class Vector
    {
-       public static Vector<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

namespace System.Runtime.Intrinsics
{
    public static class Vector64
    {
-       public static Vector64<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector64<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector128
    {
-       public static Vector128<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector128<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector256
    {
-       public static Vector256<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector256<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector512
    {
-       public static Vector512<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector512<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

API Usage

For instance, easy QI with immediate values:

IntPtr pUnknown = GetPtr();

Marshal.ThrowExceptionForHR(Marshal.QueryInterface(pUnknown, new Guid("3718BE5F-F5A1-40CF-AF09-C4ECFD858A47"), out IntPtr pObject));

Or, writing immediates into spans:

Span<byte> bytes = GetSpan();

MemoryMarshal.Write(bytes, 128UL);

Or, loading vectors from readonly spans directly:

ReadOnlySpan<int> span = GetSpan();

Vector128<int> vector = Vector128.LoadUnsafe(in span[0]);

There's of course lots more examples (see API changes above).

@Sergio0694 Sergio0694 added the api-suggestion Early API idea and discussion, it is NOT ready for implementation label May 8, 2023
@dotnet-issue-labeler dotnet-issue-labeler bot added the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label May 8, 2023
@ghost ghost added the untriaged New issue has not been triaged by the area owner label May 8, 2023
@stephentoub
Copy link
Member

This isn't actionable at present.

@Sergio0694
Copy link
Contributor Author

Yup, same as #85910, needs Roslyn changes first (I mentioned this in the introduction paragraph as well). I just had the list already from working on the language proposal, so figured I'd open this for tracking and to have a central place where we could start adding any APIs that'd need changes, so when the Roslyn changes go online we have the list ready for API review 🙂

@teo-tsirpanis
Copy link
Contributor

I don't think we should use ref readonly on ReadOnlySpan's constructor. It can sometimes be useful to create a span from an rvalue (it will be a compiler error if you return that span but still...).

@tannergooding
Copy link
Member

AFAIR, there was a fairly decent discussion in API review when ReadOnlySpan(in T value) was exposed and we had come to a general decision at that time.

That being said, going from in to ref readonly is a source breaking change and so its a case that needs more consideration.

Going from ref to ref readonly is safe given the proposed language semantics for the feature.

@ghost
Copy link

ghost commented May 8, 2023

Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices
See info in area-owners.md if you want to be subscribed.

Issue Details

Background and motivation

Note: supersedes #73608.

This issue tracks updating the signatures of all methods that can benefit from either the new ref readonly parameters (see dotnet/csharplang#6010), as well as the additional flexibility from the compiler allowing changes in ref-ness for method parameters without it being a breaking change (also see speclet at dotnet/csharplang#7165). Needs Roslyn changes first.

API Proposal

namespace System
{
    public static class Nullable
    {
-       public static ref readonly T GetValueRefOrDefaultRef<T>(in T? nullable) where T : struct;
+       public static ref readonly T GetValueRefOrDefaultRef<T>(ref readonly T? nullable) where T : struct;
    }

    public readonly ref struct ReadOnlySpan<T>
    {
-       public ReadOnlySpan(in T reference);
+       public ReadOnlySpan(ref readonly T reference);
    }
}

namespace System.Runtime.CompilerServices
{
    public static class Unsafe
    {
-       public static bool AreSame<T>(ref T left, ref T right);
+       public static bool AreSame<T>(ref readonly T left, ref readonly T right);
-       public static ref T AsRef<T>(in T source);
+       public static ref T AsRef<T>(ref readonly T source);
-       public static nint ByteOffset<T>(ref T origin, ref T target);
+       public static nint ByteOffset<T>(ref readonly T origin, ref readonly T target);
-       public static void Copy<T>(void* destination, ref T source);
+       public static void Copy<T>(void* destination, ref readonly T source);
-       public static void CopyBlock(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount);
-       public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlockUnaligned(ref byte destination, ref readonly byte source, uint byteCount);
-       public static bool IsAddressGreaterThan<T>(ref T left, ref T right);
+       public static bool IsAddressGreaterThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsAddressLessThan<T>(ref T left, ref T right);
+       public static bool IsAddressLessThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsNullRef<T>(ref T source);
+       public static bool IsNullRef<T>(ref readonly T source);
-       public static T ReadUnaligned<T>(ref byte source);
+       public static T ReadUnaligned<T>(ref readonly byte source);
    }
}

namespace namespace System.Runtime.InteropServices
{
    public static class Marshal
    {
-       public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+       public static int QueryInterface(IntPtr pUnk, in Guid iid, out IntPtr ppv);
    }

    public static class MemoryMarshal
    {
-       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length);
+       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref readonly T reference, int length);
-       public static unsafe void Write<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe void Write<T>(Span<byte> destination, in T value) where T : struct;
-       public static unsafe bool TryWrite<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe bool TryWrite<T>(Span<byte> destination, in T value) where T : struct;
    }
}

namespace System.Threading
{
    public static class Volatile
    {
-       public static bool Read(ref bool location);
+       public static bool Read(ref readonly bool location);
-       public static byte Read(ref byte location);
+       public static byte Read(ref readonly byte location);
-       public static double Read(ref double location);
+       public static double Read(ref readonly double location);
-       public static short Read(ref short location);
+       public static short Read(ref readonly short location);
-       public static int Read(ref int location);
+       public static int Read(ref readonly int location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
-       public static IntPtr Read(ref IntPtr location);
+       public static IntPtr Read(ref readonly IntPtr location);
-       public static sbyte Read(ref sbyte location);
+       public static sbyte Read(ref readonly sbyte location);
-       public static float Read(ref float location);
+       public static float Read(ref readonly float location);
-       public static ushort Read(ref ushort location);
+       public static ushort Read(ref readonly ushort location);
-       public static uint Read(ref uint location);
+       public static uint Read(ref readonly uint location);
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static UIntPtr Read(ref UIntPtr location);
+       public static UIntPtr Read(ref readonly UIntPtr location);
-       public static T Read<T>(ref T location) where T : class?;
+       public static T Read<T>(ref readonly T location) where T : class?;
    }

    public static class Interlocked
    {
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
    }
}

namespace System.Numerics
{
    public static class Vector
    {
-       public static Vector<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

namespace System.Runtime.Intrinsics
{
    public static class Vector64
    {
-       public static Vector64<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector64<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector128
    {
-       public static Vector128<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector128<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector256
    {
-       public static Vector256<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector256<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector512
    {
-       public static Vector512<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector512<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

API Usage

For instance, easy QI with immediate values:

IntPtr pUnknown = GetPtr();

Marshal.ThrowExceptionForHR(Marshal.QueryInterface(pUnknown, new Guid("3718BE5F-F5A1-40CF-AF09-C4ECFD858A47"), out IntPtr pObject));

Or, writing immediates into spans:

Span<byte> bytes = GetSpan();

MemoryMarshal.Write(bytes, 128UL);

Or, loading vectors from readonly spans directly:

ReadOnlySpan<int> span = GetSpan();

Vector128<int> vector = Vector128.LoadUnsafe(in span[0]);

There's of course lots more examples (see API changes above).

Author: Sergio0694
Assignees: -
Labels:

api-suggestion, area-System.Runtime.CompilerServices, untriaged, needs-area-label

Milestone: -

@jkotas jkotas removed the needs-area-label An area label is needed to ensure this gets routed to the appropriate area owners label May 8, 2023
@Sergio0694
Copy link
Contributor Author

Sergio0694 commented May 8, 2023

"going from in to ref readonly is a source breaking change"

It shouldn't be source breaking, given that in at the callsite is allowed (with no warning) for ref readonly parameters 🤔
It would start warning on callsites that had no annotation, but it's not a source breaking change per se I think.

@tannergooding
Copy link
Member

It's source breaking because in allows either M(in x) or M(5).

ref readonly allows M(in x) and disallows M(5). If its a "soft disallow" via a warning then that's better, but API review will need to make the decision on it then.

@hamarb123
Copy link
Contributor

If its a "soft disallow" via a warning then that's better, but API review will need to make the decision on it then.

@tannergooding It's a warning in the current spec. It's like this to allow it to be changed without any issues (other than a warning on likely unintended use). Doesn't necessarily mean we should use it for ROS's ctor, but it doesn't cause any issues other than a new warning, so it should be about whether we want it to take rvalues or not without a warning (I personally would think no, but that's up to API review).
Note that ROS's ctor is a specicific example as an API that could use ref readonly instead in the spec: https://github.com/dotnet/csharplang/pull/7165/files#diff-0a517138fd96236fac77ffa249dc25dd19240894877ddcd6d227bcb9a853d84dR35
https://github.com/dotnet/csharplang/pull/7165/files#diff-0a517138fd96236fac77ffa249dc25dd19240894877ddcd6d227bcb9a853d84dR43
(I don't know how to make a perma link to those 🙂)

@tannergooding tannergooding added api-ready-for-review API is ready for review, it is NOT ready for implementation and removed api-suggestion Early API idea and discussion, it is NOT ready for implementation untriaged New issue has not been triaged by the area owner labels May 18, 2023
@tannergooding
Copy link
Member

Marking as ready for review given the general syntax questions on the language side seem to have been resolved.

As with the corresponding attribute (#85910), keeping in future until the language feature gets closer to completion.

We can push update the milestone and push forward as/when needed.

@tannergooding tannergooding added this to the Future milestone May 18, 2023
@bartonjs
Copy link
Member

bartonjs commented Jul 6, 2023

Video

  • All of the ref to ref readonly seem fine with no further thought required. (Assuming readonly is appropriate to those members, which was not evaluated)
  • Changing ref to in or in to ref readonly could introduce problems for callers on an older compiler version. Since none of the API changes proposed are in NuGet packages, and we don't generally support old compilers against new SDK/Runtime versions, those concerns aren't manifest in these specific proposals.
namespace System
{
    public static class Nullable
    {
-       public static ref readonly T GetValueRefOrDefaultRef<T>(in T? nullable) where T : struct;
+       public static ref readonly T GetValueRefOrDefaultRef<T>(ref readonly T? nullable) where T : struct;
    }

    public readonly ref struct ReadOnlySpan<T>
    {
-       public ReadOnlySpan(in T reference);
+       public ReadOnlySpan(ref readonly T reference);
    }
}

namespace System.Runtime.CompilerServices
{
    public static class Unsafe
    {
-       public static bool AreSame<T>(ref T left, ref T right);
+       public static bool AreSame<T>(ref readonly T left, ref readonly T right);
-       public static ref T AsRef<T>(in T source);
+       public static ref T AsRef<T>(ref readonly T source);
-       public static nint ByteOffset<T>(ref T origin, ref T target);
+       public static nint ByteOffset<T>(ref readonly T origin, ref readonly T target);
-       public static void Copy<T>(void* destination, ref T source);
+       public static void Copy<T>(void* destination, ref readonly T source);
-       public static void CopyBlock(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlock(ref byte destination, ref readonly byte source, uint byteCount);
-       public static void CopyBlockUnaligned(ref byte destination, ref byte source, uint byteCount);
+       public static void CopyBlockUnaligned(ref byte destination, ref readonly byte source, uint byteCount);
-       public static bool IsAddressGreaterThan<T>(ref T left, ref T right);
+       public static bool IsAddressGreaterThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsAddressLessThan<T>(ref T left, ref T right);
+       public static bool IsAddressLessThan<T>(ref readonly T left, ref readonly T right);
-       public static bool IsNullRef<T>(ref T source);
+       public static bool IsNullRef<T>(ref readonly T source);
-       public static T ReadUnaligned<T>(ref byte source);
+       public static T ReadUnaligned<T>(ref readonly byte source);
    }
}

namespace namespace System.Runtime.InteropServices
{
    public static class Marshal
    {
-       public static int QueryInterface(IntPtr pUnk, ref Guid iid, out IntPtr ppv);
+       public static int QueryInterface(IntPtr pUnk, in Guid iid, out IntPtr ppv);
    }

    public static class MemoryMarshal
    {
-       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref T reference, int length);
+       public static ReadOnlySpan<T> CreateReadOnlySpan<T>(scoped ref readonly T reference, int length);
-       public static unsafe void Write<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe void Write<T>(Span<byte> destination, in T value) where T : struct;
-       public static unsafe bool TryWrite<T>(Span<byte> destination, ref T value) where T : struct;
+       public static unsafe bool TryWrite<T>(Span<byte> destination, in T value) where T : struct;
    }
}

namespace System.Threading
{
    public static class Volatile
    {
-       public static bool Read(ref bool location);
+       public static bool Read(ref readonly bool location);
-       public static byte Read(ref byte location);
+       public static byte Read(ref readonly byte location);
-       public static double Read(ref double location);
+       public static double Read(ref readonly double location);
-       public static short Read(ref short location);
+       public static short Read(ref readonly short location);
-       public static int Read(ref int location);
+       public static int Read(ref readonly int location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
-       public static IntPtr Read(ref IntPtr location);
+       public static IntPtr Read(ref readonly IntPtr location);
-       public static sbyte Read(ref sbyte location);
+       public static sbyte Read(ref readonly sbyte location);
-       public static float Read(ref float location);
+       public static float Read(ref readonly float location);
-       public static ushort Read(ref ushort location);
+       public static ushort Read(ref readonly ushort location);
-       public static uint Read(ref uint location);
+       public static uint Read(ref readonly uint location);
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static UIntPtr Read(ref UIntPtr location);
+       public static UIntPtr Read(ref readonly UIntPtr location);
-       public static T Read<T>(ref T location) where T : class?;
+       public static T Read<T>(ref readonly T location) where T : class?;
    }

    public static class Interlocked
    {
-       public static ulong Read(ref ulong location);
+       public static ulong Read(ref readonly ulong location);
-       public static long Read(ref long location);
+       public static long Read(ref readonly long location);
    }
}

namespace System.Numerics
{
    public static class Vector
    {
-       public static Vector<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

namespace System.Runtime.Intrinsics
{
    public static class Vector64
    {
-       public static Vector64<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector64<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector64<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector128
    {
-       public static Vector128<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector128<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector128<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector256
    {
-       public static Vector256<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector256<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector256<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }

    public static class Vector512
    {
-       public static Vector512<T> LoadUnsafe<T>(ref T source) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source) where T : struct;
-       public static Vector512<T> LoadUnsafe<T>(ref T source, nuint elementOffset) where T : struct;
+       public static Vector512<T> LoadUnsafe<T>(ref readonly T source, nuint elementOffset) where T : struct;
    }
}

@bartonjs bartonjs added api-approved API was approved in API review, it can be implemented and removed api-ready-for-review API is ready for review, it is NOT ready for implementation labels Jul 6, 2023
@ghost ghost added the in-pr There is an active PR which will close this issue when it is merged label Jul 31, 2023
@ghost ghost removed the in-pr There is an active PR which will close this issue when it is merged label Aug 2, 2023
@ghost ghost locked as resolved and limited conversation to collaborators Sep 2, 2023
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
api-approved API was approved in API review, it can be implemented area-System.Runtime.CompilerServices
Projects
None yet
Development

Successfully merging a pull request may close this issue.

7 participants