-
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
Make SourceClonedParameterSymbol abstract #54355
Make SourceClonedParameterSymbol abstract #54355
Conversation
5e45818
to
55b6ebe
Compare
@AlekseyTs This is ready for review. Thanks! |
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Show resolved
Hide resolved
Done with review pass (commit 1) |
|
||
internal override bool IsCallerMemberName => _originalParam.IsCallerMemberName; | ||
|
||
internal override int CallerArgumentExpressionParameterIndex => throw ExceptionUtilities.Unreachable; |
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.
@AlekseyTs The created parameter may not be optional as you stated in the other PR. However, I think this is still unreachable. We attempt to bind default arguments only if overload resolution succeeds.
If overload resolution succeeds, then an explicit value was passed to the parameter, meaning we are not going to access this property (I'm open to adding any test cases you'd like if the existing tests are not enough). #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.
If overload resolution succeeds, then an explicit value was passed to the parameter, meaning we are not going to access this property.
That maybe true for EndEnvoke (I assume because parameters are ref/out/in), but why this is true for BeginInvoke is not obvious to me.
I'm open to adding any test cases you'd like if the existing tests are not enough
I think we should have targeted test for Begin/EndInvoke invocations for scenarios when cloned parameters are optional and have the attribute on them.
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.
Both BeginInvoke
and EndInvoke
has extra parameter(s) at the end (AsyncCallBack
and object
for BeginInvoke
, and IAsyncResult
for EndInvoke
). If overload resolution succeeds, then these parameters must have been supplied, meaning all the previous parameters has explicitly been passed.
I'll add some tests.
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.
Both
BeginInvoke
andEndInvoke
has extra parameter(s) at the end (AsyncCallBack
andobject
forBeginInvoke
, andIAsyncResult
forEndInvoke
). If overload resolution succeeds, then these parameters must have been supplied, meaning all the previous parameters has explicitly been passed.
I see now why this is wrong.
@AlekseyTs This is ready for another look. Thanks! |
@@ -17,6 +17,142 @@ namespace Microsoft.CodeAnalysis.CSharp.UnitTests | |||
{ | |||
public class AttributeTests_CallerInfoAttributes : WellKnownAttributesTestBase | |||
{ | |||
[ConditionalFact(typeof(CoreClrOnly))] | |||
public void TestBeginInvoke() |
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.
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Outdated
Show resolved
Hide resolved
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Outdated
Show resolved
Hide resolved
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Outdated
Show resolved
Hide resolved
Done with review pass (commit 2) |
…ssion' into caller-arg-cloned-param
class Program | ||
{ | ||
const string s1 = nameof(s1); | ||
delegate void D(ref string s1, [CallerArgumentExpression(s1)] [Optional] [DefaultParameterValue(""default"")] string s2); |
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.
[CallerArgumentExpression(s1)] [Optional] [DefaultParameterValue(""default"")] string s2
The interesting scenario is when this parameter is getting cloned and the one that it references isn't and probably follows it. Is this the case in this unit-test. We want to test scenario where simply reusing the index from the original parameter will be observably wrong. #Closed
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.
The interesting scenario is when this parameter is getting cloned and the one that it references isn't
For the parameter to get cloned, it must be ref
if I understand correctly. ref
parameters seem to have a false IsOptional
. Hence, the test won't hit calling CallerArgumentExpressionIndex
. This is regardless we're in error case or not.
I think the test you're asking for should hit CallerArgumentExpressionIndex
. I'm unable to find a test case that fulfills all the following:
- The
CallerArgumentExpression
parameter is cloned. - The parameter it refers to isn't cloned.
CallerArgumentExpressionIndex
gets hit.
I added a test that fulfills 1 and 2.
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 the parameter to get cloned, it must be ref if I understand correctly. ref parameters seem to have a false IsOptional. Hence, the test won't hit calling CallerArgumentExpressionIndex. This is regardless we're in error case or not.
We still can have a test attempting to do that. Trying all possible ways marking the parameter optional, attempting to ommit it at the call-site. It is fine if we will be unable to hit the API. We still need tests that attempt to do that.
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.
@AlekseyTs I added a test in 25dd0ff, and added two more now in 8ee88e0. Let me know if there are any other scenarios :)
Done with review pass (commit 6) |
class Program | ||
{ | ||
const string s2 = nameof(s2); | ||
delegate void D([CallerArgumentExpression(s2)] [Optional] [DefaultParameterValue(""default"")] ref string s1, string s2); |
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.
{ | ||
D d = M; | ||
string s = string.Empty; | ||
d.EndInvoke(ref s, null); |
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.
{ | ||
D d = M; | ||
string s = string.Empty; | ||
d.EndInvoke(ref s, null); |
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 with review pass (commit 10) |
|
Pinging @AlekseyTs and @333fred for review. Thanks! |
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Show resolved
Hide resolved
"; | ||
|
||
var compilation = CreateCompilation(source, targetFramework: TargetFramework.NetCoreApp, options: TestOptions.ReleaseExe, parseOptions: TestOptions.RegularPreview); | ||
// Begin/EndInvoke are not currently supported. |
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.
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.
@333fred No, I meant "supported by the compiler". ie, the compiler doesn't do anything for caller argument expressions for cloned begin/end invoke parameters.
Done review pass (commit 11). Only a few small comments for clarifications. |
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Outdated
Show resolved
Hide resolved
…nedParameterSymbolForBeginAndEndInvoke.cs
...rs/CSharp/Portable/Symbols/Source/SourceDelegateClonedParameterSymbolForBeginAndEndInvoke.cs
Outdated
Show resolved
Hide resolved
…nedParameterSymbolForBeginAndEndInvoke.cs
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 (commit 13). @dotnet/roslyn-compiler for a second review.
@jcouv Can you review please? Thanks! |
Ping @jcouv |
{ | ||
} | ||
|
||
internal override bool IsCallerFilePath => _originalParam.IsCallerFilePath; |
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 didn't understand why properties that are implemented the same way in SourceDelegateClonedParameterSymbolForBeginAndEndInvoke
and SourcePropertyClonedParameterSymbolForAccessors
were moved out of the base type.
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.
@jcouv This was requested by @AlekseyTs. The reasoning is to force new types to implement it. i.e, avoid future mistakes if a new type should implement it another way.
IL_001e: ret | ||
} | ||
"); | ||
} |
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.
It looks like the added tests cover delegate scenarios. Do we already have scenarios for properties/indexers, since that's another scenario that uses SourceClonedParameterSymbol
?
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.
@jcouv There is a test for indexer:
roslyn/src/Compilers/CSharp/Test/Emit/Attributes/AttributeTests_CallerInfoAttributes.cs
Line 1685 in 63531dc
public void TestIndexers() |
Let me know if you want to extend the tests with any scenarios.
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.
Awesome, thanks
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 with review pass (iteration 13). Just a couple of questions
Also it occurred to me that we'll want to think of possible interactions between CallerArgumentExpression and interpolated string handlers. |
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 13)
Clarified from chat with Fred. Here's possible scenario (may just fall out): |
Builds on #54132 (I'll rebase once the other PR goes in).I think there is no need to wait on the other PR. Going to rebase on the current feature branch.@AlekseyTs Let me know if you want the other PR to contain everything.
Proposal: dotnet/csharplang#287
Test plan: #52745