File: Semantics\TypeInference\TypeArgumentInference.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    ''' <summary>
    ''' The only public entry point is the Infer method.
    ''' </summary>
    Friend MustInherit Class TypeArgumentInference
 
        Public Shared Function Infer(
            candidate As MethodSymbol,
            arguments As ImmutableArray(Of BoundExpression),
            parameterToArgumentMap As ArrayBuilder(Of Integer),
            paramArrayItems As ArrayBuilder(Of Integer),
            delegateReturnType As TypeSymbol,
            delegateReturnTypeReferenceBoundNode As BoundNode,
            ByRef typeArguments As ImmutableArray(Of TypeSymbol),
            ByRef inferenceLevel As InferenceLevel,
            ByRef allFailedInferenceIsDueToObject As Boolean,
            ByRef someInferenceFailed As Boolean,
            ByRef inferenceErrorReasons As InferenceErrorReasons,
            <Out> ByRef inferredTypeByAssumption As BitVector,
            <Out> ByRef typeArgumentsLocation As ImmutableArray(Of SyntaxNodeOrToken),
            <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression),
            <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol),
            diagnostic As BindingDiagnosticBag,
            Optional inferTheseTypeParameters As BitVector = Nothing
        ) As Boolean
            Debug.Assert(candidate Is candidate.ConstructedFrom)
 
            Return InferenceGraph.Infer(candidate, arguments, parameterToArgumentMap, paramArrayItems, delegateReturnType, delegateReturnTypeReferenceBoundNode,
                                        typeArguments, inferenceLevel, allFailedInferenceIsDueToObject, someInferenceFailed, inferenceErrorReasons,
                                        inferredTypeByAssumption, typeArgumentsLocation, asyncLambdaSubToFunctionMismatch,
                                        useSiteInfo, diagnostic, inferTheseTypeParameters)
        End Function
 
        ' No-one should create instances of this class.
        Private Sub New()
        End Sub
 
        Public Enum InferenceLevel As Byte
            None = 0
            ' None is used to indicate uninitialized  but semantically it should not matter if there is a whidbey delegate
            ' or no delegate in the overload resolution hence both have value 0 such that overload resolution
            ' will not prefer a non inferred method over an inferred one.
            Whidbey = 0
            Orcas = 1
 
            ' Keep invalid the biggest number
            Invalid = 2
        End Enum
 
        ' MatchGenericArgumentParameter:
        ' This is used in type inference, when matching an argument e.g. Arg(Of String) against a parameter Parm(Of T).
        ' In covariant contexts e.g. Action(Of _), the two match if Arg <= Parm (i.e. Arg inherits/implements Parm).
        ' In contravariant contexts e.g. IEnumerable(Of _), the two match if Parm <= Arg (i.e. Parm inherits/implements Arg).
        ' In invariant contexts e.g. List(Of _), the two match only if Arg and Parm are identical.
        ' Note: remember that rank-1 arrays T() implement IEnumerable(Of T), IList(Of T) and ICollection(Of T).
        Public Enum MatchGenericArgumentToParameter
            MatchBaseOfGenericArgumentToParameter
            MatchArgumentToBaseOfGenericParameter
            MatchGenericArgumentToParameterExactly
        End Enum
 
        Private Enum InferenceNodeType As Byte
            ArgumentNode
            TypeParameterNode
        End Enum
 
        Private MustInherit Class InferenceNode
            Inherits GraphNode(Of InferenceNode)
 
            Public ReadOnly NodeType As InferenceNodeType
            Public InferenceComplete As Boolean
 
            Protected Sub New(graph As InferenceGraph, nodeType As InferenceNodeType)
                MyBase.New(graph)
                Me.NodeType = nodeType
            End Sub
 
            Public Shadows ReadOnly Property Graph As InferenceGraph
                Get
                    Return DirectCast(MyBase.Graph, InferenceGraph)
                End Get
            End Property
 
            ''' <summary>
            ''' Returns True if the inference algorithm should be restarted.
            ''' </summary>
            Public MustOverride Function InferTypeAndPropagateHints() As Boolean
 
            <Conditional("DEBUG")>
            Public Sub VerifyIncomingInferenceComplete(
                    ByVal nodeType As InferenceNodeType
                )
                If Not Graph.SomeInferenceHasFailed() Then
                    For Each current As InferenceNode In IncomingEdges
                        Debug.Assert(current.NodeType = nodeType, "Should only have expected incoming edges.")
                        Debug.Assert(current.InferenceComplete, "Should have inferred type already")
                    Next
                End If
            End Sub
 
        End Class
 
        Private Class DominantTypeDataTypeInference
            Inherits DominantTypeData
 
            ' Fields needed for error reporting
            Public ByAssumption As Boolean ' was ResultType chosen by assumption or intention?
            Public Parameter As ParameterSymbol
            Public InferredFromObject As Boolean
            Public TypeParameter As TypeParameterSymbol
            Public ArgumentLocation As SyntaxNode
 
        End Class
 
        Private Class TypeParameterNode
            Inherits InferenceNode
 
            Public ReadOnly DeclaredTypeParam As TypeParameterSymbol
            Public ReadOnly InferenceTypeCollection As TypeInferenceCollection(Of DominantTypeDataTypeInference)
 
            Private _inferredType As TypeSymbol
            Private _inferredFromLocation As SyntaxNodeOrToken
            Private _inferredTypeByAssumption As Boolean
 
            ' TODO: Dev10 has two locations to track type inferred so far.
            '       One that can be changed with time and the other one that cannot be changed.
            '       This one, cannot be changed once set. We need to clean this up later.
            Private _candidateInferredType As TypeSymbol
 
            Private _parameter As ParameterSymbol
 
            Public Sub New(graph As InferenceGraph, typeParameter As TypeParameterSymbol)
                MyBase.New(graph, InferenceNodeType.TypeParameterNode)
 
                DeclaredTypeParam = typeParameter
                InferenceTypeCollection = New TypeInferenceCollection(Of DominantTypeDataTypeInference)()
 
            End Sub
 
            Public ReadOnly Property InferredType As TypeSymbol
                Get
                    Return _inferredType
                End Get
            End Property
 
            Public ReadOnly Property CandidateInferredType As TypeSymbol
                Get
                    Return _candidateInferredType
                End Get
            End Property
 
            Public ReadOnly Property InferredFromLocation As SyntaxNodeOrToken
                Get
                    Return _inferredFromLocation
                End Get
            End Property
 
            Public ReadOnly Property InferredTypeByAssumption As Boolean
                Get
                    Return _inferredTypeByAssumption
                End Get
            End Property
 
            Public Sub RegisterInferredType(inferredType As TypeSymbol, inferredFromLocation As SyntaxNodeOrToken, inferredTypeByAssumption As Boolean)
 
                ' Make sure ArrayLiteralTypeSymbol does not leak out
                Dim arrayLiteralType = TryCast(inferredType, ArrayLiteralTypeSymbol)
 
                If arrayLiteralType IsNot Nothing Then
 
                    Dim arrayLiteral = arrayLiteralType.ArrayLiteral
                    Dim arrayType = arrayLiteral.InferredType
 
                    If Not (arrayLiteral.HasDominantType AndAlso arrayLiteral.NumberOfCandidates = 1) AndAlso
                        arrayType.ElementType.SpecialType = SpecialType.System_Object Then
 
                        ' ReportArrayLiteralInferredTypeDiagnostics in ReclassifyArrayLiteralExpression reports an error
                        ' when option strict is on and the array type is object() and there wasn't a dominant type. However,
                        ' Dev10 does not report this error when inferring a type parameter's type. Create a new object() type
                        ' to suppress the error.
 
                        inferredType = ArrayTypeSymbol.CreateVBArray(arrayType.ElementType, Nothing, arrayType.Rank, arrayLiteral.Binder.Compilation.Assembly)
                    Else
                        inferredType = arrayLiteral.InferredType
                    End If
 
                End If
 
                Debug.Assert(Not (TypeOf inferredType Is ArrayLiteralTypeSymbol))
 
                _inferredType = inferredType
                _inferredFromLocation = inferredFromLocation
                _inferredTypeByAssumption = inferredTypeByAssumption
 
                ' TODO: Dev10 has two locations to track type inferred so far.
                '       One that can be changed with time and the other one that cannot be changed.
                '       We need to clean this up.
                If _candidateInferredType Is Nothing Then
                    _candidateInferredType = inferredType
                End If
            End Sub
 
            Public ReadOnly Property Parameter As ParameterSymbol
                Get
                    Return _parameter
                End Get
            End Property
 
            Public Sub SetParameter(parameter As ParameterSymbol)
                Debug.Assert(_parameter Is Nothing)
                _parameter = parameter
            End Sub
 
            Public Overrides Function InferTypeAndPropagateHints() As Boolean
                Dim numberOfIncomingEdges As Integer = IncomingEdges.Count
                Dim restartAlgorithm As Boolean = False
                Dim argumentLocation As SyntaxNode
                Dim numberOfIncomingWithNothing As Integer = 0
 
                If numberOfIncomingEdges > 0 Then
                    argumentLocation = DirectCast(IncomingEdges(0), ArgumentNode).Expression.Syntax
                Else
                    argumentLocation = Nothing
                End If
 
                Dim numberOfAssertions As Integer = 0
                Dim incomingFromObject As Boolean = False
 
                Dim list As ArrayBuilder(Of InferenceNode) = IncomingEdges
 
                For Each currentGraphNode As InferenceNode In IncomingEdges
                    Debug.Assert(currentGraphNode.NodeType = InferenceNodeType.ArgumentNode, "Should only have named nodes as incoming edges.")
                    Dim currentNamedNode = DirectCast(currentGraphNode, ArgumentNode)
 
                    If currentNamedNode.Expression.Type IsNot Nothing AndAlso
                       currentNamedNode.Expression.Type.IsObjectType() Then
                        incomingFromObject = True
                    End If
 
                    If Not currentNamedNode.InferenceComplete Then
                        Graph.RemoveEdge(currentNamedNode, Me)
                        restartAlgorithm = True
                        numberOfAssertions += 1
                    Else
                        ' We should not infer from a Nothing literal.
                        If currentNamedNode.Expression.IsStrictNothingLiteral() Then
                            numberOfIncomingWithNothing += 1
                        End If
                    End If
                Next
 
                If numberOfIncomingEdges > 0 AndAlso numberOfIncomingEdges = numberOfIncomingWithNothing Then
                    '  !! Inference has failed: All incoming type hints, were based on 'Nothing'
                    Graph.MarkInferenceFailure()
                    Graph.ReportNotFailedInferenceDueToObject()
                End If
 
                Dim numberOfTypeHints As Integer = InferenceTypeCollection.GetTypeDataList().Count()
 
                If numberOfTypeHints = 0 Then
                    If numberOfAssertions = numberOfIncomingEdges Then
                        Graph.MarkInferenceLevel(InferenceLevel.Orcas)
                    Else
                        '  !! Inference has failed. No Type hints, and some, not all were assertions, otherwise we would have picked object for strict.
                        RegisterInferredType(Nothing, Nothing, False)
                        Graph.MarkInferenceFailure()
 
                        If Not incomingFromObject Then
                            Graph.ReportNotFailedInferenceDueToObject()
                        End If
                    End If
 
                ElseIf numberOfTypeHints = 1 Then
                    Dim typeData As DominantTypeDataTypeInference = InferenceTypeCollection.GetTypeDataList()(0)
 
                    If argumentLocation Is Nothing AndAlso typeData.ArgumentLocation IsNot Nothing Then
                        argumentLocation = typeData.ArgumentLocation
                    End If
 
                    RegisterInferredType(typeData.ResultType, argumentLocation, typeData.ByAssumption)
                Else
                    ' Run the whidbey algorithm to see if we are smarter now.
                    Dim firstInferredType As TypeSymbol = Nothing
                    Dim allTypeData As ArrayBuilder(Of DominantTypeDataTypeInference) = InferenceTypeCollection.GetTypeDataList()
 
                    For Each currentTypeInfo As DominantTypeDataTypeInference In allTypeData
                        If firstInferredType Is Nothing Then
                            firstInferredType = currentTypeInfo.ResultType
 
                        ElseIf Not firstInferredType.IsSameTypeIgnoringAll(currentTypeInfo.ResultType) Then
                            ' Whidbey failed hard here, in Orcas we added dominant type information.
                            Graph.MarkInferenceLevel(InferenceLevel.Orcas)
                        End If
                    Next
 
                    Dim dominantTypeDataList = ArrayBuilder(Of DominantTypeDataTypeInference).GetInstance()
                    Dim errorReasons As InferenceErrorReasons = InferenceErrorReasons.Other
 
                    InferenceTypeCollection.FindDominantType(dominantTypeDataList, errorReasons, Graph.UseSiteInfo)
 
                    If dominantTypeDataList.Count = 1 Then
                        ' //consider: scottwis
                        ' //              This seems dangerous to me, that we
                        ' //              remove error reasons here.
                        ' //              Instead of clearing these, what we should be doing is
                        ' //              asserting that they are not set.
                        ' //              If for some reason they get set, but
                        ' //              we enter this path, then we have a bug.
                        ' //              This code is just masking any such bugs.
                        errorReasons = errorReasons And (Not (InferenceErrorReasons.Ambiguous Or InferenceErrorReasons.NoBest))
 
                        Dim typeData As DominantTypeDataTypeInference = dominantTypeDataList(0)
                        RegisterInferredType(typeData.ResultType, typeData.ArgumentLocation, typeData.ByAssumption)
 
                        ' // Also update the location of the argument for constraint error reporting later on.
                    Else
                        If (errorReasons And InferenceErrorReasons.Ambiguous) <> 0 Then
                            '  !! Inference has failed. Dominant type algorithm found ambiguous types.
                            Graph.ReportAmbiguousInferenceError(dominantTypeDataList)
                        Else
                            ' //consider: scottwis
                            ' //              This code appears to be operating under the assumption that if the error reason is not due to an
                            ' //              ambiguity then it must be because there was no best match.
                            ' //              We should be asserting here to verify that assertion.
 
                            '  !! Inference has failed. Dominant type algorithm could not find a dominant type.
                            Graph.ReportIncompatibleInferenceError(allTypeData)
                        End If
 
                        RegisterInferredType(allTypeData(0).ResultType, argumentLocation, False)
                        Graph.MarkInferenceFailure()
                    End If
 
                    Graph.RegisterErrorReasons(errorReasons)
 
                    dominantTypeDataList.Free()
                End If
 
                InferenceComplete = True
 
                Return restartAlgorithm
            End Function
 
            Public Sub AddTypeHint(
                type As TypeSymbol,
                typeByAssumption As Boolean,
                argumentLocation As SyntaxNode,
                parameter As ParameterSymbol,
                inferredFromObject As Boolean,
                inferenceRestrictions As RequiredConversion
            )
 
                Debug.Assert(Not typeByAssumption OrElse type.IsObjectType() OrElse TypeOf type Is ArrayLiteralTypeSymbol, "unexpected: a type which was 'by assumption', but isn't object or array literal")
 
                ' Don't add error types to the type argument inference collection.
                If type.IsErrorType Then
                    Return
                End If
 
                Dim foundInList As Boolean = False
 
                ' Do not merge array literals with other expressions
                If TypeOf type IsNot ArrayLiteralTypeSymbol Then
                    For Each competitor As DominantTypeDataTypeInference In InferenceTypeCollection.GetTypeDataList()
 
                        ' Do not merge array literals with other expressions
                        If TypeOf competitor.ResultType IsNot ArrayLiteralTypeSymbol AndAlso type.IsSameTypeIgnoringAll(competitor.ResultType) Then
                            competitor.ResultType = TypeInferenceCollection.MergeTupleNames(competitor.ResultType, type)
                            competitor.InferenceRestrictions = Conversions.CombineConversionRequirements(
                                                                        competitor.InferenceRestrictions,
                                                                        inferenceRestrictions)
                            competitor.ByAssumption = competitor.ByAssumption AndAlso typeByAssumption
 
                            Debug.Assert(Not foundInList, "List is supposed to be unique: how can we already find two of the same type in this list.")
                            foundInList = True
                            ' TODO: Should we simply exit the loop for RELEASE build?
                        End If
                    Next
                End If
 
                If Not foundInList Then
                    Dim typeData As DominantTypeDataTypeInference = New DominantTypeDataTypeInference()
 
                    typeData.ResultType = type
                    typeData.ByAssumption = typeByAssumption
                    typeData.InferenceRestrictions = inferenceRestrictions
 
                    typeData.ArgumentLocation = argumentLocation
                    typeData.Parameter = parameter
                    typeData.InferredFromObject = inferredFromObject
                    typeData.TypeParameter = DeclaredTypeParam
 
                    InferenceTypeCollection.GetTypeDataList().Add(typeData)
                End If
            End Sub
 
        End Class
 
        Private Class ArgumentNode
            Inherits InferenceNode
 
            Public ReadOnly ParameterType As TypeSymbol
            Public ReadOnly Expression As BoundExpression
            Public ReadOnly Parameter As ParameterSymbol
 
            Public Sub New(graph As InferenceGraph, expression As BoundExpression, parameterType As TypeSymbol, parameter As ParameterSymbol)
                MyBase.New(graph, InferenceNodeType.ArgumentNode)
                Me.Expression = expression
                Me.ParameterType = parameterType
                Me.Parameter = parameter
            End Sub
 
            Public Overrides Function InferTypeAndPropagateHints() As Boolean
 
