Skip to content

Commit c1c78fb

Browse files
Make frozen doc state non-nullable (#77896)
2 parents 5f0a49d + a1f0c49 commit c1c78fb

File tree

6 files changed

+61
-99
lines changed

6 files changed

+61
-99
lines changed

src/VisualStudio/Core/Test.Next/Remote/SerializationValidator.cs

Lines changed: 2 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -239,13 +239,8 @@ private static void AssertDocumentChecksumCollectionEqual(
239239
internal void SolutionCompilationStateEqual(SolutionCompilationStateChecksums solutionObject1, SolutionCompilationStateChecksums solutionObject2)
240240
{
241241
Assert.Equal(solutionObject1.Checksum, solutionObject2.Checksum);
242-
Assert.Equal(solutionObject1.FrozenSourceGeneratedDocumentIdentities.HasValue, solutionObject2.FrozenSourceGeneratedDocumentIdentities.HasValue);
243-
if (solutionObject1.FrozenSourceGeneratedDocumentIdentities.HasValue)
244-
AssertChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocumentIdentities.Value, solutionObject2.FrozenSourceGeneratedDocumentIdentities!.Value);
245-
246-
Assert.Equal(solutionObject1.FrozenSourceGeneratedDocuments.HasValue, solutionObject2.FrozenSourceGeneratedDocuments.HasValue);
247-
if (solutionObject1.FrozenSourceGeneratedDocuments.HasValue)
248-
AssertDocumentChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocuments.Value, solutionObject2.FrozenSourceGeneratedDocuments!.Value);
242+
AssertChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocumentIdentities, solutionObject2.FrozenSourceGeneratedDocumentIdentities);
243+
AssertDocumentChecksumCollectionEqual(solutionObject1.FrozenSourceGeneratedDocuments, solutionObject2.FrozenSourceGeneratedDocuments);
249244
}
250245

251246
internal void SolutionStateEqual(SolutionStateChecksums solutionObject1, SolutionStateChecksums solutionObject2)

src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState.cs

Lines changed: 7 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ internal sealed partial class SolutionCompilationState
4242
public SolutionState SolutionState { get; }
4343

4444
public bool PartialSemanticsEnabled { get; }
45-
public TextDocumentStates<SourceGeneratedDocumentState>? FrozenSourceGeneratedDocumentStates { get; }
45+
public TextDocumentStates<SourceGeneratedDocumentState> FrozenSourceGeneratedDocumentStates { get; }
4646

4747
// Values for all these are created on demand.
4848
private ImmutableSegmentedDictionary<ProjectId, ICompilationTracker> _projectIdToTrackerMap;
@@ -62,7 +62,7 @@ private SolutionCompilationState(
6262
bool partialSemanticsEnabled,
6363
ImmutableSegmentedDictionary<ProjectId, ICompilationTracker> projectIdToTrackerMap,
6464
SourceGeneratorExecutionVersionMap sourceGeneratorExecutionVersionMap,
65-
TextDocumentStates<SourceGeneratedDocumentState>? frozenSourceGeneratedDocumentStates,
65+
TextDocumentStates<SourceGeneratedDocumentState> frozenSourceGeneratedDocumentStates,
6666
AsyncLazy<SolutionCompilationState>? cachedFrozenSnapshot = null)
6767
{
6868
SolutionState = solution;
@@ -94,7 +94,7 @@ public SolutionCompilationState(
9494
partialSemanticsEnabled,
9595
projectIdToTrackerMap: ImmutableSegmentedDictionary<ProjectId, ICompilationTracker>.Empty,
9696
sourceGeneratorExecutionVersionMap: SourceGeneratorExecutionVersionMap.Empty,
97-
frozenSourceGeneratedDocumentStates: null)
97+
frozenSourceGeneratedDocumentStates: TextDocumentStates<SourceGeneratedDocumentState>.Empty)
9898
{
9999
}
100100

