Skip to content
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

Simplify and reduce amount of work performed by SourcePropertySymbolBase constructor. #49360

Merged
merged 8 commits into from
Nov 19, 2020

Conversation

AlekseyTs
Copy link
Contributor

Closes #45489.

@jcouv jcouv self-assigned this Nov 13, 2020
@AlekseyTs
Copy link
Contributor Author

@cston, @jcouv, @dotnet/roslyn-compiler Please review

1 similar comment
@AlekseyTs
Copy link
Contributor Author

@cston, @jcouv, @dotnet/roslyn-compiler Please review


// Due to the fact that this method is potentially reentrant, we must use a
// reentrant lock to avoid deadlock and cannot assert that at this point the work
// has completed (_state.HasComplete(CompletionPart.FinishPropertyEnsureSignature)).
Copy link
Member

@jaredpar jaredpar Nov 17, 2020

Choose a reason for hiding this comment

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

It seems that a number of the callers of EnsureSignature assume that the call will exit with the various fields being properly set. Most notable _lazyType. The re-entrant nature of the method though indicates that this is not the case. For example if EnsureSignature calls TypeWithAnnotations then that call will possibly because the second call to EnsureSignature will be re-entrant and won't guarantee all of the values are set.

How do we guard against this type of problem?

I think it's the type of error that would pretty much always play out in single threaded scenarios (i.e. it's not a race). So exhaustive testing should be enough. Wanted to make sure you agreed with that assertion. #Resolved

Copy link
Contributor Author

@AlekseyTs AlekseyTs Nov 17, 2020

Choose a reason for hiding this comment

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

How do we guard against this type of problem?

All the fields that are expected to be used in case of reentrancy are set by EnsureSignature to some preliminary values before it does anything that could cause a reentrancy. We are already using similar mechanism for method symbols.


In reply to: 525320776 [](ancestors = 525320776)

