-
Notifications
You must be signed in to change notification settings - Fork 4.7k
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
Utilize the new ref readonly
language feature
#89736
Conversation
Note regarding the This serves as a reminder for when your PR is modifying a ref *.cs file and adding/modifying public APIs, please make sure the API implementation in the src *.cs file is documented with triple slash comments, so the PR reviewers can sign off that change. |
Tagging subscribers to this area: @dotnet/area-system-runtime-compilerservices Issue DetailsThis resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (
|
@@ -667,7 +667,7 @@ public static void Write<T>(void* destination, T value) | |||
// Mono:AsRef | |||
[NonVersionable] | |||
[MethodImpl(MethodImplOptions.AggressiveInlining)] | |||
public static ref T AsRef<T>(scoped in T source) | |||
public static ref T AsRef<T>(scoped ref readonly T source) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
For .NET 9, I think it may be worth a discussion in API review on whether we want more of Unsafe
to take ref readonly
.
The general consideration is that most APIs on Unsafe
are "unsafe" and many, such as Add
, do not actually mutate the contents of the ref
but rather simply adjust the ref
to point to a new address.
If we were to changes these APIs to be, for example, ref T Add(ref readonly T source, int elementOffset)
, then it basically has an implicit ref T AsRef<T>(ref readonly T source)
built in.
The benefit of this is that it reduces "clutter" and can improve readability of such Unsafe
code. Consider the simple case below:
- ref readonly T address = ref Unsafe.Add(ref Unsafe.AsRef(in source), (nint)elementOffset);
+ ref readonly T address = ref Unsafe.Add(in source, (nint)elementOffset);
The downside is that any Unsafe
operation can go from mutable
to immutable
ref and users could introduce a mutation by accident. This could be handled with an analyzer though, suggesting users preserve mutability/immutability when using Unsafe
and to insert Unsafe.AsRef
explicitly if it was intentional.
In an ideal world, we might have overloads that were ref T Add(ref T source, int offset)
and ref readonly T Add(ref readonly T source, int offset)
. However, we can't due to them both being T&
in IL. Alternatively we could request a language feature that basically says "I match the mutability of my input". Such a feature would also be beneficial for some ref returns. But an analyzer (potentially keyed off an attribute) seems like an acceptable solution to this problem instead and would be straightforward to implement
uint address = PrivateAddress; | ||
MemoryMarshal.Write(destination, ref address); | ||
MemoryMarshal.Write(destination, in address); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Should we change this to:
MemoryMarshal.Write(destination, PrivateAddress);
? Seems like the primary motivation behind changing the parameter from ref to in is so that it can use rvalues
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
We definitely can. I had just gone with the most straightforward set of changes to start since we're trying to land this in .NET 8
@@ -99,7 +99,7 @@ public bool TryFormat(Span<char> destination, out int charsWritten) | |||
if (destination.Length > 3) | |||
{ | |||
ulong true_val = BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul; // "True" | |||
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), ref true_val); | |||
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), in true_val); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Same here and elsewhere
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Meaning this?
MemoryMarshal.Write(MemoryMarshal.AsBytes(destination), BitConverter.IsLittleEndian ? 0x65007500720054ul : 0x54007200750065ul); // "True"
ece204e
to
fe0dbaf
Compare
fe0dbaf
to
6a0761a
Compare
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I approve of merging this in for RC1. It's a late-breaking language feature that we should adopt during the release, and the compiler produces compatible output.
Thanks for fielding this, @tannergooding. I've not reviewed the CI issues; please ensure those are known/tracked before merge.
CI issue is going to be unblocked by #89593, at which point this can rerun and then be mergeable. Basically just need the roslyn toolset to be "properly" ingested to ensure source build remains happy. |
A bit late now, but a nasty side-effect of this is that it makes with an up-to-date compiler but down-level lang-ver:
without an up-to-date compiler:
(which of course it can't be; we're calling At the time of writing, no devenv update is available on public preview that can use this feature, so: no (I have 17.8.0 Preview 1.0 currently) |
This resolves #85911. The dotnet/sdk currently has the same version of Roslyn inserted (
v4.8.0-1.23378.8
).This is broken into 3 main commits:
in
toref readonly
ref
toin
ref
toref readonly
As per the API review, none of these are binary breaking changes and none of these introduce new errors. However, users may see new warnings for two of the scenarios:
in
toref readonly
, users will now be asked to use in explicitlyref
toin
, users will now be asked to use in or no longer specify ref