Skip to content

Commit 51de45f

Browse files
committed
EnC: Fix symbol mapping of delegates with indexed name
1 parent f616d20 commit 51de45f

File tree

28 files changed

+1090
-497
lines changed

28 files changed

+1090
-497
lines changed

src/Compilers/CSharp/Portable/Emitter/EditAndContinue/CSharpSymbolMatcher.cs

Lines changed: 52 additions & 45 deletions
Original file line numberDiff line numberDiff line change
@@ -7,13 +7,12 @@
77
using System.Collections.Generic;
88
using System.Collections.Immutable;
99
using System.Diagnostics;
10-
using System.Diagnostics.CodeAnalysis;
1110
using System.Linq;
1211
using Microsoft.CodeAnalysis.CodeGen;
12+
using Microsoft.CodeAnalysis.Collections;
1313
using Microsoft.CodeAnalysis.CSharp.Symbols;
1414
using Microsoft.CodeAnalysis.CSharp.Symbols.Metadata.PE;
1515
using Microsoft.CodeAnalysis.Emit;
16-
using Microsoft.CodeAnalysis.Emit.EditAndContinue;
1716
using Microsoft.CodeAnalysis.PooledObjects;
1817
using Microsoft.CodeAnalysis.Symbols;
1918
using Roslyn.Utilities;
@@ -27,25 +26,31 @@ internal sealed class CSharpSymbolMatcher : SymbolMatcher
2726
public CSharpSymbolMatcher(
2827
SourceAssemblySymbol sourceAssembly,
2928
SourceAssemblySymbol otherAssembly,
30-
SynthesizedTypeMaps synthesizedTypes,
31-
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherSynthesizedMembers,
32-
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherDeletedMembers)
29+
SynthesizedTypeMaps otherSynthesizedTypes,
30+
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> otherSynthesizedMembers,
31+
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> otherDeletedMembers)
3332
{
34-
_visitor = new Visitor(sourceAssembly, otherAssembly, synthesizedTypes, otherSynthesizedMembers, otherDeletedMembers, new DeepTranslator(otherAssembly.GetSpecialType(SpecialType.System_Object)));
33+
_visitor = new Visitor(
34+
sourceAssembly,
35+
otherAssembly,
36+
otherSynthesizedTypes,
37+
otherSynthesizedMembers,
38+
otherDeletedMembers,
39+
new DeepTranslator(otherAssembly.GetSpecialType(SpecialType.System_Object)));
3540
}
3641

3742
public CSharpSymbolMatcher(
38-
SynthesizedTypeMaps synthesizedTypes,
3943
SourceAssemblySymbol sourceAssembly,
40-
PEAssemblySymbol otherAssembly)
44+
PEAssemblySymbol otherAssembly,
45+
SynthesizedTypeMaps otherSynthesizedTypes)
4146
{
4247
_visitor = new Visitor(
4348
sourceAssembly,
4449
otherAssembly,
45-
synthesizedTypes,
46-
otherSynthesizedMembers: null,
47-
deepTranslator: null,
48-
otherDeletedMembers: null);
50+
otherSynthesizedTypes,
51+
otherSynthesizedMembers: SpecializedCollections.EmptyReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>(),
52+
otherDeletedMembers: SpecializedCollections.EmptyReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>(),
53+
deepTranslator: null);
4954
}
5055

5156
public override Cci.IDefinition? MapDefinition(Cci.IDefinition definition)
@@ -93,9 +98,12 @@ static bool isPrivateImplementationDetail(Cci.IDefinition definition)
9398
internal bool TryGetAnonymousTypeValue(AnonymousTypeManager.AnonymousTypeOrDelegateTemplateSymbol template, out AnonymousTypeValue typeValue)
9499
=> _visitor.TryGetAnonymousTypeValue(template, out typeValue);
95100

