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

Bind fully-typed lambda only once for error recovery #69695

Merged
merged 4 commits into from
Aug 29, 2023

Conversation

jjonescz
Copy link
Member

@jjonescz jjonescz commented Aug 24, 2023

Fixes #69093 (as an alternative to #69505), although not exactly as suggested there - skipping lambda body binding in HasAnonymousFunctionConversion has no effect since the lambda is bound later for error recovery or in CreateAnonymousFunctionConversion anyway (and the result is cached) - see #69505 (comment). We could perhaps skip some unnecessary binding in CreateAnonymousFunctionConversion, but not sure if that could help since in my testing scenarios, the change in this PR already makes lambdas as fast as local functions.

@dotnet-issue-labeler dotnet-issue-labeler bot added Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead labels Aug 24, 2023
comp.TestOnlyCompilationData = data;
comp.VerifyDiagnostics();
Assert.Equal(localFunctions ? 20 : 220, data.LambdaBindingCount);
}, timeout: TimeSpan.FromSeconds(20));
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 runs ~45 seconds (before the fix) vs ~5 seconds (after the fix) on my machine for lambdas and ~5 seconds both before and after for local functions.

Also without the fix, the number of lambda bindings is 1930 instead of 220.

@jjonescz jjonescz marked this pull request as ready for review August 25, 2023 11:22
@jjonescz jjonescz requested a review from a team as a code owner August 25, 2023 11:22
@jcouv jcouv self-assigned this Aug 26, 2023
unboundArgument.FunctionType is { } functionType &&
functionType.GetInternalDelegateType() is { } delegateType)
{
_ = unboundArgument.Bind(delegateType, isExpressionTree: false);
Copy link
Member

Choose a reason for hiding this comment

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

nit: Consider adding the same comment as below here ("// Just assume we're not in an expression tree for the purposes of error recovery.")

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 2)

@jaredpar
Copy link
Member

@cston PTAL

for (int j = 0; j < statementsNumber; j++)
{
builder3.AppendLine($"""arg = arg + "{j}";""");
}
Copy link
Member

@cston cston Aug 29, 2023

Choose a reason for hiding this comment

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

What is the effect of lambdasNumber or statementsNumber? Are these just constant multiples for the total execution time with or without the fix? If so, would it make sense to simply use 1 lambda and 1 statement?

Copy link
Member Author

@jjonescz jjonescz Aug 29, 2023

Choose a reason for hiding this comment

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

You're right, that was necessary when the test was based on timeouts, but now it's not since I reused your lambda binding counter.

Copy link
Member Author

Choose a reason for hiding this comment

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

With this change of the test (time doesn't change visibly anymore):

lambda bindings time
local functions 20 ~1s
lambdas 211 → 40 ~0.1s

""";
RunInThread(() =>
{
var comp = CreateCompilation(source, options: TestOptions.DebugDll.WithConcurrentBuild(false));
Copy link
Member

Choose a reason for hiding this comment

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

TestOptions.DebugDll.WithConcurrentBuild(false)

Should we test WithConcurrentBuild(true) instead?

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 could, but I'm worried that then the number of lambda bindings would be non-deterministic as two threads could race to bind the same lambda so the counter would be incremented twice in such rare case, making the test flaky.

@jjonescz jjonescz requested a review from cston August 29, 2023 11:48
@jjonescz jjonescz enabled auto-merge (squash) August 29, 2023 14:29
@jjonescz jjonescz merged commit e171178 into dotnet:main Aug 29, 2023
@jjonescz jjonescz deleted the 69093-FullyTypedLambda-2 branch August 29, 2023 16:02
@ghost ghost added this to the Next milestone Aug 29, 2023
@Cosifne Cosifne modified the milestones: Next, 17.8 P3 Sep 25, 2023
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Area-Compilers untriaged Issues and PRs which have not yet been triaged by a lead
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Ensure HasAnonymousFunctionConversion returns without binding lambda body for explicitly-typed lambda
5 participants