Skip to content

Commit

Permalink
Refactoring of synthesized types tracking accross EnC generations
Browse files Browse the repository at this point in the history
  • Loading branch information
tmat committed Aug 12, 2023
1 parent 2dd3a65 commit 61f8408
Show file tree
Hide file tree
Showing 18 changed files with 334 additions and 811 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,36 +26,30 @@ internal sealed class CSharpSymbolMatcher : SymbolMatcher
private readonly MatchSymbols _symbols;

public CSharpSymbolMatcher(
IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> anonymousTypeMap,
IReadOnlyDictionary<SynthesizedDelegateKey, SynthesizedDelegateValue> anonymousDelegates,
IReadOnlyDictionary<string, AnonymousTypeValue> anonymousDelegatesWithIndexedNames,
SourceAssemblySymbol sourceAssembly,
EmitContext sourceContext,
SourceAssemblySymbol otherAssembly,
EmitContext otherContext,
SynthesizedTypeMaps synthesizedTypes,
ImmutableDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherSynthesizedMembers,
ImmutableDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherDeletedMembers)
{
_defs = new MatchDefsToSource(sourceContext, otherContext);
_symbols = new MatchSymbols(anonymousTypeMap, anonymousDelegates, anonymousDelegatesWithIndexedNames, sourceAssembly, otherAssembly, otherSynthesizedMembers, otherDeletedMembers, new DeepTranslator(otherAssembly.GetSpecialType(SpecialType.System_Object)));
_symbols = new MatchSymbols(sourceAssembly, otherAssembly, synthesizedTypes, otherSynthesizedMembers, otherDeletedMembers, new DeepTranslator(otherAssembly.GetSpecialType(SpecialType.System_Object)));
}

