-
Notifications
You must be signed in to change notification settings - Fork 4.2k
Relax the requirement in WithChanges that changes be ordered #26798
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
Conversation
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.
why the second clause?
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.
➡️ TestChangedTextWithReplaceBeforeInsertSamePosition
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 not clear ot me why this check is correct. why is it sufficient to only check the last change range?
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 think the answer is because this is in a loop that goes through all of the changes.
In reply to: 187675569 [](ancestors = 187675569)
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.
➡️ changeRanges is always sorted (a condition that was true both before and after this change).
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.
WithChanges [](start = 31, length = 11)
Do we have tests that demonstrate the new behavior?
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.
Do we have tests that demonstrate the new behavior?
No. Local install was broken due to NRT preview install so I had to fix that, and now am working on tests. Hence the PR for Personal Review Only label. 😄
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.
Ah, sorry. The label is not in a visible location for me :( That's my bad for not checking. I'm a fan of "WIP" in teh title to help indicate this more obviously.
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.
➡️ Tests are added
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.
WIP in the title is a bad idea at the moment because of an Outlook threading bug that triggers when you change the title (e.g. to remove WIP later). I'm working with them to get that fixed.
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.
ArgumentException [](start = 30, length = 17)
Are there no tests for the exceptional behavior?
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.
➡️ Tests are included for both normal and exceptional behavior
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.
Can you please point me to tests for the exceptional behavior? Are those existing tests?
In reply to: 187682548 [](ancestors = 187682548)
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.
The only test I could find is one existing test TestChangedTextWithMultipleOverlappingChanges
In reply to: 188384892 [](ancestors = 188384892,187682548)
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.
@gafter Yes, that is the test for the condition which is still a failure
0e9e405 to
a744edd
Compare
|
@sharwell thanks for the fix! |
All the changes are non-overlapping changes on the original text. The order only matters for sequences of insertions at the same position (empty old span, non-empty new text). |
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.
Other code in this method assumes that NewText can be null. Is the check to ensure the span isn't empty a sufficient guard against this case here?
a744edd to
0ffe920
Compare
jaredpar
left a comment
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.
![]()
jasonmalinowski
left a comment
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 worry that this is an interesting kind of breaking change: since this type is something we expect people hosting Roslyn to derive from, we've now changed their contract on their derived type which says they now must support unordered changes. If VS for Mac, for example, isn't expecting this, we might still be broken.
I would have guessed we would just fix this by changing whatever code is passing unordered spans and sorting before calling WithChanges. Did that have some other complexity I'm not imagining here?
| changes = from c in changes | ||
| where !c.Span.IsEmpty || c.NewText?.Length > 0 | ||
| orderby c.Span.Start, c.Span.End | ||
| select c; |
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.
Note that this isn't being realized, and the recursive call is going to do .Any() and then an enumeration over the changes again. Will that result in multiple sorts?
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.
That's a good point. Sort requires a full iteration to resolve even Any. That will mean that we sort this at least twice: changes.Any and foreach (var change in changes)
In reply to: 188428290 [](ancestors = 188428290)
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.
That will mean that we sort this at least twice:
changes.Anyandforeach (var change in changes)
Currently, yes. However, this is really a fallback handler for a condition we try to avoid in practice (a bad outcome of a race condition during package initialization). I could call ToList() if you prefer.
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 don't consider is a "fallback handler due to package initialization" -- the compiler layer knows not what package initialization is. 😄 If I were you, I'd consider adding a .ToList(), but potentially at the start of the method. Even not in the fallback case, we enumerate this twice which is potentially bad, but potentially not.
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.
If I were you, I'd consider adding a .ToList(), but potentially at the start of the method. Even not in the fallback case, we enumerate this twice which is potentially bad, but potentially not.
It seems risky to add to the beginning of the method. If most of the inputs are collections with low-overhead enumeration, then calling ToList every time could cause a performance regression. Currently this code change only touches a path that previously threw an exception. Any objection to just calling ToList on the result of the LINQ query?
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.
That's fine too.
| { | ||
| changes = from c in changes | ||
| where !c.Span.IsEmpty || c.NewText?.Length > 0 | ||
| orderby c.Span.Start, c.Span.End |
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.
Why the secondary sort?
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.
Handles an incorrectly-ordered zero-length insertion. See #26798 (comment) which points to TestChangedTextWithReplaceBeforeInsertSamePosition.
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.
If @CyrusNajmabadi and I both had to ask, please add a comment explaining why. I admit within a minute or two of thinking it's not obvious to me why not having this breaks that other test (I'd expect this to fail either way), so a comment would be good.
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.
➡️ Fixed in af5afd7
|
And to clarify my earlier comment: this is a change that makes the world a better place for consumers of the compiler type because yes, this really wasn't a requirement we had to have. So I'm for the change, but we might want to check with VS for Mac and VS Code first to see if they'll need any updates made. |
gafter
left a comment
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 actually the other way around. One of the derived types already supported unordered changes, and consumers were depending on that behavior. However, we can no longer guarantee that derived implementation will be used, and in some edge cases this base implementation was called instead.
Yes, this was one of the alternatives discussed. The offending input is in the TypeScript code, and we could still decide to resolve this issue by requesting the input be ordered. |
Fixes https://devdiv.visualstudio.com/DevDiv/_workitems/edit/604150
/cc @minestarks
Customer scenario
A customer attempts to reformat an HTML document, and Visual Studio crashes.
Bugs this fixes
https://devdiv.visualstudio.com/DevDiv/_workitems/edit/604150
Workarounds, if any
None.
Risk
Low. This change relaxes the preconditions of an internal fallback method to produce expected results when the input is unordered but also unambiguous.
Performance impact
Performance is not changed in normal usage scenarios.
Is this a regression from a previous update?
Yes, introduced by #25558.
Root cause analysis
See #26339 for the primary RCA.
This change corrects an additional edge case for
ITextBufferinstances created beforeVisualStudioWorkspaceattaches event handlers toITextBufferFactoryServiceandIProjectionBufferFactoryService. This case is only believed to occur in IDE initialization scenarios where the workspace load is triggered by opening a document.How was the bug found?
Watson.
Test documentation updated?
N/A