#If DEBUG Then
                VerifyIncomingInferenceComplete(InferenceNodeType.TypeParameterNode)
#End If
                ' Check if all incoming are ok, otherwise skip inference.
 
                For Each currentGraphNode As InferenceNode In IncomingEdges
                    Debug.Assert(currentGraphNode.NodeType = InferenceNodeType.TypeParameterNode, "Should only have typed nodes as incoming edges.")
                    Dim currentTypedNode As TypeParameterNode = DirectCast(currentGraphNode, TypeParameterNode)
 
                    If currentTypedNode.InferredType Is Nothing Then
 
                        Dim skipThisNode As Boolean = True
 
                        If Expression.Kind = BoundKind.UnboundLambda AndAlso ParameterType.IsDelegateType() Then
                            ' Check here if we need to infer Object for some of the parameters of the Lambda if we weren't able
                            ' to infer these otherwise. This is only the case for arguments of the lambda that have a GenericParam
                            ' of the method we are inferring that is not yet inferred.
 
                            ' Now find the invoke method of the delegate
                            Dim delegateType = DirectCast(ParameterType, NamedTypeSymbol)
                            Dim invokeMethod As MethodSymbol = delegateType.DelegateInvokeMethod
 
                            If invokeMethod IsNot Nothing AndAlso invokeMethod.GetUseSiteInfo().DiagnosticInfo Is Nothing Then
 
                                Dim unboundLambda = DirectCast(Expression, UnboundLambda)
                                Dim lambdaParameters As ImmutableArray(Of ParameterSymbol) = unboundLambda.Parameters
                                Dim delegateParameters As ImmutableArray(Of ParameterSymbol) = invokeMethod.Parameters
 
                                For i As Integer = 0 To Math.Min(lambdaParameters.Length, delegateParameters.Length) - 1 Step 1
                                    Dim lambdaParameter = DirectCast(lambdaParameters(i), UnboundLambdaParameterSymbol)
                                    Dim delegateParam As ParameterSymbol = delegateParameters(i)
 
                                    If lambdaParameter.Type Is Nothing AndAlso
                                       delegateParam.Type.Equals(currentTypedNode.DeclaredTypeParam) Then
 
                                        ' If this was an argument to the unbound Lambda, infer Object.
                                        If Graph.ObjectType Is Nothing Then
                                            Graph.ObjectType = unboundLambda.Binder.GetSpecialType(SpecialType.System_Object, lambdaParameter.IdentifierSyntax, Graph.Diagnostic)
                                        End If
 
                                        currentTypedNode.RegisterInferredType(Graph.ObjectType,
                                                                              lambdaParameter.TypeSyntax,
                                                                              currentTypedNode.InferredTypeByAssumption)
 
                                        '
                                        ' Port SP1 CL 2941063 to VS10
                                        ' Bug 153317
                                        ' Report an error if Option Strict On or a warning if Option Strict Off
                                        ' because we have no hints about the lambda parameter
                                        ' and we are assuming that it is an object.
                                        ' e.g. "Sub f(Of T, U)(ByVal x As Func(Of T, U))" invoked with "f(function(z)z)"
                                        ' needs to put the squiggly on the first "z".
 
                                        unboundLambda.Binder.ReportLambdaParameterInferredToBeObject(lambdaParameter, Graph.Diagnostic)
 
                                        skipThisNode = False
                                        Exit For
                                    End If
                                Next
                            End If
                        End If
 
                        If skipThisNode Then
                            InferenceComplete = True
                            Return False ' DOn't restart the algorithm.
                        End If
                    End If
                Next
 
                Dim argumentType As TypeSymbol = Nothing
                Dim inferenceOk As Boolean = False
 
                Select Case Expression.Kind
 
                    Case BoundKind.AddressOfOperator
 
                        inferenceOk = Graph.InferTypeArgumentsFromAddressOfArgument(
                                                    Expression,
                                                    ParameterType,
                                                    Parameter)
 
                    Case BoundKind.LateAddressOfOperator
                        ' We can not infer anything for this addressOf, AddressOf can never be of type Object, so mark inference
                        ' as not failed due to object.
                        Graph.ReportNotFailedInferenceDueToObject()
                        inferenceOk = True
 
                    Case BoundKind.QueryLambda, BoundKind.GroupTypeInferenceLambda, BoundKind.UnboundLambda
 
                        ' TODO: Not sure if this is applicable to Roslyn, need to try this out when all required features are available.
                        ' BUG: 131359 If the lambda is wrapped in a delegate constructor the resultType
                        ' will be set and not be Void. In this case the lambda argument should be treated as a regular
                        ' argument so fall through in this case.
 
                        Debug.Assert(Expression.Type Is Nothing)
 
                        ' TODO: We are setting inference level before
                        '       even trying to infer something from the lambda. It is possible
                        '       that we won't infer anything, should consider changing the
                        '       inference level after.
                        Graph.MarkInferenceLevel(InferenceLevel.Orcas)
                        inferenceOk = Graph.InferTypeArgumentsFromLambdaArgument(
                                                    Expression,
                                                    ParameterType,
                                                    Parameter)
 
                    Case Else
