File: Symbols\Metadata\PE\PENamedTypeSymbol.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.Immutable
Imports System.Globalization
Imports System.Reflection.Metadata
Imports System.Reflection.Metadata.Ecma335
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports FieldAttributes = System.Reflection.FieldAttributes
Imports TypeAttributes = System.Reflection.TypeAttributes
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
 
    ''' <summary>
    ''' The class to represent all types imported from a PE/module.
    ''' </summary>
    ''' <remarks></remarks>
    Friend Class PENamedTypeSymbol
        Inherits InstanceTypeSymbol
 
        Private Shared ReadOnly s_emptyNestedTypes As Dictionary(Of String, ImmutableArray(Of PENamedTypeSymbol)) =
            New Dictionary(Of String, ImmutableArray(Of PENamedTypeSymbol))(IdentifierComparison.Comparer)
 
        Private ReadOnly _container As NamespaceOrTypeSymbol
 
#Region "Metadata"
        Private ReadOnly _handle As TypeDefinitionHandle
        Private ReadOnly _genericParameterHandles As GenericParameterHandleCollection
        Private ReadOnly _name As String
        Private ReadOnly _flags As TypeAttributes
        Private ReadOnly _arity As UShort
        Private ReadOnly _mangleName As Boolean ' CONSIDER: combine with flags
