Skip to content

Conversation

Copy link
Contributor

Copilot AI commented Dec 9, 2025

  • Add [OverloadResolutionPriority(1)] attribute to MemoryMarshal.AsRef<T>(Span<byte> span) in the implementation file (src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs)
  • Add [System.Runtime.CompilerServices.OverloadResolutionPriorityAttribute(1)] to the same method in the reference assembly file (src/libraries/System.Runtime/ref/System.Runtime.cs)
  • Add comment explaining purpose of OverloadResolutionPriority attribute
  • Add test validating that types with implicit Span conversion get mutable ref from AsRef
  • Verify that the library builds successfully
  • Verify that the existing tests pass (52,110 tests passed)
Original prompt

This section details on the original issue you should resolve

<issue_title>Increase priority of MemoryMarshal.AsRef(Span) with [OverloadResolutionPriority]</issue_title>
<issue_description>### Description

There is:

ref T AsRef<T>(Span<byte> span)
ref readonly T AsRef<T>(ReadOnlySpan<byte> span)

in System.Runtime.InteropServices.MemoryMarshal and I propose adding [OverloadResolutionPriority(1)] attribute to the AsRef<T>(Span<byte>) overload as follows:

[OverloadResolutionPriority(1)]
ref T AsRef<T>(Span<byte> span)

ref readonly T AsRef<T>(ReadOnlySpan<byte> span)

That would solve the issue described below.

Unfortunately, the usage of the first overload is impaired by changes from C# 14. I've described the issue here: dotnet/roslyn#81528 (comment) and have been told the change is intended.

Assuming we have:

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

Then, with C# 13 the following worked:

void M()
{
    // Overload AsRef<byte>(Span<byte>) is selected.
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

but with C# 14 following happens:

void M()
{
    // Does not compile. Overload AsRef<byte>(ReadOnlySpan<byte>) is selected, so `ref var` cannot be used.
    ref var r = ref MemoryMarshal.AsRef<byte>(x);

    // Compiles, but that's not what I want (I want 'ref var' and not 'ref readonly var').
    ref readonly var r2 = ref MemoryMarshal.AsRef<byte>(x);
}

The workaround is to use the explicit cast:

void M()
{
    // Compiles, but an explicit cast is needed to select the correct overload.
    ref var r = ref MemoryMarshal.AsRef<byte>((Span<byte>)x);
}

Reproduction Steps

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

void M()
{
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

Expected behavior

The following should compile with C# 14 (as it compiled with C# 13).

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

void M()
{
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

Actual behavior

The following does not compile with C# 14.

public struct MyStruct
{
    public static implicit operator Span<byte>(in MyStruct value) => default;
}

void M()
{
    ref var r = ref MemoryMarshal.AsRef<byte>(x);
}

Regression?

It worked with C# 13.

Known Workarounds

Use explicit cast (instead of implicit) to Span<byte>.

Configuration

No response

Other information

No response</issue_description>

<agent_instructions>Use the OverloadResolutionPriorityAttribute to prioritize the Span-based AsRef overload over the ReadOnlySpan-based overload, so that incoming spans result in mutable refs coming out. If any compilation issues emerge in consumers due to unforeseen consequences of making the change, abort, as this should only help to make more situations work and shouldn't introduce any compilation errors or ambiguities.</agent_instructions>

Comments on the Issue (you are @copilot in this section)


💬 We'd love your input! Share your thoughts on Copilot coding agent in our 2 minute survey.

…te>)

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copilot AI changed the title [WIP] Add OverloadResolutionPriority to MemoryMarshal.AsRef<T> Add [OverloadResolutionPriority(1)] to MemoryMarshal.AsRef(Span<byte>) Dec 9, 2025
Copilot AI requested a review from stephentoub December 9, 2025 02:34
@stephentoub
Copy link
Member

@copilot, please add a test based on the original issue. It should fail to compile prior to the fix and compile successfully after. Also, please add a succinct comment next to the ORPA attribute in the source indicating what it's there for / what problem it's solving.

…AsRef

Co-authored-by: stephentoub <2642209+stephentoub@users.noreply.github.com>
Copy link
Contributor Author

Copilot AI commented Dec 9, 2025

@copilot, please add a test based on the original issue. It should fail to compile prior to the fix and compile successfully after. Also, please add a succinct comment next to the ORPA attribute in th...

Added in 46b7492:

  • Comment next to the attribute explaining its purpose
  • Test AsRef_ImplicitSpanConversion_ReturnsMutableRef that uses a struct with implicit conversion to Span<byte> and validates that ref int value = ref MemoryMarshal.AsRef<int>(s) returns a mutable ref

Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

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

Pull request overview

This PR adds the [OverloadResolutionPriority(1)] attribute to the MemoryMarshal.AsRef<T>(Span<byte>) method to prioritize it over the AsRef<T>(ReadOnlySpan<byte>) overload during overload resolution. This resolves a C# 14 regression where types with implicit Span<byte> conversions would incorrectly resolve to the ReadOnlySpan<byte> overload, preventing mutable references from being obtained.

  • Added [OverloadResolutionPriority(1)] attribute to the Span<byte> overload in both implementation and reference assemblies
  • Added explanatory comments documenting the purpose of the attribute
  • Added comprehensive test validating that types with implicit Span<byte> conversion correctly obtain mutable references

Reviewed changes

Copilot reviewed 3 out of 3 changed files in this pull request and generated no comments.

File Description
src/libraries/System.Private.CoreLib/src/System/Runtime/InteropServices/MemoryMarshal.cs Added [OverloadResolutionPriority(1)] attribute with explanatory comment to the AsRef<T>(Span<byte>) method
src/libraries/System.Runtime/ref/System.Runtime.cs Added [OverloadResolutionPriorityAttribute(1)] to the AsRef<T>(Span<byte>) method signature in the reference assembly
src/libraries/System.Memory/tests/MemoryMarshal/AsRef.cs Added test validating that types with implicit Span<byte> conversion return mutable references through AsRef

Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

While in general we wanted ROS prioritized because of array covariance causing potential breaks, we're dealing with bytes here that's not an issue. Therefore, it seems fine to me.

@stephentoub
Copy link
Member

While in general we wanted ROS prioritized because of array covariance causing potential breaks, we're dealing with bytes here that's not an issue. Therefore, it seems fine to me.

Thanks. Not bytes necessarily, but the T is constrained to be a value type, so same argument applies.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Increase priority of MemoryMarshal.AsRef<T>(Span<T>) with [OverloadResolutionPriority]

3 participants