@@ -117,7 +117,7 @@ private SolutionCompilationState Branch(
117117
SolutionState newSolutionState,
118118
ImmutableSegmentedDictionary<ProjectId, ICompilationTracker>? projectIdToTrackerMap = null,
119119
SourceGeneratorExecutionVersionMap? sourceGeneratorExecutionVersionMap = null,
120-
Optional<TextDocumentStates<SourceGeneratedDocumentState>?> frozenSourceGeneratedDocumentStates = default,
120+
Optional<TextDocumentStates<SourceGeneratedDocumentState>> frozenSourceGeneratedDocumentStates = default,
121121
AsyncLazy<SolutionCompilationState>? cachedFrozenSnapshot = null)
122122
{
123123
projectIdToTrackerMap ??= _projectIdToTrackerMap;
@@ -1277,7 +1277,7 @@ public ValueTask<ImmutableArray<Diagnostic>> GetSourceGeneratorDiagnosticsAsync(
12771277
public SolutionCompilationState WithoutFrozenSourceGeneratedDocuments()
12781278
{
12791279
// If there's nothing frozen, there's nothing to do.
1280-
if (FrozenSourceGeneratedDocumentStates == null)
1280+
if (FrozenSourceGeneratedDocumentStates.IsEmpty)
12811281
return this;
12821282

12831283
var projectIdsToUnfreeze = FrozenSourceGeneratedDocumentStates.States.Values
@@ -1312,7 +1312,7 @@ public SolutionCompilationState WithoutFrozenSourceGeneratedDocuments()
13121312
return this.Branch(
13131313
this.SolutionState,
13141314
projectIdToTrackerMap: newTrackerMap,
1315-
frozenSourceGeneratedDocumentStates: null);
1315+
frozenSourceGeneratedDocumentStates: TextDocumentStates<SourceGeneratedDocumentState>.Empty);
13161316
}
13171317

13181318
/// <summary>
@@ -1328,7 +1328,7 @@ public SolutionCompilationState WithFrozenSourceGeneratedDocuments(
13281328
// and so those are always forks off the main solution. There's also a bit of a design question -- does calling this a second time
13291329
// leave the existing frozen documents in place, or replace them? It depends on the need, but until then we'll cross that bridge
13301330
// if/when we need it.
1331-
Contract.ThrowIfFalse(FrozenSourceGeneratedDocumentStates == null, $"We shouldn't be calling {nameof(WithFrozenSourceGeneratedDocuments)} on a solution with frozen source generated documents.");
1331+
Contract.ThrowIfTrue(FrozenSourceGeneratedDocumentStates.Count > 0, $"We shouldn't be calling {nameof(WithFrozenSourceGeneratedDocuments)} on a solution with frozen source generated documents.");
13321332

13331333
if (documents.IsEmpty)
13341334
return this;

src/Workspaces/Core/Portable/Workspace/Solution/SolutionCompilationState_Checksum.cs

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -123,20 +123,13 @@ public async Task<Checksum> GetChecksumAsync(ProjectId projectId, CancellationTo
123123
projectCone = stateChecksums.ProjectCone;
124124
}
125125

126-
ChecksumCollection? frozenSourceGeneratedDocumentIdentities = null;
127-
DocumentChecksumsAndIds? frozenSourceGeneratedDocumentTexts = null;
128-
ImmutableArray<DateTime> frozenSourceGeneratedDocumentGenerationDateTimes = default;
126+
var serializer = this.SolutionState.Services.GetRequiredService<ISerializerService>();
127+
var identityChecksums = FrozenSourceGeneratedDocumentStates.SelectAsArray(
128+
static (s, arg) => arg.serializer.CreateChecksum(s.Identity, cancellationToken: arg.cancellationToken), (serializer, cancellationToken));
129129

130-
if (FrozenSourceGeneratedDocumentStates != null)
131-
{
132-
var serializer = this.SolutionState.Services.GetRequiredService<ISerializerService>();
133-
var identityChecksums = FrozenSourceGeneratedDocumentStates.SelectAsArray(
134-
static (s, arg) => arg.serializer.CreateChecksum(s.Identity, cancellationToken: arg.cancellationToken), (serializer, cancellationToken));
135-
136-
frozenSourceGeneratedDocumentTexts = await FrozenSourceGeneratedDocumentStates.GetDocumentChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false);
137-
frozenSourceGeneratedDocumentIdentities = new ChecksumCollection(identityChecksums);
138-
frozenSourceGeneratedDocumentGenerationDateTimes = FrozenSourceGeneratedDocumentStates.SelectAsArray(d => d.GenerationDateTime);
139-
}
130+
var frozenSourceGeneratedDocumentTexts = await FrozenSourceGeneratedDocumentStates.GetDocumentChecksumsAndIdsAsync(cancellationToken).ConfigureAwait(false);
131+
var frozenSourceGeneratedDocumentIdentities = new ChecksumCollection(identityChecksums);
132+
var frozenSourceGeneratedDocumentGenerationDateTimes = FrozenSourceGeneratedDocumentStates.SelectAsArray(d => d.GenerationDateTime);
140133

141134
// Ensure we only send the execution map over for projects in the project cone.
142135
var versionMapChecksum = this.GetFilteredSourceGenerationExecutionMap(projectCone).GetChecksum();

src/Workspaces/Core/Portable/Workspace/Solution/StateChecksums.cs

Lines changed: 43 additions & 66 deletions
Original file line numberDiff line numberDiff line change
@@ -22,15 +22,10 @@ public SolutionCompilationStateChecksums(
2222
Checksum solutionState,
2323
Checksum sourceGeneratorExecutionVersionMap,
2424
// These arrays are all the same length if present, and reference the same documents in the same order.
25-
DocumentChecksumsAndIds? frozenSourceGeneratedDocuments,
26-
ChecksumCollection? frozenSourceGeneratedDocumentIdentities,
25+
DocumentChecksumsAndIds frozenSourceGeneratedDocuments,
26+
ChecksumCollection frozenSourceGeneratedDocumentIdentities,
2727
ImmutableArray<DateTime> frozenSourceGeneratedDocumentGenerationDateTimes)
2828
{
29-
// For the frozen source generated document info, we expect two either have both checksum collections or neither, and they
30-
// should both be the same length as there is a 1:1 correspondence between them.
31-
Contract.ThrowIfFalse(frozenSourceGeneratedDocumentIdentities.HasValue == frozenSourceGeneratedDocuments.HasValue);
32-
Contract.ThrowIfFalse(frozenSourceGeneratedDocumentIdentities?.Count == frozenSourceGeneratedDocuments?.Length);
33-
3429
SolutionState = solutionState;
3530
SourceGeneratorExecutionVersionMap = sourceGeneratorExecutionVersionMap;
3631
FrozenSourceGeneratedDocuments = frozenSourceGeneratedDocuments;
@@ -42,8 +37,8 @@ public SolutionCompilationStateChecksums(
4237
Checksum = Checksum.Create(
4338
SolutionState,
4439
SourceGeneratorExecutionVersionMap,
45-
FrozenSourceGeneratedDocumentIdentities?.Checksum ?? Checksum.Null,
46-
frozenSourceGeneratedDocuments?.Checksum ?? Checksum.Null);
40+
FrozenSourceGeneratedDocumentIdentities.Checksum,
41+
frozenSourceGeneratedDocuments.Checksum);
4742
}
4843

4944
public Checksum Checksum { get; }
@@ -53,8 +48,8 @@ public SolutionCompilationStateChecksums(
5348
/// <summary>
5449
/// Checksums of the SourceTexts of the frozen documents directly. Not checksums of their DocumentStates.
5550
/// </summary>
56-
public DocumentChecksumsAndIds? FrozenSourceGeneratedDocuments { get; }
57-
public ChecksumCollection? FrozenSourceGeneratedDocumentIdentities { get; }
51+
public DocumentChecksumsAndIds FrozenSourceGeneratedDocuments { get; }
52+
public ChecksumCollection FrozenSourceGeneratedDocumentIdentities { get; }
5853

5954
// note: intentionally not part of the identity contract of this type.
6055
public ImmutableArray<DateTime> FrozenSourceGeneratedDocumentGenerationDateTimes { get; }
@@ -64,8 +59,8 @@ public void AddAllTo(HashSet<Checksum> checksums)
6459
checksums.AddIfNotNullChecksum(this.Checksum);
6560
checksums.AddIfNotNullChecksum(this.SolutionState);
6661
checksums.AddIfNotNullChecksum(this.SourceGeneratorExecutionVersionMap);
67-
this.FrozenSourceGeneratedDocumentIdentities?.AddAllTo(checksums);
68-
this.FrozenSourceGeneratedDocuments?.AddAllTo(checksums);
62+
this.FrozenSourceGeneratedDocumentIdentities.AddAllTo(checksums);
63+
this.FrozenSourceGeneratedDocuments.AddAllTo(checksums);
6964
}
7065

7166
public void Serialize(ObjectWriter writer)
@@ -76,13 +71,9 @@ public void Serialize(ObjectWriter writer)
7671
this.SourceGeneratorExecutionVersionMap.WriteTo(writer);
7772

7873
// Write out a boolean to know whether we'll have this extra information
79-
writer.WriteBoolean(this.FrozenSourceGeneratedDocumentIdentities.HasValue);
80-
if (FrozenSourceGeneratedDocumentIdentities.HasValue)
81-
{
82-
this.FrozenSourceGeneratedDocuments!.Value.WriteTo(writer);
83-
this.FrozenSourceGeneratedDocumentIdentities.Value.WriteTo(writer);
84-
writer.WriteArray(this.FrozenSourceGeneratedDocumentGenerationDateTimes, static (w, d) => w.WriteInt64(d.Ticks));
85-
}
74+
this.FrozenSourceGeneratedDocuments.WriteTo(writer);
75+
this.FrozenSourceGeneratedDocumentIdentities.WriteTo(writer);
76+
writer.WriteArray(this.FrozenSourceGeneratedDocumentGenerationDateTimes, static (w, d) => w.WriteInt64(d.Ticks));
8677
}
8778

