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

Avoid binding lambdas unnecessarily in some error scenarios #59733

Draft
wants to merge 7 commits into
base: main
Choose a base branch
from

Conversation

cston
Copy link
Member

@cston cston commented Feb 24, 2022

Fixes #63896.

@cston cston force-pushed the BindForErrorRecovery branch from 72b4a11 to f2ab18e Compare February 26, 2022 17:55
var data = new LambdaBindingData();
comp.TestOnlyCompilationData = data;
var diagnostics = comp.GetDiagnostics();
Assert.Equal((84, 126), (data.LambdaBindingCount, data.UnboundLambdaStateCount));
Copy link
Member Author

@cston cston Feb 26, 2022

Choose a reason for hiding this comment

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

(84, 126)

Without the checks in BuildArgumentsForErrorRecovery, each of these error cases report (258, 344).

@@ -1663,14 +1668,17 @@ private ImmutableArray<BoundExpression> BuildArgumentsForErrorRecovery(AnalyzedA
{
// bind the argument against each applicable parameter
var unboundArgument = (UnboundLambda)argument;
foreach (var parameterList in parameterListList)
if (!unboundArgument.HasBoundForErrorRecovery)
Copy link
Member Author

Choose a reason for hiding this comment

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

if (!unboundArgument.HasBoundForErrorRecovery)

This check simply avoids binding the lambda for error recovery below when the binding will be ignored.

var data = new LambdaBindingData();
comp.TestOnlyCompilationData = data;
var diagnostics = comp.GetDiagnostics();
Assert.Equal((84, 126), (data.LambdaBindingCount, data.UnboundLambdaStateCount));
Copy link
Member Author

Choose a reason for hiding this comment

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

(84, 126)

Without the checks in BuildArgumentsForErrorRecovery, this success case reports (136, 186).

@cston cston marked this pull request as ready for review July 14, 2023 16:17
@cston cston requested a review from a team as a code owner July 14, 2023 16:17
@cston cston requested a review from CyrusNajmabadi July 14, 2023 16:17
Copy link
Member

@333fred 333fred left a comment

Choose a reason for hiding this comment

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

Done review pass

@@ -987,5 +987,231 @@ static void M(object o)
var containingTypes = exprs.SelectAsArray(e => model.GetSymbolInfo(e).Symbol.ContainingSymbol).ToTestDisplayStrings();
Assert.Equal(new[] { "A", "B", "B", "A", "B", "B" }, containingTypes);
}

[Fact]
public void NestedLambdasAndOverloads_NoTypes_NoErrors()
Copy link
Member

Choose a reason for hiding this comment

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

I think we should verify the IOperation trees for these tests to make sure that we know what semantic information will be availble to the IDE in these cases.

@jcouv jcouv self-assigned this Jul 20, 2023
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 5)

@jcouv jcouv added this to the 17.8 milestone Jul 20, 2023
@@ -1756,14 +1772,18 @@ private ImmutableArray<BoundExpression> BuildArgumentsForErrorRecovery(AnalyzedA
{
// bind the argument against each applicable parameter
var unboundArgument = (UnboundLambda)argument;
foreach (var parameterList in parameterListList)
if (NestedLambdaExpressionDepth(unboundArgument.Syntax) <= MaxLambdaExpressionDepthForErrorRecovery &&
Copy link
Contributor

Choose a reason for hiding this comment

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

NestedLambdaExpressionDepth(unboundArgument.Syntax) <= MaxLambdaExpressionDepthForErrorRecovery

This condition looks questionable to me. Perhaps, the lambda is in the third level of nesting. Why is that important on its own? We might not be rebinding any of the enclosing lambdas for error recovery, doing simple plain body binding, and recovering in this case will not cause any noticeable overhead.

The issue says: "Reduce the overhead of binding lambdas when there are nested lambda expressions with multiple overloads. Specifically, consider avoiding binding nested lambdas unnecessarily for overloads that do not match." It doesn't look like any of the conditions, except the nesting, are checked.

@AlekseyTs
Copy link
Contributor

Done with review pass (commit 5)

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

jjonescz added a commit to jjonescz/roslyn that referenced this pull request Aug 25, 2023
jjonescz added a commit that referenced this pull request Aug 29, 2023
* Bind fully-typed lambda only once for error recovery

* Assert number of lambda bindings

Inspired by #59733.

* Test only with one lambda and one statement

* Copy a comment
@cston cston marked this pull request as draft September 5, 2023 18:58
@Youssef1313
Copy link
Member

@cston What is the status on this PR please?

@jcouv jcouv modified the milestones: 17.8, 17.9 Oct 12, 2023
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.

Avoid binding lambda expressions unnecessarily in error scenarios
6 participants