HandleAsAGeneralExpression:
                        ' We should not infer from a Nothing literal.
                        If Expression.IsStrictNothingLiteral() Then
                            InferenceComplete = True
 
                            ' continue without restarting, if all hints are Nothing the InferenceTypeNode will mark
                            ' the inference as failed.
                            Return False
                        End If
 
                        Dim inferenceRestrictions As RequiredConversion = RequiredConversion.Any
 
                        If Parameter IsNot Nothing AndAlso
                           Parameter.IsByRef AndAlso
                           (Expression.IsLValue() OrElse Expression.IsPropertySupportingAssignment()) Then
                            ' A ByRef parameter needs (if the argument was an lvalue) to be copy-backable into
                            ' that argument.
                            Debug.Assert(inferenceRestrictions = RequiredConversion.Any, "there should have been no prior restrictions by the time we encountered ByRef")
 
                            inferenceRestrictions = Conversions.CombineConversionRequirements(
                                                        inferenceRestrictions,
                                                        Conversions.InvertConversionRequirement(inferenceRestrictions))
 
                            Debug.Assert(inferenceRestrictions = RequiredConversion.AnyAndReverse, "expected ByRef to require AnyAndReverseConversion")
                        End If
 
                        Dim arrayLiteral As BoundArrayLiteral = Nothing
                        Dim argumentTypeByAssumption As Boolean = False
                        Dim expressionType As TypeSymbol
 
                        If Expression.Kind = BoundKind.ArrayLiteral Then
                            arrayLiteral = DirectCast(Expression, BoundArrayLiteral)
                            argumentTypeByAssumption = arrayLiteral.NumberOfCandidates <> 1
                            expressionType = New ArrayLiteralTypeSymbol(arrayLiteral)
 
                        ElseIf Expression.Kind = BoundKind.TupleLiteral Then
                            expressionType = DirectCast(Expression, BoundTupleLiteral).InferredType
                        Else
                            expressionType = Expression.Type
                        End If
 
                        ' Need to create an ArrayLiteralTypeSymbol
                        inferenceOk = Graph.InferTypeArgumentsFromArgument(
                            Expression.Syntax,
                            expressionType,
                            argumentTypeByAssumption,
                            ParameterType,
                            Parameter,
                            MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter,
                            inferenceRestrictions)
                End Select
 
                If Not inferenceOk Then
                    '  !! Inference has failed. Mismatch of Argument and Parameter signature, so could not find type hints.
                    Graph.MarkInferenceFailure()
 
                    If Not (Expression.Type IsNot Nothing AndAlso Expression.Type.IsObjectType()) Then
                        Graph.ReportNotFailedInferenceDueToObject()
                    End If
                End If
 
                InferenceComplete = True
 
                Return False ' // Don't restart the algorithm;
            End Function
        End Class
 
        Private Class InferenceGraph
            Inherits Graph(Of InferenceNode)
 
            Public ReadOnly Diagnostic As BindingDiagnosticBag
            Public ObjectType As NamedTypeSymbol
            Public ReadOnly Candidate As MethodSymbol
            Public ReadOnly Arguments As ImmutableArray(Of BoundExpression)
            Public ReadOnly ParameterToArgumentMap As ArrayBuilder(Of Integer)
            Public ReadOnly ParamArrayItems As ArrayBuilder(Of Integer)
            Public ReadOnly DelegateReturnType As TypeSymbol
            Public ReadOnly DelegateReturnTypeReferenceBoundNode As BoundNode
            Public UseSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
 
            Private _someInferenceFailed As Boolean
            Private _inferenceErrorReasons As InferenceErrorReasons
            Private _allFailedInferenceIsDueToObject As Boolean = True ' remains true until proven otherwise.
            Private _typeInferenceLevel As InferenceLevel = InferenceLevel.None
            Private _asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression)
 
            Private ReadOnly _typeParameterNodes As ImmutableArray(Of TypeParameterNode)
 
            Private Sub New(
                diagnostic As BindingDiagnosticBag,
                candidate As MethodSymbol,
                arguments As ImmutableArray(Of BoundExpression),
                parameterToArgumentMap As ArrayBuilder(Of Integer),
                paramArrayItems As ArrayBuilder(Of Integer),
                delegateReturnType As TypeSymbol,
                delegateReturnTypeReferenceBoundNode As BoundNode,
                asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression),
                useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            )
                Debug.Assert(delegateReturnType Is Nothing OrElse delegateReturnTypeReferenceBoundNode IsNot Nothing)
                Debug.Assert(diagnostic IsNot Nothing)
                Debug.Assert(diagnostic.AccumulatesDependencies OrElse Not useSiteInfo.AccumulatesDependencies)
 
                Me.Diagnostic = diagnostic
                Me.Candidate = candidate
                Me.Arguments = arguments
                Me.ParameterToArgumentMap = parameterToArgumentMap
                Me.ParamArrayItems = paramArrayItems
                Me.DelegateReturnType = delegateReturnType
                Me.DelegateReturnTypeReferenceBoundNode = delegateReturnTypeReferenceBoundNode
                Me._asyncLambdaSubToFunctionMismatch = asyncLambdaSubToFunctionMismatch
                Me.UseSiteInfo = useSiteInfo
 
                ' Allocate the array of TypeParameter nodes.
                Dim arity As Integer = candidate.Arity
 
                Dim typeParameterNodes(arity - 1) As TypeParameterNode
 
                For i As Integer = 0 To arity - 1 Step 1
                    typeParameterNodes(i) = New TypeParameterNode(Me, candidate.TypeParameters(i))
                Next
 
                _typeParameterNodes = typeParameterNodes.AsImmutableOrNull()
            End Sub
 
            Public ReadOnly Property SomeInferenceHasFailed As Boolean
                Get
                    Return _someInferenceFailed
                End Get
            End Property
 
            Public Sub MarkInferenceFailure()
                _someInferenceFailed = True
            End Sub
 
            Public ReadOnly Property AllFailedInferenceIsDueToObject As Boolean
                Get
                    Return _allFailedInferenceIsDueToObject
                End Get
            End Property
 
            Public ReadOnly Property InferenceErrorReasons As InferenceErrorReasons
                Get
                    Return _inferenceErrorReasons
                End Get
            End Property
 
            Public Sub ReportNotFailedInferenceDueToObject()
                _allFailedInferenceIsDueToObject = False
            End Sub
 
            Public ReadOnly Property TypeInferenceLevel As InferenceLevel
                Get
                    Return _typeInferenceLevel
                End Get
            End Property
 
            Public Sub MarkInferenceLevel(typeInferenceLevel As InferenceLevel)
                If _typeInferenceLevel < typeInferenceLevel Then
                    _typeInferenceLevel = typeInferenceLevel
                End If
            End Sub
 
            Public Shared Function Infer(
                candidate As MethodSymbol,
                arguments As ImmutableArray(Of BoundExpression),
                parameterToArgumentMap As ArrayBuilder(Of Integer),
                paramArrayItems As ArrayBuilder(Of Integer),
                delegateReturnType As TypeSymbol,
                delegateReturnTypeReferenceBoundNode As BoundNode,
                ByRef typeArguments As ImmutableArray(Of TypeSymbol),
                ByRef inferenceLevel As InferenceLevel,
                ByRef allFailedInferenceIsDueToObject As Boolean,
                ByRef someInferenceFailed As Boolean,
                ByRef inferenceErrorReasons As InferenceErrorReasons,
                <Out> ByRef inferredTypeByAssumption As BitVector,
                <Out> ByRef typeArgumentsLocation As ImmutableArray(Of SyntaxNodeOrToken),
                <[In](), Out()> ByRef asyncLambdaSubToFunctionMismatch As HashSet(Of BoundExpression),
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol),
                diagnostic As BindingDiagnosticBag,
                inferTheseTypeParameters As BitVector
            ) As Boolean
                Debug.Assert(diagnostic IsNot Nothing)
                Debug.Assert(diagnostic.AccumulatesDependencies OrElse Not useSiteInfo.AccumulatesDependencies)
 
                Dim graph As New InferenceGraph(diagnostic, candidate, arguments, parameterToArgumentMap, paramArrayItems,
                                                delegateReturnType, delegateReturnTypeReferenceBoundNode, asyncLambdaSubToFunctionMismatch,
                                                useSiteInfo)
 
                ' Build a graph describing the flow of type inference data.
                ' This creates edges from "regular" arguments to type parameters and from type parameters to lambda arguments.
                ' In the rest of this function that graph is then processed (see below for more details).  Essentially, for each
                ' "type parameter" node a list of "type hints" (possible candidates for type inference) is collected. The dominant
                ' type algorithm is then performed over the list of hints associated with each node.
                '
                ' The process of populating the graph also seeds type hints for type parameters referenced by explicitly typed
                ' lambda parameters. Also, hints sometimes have restrictions placed on them that limit what conversions the dominant type
                ' algorithm can consider when it processes them. The restrictions are generally driven by the context in which type
                ' parameters are used. For example if a type parameter is used as a type parameter of another type (something like IGoo(of T)),
                ' then the dominant type algorithm is not allowed to consider any conversions. There are similar restrictions for
                ' Array co-variance.
 
                graph.PopulateGraph()
 
                Dim topoSortedGraph = ArrayBuilder(Of StronglyConnectedComponent(Of InferenceNode)).GetInstance()
 
                ' This is the restart point of the algorithm
                Do
                    Dim restartAlgorithm As Boolean = False
                    Dim stronglyConnectedComponents As Graph(Of StronglyConnectedComponent(Of InferenceNode)) =
                          graph.BuildStronglyConnectedComponents()
 
                    topoSortedGraph.Clear()
                    stronglyConnectedComponents.TopoSort(topoSortedGraph)
 
                    ' We now iterate over the topologically-sorted strongly connected components of the graph, and generate
                    ' type hints as appropriate.
                    '
                    ' When we find a node for an argument (or an ArgumentNode as it's referred to in the code), we infer
                    ' types for all type parameters referenced by that argument and then propagate those types as hints
                    ' to the referenced type parameters. If there are incoming edges into the argument node, they correspond
                    ' to parameters of lambda arguments that get their value from the delegate type that contains type
                    ' parameters that would have been inferred during a previous iteration of the loop. Those types are
                    ' flowed into the lambda argument.
                    '
                    ' When we encounter a "type parameter" node (or TypeParameterNode as it is called in the code), we run
                    ' the dominant type algorithm over all of it's hints and use the resulting type as the value for the
                    ' referenced type parameter.
                    '
                    ' If we find a strongly connected component with more than one node, it means we
                    ' have a cycle and cannot simply run the inference algorithm. When this happens,
                    ' we look through the nodes in the cycle for a type parameter node with at least
                    ' one type hint. If we find one, we remove all incoming edges to that node,
                    ' infer the type using its hints, and then restart the whole algorithm from the
                    ' beginning (recompute the strongly connected components, resort them, and then
                    ' iterate over the graph again). The source nodes of the incoming edges we
                    ' removed are added to an "assertion list". After graph traversal is done we
                    ' then run inference on any "assertion nodes" we may have created.
                    For Each sccNode As StronglyConnectedComponent(Of InferenceNode) In topoSortedGraph
                        Dim childNodes As ArrayBuilder(Of InferenceNode) = sccNode.ChildNodes
 
                        ' Small optimization if one node
                        If childNodes.Count = 1 Then
                            If childNodes(0).InferTypeAndPropagateHints() Then
                                ' consider: scottwis
                                '               We should be asserting here, because this code is unreachable..
                                '               There are two implementations of InferTypeAndPropagateHints,
                                '               one for "named nodes" (nodes corresponding to arguments) and another
                                '               for "type nodes" (nodes corresponding to types).
                                '               The implementation for "named nodes" always returns false, which means
                                '               "don't restart the algorithm". The implementation for "type nodes" only returns true
                                '               if a node has incoming edges that have not been visited previously. In order for that
                                '               to happen the node must be inside a strongly connected component with more than one node
                                '               (i.e. it must be involved in a cycle). If it wasn't we would be visiting it in
                                '               topological order, which means all incoming edges should have already been visited.
                                '               That means that if we reach this code, there is probably a bug in the traversal process. We
                                '               don't want to silently mask the bug. At a minimum we should either assert or generate a compiler error.
                                '
                                '               An argument could be made that it is good to have this because
                                '               InferTypeAndPropagateHints is virtual, and should some new node type be
                                '               added it's implementation may return true, and so this would follow that
                                '               path. That argument does make some tiny amount of sense, and so we
                                '               should keep this code here to make it easier to make any such
                                '               modifications in the future. However, we still need an assert to guard
                                '               against graph traversal bugs, and in the event that such changes are
                                '               made, leave it to the modifier to remove the assert if necessary.
                                Throw ExceptionUtilities.Unreachable
                            End If
 
                        Else
                            Dim madeInferenceProgress As Boolean = False
 
                            For Each child As InferenceNode In childNodes
                                If child.NodeType = InferenceNodeType.TypeParameterNode AndAlso
                                   DirectCast(child, TypeParameterNode).InferenceTypeCollection.GetTypeDataList().Count > 0 Then
 
                                    If child.InferTypeAndPropagateHints() Then
                                        ' If edges were broken, restart algorithm to recompute strongly connected components.
                                        restartAlgorithm = True
                                    End If
 
                                    madeInferenceProgress = True
                                End If
                            Next
 
                            If Not madeInferenceProgress Then
                                ' Did not make progress trying to force incoming edges for nodes with TypesHints, just inferring all now,
                                ' will infer object if no type hints.
                                For Each child As InferenceNode In childNodes
                                    If child.NodeType = InferenceNodeType.TypeParameterNode AndAlso
                                       child.InferTypeAndPropagateHints() Then
                                        ' If edges were broken, restart algorithm to recompute strongly connected components.
                                        restartAlgorithm = True
                                    End If
                                Next
                            End If
 
                            If restartAlgorithm Then
                                Exit For ' For Each sccNode
                            End If
                        End If
                    Next
 
                    If restartAlgorithm Then
                        Continue Do
                    End If
 
                    Exit Do
                Loop
 
                'The commented code below is from Dev10, but it looks like
                'it doesn't do anything useful because topoSortedGraph contains
                'StronglyConnectedComponents, which have NodeType=None.
                '
                'graph.m_VerifyingAssertions = True
                'GraphNodeListIterator assertionIter(&topoSortedGraph);
                '                While (assertionIter.MoveNext())
                '{
                '    GraphNode* currentNode = assertionIter.Current();
                '    if (currentNode->m_NodeType == TypedNodeType)
                '    {
                '        InferenceTypeNode* currentTypeNode = (InferenceTypeNode*)currentNode;
                '        currentTypeNode->VerifyTypeAssertions();
                '    }
                '}
                'graph.m_VerifyingAssertions = False
 
                topoSortedGraph.Free()
 
                Dim succeeded As Boolean = Not graph.SomeInferenceHasFailed
 
                someInferenceFailed = graph.SomeInferenceHasFailed
                allFailedInferenceIsDueToObject = graph.AllFailedInferenceIsDueToObject
                inferenceErrorReasons = graph.InferenceErrorReasons
 
                ' Make sure that allFailedInferenceIsDueToObject only stays set,
                ' if there was an actual inference failure.
                If Not someInferenceFailed OrElse delegateReturnType IsNot Nothing Then
                    allFailedInferenceIsDueToObject = False
                End If
 
                Dim arity As Integer = candidate.Arity
                Dim inferredTypes(arity - 1) As TypeSymbol
                Dim inferredFromLocation(arity - 1) As SyntaxNodeOrToken
 
                For i As Integer = 0 To arity - 1 Step 1
 
                    ' TODO: Should we use InferredType or CandidateInferredType here? It looks like Dev10 is using the latter,
                    '       it might not be cleaned in case of a failure. Will use the former for now.
                    Dim typeParameterNode = graph._typeParameterNodes(i)
 
                    Dim inferredType As TypeSymbol = typeParameterNode.InferredType
 
                    If inferredType Is Nothing AndAlso
                       (inferTheseTypeParameters.IsNull OrElse inferTheseTypeParameters(i)) Then
                        succeeded = False
                    End If
 
                    If typeParameterNode.InferredTypeByAssumption Then
                        If inferredTypeByAssumption.IsNull Then
                            inferredTypeByAssumption = BitVector.Create(arity)
                        End If
                        inferredTypeByAssumption(i) = True
                    End If
 
                    inferredTypes(i) = inferredType
                    inferredFromLocation(i) = typeParameterNode.InferredFromLocation
                Next
 
                typeArguments = inferredTypes.AsImmutableOrNull()
                typeArgumentsLocation = inferredFromLocation.AsImmutableOrNull()
                inferenceLevel = graph._typeInferenceLevel
 
                asyncLambdaSubToFunctionMismatch = graph._asyncLambdaSubToFunctionMismatch
                useSiteInfo = graph.UseSiteInfo
 
                Return succeeded
            End Function
 
            Private Sub PopulateGraph()
 
                Dim candidate As MethodSymbol = Me.Candidate
                Dim arguments As ImmutableArray(Of BoundExpression) = Me.Arguments
                Dim parameterToArgumentMap As ArrayBuilder(Of Integer) = Me.ParameterToArgumentMap
                Dim paramArrayItems As ArrayBuilder(Of Integer) = Me.ParamArrayItems
                Dim isExpandedParamArrayForm As Boolean = (paramArrayItems IsNot Nothing)
 
                Dim argIndex As Integer
 
                For paramIndex = 0 To candidate.ParameterCount - 1 Step 1
 
                    Dim param As ParameterSymbol = candidate.Parameters(paramIndex)
                    Dim targetType As TypeSymbol = param.Type
 
                    If param.IsParamArray AndAlso paramIndex = candidate.ParameterCount - 1 Then
 
                        If targetType.Kind <> SymbolKind.ArrayType Then
                            Continue For
                        End If
 
                        If Not isExpandedParamArrayForm Then
                            argIndex = parameterToArgumentMap(paramIndex)
                            Dim paramArrayArgument = If(argIndex = -1, Nothing, arguments(argIndex))
 
                            Debug.Assert(paramArrayArgument Is Nothing OrElse paramArrayArgument.Kind <> BoundKind.OmittedArgument)
 
                            '§11.8.2 Applicable Methods
                            'If the conversion from the type of the argument expression to the paramarray type is narrowing,
                            'then the method is only applicable in its expanded form.
                            '!!! However, there is an exception to that rule - narrowing conversion from semantical Nothing literal is Ok. !!!
 
                            If paramArrayArgument Is Nothing OrElse paramArrayArgument.HasErrors OrElse
                               Not ArgumentTypePossiblyMatchesParamarrayShape(paramArrayArgument, targetType) Then
                                Continue For
                            End If
 
                            RegisterArgument(paramArrayArgument, targetType, param)
                        Else
                            Debug.Assert(isExpandedParamArrayForm)
 
                            '§11.8.2 Applicable Methods
                            'If the argument expression is the literal Nothing, then the method is only applicable in its unexpanded form.
                            ' Note, that explicitly converted NOTHING is treated the same way by Dev10.
                            If paramArrayItems.Count = 1 AndAlso arguments(paramArrayItems(0)).IsNothingLiteral() Then
                                Continue For
                            End If
 
                            ' Otherwise, for a ParamArray parameter, all the matching arguments are passed
                            ' ByVal as instances of the element type of the ParamArray.
                            ' Perform the conversions to the element type of the ParamArray here.
                            Dim arrayType = DirectCast(targetType, ArrayTypeSymbol)
 
                            If Not arrayType.IsSZArray Then
                                Continue For
                            End If
 
                            targetType = arrayType.ElementType
 
                            If targetType.Kind = SymbolKind.ErrorType Then
                                Continue For
                            End If
 
                            For j As Integer = 0 To paramArrayItems.Count - 1 Step 1
                                If arguments(paramArrayItems(j)).HasErrors Then
                                    Continue For
                                End If
 
                                RegisterArgument(arguments(paramArrayItems(j)), targetType, param)
                            Next
                        End If
 
                        Continue For
                    End If
 
                    argIndex = parameterToArgumentMap(paramIndex)
                    Dim argument = If(argIndex = -1, Nothing, arguments(argIndex))
 
                    If argument Is Nothing OrElse argument.HasErrors OrElse targetType.IsErrorType() OrElse argument.Kind = BoundKind.OmittedArgument Then
                        Continue For
                    End If
 
                    RegisterArgument(argument, targetType, param)
                Next
 
                AddDelegateReturnTypeToGraph()
            End Sub
 
            Private Sub AddDelegateReturnTypeToGraph()
                If Me.DelegateReturnType IsNot Nothing AndAlso Not Me.DelegateReturnType.IsVoidType() Then
                    Dim fakeArgument As New BoundRValuePlaceholder(Me.DelegateReturnTypeReferenceBoundNode.Syntax,
                                                                  Me.DelegateReturnType)
 
                    Dim returnNode As New ArgumentNode(Me, fakeArgument, Me.Candidate.ReturnType, parameter:=Nothing)
 
                    ' Add the edges from all the current generic parameters to this named node.
                    For Each current As InferenceNode In Vertices
                        If current.NodeType = InferenceNodeType.TypeParameterNode Then
                            AddEdge(current, returnNode)
                        End If
                    Next
 
                    ' Add the edges from the resultType outgoing to the generic parameters.
                    AddTypeToGraph(returnNode, isOutgoingEdge:=True)
                End If
            End Sub
 
            Private Sub RegisterArgument(
                argument As BoundExpression,
                targetType As TypeSymbol,
                param As ParameterSymbol
            )
                ' Dig through parenthesized.
                If Not argument.IsNothingLiteral Then
                    argument = argument.GetMostEnclosedParenthesizedExpression()
                End If
 
                Dim argNode As New ArgumentNode(Me, argument, targetType, param)
 
                Select Case argument.Kind
                    Case BoundKind.UnboundLambda, BoundKind.QueryLambda, BoundKind.GroupTypeInferenceLambda
                        AddLambdaToGraph(argNode, argument.GetBinderFromLambda())
                    Case BoundKind.AddressOfOperator
                        AddAddressOfToGraph(argNode, DirectCast(argument, BoundAddressOfOperator).Binder)
                    Case BoundKind.TupleLiteral
                        AddTupleLiteralToGraph(argNode)
                    Case Else
                        AddTypeToGraph(argNode, isOutgoingEdge:=True)
                End Select
            End Sub
 
            Private Sub AddTypeToGraph(
                node As ArgumentNode,
                isOutgoingEdge As Boolean
            )
                AddTypeToGraph(node.ParameterType, node, isOutgoingEdge, BitVector.Create(_typeParameterNodes.Length))
            End Sub
 
            Private Function FindTypeParameterNode(typeParameter As TypeParameterSymbol) As TypeParameterNode
                Dim ordinal As Integer = typeParameter.Ordinal
 
                If ordinal < _typeParameterNodes.Length AndAlso
                   _typeParameterNodes(ordinal) IsNot Nothing AndAlso
                   typeParameter.Equals(_typeParameterNodes(ordinal).DeclaredTypeParam) Then
                    Return _typeParameterNodes(ordinal)
                End If
 
                Return Nothing
            End Function
 
            Private Sub AddTypeToGraph(
                parameterType As TypeSymbol,
                argNode As ArgumentNode,
                isOutgoingEdge As Boolean,
                ByRef haveSeenTypeParameters As BitVector
            )
                Select Case parameterType.Kind
                    Case SymbolKind.TypeParameter
                        Dim typeParameter = DirectCast(parameterType, TypeParameterSymbol)
                        Dim typeParameterNode As TypeParameterNode = FindTypeParameterNode(typeParameter)
 
                        If typeParameterNode IsNot Nothing AndAlso
                           Not haveSeenTypeParameters(typeParameter.Ordinal) Then
 
                            If typeParameterNode.Parameter Is Nothing Then
                                typeParameterNode.SetParameter(argNode.Parameter)
                            End If
 
                            If (isOutgoingEdge) Then
                                AddEdge(argNode, typeParameterNode)
                            Else
                                AddEdge(typeParameterNode, argNode)
                            End If
 
                            haveSeenTypeParameters(typeParameter.Ordinal) = True
                        End If
 
                    Case SymbolKind.ArrayType
 
                        AddTypeToGraph(DirectCast(parameterType, ArrayTypeSymbol).ElementType, argNode, isOutgoingEdge, haveSeenTypeParameters)
 
                    Case SymbolKind.NamedType
 
                        Dim possiblyGenericType = DirectCast(parameterType, NamedTypeSymbol)
 
                        Dim elementTypes As ImmutableArray(Of TypeSymbol) = Nothing
                        If possiblyGenericType.TryGetElementTypesIfTupleOrCompatible(elementTypes) Then
                            For Each elementType In elementTypes
                                AddTypeToGraph(elementType, argNode, isOutgoingEdge, haveSeenTypeParameters)
                            Next
                        Else
 
                            Do
                                For Each typeArgument In possiblyGenericType.TypeArgumentsWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
                                    AddTypeToGraph(typeArgument, argNode, isOutgoingEdge, haveSeenTypeParameters)
                                Next
 
                                possiblyGenericType = possiblyGenericType.ContainingType
                            Loop While possiblyGenericType IsNot Nothing
                        End If
                End Select
 
            End Sub
 
            Private Sub AddTupleLiteralToGraph(argNode As ArgumentNode)
                AddTupleLiteralToGraph(argNode.ParameterType, argNode)
            End Sub
 
            Private Sub AddTupleLiteralToGraph(
                parameterType As TypeSymbol,
                argNode As ArgumentNode
            )
                Debug.Assert(argNode.Expression.Kind = BoundKind.TupleLiteral)
 
                Dim tupleLiteral = DirectCast(argNode.Expression, BoundTupleLiteral)
                Dim tupleArguments = tupleLiteral.Arguments
 
                If parameterType.IsTupleOrCompatibleWithTupleOfCardinality(tupleArguments.Length) Then
                    Dim parameterElementTypes = parameterType.GetElementTypesOfTupleOrCompatible
                    For i As Integer = 0 To tupleArguments.Length - 1
                        RegisterArgument(tupleArguments(i), parameterElementTypes(i), argNode.Parameter)
                    Next
 
                    Return
                End If
 
                AddTypeToGraph(argNode, isOutgoingEdge:=True)
            End Sub
 
            Private Sub AddAddressOfToGraph(argNode As ArgumentNode, binder As Binder)
                AddAddressOfToGraph(argNode.ParameterType, argNode, binder)
            End Sub
 
            Private Sub AddAddressOfToGraph(
                parameterType As TypeSymbol,
                argNode As ArgumentNode,
                binder As Binder
            )
                Debug.Assert(argNode.Expression.Kind = BoundKind.AddressOfOperator)
 
                If parameterType.IsTypeParameter() Then
                    AddTypeToGraph(parameterType, argNode, isOutgoingEdge:=True, haveSeenTypeParameters:=BitVector.Create(_typeParameterNodes.Length))
 
                ElseIf parameterType.IsDelegateType() Then
                    Dim delegateType As NamedTypeSymbol = DirectCast(parameterType, NamedTypeSymbol)
                    Dim invoke As MethodSymbol = delegateType.DelegateInvokeMethod
 
                    If invoke IsNot Nothing AndAlso invoke.GetUseSiteInfo().DiagnosticInfo Is Nothing AndAlso delegateType.IsGenericType Then
 
                        Dim haveSeenTypeParameters = BitVector.Create(_typeParameterNodes.Length)
                        AddTypeToGraph(invoke.ReturnType, argNode, isOutgoingEdge:=True, haveSeenTypeParameters:=haveSeenTypeParameters) ' outgoing (name->type) edge
 
                        haveSeenTypeParameters.Clear()
 
                        For Each delegateParameter As ParameterSymbol In invoke.Parameters
                            AddTypeToGraph(delegateParameter.Type, argNode, isOutgoingEdge:=False, haveSeenTypeParameters:=haveSeenTypeParameters) ' incoming (type->name) edge
                        Next
                    End If
                ElseIf TypeSymbol.Equals(parameterType.OriginalDefinition, binder.Compilation.GetWellKnownType(WellKnownType.System_Linq_Expressions_Expression_T), TypeCompareKind.ConsiderEverything) Then
                    ' If we've got an Expression(Of T), skip through to T
                    AddAddressOfToGraph(DirectCast(parameterType, NamedTypeSymbol).TypeArgumentWithDefinitionUseSiteDiagnostics(0, Me.UseSiteInfo), argNode, binder)
                End If
            End Sub
 
            Private Sub AddLambdaToGraph(argNode As ArgumentNode, binder As Binder)
                AddLambdaToGraph(argNode.ParameterType, argNode, binder)
            End Sub
 
            Private Sub AddLambdaToGraph(
                parameterType As TypeSymbol,
                argNode As ArgumentNode,
                binder As Binder
            )
                If parameterType.IsTypeParameter() Then
                    ' Lambda is bound to a generic typeParam, just infer anonymous delegate
                    AddTypeToGraph(parameterType, argNode, isOutgoingEdge:=True, haveSeenTypeParameters:=BitVector.Create(_typeParameterNodes.Length))
 
                ElseIf parameterType.IsDelegateType() Then
                    Dim delegateType As NamedTypeSymbol = DirectCast(parameterType, NamedTypeSymbol)
                    Dim invoke As MethodSymbol = delegateType.DelegateInvokeMethod
 
                    If invoke IsNot Nothing AndAlso invoke.GetUseSiteInfo().DiagnosticInfo Is Nothing AndAlso delegateType.IsGenericType Then
 
                        Dim delegateParameters As ImmutableArray(Of ParameterSymbol) = invoke.Parameters
                        Dim lambdaParameters As ImmutableArray(Of ParameterSymbol)
 
                        Select Case argNode.Expression.Kind
                            Case BoundKind.QueryLambda
                                lambdaParameters = DirectCast(argNode.Expression, BoundQueryLambda).LambdaSymbol.Parameters
                            Case BoundKind.GroupTypeInferenceLambda
                                lambdaParameters = DirectCast(argNode.Expression, GroupTypeInferenceLambda).Parameters
                            Case BoundKind.UnboundLambda
                                lambdaParameters = DirectCast(argNode.Expression, UnboundLambda).Parameters
                            Case Else
                                Throw ExceptionUtilities.UnexpectedValue(argNode.Expression.Kind)
                        End Select
 
                        Dim haveSeenTypeParameters = BitVector.Create(_typeParameterNodes.Length)
 
                        For i As Integer = 0 To Math.Min(delegateParameters.Length, lambdaParameters.Length) - 1 Step 1
                            If lambdaParameters(i).Type IsNot Nothing Then
                                ' Prepopulate the hint from the lambda's parameter.
                                ' !!! Unlike Dev10, we are using MatchArgumentToBaseOfGenericParameter because a value of generic
                                ' !!! parameter will be passed into the parameter of argument type.
                                ' TODO: Consider using location for the type declaration.
                                InferTypeArgumentsFromArgument(
                                    argNode.Expression.Syntax,
                                    lambdaParameters(i).Type,
                                    argumentTypeByAssumption:=False,
                                    parameterType:=delegateParameters(i).Type,
                                    param:=delegateParameters(i),
                                    digThroughToBasesAndImplements:=MatchGenericArgumentToParameter.MatchArgumentToBaseOfGenericParameter,
                                    inferenceRestrictions:=RequiredConversion.Any)
                            End If
 
                            AddTypeToGraph(delegateParameters(i).Type, argNode, isOutgoingEdge:=False, haveSeenTypeParameters:=haveSeenTypeParameters)
                        Next
 
                        haveSeenTypeParameters.Clear()
                        AddTypeToGraph(invoke.ReturnType, argNode, isOutgoingEdge:=True, haveSeenTypeParameters:=haveSeenTypeParameters)
                    End If
 
                ElseIf TypeSymbol.Equals(parameterType.OriginalDefinition, binder.Compilation.GetWellKnownType(WellKnownType.System_Linq_Expressions_Expression_T), TypeCompareKind.ConsiderEverything) Then
                    ' If we've got an Expression(Of T), skip through to T
                    AddLambdaToGraph(DirectCast(parameterType, NamedTypeSymbol).TypeArgumentWithDefinitionUseSiteDiagnostics(0, Me.UseSiteInfo), argNode, binder)
                End If
            End Sub
 
            Private Shared Function ArgumentTypePossiblyMatchesParamarrayShape(argument As BoundExpression, paramType As TypeSymbol) As Boolean
                Dim argumentType As TypeSymbol = argument.Type
                Dim isArrayLiteral As Boolean = False
 
                If argumentType Is Nothing Then
                    If argument.Kind = BoundKind.ArrayLiteral Then
                        isArrayLiteral = True
                        argumentType = DirectCast(argument, BoundArrayLiteral).InferredType
                    Else
                        Return False
                    End If
                End If
 
                While paramType.IsArrayType()
 
                    If Not argumentType.IsArrayType() Then
                        Return False
                    End If
 
                    Dim argumentArray = DirectCast(argumentType, ArrayTypeSymbol)
                    Dim paramArrayType = DirectCast(paramType, ArrayTypeSymbol)
 
                    ' We can ignore IsSZArray value for an inferred type of an array literal as long as its rank matches.
                    If argumentArray.Rank <> paramArrayType.Rank OrElse
                       (Not isArrayLiteral AndAlso argumentArray.IsSZArray <> paramArrayType.IsSZArray) Then
                        Return False
                    End If
 
                    isArrayLiteral = False
                    argumentType = argumentArray.ElementType
                    paramType = paramArrayType.ElementType
                End While
 
                Return True
            End Function
 
            Public Sub RegisterTypeParameterHint(
                genericParameter As TypeParameterSymbol,
                inferredType As TypeSymbol,
                inferredTypeByAssumption As Boolean,
                argumentLocation As SyntaxNode,
                parameter As ParameterSymbol,
                inferredFromObject As Boolean,
                inferenceRestrictions As RequiredConversion
            )
                Dim typeNode As TypeParameterNode = FindTypeParameterNode(genericParameter)
 
                If typeNode IsNot Nothing Then
                    typeNode.AddTypeHint(inferredType, inferredTypeByAssumption, argumentLocation, parameter, inferredFromObject, inferenceRestrictions)
                End If
            End Sub
 
            Private Function RefersToGenericParameterToInferArgumentFor(
                parameterType As TypeSymbol
            ) As Boolean
                Select Case parameterType.Kind
                    Case SymbolKind.TypeParameter
                        Dim typeParameter = DirectCast(parameterType, TypeParameterSymbol)
                        Dim typeNode As TypeParameterNode = FindTypeParameterNode(typeParameter)
 
                        ' TODO: It looks like this check can give us a false positive. For example,
                        '       if we are resolving a recursive call we might already bind a type
                        '       parameter to itself (to the same type parameter of the containing method).
                        '       So, the fact that we ran into this type parameter doesn't necessary mean
                        '       that there is anything to infer. I am not sure if this can lead to some
                        '       negative effect. Dev10 appears to have the same behavior, from what I see
                        '       in the code.
                        If typeNode IsNot Nothing Then
                            Return True
                        End If
 
                    Case SymbolKind.ArrayType
 
                        Return RefersToGenericParameterToInferArgumentFor(DirectCast(parameterType, ArrayTypeSymbol).ElementType)
 
                    Case SymbolKind.NamedType
 
                        Dim possiblyGenericType = DirectCast(parameterType, NamedTypeSymbol)
 
                        Dim elementTypes As ImmutableArray(Of TypeSymbol) = Nothing
                        If possiblyGenericType.TryGetElementTypesIfTupleOrCompatible(elementTypes) Then
                            For Each elementType In elementTypes
                                If RefersToGenericParameterToInferArgumentFor(elementType) Then
                                    Return True
                                End If
                            Next
                        Else
                            Do
                                For Each typeArgument In possiblyGenericType.TypeArgumentsWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
                                    If RefersToGenericParameterToInferArgumentFor(typeArgument) Then
                                        Return True
                                    End If
                                Next
 
                                possiblyGenericType = possiblyGenericType.ContainingType
                            Loop While possiblyGenericType IsNot Nothing
                        End If
                End Select
 
                Return False
            End Function
 
            ' Given an argument type, a parameter type, and a set of (possibly unbound) type arguments
            ' to a generic method, infer type arguments corresponding to type parameters that occur
            ' in the parameter type.
            '
            ' A return value of false indicates that inference fails.
            '
            ' If a generic method is parameterized by T, an argument of type A matches a parameter of type
            ' P, this function tries to infer type for T by using these patterns:
            '
            '   -- If P is T, then infer A for T
            '   -- If P is G(Of T) and A is G(Of X), then infer X for T
            '   -- If P is Array Of T, and A is Array Of X, then infer X for T
            '   -- If P is ByRef T, then infer A for T
            Private Function InferTypeArgumentsFromArgumentDirectly(
                argumentLocation As SyntaxNode,
                argumentType As TypeSymbol,
                argumentTypeByAssumption As Boolean,
                parameterType As TypeSymbol,
                param As ParameterSymbol,
                digThroughToBasesAndImplements As MatchGenericArgumentToParameter,
                inferenceRestrictions As RequiredConversion
            ) As Boolean
 
                If argumentType Is Nothing OrElse argumentType.IsVoidType() Then
                    ' We should never be able to infer a value from something that doesn't provide a value, e.g:
                    ' Goo(Of T) can't be passed Sub bar(), as in Goo(Bar())
                    Return False
                End If
 
                ' If a generic method is parameterized by T, an argument of type A matching a parameter of type
                ' P can be used to infer a type for T by these patterns:
                '
                '   -- If P is T, then infer A for T
                '   -- If P is G(Of T) and A is G(Of X), then infer X for T
                '   -- If P is Array Of T, and A is Array Of X, then infer X for T
                '   -- If P is ByRef T, then infer A for T
                '   -- If P is (T, T) and A is (X, X), then infer X for T
 
                If parameterType.IsTypeParameter() Then
 
                    RegisterTypeParameterHint(
                        DirectCast(parameterType, TypeParameterSymbol),
                        argumentType,
                        argumentTypeByAssumption,
                        argumentLocation,
                        param,
                        False,
                        inferenceRestrictions)
                    Return True
                End If
 
                Dim parameterElementTypes As ImmutableArray(Of TypeSymbol) = Nothing
                Dim argumentElementTypes As ImmutableArray(Of TypeSymbol) = Nothing
 
                If parameterType.GetNullableUnderlyingTypeOrSelf().TryGetElementTypesIfTupleOrCompatible(parameterElementTypes) AndAlso
                   If(parameterType.IsNullableType(), argumentType.GetNullableUnderlyingTypeOrSelf(), argumentType).
                       TryGetElementTypesIfTupleOrCompatible(argumentElementTypes) Then
 
                    If parameterElementTypes.Length <> argumentElementTypes.Length Then
                        Return False
                    End If
 
                    For typeArgumentIndex As Integer = 0 To parameterElementTypes.Length - 1
 
                        Dim parameterElementType = parameterElementTypes(typeArgumentIndex)
                        Dim argumentElementType = argumentElementTypes(typeArgumentIndex)
 
                        ' propagate restrictions to the elements
                        If Not InferTypeArgumentsFromArgument(
                                        argumentLocation,
                                        argumentElementType,
                                        argumentTypeByAssumption,
                                        parameterElementType,
                                        param,
                                        digThroughToBasesAndImplements,
                                        inferenceRestrictions
                          ) Then
                            Return False
                        End If
                    Next
 
                    Return True
 
                ElseIf parameterType.Kind = SymbolKind.NamedType Then
                    ' e.g. handle goo(of T)(x as Bar(Of T)) We need to dig into Bar(Of T)
 
                    Dim parameterTypeAsNamedType = DirectCast(parameterType.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol)
 
                    If parameterTypeAsNamedType.IsGenericType Then
 
                        Dim argumentTypeAsNamedType = If(argumentType.Kind = SymbolKind.NamedType, DirectCast(argumentType.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol), Nothing)
 
                        If argumentTypeAsNamedType IsNot Nothing AndAlso argumentTypeAsNamedType.IsGenericType Then
                            If argumentTypeAsNamedType.OriginalDefinition.IsSameTypeIgnoringAll(parameterTypeAsNamedType.OriginalDefinition) Then
 
                                Do
 
                                    For typeArgumentIndex As Integer = 0 To parameterTypeAsNamedType.Arity - 1 Step 1
 
                                        ' The following code is subtle. Let's recap what's going on...
                                        ' We've so far encountered some context, e.g. "_" or "ICovariant(_)"
                                        ' or "ByRef _" or the like. This context will have given us some TypeInferenceRestrictions.
                                        ' Now, inside the context, we've discovered a generic binding "G(Of _,_,_)"
                                        ' and we have to apply extra restrictions to each of those subcontexts.
                                        ' For non-variant parameters it's easy: the subcontexts just acquire the Identity constraint.
                                        ' For variant parameters it's more subtle. First, we have to strengthen the
                                        ' restrictions to require reference conversion (rather than just VB conversion or
                                        ' whatever it was). Second, if it was an In parameter, then we have to invert
                                        ' the sense.
                                        '
 
                                        ' Processing of generics is tricky in the case that we've already encountered
                                        ' a "ByRef _". From that outer "ByRef _" we will have inferred the restriction
                                        ' "AnyConversionAndReverse", so that the argument could be copied into the parameter
                                        ' and back again. But now consider if we find a generic inside that ByRef, e.g.
                                        ' if it had been "ByRef x as G(Of T)" then what should we do? More specifically, consider a case
                                        '    "Sub f(Of T)(ByRef x as G(Of T))"  invoked with some   "dim arg as G(Of Hint)".
                                        ' What's needed for any candidate for T is that G(Of Hint) be convertible to
                                        ' G(Of Candidate), and vice versa for the copyback.
                                        '
                                        ' But then what should we write down for the hints? The problem is that hints inhere
                                        ' to the generic parameter T, not to the function parameter G(Of T). So we opt for a
                                        ' safe approximation: we just require CLR identity between a candidate and the hint.
                                        ' This is safe but is a little overly-strict. For example:
                                        '    Class G(Of T)
                                        '       Public Shared Widening Operator CType(ByVal x As G(Of T)) As G(Of Animal)
                                        '       Public Shared Widening Operator CType(ByVal x As G(Of Animal)) As G(Of T)
                                        '    Sub inf(Of T)(ByRef x as G(Of T), ByVal y as T)
                                        '    ...
                                        '    inf(New G(Of Car), New Animal)
                                        '    inf(Of Animal)(New G(Of Car), New Animal)
                                        ' Then the hints will be "T:{Car=, Animal+}" and they'll result in inference-failure,
                                        ' even though the explicitly-provided T=Animal ends up working.
                                        '
                                        ' Well, it's the best we can do without some major re-architecting of the way
                                        ' hints and type-inference works. That's because all our hints inhere to the
                                        ' type parameter T; in an ideal world, the ByRef hint would inhere to the parameter.
                                        ' But I don't think we'll ever do better than this, just because trying to do
                                        ' type inference inferring to arguments/parameters becomes exponential.
                                        ' Variance generic parameters will work the same.
 
                                        ' Dev10#595234: each Param'sInferenceRestriction is found as a modification of the surrounding InferenceRestriction:
                                        Dim paramInferenceRestrictions As RequiredConversion
 
                                        Select Case parameterTypeAsNamedType.TypeParameters(typeArgumentIndex).Variance
                                            Case VarianceKind.In
 
                                                paramInferenceRestrictions = Conversions.InvertConversionRequirement(
                                                Conversions.StrengthenConversionRequirementToReference(inferenceRestrictions))
 
                                            Case VarianceKind.Out
 
                                                paramInferenceRestrictions = Conversions.StrengthenConversionRequirementToReference(inferenceRestrictions)
 
                                            Case Else
                                                Debug.Assert(VarianceKind.None = parameterTypeAsNamedType.TypeParameters(typeArgumentIndex).Variance)
                                                paramInferenceRestrictions = RequiredConversion.Identity
                                        End Select
 
                                        Dim _DigThroughToBasesAndImplements As MatchGenericArgumentToParameter
 
                                        If paramInferenceRestrictions = RequiredConversion.Reference Then
                                            _DigThroughToBasesAndImplements = MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter
                                        ElseIf paramInferenceRestrictions = RequiredConversion.ReverseReference Then
                                            _DigThroughToBasesAndImplements = MatchGenericArgumentToParameter.MatchArgumentToBaseOfGenericParameter
                                        Else
                                            _DigThroughToBasesAndImplements = MatchGenericArgumentToParameter.MatchGenericArgumentToParameterExactly
                                        End If
 
                                        If Not InferTypeArgumentsFromArgument(
                                                                        argumentLocation,
                                                                        argumentTypeAsNamedType.TypeArgumentWithDefinitionUseSiteDiagnostics(typeArgumentIndex, Me.UseSiteInfo),
                                                                        argumentTypeByAssumption,
                                                                        parameterTypeAsNamedType.TypeArgumentWithDefinitionUseSiteDiagnostics(typeArgumentIndex, Me.UseSiteInfo),
                                                                        param,
                                                                        _DigThroughToBasesAndImplements,
                                                                        paramInferenceRestrictions
                                                                  ) Then
                                            ' TODO: Would it make sense to continue through other type arguments even if inference failed for
                                            '       the current one?
                                            Return False
                                        End If
 
                                    Next
 
                                    ' Do not forget about type parameters of containing type
                                    parameterTypeAsNamedType = parameterTypeAsNamedType.ContainingType
                                    argumentTypeAsNamedType = argumentTypeAsNamedType.ContainingType
 
                                Loop While parameterTypeAsNamedType IsNot Nothing
 
                                Debug.Assert(parameterTypeAsNamedType Is Nothing AndAlso argumentTypeAsNamedType Is Nothing)
 
                                Return True
                            End If
 
                        ElseIf parameterTypeAsNamedType.IsNullableType() Then
 
                            ' we reach here when the ParameterType is an instantiation of Nullable,
                            ' and the argument type is NOT a generic type.
 
                            ' lwischik: ??? what do array elements have to do with nullables?
                            Return InferTypeArgumentsFromArgument(
                                argumentLocation,
                                argumentType,
                                argumentTypeByAssumption,
                                parameterTypeAsNamedType.GetNullableUnderlyingType(),
                                param,
                                digThroughToBasesAndImplements,
                                Conversions.CombineConversionRequirements(inferenceRestrictions, RequiredConversion.ArrayElement))
 
                        End If
 
                        Return False
                    End If
 
                ElseIf parameterType.IsArrayType() Then
                    If argumentType.IsArrayType() Then
                        Dim parameterArray = DirectCast(parameterType, ArrayTypeSymbol)
                        Dim argumentArray = DirectCast(argumentType, ArrayTypeSymbol)
                        Dim argumentIsAarrayLiteral = TypeOf argumentArray Is ArrayLiteralTypeSymbol
 
                        ' We can ignore IsSZArray value for an inferred type of an array literal as long as its rank matches.
                        If parameterArray.Rank = argumentArray.Rank AndAlso
                           (argumentIsAarrayLiteral OrElse parameterArray.IsSZArray = argumentArray.IsSZArray) Then
                            Return InferTypeArgumentsFromArgument(
                                    argumentLocation,
                                    argumentArray.ElementType,
                                    argumentTypeByAssumption,
                                    parameterArray.ElementType,
                                    param,
                                    digThroughToBasesAndImplements,
                                    Conversions.CombineConversionRequirements(inferenceRestrictions, If(argumentIsAarrayLiteral, RequiredConversion.Any, RequiredConversion.ArrayElement)))
                        End If
                    End If
 
                    Return False
 
                End If
 
                Return True
            End Function
 
            ' Given an argument type, a parameter type, and a set of (possibly unbound) type arguments
            ' to a generic method, infer type arguments corresponding to type parameters that occur
            ' in the parameter type.
            '
            ' A return value of false indicates that inference fails.
            '
            ' This routine is given an argument e.g. "List(Of IEnumerable(Of Int))",
            ' and a parameter e.g. "IEnumerable(Of IEnumerable(Of T))".
            ' The task is to infer hints for T, e.g. "T=int".
            ' This function takes care of allowing (in this example) List(Of _) to match IEnumerable(Of _).
            ' As for the real work, i.e. matching the contents, we invoke "InferTypeArgumentsFromArgumentDirectly"
            ' to do that.
            '
            ' Note: this function returns "false" if it failed to pattern-match between argument and parameter type,
            ' and "true" if it succeeded.
            ' Success in pattern-matching may or may not produce type-hints for generic parameters.
            ' If it happened not to produce any type-hints, then maybe other argument/parameter pairs will have produced
            ' their own type hints that allow inference to succeed, or maybe no-one else will have produced type hints,
            ' or maybe other people will have produced conflicting type hints. In those cases, we'd return True from
            ' here (to show success at pattern-matching) and leave the downstream code to produce an error message about
            ' failing to infer T.
            Friend Function InferTypeArgumentsFromArgument(
                argumentLocation As SyntaxNode,
                argumentType As TypeSymbol,
                argumentTypeByAssumption As Boolean,
                parameterType As TypeSymbol,
                param As ParameterSymbol,
                digThroughToBasesAndImplements As MatchGenericArgumentToParameter,
                inferenceRestrictions As RequiredConversion
            ) As Boolean
 
                If Not RefersToGenericParameterToInferArgumentFor(parameterType) Then
                    Return True
                End If
 
                ' First try to the things directly. Only if this fails will we bother searching for things like List->IEnumerable.
                Dim Inferred As Boolean = InferTypeArgumentsFromArgumentDirectly(
                    argumentLocation,
                    argumentType,
                    argumentTypeByAssumption,
                    parameterType,
                    param,
                    digThroughToBasesAndImplements,
                    inferenceRestrictions)
 
                If Inferred Then
                    Return True
                End If
 
                If parameterType.IsTypeParameter() Then
                    ' If we failed to match an argument against a generic parameter T, it means that the
                    ' argument was something unmatchable, e.g. an AddressOf.
                    Return False
                End If
 
                ' If we didn't find a direct match, we will have to look in base classes for a match.
                ' We'll either fix ParameterType and look amongst the bases of ArgumentType,
                ' or we'll fix ArgumentType and look amongst the bases of ParameterType,
                ' depending on the "DigThroughToBasesAndImplements" flag. This flag is affected by
                ' covariance and contravariance...
 
                If digThroughToBasesAndImplements = MatchGenericArgumentToParameter.MatchGenericArgumentToParameterExactly Then
                    Return False
                End If
 
                ' Special handling for Anonymous Delegates.
                If argumentType IsNot Nothing AndAlso argumentType.IsDelegateType() AndAlso parameterType.IsDelegateType() AndAlso
                   digThroughToBasesAndImplements = MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter AndAlso
                   (inferenceRestrictions = RequiredConversion.Any OrElse inferenceRestrictions = RequiredConversion.AnyReverse OrElse
                    inferenceRestrictions = RequiredConversion.AnyAndReverse) Then
 
                    Dim argumentDelegateType = DirectCast(argumentType, NamedTypeSymbol)
                    Dim argumentInvokeProc As MethodSymbol = argumentDelegateType.DelegateInvokeMethod
                    Dim parameterDelegateType = DirectCast(parameterType, NamedTypeSymbol)
                    Dim parameterInvokeProc As MethodSymbol = parameterDelegateType.DelegateInvokeMethod
 
                    Debug.Assert(argumentInvokeProc IsNot Nothing OrElse Not argumentDelegateType.IsAnonymousType)
 
                    ' Note, null check for parameterInvokeDeclaration should also filter out MultiCastDelegate type.
                    If argumentDelegateType.IsAnonymousType AndAlso Not parameterDelegateType.IsAnonymousType AndAlso
                       parameterInvokeProc IsNot Nothing AndAlso parameterInvokeProc.GetUseSiteInfo().DiagnosticInfo Is Nothing Then
                        ' Some trickery relating to the fact that anonymous delegates can be converted to any delegate type.
                        ' We are trying to match the anonymous delegate "BaseSearchType" onto the delegate "FixedType". e.g.
                        ' Dim f = function(i as integer) i   // ArgumentType = VB$AnonymousDelegate`2(Of Integer,Integer)
                        ' inf(f)                             // ParameterType might be e.g. D(Of T) for some function inf(Of T)(f as D(Of T))
                        '                                    // maybe defined as Delegate Function D(Of T)(x as T) as T.
                        ' We're looking to achieve the same functionality in pattern-matching these types as we already
                        ' have for calling "inf(function(i as integer) i)" directly.
                        ' It allows any VB conversion from param-of-fixed-type to param-of-base-type (not just reference conversions).
                        ' But it does allow a zero-argument BaseSearchType to be used for a FixedType with more.
                        ' And it does allow a function BaseSearchType to be used for a sub FixedType.
                        '
                        ' Anyway, the plan is to match each of the parameters in the ArgumentType delegate
                        ' to the equivalent parameters in the ParameterType delegate, and also match the return types.
                        '
                        ' This only works for "ConversionRequired::Any", i.e. using VB conversion semantics. It doesn't work for
                        ' reference conversions. As for the AnyReverse/AnyAndReverse, well, in Orcas that was guaranteed
                        ' to fail type inference (i.e. return a false from this function). In Dev10 we will let it succeed
                        ' with some inferred types, for the sake of better error messages, even though we know that ultimately
                        ' it will fail (because no non-anonymous delegate type can be converted to a delegate type).
                        Dim argumentParams As ImmutableArray(Of ParameterSymbol) = argumentInvokeProc.Parameters
                        Dim parameterParams As ImmutableArray(Of ParameterSymbol) = parameterInvokeProc.Parameters
 
                        If parameterParams.Length <> argumentParams.Length AndAlso argumentParams.Length <> 0 Then
                            ' If parameter-counts are mismatched then it's a failure.
                            ' Exception: Zero-argument relaxation: we allow a parameterless VB$AnonymousDelegate argument
                            ' to be supplied to a function which expects a parameterfull delegate.
                            Return False
                        End If
 
                        ' First we'll check that the argument types all match.
                        For i As Integer = 0 To argumentParams.Length - 1
                            If argumentParams(i).IsByRef <> parameterParams(i).IsByRef Then
                                ' Require an exact match between ByRef/ByVal, since that's how type inference of lambda expressions works.
                                Return False
                            End If
 
                            If Not InferTypeArgumentsFromArgument(
                                        argumentLocation,
                                        argumentParams(i).Type,
                                        argumentTypeByAssumption,
                                        parameterParams(i).Type,
                                        param,
                                        MatchGenericArgumentToParameter.MatchArgumentToBaseOfGenericParameter,
                                        RequiredConversion.AnyReverse) Then  ' AnyReverse: contravariance in delegate arguments
                                Return False
                            End If
                        Next
 
                        ' Now check that the return type matches.
                        ' Note: we allow a *function* VB$AnonymousDelegate to be supplied to a function which expects a *sub* delegate.
 
                        If parameterInvokeProc.IsSub Then
                            ' A *sub* delegate parameter can accept either a *function* or a *sub* argument:
                            Return True
                        ElseIf argumentInvokeProc.IsSub Then
                            ' A *function* delegate parameter cannot accept a *sub* argument.
                            Return False
                        Else
                            ' Otherwise, a function argument VB$AnonymousDelegate was supplied to a function parameter:
                            Return InferTypeArgumentsFromArgument(
                                        argumentLocation,
                                        argumentInvokeProc.ReturnType,
                                        argumentTypeByAssumption,
                                        parameterInvokeProc.ReturnType,
                                        param,
                                        MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter,
                                        RequiredConversion.Any) ' Any: covariance in delegate returns
                        End If
                    End If
                End If
 
                ' MatchBaseOfGenericArgumentToParameter: used for covariant situations,
                ' e.g. matching argument "List(Of _)" to parameter "ByVal x as IEnumerable(Of _)".
                '
                ' Otherwise, MatchArgumentToBaseOfGenericParameter, used for contravariant situations,
                ' e.g. when matching argument "Action(Of IEnumerable(Of _))" to parameter "ByVal x as Action(Of List(Of _))".
 
                Dim fContinue As Boolean = False
 
                If digThroughToBasesAndImplements = MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter Then
                    fContinue = FindMatchingBase(argumentType, parameterType)
                Else
                    fContinue = FindMatchingBase(parameterType, argumentType)
                End If
 
                If Not fContinue Then
                    Return False
                End If
 
                ' NOTE: baseSearchType was a REFERENCE, to either ArgumentType or ParameterType.
                ' Therefore the above statement has altered either ArgumentType or ParameterType.
                Return InferTypeArgumentsFromArgumentDirectly(
                            argumentLocation,
                            argumentType,
                            argumentTypeByAssumption,
                            parameterType,
                            param,
                            digThroughToBasesAndImplements,
                            inferenceRestrictions)
            End Function
 
            Private Function FindMatchingBase(
                ByRef baseSearchType As TypeSymbol,
                ByRef fixedType As TypeSymbol
            ) As Boolean
 
                Dim fixedTypeAsNamedType = If(fixedType.Kind = SymbolKind.NamedType, DirectCast(fixedType, NamedTypeSymbol), Nothing)
 
                If fixedTypeAsNamedType Is Nothing OrElse Not fixedTypeAsNamedType.IsGenericType Then
                    ' If the fixed candidate isn't a generic (e.g. matching argument IList(Of String) to non-generic parameter IList),
                    ' then we won't learn anything about generic type parameters here:
                    Return False
                End If
 
                Dim fixedTypeTypeKind As TypeKind = fixedType.TypeKind
 
                If fixedTypeTypeKind <> TypeKind.Class AndAlso fixedTypeTypeKind <> TypeKind.Interface Then
                    ' Whatever "BaseSearchType" is, it can only inherit from "FixedType" if FixedType is a class/interface.
                    ' (it's impossible to inherit from anything else).
                    Return False
                End If
 
                Dim baseSearchTypeKind As SymbolKind = baseSearchType.Kind
 
                If baseSearchTypeKind <> SymbolKind.NamedType AndAlso baseSearchTypeKind <> SymbolKind.TypeParameter AndAlso
                   Not (baseSearchTypeKind = SymbolKind.ArrayType AndAlso DirectCast(baseSearchType, ArrayTypeSymbol).IsSZArray) Then
                    ' The things listed above are the only ones that have bases that could ever lead anywhere useful.
                    ' NamedType is satisfied by interfaces, structures, enums, delegates and modules as well as just classes.
                    Return False
                End If
 
                If baseSearchType.IsSameTypeIgnoringAll(fixedType) Then
                    ' If the types checked were already identical, then exit
                    Return False
                End If
 
                ' Otherwise, if we got through all the above tests, then it really is worth searching through the base
                ' types to see if that helps us find a match.
                Dim matchingBase As TypeSymbol = Nothing
 
                If fixedTypeTypeKind = TypeKind.Class Then
                    FindMatchingBaseClass(baseSearchType, fixedType, matchingBase)
                Else
                    Debug.Assert(fixedTypeTypeKind = TypeKind.Interface)
                    FindMatchingBaseInterface(baseSearchType, fixedType, matchingBase)
                End If
 
                If matchingBase Is Nothing Then
                    Return False
                End If
 
                ' And this is what we found
                baseSearchType = matchingBase
 
                Return True
            End Function
 
            Private Shared Function SetMatchIfNothingOrEqual(type As TypeSymbol, ByRef match As TypeSymbol) As Boolean
                If match Is Nothing Then
                    match = type
                    Return True
                ElseIf match.IsSameTypeIgnoringAll(type) Then
                    Return True
                Else
                    match = Nothing
                    Return False
                End If
            End Function
 
            ''' <summary>
            ''' Returns False if the search should be cancelled.
            ''' </summary>
            Private Function FindMatchingBaseInterface(derivedType As TypeSymbol, baseInterface As TypeSymbol, ByRef match As TypeSymbol) As Boolean
 
                Select Case derivedType.Kind
                    Case SymbolKind.TypeParameter
                        For Each constraint In DirectCast(derivedType, TypeParameterSymbol).ConstraintTypesWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
                            If constraint.OriginalDefinition.IsSameTypeIgnoringAll(baseInterface.OriginalDefinition) Then
                                If Not SetMatchIfNothingOrEqual(constraint, match) Then
                                    Return False
                                End If
                            End If
 
                            If Not FindMatchingBaseInterface(constraint, baseInterface, match) Then
                                Return False
                            End If
                        Next
 
                    Case Else
                        For Each [interface] In derivedType.AllInterfacesWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
                            If [interface].OriginalDefinition.IsSameTypeIgnoringAll(baseInterface.OriginalDefinition) Then
                                If Not SetMatchIfNothingOrEqual([interface], match) Then
                                    Return False
                                End If
                            End If
                        Next
 
                End Select
 
                Return True
            End Function
 
            ''' <summary>
            ''' Returns False if the search should be cancelled.
            ''' </summary>
            Private Function FindMatchingBaseClass(derivedType As TypeSymbol, baseClass As TypeSymbol, ByRef match As TypeSymbol) As Boolean
                Select Case derivedType.Kind
                    Case SymbolKind.TypeParameter
                        For Each constraint In DirectCast(derivedType, TypeParameterSymbol).ConstraintTypesWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
                            If constraint.OriginalDefinition.IsSameTypeIgnoringAll(baseClass.OriginalDefinition) Then
                                If Not SetMatchIfNothingOrEqual(constraint, match) Then
                                    Return False
                                End If
                            End If
 
                            ' TODO: Do we need to continue even if we already have a matching base class?
                            '       It looks like Dev10 continues.
                            If Not FindMatchingBaseClass(constraint, baseClass, match) Then
                                Return False
                            End If
                        Next
 
                    Case Else
 
                        Dim baseType As NamedTypeSymbol = derivedType.BaseTypeWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
 
                        While baseType IsNot Nothing
                            If baseType.OriginalDefinition.IsSameTypeIgnoringAll(baseClass.OriginalDefinition) Then
                                If Not SetMatchIfNothingOrEqual(baseType, match) Then
                                    Return False
                                End If
                                Exit While
                            End If
 
                            baseType = baseType.BaseTypeWithDefinitionUseSiteDiagnostics(Me.UseSiteInfo)
                        End While
 
                End Select
 
                Return True
            End Function
 
            Public Function InferTypeArgumentsFromAddressOfArgument(
                argument As BoundExpression,
                parameterType As TypeSymbol,
                param As ParameterSymbol
            ) As Boolean
 
                If parameterType.IsDelegateType() Then
                    Dim delegateType = DirectCast(ConstructParameterTypeIfNeeded(parameterType), NamedTypeSymbol)
 
                    ' Now find the invoke method of the delegate
                    Dim invokeMethod As MethodSymbol = delegateType.DelegateInvokeMethod
 
                    If invokeMethod Is Nothing OrElse invokeMethod.GetUseSiteInfo().DiagnosticInfo IsNot Nothing Then
                        ' If we don't have an Invoke method, just bail.
                        Return False
                    End If
 
                    Dim returnType As TypeSymbol = invokeMethod.ReturnType
 
                    ' If the return type doesn't refer to parameters, no inference required.
                    If Not RefersToGenericParameterToInferArgumentFor(returnType) Then
                        Return True
                    End If
 
                    Dim addrOf = DirectCast(argument, BoundAddressOfOperator)
                    Dim fromMethod As MethodSymbol = Nothing
                    Dim methodConversions As MethodConversionKind = MethodConversionKind.Identity
 
                    Dim matchingMethod As KeyValuePair(Of MethodSymbol, MethodConversionKind) = Binder.ResolveMethodForDelegateInvokeFullAndRelaxed(
                        addrOf,
                        invokeMethod,
                        ignoreMethodReturnType:=True,
                        diagnostics:=BindingDiagnosticBag.Discarded)
 
                    fromMethod = matchingMethod.Key
                    methodConversions = matchingMethod.Value
 
                    If fromMethod Is Nothing OrElse (methodConversions And MethodConversionKind.AllErrorReasons) <> 0 OrElse
                       (addrOf.Binder.OptionStrict = OptionStrict.On AndAlso Conversions.IsNarrowingMethodConversion(methodConversions, isForAddressOf:=True)) Then
                        Return False
                    End If
 
                    If fromMethod.IsSub Then
                        ReportNotFailedInferenceDueToObject()
                        Return True
                    End If
 
                    Dim targetReturnType As TypeSymbol = fromMethod.ReturnType
 
                    If RefersToGenericParameterToInferArgumentFor(targetReturnType) Then
                        ' Return false if we didn't make any inference progress.
                        Return False
                    End If
 
                    Return InferTypeArgumentsFromArgument(
                                argument.Syntax,
                                targetReturnType,
                                argumentTypeByAssumption:=False,
                                parameterType:=returnType,
                                param:=param,
                                digThroughToBasesAndImplements:=MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter,
                                inferenceRestrictions:=RequiredConversion.Any)
                End If
 
                ' We did not infer anything for this addressOf, AddressOf can never be of type Object, so mark inference
                ' as not failed due to object.
                ReportNotFailedInferenceDueToObject()
                Return True
 
            End Function
 
            Public Function InferTypeArgumentsFromLambdaArgument(
                argument As BoundExpression,
                parameterType As TypeSymbol,
                param As ParameterSymbol
            ) As Boolean
 
                Debug.Assert(argument.Kind = BoundKind.UnboundLambda OrElse
                             argument.Kind = BoundKind.QueryLambda OrElse
                             argument.Kind = BoundKind.GroupTypeInferenceLambda)
 
                If parameterType.IsTypeParameter() Then
                    Dim anonymousLambdaType As TypeSymbol = Nothing
 
                    Select Case argument.Kind
                        Case BoundKind.QueryLambda
                            ' Do not infer Anonymous Delegate type from query lambda.
 
                        Case BoundKind.GroupTypeInferenceLambda
                            ' Can't infer from this lambda.
 
                        Case BoundKind.UnboundLambda
                            ' Infer Anonymous Delegate type from unbound lambda.
                            Dim inferredAnonymousDelegate As KeyValuePair(Of NamedTypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol)) = DirectCast(argument, UnboundLambda).InferredAnonymousDelegate
 
                            If (inferredAnonymousDelegate.Value.Diagnostics.IsDefault OrElse Not inferredAnonymousDelegate.Value.Diagnostics.HasAnyErrors()) Then
 
                                Dim delegateInvokeMethod As MethodSymbol = Nothing
 
                                If inferredAnonymousDelegate.Key IsNot Nothing Then
                                    delegateInvokeMethod = inferredAnonymousDelegate.Key.DelegateInvokeMethod
                                End If
 
                                If delegateInvokeMethod IsNot Nothing AndAlso delegateInvokeMethod.ReturnType IsNot LambdaSymbol.ReturnTypeIsUnknown Then
                                    anonymousLambdaType = inferredAnonymousDelegate.Key
                                End If
                            End If
                        Case Else
                            Throw ExceptionUtilities.UnexpectedValue(argument.Kind)
                    End Select
 
                    If anonymousLambdaType IsNot Nothing Then
                        Return InferTypeArgumentsFromArgument(
                            argument.Syntax,
                            anonymousLambdaType,
                            argumentTypeByAssumption:=False,
                            parameterType:=parameterType,
                            param:=param,
                            digThroughToBasesAndImplements:=MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter,
                            inferenceRestrictions:=RequiredConversion.Any)
                    Else
                        Return True
                    End If
 
                ElseIf parameterType.IsDelegateType() Then
                    Dim parameterDelegateType = DirectCast(parameterType, NamedTypeSymbol)
 
                    ' First, we need to build a partial type substitution using the type of
                    ' arguments as they stand right now, with some of them still being uninferred.
 
                    ' TODO: Doesn't this make the inference algorithm order dependent? For example, if we were to
                    '       infer more stuff from other non-lambda arguments, we might have a better chance to have
                    '       more type information for the lambda, allowing successful lambda interpretation.
                    '       Perhaps the graph doesn't allow us to get here until all "inputs" for lambda parameters
                    '       are inferred.
                    Dim delegateType = DirectCast(ConstructParameterTypeIfNeeded(parameterDelegateType), NamedTypeSymbol)
 
                    ' Now find the invoke method of the delegate
 
                    Dim invokeMethod As MethodSymbol = delegateType.DelegateInvokeMethod
 
                    If invokeMethod Is Nothing OrElse invokeMethod.GetUseSiteInfo().DiagnosticInfo IsNot Nothing Then
                        ' If we don't have an Invoke method, just bail.
                        Return True
                    End If
 
                    Dim returnType As TypeSymbol = invokeMethod.ReturnType
 
                    ' If the return type doesn't refer to parameters, no inference required.
                    If Not RefersToGenericParameterToInferArgumentFor(returnType) Then
                        Return True
                    End If
 
                    Dim lambdaParams As ImmutableArray(Of ParameterSymbol)
 
                    Select Case argument.Kind
                        Case BoundKind.QueryLambda
                            lambdaParams = DirectCast(argument, BoundQueryLambda).LambdaSymbol.Parameters
                        Case BoundKind.GroupTypeInferenceLambda
                            lambdaParams = DirectCast(argument, GroupTypeInferenceLambda).Parameters
                        Case BoundKind.UnboundLambda
                            lambdaParams = DirectCast(argument, UnboundLambda).Parameters
                        Case Else
                            Throw ExceptionUtilities.UnexpectedValue(argument.Kind)
                    End Select
 
                    Dim delegateParams As ImmutableArray(Of ParameterSymbol) = invokeMethod.Parameters
 
                    If lambdaParams.Length > delegateParams.Length Then
                        Return True
                    End If
 
                    For i As Integer = 0 To lambdaParams.Length - 1 Step 1
                        Dim lambdaParam As ParameterSymbol = lambdaParams(i)
                        Dim delegateParam As ParameterSymbol = delegateParams(i)
 
                        If lambdaParam.Type Is Nothing Then
                            ' If a lambda parameter has no type and the delegate parameter refers
                            ' to an unbound generic parameter, we can't infer yet.
                            If RefersToGenericParameterToInferArgumentFor(delegateParam.Type) Then
                                ' Skip this type argument and other parameters will infer it or
                                ' if that doesn't happen it will report an error.
 
                                ' TODO: Why does it make sense to continue here? It looks like we can infer something from
                                '       lambda's return type based on incomplete information. Also, this 'if' is redundant,
                                '       there is nothing left to do in this loop anyway, and "continue" doesn't change anything.
                                Continue For
                            End If
                        Else
                            ' report the type of the lambda parameter to the delegate parameter.
                            ' !!! Unlike Dev10, we are using MatchArgumentToBaseOfGenericParameter because a value of generic
                            ' !!! parameter will be passed into the parameter of argument type.
                            InferTypeArgumentsFromArgument(
                                argument.Syntax,
                                lambdaParam.Type,
                                argumentTypeByAssumption:=False,
                                parameterType:=delegateParam.Type,
                                param:=param,
                                digThroughToBasesAndImplements:=MatchGenericArgumentToParameter.MatchArgumentToBaseOfGenericParameter,
                                inferenceRestrictions:=RequiredConversion.Any)
                        End If
                    Next
 
                    ' OK, now try to infer delegates return type from the lambda.
                    Dim lambdaReturnType As TypeSymbol
 
                    Select Case argument.Kind
                        Case BoundKind.QueryLambda
                            Dim queryLambda = DirectCast(argument, BoundQueryLambda)
 
                            lambdaReturnType = queryLambda.LambdaSymbol.ReturnType
                            If lambdaReturnType Is LambdaSymbol.ReturnTypePendingDelegate Then
                                lambdaReturnType = queryLambda.Expression.Type
 
                                If lambdaReturnType Is Nothing Then
                                    lambdaReturnType = queryLambda.LambdaSymbol.ContainingBinder.MakeRValue(queryLambda.Expression, Me.Diagnostic).Type
                                End If
                            End If
 
                        Case BoundKind.GroupTypeInferenceLambda
                            lambdaReturnType = DirectCast(argument, GroupTypeInferenceLambda).InferLambdaReturnType(delegateParams)
 
                        Case BoundKind.UnboundLambda
                            Dim unboundLambda = DirectCast(argument, UnboundLambda)
 
                            If unboundLambda.IsFunctionLambda Then
                                Dim inferenceSignature As New UnboundLambda.TargetSignature(delegateParams, unboundLambda.Binder.Compilation.GetSpecialType(SpecialType.System_Void), returnsByRef:=False)
                                Dim returnTypeInfo As KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol)) = unboundLambda.InferReturnType(inferenceSignature)
 
                                If Not returnTypeInfo.Value.Diagnostics.IsDefault AndAlso returnTypeInfo.Value.Diagnostics.HasAnyErrors() Then
                                    lambdaReturnType = Nothing
 
                                    ' Let's keep return type inference errors
                                    Me.Diagnostic.AddRange(returnTypeInfo.Value)
 
                                ElseIf returnTypeInfo.Key Is LambdaSymbol.ReturnTypeIsUnknown Then
                                    lambdaReturnType = Nothing
 
                                Else
                                    Dim boundLambda As BoundLambda = unboundLambda.Bind(New UnboundLambda.TargetSignature(inferenceSignature.ParameterTypes,
                                                                                                                          inferenceSignature.ParameterIsByRef,
                                                                                                                          returnTypeInfo.Key,
                                                                                                                          returnsByRef:=False))
 
                                    Debug.Assert(boundLambda.LambdaSymbol.ReturnType Is returnTypeInfo.Key)
                                    If Not boundLambda.HasErrors AndAlso Not boundLambda.Diagnostics.Diagnostics.HasAnyErrors Then
                                        lambdaReturnType = returnTypeInfo.Key
 
                                        ' Let's keep return type inference warnings, if any.
                                        Me.Diagnostic.AddRange(returnTypeInfo.Value)
                                        Me.Diagnostic.AddDependencies(boundLambda.Diagnostics.Dependencies)
                                    Else
                                        lambdaReturnType = Nothing
 
                                        ' Let's preserve diagnostics that caused the failure
                                        If Not boundLambda.Diagnostics.Diagnostics.IsDefaultOrEmpty Then
                                            Me.Diagnostic.AddRange(boundLambda.Diagnostics)
                                        End If
                                    End If
                                End If
 
                                ' But in the case of async/iterator lambdas, e.g. pass "Async Function() 1" to a parameter
                                ' of type "Func(Of Task(Of T))" then we have to dig in further and match 1 to T...
                                If (unboundLambda.Flags And (SourceMemberFlags.Async Or SourceMemberFlags.Iterator)) <> 0 AndAlso
                                        lambdaReturnType IsNot Nothing AndAlso lambdaReturnType.Kind = SymbolKind.NamedType AndAlso
                                        returnType IsNot Nothing AndAlso returnType.Kind = SymbolKind.NamedType Then
 
                                    ' By this stage we know that
                                    '   * we have an async/iterator lambda argument
                                    '   * the parameter-to-match is a delegate type whose result type refers to generic parameters
                                    ' The parameter might be a delegate with result type e.g. "Task(Of T)" in which case we have
                                    ' to dig in. Or it might be a delegate with result type "T" in which case we
                                    ' don't dig in.
                                    Dim lambdaReturnNamedType = DirectCast(lambdaReturnType, NamedTypeSymbol)
                                    Dim returnNamedType = DirectCast(returnType, NamedTypeSymbol)
                                    If lambdaReturnNamedType.Arity = 1 AndAlso
                                            IsSameTypeIgnoringAll(lambdaReturnNamedType.OriginalDefinition,
                                                                              returnNamedType.OriginalDefinition) Then
 
                                        ' We can assume that the lambda will have return type Task(Of T) or IEnumerable(Of T)
                                        ' or IEnumerator(Of T) as appropriate. That's already been ensured by the lambda-interpretation.
                                        Debug.Assert(TypeSymbol.Equals(lambdaReturnNamedType.OriginalDefinition, argument.GetBinderFromLambda().Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T), TypeCompareKind.ConsiderEverything) OrElse
                                                     TypeSymbol.Equals(lambdaReturnNamedType.OriginalDefinition, argument.GetBinderFromLambda().Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T), TypeCompareKind.ConsiderEverything) OrElse
                                                     TypeSymbol.Equals(lambdaReturnNamedType.OriginalDefinition, argument.GetBinderFromLambda().Compilation.GetSpecialType(SpecialType.System_Collections_Generic_IEnumerator_T), TypeCompareKind.ConsiderEverything))
 
                                        lambdaReturnType = lambdaReturnNamedType.TypeArgumentWithDefinitionUseSiteDiagnostics(0, Me.UseSiteInfo)
                                        returnType = returnNamedType.TypeArgumentWithDefinitionUseSiteDiagnostics(0, Me.UseSiteInfo)
                                    End If
 
                                End If
 
                            Else
                                lambdaReturnType = Nothing
 
                                If Not invokeMethod.IsSub AndAlso (unboundLambda.Flags And SourceMemberFlags.Async) <> 0 Then
                                    Dim boundLambda As BoundLambda = unboundLambda.Bind(New UnboundLambda.TargetSignature(delegateParams,
                                                                            unboundLambda.Binder.Compilation.GetSpecialType(SpecialType.System_Void),
                                                                            returnsByRef:=False))
 
                                    If Not boundLambda.HasErrors AndAlso Not boundLambda.Diagnostics.Diagnostics.HasAnyErrors() Then
                                        If _asyncLambdaSubToFunctionMismatch Is Nothing Then
                                            _asyncLambdaSubToFunctionMismatch = New HashSet(Of BoundExpression)(ReferenceEqualityComparer.Instance)
                                        End If
 
                                        _asyncLambdaSubToFunctionMismatch.Add(unboundLambda)
                                    End If
                                End If
                            End If
                        Case Else
                            Throw ExceptionUtilities.UnexpectedValue(argument.Kind)
                    End Select
 
                    If lambdaReturnType Is Nothing Then
                        ' Inference failed, give up.
                        Return False
                    End If
 
                    If lambdaReturnType.IsErrorType() Then
                        Return True
                    End If
 
                    ' Now infer from the result type
                    ' not ArgumentTypeByAssumption ??? lwischik: but maybe it should...
                    Return InferTypeArgumentsFromArgument(
                            argument.Syntax,
                            lambdaReturnType,
                            argumentTypeByAssumption:=False,
                            parameterType:=returnType,
                            param:=param, digThroughToBasesAndImplements:=MatchGenericArgumentToParameter.MatchBaseOfGenericArgumentToParameter,
                            inferenceRestrictions:=RequiredConversion.Any)
 
                ElseIf TypeSymbol.Equals(parameterType.OriginalDefinition, argument.GetBinderFromLambda().Compilation.GetWellKnownType(WellKnownType.System_Linq_Expressions_Expression_T), TypeCompareKind.ConsiderEverything) Then
                    ' If we've got an Expression(Of T), skip through to T
                    Return InferTypeArgumentsFromLambdaArgument(argument, DirectCast(parameterType, NamedTypeSymbol).TypeArgumentWithDefinitionUseSiteDiagnostics(0, Me.UseSiteInfo), param)
                End If
 
                Return True
            End Function
 
            Public Function ConstructParameterTypeIfNeeded(parameterType As TypeSymbol) As TypeSymbol
                ' First, we need to build a partial type substitution using the type of
                ' arguments as they stand right now, with some of them still being uninferred.
 
                Dim methodSymbol As MethodSymbol = Candidate
                Dim typeArguments = ArrayBuilder(Of TypeWithModifiers).GetInstance(_typeParameterNodes.Length)
 
                For i As Integer = 0 To _typeParameterNodes.Length - 1 Step 1
                    Dim typeNode As TypeParameterNode = _typeParameterNodes(i)
                    Dim newType As TypeSymbol
 
                    If typeNode Is Nothing OrElse typeNode.CandidateInferredType Is Nothing Then
                        'No substitution
                        newType = methodSymbol.TypeParameters(i)
                    Else
                        newType = typeNode.CandidateInferredType
                    End If
 
                    typeArguments.Add(New TypeWithModifiers(newType))
                Next
 
                Dim partialSubstitution = TypeSubstitution.CreateAdditionalMethodTypeParameterSubstitution(methodSymbol.ConstructedFrom, typeArguments.ToImmutableAndFree())
 
                ' Now we apply the partial substitution to the delegate type, leaving uninferred type parameters as is
                Return parameterType.InternalSubstituteTypeParameters(partialSubstitution).Type
            End Function
 
            Public Sub ReportAmbiguousInferenceError(typeInfos As ArrayBuilder(Of DominantTypeDataTypeInference))
                Debug.Assert(typeInfos.Count() >= 2, "Must have at least 2 elements in the list")
 
                ' Since they get added fifo, we need to walk the list backward.
                For i As Integer = 1 To typeInfos.Count - 1 Step 1
                    Dim currentTypeInfo As DominantTypeDataTypeInference = typeInfos(i)
 
                    If Not currentTypeInfo.InferredFromObject Then
                        ReportNotFailedInferenceDueToObject()
                        ' TODO: Should we exit the loop? For some reason Dev10 keeps going.
                    End If
                Next
            End Sub
 
            Public Sub ReportIncompatibleInferenceError(
                typeInfos As ArrayBuilder(Of DominantTypeDataTypeInference))
                If typeInfos.Count < 1 Then
                    Return
                End If
 
                ' Since they get added fifo, we need to walk the list backward.
                For i As Integer = 1 To typeInfos.Count - 1 Step 1
                    Dim currentTypeInfo As DominantTypeDataTypeInference = typeInfos(i)
 
                    If Not currentTypeInfo.InferredFromObject Then
                        ReportNotFailedInferenceDueToObject()
                        ' TODO: Should we exit the loop? For some reason Dev10 keeps going.
                    End If
                Next
            End Sub
 
            Public Sub RegisterErrorReasons(inferenceErrorReasons As InferenceErrorReasons)
                _inferenceErrorReasons = _inferenceErrorReasons Or inferenceErrorReasons
            End Sub
 
        End Class
    End Class
End Namespace