8879
public static SolutionCompilationStateChecksums Deserialize(ObjectReader reader)
@@ -91,17 +82,9 @@ public static SolutionCompilationStateChecksums Deserialize(ObjectReader reader)
9182
var solutionState = Checksum.ReadFrom(reader);
9283
var sourceGeneratorExecutionVersionMap = Checksum.ReadFrom(reader);
9384

94-
var hasFrozenSourceGeneratedDocuments = reader.ReadBoolean();
95-
DocumentChecksumsAndIds? frozenSourceGeneratedDocumentTexts = null;
96-
ChecksumCollection? frozenSourceGeneratedDocumentIdentities = null;
97-
ImmutableArray<DateTime> frozenSourceGeneratedDocumentGenerationDateTimes = default;
98-
99-
if (hasFrozenSourceGeneratedDocuments)
100-
{
101-
frozenSourceGeneratedDocumentTexts = DocumentChecksumsAndIds.ReadFrom(reader);
102-
frozenSourceGeneratedDocumentIdentities = ChecksumCollection.ReadFrom(reader);
103-
frozenSourceGeneratedDocumentGenerationDateTimes = reader.ReadArray(r => new DateTime(r.ReadInt64()));
104-
}
85+
var frozenSourceGeneratedDocumentTexts = DocumentChecksumsAndIds.ReadFrom(reader);
86+
var frozenSourceGeneratedDocumentIdentities = ChecksumCollection.ReadFrom(reader);
87+
var frozenSourceGeneratedDocumentGenerationDateTimes = reader.ReadArray(r => new DateTime(r.ReadInt64()));
10588

