File: Emit\PEModuleBuilder.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Collections.Concurrent
Imports System.Collections.Immutable
Imports System.Reflection.PortableExecutable
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.CodeGen
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Emit
 
    Partial Friend MustInherit Class PEModuleBuilder
        Inherits PEModuleBuilder(Of VisualBasicCompilation, SourceModuleSymbol, AssemblySymbol, TypeSymbol, NamedTypeSymbol, MethodSymbol, SyntaxNode, NoPia.EmbeddedTypesManager, ModuleCompilationState)
 
        ' Not many methods should end up here.
        Private ReadOnly _disableJITOptimization As ConcurrentDictionary(Of MethodSymbol, Boolean) = New ConcurrentDictionary(Of MethodSymbol, Boolean)(ReferenceEqualityComparer.Instance)
 
        ' Gives the name of this module (may not reflect the name of the underlying symbol).
        ' See Assembly.MetadataName.
        Private ReadOnly _metadataName As String
 
        Private _lazyExportedTypes As ImmutableArray(Of Cci.ExportedType)
        Private _lazyTranslatedImports As ImmutableArray(Of Cci.UsedNamespaceOrType)
        Private _lazyDefaultNamespace As String
 
        Friend Sub New(sourceModule As SourceModuleSymbol,
                       emitOptions As EmitOptions,
                       outputKind As OutputKind,
                       serializationProperties As Cci.ModulePropertiesForSerialization,
                       manifestResources As IEnumerable(Of ResourceDescription))
 
            MyBase.New(sourceModule.ContainingSourceAssembly.DeclaringCompilation,
                       sourceModule,
                       serializationProperties,
                       manifestResources,
                       outputKind,
                       emitOptions,
                       New ModuleCompilationState())
 
            Dim specifiedName = sourceModule.MetadataName
 
            _metadataName = If(specifiedName <> CodeAnalysis.Compilation.UnspecifiedModuleAssemblyName,
                                specifiedName,
                                If(emitOptions.OutputNameOverride, specifiedName))
 
            m_AssemblyOrModuleSymbolToModuleRefMap.Add(sourceModule, Me)
 
            If sourceModule.AnyReferencedAssembliesAreLinked Then
                _embeddedTypesManagerOpt = New NoPia.EmbeddedTypesManager(Me)
            End If
        End Sub
 
        ''' <summary>
        ''' True if conditional calls may be omitted when the required preprocessor symbols are not defined.
        ''' </summary>
        ''' <remarks>
        ''' Only false in debugger scenarios (where calls should never be omitted).
        ''' </remarks>
        Friend MustOverride ReadOnly Property AllowOmissionOfConditionalCalls As Boolean
 
        Public Overrides ReadOnly Property Name As String
            Get
                Return _metadataName
            End Get
        End Property
 
        Friend NotOverridable Overrides ReadOnly Property ModuleName As String
            Get
                Return _metadataName
            End Get
        End Property
 
        Friend NotOverridable Overrides ReadOnly Property CorLibrary As AssemblySymbol
            Get
                Return SourceModule.ContainingSourceAssembly.CorLibrary
            End Get
        End Property
 
        Public NotOverridable Overrides ReadOnly Property GenerateVisualBasicStylePdb As Boolean
            Get
                Return True
            End Get
        End Property
 
        Public Overrides ReadOnly Property LinkedAssembliesDebugInfo As IEnumerable(Of String)
            Get
                ' NOTE: Dev12 does not seem to emit anything but the name (i.e. no version, token, etc).
                ' See Builder::WriteNoPiaPdbList
                Return SourceModule.ReferencedAssemblySymbols.Where(Function(a) a.IsLinked).Select(Function(a) a.Name)
            End Get
        End Property
 
        Public NotOverridable Overrides Function GetImports() As ImmutableArray(Of Cci.UsedNamespaceOrType)
            ' Imports should have been translated in code gen phase.
            Debug.Assert(Not _lazyTranslatedImports.IsDefault)
            Return _lazyTranslatedImports
        End Function
 
        Public Sub TranslateImports(diagnostics As DiagnosticBag)
            If _lazyTranslatedImports.IsDefault Then
                ImmutableInterlocked.InterlockedInitialize(
                    _lazyTranslatedImports,
                    NamespaceScopeBuilder.BuildNamespaceScope(Me, SourceModule.XmlNamespaces, SourceModule.AliasImports, SourceModule.MemberImports, diagnostics))
            End If
        End Sub
 
        Public NotOverridable Overrides ReadOnly Property DefaultNamespace As String
            Get
                If _lazyDefaultNamespace IsNot Nothing Then
                    Return _lazyDefaultNamespace
                End If
 
                Dim rootNamespace = SourceModule.RootNamespace
                If rootNamespace.IsGlobalNamespace Then
                    Return String.Empty
                End If
 
                _lazyDefaultNamespace = rootNamespace.ToDisplayString(SymbolDisplayFormat.QualifiedNameOnlyFormat)
                Return _lazyDefaultNamespace
            End Get
        End Property
 
        Protected NotOverridable Overrides Iterator Function GetAssemblyReferencesFromAddedModules(diagnostics As DiagnosticBag) As IEnumerable(Of Cci.IAssemblyReference)
            Dim modules As ImmutableArray(Of ModuleSymbol) = SourceModule.ContainingAssembly.Modules
 
            For i As Integer = 1 To modules.Length - 1
                For Each aRef As AssemblySymbol In modules(i).GetReferencedAssemblySymbols()
                    Yield Translate(aRef, diagnostics)
                Next
            Next
        End Function
 
        Private Sub ValidateReferencedAssembly(assembly As AssemblySymbol, asmRef As AssemblyReference, diagnostics As DiagnosticBag)
            Dim asmIdentity As AssemblyIdentity = SourceModule.ContainingAssembly.Identity
            Dim refIdentity As AssemblyIdentity = asmRef.Identity
 
            If asmIdentity.IsStrongName AndAlso Not refIdentity.IsStrongName AndAlso
               asmRef.Identity.ContentType <> Reflection.AssemblyContentType.WindowsRuntime Then
                ' Dev12 reported error, we have changed it to a warning to allow referencing libraries
                ' built for platforms that don't support strong names.
                diagnostics.Add(ErrorFactory.ErrorInfo(ERRID.WRN_ReferencedAssemblyDoesNotHaveStrongName, assembly), NoLocation.Singleton)
            End If
 
            If OutputKind <> OutputKind.NetModule AndAlso
               Not String.IsNullOrEmpty(refIdentity.CultureName) AndAlso
               Not String.Equals(refIdentity.CultureName, asmIdentity.CultureName, StringComparison.OrdinalIgnoreCase) Then
                diagnostics.Add(ErrorFactory.ErrorInfo(ERRID.WRN_RefCultureMismatch, assembly, refIdentity.CultureName), NoLocation.Singleton)
            End If
 
            Dim refMachine = assembly.Machine
            ' If other assembly is agnostic, this is always safe
            ' Also, if no mscorlib was specified for back compat we add a reference to mscorlib
            ' that resolves to the current framework directory. If the compiler Is 64-bit
            ' this Is a 64-bit mscorlib, which will produce a warning if /platform:x86 Is
            ' specified.A reference to the default mscorlib should always succeed without
            ' warning so we ignore it here.
            If assembly IsNot assembly.CorLibrary AndAlso
               Not (refMachine = Machine.I386 AndAlso Not assembly.Bit32Required) Then
                Dim machine = SourceModule.Machine
 
                If Not (machine = Machine.I386 AndAlso Not SourceModule.Bit32Required) AndAlso
                    machine <> refMachine Then
                    ' Different machine types, and neither is agnostic
                    diagnostics.Add(ErrorFactory.ErrorInfo(ERRID.WRN_ConflictingMachineAssembly, assembly), NoLocation.Singleton)
                End If
            End If
 
            If _embeddedTypesManagerOpt IsNot Nothing AndAlso _embeddedTypesManagerOpt.IsFrozen Then
                _embeddedTypesManagerOpt.ReportIndirectReferencesToLinkedAssemblies(assembly, diagnostics)
            End If
        End Sub
 
        Friend NotOverridable Overrides Function SynthesizeAttribute(attributeConstructor As WellKnownMember) As Cci.ICustomAttribute
            Return Me.Compilation.TrySynthesizeAttribute(attributeConstructor)
        End Function
 
        Public NotOverridable Overrides Function GetSourceAssemblyAttributes(isRefAssembly As Boolean) As IEnumerable(Of Cci.ICustomAttribute)
            Return SourceModule.ContainingSourceAssembly.GetAssemblyCustomAttributesToEmit(Me,
                                                                                           isRefAssembly,
                                                                                           emittingAssemblyAttributesInNetModule:=OutputKind.IsNetModule())
        End Function
 
        Public NotOverridable Overrides Function GetSourceAssemblySecurityAttributes() As IEnumerable(Of Cci.SecurityAttribute)
            Return SourceModule.ContainingSourceAssembly.GetSecurityAttributes()
        End Function
 
        Public NotOverridable Overrides Function GetSourceModuleAttributes() As IEnumerable(Of Cci.ICustomAttribute)
            Return SourceModule.GetCustomAttributesToEmit(Me)
        End Function
 
        Public NotOverridable Overrides Function GetSymbolToLocationMap() As MultiDictionary(Of Cci.DebugSourceDocument, Cci.DefinitionWithLocation)
            Dim result As New MultiDictionary(Of Cci.DebugSourceDocument, Cci.DefinitionWithLocation)()
 
            Dim namespacesAndTypesToProcess As New Stack(Of NamespaceOrTypeSymbol)()
            namespacesAndTypesToProcess.Push(SourceModule.GlobalNamespace)
 
            Dim location As Location = Nothing
 
            While namespacesAndTypesToProcess.Count > 0
                Dim symbol As NamespaceOrTypeSymbol = namespacesAndTypesToProcess.Pop()
                Select Case symbol.Kind
 
                    Case SymbolKind.Namespace
                        location = GetSmallestSourceLocationOrNull(symbol)
 
                        ' filtering out synthesized symbols not having real source
                        ' locations such as anonymous types, my types, etc...
                        If location IsNot Nothing Then
                            For Each member In symbol.GetMembers()
                                Select Case member.Kind
                                    Case SymbolKind.Namespace, SymbolKind.NamedType
                                        namespacesAndTypesToProcess.Push(DirectCast(member, NamespaceOrTypeSymbol))
                                    Case Else
                                        Throw ExceptionUtilities.UnexpectedValue(member.Kind)
                                End Select
                            Next
                        End If
 
                    Case SymbolKind.NamedType
                        location = GetSmallestSourceLocationOrNull(symbol)
                        If location IsNot Nothing Then
                            ' add this named type location
                            AddSymbolLocation(result, location, DirectCast(symbol.GetCciAdapter(), Cci.IDefinition))
 
                            For Each member In symbol.GetMembers()
                                Select Case member.Kind
                                    Case SymbolKind.NamedType
                                        namespacesAndTypesToProcess.Push(DirectCast(member, NamespaceOrTypeSymbol))
 
                                    Case SymbolKind.Method
                                        Dim method = DirectCast(member, MethodSymbol)
                                        If method.IsDefaultValueTypeConstructor() OrElse
                                           method.IsPartialWithoutImplementation Then
                                            Exit Select
                                        End If
 
                                        AddSymbolLocation(result, member)
 
                                    Case SymbolKind.Property,
                                         SymbolKind.Field
                                        AddSymbolLocation(result, member)
 
                                    Case SymbolKind.Event
                                        AddSymbolLocation(result, member)
                                        Dim AssociatedField = (DirectCast(member, EventSymbol)).AssociatedField
 
                                        If AssociatedField IsNot Nothing Then
                                            ' event backing fields do not show up in GetMembers
                                            AddSymbolLocation(result, AssociatedField)
                                        End If
 
                                    Case Else
                                        Throw ExceptionUtilities.UnexpectedValue(member.Kind)
                                End Select
                            Next
                        End If
 
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(symbol.Kind)
                End Select
            End While
 
            Return result
        End Function
 
        Private Sub AddSymbolLocation(result As MultiDictionary(Of Cci.DebugSourceDocument, Cci.DefinitionWithLocation), symbol As Symbol)
            Dim location As Location = GetSmallestSourceLocationOrNull(symbol)
            If location IsNot Nothing Then
                AddSymbolLocation(result, location, DirectCast(symbol.GetCciAdapter(), Cci.IDefinition))
            End If
        End Sub
 
        Private Sub AddSymbolLocation(result As MultiDictionary(Of Cci.DebugSourceDocument, Cci.DefinitionWithLocation), location As Location, definition As Cci.IDefinition)
            Dim span As FileLinePositionSpan = location.GetLineSpan()
 
            Dim doc As Cci.DebugSourceDocument = DebugDocumentsBuilder.TryGetDebugDocument(span.Path, basePath:=location.SourceTree.FilePath)
            If (doc IsNot Nothing) Then
                result.Add(doc,
                       New Cci.DefinitionWithLocation(
                           definition,
                           span.StartLinePosition.Line,
                           span.StartLinePosition.Character,
                           span.EndLinePosition.Line,
                           span.EndLinePosition.Character))
            End If
        End Sub
 
        Private Function GetSmallestSourceLocationOrNull(symbol As Symbol) As Location
            Dim compilation As VisualBasicCompilation = symbol.DeclaringCompilation
            Debug.Assert(Me.Compilation Is compilation, "How did we get symbol from different compilation?")
 
            Dim result As Location = Nothing
 
            For Each loc In symbol.Locations
                If loc.IsInSource AndAlso (result Is Nothing OrElse compilation.CompareSourceLocations(result, loc) > 0) Then
                    result = loc
                End If
            Next
 
            Return result
        End Function
 
        ''' <summary>
        ''' Ignore accessibility when resolving well-known type
        ''' members, in particular for generic type arguments
        ''' (e.g.: binding to internal types in the EE).
        ''' </summary>
        Friend Overridable ReadOnly Property IgnoreAccessibility As Boolean
            Get
                Return False
            End Get
        End Property
 
        Friend Overridable Function TryCreateVariableSlotAllocator(method As MethodSymbol, topLevelMethod As MethodSymbol, diagnostics As DiagnosticBag) As VariableSlotAllocator
            Return Nothing
        End Function
 
        Friend Overridable Function GetMethodBodyInstrumentations(method As MethodSymbol) As MethodInstrumentation
            Return New MethodInstrumentation() With {.Kinds = EmitOptions.InstrumentationKinds}
        End Function
 
        Friend Overridable Function GetPreviousAnonymousTypes() As ImmutableArray(Of AnonymousTypeKey)
            Return ImmutableArray(Of AnonymousTypeKey).Empty
        End Function
 
        Friend Overridable Function GetNextAnonymousTypeIndex(fromDelegates As Boolean) As Integer
            Return 0
        End Function
 
        Friend Overridable Function TryGetAnonymousTypeName(template As AnonymousTypeManager.AnonymousTypeOrDelegateTemplateSymbol, <Out> ByRef name As String, <Out> ByRef index As Integer) As Boolean
            Debug.Assert(Compilation Is template.DeclaringCompilation)
            name = Nothing
            index = -1
            Return False
        End Function
 
        Public NotOverridable Overrides Function GetAnonymousTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition)
            If context.MetadataOnly Then
                Return SpecializedCollections.EmptyEnumerable(Of Cci.INamespaceTypeDefinition)
            End If
 
#If DEBUG Then
            Return SourceModule.ContainingSourceAssembly.DeclaringCompilation.AnonymousTypeManager.AllCreatedTemplates.Select(Function(t) t.GetCciAdapter())
#Else
            Return SourceModule.ContainingSourceAssembly.DeclaringCompilation.AnonymousTypeManager.AllCreatedTemplates
#End If
        End Function
 
        Public Overrides Iterator Function GetTopLevelSourceTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition)
            Dim embeddedSymbolManager As EmbeddedSymbolManager = SourceModule.ContainingSourceAssembly.DeclaringCompilation.EmbeddedSymbolManager
            Dim stack As New Stack(Of NamespaceOrTypeSymbol)()
 
            stack.Push(SourceModule.GlobalNamespace)
 
            Do
                Dim sym As NamespaceOrTypeSymbol = stack.Pop()
 
                If sym.Kind = SymbolKind.NamedType Then
                    Debug.Assert(sym Is sym.OriginalDefinition)
                    Debug.Assert(sym.ContainingType Is Nothing)
 
                    ' Skip unreferenced embedded types.
                    If Not sym.IsEmbedded OrElse embeddedSymbolManager.IsSymbolReferenced(sym) Then
                        Yield DirectCast(sym, NamedTypeSymbol).GetCciAdapter()
                    End If
                Else
                    Debug.Assert(sym.Kind = SymbolKind.Namespace)
                    Dim members As ImmutableArray(Of Symbol) = sym.GetMembers()
                    For i As Integer = members.Length - 1 To 0 Step -1
                        Dim namespaceOrType As NamespaceOrTypeSymbol = TryCast(members(i), NamespaceOrTypeSymbol)
                        If namespaceOrType IsNot Nothing Then
                            stack.Push(namespaceOrType)
                        End If
                    Next
                End If
            Loop While stack.Count > 0
        End Function
 
        Public NotOverridable Overrides Function GetExportedTypes(diagnostics As DiagnosticBag) As ImmutableArray(Of Cci.ExportedType)
            Debug.Assert(HaveDeterminedTopLevelTypes)
 
            If _lazyExportedTypes.IsDefault Then
                Dim initialized = ImmutableInterlocked.InterlockedInitialize(_lazyExportedTypes, CalculateExportedTypes())
 
                If initialized AndAlso _lazyExportedTypes.Length > 0 Then
                    ReportExportedTypeNameCollisions(_lazyExportedTypes, diagnostics)
                End If
            End If
 
            Return _lazyExportedTypes
        End Function
 
        ''' <summary>
        ''' Builds an array of public type symbols defined in netmodules included in the compilation
        ''' And type forwarders defined in this compilation Or any included netmodule (in this order).
        ''' </summary>
        Private Function CalculateExportedTypes() As ImmutableArray(Of Cci.ExportedType)
            Dim builder = ArrayBuilder(Of Cci.ExportedType).GetInstance()
            Dim sourceAssembly As SourceAssemblySymbol = SourceModule.ContainingSourceAssembly
 
            If Not OutputKind.IsNetModule() Then
                Dim modules = sourceAssembly.Modules
 
                For i As Integer = 1 To modules.Length - 1 'NOTE: skipping modules(0)
                    GetExportedTypes(modules(i).GlobalNamespace, -1, builder)
                Next
            End If
 
            Debug.Assert(OutputKind.IsNetModule() = sourceAssembly.DeclaringCompilation.Options.OutputKind.IsNetModule())
            GetForwardedTypes(sourceAssembly, builder)
            Return builder.ToImmutableAndFree()
        End Function
 
        ''' <summary>
        ''' Returns a set of top-level forwarded types
        ''' </summary>
        Friend Shared Function GetForwardedTypes(sourceAssembly As SourceAssemblySymbol, builderOpt As ArrayBuilder(Of Cci.ExportedType)) As HashSet(Of NamedTypeSymbol)
            Dim seenTopLevelForwardedTypes = New HashSet(Of NamedTypeSymbol)()
            GetForwardedTypes(seenTopLevelForwardedTypes, sourceAssembly.GetSourceDecodedWellKnownAttributeData(), builderOpt)
 
            If Not sourceAssembly.DeclaringCompilation.Options.OutputKind.IsNetModule() Then
                GetForwardedTypes(seenTopLevelForwardedTypes, sourceAssembly.GetNetModuleDecodedWellKnownAttributeData(), builderOpt)
            End If
 
            Return seenTopLevelForwardedTypes
        End Function
 
        Private Sub ReportExportedTypeNameCollisions(exportedTypes As ImmutableArray(Of Cci.ExportedType), diagnostics As DiagnosticBag)
            Dim sourceAssembly As SourceAssemblySymbol = SourceModule.ContainingSourceAssembly
            Dim exportedNamesMap = New Dictionary(Of String, NamedTypeSymbol)()
 
            For Each exportedType In _lazyExportedTypes
                Dim typeReference As Cci.ITypeReference = exportedType.Type
                Dim type = DirectCast(typeReference.GetInternalSymbol(), NamedTypeSymbol)
 
                Debug.Assert(type.IsDefinition)
 
                If type.ContainingType IsNot Nothing Then
                    Continue For
                End If
 
                ' exported types are not emitted in EnC deltas (hence generation 0):
                Dim fullEmittedName As String = MetadataHelpers.BuildQualifiedName(
                    DirectCast(typeReference, Cci.INamespaceTypeReference).NamespaceName,
                    Cci.MetadataWriter.GetMetadataName(DirectCast(typeReference, Cci.INamedTypeReference), generation:=0))
 
                ' First check against types declared in the primary module
                If ContainsTopLevelType(fullEmittedName) Then
                    If type.ContainingAssembly Is sourceAssembly Then
                        diagnostics.Add(ERRID.ERR_ExportedTypeConflictsWithDeclaration, NoLocation.Singleton, type, type.ContainingModule)
                    Else
                        diagnostics.Add(ERRID.ERR_ForwardedTypeConflictsWithDeclaration, NoLocation.Singleton, CustomSymbolDisplayFormatter.DefaultErrorFormat(type))
                    End If
 
                    Continue For
                End If
 
                Dim contender As NamedTypeSymbol = Nothing
 
                ' Now check against other exported types
                If exportedNamesMap.TryGetValue(fullEmittedName, contender) Then
 
                    If type.ContainingAssembly Is sourceAssembly Then
                        ' all exported types precede forwarded types, therefore contender cannot be a forwarded type.
                        Debug.Assert(contender.ContainingAssembly Is sourceAssembly)
 
                        diagnostics.Add(ERRID.ERR_ExportedTypesConflict, NoLocation.Singleton,
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(type),
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(type.ContainingModule),
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(contender),
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(contender.ContainingModule))
                    ElseIf contender.ContainingAssembly Is sourceAssembly Then
                        ' Forwarded type conflicts with exported type
                        diagnostics.Add(ERRID.ERR_ForwardedTypeConflictsWithExportedType, NoLocation.Singleton,
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(type),
                            type.ContainingAssembly,
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(contender),
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(contender.ContainingModule))
                    Else
                        ' Forwarded type conflicts with another forwarded type
                        diagnostics.Add(ERRID.ERR_ForwardedTypesConflict, NoLocation.Singleton,
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(type),
                            type.ContainingAssembly,
                            CustomSymbolDisplayFormatter.DefaultErrorFormat(contender),
                            contender.ContainingAssembly)
                    End If
 
                    Continue For
                End If
 
                exportedNamesMap.Add(fullEmittedName, type)
            Next
        End Sub
 
        Private Overloads Sub GetExportedTypes(symbol As NamespaceOrTypeSymbol, parentIndex As Integer, builder As ArrayBuilder(Of Cci.ExportedType))
            Dim index As Integer
 
            If symbol.Kind = SymbolKind.NamedType Then
                If symbol.DeclaredAccessibility <> Accessibility.Public Then
                    Return
                End If
 
                Debug.Assert(symbol.IsDefinition)
                index = builder.Count
                builder.Add(New Cci.ExportedType(DirectCast(symbol, NamedTypeSymbol).GetCciAdapter(), parentIndex, isForwarder:=False))
            Else
                index = -1
            End If
 
            For Each member In symbol.GetMembers()
                Dim namespaceOrType = TryCast(member, NamespaceOrTypeSymbol)
 
                If namespaceOrType IsNot Nothing Then
                    GetExportedTypes(namespaceOrType, index, builder)
                End If
            Next
        End Sub
 
        Private Shared Sub GetForwardedTypes(
            seenTopLevelTypes As HashSet(Of NamedTypeSymbol),
            wellKnownAttributeData As CommonAssemblyWellKnownAttributeData(Of NamedTypeSymbol),
            builderOpt As ArrayBuilder(Of Cci.ExportedType))
 
            If wellKnownAttributeData?.ForwardedTypes?.Count > 0 Then
                ' (type, index of the parent exported type in builder, or -1 if the type is a top-level type)
                Dim stack = ArrayBuilder(Of (type As NamedTypeSymbol, parentIndex As Integer)).GetInstance()
 
                ' Hashset enumeration is not guaranteed to be deterministic. Emitting in the order of fully qualified names.
                Dim orderedForwardedTypes As IEnumerable(Of NamedTypeSymbol) = wellKnownAttributeData.ForwardedTypes
 
                If builderOpt IsNot Nothing Then
                    orderedForwardedTypes = orderedForwardedTypes.OrderBy(Function(t) t.OriginalDefinition.ToDisplayString(SymbolDisplayFormat.QualifiedNameArityFormat))
                End If
 
                For Each forwardedType As NamedTypeSymbol In orderedForwardedTypes
                    Dim originalDefinition As NamedTypeSymbol = forwardedType.OriginalDefinition
                    Debug.Assert(originalDefinition.ContainingType Is Nothing, "How did a nested type get forwarded?")
 
                    ' De-dup the original definitions before emitting.
                    If Not seenTopLevelTypes.Add(originalDefinition) Then
                        Continue For
                    End If
 
                    If builderOpt IsNot Nothing Then
                        ' Return all nested types.
                        ' Note the order: depth first, children in reverse order (to match dev10, not a requirement).
                        Debug.Assert(stack.Count = 0)
                        stack.Push((originalDefinition, -1))
 
                        While stack.Count > 0
                            Dim entry = stack.Pop()
 
                            ' In general, we don't want private types to appear in the ExportedTypes table.
                            If entry.type.DeclaredAccessibility = Accessibility.Private Then
                                ' NOTE: this will also exclude nested types of curr.
                                Continue While
                            End If
 
                            ' NOTE: not bothering to put nested types in seenTypes - the top-level type is adequate protection.
                            Dim index = builderOpt.Count
                            builderOpt.Add(New Cci.ExportedType(entry.type.GetCciAdapter(), entry.parentIndex, isForwarder:=True))
 
                            ' Iterate backwards so they get popped in forward order.
                            Dim nested As ImmutableArray(Of NamedTypeSymbol) = entry.type.GetTypeMembers() ' Ordered.
                            For i As Integer = nested.Length - 1 To 0 Step -1
                                stack.Push((nested(i), index))
                            Next
                        End While
                    End If
                Next
 
                stack.Free()
            End If
        End Sub
 
        Friend Iterator Function GetReferencedAssembliesUsedSoFar() As IEnumerable(Of AssemblySymbol)
            For Each assembly In SourceModule.GetReferencedAssemblySymbols()
                If Not assembly.IsLinked AndAlso
                    Not assembly.IsMissing AndAlso
                    m_AssemblyOrModuleSymbolToModuleRefMap.ContainsKey(assembly) Then
                    Yield assembly
                End If
            Next
        End Function
 
        Friend NotOverridable Overrides Function GetSpecialType(specialType As SpecialType, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As Cci.INamedTypeReference
            Return Translate(GetUntranslatedSpecialType(specialType, syntaxNodeOpt, diagnostics),
                             needDeclaration:=True,
                             syntaxNodeOpt:=syntaxNodeOpt,
                             diagnostics:=diagnostics)
        End Function
 
        Private Function GetUntranslatedSpecialType(specialType As SpecialType, syntaxNodeOpt As SyntaxNode, diagnostics As DiagnosticBag) As NamedTypeSymbol
            Dim typeSymbol = SourceModule.ContainingAssembly.GetSpecialType(specialType)
 
            Dim info = Binder.GetUseSiteInfoForSpecialType(typeSymbol)
            If info.DiagnosticInfo IsNot Nothing Then
                Binder.ReportDiagnostic(diagnostics, If(syntaxNodeOpt IsNot Nothing, syntaxNodeOpt.GetLocation(), NoLocation.Singleton), info.DiagnosticInfo)
            End If
 
            Return typeSymbol
        End Function
 
        Public NotOverridable Overrides Function GetInitArrayHelper() As Cci.IMethodReference
            Return DirectCast(Compilation.GetWellKnownTypeMember(WellKnownMember.System_Runtime_CompilerServices_RuntimeHelpers__InitializeArrayArrayRuntimeFieldHandle), MethodSymbol)?.GetCciAdapter()
        End Function
 
        Public NotOverridable Overrides Function IsPlatformType(typeRef As Cci.ITypeReference, platformType As Cci.PlatformType) As Boolean
            Dim namedType = TryCast(typeRef.GetInternalSymbol(), NamedTypeSymbol)
 
            If namedType IsNot Nothing Then
                If platformType = Cci.PlatformType.SystemType Then
                    Return namedType Is Compilation.GetWellKnownType(WellKnownType.System_Type)
                End If
 
                Return namedType.SpecialType = CType(platformType, SpecialType)
            End If
 
            Return False
        End Function
 
        Protected NotOverridable Overrides Function GetCorLibraryReferenceToEmit(context As EmitContext) As Cci.IAssemblyReference
            Dim corLib = CorLibrary
 
            If Not corLib.IsMissing AndAlso
                Not corLib.IsLinked AndAlso
                corLib IsNot SourceModule.ContainingAssembly Then
                Return Translate(corLib, context.Diagnostics)
            End If
 
            Return Nothing
        End Function
 
        Friend NotOverridable Overrides Function GetSynthesizedNestedTypes(container As NamedTypeSymbol) As IEnumerable(Of Cci.INestedTypeDefinition)
            Return container.GetSynthesizedNestedTypes()
        End Function
 
        Public Overrides Iterator Function GetTypeToDebugDocumentMap(context As EmitContext) As IEnumerable(Of (Cci.ITypeDefinition, ImmutableArray(Of Cci.DebugSourceDocument)))
            Dim typesToProcess = ArrayBuilder(Of Cci.ITypeDefinition).GetInstance()
            Dim debugDocuments = ArrayBuilder(Of Cci.DebugSourceDocument).GetInstance()
            Dim methodDocumentList = PooledHashSet(Of Cci.DebugSourceDocument).GetInstance()
 
            Dim namespacesAndTopLevelTypesToProcess = ArrayBuilder(Of NamespaceOrTypeSymbol).GetInstance()
            namespacesAndTopLevelTypesToProcess.Push(SourceModule.GlobalNamespace)
 
            While namespacesAndTopLevelTypesToProcess.Count > 0
                Dim symbol = namespacesAndTopLevelTypesToProcess.Pop()
 
                If symbol.Locations.Length = 0 Then
                    Continue While
                End If
 
                Select Case symbol.Kind
                    Case SymbolKind.Namespace
                        Dim location = GetSmallestSourceLocationOrNull(symbol)
 
                        ' filtering out synthesized symbols not having real source
                        ' locations such as anonymous types, my types, etc...
                        If location IsNot Nothing Then
                            For Each member In symbol.GetMembers()
                                Select Case member.Kind
                                    Case SymbolKind.Namespace, SymbolKind.NamedType
                                        namespacesAndTopLevelTypesToProcess.Push(DirectCast(member, NamespaceOrTypeSymbol))
                                    Case Else
                                        Throw ExceptionUtilities.UnexpectedValue(member.Kind)
                                End Select
                            Next
                        End If
 
                    Case SymbolKind.NamedType
                        ' We only process top level types in this method, and only return documents for types if there are no
                        ' methods that would refer to the same document, either in the type or in any nested type.
                        Debug.Assert(debugDocuments.Count = 0)
                        Debug.Assert(methodDocumentList.Count = 0)
                        Debug.Assert(typesToProcess.Count = 0)
 
                        Dim typeDefinition = DirectCast(symbol.GetCciAdapter(), Cci.ITypeDefinition)
                        typesToProcess.Push(typeDefinition)
                        GetDocumentsForMethodsAndNestedTypes(methodDocumentList, typesToProcess, context)
 
                        For Each loc In symbol.Locations
                            If Not loc.IsInSource Then
                                Continue For
                            End If
 
                            Dim span = loc.GetLineSpan()
                            Dim debugDocument = DebugDocumentsBuilder.TryGetDebugDocument(span.Path, basePath:=Nothing)
 
                            If debugDocument IsNot Nothing AndAlso Not methodDocumentList.Contains(debugDocument) Then
                                debugDocuments.Add(debugDocument)
                            End If
                        Next
 
                        If debugDocuments.Count > 0 Then
                            Yield (typeDefinition, debugDocuments.ToImmutable())
                        End If
                        debugDocuments.Clear()
                        methodDocumentList.Clear()
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(symbol.Kind)
                End Select
            End While
 
            namespacesAndTopLevelTypesToProcess.Free()
            debugDocuments.Free()
            methodDocumentList.Free()
            typesToProcess.Free()
        End Function
 
        Private Shared Sub GetDocumentsForMethodsAndNestedTypes(documentList As PooledHashSet(Of Cci.DebugSourceDocument), typesToProcess As ArrayBuilder(Of Cci.ITypeDefinition), context As EmitContext)
 
            ' Temporarily disable assert to unblock getting net8.0 teststing re-nabled on Unix. Will 
            ' remove this shortly.
            ' https://github.com/dotnet/roslyn/issues/71571
            ' Debug.Assert(Not context.MetadataOnly)
 
            While typesToProcess.Count > 0
                Dim definition = typesToProcess.Pop()
 
                Dim typeMethods = definition.GetMethods(context)
                For Each method In typeMethods
                    Dim body = method.GetBody(context)
                    If body Is Nothing Then
                        Continue For
                    End If
 
                    For Each point In body.SequencePoints
                        documentList.Add(point.Document)
                    Next
                Next
 
                Dim nestedTypes = definition.GetNestedTypes(context)
                For Each nestedTypeDefinition In nestedTypes
                    typesToProcess.Push(nestedTypeDefinition)
                Next
            End While
        End Sub
 
        Public Sub SetDisableJITOptimization(methodSymbol As MethodSymbol)
            Debug.Assert(methodSymbol.ContainingModule Is Me.SourceModule AndAlso methodSymbol Is methodSymbol.OriginalDefinition)
 
            _disableJITOptimization.TryAdd(methodSymbol, True)
        End Sub
 
        Public Function JITOptimizationIsDisabled(methodSymbol As MethodSymbol) As Boolean
            Debug.Assert(methodSymbol Is methodSymbol.OriginalDefinition)
            Return _disableJITOptimization.ContainsKey(methodSymbol)
        End Function
 
        Protected NotOverridable Overrides Function CreatePrivateImplementationDetailsStaticConstructor(syntaxOpt As SyntaxNode, diagnostics As DiagnosticBag) As Cci.IMethodDefinition
            Return New SynthesizedPrivateImplementationDetailsSharedConstructor(SourceModule, GetPrivateImplClass(syntaxOpt, diagnostics), GetUntranslatedSpecialType(SpecialType.System_Void, syntaxOpt, diagnostics)).GetCciAdapter()
        End Function
 
        Public Overrides Function GetAdditionalTopLevelTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition)
#If DEBUG Then
            Return GetAdditionalTopLevelTypes().Select(Function(t) t.GetCciAdapter())
#Else
            Return GetAdditionalTopLevelTypes()
#End If
        End Function
 
        Public Overrides Function GetEmbeddedTypeDefinitions(context As EmitContext) As IEnumerable(Of Cci.INamespaceTypeDefinition)
#If DEBUG Then
            Return GetEmbeddedTypes(context.Diagnostics).Select(Function(t) t.GetCciAdapter())
#Else
            Return GetEmbeddedTypes(context.Diagnostics)
#End If
        End Function
    End Class
End Namespace