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

Push task-ifying extract-method return type to the code gen stage. #76670

Merged
merged 8 commits into from
Jan 8, 2025

Conversation

CyrusNajmabadi
Copy link
Member

@CyrusNajmabadi CyrusNajmabadi commented Jan 7, 2025

The goal here is to have the internal model for EM store the true type of the value returned by the extract method, as a distinct concept from what the final return-type might be (which might be wrapped in something like 'Task').

This benefits the work being down in another branch to extract methods with complex flow control, but allowing manipulation of the original return type, a new return value for flow control purposes, and then any wrapping that needs to happen around that.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead labels Jan 7, 2025
@CyrusNajmabadi CyrusNajmabadi marked this pull request as ready for review January 7, 2025 23:49
@CyrusNajmabadi CyrusNajmabadi requested a review from a team as a code owner January 7, 2025 23:49
@@ -89,7 +89,7 @@ protected override IMethodSymbol GenerateMethodDefinition(
attributes: [],
accessibility: Accessibility.Private,
modifiers: CreateMethodModifiers(),
returnType: AnalyzerResult.ReturnType,
returnType: this.GetFinalReturnType(),
Copy link
Member Author

Choose a reason for hiding this comment

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

only when we're actually generating the final method declaration do we get teh type, potentially wrapped with 'Task'. Everything else sees the 'core' type and can ask questions of that.

@@ -209,7 +209,7 @@ private bool ShouldPutUnsafeModifier()
private DeclarationModifiers CreateMethodModifiers()
{
var isUnsafe = ShouldPutUnsafeModifier();
var isAsync = this.SelectionResult.CreateAsyncMethod();
var isAsync = this.SelectionResult.ContainsAwaitExpression();
Copy link
Member Author

Choose a reason for hiding this comment

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

renamed for clarity

{
Name: nameof(Task.ConfigureAwait),
Parameters: [{ Type.SpecialType: SpecialType.System_Boolean }],
}))
Copy link
Member Author

Choose a reason for hiding this comment

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

note: i removed the check that the final type we're extracting actually has a .ConfigureAwait(bool) method on it. We're only adding .ConfigureAwait(false) because we saw it in the user's original code. So we can trust they know what pattern they're following and that we should follow it as well. This also makes things work if the ConfigureAwait is an extension method.

@@ -68,27 +66,6 @@ protected override SyntaxNode GetNodeForDataFlowAnalysis()
: node;
}

protected override bool UnderAnonymousOrLocalMethod(SyntaxToken token, SyntaxToken firstToken, SyntaxToken lastToken)
Copy link
Member Author

Choose a reason for hiding this comment

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

these are no longer needed as they were hacks on how we previously determined certain syntactic facts about the code being extracted.

// change return type to be wrapped in Task
var shouldPutAsyncModifier = SelectionResult.CreateAsyncMethod();
if (shouldPutAsyncModifier)
return WrapReturnTypeInTask(returnType);
Copy link
Member Author

Choose a reason for hiding this comment

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

we no longer do the wrapping step here. we hold off on that until we need the final type for the method decl to have.

/// </summary>
/// <param name="predicate"></param>
/// <returns></returns>
private bool CheckNodesInSelection(Func<ISyntaxFacts, SyntaxNode, bool> predicate)
Copy link
Member Author

Choose a reason for hiding this comment

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

this is the right wayu to write the loop. descend the nodes. do not descend into localfunctions/lambdas, and check only those that intersect the span of interest. Both ContainsAwaitExpression and ContainsConfigureAwait can now jusst defer to this helper.

{
get
{
return ReturnType.SpecialType != SpecialType.System_Void && !AwaitTaskReturn;
Copy link
Member Author

Choose a reason for hiding this comment

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

note: i genuinely don't know what this expression meant before. especially the AwaitTaskReturn part. This is much clearer now. There is a core return type (prior to any task wrapping) and it can be checked. To know if there is a return type or not, it can be checked against System.Void.

@CyrusNajmabadi CyrusNajmabadi changed the title Initial work to push task-ifying extract-method to the end Push task-ifying extract-method return type to the code gen stage. Jan 7, 2025
continue;

if (IsConfigureAwaitFalse(node) && !UnderAnonymousOrLocalMethod(node.GetFirstToken(), firstToken, lastToken))
if (current.Span.OverlapsWith(span) && predicate(syntaxFacts, current))
Copy link
Contributor

Choose a reason for hiding this comment

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

current.Span.OverlapsWith(span)

isn't this already checked before the node was pushed onto the stack?

Copy link
Member Author

Choose a reason for hiding this comment

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

hrm... i could potentially remove it. iw as being paranoid. let me see about that in followup.

Copy link
Member Author

Choose a reason for hiding this comment

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

ok. this can be removed. will do in followup pr.

Copy link
Contributor

@ToddGrun ToddGrun left a comment

Choose a reason for hiding this comment

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

:shipit:

@CyrusNajmabadi CyrusNajmabadi merged commit 56a3e41 into dotnet:main Jan 8, 2025
25 checks passed
@dotnet-policy-service dotnet-policy-service bot added this to the Next milestone Jan 8, 2025
@CyrusNajmabadi CyrusNajmabadi deleted the emReturnType branch January 8, 2025 01:15
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-IDE untriaged Issues and PRs which have not yet been triaged by a lead VSCode
Projects
None yet
Development

Successfully merging this pull request may close these issues.

3 participants