File: Binding\Binder_Lookup.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.Generic
Imports System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports System.Threading
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Imports TypeKind = Microsoft.CodeAnalysis.TypeKind
 
Namespace Microsoft.CodeAnalysis.VisualBasic
    ' Handler the parts of binding for member lookup.
    Partial Friend Class Binder
 
        Friend Sub LookupMember(lookupResult As LookupResult,
                                container As NamespaceOrTypeSymbol,
                                name As String,
                                arity As Integer,
                                options As LookupOptions,
                                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
            Debug.Assert(options.IsValid())
 
            options = BinderSpecificLookupOptions(options)
            MemberLookup.Lookup(lookupResult, container, name, arity, options, Me, useSiteInfo)
        End Sub
 
        Friend Sub LookupMember(lookupResult As LookupResult,
                                container As TypeSymbol,
                                name As String,
                                arity As Integer,
                                options As LookupOptions,
                                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
            Debug.Assert(options.IsValid())
 
            options = BinderSpecificLookupOptions(options)
            Dim tempResult = lookupResult.GetInstance()
            MemberLookup.Lookup(lookupResult, container, name, arity, options, Me, tempResult, useSiteInfo)
            tempResult.Free()
        End Sub
 
        Friend Sub LookupMember(lookupResult As LookupResult,
                                container As NamespaceSymbol,
                                name As String,
                                arity As Integer,
                                options As LookupOptions,
                                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
            Debug.Assert(options.IsValid())
 
            options = BinderSpecificLookupOptions(options)
            MemberLookup.Lookup(lookupResult, container, name, arity, options, Me, useSiteInfo)
        End Sub
 
        Friend Sub LookupMemberImmediate(lookupResult As LookupResult,
                                container As NamespaceSymbol,
                                name As String,
                                arity As Integer,
                                options As LookupOptions,
                                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
            Debug.Assert(options.IsValid())
 
            options = BinderSpecificLookupOptions(options)
            MemberLookup.LookupImmediate(lookupResult, container, name, arity, options, Me, useSiteInfo)
        End Sub
 
        Friend Sub LookupExtensionMethods(
            lookupResult As LookupResult,
            container As TypeSymbol,
            name As String,
            arity As Integer,
            options As LookupOptions,
            <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
        )
            Debug.Assert(options.IsValid())
            Debug.Assert(lookupResult.IsClear)
            options = BinderSpecificLookupOptions(options)
            MemberLookup.LookupForExtensionMethods(lookupResult, container, name, arity, options, Me, useSiteInfo)
        End Sub
 
        Friend Sub LookupMemberInModules(lookupResult As LookupResult,
                                container As NamespaceSymbol,
                                name As String,
                                arity As Integer,
                                options As LookupOptions,
                                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
            Debug.Assert(options.IsValid())
 
            options = BinderSpecificLookupOptions(options)
            MemberLookup.LookupInModules(lookupResult, container, name, arity, options, Me, useSiteInfo)
        End Sub
 
        Friend Sub AddMemberLookupSymbolsInfo(nameSet As LookupSymbolsInfo,
                                     container As NamespaceOrTypeSymbol,
                                     options As LookupOptions)
            Debug.Assert(options.IsValid())
 
            options = BinderSpecificLookupOptions(options)
            MemberLookup.AddLookupSymbolsInfo(nameSet, container, options, Me)
        End Sub
 
        ' Validates a symbol to check if it 
        ' a) has the right arity 
        ' b) is accessible. (accessThroughType is passed in for protected access checks)
        ' c) matches the lookup options.
        ' A non-empty SingleLookupResult with the result is returned.
        '
        ' For symbols from outside of this compilation the method also checks 
        ' if the symbol is marked with 'Microsoft.VisualBasic.Embedded' or 'Microsoft.CodeAnalysis.Embedded' attributes.
        '
        ' If arity passed in is -1, no arity checks are done.
        Friend Function CheckViability(sym As Symbol,
                                       arity As Integer,
                                       options As LookupOptions,
                                       accessThroughType As TypeSymbol,
                                       <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As SingleLookupResult
            Debug.Assert(sym IsNot Nothing)
 
            If Not sym.CanBeReferencedByNameIgnoringIllegalCharacters Then
                Return SingleLookupResult.Empty
            End If
 
            If (options And LookupOptions.LabelsOnly) <> 0 Then
                ' If LabelsOnly is set then the symbol must be a label otherwise return empty
                If options = LookupOptions.LabelsOnly AndAlso sym.Kind = SymbolKind.Label Then
                    Return SingleLookupResult.Good(sym)
                End If
 
                ' Mixing LabelsOnly with any other flag returns an empty result
                Return SingleLookupResult.Empty
            End If
 
            If (options And LookupOptions.MustNotBeReturnValueVariable) <> 0 Then
                '§11.4.4 Simple Name Expressions
                '    If the identifier matches a local variable, the local variable matched is 
                '    the implicit function or Get accessor return local variable, and the expression
                '    is part of an invocation expression, invocation statement, or an AddressOf 
                '    expression, then no match occurs and resolution continues.
                '
                ' LookupOptions.MustNotBeReturnValueVariable is set if "the expression
                ' is part of an invocation expression, invocation statement, or an AddressOf 
                ' expression", and we then skip return value variables.
                ' We'll always bind to the containing method or property instead further on in the lookup process.
                If sym.Kind = SymbolKind.Local AndAlso DirectCast(sym, LocalSymbol).IsFunctionValue Then
                    Return SingleLookupResult.Empty
                End If
            End If
 
            Dim unwrappedSym = sym
            Dim asAlias = TryCast(sym, AliasSymbol)
            If asAlias IsNot Nothing Then
                unwrappedSym = asAlias.Target
            End If
 
            ' Check for external symbols marked with 'Microsoft.VisualBasic.Embedded' or 'Microsoft.CodeAnalysis.Embedded' attributes
            If unwrappedSym.ContainingModule IsNot Me.ContainingModule Then
                If unwrappedSym.IsHiddenByVisualBasicEmbeddedAttribute() OrElse unwrappedSym.IsHiddenByCodeAnalysisEmbeddedAttribute() Then
                    Return SingleLookupResult.Empty
                End If
            End If
 
            If unwrappedSym.Kind = SymbolKind.NamedType AndAlso unwrappedSym.EmbeddedSymbolKind = EmbeddedSymbolKind.EmbeddedAttribute AndAlso
                    Me.SyntaxTree IsNot Nothing AndAlso Me.SyntaxTree.GetEmbeddedKind = EmbeddedSymbolKind.None Then
                ' Only allow direct access to Microsoft.VisualBasic.Embedded attribute
                ' from user code if current compilation embeds Vb Core
                If Not Me.Compilation.Options.EmbedVbCoreRuntime Then
                    Return SingleLookupResult.Empty
                End If
            End If
 
            ' Do arity checking, unless specifically asked not to.
            ' Only types and namespaces in VB shadow by arity. All other members shadow 
            ' regardless of arity. So, we only check arity on types.
            If arity <> -1 Then
                Select Case sym.Kind
                    Case SymbolKind.NamedType, SymbolKind.ErrorType
                        Dim actualArity As Integer = DirectCast(sym, NamedTypeSymbol).Arity
                        If actualArity <> arity Then
                            Return SingleLookupResult.WrongArity(sym, WrongArityErrid(actualArity, arity))
                        End If
 
                    Case SymbolKind.TypeParameter, SymbolKind.Namespace
                        If arity <> 0 Then ' type parameters and namespaces are always arity 0
                            Return SingleLookupResult.WrongArity(unwrappedSym, WrongArityErrid(0, arity))
                        End If
 
                    Case SymbolKind.Alias
                        ' Since raw generics cannot be imported, the import aliases would always refer to
                        ' constructed types when referring to generics. So any other generic arity besides
                        ' -1 or 0 are invalid.
                        If arity <> 0 Then ' aliases are always arity 0, but error refers to the target
                            ' Note, Dev11 doesn't stop lookup in case of arity mismatch for an alias.
                            Return SingleLookupResult.WrongArity(unwrappedSym, WrongArityErrid(0, arity))
                        End If
 
                    Case SymbolKind.Method
                        ' Unlike types and namespaces, we always stop looking if we find a method with the right name but wrong arity.
 
                        ' The arity matching rules for methods are customizable for the LookupOptions; when binding expressions 
                        ' we always pass AllMethodsOfAnyArity and allow overload resolution to filter methods. The other flags
                        ' are for binding API scenarios.
                        Dim actualArity As Integer = DirectCast(sym, MethodSymbol).Arity
                        If actualArity <> arity AndAlso
                           Not ((options And LookupOptions.AllMethodsOfAnyArity) <> 0) Then
                            Return SingleLookupResult.WrongArityAndStopLookup(sym, WrongArityErrid(actualArity, arity))
                        End If
 
                    Case Else
                        ' Unlike types and namespace, we stop looking if we find other symbols with wrong arity.
                        ' All these symbols have arity 0.
                        If arity <> 0 Then
                            Return SingleLookupResult.WrongArityAndStopLookup(sym, WrongArityErrid(0, arity))
                        End If
                End Select
            End If
 
            If (options And LookupOptions.IgnoreAccessibility) = 0 Then
                Dim accessCheckResult = CheckAccessibility(unwrappedSym, useSiteInfo, If((options And LookupOptions.UseBaseReferenceAccessibility) <> 0, Nothing, accessThroughType))
                ' Check if we are in 'MyBase' resolving mode and we need to ignore 'accessThroughType' to make protected members accessed
                If accessCheckResult <> VisualBasic.AccessCheckResult.Accessible Then
                    Return SingleLookupResult.Inaccessible(sym, GetInaccessibleErrorInfo(sym))
                End If
            End If
 
            If (options And Global.Microsoft.CodeAnalysis.VisualBasic.LookupOptions.MustNotBeInstance) <> 0 AndAlso sym.IsInstanceMember Then
                Return Global.Microsoft.CodeAnalysis.VisualBasic.SingleLookupResult.MustNotBeInstance(sym, Global.Microsoft.CodeAnalysis.VisualBasic.ERRID.ERR_ObjectReferenceNotSupplied)
            ElseIf (options And Global.Microsoft.CodeAnalysis.VisualBasic.LookupOptions.MustBeInstance) <> 0 AndAlso Not sym.IsInstanceMember Then
                Return Global.Microsoft.CodeAnalysis.VisualBasic.SingleLookupResult.MustBeInstance(sym) ' there is no error message for this 
            End If
 
            Return SingleLookupResult.Good(sym)
        End Function
 
        Friend Function GetInaccessibleErrorInfo(sym As Symbol) As DiagnosticInfo
            Dim unwrappedSym = sym
            Dim asAlias = TryCast(sym, AliasSymbol)
            If asAlias IsNot Nothing Then
                unwrappedSym = asAlias.Target
            ElseIf sym.Kind = SymbolKind.Method Then
                sym = DirectCast(sym, MethodSymbol).ConstructedFrom
            End If
 
            Dim diagInfo As DiagnosticInfo
 
            ' for inaccessible members (in e.g. AddressOf expressions, DEV10 shows a ERR_InaccessibleMember3 diagnostic)
            ' TODO maybe this condition needs to be adjusted to be shown in cases of e.g. inaccessible properties
            If unwrappedSym.Kind = SymbolKind.Method AndAlso unwrappedSym.ContainingSymbol IsNot Nothing Then
                diagInfo = New BadSymbolDiagnostic(sym,
                                                   ERRID.ERR_InaccessibleMember3,
                                                   sym.ContainingSymbol.Name,
                                                   sym,
                                                   AccessCheck.GetAccessibilityForErrorMessage(sym, Me.Compilation.Assembly))
            Else
                diagInfo = New BadSymbolDiagnostic(sym,
                                                   ERRID.ERR_InaccessibleSymbol2,
                                                   CustomSymbolDisplayFormatter.QualifiedName(sym),
                                                   AccessCheck.GetAccessibilityForErrorMessage(sym, sym.ContainingAssembly))
            End If
 
            Debug.Assert(diagInfo.Severity = DiagnosticSeverity.Error)
            Return diagInfo
        End Function
 
        ''' <summary>
        ''' Used by Add*LookupSymbolsInfo* to determine whether the symbol is of interest.
        ''' Distinguish from <see cref="CheckViability"/>, which performs an analogous task for LookupSymbols*.
        ''' </summary>
        ''' <remarks>
        ''' Does not consider <see cref="Symbol.CanBeReferencedByName"/> - that is left to the caller.
        ''' </remarks>
        Friend Function CanAddLookupSymbolInfo(sym As Symbol,
                                                    options As LookupOptions,
                                                    nameSet As LookupSymbolsInfo,
                                                    accessThroughType As TypeSymbol) As Boolean
            Debug.Assert(sym IsNot Nothing)
 
            If Not nameSet.CanBeAdded(sym.Name) Then
                Return False
            End If
 
            Dim singleResult = CheckViability(sym, -1, options, accessThroughType, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
 
            If (options And LookupOptions.MethodsOnly) <> 0 AndAlso
               sym.Kind <> SymbolKind.Method Then
                Return False
            End If
 
            If singleResult.IsGoodOrAmbiguous Then
                ' Its possible there is an error (ambiguity, wrong arity) associated with result.
                ' We still return true here, because binding finds that symbol and doesn't continue.
 
                ' NOTE: We're going to let the SemanticModel check for symbols that can't be
                ' referenced by name.  That way, it can either filter them or not, depending
                ' on whether a name was passed to LookupSymbols.
                Return True
            End If
 
            Return False
        End Function
 
        ' return the error id for mismatched arity.
        Private Shared Function WrongArityErrid(actualArity As Integer, arity As Integer) As ERRID
            If actualArity < arity Then
                If actualArity = 0 Then
                    Return ERRID.ERR_TypeOrMemberNotGeneric1
                Else
                    Return ERRID.ERR_TooManyGenericArguments1
                End If
            Else
                Debug.Assert(actualArity > arity, "arities shouldn't match")
                Return ERRID.ERR_TooFewGenericArguments1
            End If
        End Function
 
        ''' <summary>
        ''' This class handles binding of members of namespaces and types.
        ''' The key member is Lookup, which handles looking up a name
        ''' in a namespace or type, by name and arity, and produces a 
        ''' lookup result. 
        ''' </summary>
        Private Class MemberLookup
            ''' <summary>
            ''' Lookup a member name in a namespace or type, returning a LookupResult that
            ''' summarizes the results of the lookup. See LookupResult structure for a detailed
            ''' discussing of the meaning of the results. The supplied binder is used for accessibility
            ''' checked and base class suppression.
            ''' </summary>
            Public Shared Sub Lookup(lookupResult As LookupResult,
                                     container As NamespaceOrTypeSymbol,
                                     name As String,
                                     arity As Integer,
                                     options As LookupOptions,
                                     binder As Binder,
                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                If container.IsNamespace Then
                    Lookup(lookupResult, DirectCast(container, NamespaceSymbol), name, arity, options, binder, useSiteInfo)
                Else
                    Dim tempResult = lookupResult.GetInstance()
                    Lookup(lookupResult, DirectCast(container, TypeSymbol), name, arity, options, binder, tempResult, useSiteInfo)
                    tempResult.Free()
                End If
            End Sub
 
            ' Lookup all the names available on the given container, that match the given lookup options.
            ' The supplied binder is used for accessibility checking.
            Public Shared Sub AddLookupSymbolsInfo(nameSet As LookupSymbolsInfo,
                                                    container As NamespaceOrTypeSymbol,
                                                    options As LookupOptions,
                                                    binder As Binder)
                If container.IsNamespace Then
                    AddLookupSymbolsInfo(nameSet, DirectCast(container, NamespaceSymbol), options, binder)
                Else
                    AddLookupSymbolsInfo(nameSet, DirectCast(container, TypeSymbol), options, binder)
                End If
            End Sub
 
            ''' <summary>
            ''' Lookup a member name in a namespace, returning a LookupResult that
            ''' summarizes the results of the lookup. See LookupResult structure for a detailed
            ''' discussing of the meaning of the results. The supplied binder is used for accessibility
            ''' checked and base class suppression.
            ''' </summary>
            Public Shared Sub Lookup(lookupResult As LookupResult,
                                     container As NamespaceSymbol,
                                     name As String,
                                     arity As Integer,
                                     options As LookupOptions,
                                     binder As Binder,
                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
 
                Debug.Assert(lookupResult.IsClear)
 
                LookupImmediate(lookupResult, container, name, arity, options, binder, useSiteInfo)
 
                ' Result in the namespace takes precedence over results in containing modules.
                If lookupResult.StopFurtherLookup Then
                    Return
                End If
 
                Dim currentResult = lookupResult.GetInstance()
 
                LookupInModules(currentResult, container, name, arity, options, binder, useSiteInfo)
                lookupResult.MergeAmbiguous(currentResult, s_ambiguousInModuleError)
 
                currentResult.Free()
            End Sub
 
            ''' <summary>
            ''' Lookup an immediate (without descending into modules) member name in a namespace, 
            ''' returning a LookupResult that summarizes the results of the lookup. 
            ''' See LookupResult structure for a detailed discussion of the meaning of the results. 
            ''' The supplied binder is used for accessibility checks and base class suppression.
            ''' </summary>
            Public Shared Sub LookupImmediate(lookupResult As LookupResult,
                                     container As NamespaceSymbol,
                                     name As String,
                                     arity As Integer,
                                     options As LookupOptions,
                                     binder As Binder,
                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
 
                Debug.Assert(lookupResult.IsClear)
 
                Dim sourceModule = binder.Compilation.SourceModule
 
                ' Handle a case of being able to refer to System.Int32 through System.Integer.
                ' Same for other intrinsic types with intrinsic name different from emitted name.
                If (options And LookupOptions.AllowIntrinsicAliases) <> 0 AndAlso arity = 0 Then
                    Dim containingNs = container.ContainingNamespace
 
                    If containingNs IsNot Nothing AndAlso containingNs.IsGlobalNamespace AndAlso CaseInsensitiveComparison.Equals(container.Name, MetadataHelpers.SystemString) Then
                        Dim specialType = GetTypeForIntrinsicAlias(name)
 
                        If specialType <> specialType.None Then
                            Dim candidate = binder.Compilation.GetSpecialType(specialType)
 
                            ' Intrinsic alias works only if type is available
                            If Not candidate.IsErrorType() Then
                                lookupResult.MergeMembersOfTheSameNamespace(binder.CheckViability(candidate, arity, options, Nothing, useSiteInfo), sourceModule, options)
                            End If
                        End If
                    End If
                End If
 
#If DEBUG Then
                Dim haveSeenNamespace As Boolean = False
#End If
 
                For Each sym In container.GetMembers(name)
#If DEBUG Then
                    If sym.Kind = SymbolKind.Namespace Then
                        Debug.Assert(Not haveSeenNamespace, "Expected namespaces to be merged into a single symbol.")
                        haveSeenNamespace = True
                    End If
#End If
 
                    Dim currentResult As SingleLookupResult = binder.CheckViability(sym, arity, options, Nothing, useSiteInfo)
 
                    lookupResult.MergeMembersOfTheSameNamespace(currentResult, sourceModule, options)
                Next
            End Sub
 
            Public Shared Function GetTypeForIntrinsicAlias(possibleAlias As String) As SpecialType
                Dim aliasAsKeyword As SyntaxKind = SyntaxFacts.GetKeywordKind(possibleAlias)
 
                Select Case aliasAsKeyword
                    Case SyntaxKind.DateKeyword
                        Return SpecialType.System_DateTime
                    Case SyntaxKind.UShortKeyword
                        Return SpecialType.System_UInt16
                    Case SyntaxKind.ShortKeyword
                        Return SpecialType.System_Int16
                    Case SyntaxKind.UIntegerKeyword
                        Return SpecialType.System_UInt32
                    Case SyntaxKind.IntegerKeyword
                        Return SpecialType.System_Int32
                    Case SyntaxKind.ULongKeyword
                        Return SpecialType.System_UInt64
                    Case SyntaxKind.LongKeyword
                        Return SpecialType.System_Int64
                    Case Else
                        Return SpecialType.None
                End Select
            End Function
 
            ''' <summary>
            ''' Lookup a member name in modules of a namespace, 
            ''' returning a LookupResult that summarizes the results of the lookup. 
            ''' See LookupResult structure for a detailed discussion of the meaning of the results. 
            ''' The supplied binder is used for accessibility checks and base class suppression.
            ''' </summary>
            Public Shared Sub LookupInModules(lookupResult As LookupResult,
                                     container As NamespaceSymbol,
                                     name As String,
                                     arity As Integer,
                                     options As LookupOptions,
                                     binder As Binder,
                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
 
                Debug.Assert(lookupResult.IsClear)
                Dim firstModule As Boolean = True
                Dim sourceModule = binder.Compilation.SourceModule
 
                ' NOTE: while looking up the symbol in modules we should ignore base class
                options = options Or LookupOptions.IgnoreExtensionMethods Or LookupOptions.NoBaseClassLookup
                Dim currentResult As LookupResult = Nothing
                Dim tempResult = lookupResult.GetInstance()
 
                ' Next, do a lookup in each contained module and merge the results.
                For Each containedModule As NamedTypeSymbol In container.GetModuleMembers()
                    If firstModule Then
                        Lookup(lookupResult, containedModule, name, arity, options, binder, tempResult, useSiteInfo)
                        firstModule = False
                    Else
                        If currentResult Is Nothing Then
                            currentResult = lookupResult.GetInstance()
                        Else
                            currentResult.Clear()
                        End If
 
                        Lookup(currentResult, containedModule, name, arity, options, binder, tempResult, useSiteInfo)
 
                        ' Symbols in source take priority over symbols in a referenced assembly.
                        If currentResult.StopFurtherLookup AndAlso currentResult.Symbols.Count > 0 AndAlso
                           lookupResult.StopFurtherLookup AndAlso lookupResult.Symbols.Count > 0 Then
 
                            Dim currentFromSource = currentResult.Symbols(0).ContainingModule Is sourceModule
                            Dim contenderFromSource = lookupResult.Symbols(0).ContainingModule Is sourceModule
 
                            If currentFromSource Then
                                If Not contenderFromSource Then
                                    ' current is better
                                    lookupResult.SetFrom(currentResult)
                                    Continue For
                                End If
 
                            ElseIf contenderFromSource Then
                                ' contender is better
                                Continue For
                            End If
                        End If
 
                        lookupResult.MergeAmbiguous(currentResult, s_ambiguousInModuleError)
                    End If
                Next
 
                tempResult.Free()
                currentResult?.Free()
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfo(nameSet As LookupSymbolsInfo,
                                           container As NamespaceSymbol,
                                           options As LookupOptions,
                                           binder As Binder)
                ' Add names from the namespace
                For Each sym In container.GetMembersUnordered()
                    ' UNDONE: filter by options
                    If binder.CanAddLookupSymbolInfo(sym, options, nameSet, Nothing) Then
                        nameSet.AddSymbol(sym, sym.Name, sym.GetArity())
                    End If
                Next
 
                ' Next, add names from each contained module.
                For Each containedModule As NamedTypeSymbol In container.GetModuleMembers()
                    AddLookupSymbolsInfo(nameSet, containedModule, options, binder)
                Next
            End Sub
 
            ' Create a diagnostic for ambiguous names in multiple modules.
            Private Shared ReadOnly s_ambiguousInModuleError As Func(Of ImmutableArray(Of Symbol), AmbiguousSymbolDiagnostic) =
                Function(syms As ImmutableArray(Of Symbol)) As AmbiguousSymbolDiagnostic
                    Dim name As String = syms(0).Name
                    Dim deferredFormattedList As New FormattedSymbolList(syms.Select(Function(sym) sym.ContainingType))
 
                    Return New AmbiguousSymbolDiagnostic(ERRID.ERR_AmbiguousInModules2, syms, name, deferredFormattedList)
                End Function
 
            ''' <summary>
            ''' Lookup a member name in a type, returning a LookupResult that
            ''' summarizes the results of the lookup. See LookupResult structure for a detailed
            ''' discussing of the meaning of the results. The supplied binder is used for accessibility
            ''' checked and base class suppression.
            ''' </summary>
            Friend Shared Sub Lookup(lookupResult As LookupResult,
                                      type As TypeSymbol,
                                      name As String,
                                      arity As Integer,
                                      options As LookupOptions,
                                      binder As Binder,
                                      tempResult As LookupResult,
                                      <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                Debug.Assert(lookupResult.IsClear)
 
                Select Case type.TypeKind
                    Case TypeKind.Class, TypeKind.Module, TypeKind.Structure, TypeKind.Delegate, TypeKind.Array, TypeKind.Enum
                        LookupInClass(lookupResult, type, name, arity, options, type, binder, tempResult, useSiteInfo)
 
                    Case TypeKind.Submission
                        LookupInSubmissions(lookupResult, type, name, arity, options, binder, useSiteInfo)
 
                    Case TypeKind.Interface
                        LookupInInterface(lookupResult, DirectCast(type, NamedTypeSymbol), name, arity, options, binder, tempResult, useSiteInfo)
 
                    Case TypeKind.TypeParameter
                        LookupInTypeParameter(lookupResult, DirectCast(type, TypeParameterSymbol), name, arity, options, binder, tempResult, useSiteInfo)
 
                    Case TypeKind.Error
                        ' Error types have no members.
                        Return
 
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(type.TypeKind)
                End Select
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfo(nameSet As LookupSymbolsInfo,
                                                     container As TypeSymbol,
                                                     options As LookupOptions,
                                                     binder As Binder)
                Select Case container.TypeKind
                    Case TypeKind.Class, TypeKind.Structure, TypeKind.Delegate, TypeKind.Array, TypeKind.Enum
                        AddLookupSymbolsInfoInClass(nameSet, container, options, binder)
 
                    Case TypeKind.Module
                        AddLookupSymbolsInfoInClass(nameSet, container, options Or LookupOptions.NoBaseClassLookup, binder)
 
                    Case TypeKind.Submission
                        AddLookupSymbolsInfoInSubmissions(nameSet, container, options, binder)
 
                    Case TypeKind.Interface
                        AddLookupSymbolsInfoInInterface(nameSet, DirectCast(container, NamedTypeSymbol), options, binder)
 
                    Case TypeKind.TypeParameter
                        AddLookupSymbolsInfoInTypeParameter(nameSet, DirectCast(container, TypeParameterSymbol), options, binder)
 
                    Case TypeKind.Error
                        ' Error types have no members.
                        Return
 
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(container.TypeKind)
                End Select
            End Sub
 
            ''' <summary>
            ''' Lookup a member name in a module, class, struct, enum, or delegate, returning a LookupResult that
            ''' summarizes the results of the lookup. See LookupResult structure for a detailed
            ''' discussing of the meaning of the results. The supplied binder is used for accessibility
            ''' checks and base class suppression.
            ''' </summary>
            Private Shared Sub LookupInClass(result As LookupResult,
                                             container As TypeSymbol,
                                             name As String,
                                             arity As Integer,
                                             options As LookupOptions,
                                             accessThroughType As TypeSymbol,
                                             binder As Binder,
                                             tempResult As LookupResult,
                                             <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                Debug.Assert(result.IsClear)
 
                Dim methodsOnly As Boolean = CheckAndClearMethodsOnlyOption(options)
 
                ' Lookup proceeds up the base class chain.
                Dim currentType = container
 
                Do
                    tempResult.Clear()
                    Dim hitNonoverloadingSymbol As Boolean = False
 
                    LookupWithoutInheritance(tempResult, currentType, name, arity, options, accessThroughType, binder, useSiteInfo)
                    If result.IsGoodOrAmbiguous AndAlso tempResult.IsGoodOrAmbiguous AndAlso Not LookupResult.CanOverload(result.Symbols(0), tempResult.Symbols(0)) Then
                        ' We hit another good symbol that can't overload this one. That doesn't affect the lookup result, but means we have to stop
                        ' looking for more members. See bug #14078 for example.
                        hitNonoverloadingSymbol = True
                    End If
                    result.MergeOverloadedOrPrioritized(tempResult, True)
 
                    ' If the type is from a winmd file and implements any of the special WinRT collection
                    ' projections, then we may need to add projected interface members
                    Dim namedType = TryCast(currentType, NamedTypeSymbol)
                    If namedType IsNot Nothing AndAlso namedType.ShouldAddWinRTMembers Then
                        FindWinRTMembers(result,
                                         namedType,
                                         binder,
                                         tempResult,
                                         useSiteInfo,
                                         lookupMembersNotDefaultProperties:=True,
                                         name:=name,
                                         arity:=arity,
                                         options:=options)
                    End If
 
                    If hitNonoverloadingSymbol Then
                        Exit Do ' still do extension methods.
                    End If
 
                    If result.StopFurtherLookup Then
                        ' If we found a non-overloadable symbol, we can stop now. Note that even if we find a method without the Overloads
                        ' modifier, we cannot stop because we need to check for extension methods.
                        If result.HasSymbol Then
                            If Not result.Symbols.First.IsOverloadable Then
                                If methodsOnly Then
                                    Exit Do ' Need to look for extension methods.
                                End If
 
                                Return
                            End If
                        End If
                    End If
 
                    ' Go to base type, unless that would case infinite recursion or the options or the binder
                    ' disallows it.
                    If (options And LookupOptions.NoBaseClassLookup) <> 0 OrElse binder.IgnoreBaseClassesInLookup Then
                        currentType = Nothing
                    Else
                        currentType = currentType.GetDirectBaseTypeWithDefinitionUseSiteDiagnostics(binder.BasesBeingResolved, useSiteInfo)
                    End If
 
                    If currentType Is Nothing Then
                        Exit Do
                    End If
                Loop
 
                ClearLookupResultIfNotMethods(methodsOnly, result)
                LookupForExtensionMethodsIfNeedTo(result, container, name, arity, options, binder, tempResult, useSiteInfo)
            End Sub
 
            Public Delegate Sub WinRTLookupDelegate(iface As NamedTypeSymbol,
                                                     binder As Binder,
                                                     result As LookupResult,
                                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
 
            ''' <summary>
            ''' This function generalizes the idea of producing a set of non-conflicting
            ''' WinRT members of a given type based on the results of some arbitrary lookup
            ''' closure (which produces a LookupResult signifying success as IsGood).
            '''
            ''' A non-conflicting WinRT member lookup looks for all members of projected
            ''' WinRT interfaces which are implemented by a given type, discarding any 
            ''' which have equal signatures.
            ''' 
            ''' If <paramref name="lookupMembersNotDefaultProperties" /> is true then
            ''' this function lookups up members with the given <paramref name="name" />,
            ''' <paramref name="arity" />, and <paramref name="options" />. Otherwise, it looks for default properties.
            ''' </summary>
            Private Shared Sub FindWinRTMembers(result As LookupResult,
                                                type As NamedTypeSymbol,
                                                binder As Binder,
                                                tempResult As LookupResult,
                                                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol),
                                                lookupMembersNotDefaultProperties As Boolean,
                                                Optional name As String = Nothing,
                                                Optional arity As Integer = -1,
                                                Optional options As LookupOptions = Nothing)
                ' If we have no conflict with existing members, we also have to check
                ' if we have a conflict with other interface members. An example would be
                ' a type which implements both IIterable (IEnumerable) and IMap 
                ' (IDictionary).There are two different GetEnumerator methods from each
                ' interface. Thus, we don't know which method to choose. The solution?
                ' Don't add any GetEnumerator method.
 
                Dim comparer = MemberSignatureComparer.WinRTComparer
 
                Dim allMembers = New HashSet(Of Symbol)(comparer)
                Dim conflictingMembers = New HashSet(Of Symbol)(comparer)
 
                ' Add all viable members from type lookup
                If result.IsGood Then
                    For Each sym In result.Symbols
                        ' Fields can't be present in the HashSet because they can't be compared
                        ' with a MemberSignatureComparer
                        ' TODO: Add field support in the C# and VB member comparers and then
                        ' delete this check
                        If sym.Kind <> SymbolKind.Field Then
                            allMembers.Add(sym)
                        End If
                    Next
                End If
 
                Dim tmp = LookupResult.GetInstance()
 
                ' Dev11 searches all declared and undeclared base interfaces
                For Each iface In type.AllInterfacesWithDefinitionUseSiteDiagnostics(useSiteInfo)
                    If IsWinRTProjectedInterface(iface, binder.Compilation) Then
                        If lookupMembersNotDefaultProperties Then
                            Debug.Assert(name IsNot Nothing)
                            LookupWithoutInheritance(tmp,
                                                     iface,
                                                     name,
                                                     arity,
                                                     options,
                                                     iface,
                                                     binder,
                                                     useSiteInfo)
                        Else
                            LookupDefaultPropertyInSingleType(tmp,
                                                              iface,
                                                              iface,
                                                              binder,
                                                              tempResult,
                                                              useSiteInfo)
                        End If
                        ' only add viable members
                        If tmp.IsGood Then
                            For Each sym In tmp.Symbols
                                If Not allMembers.Add(sym) Then
                                    conflictingMembers.Add(sym)
                                End If
                            Next
                        End If
                        tmp.Clear()
                    End If
                Next
 
                tmp.Free()
                If result.IsGood Then
                    For Each sym In result.Symbols
                        If sym.Kind <> SymbolKind.Field Then
                            allMembers.Remove(sym)
                            conflictingMembers.Remove(sym)
                        End If
                    Next
                End If
 
                For Each sym In allMembers
                    If Not conflictingMembers.Contains(sym) Then
                        ' since we only added viable members, every lookupresult should be viable
                        result.MergeOverloadedOrPrioritized(
                            New SingleLookupResult(LookupResultKind.Good, sym, Nothing),
                            checkIfCurrentHasOverloads:=False)
                    End If
                Next
            End Sub
 
            Private Shared Function IsWinRTProjectedInterface(iFace As NamedTypeSymbol, compilation As VisualBasicCompilation) As Boolean
                Dim idictSymbol = compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IDictionary_KV)
                Dim iroDictSymbol = compilation.GetWellKnownType(WellKnownType.System_Collections_Generic_IReadOnlyDictionary_KV)
                Dim iListSymbol = compilation.GetWellKnownType(WellKnownType.System_Collections_IList)
                Dim iCollectionSymbol = compilation.GetWellKnownType(WellKnownType.System_Collections_ICollection)
                Dim inccSymbol = compilation.GetWellKnownType(WellKnownType.System_Collections_Specialized_INotifyCollectionChanged)
                Dim inpcSymbol = compilation.GetWellKnownType(WellKnownType.System_ComponentModel_INotifyPropertyChanged)
 
                Dim iFaceOriginal = iFace.OriginalDefinition
                Dim iFaceSpecial = iFaceOriginal.SpecialType
                ' Types match the list given in dev11 IMPORTER::GetWindowsRuntimeInterfacesToFake
                Return iFaceSpecial = SpecialType.System_Collections_Generic_IEnumerable_T OrElse
                       iFaceSpecial = SpecialType.System_Collections_Generic_IList_T OrElse
                       iFaceSpecial = SpecialType.System_Collections_Generic_ICollection_T OrElse
                       TypeSymbol.Equals(iFaceOriginal, idictSymbol, TypeCompareKind.ConsiderEverything) OrElse
                       iFaceSpecial = SpecialType.System_Collections_Generic_IReadOnlyList_T OrElse
                       iFaceSpecial = SpecialType.System_Collections_Generic_IReadOnlyCollection_T OrElse
                       TypeSymbol.Equals(iFaceOriginal, iroDictSymbol, TypeCompareKind.ConsiderEverything) OrElse
                       iFaceSpecial = SpecialType.System_Collections_IEnumerable OrElse
                       TypeSymbol.Equals(iFaceOriginal, iListSymbol, TypeCompareKind.ConsiderEverything) OrElse
                       TypeSymbol.Equals(iFaceOriginal, iCollectionSymbol, TypeCompareKind.ConsiderEverything) OrElse
                       TypeSymbol.Equals(iFaceOriginal, inccSymbol, TypeCompareKind.ConsiderEverything) OrElse
                       TypeSymbol.Equals(iFaceOriginal, inpcSymbol, TypeCompareKind.ConsiderEverything)
            End Function
 
            ''' <summary>
            ''' Lookup a member name in a submission chain.
            ''' </summary>
            ''' <remarks>
            ''' We start with the current submission class and walk the submission chain back to the first submission.
            ''' The search has two phases
            ''' 1) We are looking for any symbol matching the given name, arity, and options. If we don't find any the search is over.
            '''    If we find an overloadable symbol(s) (a method or a property) we start looking for overloads of this kind 
            '''    (lookingForOverloadsOfKind) of symbol in phase 2.
            ''' 2) If a visited submission contains a matching member of a kind different from lookingForOverloadsOfKind we stop 
            '''    looking further. Otherwise, if we find viable overload(s) we add them into the result. Overloads modifier is ignored.
            ''' </remarks>
            Private Shared Sub LookupInSubmissions(result As LookupResult,
                                                   submissionClass As TypeSymbol,
                                                   name As String,
                                                   arity As Integer,
                                                   options As LookupOptions,
                                                   binder As Binder,
                                                   <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                Debug.Assert(result.IsClear)
                Dim submissionSymbols = LookupResult.GetInstance()
                Dim nonViable = LookupResult.GetInstance()
                Dim lookingForOverloadsOfKind As SymbolKind? = Nothing
 
                Dim submission = binder.Compilation
                Do
                    submissionSymbols.Clear()
 
                    If submission.ScriptClass IsNot Nothing Then
                        LookupWithoutInheritance(submissionSymbols, submission.ScriptClass, name, arity, options, submissionClass, binder, useSiteInfo)
                    End If
 
                    ' TODO (tomat): import aliases
 
                    If lookingForOverloadsOfKind Is Nothing Then
                        If Not submissionSymbols.IsGoodOrAmbiguous Then
                            ' skip non-viable members, but remember them in case no viable members are found in previous submissions:
                            nonViable.MergePrioritized(submissionSymbols)
 
                            submission = submission.PreviousSubmission
                            Continue Do
                        End If
 
                        ' always overload (ignore Overloads modifier):
                        result.MergeOverloadedOrPrioritized(submissionSymbols, checkIfCurrentHasOverloads:=False)
 
                        Dim first = submissionSymbols.Symbols.First
                        If Not first.IsOverloadable Then
                            Exit Do
                        End If
 
                        ' we are now looking for any kind of member regardless of the original binding restrictions:
                        options = options And Not LookupOptions.NamespacesOrTypesOnly
                        lookingForOverloadsOfKind = first.Kind
                    Else
                        ' found a member we are not looking for - the overload set is final now
                        If submissionSymbols.HasSymbol AndAlso submissionSymbols.Symbols.First.Kind <> lookingForOverloadsOfKind.Value Then
                            Exit Do
                        End If
 
                        ' found a viable overload
                        If submissionSymbols.IsGoodOrAmbiguous Then
                            ' merge overloads
                            Debug.Assert(result.Symbols.All(Function(s) s.IsOverloadable))
 
                            ' always overload (ignore Overloads modifier):
                            result.MergeOverloadedOrPrioritized(submissionSymbols, checkIfCurrentHasOverloads:=False)
                        End If
                    End If
 
                    submission = submission.PreviousSubmission
                Loop Until submission Is Nothing
 
                If Not result.HasSymbol Then
                    result.SetFrom(nonViable)
                End If
 
                ' TODO (tomat): extension methods
 
                submissionSymbols.Free()
                nonViable.Free()
            End Sub
 
            Public Shared Sub LookupDefaultProperty(result As LookupResult, container As TypeSymbol, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                Select Case container.TypeKind
                    Case TypeKind.Class, TypeKind.Module, TypeKind.Structure
                        Dim tempResult = LookupResult.GetInstance()
                        LookupDefaultPropertyInClass(result, DirectCast(container, NamedTypeSymbol), binder, tempResult, useSiteInfo)
                        tempResult.Free()
 
                    Case TypeKind.Interface
                        Dim tempResult = LookupResult.GetInstance()
                        LookupDefaultPropertyInInterface(result, DirectCast(container, NamedTypeSymbol), binder, tempResult, useSiteInfo)
                        tempResult.Free()
 
                    Case TypeKind.TypeParameter
                        Dim tempResult = LookupResult.GetInstance()
                        LookupDefaultPropertyInTypeParameter(result, DirectCast(container, TypeParameterSymbol), binder, tempResult, useSiteInfo)
                        tempResult.Free()
                End Select
            End Sub
 
            Private Shared Sub LookupDefaultPropertyInClass(
                result As LookupResult,
                type As NamedTypeSymbol,
                binder As Binder,
                tempResult As LookupResult,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Debug.Assert(type.IsClassType OrElse type.IsModuleType OrElse type.IsStructureType OrElse type.IsDelegateType)
                Dim accessThroughType As NamedTypeSymbol = type
 
                While type IsNot Nothing
                    If LookupDefaultPropertyInSingleType(result, type, accessThroughType, binder, tempResult, useSiteInfo) Then
                        Return
                    End If
 
                    ' If this is a WinRT type, we should also look for default properties in the
                    ' implemented projected interfaces
                    If type.ShouldAddWinRTMembers Then
                        FindWinRTMembers(result,
                                         type,
                                         binder,
                                         tempResult,
                                         useSiteInfo,
                                         lookupMembersNotDefaultProperties:=False)
                        If result.IsGood Then
                            Return
                        End If
                    End If
 
                    type = type.BaseTypeWithDefinitionUseSiteDiagnostics(useSiteInfo)
                End While
 
            End Sub
 
            ' See Semantics::LookupDefaultPropertyInInterface.
            Private Shared Sub LookupDefaultPropertyInInterface(
                result As LookupResult,
                [interface] As NamedTypeSymbol,
                binder As Binder,
                tempResult As LookupResult,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Debug.Assert([interface].IsInterfaceType)
 
                If LookupDefaultPropertyInSingleType(result, [interface], [interface], binder, tempResult, useSiteInfo) Then
                    Return
                End If
 
                For Each baseInterface In [interface].InterfacesNoUseSiteDiagnostics
                    baseInterface.OriginalDefinition.AddUseSiteInfo(useSiteInfo)
 
                    LookupDefaultPropertyInBaseInterface(result, baseInterface, binder, tempResult, useSiteInfo)
                    If result.HasDiagnostic Then
                        Return
                    End If
                Next
            End Sub
 
            Private Shared Sub LookupDefaultPropertyInTypeParameter(
                    result As LookupResult,
                    typeParameter As TypeParameterSymbol,
                    binder As Binder,
                    tempResult As LookupResult,
                    <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                ' Look up in class constraint.
                Dim constraintClass = typeParameter.GetClassConstraint(useSiteInfo)
                If constraintClass IsNot Nothing Then
                    LookupDefaultPropertyInClass(result, constraintClass, binder, tempResult, useSiteInfo)
                    If Not result.IsClear Then
                        Return
                    End If
                End If
 
                ' Look up in interface constraints.
                Dim lookIn As Queue(Of InterfaceInfo) = Nothing
                Dim processed As HashSet(Of InterfaceInfo) = Nothing
                AddInterfaceConstraints(typeParameter, lookIn, processed, useSiteInfo)
 
                If lookIn IsNot Nothing Then
                    For Each baseInterface In lookIn
                        LookupDefaultPropertyInBaseInterface(result, baseInterface.InterfaceType, binder, tempResult, useSiteInfo)
                        If result.HasDiagnostic Then
                            Return
                        End If
                    Next
                End If
            End Sub
 
            ' See Semantics::LookupDefaultPropertyInBaseInterface.
            Private Shared Sub LookupDefaultPropertyInBaseInterface(
                result As LookupResult,
                type As NamedTypeSymbol,
                binder As Binder,
                tempResult As LookupResult,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                If type.IsErrorType() Then
                    Return
                End If
 
                Debug.Assert(type.IsInterfaceType)
                Debug.Assert(Not result.HasDiagnostic)
 
                Dim tmpResult = LookupResult.GetInstance()
                Try
                    LookupDefaultPropertyInInterface(tmpResult, type, binder, tempResult, useSiteInfo)
 
                    If Not tmpResult.HasSymbol Then
                        Return
                    End If
 
                    If tmpResult.HasDiagnostic OrElse Not result.HasSymbol Then
                        result.SetFrom(tmpResult)
                        Return
                    End If
 
                    ' At least one member was found on another interface.
                    ' Report an ambiguity error if the two interfaces are distinct.
                    Dim symbolA = result.Symbols(0)
                    Dim symbolB = tmpResult.Symbols(0)
 
                    If symbolA.ContainingSymbol <> symbolB.ContainingSymbol Then
                        result.MergeAmbiguous(tmpResult, AddressOf GenerateAmbiguousDefaultPropertyDiagnostic)
                    End If
                Finally
                    tmpResult.Free()
                End Try
            End Sub
 
            ' Return True if a default property is defined on the type.
            Private Shared Function LookupDefaultPropertyInSingleType(
                result As LookupResult,
                type As NamedTypeSymbol,
                accessThroughType As TypeSymbol,
                binder As Binder,
                tempResult As LookupResult,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            ) As Boolean
                Dim defaultPropertyName = type.DefaultPropertyName
                If String.IsNullOrEmpty(defaultPropertyName) Then
                    Return False
                End If
 
                Select Case type.TypeKind
                    Case TypeKind.Class, TypeKind.Module, TypeKind.Structure
                        LookupInClass(
                            result,
                            type,
                            defaultPropertyName,
                            arity:=0,
                            options:=LookupOptions.Default,
                            accessThroughType:=accessThroughType,
                            binder:=binder,
                            tempResult:=tempResult,
                            useSiteInfo:=useSiteInfo)
 
                    Case TypeKind.Interface
                        Debug.Assert(accessThroughType Is type)
                        LookupInInterface(
                            result,
                            type,
                            defaultPropertyName,
                            arity:=0,
                            options:=LookupOptions.Default,
                            binder:=binder,
                            tempResult:=tempResult,
                            useSiteInfo:=useSiteInfo)
 
                    Case TypeKind.TypeParameter
                        Throw ExceptionUtilities.UnexpectedValue(type.TypeKind)
                End Select
 
                Return result.HasSymbol
            End Function
 
            Private Shared Function GenerateAmbiguousDefaultPropertyDiagnostic(symbols As ImmutableArray(Of Symbol)) As AmbiguousSymbolDiagnostic
                Debug.Assert(symbols.Length > 1)
 
                Dim symbolA = symbols(0)
                Dim containingSymbolA = symbolA.ContainingSymbol
 
                For i = 1 To symbols.Length - 1
                    Dim symbolB = symbols(i)
                    Dim containingSymbolB = symbolB.ContainingSymbol
 
                    If containingSymbolA <> containingSymbolB Then
                        ' "Default property access is ambiguous between the inherited interface members '{0}' of interface '{1}' and '{2}' of interface '{3}'."
                        Return New AmbiguousSymbolDiagnostic(ERRID.ERR_DefaultPropertyAmbiguousAcrossInterfaces4, symbols, symbolA, containingSymbolA, symbolB, containingSymbolB)
                    End If
                Next
 
                ' Expected ambiguous symbols
                Throw ExceptionUtilities.Unreachable
            End Function
 
            Private Shared Sub LookupForExtensionMethodsIfNeedTo(
                result As LookupResult,
                container As TypeSymbol,
                name As String,
                arity As Integer,
                options As LookupOptions,
                binder As Binder,
                tempResult As LookupResult,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                If result.IsGood AndAlso
                    ((options And LookupOptions.EagerlyLookupExtensionMethods) = 0 OrElse
                     result.Symbols(0).Kind <> SymbolKind.Method) Then
                    Return
                End If
 
                tempResult.Clear()
                LookupForExtensionMethods(tempResult, container, name, arity, options, binder, useSiteInfo)
                MergeInternalXmlHelperValueIfNecessary(tempResult, container, name, arity, options, binder, useSiteInfo)
                result.MergeOverloadedOrPrioritized(tempResult, checkIfCurrentHasOverloads:=False)
            End Sub
 
            Private Shared Function ShouldLookupExtensionMethods(options As LookupOptions, container As TypeSymbol) As Boolean
                Return options.ShouldLookupExtensionMethods AndAlso
                   Not container.IsObjectType() AndAlso
                   Not container.IsShared AndAlso
                   Not container.IsModuleType()
            End Function
 
            Public Shared Sub LookupForExtensionMethods(
                lookupResult As LookupResult,
                container As TypeSymbol,
                name As String,
                arity As Integer,
                options As LookupOptions,
                binder As Binder,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Debug.Assert(lookupResult.IsClear)
 
                If Not ShouldLookupExtensionMethods(options, container) Then
                    lookupResult.SetFrom(SingleLookupResult.Empty)
                    Return
                End If
 
                ' Proceed up the chain of binders, collecting extension methods
                Dim originalBinder = binder
                Dim currentBinder = binder
 
                Dim methods = ArrayBuilder(Of MethodSymbol).GetInstance()
                Dim proximity As Integer = 0
 
                ' We don't want to process the same methods more than once, but the same extension method 
                ' might be in scope in several different binders. For example, within a type, within
                ' imported the same type, within imported namespace containing the type. 
                ' So, taking into consideration the fact that CollectProbableExtensionMethodsInSingleBinder 
                ' groups methods from the same containing type together, we will keep track of the types and
                ' will process all the methods from the same containing type at once.
                Dim seenContainingTypes As New HashSet(Of NamedTypeSymbol)()
 
                Do
                    methods.Clear()
                    currentBinder.CollectProbableExtensionMethodsInSingleBinder(name, methods, originalBinder)
 
                    Dim i As Integer = 0
                    Dim count As Integer = methods.Count
 
                    While i < count
                        Dim containingType As NamedTypeSymbol = methods(i).ContainingType
 
                        If seenContainingTypes.Add(containingType) AndAlso
                           ((options And LookupOptions.IgnoreAccessibility) <> 0 OrElse
                            AccessCheck.IsSymbolAccessible(containingType, binder.Compilation.Assembly, useSiteInfo)) Then
 
                            ' Process all methods from the same type together.
                            Do
                                ' Try to reduce this method and merge with the current result
                                Dim reduced As MethodSymbol = methods(i).ReduceExtensionMethod(container, proximity, useSiteInfo, binder.Compilation.LanguageVersion)
 
                                If reduced IsNot Nothing Then
                                    lookupResult.MergeOverloadedOrPrioritizedExtensionMethods(binder.CheckViability(reduced, arity, options, reduced.ContainingType, useSiteInfo))
                                End If
 
                                i += 1
                            Loop While i < count AndAlso containingType Is methods(i).ContainingSymbol
                        Else
                            ' We already processed extension methods from this container before or the whole container is not accessible,
                            ' skip the whole group of methods from this containing type.
                            Do
                                i += 1
                            Loop While i < count AndAlso containingType Is methods(i).ContainingSymbol
                        End If
                    End While
 
                    ' Continue to containing binders.
                    proximity += 1
                    currentBinder = currentBinder.m_containingBinder
                Loop While currentBinder IsNot Nothing
 
                methods.Free()
            End Sub
 
            ''' <summary>
            ''' Include the InternalXmlHelper.Value extension property in the LookupResult
            ''' if the container implements IEnumerable(Of XElement), the name is "Value",
            ''' and the arity is 0.
            ''' </summary>
            Private Shared Sub MergeInternalXmlHelperValueIfNecessary(
                lookupResult As LookupResult,
                container As TypeSymbol,
                name As String,
                arity As Integer,
                options As LookupOptions,
                binder As Binder,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
 
                If (arity <> 0) OrElse Not IdentifierComparison.Equals(name, StringConstants.ValueProperty) Then
                    Return
                End If
 
                Dim compilation = binder.Compilation
                If (options And LookupOptions.NamespacesOrTypesOnly) <> 0 OrElse
                   Not container.IsOrImplementsIEnumerableOfXElement(compilation, useSiteInfo) Then
                    Return
                End If
 
                Dim symbol = binder.GetInternalXmlHelperValueExtensionProperty()
                Dim singleResult As SingleLookupResult
                If symbol Is Nothing Then
                    ' Match the native compiler which reports ERR_XmlFeaturesNotAvailable in this case.
                    Dim useSiteError = ErrorFactory.ErrorInfo(ERRID.ERR_XmlFeaturesNotAvailable)
                    singleResult = New SingleLookupResult(LookupResultKind.NotReferencable, binder.GetErrorSymbol(name, useSiteError), useSiteError)
                Else
                    Dim reduced = New ReducedExtensionPropertySymbol(DirectCast(symbol, PropertySymbol))
                    singleResult = binder.CheckViability(reduced, arity, options, reduced.ContainingType, useSiteInfo)
                End If
 
                lookupResult.MergePrioritized(singleResult)
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfoOfExtensionMethods(nameSet As LookupSymbolsInfo,
                                                               container As TypeSymbol,
                                                               newInfo As LookupSymbolsInfo,
                                                               binder As Binder)
                Dim lookup = LookupResult.GetInstance()
 
                For Each name In newInfo.Names
                    lookup.Clear()
 
                    LookupForExtensionMethods(lookup, container, name, 0,
                                              LookupOptions.AllMethodsOfAnyArity Or LookupOptions.IgnoreAccessibility,
                                              binder, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
 
                    If lookup.IsGood Then
                        For Each method As MethodSymbol In lookup.Symbols
                            nameSet.AddSymbol(method, method.Name, method.Arity)
                        Next
                    End If
                Next
 
                lookup.Free()
            End Sub
 
            Public Shared Sub AddExtensionMethodLookupSymbolsInfo(nameSet As LookupSymbolsInfo,
                                                                   container As TypeSymbol,
                                                                   options As LookupOptions,
                                                                   binder As Binder)
                If Not ShouldLookupExtensionMethods(options, container) Then
                    Return
                End If
 
                ' We will not reduce extension methods for the purpose of this operation,
                ' they will still be shared methods.
                options = options And (Not Global.Microsoft.CodeAnalysis.VisualBasic.LookupOptions.MustBeInstance)
 
                ' Proceed up the chain of binders, collecting names of extension methods
                Dim currentBinder As Binder = binder
 
                Dim newInfo = LookupSymbolsInfo.GetInstance()
 
                Do
                    currentBinder.AddExtensionMethodLookupSymbolsInfoInSingleBinder(newInfo, options, binder)
 
                    ' Continue to containing binders.
                    currentBinder = currentBinder.m_containingBinder
                Loop While currentBinder IsNot Nothing
 
                AddLookupSymbolsInfoOfExtensionMethods(nameSet, container, newInfo, binder)
 
                newInfo.Free()
 
                ' Include "Value" for InternalXmlHelper.Value if necessary.
                Dim compilation = binder.Compilation
                Dim useSiteInfo = CompoundUseSiteInfo(Of AssemblySymbol).DiscardedDependencies
                If container.IsOrImplementsIEnumerableOfXElement(compilation, useSiteInfo) AndAlso useSiteInfo.Diagnostics.IsNullOrEmpty Then
                    nameSet.AddSymbol(Nothing, StringConstants.ValueProperty, 0)
                End If
            End Sub
 
            ''' <summary>
            ''' Checks if two interfaces have a base-derived relationship
            ''' </summary>
            Private Shared Function IsDerivedInterface(
                        base As NamedTypeSymbol,
                        derived As NamedTypeSymbol,
                        basesBeingResolved As BasesBeingResolved,
                        <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            ) As Boolean
 
                Debug.Assert(base.IsInterface)
                Debug.Assert(derived.IsInterface)
 
                If TypeSymbol.Equals(derived.OriginalDefinition, base.OriginalDefinition, TypeCompareKind.ConsiderEverything) Then
                    Return False
                End If
 
                ' if we are not resolving bases we can just go through AllInterfaces list
                If basesBeingResolved.InheritsBeingResolvedOpt Is Nothing Then
                    For Each i In derived.AllInterfacesWithDefinitionUseSiteDiagnostics(useSiteInfo)
                        If TypeSymbol.Equals(i, base, TypeCompareKind.ConsiderEverything) Then
                            Return True
                        End If
                    Next
 
                    Return False
                End If
 
                ' we are resolving bases so should use a private helper that relies only on Declared interfaces
                Return IsDerivedInterface(base, derived, basesBeingResolved, New HashSet(Of Symbol), useSiteInfo)
            End Function
 
            Private Shared Function IsDerivedInterface(
                        base As NamedTypeSymbol,
                        derived As NamedTypeSymbol,
                        basesBeingResolved As BasesBeingResolved,
                        verified As HashSet(Of Symbol),
                        <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            ) As Boolean
 
                Debug.Assert(Not TypeSymbol.Equals(base, derived, TypeCompareKind.ConsiderEverything), "should already be verified for equality")
                Debug.Assert(base.IsInterface)
                Debug.Assert(derived.IsInterface)
 
                verified.Add(derived)
 
                ' not afraid of cycles here as we will not verify same symbol twice
                Dim interfaces = derived.GetDeclaredInterfacesWithDefinitionUseSiteDiagnostics(basesBeingResolved, useSiteInfo)
 
                If Not interfaces.IsDefaultOrEmpty Then
                    For Each i In interfaces
                        If TypeSymbol.Equals(i, base, TypeCompareKind.ConsiderEverything) Then
                            Return True
                        End If
 
                        If verified.Contains(i) Then
                            ' seen this already
                            Continue For
                        End If
 
                        If IsDerivedInterface(
                            base,
                            i,
                            basesBeingResolved,
                            verified,
                            useSiteInfo) Then
 
                            Return True
                        End If
                    Next
                End If
 
                Return False
            End Function
 
            Private Structure InterfaceInfo
                Implements IEquatable(Of InterfaceInfo)
 
                Public ReadOnly InterfaceType As NamedTypeSymbol
                Public ReadOnly InComInterfaceContext As Boolean
                Public ReadOnly DescendantDefinitions As ImmutableHashSet(Of NamedTypeSymbol)
 
                Public Sub New(interfaceType As NamedTypeSymbol, inComInterfaceContext As Boolean, Optional descendantDefinitions As ImmutableHashSet(Of NamedTypeSymbol) = Nothing)
                    Me.InterfaceType = interfaceType
                    Me.InComInterfaceContext = inComInterfaceContext
                    Me.DescendantDefinitions = descendantDefinitions
                End Sub
 
                Public Overrides Function GetHashCode() As Integer
                    Return Hash.Combine(Me.InterfaceType.GetHashCode(), Me.InComInterfaceContext.GetHashCode())
                End Function
 
                Public Overloads Overrides Function Equals(obj As Object) As Boolean
                    Return TypeOf obj Is InterfaceInfo AndAlso Equals(DirectCast(obj, InterfaceInfo))
                End Function
 
                Public Overloads Function Equals(other As InterfaceInfo) As Boolean Implements IEquatable(Of InterfaceInfo).Equals
                    Return Me.InterfaceType.Equals(other.InterfaceType) AndAlso Me.InComInterfaceContext = other.InComInterfaceContext
                End Function
            End Structure
 
            Private Shared Sub LookupInInterface(lookupResult As LookupResult,
                         container As NamedTypeSymbol,
                         name As String,
                         arity As Integer,
                         options As LookupOptions,
                         binder As Binder,
                         tempResult As LookupResult,
                         <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Debug.Assert(lookupResult.IsClear)
 
                Dim methodsOnly As Boolean = CheckAndClearMethodsOnlyOption(options)
 
                ' look in these types. Start with container, add more accordingly.
                Dim info As New InterfaceInfo(container, False)
 
                Dim lookIn As New Queue(Of InterfaceInfo)
                lookIn.Enqueue(info)
 
                Dim processed As New HashSet(Of InterfaceInfo)
                processed.Add(info)
 
                LookupInInterfaces(lookupResult, container, lookIn, processed, name, arity, options, binder, methodsOnly, useSiteInfo)
 
                ' If no viable or ambiguous results, look in Object.
                If Not lookupResult.IsGoodOrAmbiguous AndAlso (options And LookupOptions.NoSystemObjectLookupForInterfaces) = 0 Then
                    Dim currentResult = lookupResult.GetInstance()
                    Dim obj As NamedTypeSymbol = binder.SourceModule.ContainingAssembly.GetSpecialType(SpecialType.System_Object)
 
                    LookupInClass(currentResult,
                                  obj,
                                  name, arity, options Or LookupOptions.IgnoreExtensionMethods, obj, binder,
                                  tempResult,
                                  useSiteInfo)
 
                    If currentResult.IsGood Then
                        lookupResult.SetFrom(currentResult)
                    End If
 
                    currentResult.Free()
                End If
 
                ClearLookupResultIfNotMethods(methodsOnly, lookupResult)
                LookupForExtensionMethodsIfNeedTo(lookupResult, container, name, arity, options, binder, tempResult, useSiteInfo)
                Return
            End Sub
 
            Private Shared Sub LookupInInterfaces(lookupResult As LookupResult,
                         container As TypeSymbol,
                         lookIn As Queue(Of InterfaceInfo),
                         processed As HashSet(Of InterfaceInfo),
                         name As String,
                         arity As Integer,
                         options As LookupOptions,
                         binder As Binder,
                         methodsOnly As Boolean,
                         <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Debug.Assert(lookupResult.IsClear)
 
                Dim basesBeingResolved As BasesBeingResolved = binder.BasesBeingResolved()
 
                Dim isEventsOnlySpecified As Boolean = (options And LookupOptions.EventsOnly) <> 0
 
                Dim currentResult = lookupResult.GetInstance()
                Do
                    Dim info As InterfaceInfo = lookIn.Dequeue()
                    Debug.Assert(processed.Contains(info))
 
                    Debug.Assert(currentResult.IsClear)
                    LookupWithoutInheritance(currentResult, info.InterfaceType, name, arity, options, container, binder, useSiteInfo)
 
                    ' if result does not shadow we will have bases to visit
                    If Not (currentResult.StopFurtherLookup AndAlso AnyShadows(currentResult)) Then
                        If (options And LookupOptions.NoBaseClassLookup) = 0 AndAlso Not binder.IgnoreBaseClassesInLookup Then
                            AddBaseInterfacesToTheSearch(binder, info, lookIn, processed, useSiteInfo)
                        End If
                    End If
 
                    Dim leaveEventsOnly As Boolean? = Nothing
                    If info.InComInterfaceContext Then
                        leaveEventsOnly = isEventsOnlySpecified
                    End If
 
                    If lookupResult.IsGood AndAlso currentResult.IsGood Then
                        ' We have _another_ viable result while lookupResult is already viable. Use special interface merging rules.
                        MergeInterfaceLookupResults(lookupResult, currentResult, basesBeingResolved, leaveEventsOnly, useSiteInfo)
                    Else
                        If currentResult.IsGood AndAlso leaveEventsOnly.HasValue Then
                            FilterSymbolsInLookupResult(currentResult, SymbolKind.Event, leaveInsteadOfRemoving:=leaveEventsOnly.Value)
                        End If
                        lookupResult.MergePrioritized(currentResult)
                    End If
                    currentResult.Clear()
 
                Loop While lookIn.Count <> 0
 
                currentResult.Free()
 
                If methodsOnly AndAlso lookupResult.IsGood Then
                    ' We need to filter out non-method symbols from 'currentResult' 
                    ' before merging with 'lookupResult'
                    FilterSymbolsInLookupResult(lookupResult, SymbolKind.Method, leaveInsteadOfRemoving:=True)
                End If
 
                ' it may look like a Good result, but it may have ambiguities inside
                ' so we need to check that to be sure.
                If lookupResult.IsGood Then
                    Dim ambiguityDiagnostics As AmbiguousSymbolDiagnostic = Nothing
                    Dim symbols As ArrayBuilder(Of Symbol) = lookupResult.Symbols
 
                    For i As Integer = 0 To symbols.Count - 2
                        Dim interface1 = DirectCast(symbols(i).ContainingType, NamedTypeSymbol)
 
                        For j As Integer = i + 1 To symbols.Count - 1
 
                            If Not lookupResult.CanOverload(symbols(i), symbols(j)) Then
                                ' Symbols cannot overload each other.
                                ' If they were from the same interface, LookupWithoutInheritance would make the result ambiguous.
                                ' If they were from interfaces related through inheritance, one of them would shadow another,
                                ' MergeInterfaceLookupResults handles that.
                                ' Therefore, this symbols are from unrelated interfaces.
                                ambiguityDiagnostics = New AmbiguousSymbolDiagnostic(
                                            ERRID.ERR_AmbiguousAcrossInterfaces3,
                                            symbols.ToImmutable,
                                            name,
                                            CustomSymbolDisplayFormatter.DefaultErrorFormat(symbols(i).ContainingType),
                                            CustomSymbolDisplayFormatter.DefaultErrorFormat(symbols(j).ContainingType))
 
                                GoTo ExitForFor
                            End If
                        Next
                    Next
ExitForFor:
                    If ambiguityDiagnostics IsNot Nothing Then
                        lookupResult.SetFrom(New SingleLookupResult(LookupResultKind.Ambiguous, symbols.First, ambiguityDiagnostics))
                    End If
                End If
            End Sub
 
            Private Shared Sub FilterSymbolsInLookupResult(result As LookupResult, kind As SymbolKind, leaveInsteadOfRemoving As Boolean)
                Debug.Assert(result.IsGood)
 
                Dim resultSymbols As ArrayBuilder(Of Symbol) = result.Symbols
                Debug.Assert(resultSymbols.Count > 0)
 
                Dim i As Integer = 0
                Dim j As Integer = 0
                While j < resultSymbols.Count
                    Dim symbol As Symbol = resultSymbols(j)
                    If (symbol.Kind = kind) = leaveInsteadOfRemoving Then
                        resultSymbols(i) = resultSymbols(j)
                        i += 1
                    End If
                    j += 1
                End While
 
                resultSymbols.Clip(i)
                If i = 0 Then
                    result.Clear()
                End If
            End Sub
 
            Private Shared Sub LookupInTypeParameter(lookupResult As LookupResult,
                         typeParameter As TypeParameterSymbol,
                         name As String,
                         arity As Integer,
                         options As LookupOptions,
                         binder As Binder,
                         tempResult As LookupResult,
                         <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
 
                Dim methodsOnly = CheckAndClearMethodsOnlyOption(options)
                LookupInTypeParameterNoExtensionMethods(lookupResult, typeParameter, name, arity, options, binder, tempResult, useSiteInfo)
 
                ClearLookupResultIfNotMethods(methodsOnly, lookupResult)
                LookupForExtensionMethodsIfNeedTo(lookupResult, typeParameter, name, arity, options, binder, tempResult, useSiteInfo)
            End Sub
 
            Private Shared Sub LookupInTypeParameterNoExtensionMethods(result As LookupResult,
                         typeParameter As TypeParameterSymbol,
                         name As String,
                         arity As Integer,
                         options As LookupOptions,
                         binder As Binder,
                         tempResult As LookupResult,
                         <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
                Debug.Assert((options And LookupOptions.MethodsOnly) = 0)
 
                options = options Or LookupOptions.IgnoreExtensionMethods
 
                ' §4.9.2: "the class constraint hides members in interface constraints, which
                ' hide members in System.ValueType (if Structure constraint is specified),
                ' which hides members in Object."
 
                ' Look up in class constraint.
                Dim constraintClass = typeParameter.GetClassConstraint(useSiteInfo)
                If constraintClass IsNot Nothing Then
                    LookupInClass(result, constraintClass, name, arity, options, constraintClass, binder, tempResult, useSiteInfo)
                    If result.StopFurtherLookup Then
                        Return
                    End If
                End If
 
                ' Look up in interface constraints.
                Dim lookIn As Queue(Of InterfaceInfo) = Nothing
                Dim processed As HashSet(Of InterfaceInfo) = Nothing
                AddInterfaceConstraints(typeParameter, lookIn, processed, useSiteInfo)
 
                If lookIn IsNot Nothing Then
                    ' §4.9.2: "If a member with the same name appears in more than one interface
                    ' constraint the member is unavailable (as in multiple interface inheritance)"
                    Dim interfaceResult = LookupResult.GetInstance()
                    Debug.Assert((options And LookupOptions.MethodsOnly) = 0)
                    LookupInInterfaces(interfaceResult, typeParameter, lookIn, processed, name, arity, options, binder, False, useSiteInfo)
                    result.MergePrioritized(interfaceResult)
                    interfaceResult.Free()
                    If Not result.IsClear Then
                        Return
                    End If
                End If
 
                ' Look up in System.ValueType or System.Object.
                If constraintClass Is Nothing Then
                    Debug.Assert(result.IsClear)
                    Dim baseType = GetTypeParameterBaseType(typeParameter)
                    LookupInClass(result, baseType, name, arity, options, baseType, binder, tempResult, useSiteInfo)
                End If
            End Sub
 
            Private Shared Function CheckAndClearMethodsOnlyOption(ByRef options As LookupOptions) As Boolean
                If (options And LookupOptions.MethodsOnly) <> 0 Then
                    options = CType(options And (Not LookupOptions.MethodsOnly), LookupOptions)
                    Return True
                End If
                Return False
            End Function
 
            Private Shared Sub ClearLookupResultIfNotMethods(methodsOnly As Boolean, lookupResult As LookupResult)
                If methodsOnly AndAlso
                   lookupResult.HasSymbol AndAlso
                   lookupResult.Symbols(0).Kind <> SymbolKind.Method Then
                    lookupResult.Clear()
                End If
            End Sub
 
            Private Shared Sub AddInterfaceConstraints(typeParameter As TypeParameterSymbol,
                                                       ByRef allInterfaces As Queue(Of InterfaceInfo),
                                                       ByRef processedInterfaces As HashSet(Of InterfaceInfo),
                                                       <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                For Each constraintType In typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(useSiteInfo)
                    Select Case constraintType.TypeKind
                        Case TypeKind.Interface
                            Dim newInfo As New InterfaceInfo(DirectCast(constraintType, NamedTypeSymbol), False)
 
                            If processedInterfaces Is Nothing OrElse Not processedInterfaces.Contains(newInfo) Then
                                If processedInterfaces Is Nothing Then
                                    allInterfaces = New Queue(Of InterfaceInfo)
                                    processedInterfaces = New HashSet(Of InterfaceInfo)
                                End If
 
                                allInterfaces.Enqueue(newInfo)
                                processedInterfaces.Add(newInfo)
                            End If
 
                        Case TypeKind.TypeParameter
                            AddInterfaceConstraints(DirectCast(constraintType, TypeParameterSymbol), allInterfaces, processedInterfaces, useSiteInfo)
                    End Select
                Next
            End Sub
 
            ''' <summary>
            ''' Merges two lookup results while eliminating symbols that are shadowed.
            ''' Note that the final result may contain unrelated and possibly conflicting symbols as
            ''' this helper is not intended to catch ambiguities.
            ''' </summary>
            ''' <param name="leaveEventsOnly">
            ''' If is not Nothing and False filters out all Event symbols, and if is not Nothing 
            ''' and True filters out all non-Event symbols, nos not have any effect otherwise.
            ''' Is used for special handling of Events inside COM interfaces.
            ''' </param>
            Private Shared Sub MergeInterfaceLookupResults(
                                        knownResult As LookupResult,
                                        newResult As LookupResult,
                                        BasesBeingResolved As BasesBeingResolved,
                                        leaveEventsOnly As Boolean?,
                                        <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
 
                Debug.Assert(knownResult.Kind = newResult.Kind)
 
                Dim knownSymbols As ArrayBuilder(Of Symbol) = knownResult.Symbols
                Dim newSymbols As ArrayBuilder(Of Symbol) = newResult.Symbols
                Dim newSymbolContainer = newSymbols.First().ContainingType
 
                For i As Integer = 0 To knownSymbols.Count - 1
                    Dim knownSymbol = knownSymbols(i)
 
                    ' Nothing means that the symbol has been eliminated via shadowing
                    If knownSymbol Is Nothing Then
                        Continue For
                    End If
 
                    Dim knownSymbolContainer = knownSymbol.ContainingType
 
                    For j As Integer = 0 To newSymbols.Count - 1
                        Dim newSymbol As Symbol = newSymbols(j)
                        ' Nothing means that the symbol has been eliminated via shadowing
                        If newSymbol Is Nothing Then
                            Continue For
                        End If
 
                        ' Special-case events in case we are inside COM interface
                        If leaveEventsOnly.HasValue AndAlso (newSymbol.Kind = SymbolKind.Event) <> leaveEventsOnly.Value Then
                            newSymbols(j) = Nothing
                            Continue For
                        End If
 
                        If knownSymbol = newSymbol Then
                            ' this is the same result as we already have, remove from the new set
                            newSymbols(j) = Nothing
                            Continue For
                        End If
 
                        ' container of the first new symbol should be container of all others
                        Debug.Assert(TypeSymbol.Equals(newSymbolContainer, newSymbol.ContainingType, TypeCompareKind.ConsiderEverything))
 
                        ' Are the known and new symbols of the right kinds to overload?
                        Dim cantOverloadEachOther = Not LookupResult.CanOverload(knownSymbol, newSymbol)
 
                        If IsDerivedInterface(base:=newSymbolContainer,
                                                 derived:=knownSymbolContainer,
                                                 basesBeingResolved:=BasesBeingResolved,
                                                 useSiteInfo:=useSiteInfo) Then
 
                            ' if currently known is more derived and shadows the new one
                            ' it shadows all the new ones and we are done
                            If IsShadows(knownSymbol) OrElse cantOverloadEachOther Then
                                ' no need to continue with merge. new symbols are all shadowed
                                ' and they cannot shadow anything in the old set
                                Debug.Assert(Not knownSymbols.Any(Function(s) s Is Nothing))
                                newResult.Clear()
                                Return
                            End If
 
                        ElseIf IsDerivedInterface(base:=knownSymbolContainer,
                                             derived:=newSymbolContainer,
                                             basesBeingResolved:=BasesBeingResolved,
                                             useSiteInfo:=useSiteInfo) Then
 
                            ' if new is more derived and shadows
                            ' the current one should be dropped
                            ' NOTE that we continue iterating as more known symbols may be "shadowed out" by the current.
                            If IsShadows(newSymbol) OrElse cantOverloadEachOther Then
                                knownSymbols(i) = Nothing
 
                                ' all following known symbols in the same container are shadowed by the new one
                                ' we can do a quick check and remove them here
                                For k = i + 1 To knownSymbols.Count - 1
                                    Dim otherKnown As Symbol = knownSymbols(k)
                                    If otherKnown IsNot Nothing AndAlso TypeSymbol.Equals(otherKnown.ContainingType, knownSymbolContainer, TypeCompareKind.ConsiderEverything) Then
                                        knownSymbols(k) = Nothing
                                    End If
                                Next
                            End If
                        End If
 
                        ' we can get here if results are completely unrelated.
                        ' However we do not know if they are conflicting as either one could be "shadowed out" in later iterations.
                        ' for now we let both known and new stay
                    Next
                Next
 
                CompactAndAppend(knownSymbols, newSymbols)
                newResult.Clear()
            End Sub
 
            ''' <summary>
            ''' first.Where(t IsNot Nothing).Concat(second.Where(t IsNot Nothing))
            ''' </summary>
            Private Shared Sub CompactAndAppend(first As ArrayBuilder(Of Symbol), second As ArrayBuilder(Of Symbol))
                Dim i As Integer = 0
 
                ' skip non nulls
                While i < first.Count
                    If first(i) Is Nothing Then
                        Exit While
                    End If
 
                    i += 1
                End While
 
                ' compact the rest
                Dim j As Integer = i + 1
                While j < first.Count
                    Dim item As Symbol = first(j)
 
                    If item IsNot Nothing Then
                        first(i) = item
                        i += 1
                    End If
 
                    j += 1
                End While
 
                ' clip to compacted size
                first.Clip(i)
 
                ' append non nulls from second
                i = 0
                While i < second.Count
                    Dim items As Symbol = second(i)
                    If items IsNot Nothing Then
                        first.Add(items)
                    End If
                    i += 1
                End While
            End Sub
 
            ''' <summary>
            ''' 
            ''' </summary>
            Private Shared Sub AddBaseInterfacesToTheSearch(binder As Binder,
                               currentInfo As InterfaceInfo,
                               lookIn As Queue(Of InterfaceInfo),
                               processed As HashSet(Of InterfaceInfo),
                               <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
 
                Dim interfaces As ImmutableArray(Of NamedTypeSymbol) = currentInfo.InterfaceType.GetDirectBaseInterfacesNoUseSiteDiagnostics(binder.BasesBeingResolved)
 
                If Not interfaces.IsDefaultOrEmpty Then
                    Dim inComInterfaceContext As Boolean = currentInfo.InComInterfaceContext OrElse
                                                           currentInfo.InterfaceType.CoClassType IsNot Nothing
 
                    Dim descendants As ImmutableHashSet(Of NamedTypeSymbol)
 
                    If binder.BasesBeingResolved.InheritsBeingResolvedOpt Is Nothing Then
                        descendants = Nothing
                    Else
                        ' We need to watch out for cycles in inheritance chain since they are not broken while bases are being resolved.
                        If currentInfo.DescendantDefinitions Is Nothing Then
                            descendants = ImmutableHashSet.Create(currentInfo.InterfaceType.OriginalDefinition)
                        Else
                            descendants = currentInfo.DescendantDefinitions.Add(currentInfo.InterfaceType.OriginalDefinition)
                        End If
                    End If
 
                    For Each i In interfaces
                        If descendants IsNot Nothing AndAlso descendants.Contains(i.OriginalDefinition) Then
                            ' About to get in an inheritance cycle
                            Continue For
                        End If
 
                        i.OriginalDefinition.AddUseSiteInfo(useSiteInfo)
 
                        Dim newInfo As New InterfaceInfo(i, inComInterfaceContext, descendants)
                        If processed.Add(newInfo) Then
                            lookIn.Enqueue(newInfo)
                        End If
                    Next
                End If
            End Sub
 
            ''' <summary>
            ''' if any symbol in the list Shadows. This implies that name is not visible through the base.
            ''' </summary>
            Private Shared Function AnyShadows(result As LookupResult) As Boolean
                For Each sym As Symbol In result.Symbols
                    If sym.IsShadows Then
                        Return True
                    End If
                Next
 
                Return False
            End Function
 
            ' Find all names in a non-interface type, consider inheritance.
            Private Shared Sub AddLookupSymbolsInfoInClass(nameSet As LookupSymbolsInfo,
                                                  container As TypeSymbol,
                                                  options As LookupOptions,
                                                  binder As Binder)
                ' We need a check for SpecialType.System_Void as its base type is
                ' ValueType but we don't wish to return any members for void type
                If container IsNot Nothing And container.SpecialType = SpecialType.System_Void Then
                    Return
                End If
 
                ' Lookup proceeds up the base class chain.
                Dim currentType = container
                Do
                    AddLookupSymbolsInfoWithoutInheritance(nameSet, currentType, options, container, binder)
 
                    ' If the type is from a winmd file and implements any of the special WinRT collection
                    ' projections, then we may need to add projected interface members
                    Dim namedType = TryCast(currentType, NamedTypeSymbol)
                    If namedType IsNot Nothing AndAlso namedType.ShouldAddWinRTMembers Then
                        AddWinRTMembersLookupSymbolsInfo(nameSet, namedType, options, container, binder)
                    End If
 
                    ' Go to base type, unless that would case infinite recursion or the options or the binder
                    ' disallows it.
                    If (options And LookupOptions.NoBaseClassLookup) <> 0 OrElse binder.IgnoreBaseClassesInLookup Then
                        currentType = Nothing
                    Else
                        currentType = currentType.GetDirectBaseTypeNoUseSiteDiagnostics(binder.BasesBeingResolved)
                    End If
                Loop While currentType IsNot Nothing
 
                ' Search for extension methods.
                AddExtensionMethodLookupSymbolsInfo(nameSet, container, options, binder)
 
                ' Special case: if we're in a constructor of a class or structure, then we can call constructors on ourself or our immediate base
                ' (via Me.New or MyClass.New or MyBase.New). We don't have enough info to check the constraints that the constructor must be
                ' the specific tokens Me, MyClass, or MyBase, or that its the first statement in the constructor, so services must do
                ' that check if it wants to show that.
                ' Roslyn Bug 9701.
                Dim containingMethod = TryCast(binder.ContainingMember, MethodSymbol)
                If containingMethod IsNot Nothing AndAlso
                   containingMethod.MethodKind = MethodKind.Constructor AndAlso
                   (container.TypeKind = TypeKind.Class OrElse container.TypeKind = TypeKind.Structure) AndAlso
                   (TypeSymbol.Equals(containingMethod.ContainingType, container, TypeCompareKind.ConsiderEverything) OrElse TypeSymbol.Equals(containingMethod.ContainingType.BaseTypeNoUseSiteDiagnostics, container, TypeCompareKind.ConsiderEverything)) Then
                    nameSet.AddSymbol(Nothing, WellKnownMemberNames.InstanceConstructorName, 0)
                End If
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfoInSubmissions(nameSet As LookupSymbolsInfo,
                                                                  submissionClass As TypeSymbol,
                                                                  options As LookupOptions,
                                                                  binder As Binder)
                Dim submission = binder.Compilation
                Do
                    ' TODO (tomat): import aliases
 
                    If submission.ScriptClass IsNot Nothing Then
                        AddLookupSymbolsInfoWithoutInheritance(nameSet, submission.ScriptClass, options, submissionClass, binder)
                    End If
 
                    submission = submission.PreviousSubmission
                Loop Until submission Is Nothing
 
                ' TODO (tomat): extension methods
            End Sub
 
            ' Find all names in an interface type, consider inheritance.
            Private Shared Sub AddLookupSymbolsInfoInInterface(nameSet As LookupSymbolsInfo,
                                                                container As NamedTypeSymbol,
                                                                options As LookupOptions,
                                                                binder As Binder)
 
                Dim info As New InterfaceInfo(container, False)
 
                Dim lookIn As New Queue(Of InterfaceInfo)
                lookIn.Enqueue(info)
 
                Dim processed As New HashSet(Of InterfaceInfo)
                processed.Add(info)
 
                AddLookupSymbolsInfoInInterfaces(nameSet, container, lookIn, processed, options, binder)
 
                ' Look in Object.
                AddLookupSymbolsInfoInClass(nameSet,
                              binder.SourceModule.ContainingAssembly.GetSpecialType(SpecialType.System_Object),
                              options Or LookupOptions.IgnoreExtensionMethods, binder)
 
                ' Search for extension methods.
                AddExtensionMethodLookupSymbolsInfo(nameSet, container, options, binder)
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfoInInterfaces(nameSet As LookupSymbolsInfo,
                                                                container As TypeSymbol,
                                                                lookIn As Queue(Of InterfaceInfo),
                                                                processed As HashSet(Of InterfaceInfo),
                                                                options As LookupOptions,
                                                                binder As Binder)
                Dim useSiteInfo = CompoundUseSiteInfo(Of AssemblySymbol).Discarded
 
                Do
                    Dim currentType As InterfaceInfo = lookIn.Dequeue
 
                    AddLookupSymbolsInfoWithoutInheritance(nameSet, currentType.InterfaceType, options, container, binder)
 
                    ' Go to base type, unless that would case infinite recursion or the options or the binder
                    ' disallows it.
                    If (options And LookupOptions.NoBaseClassLookup) = 0 AndAlso Not binder.IgnoreBaseClassesInLookup Then
                        AddBaseInterfacesToTheSearch(binder, currentType, lookIn, processed, useSiteInfo)
                    End If
 
                Loop While lookIn.Count <> 0
 
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfoInTypeParameter(nameSet As LookupSymbolsInfo,
                                                                    typeParameter As TypeParameterSymbol,
                                                                    options As LookupOptions,
                                                                    binder As Binder)
                If typeParameter.TypeParameterKind = TypeParameterKind.Cref Then
                    Return
                End If
 
                AddLookupSymbolsInfoInTypeParameterNoExtensionMethods(nameSet, typeParameter, options, binder)
 
                ' Search for extension methods.
                AddExtensionMethodLookupSymbolsInfo(nameSet, typeParameter, options, binder)
            End Sub
 
            Private Shared Sub AddLookupSymbolsInfoInTypeParameterNoExtensionMethods(nameSet As LookupSymbolsInfo,
                                                                                      typeParameter As TypeParameterSymbol,
                                                                                      options As LookupOptions,
                                                                                      binder As Binder)
                options = options Or LookupOptions.IgnoreExtensionMethods
 
                ' Look up in class constraint.
                Dim constraintClass = typeParameter.GetClassConstraint(CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
                If constraintClass IsNot Nothing Then
                    AddLookupSymbolsInfoInClass(nameSet, constraintClass, options, binder)
                End If
 
                ' Look up in interface constraints.
                Dim lookIn As Queue(Of InterfaceInfo) = Nothing
                Dim processed As HashSet(Of InterfaceInfo) = Nothing
                AddInterfaceConstraints(typeParameter, lookIn, processed, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
 
                If lookIn IsNot Nothing Then
                    AddLookupSymbolsInfoInInterfaces(nameSet, typeParameter, lookIn, processed, options, binder)
                End If
 
                ' Look up in System.ValueType or System.Object.
                If constraintClass Is Nothing Then
                    Dim baseType = GetTypeParameterBaseType(typeParameter)
                    AddLookupSymbolsInfoInClass(nameSet, baseType, options, binder)
                End If
            End Sub
 
            ''' <summary>
            ''' Lookup a member name in a type without considering inheritance, returning a LookupResult that
            ''' summarizes the results of the lookup. See LookupResult structure for a detailed
            ''' discussing of the meaning of the results.
            ''' </summary>
            Private Shared Sub LookupWithoutInheritance(lookupResult As LookupResult,
                                                       container As TypeSymbol,
                                                       name As String,
                                                       arity As Integer,
                                                       options As LookupOptions,
                                                       accessThroughType As TypeSymbol,
                                                       binder As Binder,
                                                       <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Dim members As ImmutableArray(Of Symbol) = ImmutableArray(Of Symbol).Empty
 
                If (options And (LookupOptions.NamespacesOrTypesOnly Or LookupOptions.LabelsOnly)) = LookupOptions.NamespacesOrTypesOnly Then
                    ' Only named types have members that are types. Go through all the types in this type and
                    ' validate them. If there's multiple, give an error.
                    If TypeOf container Is NamedTypeSymbol Then
                        members = ImmutableArray(Of Symbol).CastUp(container.GetTypeMembers(name))
                    End If
                ElseIf (options And LookupOptions.LabelsOnly) = 0 Then
                    members = container.GetMembers(name)
                End If
 
                Debug.Assert(lookupResult.IsClear)
 
                ' Go through each member of the type, and combine them into a single result. Overloadable members
                ' are combined together, while other duplicates cause an ambiguity error.
                If Not members.IsDefaultOrEmpty Then
                    Dim imported As Boolean = container.ContainingModule IsNot binder.SourceModule
 
                    For Each sym In members
                        lookupResult.MergeMembersOfTheSameType(binder.CheckViability(sym, arity, options, accessThroughType, useSiteInfo), imported)
                    Next
                End If
            End Sub
 
            ' Find all names in a type, without considering inheritance.
            Private Shared Sub AddLookupSymbolsInfoWithoutInheritance(nameSet As LookupSymbolsInfo,
                                                                       container As TypeSymbol,
                                                                       options As LookupOptions,
                                                                       accessThroughType As TypeSymbol,
                                                                       binder As Binder)
                ' UNDONE: validate symbols with something that looks like ValidateSymbol.
 
                If (options And (LookupOptions.NamespacesOrTypesOnly Or LookupOptions.LabelsOnly)) = LookupOptions.NamespacesOrTypesOnly Then
                    ' Only named types have members that are types. Go through all the types in this type and
                    ' validate them.
                    If TypeOf container Is NamedTypeSymbol Then
                        For Each sym In container.GetTypeMembersUnordered()
                            If binder.CanAddLookupSymbolInfo(sym, options, nameSet, accessThroughType) Then
                                nameSet.AddSymbol(sym, sym.Name, sym.Arity)
                            End If
                        Next
                    End If
                ElseIf (options And LookupOptions.LabelsOnly) = 0 Then
                    ' Go through each member of the type.
                    For Each sym In container.GetMembersUnordered()
                        If binder.CanAddLookupSymbolInfo(sym, options, nameSet, accessThroughType) Then
                            nameSet.AddSymbol(sym, sym.Name, sym.GetArity())
                        End If
                    Next
                End If
            End Sub
 
            Private Shared Sub AddWinRTMembersLookupSymbolsInfo(
                nameSet As LookupSymbolsInfo,
                type As NamedTypeSymbol,
                options As LookupOptions,
                accessThroughType As TypeSymbol,
                binder As Binder
            )
                ' Dev11 searches all declared and undeclared base interfaces
                For Each iface In type.AllInterfacesNoUseSiteDiagnostics
                    If IsWinRTProjectedInterface(iface, binder.Compilation) Then
                        AddLookupSymbolsInfoWithoutInheritance(nameSet, iface, options, accessThroughType, binder)
                    End If
                Next
            End Sub
 
            Private Shared Function GetTypeParameterBaseType(typeParameter As TypeParameterSymbol) As NamedTypeSymbol
                ' The default base type should only be used if there is no explicit class constraint.
                Debug.Assert(typeParameter.GetClassConstraint(CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Is Nothing)
                Return typeParameter.ContainingAssembly.GetSpecialType(If(typeParameter.HasValueTypeConstraint, SpecialType.System_ValueType, SpecialType.System_Object))
            End Function
        End Class
    End Class
End Namespace