public CSharpSymbolMatcher(
IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> anonymousTypeMap,
IReadOnlyDictionary<SynthesizedDelegateKey, SynthesizedDelegateValue> anonymousDelegates,
IReadOnlyDictionary<string, AnonymousTypeValue> anonymousDelegatesWithIndexedNames,
SynthesizedTypeMaps synthesizedTypes,
SourceAssemblySymbol sourceAssembly,
EmitContext sourceContext,
PEAssemblySymbol otherAssembly)
{
_defs = new MatchDefsToMetadata(sourceContext, otherAssembly);

_symbols = new MatchSymbols(
anonymousTypeMap,
anonymousDelegates,
anonymousDelegatesWithIndexedNames,
sourceAssembly,
otherAssembly,
synthesizedTypes,
otherSynthesizedMembers: null,
deepTranslator: null,
otherDeletedMembers: null);
Expand Down Expand Up @@ -281,9 +275,7 @@ public MatchDefsToSource(

private sealed class MatchSymbols : CSharpSymbolVisitor<Symbol?>
{
private readonly IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> _anonymousTypeMap;
private readonly IReadOnlyDictionary<SynthesizedDelegateKey, SynthesizedDelegateValue> _anonymousDelegates;
private readonly IReadOnlyDictionary<string, AnonymousTypeValue> _anonymousDelegatesWithIndexedNames;
private readonly SynthesizedTypeMaps _synthesizedTypes;
private readonly SourceAssemblySymbol _sourceAssembly;

// metadata or source assembly:
Expand All @@ -309,18 +301,14 @@ private sealed class MatchSymbols : CSharpSymbolVisitor<Symbol?>
private readonly ConcurrentDictionary<ISymbolInternal, IReadOnlyDictionary<string, ImmutableArray<ISymbolInternal>>> _otherMembers = new(ReferenceEqualityComparer.Instance);

public MatchSymbols(
IReadOnlyDictionary<AnonymousTypeKey, AnonymousTypeValue> anonymousTypeMap,
IReadOnlyDictionary<SynthesizedDelegateKey, SynthesizedDelegateValue> anonymousDelegates,
IReadOnlyDictionary<string, AnonymousTypeValue> anonymousDelegatesWithIndexedNames,
SourceAssemblySymbol sourceAssembly,
AssemblySymbol otherAssembly,
SynthesizedTypeMaps synthesizedTypes,
ImmutableDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherSynthesizedMembers,
ImmutableDictionary<ISymbolInternal, ImmutableArray<ISymbolInternal>>? otherDeletedMembers,
DeepTranslator? deepTranslator)
{
_anonymousTypeMap = anonymousTypeMap;
_anonymousDelegates = anonymousDelegates;
_anonymousDelegatesWithIndexedNames = anonymousDelegatesWithIndexedNames;
_synthesizedTypes = synthesizedTypes;
_sourceAssembly = sourceAssembly;
_otherAssembly = otherAssembly;
_otherSynthesizedMembers = otherSynthesizedMembers;
Expand Down Expand Up @@ -680,15 +668,15 @@ internal bool TryFindAnonymousType(AnonymousTypeManager.AnonymousTypeTemplateSym
{
Debug.Assert((object)type.ContainingSymbol == (object)_sourceAssembly.GlobalNamespace);

return _anonymousTypeMap.TryGetValue(type.GetAnonymousTypeKey(), out otherType);
return _synthesizedTypes.AnonymousTypes.TryGetValue(type.GetAnonymousTypeKey(), out otherType);
}

internal bool TryFindAnonymousDelegate(AnonymousTypeManager.AnonymousDelegateTemplateSymbol delegateSymbol, out SynthesizedDelegateValue otherDelegateSymbol)
{
Debug.Assert((object)delegateSymbol.ContainingSymbol == (object)_sourceAssembly.GlobalNamespace);

var key = new SynthesizedDelegateKey(delegateSymbol.MetadataName);
return _anonymousDelegates.TryGetValue(key, out otherDelegateSymbol);
return _synthesizedTypes.AnonymousDelegates.TryGetValue(key, out otherDelegateSymbol);
}

internal bool TryFindAnonymousDelegateWithIndexedName(AnonymousTypeManager.AnonymousDelegateTemplateSymbol type, out AnonymousTypeValue otherType)
Expand All @@ -701,7 +689,7 @@ internal bool TryFindAnonymousDelegateWithIndexedName(AnonymousTypeManager.Anony
// expression may have been changed explicitly, or another lambda expression may have been inserted
// ahead of this one in source order. Therefore, we need to verify the signatures of the delegate types
// are equivalent - by comparing the Invoke() method signatures.
if (_anonymousDelegatesWithIndexedNames.TryGetValue(type.Name, out otherType) &&
if (_synthesizedTypes.AnonymousDelegatesWithIndexedNames.TryGetValue(type.Name, out otherType) &&
otherType.Type.GetInternalSymbol() is NamedTypeSymbol otherDelegateType &&
isCorrespondingAnonymousDelegate(type, otherDelegateType))
{
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,7 @@
using System.Reflection.Metadata;
using System.Threading;
using Microsoft.CodeAnalysis.CodeGen;
using Microsoft.CodeAnalysis.CSharp.Symbols;
using Microsoft.CodeAnalysis.Emit;
using Microsoft.CodeAnalysis.PooledObjects;
using Roslyn.Utilities;
Expand Down Expand Up @@ -82,7 +83,7 @@ internal static EmitDifferenceResult EmitDifference(
filterOpt: s => changes.RequiresCompilation(s.GetISymbol()),
cancellationToken: cancellationToken))
{
if (!ContainsPreviousAnonymousDelegates(definitionMap, baseline.AnonymousDelegatesWithIndexedNames, moduleBeingBuilt.GetAnonymousDelegatesWithIndexedNames()))
if (!ContainsPreviousAnonymousDelegates(definitionMap, baseline.SynthesizedTypes.AnonymousDelegatesWithIndexedNames, compilation.AnonymousTypeManager.GetCreatedAnonymousDelegateTypesWithIndexedNames()))
{
diagnostics.Add(ErrorCode.ERR_EncUpdateFailedDelegateTypeChanged, Location.None);
}
Expand Down Expand Up @@ -120,32 +121,31 @@ internal static EmitDifferenceResult EmitDifference(

private static bool ContainsPreviousAnonymousDelegates(
CSharpDefinitionMap definitionMap,
IReadOnlyDictionary<string, AnonymousTypeValue> previousDictionary,
IReadOnlyDictionary<string, AnonymousTypeValue> currentDictionary)
ImmutableDictionary<string, AnonymousTypeValue> previousDictionary,
IEnumerable<Cci.ITypeDefinition> currentTypes)
{
if (previousDictionary.Count == 0)
{
return true;
}

if (previousDictionary.Count > currentDictionary.Count)
var currentTypesByName = currentTypes.ToImmutableDictionary(getName);
if (previousDictionary.Count > currentTypesByName.Count)
{
return false;
}

Dictionary<string, Cci.ITypeDefinition> currentTypes = getTypes(currentDictionary).ToDictionary(t => getName(t));
IEnumerable<Cci.ITypeDefinition> previousTypes = getTypes(previousDictionary);
foreach (var previousType in previousTypes)
foreach (var previousType in previousDictionary)
{
if (!currentTypes.TryGetValue(getName(previousType), out var currentType) ||
if (!currentTypesByName.TryGetValue(getName(previousType.Value.Type), out var currentType) ||
definitionMap.MapDefinition(currentType) is null)
{
return false;
}
}

return true;

static IEnumerable<Cci.ITypeDefinition> getTypes(IReadOnlyDictionary<string, AnonymousTypeValue> dictionary) => dictionary.Values.Select(v => v.Type);
static string getName(Cci.ITypeDefinition type) => ((Cci.INamedEntity)type).Name!;
}

Expand Down Expand Up @@ -175,25 +175,21 @@ private static EmitBaseline MapToCompilation(
RoslynDebug.AssertNotNull(previousGeneration.PEModuleBuilder);
RoslynDebug.AssertNotNull(moduleBeingBuilt.EncSymbolChanges);

var synthesizedTypes = moduleBeingBuilt.GetSynthesizedTypes();
var currentSynthesizedMembers = moduleBeingBuilt.GetAllSynthesizedMembers();
var currentDeletedMembers = moduleBeingBuilt.EncSymbolChanges.GetAllDeletedMembers();

// Mapping from previous compilation to the current.
var anonymousTypeMap = moduleBeingBuilt.GetAnonymousTypeMap();
var anonymousDelegates = moduleBeingBuilt.GetAnonymousDelegates();
var anonymousDelegatesWithIndexedNames = moduleBeingBuilt.GetAnonymousDelegatesWithIndexedNames();
var sourceAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly;
var sourceContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);
var otherContext = new EmitContext(moduleBeingBuilt, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true);

var matcher = new CSharpSymbolMatcher(
anonymousTypeMap,
anonymousDelegates,
anonymousDelegatesWithIndexedNames,
sourceAssembly,
sourceContext,
compilation.SourceAssembly,
otherContext,
synthesizedTypes,
currentSynthesizedMembers,
currentDeletedMembers);

Expand All @@ -204,13 +200,11 @@ private static EmitBaseline MapToCompilation(

// TODO: can we reuse some data from the previous matcher?
var matcherWithAllSynthesizedMembers = new CSharpSymbolMatcher(
anonymousTypeMap,
anonymousDelegates,
anonymousDelegatesWithIndexedNames,
sourceAssembly,
sourceContext,
compilation.SourceAssembly,
otherContext,
synthesizedTypes,
mappedSynthesizedMembers,
mappedDeletedMembers);

Expand Down
Loading

0 comments on commit 61f8408

Please sign in to comment.