#End Region
 
        ''' <summary>
        ''' A map of types immediately contained within this type 
        ''' grouped by their name (case-insensitively).
        ''' </summary>
        Private _lazyNestedTypes As Dictionary(Of String, ImmutableArray(Of PENamedTypeSymbol))
 
        ''' <summary>
        ''' A set of all the names of the members in this type.
        ''' </summary>
        Private _lazyMemberNames As ICollection(Of String)
 
        ''' <summary>
        ''' A map of members immediately contained within this type 
        ''' grouped by their name (case-insensitively).
        ''' </summary>
        ''' <remarks></remarks>
        Private _lazyMembers As Dictionary(Of String, ImmutableArray(Of Symbol))
 
        Private _lazyTypeParameters As ImmutableArray(Of TypeParameterSymbol)
 
        Private _lazyEnumUnderlyingType As NamedTypeSymbol
 
        Private _lazyCustomAttributes As ImmutableArray(Of VisualBasicAttributeData)
        Private _lazyConditionalAttributeSymbols As ImmutableArray(Of String)
        Private _lazyAttributeUsageInfo As AttributeUsageInfo = AttributeUsageInfo.Null
 
        Private _lazyCoClassType As TypeSymbol = ErrorTypeSymbol.UnknownResultType
 
        ''' <summary>
        ''' Lazily initialized by TypeKind property.
        ''' Using Integer type to make sure read/write operations are atomic.
        ''' </summary>
        ''' <remarks></remarks>
        Private _lazyTypeKind As Integer
 
        Private _lazyDocComment As Tuple(Of CultureInfo, String)
 
        Private _lazyDefaultPropertyName As String
 
        Private _lazyCachedUseSiteInfo As CachedUseSiteInfo(Of AssemblySymbol) = CachedUseSiteInfo(Of AssemblySymbol).Uninitialized ' Indicates unknown state. 
 
        Private _lazyMightContainExtensionMethods As Byte = ThreeState.Unknown
 
        Private _lazyHasCodeAnalysisEmbeddedAttribute As Integer = ThreeState.Unknown
 
        Private _lazyHasVisualBasicEmbeddedAttribute As Integer = ThreeState.Unknown
 
        Private _lazyObsoleteAttributeData As ObsoleteAttributeData = ObsoleteAttributeData.Uninitialized
 
        Private _lazyIsExtensibleInterface As ThreeState = ThreeState.Unknown
 
        Friend Sub New(
            moduleSymbol As PEModuleSymbol,
            containingNamespace As PENamespaceSymbol,
            handle As TypeDefinitionHandle
        )
            Me.New(moduleSymbol, containingNamespace, 0, handle)
        End Sub
 
        Friend Sub New(
            moduleSymbol As PEModuleSymbol,
            containingType As PENamedTypeSymbol,
            handle As TypeDefinitionHandle
        )
            Me.New(moduleSymbol, containingType, CUShort(containingType.MetadataArity), handle)
        End Sub
 
        Private Sub New(
            moduleSymbol As PEModuleSymbol,
            container As NamespaceOrTypeSymbol,
            containerMetadataArity As UShort,
            handle As TypeDefinitionHandle
        )
            Debug.Assert(Not handle.IsNil)
            Debug.Assert(container IsNot Nothing)
 
            _handle = handle
            _container = container
 
            Dim makeBad As Boolean = False
 
            Dim name As String
 
            Try
                name = moduleSymbol.Module.GetTypeDefNameOrThrow(handle)
            Catch mrEx As BadImageFormatException
                name = String.Empty
                makeBad = True
            End Try
 
            Try
                _flags = moduleSymbol.Module.GetTypeDefFlagsOrThrow(handle)
            Catch mrEx As BadImageFormatException
                makeBad = True
            End Try
 
            Dim metadataArity As Integer
 
            Try
                _genericParameterHandles = moduleSymbol.Module.GetTypeDefGenericParamsOrThrow(handle)
                metadataArity = _genericParameterHandles.Count
            Catch mrEx As BadImageFormatException
                _genericParameterHandles = Nothing
                metadataArity = 0
                makeBad = True
            End Try
 
            ' Figure out arity from the language point of view
            If metadataArity > containerMetadataArity Then
                _arity = CType(metadataArity - containerMetadataArity, UShort)
            End If
 
            If _arity = 0 Then
                _lazyTypeParameters = ImmutableArray(Of TypeParameterSymbol).Empty
                _name = name
                _mangleName = False
            Else
                ' Unmangle name for a generic type.
                _name = MetadataHelpers.UnmangleMetadataNameForArity(name, _arity)
                _mangleName = (_name IsNot name)
            End If
 
            If makeBad OrElse metadataArity < containerMetadataArity Then
                _lazyCachedUseSiteInfo.Initialize(If(DeriveCompilerFeatureRequiredDiagnostic(), ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me)))
            End If
 
            Debug.Assert(Not _mangleName OrElse _name.Length < name.Length)
        End Sub
 
        Friend ReadOnly Property ContainingPEModule As PEModuleSymbol
            Get
                Dim s As Symbol = _container
 
                While s.Kind <> SymbolKind.Namespace
                    s = s.ContainingSymbol
                End While
 
                Return DirectCast(s, PENamespaceSymbol).ContainingPEModule
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingModule As ModuleSymbol
            Get
                Return ContainingPEModule
            End Get
        End Property
 
        Public Overrides ReadOnly Property Arity As Integer
            Get
                Return _arity
            End Get
        End Property
 
        Friend Overrides ReadOnly Property MangleName As Boolean
            Get
                Return _mangleName
            End Get
        End Property
 
        Friend Overrides ReadOnly Property Layout As TypeLayout
            Get
                Return Me.ContainingPEModule.Module.GetTypeLayout(_handle)
            End Get
        End Property
 
        Friend Overrides ReadOnly Property MarshallingCharSet As CharSet
            Get
                Dim result As CharSet = _flags.ToCharSet()
                If result = 0 Then
                    Return CharSet.Ansi
                End If
 
                Return result
            End Get
        End Property
 
        Public Overrides ReadOnly Property IsSerializable As Boolean
            Get
#Disable Warning SYSLIB0050 ' 'TypeAttributes.Serializable' is obsolete
                Return (_flags And TypeAttributes.Serializable) <> 0
#Enable Warning SYSLIB0050
            End Get
        End Property
 
        Friend Overrides ReadOnly Property HasSpecialName As Boolean
            Get
                Return (_flags And TypeAttributes.SpecialName) <> 0
            End Get
        End Property
 
        Friend ReadOnly Property MetadataArity As Integer
            Get
                Return _genericParameterHandles.Count
            End Get
        End Property
 
        Friend ReadOnly Property Handle As TypeDefinitionHandle
            Get
                Return _handle
            End Get
        End Property
 
        Public Overrides ReadOnly Property MetadataToken As Integer
            Get
                Return MetadataTokens.GetToken(_handle)
            End Get
        End Property
 
        Friend Overrides Function GetInterfacesToEmit() As IEnumerable(Of NamedTypeSymbol)
            Return InterfacesNoUseSiteDiagnostics
        End Function
 
        Friend Overrides Function MakeDeclaredBase(basesBeingResolved As BasesBeingResolved, diagnostics As BindingDiagnosticBag) As NamedTypeSymbol
            If (Me._flags And TypeAttributes.Interface) = 0 Then
                Dim moduleSymbol As PEModuleSymbol = Me.ContainingPEModule
 
                Try
                    Dim token As EntityHandle = moduleSymbol.Module.GetBaseTypeOfTypeOrThrow(Me._handle)
                    If Not token.IsNil Then
                        Dim decodedType = New MetadataDecoder(moduleSymbol, Me).GetTypeOfToken(token)
                        Return DirectCast(TupleTypeDecoder.DecodeTupleTypesIfApplicable(decodedType, _handle, moduleSymbol), NamedTypeSymbol)
 
                    End If
                Catch mrEx As BadImageFormatException
                    Return New UnsupportedMetadataTypeSymbol(mrEx)
                End Try
            End If
            Return Nothing
        End Function
 
        Friend Overrides Function MakeDeclaredInterfaces(basesBeingResolved As BasesBeingResolved, diagnostics As BindingDiagnosticBag) As ImmutableArray(Of NamedTypeSymbol)
            Try
                Dim moduleSymbol As PEModuleSymbol = Me.ContainingPEModule
                Dim interfaceImpls = moduleSymbol.Module.GetInterfaceImplementationsOrThrow(Me._handle)
 
                If interfaceImpls.Count = 0 Then
                    Return ImmutableArray(Of NamedTypeSymbol).Empty
                End If
 
                Dim symbols As NamedTypeSymbol() = New NamedTypeSymbol(interfaceImpls.Count - 1) {}
                Dim tokenDecoder As New MetadataDecoder(moduleSymbol, Me)
                Dim i = 0
                For Each interfaceImpl In interfaceImpls
                    Dim interfaceHandle As EntityHandle = moduleSymbol.Module.MetadataReader.GetInterfaceImplementation(interfaceImpl).Interface
                    Dim typeSymbol As TypeSymbol = tokenDecoder.GetTypeOfToken(interfaceHandle)
 
                    typeSymbol = DirectCast(TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeSymbol, interfaceImpl, moduleSymbol), NamedTypeSymbol)
 
                    'TODO: how to pass reason to unsupported
                    Dim namedTypeSymbol As NamedTypeSymbol = TryCast(typeSymbol, NamedTypeSymbol)
                    symbols(i) = If(namedTypeSymbol IsNot Nothing, namedTypeSymbol, New UnsupportedMetadataTypeSymbol()) ' "interface tmpList contains a bad type"
                    i = i + 1
                Next
 
                Return symbols.AsImmutableOrNull
 
            Catch mrEx As BadImageFormatException
                Return ImmutableArray.Create(Of NamedTypeSymbol)(New UnsupportedMetadataTypeSymbol(mrEx))
            End Try
        End Function
 
        Private Shared Function CyclicInheritanceError(diag As DiagnosticInfo) As ErrorTypeSymbol
            Return New ExtendedErrorTypeSymbol(diag, True)
        End Function
 
        Friend Overrides Function MakeAcyclicBaseType(diagnostics As BindingDiagnosticBag) As NamedTypeSymbol
            Dim diag = BaseTypeAnalysis.GetDependencyDiagnosticsForImportedClass(Me)
            If diag IsNot Nothing Then
                Return CyclicInheritanceError(diag)
            End If
 
            Return GetDeclaredBase(Nothing)
        End Function
 
        Friend Overrides Function MakeAcyclicInterfaces(diagnostics As BindingDiagnosticBag) As ImmutableArray(Of NamedTypeSymbol)
            Dim declaredInterfaces As ImmutableArray(Of NamedTypeSymbol) = GetDeclaredInterfacesNoUseSiteDiagnostics(Nothing)
            If (Not Me.IsInterface) Then
                ' only interfaces needs to check for inheritance cycles via interfaces.
                Return declaredInterfaces
            End If
 
            Return (From t In declaredInterfaces
                    Let diag = BaseTypeAnalysis.GetDependencyDiagnosticsForImportedBaseInterface(Me, t)
                    Select If(diag Is Nothing, t, CyclicInheritanceError(diag))).AsImmutable
 
        End Function
 
        Public Overrides ReadOnly Property ContainingSymbol As Symbol
            Get
                Return _container
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingType As NamedTypeSymbol
            Get
                Return TryCast(_container, NamedTypeSymbol)
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaredAccessibility As Accessibility
            Get
                Dim access As Accessibility = Accessibility.Private
 
                Select Case _flags And TypeAttributes.VisibilityMask
                    Case TypeAttributes.NestedAssembly
                        access = Accessibility.Friend
 
                    Case TypeAttributes.NestedFamORAssem
                        access = Accessibility.ProtectedOrFriend
 
                    Case TypeAttributes.NestedFamANDAssem
                        access = Accessibility.ProtectedAndFriend
 
                    Case TypeAttributes.NestedPrivate
                        access = Accessibility.Private
 
                    Case TypeAttributes.Public,
                         TypeAttributes.NestedPublic
                        access = Accessibility.Public
 
                    Case TypeAttributes.NestedFamily
                        access = Accessibility.Protected
 
                    Case TypeAttributes.NotPublic
                        access = Accessibility.Friend
 
                    Case Else
                        Debug.Assert(False, "Unexpected!!!")
                End Select
 
                Return access
            End Get
        End Property
 
        Public Overrides ReadOnly Property EnumUnderlyingType As NamedTypeSymbol
            Get
                If _lazyEnumUnderlyingType Is Nothing AndAlso TypeKind = TypeKind.Enum Then
                    ' From §8.5.2
                    ' An enum is considerably more restricted than a true type, as
                    ' follows:
                    ' • It shall have exactly one instance field, and the type of that field defines the underlying type of
                    ' the enumeration.
                    ' • It shall not have any static fields unless they are literal. (see §8.6.1.2)
 
                    ' The underlying type shall be a built-in integer type. Enums shall derive from System.Enum, hence they are
                    ' value types. Like all value types, they shall be sealed (see §8.9.9).
 
                    Dim underlyingType As NamedTypeSymbol = Nothing
                    For Each member In GetMembers()
                        If (Not member.IsShared AndAlso member.Kind = SymbolKind.Field) Then
                            Dim type = DirectCast(member, FieldSymbol).Type
 
                            If (type.SpecialType.IsClrInteger()) Then
                                If (underlyingType Is Nothing) Then
                                    underlyingType = DirectCast(type, NamedTypeSymbol)
                                Else
                                    underlyingType = New UnsupportedMetadataTypeSymbol()
                                    Exit For
                                End If
                            End If
                        End If
                    Next
 
                    Interlocked.CompareExchange(_lazyEnumUnderlyingType,
                        If(underlyingType, New UnsupportedMetadataTypeSymbol()),
                        Nothing)
                End If
 
                Return _lazyEnumUnderlyingType
            End Get
        End Property
 
        Public Overloads Overrides Function GetAttributes() As ImmutableArray(Of VisualBasicAttributeData)
            If _lazyCustomAttributes.IsDefault Then
                If (_lazyTypeKind = TypeKind.Unknown AndAlso
                    ((_flags And TypeAttributes.Interface) <> 0 OrElse Me.Arity <> 0 OrElse Me.ContainingType IsNot Nothing)) OrElse
                   Me.TypeKind <> TypeKind.Module Then
                    ContainingPEModule.LoadCustomAttributes(_handle, _lazyCustomAttributes)
                Else
                    Dim stdModuleAttribute As CustomAttributeHandle
                    Dim attributes = ContainingPEModule.GetCustomAttributesForToken(
                        _handle,
                        stdModuleAttribute,
                        filterOut1:=AttributeDescription.StandardModuleAttribute)
 
                    Debug.Assert(Not stdModuleAttribute.IsNil)
                    ImmutableInterlocked.InterlockedInitialize(_lazyCustomAttributes, attributes)
                End If
            End If
 
            Return _lazyCustomAttributes
        End Function
 
        Friend Overrides Iterator Function GetCustomAttributesToEmit(moduleBuilder As PEModuleBuilder) As IEnumerable(Of VisualBasicAttributeData)
            For Each attribute In GetAttributes()
                Yield attribute
            Next
 
            If Me.TypeKind = TypeKind.Module Then
                Yield New PEAttributeData(ContainingPEModule,
                                          ContainingPEModule.Module.GetAttributeHandle(Me._handle, AttributeDescription.StandardModuleAttribute))
            End If
        End Function
 
        Public Overrides ReadOnly Property MemberNames As IEnumerable(Of String)
            Get
                EnsureNonTypeMemberNamesAreLoaded()
                Return _lazyMemberNames
            End Get
        End Property
 
        Private Sub EnsureNonTypeMemberNamesAreLoaded()
            If _lazyMemberNames Is Nothing Then
 
                Dim peModule = ContainingPEModule.Module
                Dim names = New HashSet(Of String)()
 
                Try
                    For Each methodDef In peModule.GetMethodsOfTypeOrThrow(_handle)
                        Try
                            names.Add(peModule.GetMethodDefNameOrThrow(methodDef))
                        Catch mrEx As BadImageFormatException
                        End Try
                    Next
                Catch mrEx As BadImageFormatException
                End Try
 
                Try
                    For Each propertyDef In peModule.GetPropertiesOfTypeOrThrow(_handle)
                        Try
                            names.Add(peModule.GetPropertyDefNameOrThrow(propertyDef))
                        Catch mrEx As BadImageFormatException
                        End Try
                    Next
                Catch mrEx As BadImageFormatException
                End Try
 
                Try
                    For Each eventDef In peModule.GetEventsOfTypeOrThrow(_handle)
                        Try
                            names.Add(peModule.GetEventDefNameOrThrow(eventDef))
                        Catch mrEx As BadImageFormatException
                        End Try
                    Next
                Catch mrEx As BadImageFormatException
                End Try
 
                Try
                    For Each fieldDef In peModule.GetFieldsOfTypeOrThrow(_handle)
                        Try
                            names.Add(peModule.GetFieldDefNameOrThrow(fieldDef))
                        Catch mrEx As BadImageFormatException
                        End Try
                    Next
                Catch mrEx As BadImageFormatException
                End Try
 
                Interlocked.CompareExchange(Of ICollection(Of String))(
                    _lazyMemberNames,
                    SpecializedCollections.ReadOnlySet(names),
                    Nothing)
            End If
        End Sub
 
        Public Overloads Overrides Function GetMembers() As ImmutableArray(Of Symbol)
            EnsureNestedTypesAreLoaded()
            EnsureNonTypeMembersAreLoaded()
 
            Return _lazyMembers.Flatten(DeclarationOrderSymbolComparer.Instance)
        End Function
 
        Friend Overrides Function GetMembersUnordered() As ImmutableArray(Of Symbol)
            EnsureNestedTypesAreLoaded()
            EnsureNonTypeMembersAreLoaded()
 
            Return _lazyMembers.Flatten().ConditionallyDeOrder()
        End Function
 
        Friend Overrides Function GetFieldsToEmit() As IEnumerable(Of FieldSymbol)
            ' If there are any fields, they are at the very beginning.
            Return GetMembers(Of FieldSymbol)(GetMembers(), SymbolKind.Field, offset:=0)
        End Function
 
        Friend Overrides Iterator Function GetMethodsToEmit() As IEnumerable(Of MethodSymbol)
            Dim members = GetMembers()
 
            ' Get to methods.
            Dim index = GetIndexOfFirstMember(members, SymbolKind.Method)
 
            If Not Me.IsInterfaceType() Then
                While index < members.Length
                    Dim member = members(index)
                    If member.Kind <> SymbolKind.Method Then
                        Exit While
                    End If
 
                    Dim method = DirectCast(member, MethodSymbol)
 
                    ' Don't emit the default value type constructor - the runtime handles that
                    If Not method.IsDefaultValueTypeConstructor() Then
                        Yield method
                    End If
 
                    index += 1
                End While
 
            Else
                ' We do not create symbols for v-table gap methods, let's figure out where the gaps go.
                If index >= members.Length OrElse members(index).Kind <> SymbolKind.Method Then
                    ' We didn't import any methods, it is Ok to return an empty set.
                    Return
                End If
 
                Dim method = DirectCast(members(index), PEMethodSymbol)
                Dim [module] = ContainingPEModule.Module
                Dim methodDefs = ArrayBuilder(Of MethodDefinitionHandle).GetInstance()
 
                Try
                    For Each methodDef In [module].GetMethodsOfTypeOrThrow(_handle)
                        methodDefs.Add(methodDef)
                    Next
                Catch mrEx As BadImageFormatException
                End Try
 
                For Each methodDef In methodDefs
                    If method.Handle = methodDef Then
                        Yield method
                        index += 1
 
                        If index = members.Length OrElse members(index).Kind <> SymbolKind.Method Then
                            ' no need to return any gaps at the end.
                            methodDefs.Free()
                            Return
                        End If
 
                        method = DirectCast(members(index), PEMethodSymbol)
 
                    Else
                        ' Encountered a gap.
                        Dim gapSize As Integer
 
                        Try
                            gapSize = ModuleExtensions.GetVTableGapSize([module].GetMethodDefNameOrThrow(methodDef))
                        Catch mrEx As BadImageFormatException
                            gapSize = 1
                        End Try
 
                        ' We don't have a symbol to return, so, even if the name doesn't represent a gap, we still have a gap.
                        Do
                            Yield Nothing
                            gapSize -= 1
                        Loop While gapSize > 0
                    End If
                Next
 
                ' Ensure we explicitly returned from inside loop.
                Throw ExceptionUtilities.Unreachable
            End If
        End Function
 
        Friend Overrides Function GetPropertiesToEmit() As IEnumerable(Of PropertySymbol)
            Return GetMembers(Of PropertySymbol)(GetMembers(), SymbolKind.Property)
        End Function
 
        Friend Overrides Function GetEventsToEmit() As IEnumerable(Of EventSymbol)
            Return GetMembers(Of EventSymbol)(GetMembers(), SymbolKind.Event)
        End Function
 
        Private Class DeclarationOrderSymbolComparer
            Implements IComparer(Of ISymbol)
 
            Public Shared ReadOnly Instance As New DeclarationOrderSymbolComparer()
 
            Private Sub New()
            End Sub
 
            Public Function Compare(x As ISymbol, y As ISymbol) As Integer Implements IComparer(Of ISymbol).Compare
                If x Is y Then
                    Return 0
                End If
 
                Dim cmp As Integer = x.Kind.ToSortOrder - y.Kind.ToSortOrder
 
                If cmp <> 0 Then
                    Return cmp
                End If
 
                Select Case x.Kind
                    Case SymbolKind.Field
                        Return HandleComparer.Default.Compare(DirectCast(x, PEFieldSymbol).Handle, DirectCast(y, PEFieldSymbol).Handle)
                    Case SymbolKind.Method
                        If DirectCast(x, MethodSymbol).IsDefaultValueTypeConstructor() Then
                            Return -1
                        ElseIf DirectCast(y, MethodSymbol).IsDefaultValueTypeConstructor() Then
                            Return 1
                        End If
 
                        Return HandleComparer.Default.Compare(DirectCast(x, PEMethodSymbol).Handle, DirectCast(y, PEMethodSymbol).Handle)
                    Case SymbolKind.Property
                        Return HandleComparer.Default.Compare(DirectCast(x, PEPropertySymbol).Handle, DirectCast(y, PEPropertySymbol).Handle)
                    Case SymbolKind.Event
                        Return HandleComparer.Default.Compare(DirectCast(x, PEEventSymbol).Handle, DirectCast(y, PEEventSymbol).Handle)
                    Case SymbolKind.NamedType
                        Return HandleComparer.Default.Compare(DirectCast(x, PENamedTypeSymbol).Handle, DirectCast(y, PENamedTypeSymbol).Handle)
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(x.Kind)
                End Select
            End Function
        End Class
 
        Private Sub EnsureNonTypeMembersAreLoaded()
 
            If _lazyMembers Is Nothing Then
                ' A method may be referenced as an accessor by one or more properties. And,
                ' any of those properties may be "bogus" if one of the property accessors
                ' does not match the property signature. If the method is referenced by at
                ' least one non-bogus property, then the method is created as an accessor,
                ' and (for purposes of error reporting if the method is referenced directly) the
                ' associated property is set (arbitrarily) to the first non-bogus property found
                ' in metadata. If the method is not referenced by any non-bogus properties,
                ' then the method is created as a normal method rather than an accessor.
                ' Create a dictionary of method symbols indexed by metadata row id
                ' (to allow efficient lookup when matching property accessors).
                Dim methodHandleToSymbol As Dictionary(Of MethodDefinitionHandle, PEMethodSymbol) = CreateMethods()
                Dim members = ArrayBuilder(Of Symbol).GetInstance()
 
                Dim ensureParameterlessConstructor As Boolean = (TypeKind = TypeKind.Structure OrElse TypeKind = TypeKind.Enum) AndAlso Not IsShared
 
                For Each member In methodHandleToSymbol.Values
                    members.Add(member)
 
                    If ensureParameterlessConstructor Then
                        ensureParameterlessConstructor = Not member.IsParameterlessConstructor()
                    End If
                Next
 
                If ensureParameterlessConstructor Then
                    members.Add(New SynthesizedConstructorSymbol(Nothing, Me, Me.IsShared, False, Nothing, Nothing))
                End If
 
                ' CreateFields will add withEvent names here if there are any.
                ' Otherwise stays Nothing
                Dim withEventNames As HashSet(Of String) = Nothing
 
                CreateProperties(methodHandleToSymbol, members)
                CreateFields(members, withEventNames)
                CreateEvents(methodHandleToSymbol, members)
 
                Dim membersDict As New Dictionary(Of String, ImmutableArray(Of Symbol))(CaseInsensitiveComparison.Comparer)
                Dim groupedMembers = members.GroupBy(Function(m) m.Name, CaseInsensitiveComparison.Comparer)
 
                For Each g In groupedMembers
                    membersDict.Add(g.Key, ImmutableArray.CreateRange(g))
                Next
 
                members.Free()
 
                ' tell WithEvents properties that they are WithEvents properties
                If withEventNames IsNot Nothing Then
                    For Each withEventName In withEventNames
                        Dim weMembers As ImmutableArray(Of Symbol) = Nothing
                        If membersDict.TryGetValue(withEventName, weMembers) Then
                            ' there must be only a single match for a given WithEvents name
                            If weMembers.Length <> 1 Then
                                Continue For
                            End If
 
                            ' it must be a valid property
                            Dim asProperty = TryCast(weMembers(0), PEPropertySymbol)
                            If asProperty IsNot Nothing AndAlso IsValidWithEventsProperty(asProperty) Then
                                asProperty.SetIsWithEvents(True)
                            End If
                        End If
                    Next
                End If
 
                ' Merge types into members
                For Each typeSymbols In _lazyNestedTypes.Values
                    Dim name = typeSymbols(0).Name
 
                    Dim symbols As ImmutableArray(Of Symbol) = Nothing
                    If Not membersDict.TryGetValue(name, symbols) Then
                        membersDict.Add(name, StaticCast(Of Symbol).From(typeSymbols))
                    Else
                        membersDict(name) = symbols.Concat(StaticCast(Of Symbol).From(typeSymbols))
                    End If
                Next
 
                Dim exchangeResult = Interlocked.CompareExchange(_lazyMembers, membersDict, Nothing)
 
                If exchangeResult Is Nothing Then
                    Dim memberNames = SpecializedCollections.ReadOnlyCollection(membersDict.Keys)
                    Interlocked.Exchange(Of ICollection(Of String))(_lazyMemberNames, memberNames)
                End If
            End If
        End Sub
 
        ''' <summary>
        ''' Some simple sanity checks if a property can actually be a withevents property
        ''' </summary>
        Private Function IsValidWithEventsProperty(prop As PEPropertySymbol) As Boolean
            ' NOTE: Dev10 does not make any checks. Just has comment that it could be a good idea to do in Whidbey.
            ' We will check, just to make stuff a bit more robust.
            ' It will be extremely rare that this function would fail though.
 
            If prop.IsReadOnly Or prop.IsWriteOnly Then
                Return False
            End If
 
            If Not prop.IsOverridable Then
                Return False
            End If
 
            Return True
        End Function
 
        Public Overloads Overrides Function GetMembers(name As String) As ImmutableArray(Of Symbol)
            EnsureNestedTypesAreLoaded()
            EnsureNonTypeMembersAreLoaded()
 
            Dim m As ImmutableArray(Of Symbol) = Nothing
 
            If _lazyMembers.TryGetValue(name, m) Then
                Return m
            End If
 
            Return ImmutableArray(Of Symbol).Empty
        End Function
 
        Friend Overrides Function GetTypeMembersUnordered() As ImmutableArray(Of NamedTypeSymbol)
            EnsureNestedTypesAreLoaded()
 
            Return StaticCast(Of NamedTypeSymbol).From(_lazyNestedTypes.Flatten())
        End Function
 
        Public Overloads Overrides Function GetTypeMembers() As ImmutableArray(Of NamedTypeSymbol)
            EnsureNestedTypesAreLoaded()
 
            Return StaticCast(Of NamedTypeSymbol).From(_lazyNestedTypes.Flatten(DeclarationOrderSymbolComparer.Instance))
        End Function
 
        Private Sub EnsureNestedTypesAreLoaded()
 
            If _lazyNestedTypes Is Nothing Then
 
                Dim types = ArrayBuilder(Of PENamedTypeSymbol).GetInstance()
                CreateNestedTypes(types)
                Dim typesDict = GroupByName(types)
 
                Interlocked.CompareExchange(_lazyNestedTypes, typesDict, Nothing)
 
                If _lazyNestedTypes Is typesDict Then
                    ' Build cache of TypeDef Tokens
                    ' Potentially this can be done in the background.
                    ContainingPEModule.OnNewTypeDeclarationsLoaded(typesDict)
                End If
 
                types.Free()
            End If
 
        End Sub
 
        Public Overloads Overrides Function GetTypeMembers(name As String) As ImmutableArray(Of NamedTypeSymbol)
            EnsureNestedTypesAreLoaded()
 
            Dim t As ImmutableArray(Of PENamedTypeSymbol) = Nothing
 
            If _lazyNestedTypes.TryGetValue(name, t) Then
                Return StaticCast(Of NamedTypeSymbol).From(t)
            End If
 
            Return ImmutableArray(Of NamedTypeSymbol).Empty
        End Function
 
        Public Overloads Overrides Function GetTypeMembers(name As String, arity As Integer) As ImmutableArray(Of NamedTypeSymbol)
            Return GetTypeMembers(name).WhereAsArray(Function(type, arity_) type.Arity = arity_, arity)
        End Function
 
        Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location)
            Get
                Return StaticCast(Of Location).From(ContainingPEModule.MetadataLocation)
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference)
            Get
                Return ImmutableArray(Of SyntaxReference).Empty
            End Get
        End Property
 
        Public Overrides ReadOnly Property Name As String
            Get
                Return _name
            End Get
        End Property
 
        Friend ReadOnly Property TypeDefFlags As TypeAttributes
            Get
                Return _flags
            End Get
        End Property
 
        Public Overrides ReadOnly Property TypeParameters As ImmutableArray(Of TypeParameterSymbol)
            Get
                EnsureTypeParametersAreLoaded()
                Return _lazyTypeParameters
            End Get
        End Property
 
        Private Sub EnsureTypeParametersAreLoaded()
 
            If _lazyTypeParameters.IsDefault Then
 
                Debug.Assert(_arity > 0)
 
                Dim ownedParams(_arity - 1) As PETypeParameterSymbol
 
                Dim moduleSymbol = ContainingPEModule
 
                ' If this is a nested type generic parameters in metadata include generic parameters of the outer types.
                Dim firstIndex = _genericParameterHandles.Count - Arity
 
                For i = 0 To ownedParams.Length - 1
                    ownedParams(i) = New PETypeParameterSymbol(moduleSymbol, Me, CUShort(i), _genericParameterHandles(firstIndex + i))
                Next
 
                ImmutableInterlocked.InterlockedCompareExchange(_lazyTypeParameters,
                                            StaticCast(Of TypeParameterSymbol).From(ownedParams.AsImmutableOrNull),
                                            Nothing)
            End If
 
        End Sub
 
        Public Overrides ReadOnly Property IsMustInherit As Boolean
            Get
                Return (_flags And TypeAttributes.Abstract) <> 0 AndAlso
                    (_flags And TypeAttributes.Sealed) = 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsMetadataAbstract As Boolean
            Get
                Return (_flags And TypeAttributes.Abstract) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property IsNotInheritable As Boolean
            Get
                Return (_flags And TypeAttributes.Sealed) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsMetadataSealed As Boolean
            Get
                Return (_flags And TypeAttributes.Sealed) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsWindowsRuntimeImport As Boolean
            Get
                Return (_flags And TypeAttributes.WindowsRuntime) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property ShouldAddWinRTMembers As Boolean
            Get
                Return IsWindowsRuntimeImport
            End Get
        End Property
 
        Friend Overrides Function GetGuidString(ByRef guidString As String) As Boolean
            Return ContainingPEModule.Module.HasGuidAttribute(_handle, guidString)
        End Function
 
        Public NotOverridable Overrides ReadOnly Property MightContainExtensionMethods As Boolean
            Get
                If _lazyMightContainExtensionMethods = ThreeState.Unknown Then
 
                    ' Only top level non-generic types with an Extension attribute are
                    ' valid containers of extension methods.
                    Dim result As Boolean = False
 
                    If _container.Kind = SymbolKind.Namespace AndAlso _arity = 0 Then
                        Dim containingModuleSymbol = Me.ContainingPEModule
 
                        If containingModuleSymbol.MightContainExtensionMethods AndAlso
                           containingModuleSymbol.Module.HasExtensionAttribute(Me._handle, ignoreCase:=True) Then
                            result = True
                        End If
                    End If
 
                    If result Then
                        _lazyMightContainExtensionMethods = ThreeState.True
                    Else
                        _lazyMightContainExtensionMethods = ThreeState.False
                    End If
                End If
 
                Return _lazyMightContainExtensionMethods = ThreeState.True
            End Get
        End Property
 
        Friend Overrides ReadOnly Property HasCodeAnalysisEmbeddedAttribute As Boolean
            Get
                If Me._lazyHasCodeAnalysisEmbeddedAttribute = ThreeState.Unknown Then
                    Interlocked.CompareExchange(
                        Me._lazyHasCodeAnalysisEmbeddedAttribute,
                        Me.ContainingPEModule.Module.HasCodeAnalysisEmbeddedAttribute(Me._handle).ToThreeState(),
                        ThreeState.Unknown)
                End If
                Return Me._lazyHasCodeAnalysisEmbeddedAttribute = ThreeState.True
            End Get
        End Property
 
        Friend Overrides ReadOnly Property HasVisualBasicEmbeddedAttribute As Boolean
            Get
                If Me._lazyHasVisualBasicEmbeddedAttribute = ThreeState.Unknown Then
                    Interlocked.CompareExchange(
                        Me._lazyHasVisualBasicEmbeddedAttribute,
                        Me.ContainingPEModule.Module.HasVisualBasicEmbeddedAttribute(Me._handle).ToThreeState(),
                        ThreeState.Unknown)
                End If
                Return Me._lazyHasVisualBasicEmbeddedAttribute = ThreeState.True
            End Get
        End Property
 
        Friend Overrides Sub BuildExtensionMethodsMap(
            map As Dictionary(Of String, ArrayBuilder(Of MethodSymbol)),
            appendThrough As NamespaceSymbol
        )
            If Me.MightContainExtensionMethods Then
                EnsureNestedTypesAreLoaded()
                EnsureNonTypeMembersAreLoaded()
 
                If Not appendThrough.BuildExtensionMethodsMap(map, _lazyMembers) Then
                    ' Didn't find any extension methods, record the fact.
                    _lazyMightContainExtensionMethods = ThreeState.False
                End If
            End If
        End Sub
 
        Friend Overrides Sub AddExtensionMethodLookupSymbolsInfo(nameSet As LookupSymbolsInfo,
                                                                  options As LookupOptions,
                                                                  originalBinder As Binder,
                                                                  appendThrough As NamedTypeSymbol)
            If Me.MightContainExtensionMethods Then
                EnsureNestedTypesAreLoaded()
                EnsureNonTypeMembersAreLoaded()
 
                If Not appendThrough.AddExtensionMethodLookupSymbolsInfo(nameSet, options, originalBinder, _lazyMembers) Then
                    ' Didn't find any extension methods, record the fact.
                    _lazyMightContainExtensionMethods = ThreeState.False
                End If
            End If
        End Sub
 
        Public Overrides ReadOnly Property TypeKind As TypeKind
            Get
                If _lazyTypeKind = TypeKind.Unknown Then
 
                    Dim result As TypeKind
 
                    If (_flags And TypeAttributes.Interface) <> 0 Then
                        result = TypeKind.Interface
                    Else
                        Dim base As TypeSymbol = GetDeclaredBase(Nothing)
 
                        result = TypeKind.Class
 
                        If base IsNot Nothing Then
                            ' Code is cloned from MetaImport::DoImportBaseAndImplements()
                            Dim baseCorTypeId As SpecialType = base.SpecialType
 
                            If baseCorTypeId = SpecialType.System_Enum Then
                                ' Enum
                                result = TypeKind.Enum
                            ElseIf baseCorTypeId = SpecialType.System_MulticastDelegate OrElse
                                   (baseCorTypeId = SpecialType.System_Delegate AndAlso Me.SpecialType <> SpecialType.System_MulticastDelegate) Then
                                ' Delegate
                                result = TypeKind.Delegate
                            ElseIf (baseCorTypeId = SpecialType.System_ValueType AndAlso
                                     Me.SpecialType <> SpecialType.System_Enum) Then
                                ' Struct
                                result = TypeKind.Structure
                            ElseIf Me.Arity = 0 AndAlso
                                Me.ContainingType Is Nothing AndAlso
                                ContainingPEModule.Module.HasAttribute(Me._handle, AttributeDescription.StandardModuleAttribute) Then
                                result = TypeKind.Module
                            End If
                        End If
                    End If
 
                    _lazyTypeKind = result
                End If
 
                Return CType(_lazyTypeKind, TypeKind)
            End Get
        End Property
 
        Friend Overrides ReadOnly Property IsInterface As Boolean
            Get
                Return (_flags And TypeAttributes.Interface) <> 0
            End Get
        End Property
 
        Public Overrides Function GetDocumentationCommentXml(Optional preferredCulture As CultureInfo = Nothing, Optional expandIncludes As Boolean = False, Optional cancellationToken As CancellationToken = Nothing) As String
            ' Note: m_lazyDocComment is passed ByRef
            Return PEDocumentationCommentUtils.GetDocumentationComment(
                Me, ContainingPEModule, preferredCulture, cancellationToken, _lazyDocComment)
        End Function
 
        Friend Overrides ReadOnly Property IsComImport As Boolean
            Get
                Return (_flags And TypeAttributes.Import) <> 0
            End Get
        End Property
 
        Friend Overrides ReadOnly Property CoClassType As TypeSymbol
            Get
                If _lazyCoClassType Is ErrorTypeSymbol.UnknownResultType Then
                    Interlocked.CompareExchange(_lazyCoClassType,
                                                MakeComImportCoClassType(),
                                                DirectCast(ErrorTypeSymbol.UnknownResultType, TypeSymbol))
                End If
 
                Return _lazyCoClassType
            End Get
        End Property
 
        Private Function MakeComImportCoClassType() As TypeSymbol
            If Not Me.IsInterface Then
                Return Nothing
            End If
 
            Dim coClassTypeName As String = Nothing
            If Not Me.ContainingPEModule.Module.HasStringValuedAttribute(Me._handle, AttributeDescription.CoClassAttribute, coClassTypeName) Then
                Return Nothing
            End If
 
            Dim decoder As New MetadataDecoder(Me.ContainingPEModule)
            Return decoder.GetTypeSymbolForSerializedType(coClassTypeName)
        End Function
 
        Friend Overrides ReadOnly Property DefaultPropertyName As String
            Get
                ' Unset value is Nothing. No default member is String.Empty.
                If _lazyDefaultPropertyName Is Nothing Then
                    Dim memberName = GetDefaultPropertyName()
                    Interlocked.CompareExchange(_lazyDefaultPropertyName, If(memberName, String.Empty), Nothing)
                End If
 
                ' Return Nothing rather than String.Empty for no default member.
                Return If(String.IsNullOrEmpty(_lazyDefaultPropertyName), Nothing, _lazyDefaultPropertyName)
            End Get
        End Property
 
        Private Function GetDefaultPropertyName() As String
            Dim memberName As String = Nothing
            ContainingPEModule.Module.HasDefaultMemberAttribute(Me._handle, memberName)
 
            If memberName IsNot Nothing Then
                For Each member In GetMembers(memberName)
                    ' Allow Default Shared properties for consistency with Dev10.
                    If member.Kind = SymbolKind.Property Then
                        Return memberName
                    End If
                Next
            End If
 
            Return Nothing
        End Function
 
        Private Sub CreateNestedTypes(members As ArrayBuilder(Of PENamedTypeSymbol))
            Dim moduleSymbol = Me.ContainingPEModule
            Dim [module] = moduleSymbol.Module
 
            Try
                For Each nestedTypeDef In [module].GetNestedTypeDefsOrThrow(_handle)
                    members.Add(New PENamedTypeSymbol(moduleSymbol, Me, nestedTypeDef))
                Next
            Catch mrEx As BadImageFormatException
            End Try
        End Sub
 
        Private Sub CreateFields(members As ArrayBuilder(Of Symbol),
                                 <Out()> ByRef witheventPropertyNames As HashSet(Of String))
 
            Dim moduleSymbol = Me.ContainingPEModule
            Dim [module] = moduleSymbol.Module
 
            Try
                For Each fieldDef In [module].GetFieldsOfTypeOrThrow(_handle)
                    Dim import As Boolean
 
                    Try
                        import = [module].ShouldImportField(fieldDef, moduleSymbol.ImportOptions)
 
                        If Not import Then
                            Select Case Me.TypeKind
                                Case TypeKind.Structure
                                    Select Case Me.SpecialType
                                        Case SpecialType.System_Void,
                                             SpecialType.System_Boolean,
                                             SpecialType.System_Char,
                                             SpecialType.System_Byte,
                                             SpecialType.System_SByte,
                                             SpecialType.System_Int16,
                                             SpecialType.System_UInt16,
                                             SpecialType.System_Int32,
                                             SpecialType.System_UInt32,
                                             SpecialType.System_Int64,
                                             SpecialType.System_UInt64,
                                             SpecialType.System_Single,
                                             SpecialType.System_Double,
                                             SpecialType.System_Decimal,
                                             SpecialType.System_IntPtr,
                                             SpecialType.System_UIntPtr,
                                             SpecialType.System_DateTime,
                                             SpecialType.System_TypedReference,
                                             SpecialType.System_ArgIterator,
                                             SpecialType.System_RuntimeArgumentHandle,
                                             SpecialType.System_RuntimeFieldHandle,
                                             SpecialType.System_RuntimeMethodHandle,
                                             SpecialType.System_RuntimeTypeHandle
                                        Case Else
                                            ' This is an ordinary struct
                                            If ([module].GetFieldDefFlagsOrThrow(fieldDef) And FieldAttributes.Static) = 0 Then
                                                import = True
                                            End If
                                    End Select
 
                                Case TypeKind.Enum
                                    If ([module].GetFieldDefFlagsOrThrow(fieldDef) And FieldAttributes.Static) = 0 Then
                                        import = True
                                    End If
                            End Select
                        End If
                    Catch mrEx As BadImageFormatException
                    End Try
 
                    If import Then
                        members.Add(New PEFieldSymbol(moduleSymbol, Me, fieldDef))
                    End If
 
                    Dim witheventPropertyName As String = Nothing
                    If [module].HasAccessedThroughPropertyAttribute(fieldDef, witheventPropertyName) Then
                        '       Dev10 does not check if names are duplicated, but it does check
                        '       that withevents names match some property name using identifier match
                        '       So if names are duplicated they would refer to same property.
                        '       We will just put names in a set.
                        If witheventPropertyNames Is Nothing Then
                            witheventPropertyNames = New HashSet(Of String)(IdentifierComparison.Comparer)
                        End If
 
                        witheventPropertyNames.Add(witheventPropertyName)
                    End If
 
                Next
            Catch mrEx As BadImageFormatException
            End Try
        End Sub
 
        Private Function CreateMethods() As Dictionary(Of MethodDefinitionHandle, PEMethodSymbol)
            Dim methods = New Dictionary(Of MethodDefinitionHandle, PEMethodSymbol)()
            Dim moduleSymbol = Me.ContainingPEModule
            Dim [module] = moduleSymbol.Module
 
            Try
                For Each methodDef In [module].GetMethodsOfTypeOrThrow(_handle)
                    If [module].ShouldImportMethod(_handle, methodDef, moduleSymbol.ImportOptions) Then
                        methods.Add(methodDef, New PEMethodSymbol(moduleSymbol, Me, methodDef))
                    End If
                Next
            Catch mrEx As BadImageFormatException
            End Try
 
            Return methods
        End Function
 
        Private Sub CreateProperties(methodHandleToSymbol As Dictionary(Of MethodDefinitionHandle, PEMethodSymbol), members As ArrayBuilder(Of Symbol))
            Dim moduleSymbol = Me.ContainingPEModule
            Dim [module] = moduleSymbol.Module
 
            Try
                For Each propertyDef In [module].GetPropertiesOfTypeOrThrow(_handle)
                    Try
                        Dim methods = [module].GetPropertyMethodsOrThrow(propertyDef)
 
                        Dim getMethod = GetAccessorMethod(moduleSymbol, methodHandleToSymbol, _handle, methods.Getter)
                        Dim setMethod = GetAccessorMethod(moduleSymbol, methodHandleToSymbol, _handle, methods.Setter)
 
                        If (getMethod IsNot Nothing) OrElse (setMethod IsNot Nothing) Then
                            members.Add(PEPropertySymbol.Create(moduleSymbol, Me, propertyDef, getMethod, setMethod))
                        End If
                    Catch mrEx As BadImageFormatException
                    End Try
                Next
            Catch mrEx As BadImageFormatException
            End Try
        End Sub
 
        Private Sub CreateEvents(methodHandleToSymbol As Dictionary(Of MethodDefinitionHandle, PEMethodSymbol), members As ArrayBuilder(Of Symbol))
            Dim moduleSymbol = Me.ContainingPEModule
            Dim [module] = moduleSymbol.Module
 
            Try
                For Each eventRid In [module].GetEventsOfTypeOrThrow(_handle)
                    Try
                        Dim methods = [module].GetEventMethodsOrThrow(eventRid)
 
                        ' NOTE: C# ignores all other accessors (most notably, raise/fire).
                        Dim addMethod = GetAccessorMethod(moduleSymbol, methodHandleToSymbol, _handle, methods.Adder)
                        Dim removeMethod = GetAccessorMethod(moduleSymbol, methodHandleToSymbol, _handle, methods.Remover)
                        Dim raiseMethod = GetAccessorMethod(moduleSymbol, methodHandleToSymbol, _handle, methods.Raiser)
 
                        ' VB ignores events that do not have both Add and Remove.
                        If (addMethod IsNot Nothing) AndAlso (removeMethod IsNot Nothing) Then
                            members.Add(New PEEventSymbol(moduleSymbol, Me, eventRid, addMethod, removeMethod, raiseMethod))
                        End If
                    Catch mrEx As BadImageFormatException
                    End Try
                Next
            Catch mrEx As BadImageFormatException
            End Try
        End Sub
 
        Private Shared Function GetAccessorMethod(moduleSymbol As PEModuleSymbol, methodHandleToSymbol As Dictionary(Of MethodDefinitionHandle, PEMethodSymbol), typeDef As TypeDefinitionHandle, methodDef As MethodDefinitionHandle) As PEMethodSymbol
            If methodDef.IsNil Then
                Return Nothing
            End If
 
            Dim method As PEMethodSymbol = Nothing
            Dim found As Boolean = methodHandleToSymbol.TryGetValue(methodDef, method)
            Debug.Assert(found OrElse Not moduleSymbol.Module.ShouldImportMethod(typeDef, methodDef, moduleSymbol.ImportOptions))
            Return method
        End Function
 
        Private Shared Function GroupByName(symbols As ArrayBuilder(Of PENamedTypeSymbol)) As Dictionary(Of String, ImmutableArray(Of PENamedTypeSymbol))
            If symbols.Count = 0 Then
                Return s_emptyNestedTypes
            End If
 
            Return symbols.ToDictionary(Function(s) s.Name, IdentifierComparison.Comparer)
        End Function
 
        Friend Overrides Function GetUseSiteInfo() As UseSiteInfo(Of AssemblySymbol)
            Dim primaryDependency As AssemblySymbol = Me.PrimaryDependency
 
            If Not _lazyCachedUseSiteInfo.IsInitialized Then
                _lazyCachedUseSiteInfo.Initialize(primaryDependency, CalculateUseSiteInfoImpl())
            End If
 
            Return _lazyCachedUseSiteInfo.ToUseSiteInfo(primaryDependency)
        End Function
 
        Private Function CalculateUseSiteInfoImpl() As UseSiteInfo(Of AssemblySymbol)
            ' GetCompilerFeatureRequiredDiagnostic depends on this being the highest priority use-site diagnostic. If another
            ' diagnostic was calculated first and cached, it will return incorrect results and assert in Debug mode.
            Dim compilerFeatureRequiredDiagnostic = DeriveCompilerFeatureRequiredDiagnostic()
            If compilerFeatureRequiredDiagnostic IsNot Nothing Then
                Return New UseSiteInfo(Of AssemblySymbol)(compilerFeatureRequiredDiagnostic)
            End If
 
            Dim useSiteInfo = CalculateUseSiteInfo()
 
            If useSiteInfo.DiagnosticInfo Is Nothing Then
 
                ' Check if this type Is marked by RequiredAttribute attribute.
                ' If so mark the type as bad, because it relies upon semantics that are not understood by the VB compiler.
                If Me.ContainingPEModule.Module.HasRequiredAttributeAttribute(Me.Handle) Then
                    Return New UseSiteInfo(Of AssemblySymbol)(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me))
                End If
 
                Dim typeKind = Me.TypeKind
                Dim specialtype = Me.SpecialType
                If (typeKind = TypeKind.Class OrElse typeKind = TypeKind.Module) AndAlso
                   specialtype <> SpecialType.System_Enum AndAlso specialtype <> SpecialType.System_MulticastDelegate Then
                    Dim base As TypeSymbol = GetDeclaredBase(Nothing)
 
                    If base IsNot Nothing AndAlso base.SpecialType = SpecialType.None AndAlso base.ContainingAssembly?.IsMissing Then
                        Dim missingType = TryCast(base, MissingMetadataTypeSymbol.TopLevel)
 
                        If missingType IsNot Nothing AndAlso missingType.Arity = 0 Then
                            Dim emittedName As String = MetadataHelpers.BuildQualifiedName(missingType.NamespaceName, missingType.MetadataName)
 
                            Select Case SpecialTypes.GetTypeFromMetadataName(emittedName)
                                Case SpecialType.System_Enum,
                                     SpecialType.System_Delegate,
                                     SpecialType.System_MulticastDelegate,
                                     SpecialType.System_ValueType
                                    ' This might be a structure, an enum, or a delegate
                                    Return missingType.GetUseSiteInfo()
                            End Select
                        End If
                    End If
                End If
 
                ' Verify type parameters for containing types
                ' match those on the containing types.
                If Not MatchesContainingTypeParameters() Then
                    Return New UseSiteInfo(Of AssemblySymbol)(ErrorFactory.ErrorInfo(ERRID.ERR_NestingViolatesCLS1, Me))
                End If
            End If
 
            Return useSiteInfo
        End Function
 
        Friend Function GetCompilerFeatureRequiredDiagnostic() As DiagnosticInfo
            Dim typeUseSiteInfo = GetUseSiteInfo()
            If typeUseSiteInfo.DiagnosticInfo?.Code = ERRID.ERR_UnsupportedCompilerFeature Then
                Return typeUseSiteInfo.DiagnosticInfo
            End If
 
            Debug.Assert(DeriveCompilerFeatureRequiredDiagnostic() Is Nothing)
 
            Return Nothing
        End Function
 
        Private Function DeriveCompilerFeatureRequiredDiagnostic() As DiagnosticInfo
            Dim decoder = New MetadataDecoder(ContainingPEModule, Me)
 
            Dim diagnostic = DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, ContainingPEModule, Handle, CompilerFeatureRequiredFeatures.RefStructs, decoder)
 
            If diagnostic IsNot Nothing Then
                Return diagnostic
            End If
 
            For Each typeParameter In TypeParameters
                diagnostic = DirectCast(typeParameter, PETypeParameterSymbol).DeriveCompilerFeatureRequiredDiagnostic(decoder)
 
                If diagnostic IsNot Nothing Then
                    Return diagnostic
                End If
            Next
 
            Dim containingPEType = TryCast(ContainingType, PENamedTypeSymbol)
 
            Return If(containingPEType IsNot Nothing, containingPEType.GetCompilerFeatureRequiredDiagnostic(), ContainingPEModule.GetCompilerFeatureRequiredDiagnostic())
        End Function
 
        ''' <summary>
        ''' Return true if the type parameters specified on the nested type (Me),
        ''' that represent the corresponding type parameters on the containing
        ''' types, in fact match the actual type parameters on the containing types.
        ''' </summary>
        Private Function MatchesContainingTypeParameters() As Boolean
            If _genericParameterHandles.Count = 0 Then
                Return True
            End If
 
            Dim container = ContainingType
            If container Is Nothing Then
                Return True
            End If
 
            Dim containingTypeParameters = container.GetAllTypeParameters()
            Dim n = containingTypeParameters.Length
 
            If n = 0 Then
                Return True
            End If
 
            ' Create an instance of PENamedTypeSymbol for the nested type, but
            ' with all type parameters, from the nested type and all containing
            ' types. The type parameters on this temporary type instance are used
            ' for comparison with those on the actual containing types. The
            ' containing symbol for the temporary type is the namespace directly.
            Dim nestedType = New PENamedTypeSymbol(ContainingPEModule, DirectCast(ContainingNamespace, PENamespaceSymbol), _handle)
            Dim nestedTypeParameters = nestedType.TypeParameters
            Dim containingTypeMap = TypeSubstitution.Create(
                container,
                containingTypeParameters,
                IndexedTypeParameterSymbol.Take(n).As(Of TypeSymbol))
            Dim nestedTypeMap = TypeSubstitution.Create(
                nestedType,
                nestedTypeParameters,
                IndexedTypeParameterSymbol.Take(nestedTypeParameters.Length).As(Of TypeSymbol))
 
            For i = 0 To n - 1
                Dim containingTypeParameter = containingTypeParameters(i)
                Dim nestedTypeParameter = nestedTypeParameters(i)
                If Not MethodSignatureComparer.HaveSameConstraints(
                    containingTypeParameter,
                    containingTypeMap,
                    nestedTypeParameter,
                    nestedTypeMap) Then
                    Return False
                End If
            Next
 
            Return True
        End Function
 
        ''' <summary>
        ''' Force all declaration errors to be generated.
        ''' </summary>
        Friend Overrides Sub GenerateDeclarationErrors(cancellationToken As CancellationToken)
            Throw ExceptionUtilities.Unreachable
        End Sub
 
        Friend Overrides ReadOnly Property ObsoleteAttributeData As ObsoleteAttributeData
            Get
                ObsoleteAttributeHelpers.InitializeObsoleteDataFromMetadata(_lazyObsoleteAttributeData, _handle, ContainingPEModule)
                Return _lazyObsoleteAttributeData
            End Get
        End Property
 
        Friend Overrides Function GetAppliedConditionalSymbols() As ImmutableArray(Of String)
            If Me._lazyConditionalAttributeSymbols.IsDefault Then
                Dim conditionalSymbols As ImmutableArray(Of String) = ContainingPEModule.Module.GetConditionalAttributeValues(_handle)
                Debug.Assert(Not conditionalSymbols.IsDefault)
                ImmutableInterlocked.InterlockedCompareExchange(_lazyConditionalAttributeSymbols, conditionalSymbols, Nothing)
            End If
 
            Return Me._lazyConditionalAttributeSymbols
        End Function
 
        Friend Overrides Function GetAttributeUsageInfo() As AttributeUsageInfo
            If _lazyAttributeUsageInfo.IsNull Then
                _lazyAttributeUsageInfo = DecodeAttributeUsageInfo()
            End If
 
            Debug.Assert(Not _lazyAttributeUsageInfo.IsNull)
            Return _lazyAttributeUsageInfo
        End Function
 
        Private Function DecodeAttributeUsageInfo() As AttributeUsageInfo
            Dim result As AttributeUsageInfo = Nothing
 
            If Me.ContainingPEModule.Module.HasAttributeUsageAttribute(_handle, New MetadataDecoder(ContainingPEModule), result) Then
                Return result
            End If
 
            Dim baseType = Me.BaseTypeNoUseSiteDiagnostics
            Return If(baseType IsNot Nothing, baseType.GetAttributeUsageInfo(), AttributeUsageInfo.Default)
        End Function
 
        Friend Overrides ReadOnly Property HasDeclarativeSecurity As Boolean
            Get
                Throw ExceptionUtilities.Unreachable
            End Get
        End Property
 
        Friend Overrides Function GetSecurityInformation() As IEnumerable(Of Microsoft.Cci.SecurityAttribute)
            Throw ExceptionUtilities.Unreachable
        End Function
 
        Friend Overrides ReadOnly Property IsExtensibleInterfaceNoUseSiteDiagnostics As Boolean
            Get
                If _lazyIsExtensibleInterface = ThreeState.Unknown Then
                    _lazyIsExtensibleInterface = DecodeIsExtensibleInterface().ToThreeState()
                End If
 
                Return _lazyIsExtensibleInterface.Value
            End Get
        End Property
 
        Private Function DecodeIsExtensibleInterface() As Boolean
            If Me.IsInterfaceType() Then
                If Me.HasAttributeForExtensibleInterface() Then
                    Return True
                End If
 
                For Each [interface] In Me.AllInterfacesNoUseSiteDiagnostics
                    If [interface].IsExtensibleInterfaceNoUseSiteDiagnostics Then
                        Return True
                    End If
                Next
            End If
 
            Return False
        End Function
 
        Private Function HasAttributeForExtensibleInterface() As Boolean
            Dim metadataModule = Me.ContainingPEModule.Module
 
            ' Is interface marked with 'TypeLibTypeAttribute( flags w/o TypeLibTypeFlags.FNonExtensible )' attribute
            Dim flags As Cci.TypeLibTypeFlags = Nothing
            If metadataModule.HasTypeLibTypeAttribute(Me._handle, flags) AndAlso
                (flags And Cci.TypeLibTypeFlags.FNonExtensible) = 0 Then
                Return True
            End If
 
            ' Is interface marked with 'InterfaceTypeAttribute( flags with ComInterfaceType.InterfaceIsIDispatch )' attribute
            Dim interfaceType As ComInterfaceType = Nothing
            If metadataModule.HasInterfaceTypeAttribute(Me._handle, interfaceType) AndAlso
                (interfaceType And Cci.Constants.ComInterfaceType_InterfaceIsIDispatch) <> 0 Then
                Return True
            End If
 
            Return False
        End Function
 
        ''' <remarks>
        ''' This is for perf, not for correctness.
        ''' </remarks>
        Friend NotOverridable Overrides ReadOnly Property DeclaringCompilation As VisualBasicCompilation
            Get
                Return Nothing
            End Get
        End Property
 
        ''' <summary>
        ''' Returns the index of the first member of the specific kind.
        ''' Returns the number of members if not found.
        ''' </summary>
        Private Shared Function GetIndexOfFirstMember(members As ImmutableArray(Of Symbol), kind As SymbolKind) As Integer
            Dim n = members.Length
            For i = 0 To n - 1
                If members(i).Kind = kind Then
                    Return i
                End If
            Next
            Return n
        End Function
 
        ''' <summary>
        ''' Returns all members of the specific kind, starting at the optional offset.
        ''' Members of the same kind are assumed to be contiguous.
        ''' </summary>
        Private Overloads Shared Iterator Function GetMembers(Of TSymbol As Symbol)(members As ImmutableArray(Of Symbol), kind As SymbolKind, Optional offset As Integer = -1) As IEnumerable(Of TSymbol)
            If offset < 0 Then
                offset = GetIndexOfFirstMember(members, kind)
            End If
            Dim n = members.Length
            For i = offset To n - 1
                Dim member = members(i)
                If member.Kind <> kind Then
                    Return
                End If
                Yield DirectCast(member, TSymbol)
            Next
        End Function
 
        Friend NotOverridable Overrides Function GetSynthesizedWithEventsOverrides() As IEnumerable(Of PropertySymbol)
            Return SpecializedCollections.EmptyEnumerable(Of PropertySymbol)()
        End Function
 
        Friend Overrides ReadOnly Property HasAnyDeclaredRequiredMembers As Boolean
            Get
                Return ContainingPEModule.Module.HasAttribute(Handle, AttributeDescription.RequiredMemberAttribute)
            End Get
        End Property
    End Class
 
End Namespace