101+
protected override bool TryGetMatchingDelegateWithIndexedName(INamedTypeSymbolInternal delegateTemplate, ImmutableArray<AnonymousTypeValue> values, out AnonymousTypeValue match)
102+
=> _visitor.TryGetMatchingDelegateWithIndexedName((AnonymousTypeManager.AnonymousDelegateTemplateSymbol)delegateTemplate, values, out match);
103+
96104
private sealed class Visitor : CSharpSymbolVisitor<Symbol?>
97105
{
98-
private readonly SynthesizedTypeMaps _synthesizedTypes;
106+
private readonly SynthesizedTypeMaps _otherSynthesizedTypes;
99107
private readonly SourceAssemblySymbol _sourceAssembly;
100108

101109
// metadata or source assembly:
@@ -105,9 +113,9 @@ private sealed class Visitor : CSharpSymbolVisitor<Symbol?>
105113
/// Members that are not listed directly on their containing type or namespace symbol as they were synthesized in a lowering phase,
106114
/// after the symbol has been created.
107115
/// </summary>
108-
private readonly IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? _otherSynthesizedMembers;
116+
private readonly IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> _otherSynthesizedMembers;
109117

110-
private readonly IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? _otherDeletedMembers;
118+
private readonly IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> _otherDeletedMembers;
111119

112120
private readonly SymbolComparer _comparer;
113121
private readonly ConcurrentDictionary<Symbol, Symbol?> _matches = new(ReferenceEqualityComparer.Instance);
@@ -123,12 +131,12 @@ private sealed class Visitor : CSharpSymbolVisitor<Symbol?>
123131
public Visitor(
124132
SourceAssemblySymbol sourceAssembly,
125133
AssemblySymbol otherAssembly,
126-
SynthesizedTypeMaps synthesizedTypes,
127-
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherSynthesizedMembers,
128-
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherDeletedMembers,
134+
SynthesizedTypeMaps otherSynthesizedTypes,
135+
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> otherSynthesizedMembers,
136+
IReadOnlyDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>> otherDeletedMembers,
129137
DeepTranslator? deepTranslator)
130138
{
131-
_synthesizedTypes = synthesizedTypes;
139+
_otherSynthesizedTypes = otherSynthesizedTypes;
132140
_sourceAssembly = sourceAssembly;
133141
_otherAssembly = otherAssembly;
134142
_otherSynthesizedMembers = otherSynthesizedMembers;
@@ -470,45 +478,44 @@ private CustomModifier VisitCustomModifier(CustomModifier modifier)
470478
CSharpCustomModifier.CreateRequired(type);
471479
}
472480

473-
internal bool TryGetAnonymousDelegateValue(AnonymousTypeManager.AnonymousDelegateTemplateSymbol delegateSymbol, out SynthesizedDelegateValue otherDelegateSymbol)
481+
private bool TryGetAnonymousDelegateValue(AnonymousTypeManager.AnonymousDelegateTemplateSymbol delegateSymbol, out SynthesizedDelegateValue otherDelegateSymbol)
474482
{
475-
Debug.Assert((object)delegateSymbol.ContainingSymbol == (object)_sourceAssembly.GlobalNamespace);
476-
477483
var key = new SynthesizedDelegateKey(delegateSymbol.MetadataName);
478-
return _synthesizedTypes.AnonymousDelegates.TryGetValue(key, out otherDelegateSymbol);
484+
return _otherSynthesizedTypes.AnonymousDelegates.TryGetValue(key, out otherDelegateSymbol);
479485
}
480486

481487
internal bool TryGetAnonymousTypeValue(AnonymousTypeManager.AnonymousTypeOrDelegateTemplateSymbol template, out AnonymousTypeValue otherType)
482488
{
483-
Debug.Assert((object)template.ContainingSymbol == (object)_sourceAssembly.GlobalNamespace);
484-
485489
if (template is AnonymousTypeManager.AnonymousTypeTemplateSymbol typeTemplate)
486490
{
487-
return _synthesizedTypes.AnonymousTypes.TryGetValue(typeTemplate.GetAnonymousTypeKey(), out otherType);
491+
return _otherSynthesizedTypes.AnonymousTypes.TryGetValue(typeTemplate.GetAnonymousTypeKey(), out otherType);
488492
}
489493

490494
var delegateTemplate = (AnonymousTypeManager.AnonymousDelegateTemplateSymbol)template;
491495
Debug.Assert(delegateTemplate.DelegateInvokeMethod != null);
492496

497+
otherType = default;
498+
493499
var key = new AnonymousDelegateWithIndexedNamePartialKey(delegateTemplate.Arity, delegateTemplate.DelegateInvokeMethod.ParameterCount);
494-
if (_synthesizedTypes.AnonymousDelegatesWithIndexedNames.TryGetValue(key, out var otherTypeCandidates))
500+
return _otherSynthesizedTypes.AnonymousDelegatesWithIndexedNames.TryGetValue(key, out var otherTypeCandidates) &&
501+
TryGetMatchingDelegateWithIndexedName(delegateTemplate, otherTypeCandidates, out otherType);
502+
}
503+
504+
internal bool TryGetMatchingDelegateWithIndexedName(AnonymousTypeManager.AnonymousDelegateTemplateSymbol delegateTemplate, ImmutableArray<AnonymousTypeValue> values, out AnonymousTypeValue match)
505+
{
506+
foreach (var otherTypeCandidate in values)
495507
{
496-
// The key is partial (not unique). Find a matching Invoke method signature.
508+
var otherDelegateType = (NamedTypeSymbol?)otherTypeCandidate.Type.GetInternalSymbol();
509+
Debug.Assert(otherDelegateType is not null);
497510

498-
foreach (var otherTypeCandidate in otherTypeCandidates)
511+
if (isCorrespondingAnonymousDelegate(delegateTemplate, otherDelegateType))
499512
{
500-
var otherDelegateType = (NamedTypeSymbol?)otherTypeCandidate.Type.GetInternalSymbol();
501-
Debug.Assert(otherDelegateType is not null);
502-
503-
if (isCorrespondingAnonymousDelegate(delegateTemplate, otherDelegateType))
504-
{
505-
otherType = otherTypeCandidate;
506-
return true;
507-
}
513+
match = otherTypeCandidate;
514+
return true;
508515
}
509516
}
510517

511-
otherType = default;
518+
match = default;
512519
return false;
513520

514521
bool isCorrespondingAnonymousDelegate(NamedTypeSymbol type, NamedTypeSymbol otherType)
@@ -526,12 +533,12 @@ otherType.DelegateInvokeMethod is { } otherInvokeMethod &&
526533
x.IsParamsArray == y.IsParamsArray &&
527534
x.IsParamsCollection == y.IsParamsCollection) &&
528535
isCorrespondingType(invokeMethod.ReturnTypeWithAnnotations, otherInvokeMethod.ReturnTypeWithAnnotations);
529-
}
530536

