-
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
Bind fully-typed lambda only once for error recovery #69695
Conversation
Inspired by dotnet#59733.
comp.TestOnlyCompilationData = data; | ||
comp.VerifyDiagnostics(); | ||
Assert.Equal(localFunctions ? 20 : 220, data.LambdaBindingCount); | ||
}, timeout: TimeSpan.FromSeconds(20)); |
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.
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.
unboundArgument.FunctionType is { } functionType && | ||
functionType.GetInternalDelegateType() is { } delegateType) | ||
{ | ||
_ = unboundArgument.Bind(delegateType, isExpressionTree: 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.
nit: Consider adding the same comment as below here ("// Just assume we're not in an expression tree for the purposes of error recovery.")
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 2)
@cston PTAL |
for (int j = 0; j < statementsNumber; j++) | ||
{ | ||
builder3.AppendLine($"""arg = arg + "{j}";"""); | ||
} |
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 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?
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.
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.
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.
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)); |
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.
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.
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 inCreateAnonymousFunctionConversion
anyway (and the result is cached) - see #69505 (comment). We could perhaps skip some unnecessary binding inCreateAnonymousFunctionConversion
, 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.