-
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
Merge touch document actions #73399
Merge touch document actions #73399
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3,6 +3,7 @@ | |
// See the LICENSE file in the project root for more information. | ||
|
||
using System.Collections.Immutable; | ||
using System.Linq; | ||
using System.Threading; | ||
using System.Threading.Tasks; | ||
using Microsoft.CodeAnalysis.Diagnostics; | ||
|
@@ -15,24 +16,29 @@ internal partial class SolutionCompilationState | |
{ | ||
private abstract partial class TranslationAction | ||
{ | ||
internal sealed class TouchDocumentAction( | ||
internal sealed class TouchDocumentsAction( | ||
ProjectState oldProjectState, | ||
ProjectState newProjectState, | ||
DocumentState oldState, | ||
DocumentState newState) | ||
: TranslationAction(oldProjectState, newProjectState) | ||
ImmutableArray<DocumentState> newStates) : TranslationAction(oldProjectState, newProjectState) | ||
{ | ||
private readonly DocumentState _oldState = oldState; | ||
private readonly DocumentState _newState = newState; | ||
private readonly ImmutableArray<DocumentState> _oldStates = newStates.SelectAsArray(s => oldProjectState.DocumentStates.GetRequiredState(s.Id)); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. it can be. but then i needed this here and for the sequence-equals. so basically, it was just nice to have the member. note: if there's a problem here, we could always change this to be a OneOrMany. It's highly likely that thsi will be the 'One' case for the normal mode of a user editing a document. So we'd save on the array in that case. That said. I think this is unlikely to matter in practice since the arrays will be small, and GC'ed asap. So i'd like to keep this as-is for simplicity. |
||
private readonly ImmutableArray<DocumentState> _newStates = newStates; | ||
|
||
public override async Task<Compilation> TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) | ||
{ | ||
return oldCompilation.ReplaceSyntaxTree( | ||
await _oldState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), | ||
await _newState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); | ||
} | ||
var finalCompilation = oldCompilation; | ||
for (int i = 0, n = _newStates.Length; i < n; i++) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
var newState = _newStates[i]; | ||
var oldState = _oldStates[i]; | ||
finalCompilation = finalCompilation.ReplaceSyntaxTree( | ||
await oldState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), | ||
await newState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); | ||
} | ||
|
||
public DocumentId DocumentId => _newState.Attributes.Id; | ||
return finalCompilation; | ||
} | ||
|
||
/// <summary> | ||
/// Replacing a single tree doesn't impact the generated trees in a compilation, so we can use this against | ||
|
@@ -45,71 +51,18 @@ public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generat | |
|
||
public override TranslationAction? TryMergeWithPrior(TranslationAction priorAction) | ||
{ | ||
if (priorAction is TouchDocumentAction priorTouchAction && | ||
priorTouchAction._newState == _oldState) | ||
if (priorAction is TouchDocumentsAction priorTouchAction && | ||
priorTouchAction._newStates.SequenceEqual(_oldStates)) | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe 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 commentThe reason will be displayed to describe this comment to others. Learn more. it's very likely. this is what happens when you get a stream of edits coming in for one document (basically, the typing scenario). we can either keep making a longer and longer chain of 'edits' where the compilation goes through N steps to get to hte end. Or we can say that the actions 'merge' and we'll jump from teh starting compilation all the way to teh end step. So, instead of A->B->C->D, we can collapse as we're adding these and end up with just an A->D transition. |
||
{ | ||
// As we're merging ourselves with the prior touch action, we want to keep the old project state | ||
// that we are translating from. | ||
return new TouchDocumentAction(priorAction.OldProjectState, this.NewProjectState, priorTouchAction._oldState, _newState); | ||
return new TouchDocumentsAction(priorAction.OldProjectState, this.NewProjectState, _newStates); | ||
} | ||
|
||
return null; | ||
} | ||
} | ||
|
||
internal sealed class TouchDocumentsAction : TranslationAction | ||
{ | ||
private readonly ImmutableArray<DocumentState> _newStates; | ||
|
||
private TouchDocumentsAction( | ||
ProjectState oldProjectState, | ||
ProjectState newProjectState, | ||
ImmutableArray<DocumentState> newStates) | ||
: base(oldProjectState, newProjectState) | ||
{ | ||
_newStates = newStates; | ||
} | ||
|
||
public static TranslationAction Create( | ||
ProjectState oldProjectState, | ||
ProjectState newProjectState, | ||
ImmutableArray<DocumentState> newStates) | ||
{ | ||
// Special case when we're only updating a single document. This case can be optimized more, and | ||
// corresponds to the common case of a single file being edited. | ||
return newStates.Length == 1 | ||
? new TouchDocumentAction(oldProjectState, newProjectState, oldProjectState.DocumentStates.GetRequiredState(newStates[0].Id), newStates[0]) | ||
: new TouchDocumentsAction(oldProjectState, newProjectState, newStates); | ||
} | ||
|
||
public override async Task<Compilation> TransformCompilationAsync(Compilation oldCompilation, CancellationToken cancellationToken) | ||
{ | ||
var finalCompilation = oldCompilation; | ||
for (int i = 0, n = _newStates.Length; i < n; i++) | ||
{ | ||
cancellationToken.ThrowIfCancellationRequested(); | ||
var newState = _newStates[i]; | ||
var oldState = this.OldProjectState.DocumentStates.GetRequiredState(newState.Id); | ||
finalCompilation = finalCompilation.ReplaceSyntaxTree( | ||
await oldState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false), | ||
await newState.GetSyntaxTreeAsync(cancellationToken).ConfigureAwait(false)); | ||
} | ||
|
||
return finalCompilation; | ||
} | ||
|
||
/// <inheritdoc cref="TouchDocumentAction.CanUpdateCompilationWithStaleGeneratedTreesIfGeneratorsGiveSameOutput"/> | ||
public override bool CanUpdateCompilationWithStaleGeneratedTreesIfGeneratorsGiveSameOutput | ||
=> true; | ||
|
||
/// <inheritdoc cref="TouchDocumentAction.TransformGeneratorDriver"/> | ||
public override GeneratorDriver TransformGeneratorDriver(GeneratorDriver generatorDriver) | ||
=> generatorDriver; | ||
|
||
public override TranslationAction? TryMergeWithPrior(TranslationAction priorAction) | ||
=> null; | ||
} | ||
|
||
internal sealed class TouchAdditionalDocumentAction( | ||
ProjectState oldProjectState, | ||
ProjectState newProjectState, | ||
|
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.
passing in oldState/oldStates is redundant given that we have oldProjectState.