-
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
Do not copy nullable value type receiver of a constrained call. #66311
Conversation
The check that we used to detect value types at runtime didn’t quite work for nullable value types due to special boxing behavior for them. Switching to `typeof(T).IsValueType` check instead. Fixes dotnet#66162. Related to dotnet#63221.
@dotnet/roslyn-compiler Please review |
FWIW, I took a look (trying to understand the problem in the bug and how it was resolved), but couldn't figure it out after 20 minutes so I'm leaving it for someone else or if some more context could be provided (what's wrong with the IL from In reply to: 1376375491 |
If you look at the IL diff for affected tests, you'll notice that the change replaces sequences like
with sequences like:
These IL sequences produce the same result for all types, but for nullable value types. There is a special boxing behavior for nullable value types, boxing of a default value of a nullable value type yields null. Therefore, the old IL is not going to jump for a nullable value type, but instead going to fall through to the code that is supposed to be executed only for a class. That is wrong because a nullable value type is a value type. |
@@ -4579,6 +4579,21 @@ internal enum AddressKind | |||
stackLocalsOpt)); | |||
goto case BoundKind.ConditionalReceiver; | |||
|
|||
case BoundKind.ComplexReceiver: |
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.
Can we reach this? I thought this node would only be introduced in a later phase (but not during initial binding). #Resolved
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.
Can we reach this? I thought this node would only be introduced in a later phase (but not during initial binding).
The same goes for BoundKind.ComplexConditionalReceiver
. Just follow the pattern.
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.
Why not throw unreachable exception since this is unreachable? I'd do that for ComplexConditionalReceiver
too
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.
Why not throw unreachable exception since this is unreachable? I'd do that for
ComplexConditionalReceiver
too
I am comfortable going as is
|
||
private void EmitComplexReceiver(BoundComplexReceiver expression, bool used) | ||
{ | ||
Debug.Assert(!used); |
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.
nit: What's the benefit of only asserting? Throwing seems better.
We can still keep the conditional AdjustStack
below for the day we could reach with here with used==true. #Resolved
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.
What's the benefit of only asserting? Throwing seems better.
The implementation is doing the right thing. I do not see any point in throwing. The assert will help us identify the test scenario.
We have a note in the compiler test plan: "If you add a new expression form that requires spilling, test it in the catch filter". Consider adding a test for this. In reply to: 1376544884 Refers to: src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs:30721 in 208dc2a. [](commit_id = 208dc2a, deletion_comment = False) |
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.
LGTM Thanks (iteration 1) with test suggestion to consider
@@ -2940,6 +2940,20 @@ public override BoundNode VisitComplexConditionalReceiver(BoundComplexConditiona | |||
return null; | |||
} | |||
|
|||
public override BoundNode VisitComplexReceiver(BoundComplexReceiver node) |
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.
Are any flow passes actually going to see one of these? It looks like they're only created during local lowering, so I wouldn't expected them to be seen. #Resolved
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.
Are any flow passes actually going to see one of these? It looks like they're only created during local lowering, so I wouldn't expected them to be seen.
This code path is reachable. Flow analysis is done during async rewrite, etc.
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.
Done review pass (commit 1)
I think that refers to language constructs that themselves trigger spilling, like async or patterns, and is not talking about new bound nodes. I am not adding anything like that. In reply to: 1376544884 Refers to: src/Compilers/CSharp/Test/Emit2/CodeGen/CodeGenCallTests.cs:30721 in 208dc2a. [](commit_id = 208dc2a, deletion_comment = False) |
…l." (#66407) Reverts #66311 due to dotnet/runtime#80429 (comment)
The check that we used to detect value types at runtime didn’t quite work for nullable value types due to special boxing behavior for them. Switching to
typeof(T).IsValueType
check instead.Fixes #66162.
Related to #63221.