-
Notifications
You must be signed in to change notification settings - Fork 4k
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
Remove CapturedVariablesByLambda #20878
Conversation
Swaps out all uses of CapturedVariablesByLambda for functions on the Scope tree.
/// <summary> | ||
/// The root of the scope tree for this method. | ||
/// </summary> | ||
public Scope ScopeTree { get; private set; } |
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.
Delete the private set
. It's unnecessary since you only modify the value in the ctor. Makes it clear this is a readonly
property.
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.
? It's set in the visitor, not in the constructor. I could set it in the constructor but that's a dangerous dance as I would be handing out this
before fully constructed.
/// <returns> | ||
/// A tuple of the found <see cref="Closure"/> and the <see cref="Scope"/> it was found in. | ||
/// </returns> | ||
public static (Closure, Scope) FindClosureInScope(Scope startingScope, MethodSymbol closureSymbol) |
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.
Consider GetClosureInScope
vs. Find
. The general rule for funtions like this is:
- Find: returns null on failure. Essentially a method that expects failure as an outcome.
- Get: throws on failure. A method which expects to find the value.
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.
Hmm also consider simply GetClosure
. The InScope
part to me can read as "find a closure inside this scope" which is contrary to the implementation.
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.
I was trying to find some way to say "this method searches up", as opposed to the other one, which searches down. Any suggestions?
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.
GetVisibleClosure?
/// <summary> | ||
/// Finds a <see cref="Closure"/> with a matching original symbol somewhere in the given scope or nested scopes. | ||
/// </summary> | ||
public static Closure FindClosureInTree(Scope rootScope, MethodSymbol closureSymbol) |
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.
Another place to consider Get
vs. Find
/// <summary> | ||
/// Finds a <see cref="Closure"/> with a matching original symbol somewhere in the given scope or nested scopes. | ||
/// </summary> | ||
public static Closure FindClosureInTree(Scope rootScope, MethodSymbol closureSymbol) |
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.
Consider using treeRoot
vs. rootScope
. The term root scope has a particular meaning in this code base already: the absolute root of the scopes. This method though works on any arbitrary scope.
{ | ||
return result; | ||
} | ||
throw ExceptionUtilities.Unreachable; |
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.
return result ?? throw ...
Don't actually care if you do this, just a reminder to myself that you could 😄
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.
niiice
|
||
Closure Helper(Scope scope) | ||
{ | ||
foreach (var closure in scope.Closures) |
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.
In the FindClosureInScope you used SingleOrDefault to accomplish the exact same operation. Why use foreach
here but SingleOrDefault
there? Seems like these should do the same operation.
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.
I'll change the other one to use a foreach
loop too. Avoids allocating a capture environment and a delegate 😄
A number of the tests needed to be re-baselined due to the generated closure names changing. Can you please add an explanation for why that happened? Want to make sure this is expected and we understand why it's changing. |
@jaredpar Certainly. The reason the baseline changed is that the order of enumerating closures changed. I briefly looked into matching the behavior, but the problem is that the closure order in the old visitors is determined by the visitation of captured variables, not visitation of the closures themselves. More specifically, an item is only added to the CapturedVariablesByLambda dictionary when In contrast, the visitation of the Scope tree looks at closures in an in-order traversal of the tree, stopping at the first introduced closure, not necessarily the closure which first captured a variable. One obvious consequence of this changing is that the old ordering for a series of nested lambdas was effectively post-order -- the interior closures would be added to the visitation first, since they would be added from the perspective of the captured variable looking up, instead of the visitor looking down. This particular case is responsible for all the baseline changes that I have seen. When I looked into replicating this traversal order I found it complicated and pretty counter-intuitive. Since the baseline change was so low in emitted IL, I thought it better to keep a very natural in-order tree traversal and just rebaseline a few tests. |
Thanks for the explanation. Could you find a way to get that explanation into one of the commit messages here? That way future code historians can understand why these baselines changed? Would recomend just ammend the change that updated the baseline to have the commit message. |
@jaredpar I plan on squashing these changes, so how about I add it to the squashed message? |
@@ -328,22 +328,20 @@ protected override NamedTypeSymbol ContainingType | |||
/// </summary> | |||
private void MakeFrames(ArrayBuilder<ClosureDebugInfo> closureDebugInfo) | |||
{ | |||
var closures = _analysis.CapturedVariablesByLambda.Keys; | |||
|
|||
foreach (var closure in closures) |
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.
Is this why the names changed? We are traversing closures in different order? I think this is ok.
I think we may be changing the order more in the future. It may make sense eventually for the frame generator to just traverse Scopes/DeclaredVariables instead.
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.
Agreed
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
That's fine. Achieves the goal of "developer sees change, uses git blame, and gets a good explanation". |
…c-member-reference * dotnet/features/ioperation: (134 commits) Fix build break in IOperation feature branch Fix unit tests that broke with previous commit Address PR feedback from Chuck Fix unit test Add IOperation support for variations of object creation expressions (type parameter, nopia and dynamic) Remove dead code from GenerateConstructor. Disable NETCore version check Fixed review notes. Add comment Disable NETCore version check Show modifier/method/type block declaration keywords after attribute lists Improve type argument list parsing in error conditions. (dotnet#19467) Don't report modifier errors while parsing. (dotnet#16339) Fix assert and merge Remove extra space Restore failure behavior. Simplify implementation of parsing constraints. (dotnet#16429) Fix csproj Remove CapturedVariablesByLambda (dotnet#20878) Remove testing wait ...
Swaps out all uses of CapturedVariablesByLambda for functions on the
Scope tree.
Fixes https://github.com/dotnet/roslyn/projects/26#card-3753318