531-
bool isCorrespondingType(TypeWithAnnotations type, TypeWithAnnotations expectedType)
532-
{
533-
var otherType = type.WithTypeAndModifiers((TypeSymbol?)this.Visit(type.Type), this.VisitCustomModifiers(type.CustomModifiers));
534-
return otherType.Equals(expectedType, TypeCompareKind.CLRSignatureCompareOptions);
537+
bool isCorrespondingType(TypeWithAnnotations type, TypeWithAnnotations expectedType)
538+
{
539+
var otherType = type.WithTypeAndModifiers((TypeSymbol?)this.Visit(type.Type), this.VisitCustomModifiers(type.CustomModifiers));
540+
return otherType.Equals(expectedType, TypeCompareKind.CLRSignatureCompareOptions);
541+
}
535542
}
536543
}
537544

@@ -799,12 +806,12 @@ private IReadOnlyDictionary<string, ImmutableArray<ISymbolInternal>> GetAllEmitt
799806
members.AddRange(((NamespaceSymbol)symbol).GetMembers());
800807
}
801808

802-
if (_otherSynthesizedMembers != null && _otherSynthesizedMembers.TryGetValue(symbol, out var synthesizedMembers))
809+
if (_otherSynthesizedMembers.TryGetValue(symbol, out var synthesizedMembers))
803810
{
804811
members.AddRange(synthesizedMembers);
805812
}
806813

807-
if (_otherDeletedMembers?.TryGetValue(symbol, out var deletedMembers) == true)
814+
if (_otherDeletedMembers.TryGetValue(symbol, out var deletedMembers))
808815
{
809816
members.AddRange(deletedMembers);
810817
}