10689
var result = new SolutionCompilationStateChecksums(
10790
solutionState: solutionState,
@@ -138,50 +121,44 @@ public async Task FindAsync<TArg>(
138121
onAssetFound(this.SourceGeneratorExecutionVersionMap, filteredExecutionMap, arg);
139122
}
140123

141-
if (compilationState.FrozenSourceGeneratedDocumentStates != null)
124+
// This could either be the checksum for the text (which we'll use our regular helper for first)...
125+
if (assetPath.IncludeSolutionFrozenSourceGeneratedDocumentText)
142126
{
143-
Contract.ThrowIfFalse(FrozenSourceGeneratedDocumentIdentities.HasValue);
144-
Contract.ThrowIfFalse(FrozenSourceGeneratedDocuments.HasValue);
145-
146-
// This could either be the checksum for the text (which we'll use our regular helper for first)...
147-
if (assetPath.IncludeSolutionFrozenSourceGeneratedDocumentText)
148-
{
149-
await ChecksumCollection.FindAsync(
150-
new AssetPath(AssetPathKind.DocumentText, assetPath.ProjectId, assetPath.DocumentId),
151-
compilationState.FrozenSourceGeneratedDocumentStates, searchingChecksumsLeft, onAssetFound, arg, cancellationToken).ConfigureAwait(false);
152-
}
127+
await ChecksumCollection.FindAsync(
128+
new AssetPath(AssetPathKind.DocumentText, assetPath.ProjectId, assetPath.DocumentId),
129+
compilationState.FrozenSourceGeneratedDocumentStates, searchingChecksumsLeft, onAssetFound, arg, cancellationToken).ConfigureAwait(false);
130+
}
153131

154-
// ... or one of the identities. In this case, we'll use the fact that there's a 1:1 correspondence between the
155-
// two collections we hold onto.
156-
if (assetPath.IncludeSolutionFrozenSourceGeneratedDocumentIdentities)
132+
// ... or one of the identities. In this case, we'll use the fact that there's a 1:1 correspondence between the
133+
// two collections we hold onto.
134+
if (assetPath.IncludeSolutionFrozenSourceGeneratedDocumentIdentities)
135+
{
136+
var documentId = assetPath.DocumentId;
137+
if (documentId != null)
157138
{
158-
var documentId = assetPath.DocumentId;
159-
if (documentId != null)
139+
// If the caller is asking for a specific document, we can just look it up directly.
140+
var index = FrozenSourceGeneratedDocuments.Ids.IndexOf(documentId);
141+
if (index >= 0)
160142
{
161-
// If the caller is asking for a specific document, we can just look it up directly.
162-
var index = FrozenSourceGeneratedDocuments.Value.Ids.IndexOf(documentId);
163-
if (index >= 0)
143+
var identityChecksum = FrozenSourceGeneratedDocumentIdentities.Children[index];
144+
if (searchingChecksumsLeft.Remove(identityChecksum))
164145
{
165-
var identityChecksum = FrozenSourceGeneratedDocumentIdentities.Value.Children[index];
166-
if (searchingChecksumsLeft.Remove(identityChecksum))
167-
{
168-
Contract.ThrowIfFalse(compilationState.FrozenSourceGeneratedDocumentStates.TryGetState(documentId, out var state));
169-
onAssetFound(identityChecksum, state.Identity, arg);
170-
}
146+
Contract.ThrowIfFalse(compilationState.FrozenSourceGeneratedDocumentStates.TryGetState(documentId, out var state));
147+
onAssetFound(identityChecksum, state.Identity, arg);
171148
}
172149
}
173-
else
150+
}
151+
else
152+
{
153+
// Otherwise, we'll have to search through all of them.
154+
for (var i = 0; i < FrozenSourceGeneratedDocumentIdentities.Count; i++)
174155
{
175-
// Otherwise, we'll have to search through all of them.
176-
for (var i = 0; i < FrozenSourceGeneratedDocumentIdentities.Value.Count; i++)
156+
var identityChecksum = FrozenSourceGeneratedDocumentIdentities[0];
157+
if (searchingChecksumsLeft.Remove(identityChecksum))
177158
{
178-
var identityChecksum = FrozenSourceGeneratedDocumentIdentities.Value[0];
179-
if (searchingChecksumsLeft.Remove(identityChecksum))
180-
{
181-
var id = FrozenSourceGeneratedDocuments.Value.Ids[i];
182-
Contract.ThrowIfFalse(compilationState.FrozenSourceGeneratedDocumentStates.TryGetState(id, out var state));
183-
onAssetFound(identityChecksum, state.Identity, arg);
184-
}
159+
var id = FrozenSourceGeneratedDocuments.Ids[i];
160+
Contract.ThrowIfFalse(compilationState.FrozenSourceGeneratedDocumentStates.TryGetState(id, out var state));
161+
onAssetFound(identityChecksum, state.Identity, arg);
185162
}
186163
}
187164
}

src/Workspaces/Remote/ServiceHub/Host/RemoteWorkspace.SolutionCreator.cs

Lines changed: 2 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -82,12 +82,9 @@ public async Task<Solution> CreateSolutionAsync(Checksum newSolutionChecksum, Ca
8282
AssetPathKind.SolutionFallbackAnalyzerOptions, newSolutionChecksums.FallbackAnalyzerOptions, cancellationToken).ConfigureAwait(false));
8383
}
8484

85-
if (newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.HasValue &&
86-
newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.HasValue &&
87-
!newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentGenerationDateTimes.IsDefault)
8885
{
89-
var newSolutionFrozenSourceGeneratedDocumentIdentities = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities.Value;
90-
var newSolutionFrozenSourceGeneratedDocuments = newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments.Value;
86+
var newSolutionFrozenSourceGeneratedDocumentIdentities = newSolutionCompilationChecksums.FrozenSourceGeneratedDocumentIdentities;
87+
var newSolutionFrozenSourceGeneratedDocuments = newSolutionCompilationChecksums.FrozenSourceGeneratedDocuments;
9188
var count = newSolutionFrozenSourceGeneratedDocuments.Ids.Length;
9289

9390
var frozenDocuments = new FixedSizeArrayBuilder<(SourceGeneratedDocumentIdentity identity, DateTime generationDateTime, SourceText text)>(count);

0 commit comments

Comments
 (0)