public PEDeltaAssemblyBuilder( SourceAssemblySymbol sourceAssembly, EmitOptions emitOptions, OutputKind outputKind, Cci.ModulePropertiesForSerialization serializationProperties, IEnumerable <ResourceDescription> manifestResources, EmitBaseline previousGeneration, IEnumerable <SemanticEdit> edits, Func <ISymbol, bool> isAddedSymbol) : base(sourceAssembly, emitOptions, outputKind, serializationProperties, manifestResources, additionalTypes: ImmutableArray <NamedTypeSymbol> .Empty) { var initialBaseline = previousGeneration.InitialBaseline; var context = new EmitContext(this, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); // Hydrate symbols from initial metadata. Once we do so it is important to reuse these symbols across all generations, // in order for the symbol matcher to be able to use reference equality once it maps symbols to initial metadata. var metadataSymbols = GetOrCreateMetadataSymbols(initialBaseline, sourceAssembly.DeclaringCompilation); var metadataDecoder = (MetadataDecoder)metadataSymbols.MetadataDecoder; var metadataAssembly = (PEAssemblySymbol)metadataDecoder.ModuleSymbol.ContainingAssembly; var matchToMetadata = new CSharpSymbolMatcher(metadataSymbols.AnonymousTypes, sourceAssembly, context, metadataAssembly); CSharpSymbolMatcher matchToPrevious = null; if (previousGeneration.Ordinal > 0) { var previousAssembly = ((CSharpCompilation)previousGeneration.Compilation).SourceAssembly; var previousContext = new EmitContext((PEModuleBuilder)previousGeneration.PEModuleBuilder, null, new DiagnosticBag(), metadataOnly: false, includePrivateMembers: true); matchToPrevious = new CSharpSymbolMatcher( previousGeneration.AnonymousTypeMap, sourceAssembly: sourceAssembly, sourceContext: context, otherAssembly: previousAssembly, otherContext: previousContext, otherSynthesizedMembersOpt: previousGeneration.SynthesizedMembers); } _previousDefinitions = new CSharpDefinitionMap(previousGeneration.OriginalMetadata.Module, edits, metadataDecoder, matchToMetadata, matchToPrevious); _previousGeneration = previousGeneration; _changes = new SymbolChanges(_previousDefinitions, edits, isAddedSymbol); // Workaround for https://github.com/dotnet/roslyn/issues/3192. // When compiling state machine we stash types of awaiters and state-machine hoisted variables, // so that next generation can look variables up and reuse their slots if possible. // // When we are about to allocate a slot for a lifted variable while compiling the next generation // we map its type to the previous generation and then check the slot types that we stashed earlier. // If the variable type matches we reuse it. In order to compare the previous variable type with the current one // both need to be completely lowered (translated). Standard translation only goes one level deep. // Generic arguments are not translated until they are needed by metadata writer. // // In order to get the fully lowered form we run the type symbols of stashed variables through a deep translator // that translates the symbol recursively. _deepTranslator = new CSharpSymbolMatcher.DeepTranslator(sourceAssembly.GetSpecialType(SpecialType.System_Object)); }
/// <summary> /// Return a version of the baseline with all definitions mapped to this compilation. /// Definitions from the initial generation, from metadata, are not mapped since /// the initial generation is always included as metadata. That is, the symbols from /// types, methods, ... in the TypesAdded, MethodsAdded, ... collections are replaced /// by the corresponding symbols from the current compilation. /// </summary> private static EmitBaseline MapToCompilation( CSharpCompilation compilation, PEDeltaAssemblyBuilder moduleBeingBuilt) { var previousGeneration = moduleBeingBuilt.PreviousGeneration; Debug.Assert(previousGeneration.Compilation != compilation); if (previousGeneration.Ordinal == 0) { // Initial generation, nothing to map. (Since the initial generation // is always loaded from metadata in the context of the current // compilation, there's no separate mapping step.) return(previousGeneration); } var currentSynthesizedMembers = moduleBeingBuilt.GetSynthesizedMembers(); // Mapping from previous compilation to the current. var anonymousTypeMap = moduleBeingBuilt.GetAnonymousTypeMap(); 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, sourceAssembly, sourceContext, compilation.SourceAssembly, otherContext, currentSynthesizedMembers); var mappedSynthesizedMembers = matcher.MapSynthesizedMembers(previousGeneration.SynthesizedMembers, currentSynthesizedMembers); // TODO: can we reuse some data from the previous matcher? var matcherWithAllSynthesizedMembers = new CSharpSymbolMatcher( anonymousTypeMap, sourceAssembly, sourceContext, compilation.SourceAssembly, otherContext, mappedSynthesizedMembers); return(matcherWithAllSynthesizedMembers.MapBaselineToCompilation( previousGeneration, compilation, moduleBeingBuilt, mappedSynthesizedMembers)); }