src/Compilers/CSharp/Portable/Emitter/EditAndContinue/EmitHelpers.cs

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -67,14 +67,14 @@ internal static EmitDifferenceResult EmitDifference(
6767
var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly;
6868

6969
var sourceToMetadata = new CSharpSymbolMatcher(
70-
metadataSymbols.SynthesizedTypes,
71-
sourceAssembly,
72-
metadataAssembly);
70+
sourceAssembly: sourceAssembly,
71+
otherAssembly: metadataAssembly,
72+
otherSynthesizedTypes: metadataSymbols.SynthesizedTypes);
7373

7474
var previousSourceToMetadata = new CSharpSymbolMatcher(
75-
metadataSymbols.SynthesizedTypes,
76-
previousSourceAssembly,
77-
metadataAssembly);
75+
sourceAssembly: previousSourceAssembly,
76+
otherAssembly: metadataAssembly,
77+
otherSynthesizedTypes: metadataSymbols.SynthesizedTypes);
7878

7979
CSharpSymbolMatcher? currentSourceToPreviousSource = null;
8080
if (baseline.Ordinal > 0)
@@ -84,7 +84,7 @@ internal static EmitDifferenceResult EmitDifference(
8484
currentSourceToPreviousSource = new CSharpSymbolMatcher(
8585
sourceAssembly: sourceAssembly,
8686
otherAssembly: previousSourceAssembly,
87-
baseline.SynthesizedTypes,
87+
otherSynthesizedTypes: baseline.SynthesizedTypes,
8888
otherSynthesizedMembers: baseline.SynthesizedMembers,
8989
otherDeletedMembers: baseline.DeletedMembers);
9090
}
@@ -205,37 +205,40 @@ internal static EmitBaseline MapToCompilation(
205205
RoslynDebug.AssertNotNull(previousGeneration.PEModuleBuilder);
206206
RoslynDebug.AssertNotNull(moduleBeingBuilt.EncSymbolChanges);
207207

208-
var synthesizedTypes = moduleBeingBuilt.GetSynthesizedTypes();
208+
var currentSynthesizedTypes = moduleBeingBuilt.GetAllSynthesizedTypes();
209209
var currentSynthesizedMembers = moduleBeingBuilt.GetAllSynthesizedMembers();
210210
var currentDeletedMembers = moduleBeingBuilt.EncSymbolChanges.DeletedMembers;
211211

212212
// Mapping from previous compilation to the current.
213213
var previousSourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
214214

215215
var matcher = new CSharpSymbolMatcher(
216-
previousSourceAssembly,
217-
compilation.SourceAssembly,
218-
synthesizedTypes,
219-
currentSynthesizedMembers,
220-
currentDeletedMembers);
216+
sourceAssembly: previousSourceAssembly,
217+
otherAssembly: compilation.SourceAssembly,
218+
otherSynthesizedTypes: currentSynthesizedTypes,
219+
otherSynthesizedMembers: currentSynthesizedMembers,
220+
otherDeletedMembers: currentDeletedMembers);
221+
222+
var mappedSynthesizedTypes = matcher.MapSynthesizedTypes(previousGeneration.SynthesizedTypes, currentSynthesizedTypes);
221223

222224
var mappedSynthesizedMembers = matcher.MapSynthesizedOrDeletedMembers(previousGeneration.SynthesizedMembers, currentSynthesizedMembers, isDeletedMemberMapping: false);
223225

224226
// Deleted members are mapped the same way as synthesized members, so we can just call the same method.
225227
var mappedDeletedMembers = matcher.MapSynthesizedOrDeletedMembers(previousGeneration.DeletedMembers, currentDeletedMembers, isDeletedMemberMapping: true);
226228