{
Debug.Assert(GetMethod is object);

if (!IsStatic && SetMethod is object && !SetMethod.IsInitOnly)
Copy link
Member

@jaredpar jaredpar Nov 17, 2020

Choose a reason for hiding this comment

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

Consider a pattern here to avoid the double read of SetMethod

Suggested change
if (!IsStatic && SetMethod is object && !SetMethod.IsInitOnly)
if (!IsStatic && SetMethod is { IsInitOnly: false }
``` #Resolved

@@ -1349,6 +1415,11 @@ internal override void ForceComplete(SourceLocation locationOpt, CancellationTok
GetAttributes();
break;

case CompletionPart.StartPropertyEnsureSignature:
case CompletionPart.FinishPropertyEnsureSignature:
EnsureSignature();
Copy link
Member

@jaredpar jaredpar Nov 17, 2020

Choose a reason for hiding this comment

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

Believe we need the following here

_state.SpinWaitComplete(CompletionPart.FinishPropertyEnsureSignature, cancellationToken);

This is necessary if the call to EnsureSignature could call out to ForceComplete. In that case the call to EnsureSignature would be re-entrant here and hence wouldn't satisfy the contract of ForceComplete.

Unsure if this is or isn't possible given the call graph of EnsureSignature. At the least I think we should have an assert that validates the part is marked as complete after EnsureSignature is called. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

We have SpinWaitComplete after this switch.

if the call to EnsureSignature could call out to ForceComplete.

I do not think this can happen. ForceComplete is there to make sure we collected all declaration diagnostics, it is not meant to be used for any other purpose.

I will add the suggested assert.


In reply to: 525326274 [](ancestors = 525326274)

@AlekseyTs
Copy link
Contributor Author

@jaredpar Addressed feedback

@AlekseyTs
Copy link
Contributor Author

@cston, @jcouv, @dotnet/roslyn-compiler Please review

{
Debug.Assert(!isExpressionBodied || !isAutoProperty);
Debug.Assert(!isExpressionBodied || !hasInitializer);
Copy link
Member

@jaredpar jaredpar Nov 18, 2020

Choose a reason for hiding this comment

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

Does it make sense to add this assert? Or am I misunderstanding the relationship between the properties here?

Debug.Assert(!isExplicitInterfaceImplementation || explicitInterfaceType is not null);
``` #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does it make sense to add this assert? Or am I misunderstanding the relationship between the properties here?

In error scenarios we may fail to find the type, but the property is still an explicit implementation. It is purely a syntax check


In reply to: 526216252 [](ancestors = 526216252)


private void EnsureSignature(DiagnosticBag diagnostics)
Copy link
Member

@jaredpar jaredpar Nov 18, 2020

Choose a reason for hiding this comment

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

Believe this can only legally called from EnsureSignature() correct? If so did you consider making this a local function there to prevent bad calls?

Not something I feel strongly about, just curious. #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Believe this can only legally called from EnsureSignature() correct? If so did you consider making this a local function there to prevent bad calls?

To simplify review process I tried to keep original code as close to the original place as possible and tried to make as little as possible changes around it. Since the method is private, I do not see significant advantage in using a local function at this point.


In reply to: 526219649 [](ancestors = 526219649)

{
// Nothing to do here
Debug.Assert(isAutoPropertyAccessor);
Copy link
Member

@jaredpar jaredpar Nov 18, 2020

Choose a reason for hiding this comment

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

Does this assert make sense

Debug.Assert(!isExplicitInterfaceImplementation);
``` #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Does this assert make sense

That would be a valid assumption, but I don't think it is worth verifying given the nature of this sealed class.


In reply to: 526239409 [](ancestors = 526239409)

AlekseyTs and others added 2 commits November 18, 2020 09:57
Co-authored-by: Jared Parsons <jaredpparsons@gmail.com>
@AlekseyTs
Copy link
Contributor Author

@cston, @jcouv, @dotnet/roslyn-compiler Please review, need a second sign-off

@jcouv
Copy link
Member

jcouv commented Nov 19, 2020

Looking #Resolved

// requires that we return here even though the work is not complete. That's because
// signature is processed by first populating the return type and parameters by binding
// the syntax from source. Those values are visible to the same thread for the purpose
// of computing which methods are implemented and overridden. But then those values
Copy link
Member

@jcouv jcouv Nov 19, 2020

Choose a reason for hiding this comment

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

Might we be able to use signature-only symbols, rather than partially constructed symbols, to find which methods are implemented and overridden? #Resolved

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Might we be able to use signature-only symbols, rather than partially constructed symbols, to find which methods are implemented and overridden?

I think technically it should be possible to locate overridden/implemented property with an alternative signature representation. A signature-only symbol is one way to do that. Perhaps, if we were implementing this from scratch, we should have taken that route. At this point, however, I prefer sticking to the existing way of doing things, which has been verified to work (in the old constructor and with method symbols). Trying to use signature-only symbols, will likely require changes elsewhere, the symbol itself is getting updated in the process, the symbol itself is getting captured somewhere. For example, in diagnostics, etc.


In reply to: 527209014 [](ancestors = 527209014)

Copy link
Member

@jcouv jcouv left a comment

Choose a reason for hiding this comment

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

LGTM Thanks (iteration 8)

@AlekseyTs AlekseyTs merged commit bd92aeb into dotnet:master Nov 19, 2020
@ghost ghost added this to the Next milestone Nov 19, 2020
333fred added a commit to 333fred/roslyn that referenced this pull request Nov 20, 2020
* upstream/master: (47 commits)
  Make compiler server logging explicit (dotnet#48557)
  [master] Update dependencies from dotnet/arcade (dotnet#48274)
  Handle removed project in ExternalErrorDiagnosticUpdateSource
  Report an error for ref-returning auto-properties declared in an interface. (dotnet#49510)
  Add usings on paste (dotnet#48501)
  Determinism test needs to use bootstrap compiler (dotnet#49483)
  Simplify and reduce amount of work performed by SourcePropertySymbolBase constructor. (dotnet#49360)
  Updates test
  Simplify
  Split Document/Workspace handler into only handling open/closed documents respectively.
  only report watson once.
  Additional usage of a PooledHashset. (dotnet#49459)
  Loc checkin
  Update src/Features/CSharp/Portable/CodeRefactorings/ConvertLocalFunctionToMethod/CSharpConvertLocalFunctionToMethodCodeRefactoringProvider.cs
  Preserve annotation on comment trivia when performing formatting.
  Validate arguments to IAsyncCompletionSource methods
  Determinism fixes for AnonymousTypes in VB (dotnet#49467)
  Collect nfw information for a crash we're seeing.
  Make sure to not discard text changes when no reference changes are present
  Create an unsafe method from a local function when necessary (dotnet#49389)
  ...
@allisonchou allisonchou modified the milestones: Next, 16.9.P2 Nov 24, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Simplify SourcePropertySymbolBase constructor.
4 participants