-
Notifications
You must be signed in to change notification settings - Fork 4.1k
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
Ref returns and Locals #8030
Ref returns and Locals #8030
Conversation
627fff2
to
eebffc4
Compare
@dotnet/roslyn-compiler @dotnet/roslyn-ide - could you take look? |
ping |
Notes to testers:
|
@dotnet-bot test prtest/win/dbg/unit32 please |
@dotnet-bot test prtest/lin/tst/unit32 please |
@dotnet-bot test prtest/win/dbg/unit64 please |
@dotnet-bot retest prtest/win/dbg/unit64 please |
If I've understood via quick code search correctly, there will need to be a public representation of the assignment ref kind added to IAssignmentExpression so that IOperation analyzers can differentiate between the two cases. cc @JohnHamby |
@nguerrera There are also ref returns. Not sure if you need to differentiate for those too. |
Close/open cycling this PR to try to get past the MakeConst failure |
@VSadov. Yes. Correct me if I'm wrong, but I believe |
@nguerrera - what I meant is the case inside a byref method or property getter where you do {
return ref arr[0];
} |
@VSadov Ah. Yes, I think there should be some indication of |
I think there is also an IOperation issue that there's no current way to make an IInvocationExptession into an IReferenceExpression for eligibility as LHS of assignment. |
… the current master.
member declaration parse should not be considered not advanced when "ref" keyword was consumed. Fixes dotnet#8402
Ideally EE should not encounter ByRef types, but for now I just make EE resilient if it sees them
The feature needs to be properly implemented taking into account that variable is byref. For now disabling this refactoring if variable happen to be byref to avoid crash as described in dotnet#8416
test prtest/mac/dbg/unit32 please |
I have probably missed the discussion, but why is ref int r = ref Find(numbers); It looks a bit confusing to me, like asking for a reference to the reference... why not ref int r = Find(numbers); only? |
Implementation of Ref returns and Ref locals
The original proposal and motivation for the feature is: #118
Ref locals and Ref returns
Ref locals and ref returns are generalizations of ref parameters in a sense that they do not get attached to a data slot automatically and instead can represent existing storage locations.
The goal is to allow abstracting in-place data from its actual storage (fields, arrays, slices) with minimum overhead. The targeted audience is the set of high performance scenarios where in-place update operations could be used to reduce unnecessary copying.
Ref locals
For the most part, ref locals behave just like regular locals. The most important difference is that
unlike regular locals, ref locals do not get a distinct storage location and instead can be ref-assigned an existing location.
In fact, due to definite assignment rules, a ref local must be ref-assigned before it can be used as a regular local.
To guarantee that references do not outlive referents, a "safe to return" rule is applied at the point of ref assignment and further propagated.
Ref returns
We would allow a function to indicate that its return value is a ref:
Just like ref arguments need to be explicitly annotated as such at the call site, ref return values must also be explicitly indicated in the return statement. This is a syntactic rule to ensure people are aware that they are trading in refs. A call to a ref-returning method is classified as a variable, and can therefore be assigned to.
It should be legal for a method to pass its own locals to a ref returning method, and get one of them back. However, we want to avoid a method returning a ref to one of its own locals. Technically, we could capture them and hoist them to the heap to enable this, just as we do for lambdas, but that defeats the purpose of being nimble and close to the metal.
Instead there are simple rules about which variables are “safe to return”, essentially ensuring that a method does not return its own variables:
• refs to variables on the heap are safe to return
• ref parameters are safe to return
• out parameters are safe to return (but must be assigned, as is already the case today)
• instance struct fields are safe to return as long as the receiver is safe to return
• “this” is not safe to return inside struct members
• a ref returned from another method is safe to return if all refs passed to that method as formal parameters were safe to return. (specifically it is irrelevant if receiver is safe to return, regardless whether receiver is a struct, class or typed as a generic type parameter)
The last rule works because the rules apply recursively to the invoked method as well.
Here is an example of what’s allowed and what’s not:
== Also in:
== Notes
Although the feature can be generalized to allow multiple re-assignments, it would complicate the feature, perhaps unnecessarily, so it is not currently allowed.