227229
// TODO: can we reuse some data from the previous matcher?
228-
var matcherWithAllSynthesizedMembers = new CSharpSymbolMatcher(
229-
previousSourceAssembly,
230-
compilation.SourceAssembly,
231-
synthesizedTypes,
232-
mappedSynthesizedMembers,
233-
mappedDeletedMembers);
234-
235-
return matcherWithAllSynthesizedMembers.MapBaselineToCompilation(
230+
var matcherWithAllSynthesizedTypesAndMembers = new CSharpSymbolMatcher(
231+
sourceAssembly: previousSourceAssembly,
232+
otherAssembly: compilation.SourceAssembly,
233+
otherSynthesizedTypes: mappedSynthesizedTypes,
234+
otherSynthesizedMembers: mappedSynthesizedMembers,
235+
otherDeletedMembers: mappedDeletedMembers);
236+
237+
return matcherWithAllSynthesizedTypesAndMembers.MapBaselineToCompilation(
236238
previousGeneration,
237239
compilation,
238240
moduleBeingBuilt,
241+
mappedSynthesizedTypes,
239242
mappedSynthesizedMembers,
240243
mappedDeletedMembers);
241244
}

src/Compilers/CSharp/Portable/Emitter/EditAndContinue/PEDeltaAssemblyBuilder.cs

Lines changed: 0 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -224,19 +224,6 @@ private static bool TryGetAnonymousTypeKey(
224224
internal CSharpDefinitionMap PreviousDefinitions
225225
=> (CSharpDefinitionMap)_changes.DefinitionMap;
226226

227-
public SynthesizedTypeMaps GetSynthesizedTypes()
228-
{
229-
var result = new SynthesizedTypeMaps(
230-
Compilation.AnonymousTypeManager.GetAnonymousTypeMap(),
231-
Compilation.AnonymousTypeManager.GetAnonymousDelegates(),
232-
Compilation.AnonymousTypeManager.GetAnonymousDelegatesWithIndexedNames());
233-
234-
// Should contain all entries in previous generation.
235-
Debug.Assert(PreviousGeneration.SynthesizedTypes.IsSubsetOf(result));
236-
237-
return result;
238-
}
239-
240227
public override IEnumerable<Cci.INamespaceTypeDefinition> GetTopLevelTypeDefinitions(EmitContext context)
241228
=> GetTopLevelTypeDefinitionsExcludingNoPiaAndRootModule(context, includePrivateImplementationDetails: true);
242229

@@ -258,16 +245,6 @@ internal override MethodInstrumentation GetMethodBodyInstrumentations(MethodSymb
258245
return _changes.DefinitionMap.GetMethodBodyInstrumentations(method);
259246
}
260247

261-
internal override ImmutableArray<AnonymousTypeKey> GetPreviousAnonymousTypes()
262-
{
263-
return ImmutableArray.CreateRange(PreviousGeneration.SynthesizedTypes.AnonymousTypes.Keys);
264-
}
265-
266-
internal override ImmutableArray<SynthesizedDelegateKey> GetPreviousAnonymousDelegates()
267-
{
268-
return ImmutableArray.CreateRange(PreviousGeneration.SynthesizedTypes.AnonymousDelegates.Keys);
269-
}
270-
271248
internal override int GetNextAnonymousTypeIndex()
272249
=> PreviousGeneration.GetNextAnonymousTypeIndex();
273250

src/Compilers/CSharp/Portable/Emitter/Model/PEModuleBuilder.cs

Lines changed: 0 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -505,16 +505,6 @@ internal virtual VariableSlotAllocator TryCreateVariableSlotAllocator(MethodSymb
505505
internal virtual MethodInstrumentation GetMethodBodyInstrumentations(MethodSymbol method)
506506
=> new MethodInstrumentation { Kinds = EmitOptions.InstrumentationKinds };
507507

508-
internal virtual ImmutableArray<AnonymousTypeKey> GetPreviousAnonymousTypes()
509-
{
510-
return ImmutableArray<AnonymousTypeKey>.Empty;
511-
}
512-
513-
internal virtual ImmutableArray<SynthesizedDelegateKey> GetPreviousAnonymousDelegates()
514-
{
515-
return ImmutableArray<SynthesizedDelegateKey>.Empty;
516-
}
517-
518508
internal virtual int GetNextAnonymousTypeIndex()
519509
{
520510
return 0;

0 commit comments

Comments
 (0)