File: Binding\Binder_Lambda.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 System.Threading
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    Partial Friend Class Binder
 
        Private Function BindLambdaExpression(
             node As LambdaExpressionSyntax,
             diagnostics As BindingDiagnosticBag
         ) As BoundExpression
 
            Const asyncIterator As SourceMemberFlags = SourceMemberFlags.Async Or SourceMemberFlags.Iterator
 
            ' Decode the modifiers.
            Dim modifiers As SourceMemberFlags = DecodeModifiers(node.SubOrFunctionHeader.Modifiers, asyncIterator, ERRID.ERR_InvalidLambdaModifier, Accessibility.Public, If(diagnostics.DiagnosticBag, New DiagnosticBag())).FoundFlags And asyncIterator
 
            If (modifiers And asyncIterator) = asyncIterator AndAlso diagnostics.AccumulatesDiagnostics Then
                ReportModifierError(node.SubOrFunctionHeader.Modifiers, ERRID.ERR_InvalidAsyncIteratorModifiers, diagnostics.DiagnosticBag, InvalidAsyncIterator)
            End If
 
            Dim parameters As ImmutableArray(Of ParameterSymbol)
            parameters = DecodeParameterList(Me.ContainingMember, True, modifiers, node.SubOrFunctionHeader.ParameterList, diagnostics)
 
            For Each param In parameters
                ' Look up in container binders for name clashes with other locals and parameters.
                Dim identifierSyntax As SyntaxNodeOrToken = DirectCast(param, UnboundLambdaParameterSymbol).IdentifierSyntax
                Me.VerifyNameShadowingInMethodBody(param, identifierSyntax, identifierSyntax, diagnostics)
            Next
 
            Dim returnType As TypeSymbol = Nothing
            Dim hasErrors As Boolean = False
 
            If node.Kind = SyntaxKind.MultiLineFunctionLambdaExpression AndAlso
               node.SubOrFunctionHeader.AsClause IsNot Nothing Then
                returnType = BindTypeSyntax(node.SubOrFunctionHeader.AsClause.Type, diagnostics)
 
                If returnType.IsRestrictedType() Then
                    ReportDiagnostic(diagnostics, node.SubOrFunctionHeader.AsClause.Type, ERRID.ERR_RestrictedType1, returnType)
                    hasErrors = True
 
                ElseIf Not returnType.IsErrorType() Then
                    If Not (modifiers And asyncIterator) = asyncIterator Then
 
                        If modifiers = SourceMemberFlags.Async AndAlso
                           Not returnType.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) AndAlso
                           Not returnType.Equals(Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task)) Then
                            ReportDiagnostic(diagnostics, node.SubOrFunctionHeader.AsClause.Type, ERRID.ERR_BadAsyncReturn)
                        End If
 
                        If modifiers = SourceMemberFlags.Iterator Then
                            Dim originalRetTypeDef = returnType.OriginalDefinition
                            If originalRetTypeDef.SpecialType <> SpecialType.System_Collections_Generic_IEnumerable_T AndAlso
                                originalRetTypeDef.SpecialType <> SpecialType.System_Collections_Generic_IEnumerator_T AndAlso
                                returnType.SpecialType <> SpecialType.System_Collections_IEnumerable AndAlso
                                returnType.SpecialType <> SpecialType.System_Collections_IEnumerator Then
                                ReportDiagnostic(diagnostics, node.SubOrFunctionHeader.AsClause.Type, ERRID.ERR_BadIteratorReturn)
                            End If
                        End If
                    End If
                End If
            ElseIf node.Kind = SyntaxKind.MultiLineSubLambdaExpression OrElse
                node.Kind = SyntaxKind.SingleLineSubLambdaExpression Then
 
                returnType = GetSpecialType(SpecialType.System_Void, node.SubOrFunctionHeader, diagnostics)
 
                If modifiers = SourceMemberFlags.Iterator Then
                    ReportDiagnostic(diagnostics, node.SubOrFunctionHeader.DeclarationKeyword, ERRID.ERR_BadIteratorReturn)
                End If
            End If
 
            Return New UnboundLambda(node, Me, modifiers, parameters, returnType, New UnboundLambda.UnboundLambdaBindingCache(diagnostics.AccumulatesDependencies), hasErrors)
        End Function
 
        Friend Function BuildBoundLambdaParameters(
            source As UnboundLambda,
            targetSignature As UnboundLambda.TargetSignature,
            diagnostics As BindingDiagnosticBag
        ) As ImmutableArray(Of BoundLambdaParameterSymbol)
 
            If source.Parameters.Length = 0 Then
                Return ImmutableArray(Of BoundLambdaParameterSymbol).Empty
            End If
 
            Dim unboundParams As ImmutableArray(Of ParameterSymbol) = source.Parameters
            Dim parameters(unboundParams.Length - 1) As BoundLambdaParameterSymbol
            Dim minCount As Integer = Math.Min(parameters.Length, targetSignature.ParameterTypes.Length)
 
            For i As Integer = 0 To minCount - 1 Step 1
                Dim unboundParam = DirectCast(unboundParams(i), UnboundLambdaParameterSymbol)
 
                Dim unboundType As TypeSymbol = unboundParam.Type
                Dim delegateType As TypeSymbol = targetSignature.ParameterTypes(i)
 
                If unboundType Is Nothing Then
                    ' Get the type from the target.
                    unboundType = delegateType
 
                    If Not unboundParam.IsByRef AndAlso source.Flags <> 0 AndAlso unboundType.IsRestrictedType Then
                        ReportDiagnostic(diagnostics, unboundParam.IdentifierSyntax, ERRID.ERR_RestrictedResumableType1, unboundType)
                    Else
                        ' Other cases with restricted types are not interesting because either the target delegate type is "bad"
                        ' due to the way restricted type is used in its signature, or there is a ByRef/ByVal mismatch for the parameter.
                    End If
                End If
 
                parameters(i) = New BoundLambdaParameterSymbol(unboundParam.Name,
                                                               unboundParam.Ordinal,
                                                               unboundType,
                                                               unboundParam.IsByRef,
                                                               unboundParam.Syntax,
                                                               unboundParam.Locations(0))
            Next
 
            If parameters.Length <> targetSignature.ParameterTypes.Length Then
                ' Create the rest of the parameters
                Dim objectType As TypeSymbol = Nothing
 
                For i As Integer = minCount To parameters.Length - 1 Step 1
                    Dim unboundParam = DirectCast(unboundParams(i), UnboundLambdaParameterSymbol)
                    Dim unboundType As TypeSymbol = unboundParam.Type
 
                    If unboundType Is Nothing Then
                        If objectType Is Nothing Then
                            objectType = GetSpecialType(SpecialType.System_Object, unboundParam.IdentifierSyntax, diagnostics)
                        End If
 
                        unboundType = objectType
                        ReportLambdaParameterInferredToBeObject(unboundParam, diagnostics)
                    End If
 
                    parameters(i) = New BoundLambdaParameterSymbol(unboundParam.Name,
                                                                   unboundParam.Ordinal,
                                                                   unboundType,
                                                                   unboundParam.IsByRef,
                                                                   unboundParam.Syntax,
                                                                   unboundParam.Locations(0))
                Next
            End If
 
            Return parameters.AsImmutableOrNull()
        End Function
 
        Friend Function BindUnboundLambda(source As UnboundLambda, target As UnboundLambda.TargetSignature) As BoundLambda
            Debug.Assert(Me Is source.Binder)
 
            Dim maxRelaxationLevel As ConversionKind = ConversionKind.DelegateRelaxationLevelNone
            Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, source.WithDependencies)
            Dim targetReturnType As TypeSymbol
 
            If source.ReturnType IsNot Nothing Then
                targetReturnType = source.ReturnType
 
                If source.IsFunctionLambda Then
                    If targetReturnType.IsVoidType() Then
                        targetReturnType = Microsoft.CodeAnalysis.VisualBasic.Symbols.LambdaSymbol.ReturnTypeVoidReplacement
                    End If
                End If
            Else
                Debug.Assert(source.IsFunctionLambda)
 
                ' For Async | Iterator lambdas with nongeneric target delegate return type, we still want to do return type inference
                ' in order to infer more specific return type Task(Of T) | IEnumerable(of T), if possible.
                If target.ReturnType.SpecialType <> SpecialType.System_Void AndAlso
                   Not ((source.Flags And SourceMemberFlags.Async) <> 0 AndAlso target.ReturnType Is Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task)) AndAlso
                   Not ((source.Flags And SourceMemberFlags.Iterator) <> 0 AndAlso (target.ReturnType.SpecialType = SpecialType.System_Collections_IEnumerable OrElse
                                                                                    target.ReturnType.SpecialType = SpecialType.System_Collections_IEnumerator)) Then
 
                    targetReturnType = target.ReturnType
 
                    If Not targetReturnType.IsErrorType() Then
                        If source.Flags = SourceMemberFlags.Async Then
                            If Not TypeSymbol.Equals(targetReturnType.OriginalDefinition, Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T), TypeCompareKind.ConsiderEverything) Then
                                ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_BadAsyncReturn)
                            End If
                        End If
 
                        If source.Flags = SourceMemberFlags.Iterator Then
                            Dim origTargetReturnType = targetReturnType.OriginalDefinition
                            If origTargetReturnType.SpecialType <> SpecialType.System_Collections_Generic_IEnumerable_T AndAlso
                                origTargetReturnType.SpecialType <> SpecialType.System_Collections_Generic_IEnumerator_T Then
                                ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_BadIteratorReturn)
                            End If
                        End If
                    End If
 
                Else
                    ' Target signature is a Sub, but lambda is a function; or target return type is Task and lambda is Async.
                    ' Have to infer the type
                    Debug.Assert(target.ReturnType.IsVoidType() OrElse
                                 ((source.Flags And SourceMemberFlags.Async) <> 0 AndAlso target.ReturnType.Equals(Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task))))
 
                    Dim targetForInference As UnboundLambda.TargetSignature = target
 
                    If Not targetForInference.ReturnType.IsVoidType() Then
                        targetForInference = New UnboundLambda.TargetSignature(targetForInference.ParameterTypes, targetForInference.ParameterIsByRef,
                                                                               Compilation.GetSpecialType(SpecialType.System_Void), ' No need to report use-site error.
                                                                               returnsByRef:=False)
                    End If
 
                    Dim typeInfo As KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol)) = source.InferReturnType(targetForInference)
 
                    targetReturnType = typeInfo.Key
                    diagnostics.AddRange(typeInfo.Value)
                End If
            End If
 
            ' Create parameters
            Dim parameters As ImmutableArray(Of BoundLambdaParameterSymbol) = BuildBoundLambdaParameters(source, target, diagnostics)
            Dim lambdaSymbol As New SourceLambdaSymbol(source.Syntax, source, parameters, targetReturnType, Me)
 
            Dim delegateRelaxation As ConversionKind = Nothing
            Dim lambdaBinder As LambdaBodyBinder = Nothing
 
            Dim block As BoundBlock = BindLambdaBody(lambdaSymbol, diagnostics, lambdaBinder)
 
            If block.HasErrors OrElse diagnostics.HasAnyErrors() Then
                delegateRelaxation = ConversionKind.DelegateRelaxationLevelInvalid 'No conversion
            Else
                ' Add information about delegate relaxation level across all Return statements within the lambda body.
                If lambdaSymbol.IsSub Then
                    delegateRelaxation = ConversionKind.DelegateRelaxationLevelNone
                Else
                    Dim seenReturnWithAValue As Boolean = False
                    Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                    delegateRelaxation = LambdaRelaxationVisitor.DetermineDelegateRelaxationLevel(lambdaSymbol, source.Flags = SourceMemberFlags.Iterator, block, seenReturnWithAValue, useSiteInfo)
 
                    diagnostics.Add(LambdaHeaderErrorNode(source), useSiteInfo)
 
                    ' Dev11#94373: we also need to track whether there were any returns with operands, since
                    ' turning "Async Function() : End Function" into a Func(Of Task(Of Integer)) is a delegate
                    ' relaxation.
                    If Not seenReturnWithAValue AndAlso lambdaSymbol.IsAsync AndAlso delegateRelaxation < ConversionKind.DelegateRelaxationLevelWideningDropReturnOrArgs AndAlso
                       lambdaSymbol.ReturnType.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) Then
                        delegateRelaxation = ConversionKind.DelegateRelaxationLevelWideningDropReturnOrArgs
                    End If
                End If
            End If
 
            ' See if we need to relax the lambda
            Dim methodConversions As MethodConversionKind = MethodConversionKind.Error_Unspecified
 
            If delegateRelaxation <> ConversionKind.DelegateRelaxationLevelInvalid Then
                ' Figure out conversion kind.
                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                methodConversions = Conversions.ClassifyMethodConversionForLambdaOrAnonymousDelegate(target, lambdaSymbol, useSiteInfo)
 
                If diagnostics.Add(LambdaHeaderErrorNode(source), useSiteInfo) Then
                    ' Suppress additional diagnostics
                    diagnostics = BindingDiagnosticBag.Discarded
                End If
 
                If Conversions.IsDelegateRelaxationSupportedFor(methodConversions) Then
                    If Conversions.IsStubRequiredForMethodConversion(methodConversions) Then
                        ' We will need a stub for this lambda, which means that we will need to instantiate
                        ' an Anonymous Delegate matching the signature of the lambdaSymbol.
                        ' Anonymous Delegate has some limitations on parameter and return types.
                        For Each param In lambdaSymbol.Parameters
                            ' Verify for restricted types.
                            Dim restrictedType As TypeSymbol = Nothing
                            If param.Type.IsRestrictedTypeOrArrayType(restrictedType) Then
                                ReportDiagnostic(diagnostics,
                                                 DirectCast(source.Parameters(param.Ordinal), UnboundLambdaParameterSymbol).TypeSyntax,
                                                 ERRID.ERR_RestrictedType1, restrictedType)
                                delegateRelaxation = ConversionKind.DelegateRelaxationLevelInvalid 'No conversion
                                methodConversions = methodConversions Or MethodConversionKind.Error_RestrictedType
                                Exit For
                            End If
                        Next
 
                        If delegateRelaxation <> ConversionKind.DelegateRelaxationLevelInvalid Then
                            Debug.Assert(targetReturnType Is lambdaSymbol.ReturnType)
 
                            ' Check return type as well, but complain only if we "inherited" it from the target signature. If we got
                            ' it from the lambda's signature or inferred it, we already complained about it.
                            Dim restrictedType As TypeSymbol = Nothing
                            If targetReturnType.IsRestrictedTypeOrArrayType(restrictedType) Then
                                delegateRelaxation = ConversionKind.DelegateRelaxationLevelInvalid 'No conversion
                                methodConversions = methodConversions Or MethodConversionKind.Error_RestrictedType
 
                                If source.ReturnType Is Nothing AndAlso target.ReturnType.SpecialType <> SpecialType.System_Void Then
                                    ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_RestrictedType1, restrictedType)
                                End If
                            End If
                        End If
                    End If
                End If
 
                delegateRelaxation = CType(Math.Max(delegateRelaxation, Conversions.DetermineDelegateRelaxationLevel(methodConversions)), ConversionKind)
            End If
 
            ' the control flow of lambda expression bodies have not yet been analyzed. This will report unreachable code, ...
            ControlFlowPass.Analyze(New FlowAnalysisInfo(Compilation, lambdaSymbol, block), diagnostics.DiagnosticBag, True)
 
            Dim hasAnyErrors = diagnostics.HasAnyErrors()
 
            ' handle cases where control flow reports errors (such as illegal goto out of Finally)
            ' this will not change the outcome of overload resolution since control flow errors will happen
            ' regardless of substitutions.
            If hasAnyErrors Then
                delegateRelaxation = ConversionKind.DelegateRelaxationLevelInvalid 'No conversion
            End If
 
            Dim sealedDiagnostics = diagnostics.ToReadOnlyAndFree()
 
            Return New BoundLambda(source.Syntax, lambdaSymbol, block,
                                   sealedDiagnostics,
                                   lambdaBinder,
                                   delegateRelaxation,
                                   methodConversions,
                                   hasAnyErrors)
        End Function
 
        Private Class LambdaRelaxationVisitor
            Inherits StatementWalker
 
            Private ReadOnly _lambdaSymbol As LambdaSymbol
            Private ReadOnly _isIterator As Boolean
            Private _delegateRelaxationLevel As ConversionKind = ConversionKind.DelegateRelaxationLevelNone
            Private _seenReturnWithAValue As Boolean
            Private _useSiteDiagnostics As CompoundUseSiteInfo(Of AssemblySymbol)
 
            Private Sub New(lambdaSymbol As LambdaSymbol, isIterator As Boolean)
                _lambdaSymbol = lambdaSymbol
                _isIterator = isIterator
            End Sub
 
            Public Shared Function DetermineDelegateRelaxationLevel(
                lambdaSymbol As LambdaSymbol,
                isIterator As Boolean,
                lambdaBlock As BoundBlock,
                <Out()> ByRef seenReturnWithAValue As Boolean,
                <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
            ) As ConversionKind
                Dim visitor As New LambdaRelaxationVisitor(lambdaSymbol, isIterator)
                visitor._useSiteDiagnostics = useSiteInfo
                visitor.VisitBlock(lambdaBlock)
                seenReturnWithAValue = visitor._seenReturnWithAValue
                useSiteInfo = visitor._useSiteDiagnostics
                Return visitor._delegateRelaxationLevel
            End Function
 
            Public Overrides Function Visit(node As BoundNode) As BoundNode
                'Do not visit expressions
                If node Is Nothing OrElse TypeOf node Is BoundExpression Then
                    Return Nothing
                End If
 
                Return MyBase.Visit(node)
            End Function
 
            Public Overrides Function VisitLambda(node As BoundLambda) As BoundNode
                Throw ExceptionUtilities.Unreachable
            End Function
 
            Public Overrides Function VisitReturnStatement(node As BoundReturnStatement) As BoundNode
                ' not interested in Returns in an iterator.
                If _isIterator Then
                    Return Nothing
                End If
 
                ' Ignore implicit return at the end of the body.
                If node.ExpressionOpt IsNot Nothing Then
 
                    If node.ExpressionOpt.Kind = BoundKind.Local Then
                        Dim local As LocalSymbol = DirectCast(node.ExpressionOpt, BoundLocal).LocalSymbol
 
                        If local.IsFunctionValue AndAlso local.ContainingSymbol Is _lambdaSymbol Then
                            Return Nothing
                        End If
                    End If
 
                    _seenReturnWithAValue = True
                End If
 
                Dim returnRelaxation As ConversionKind = Conversions.DetermineDelegateRelaxationLevelForLambdaReturn(node.ExpressionOpt, _useSiteDiagnostics)
 
                If returnRelaxation > _delegateRelaxationLevel Then
                    _delegateRelaxationLevel = returnRelaxation
                End If
 
                Return Nothing
            End Function
 
            Public Overrides Function VisitYieldStatement(node As BoundYieldStatement) As BoundNode
                If _isIterator Then
                    Dim returnRelaxation As ConversionKind = Conversions.DetermineDelegateRelaxationLevelForLambdaReturn(node.Expression, _useSiteDiagnostics)
 
                    If returnRelaxation > _delegateRelaxationLevel Then
                        _delegateRelaxationLevel = returnRelaxation
                    End If
                End If
 
                Return Nothing
            End Function
 
        End Class
 
        Private Function BindLambdaBody(
            lambdaSymbol As LambdaSymbol,
            diagnostics As BindingDiagnosticBag,
            ByRef lambdaBinder As LambdaBodyBinder
        ) As BoundBlock
            Dim implicitVariablesBinder As Binder = Nothing
 
            If ContainingBinder.OptionExplicit = False AndAlso Not ContainingBinder.ImplicitVariableDeclarationAllowed Then
                ' Option Explicit is Off, but we're not in a location than allows implicit variable declaration (i.e., a field initializer).
                ' Install an implicit variables binder to capture implicit variables in this lambda.
                implicitVariablesBinder = New ImplicitVariableBinder(Me, lambdaSymbol)
                lambdaBinder = New LambdaBodyBinder(lambdaSymbol, implicitVariablesBinder)
            Else
                lambdaBinder = New LambdaBodyBinder(lambdaSymbol, Me)
            End If
 
#If DEBUG Then
            lambdaBinder.EnableSimpleNameBindingOrderChecks(True)
#End If
            Dim lambdaSyntax = lambdaSymbol.Syntax
            Dim bodyBinder = lambdaBinder.GetBinder(lambdaSyntax)
            Dim endSyntax As SyntaxNode = lambdaSyntax
 
            Dim block As BoundBlock
 
            Select Case lambdaSyntax.Kind
                Case SyntaxKind.SingleLineFunctionLambdaExpression
                    Debug.Assert(lambdaSymbol.ReturnType Is Nothing OrElse Not lambdaSymbol.ReturnType.IsVoidType())
                    Dim expression As BoundExpression = bodyBinder.BindValue(
                                                            DirectCast(
                                                                DirectCast(lambdaSyntax, SingleLineLambdaExpressionSyntax).Body,
                                                                ExpressionSyntax),
                                                            diagnostics)
 
                    If lambdaSymbol.ReturnType IsNot LambdaSymbol.ReturnTypeIsBeingInferred Then
                        If lambdaSymbol.ReturnType IsNot LambdaSymbol.ReturnTypeIsUnknown Then
 
                            Dim retType As TypeSymbol = lambdaSymbol.ReturnType
 
                            If lambdaSymbol.IsAsync Then
                                If retType.OriginalDefinition.Equals(Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T)) Then
                                    retType = DirectCast(retType, NamedTypeSymbol).TypeArgumentsNoUseSiteDiagnostics(0)
                                Else
                                    ' We should have forced Task(Of T) inference.
                                    Debug.Assert(Not retType.Equals(Compilation.GetWellKnownType(WellKnownType.System_Threading_Tasks_Task)))
                                End If
                            End If
 
                            expression = bodyBinder.ApplyImplicitConversion(expression.Syntax, retType, expression, diagnostics, False)
                        Else
                            expression = bodyBinder.MakeRValueAndIgnoreDiagnostics(expression)
                        End If
                    End If
 
                    Dim boundReturn = New BoundReturnStatement(expression.Syntax,
                                                               expression,
                                                               bodyBinder.GetLocalForFunctionValue(),
                                                               bodyBinder.GetReturnLabel(),
                                                               expression.HasErrors)
                    boundReturn.SetWasCompilerGenerated()
 
                    block = New BoundBlock(lambdaSyntax, Nothing, ImmutableArray(Of LocalSymbol).Empty,
                                           ImmutableArray.Create(Of BoundStatement)(boundReturn),
                                           expression.HasErrors).MakeCompilerGenerated()
 
                Case SyntaxKind.SingleLineSubLambdaExpression
                    Debug.Assert(lambdaSymbol.ReturnType IsNot Nothing AndAlso lambdaSymbol.ReturnType.IsVoidType())
 
                    Dim singleLineLambdaSyntax = DirectCast(lambdaSyntax, SingleLineLambdaExpressionSyntax)
                    Dim statement = DirectCast(singleLineLambdaSyntax.Body, StatementSyntax)
 
                    If statement.Kind = SyntaxKind.LocalDeclarationStatement Then
                        ' A local declaration is not allowed in a single line lambda as the top level statement.  Report the error here because it is legal
                        ' to have a single line if which contains a local declaration.  If the error reporting is done in BindStatement then all local 
                        ' declarations are prohibited.
 
                        ' Bind local declaration, discard diagnostics
                        block = bodyBinder.BindBlock(lambdaSyntax, singleLineLambdaSyntax.Statements, BindingDiagnosticBag.Discarded).MakeCompilerGenerated()
 
                        ' Generate a diagnostic and a bad statement node
                        ReportDiagnostic(diagnostics, statement, ERRID.ERR_SubDisallowsStatement)
                    Else
                        block = bodyBinder.BindBlock(lambdaSyntax, singleLineLambdaSyntax.Statements, diagnostics).MakeCompilerGenerated()
                    End If
 
                Case SyntaxKind.MultiLineFunctionLambdaExpression,
                     SyntaxKind.MultiLineSubLambdaExpression
 
                    Dim blockSyntax = DirectCast(lambdaSyntax, MultiLineLambdaExpressionSyntax)
                    endSyntax = blockSyntax.EndSubOrFunctionStatement
 
                    block = bodyBinder.BindBlock(lambdaSyntax, blockSyntax.Statements, diagnostics).MakeCompilerGenerated()
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(lambdaSyntax.Kind)
            End Select
 
            Dim localBuilder = ArrayBuilder(Of LocalSymbol).GetInstance()
 
            ' TODO: this is adapted from BindMethodBody. It handles adding a return value local if needed and 
            '       a function epilogue for the exit label
            '       for single line lambdas it may make sense to do in-place 
            '
            ' add indirect return sequence
            ' and maybe an indirect result local (if this is a function)
            Dim statements = ArrayBuilder(Of BoundStatement).GetInstance
            statements.AddRange(block.Statements)
            Select Case lambdaSyntax.Kind
                Case SyntaxKind.SingleLineFunctionLambdaExpression,
                    SyntaxKind.MultiLineFunctionLambdaExpression
 
                    Dim localForFunctionValue = bodyBinder.GetLocalForFunctionValue
                    localBuilder.Add(localForFunctionValue)
 
                    Dim returnLabel = New BoundLabelStatement(endSyntax, bodyBinder.GetReturnLabel())
                    Dim boundLocal = New BoundLocal(endSyntax, localForFunctionValue, isLValue:=False, type:=localForFunctionValue.Type).MakeCompilerGenerated()
                    Dim returnStmt = New BoundReturnStatement(endSyntax, boundLocal, Nothing, Nothing)
 
                    If lambdaSyntax.Kind = SyntaxKind.SingleLineFunctionLambdaExpression OrElse endSyntax Is lambdaSyntax Then
                        returnLabel.SetWasCompilerGenerated()
                        returnStmt.SetWasCompilerGenerated()
                    End If
 
                    statements.Add(returnLabel)
                    statements.Add(returnStmt)
 
                Case SyntaxKind.SingleLineSubLambdaExpression,
                    SyntaxKind.MultiLineSubLambdaExpression
 
                    Dim returnLabel = New BoundLabelStatement(endSyntax, bodyBinder.GetReturnLabel())
                    Dim returnStmt = New BoundReturnStatement(endSyntax, Nothing, Nothing, Nothing)
 
                    If lambdaSyntax.Kind = SyntaxKind.SingleLineSubLambdaExpression OrElse endSyntax Is lambdaSyntax Then
                        returnLabel.SetWasCompilerGenerated()
                        returnStmt.SetWasCompilerGenerated()
                    End If
 
                    statements.Add(returnLabel)
                    statements.Add(returnStmt)
            End Select
 
#If DEBUG Then
            lambdaBinder.EnableSimpleNameBindingOrderChecks(False)
#End If
 
            If implicitVariablesBinder IsNot Nothing Then
                ' Add any implicitly declared variables to the block.
                implicitVariablesBinder.DisallowFurtherImplicitVariableDeclaration(diagnostics)
                localBuilder.AddRange(implicitVariablesBinder.ImplicitlyDeclaredVariables)
            End If
 
            If Not block.Locals.IsEmpty Then
                localBuilder.AddRange(block.Locals)
            End If
 
            block = block.Update(block.StatementListSyntax, localBuilder.ToImmutableAndFree(), statements.ToImmutableAndFree)
            block.SetWasCompilerGenerated()
 
            If lambdaSymbol.IsAsync AndAlso Not CheckAwaitWalker.VisitBlock(bodyBinder, block, diagnostics) AndAlso
               Not block.HasErrors AndAlso Not lambdaSymbol.IsIterator Then
                ReportDiagnostic(diagnostics,
                                 DirectCast(lambdaSyntax, LambdaExpressionSyntax).SubOrFunctionHeader.DeclarationKeyword,
                                 ERRID.WRN_AsyncLacksAwaits)
            End If
 
            Return block
        End Function
 
        Private Class CheckAwaitWalker
            Inherits BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
 
            Private ReadOnly _binder As Binder
            Private ReadOnly _diagnostics As BindingDiagnosticBag
            Private _isInCatchFinallyOrSyncLock As Boolean
            Private _containsAwait As Boolean
 
            Private Sub New(binder As Binder, diagnostics As BindingDiagnosticBag)
                _diagnostics = diagnostics
                _binder = binder
            End Sub
 
            Public Shared Shadows Function VisitBlock(
                binder As Binder,
                block As BoundBlock,
                diagnostics As BindingDiagnosticBag
            ) As Boolean
                Debug.Assert(binder.IsInAsyncContext())
 
                Try
                    Dim walker As New CheckAwaitWalker(binder, diagnostics)
                    walker.Visit(block)
                    Debug.Assert(Not walker._isInCatchFinallyOrSyncLock)
 
                    Return walker._containsAwait
                Catch ex As CancelledByStackGuardException
                    ex.AddAnError(diagnostics)
                    Return True
                End Try
            End Function
 
            Public Overrides Function VisitTryStatement(node As BoundTryStatement) As BoundNode
                Debug.Assert(Not node.WasCompilerGenerated)
 
                Visit(node.TryBlock)
 
                Dim save_m_isInCatchFinallyOrSyncLock As Boolean = _isInCatchFinallyOrSyncLock
                _isInCatchFinallyOrSyncLock = True
 
                VisitList(node.CatchBlocks)
                Visit(node.FinallyBlockOpt)
 
                _isInCatchFinallyOrSyncLock = save_m_isInCatchFinallyOrSyncLock
                Return Nothing
            End Function
 
            Public Overrides Function VisitSyncLockStatement(node As BoundSyncLockStatement) As BoundNode
                Debug.Assert(Not node.WasCompilerGenerated)
                Dim save_m_isInCatchFinallyOrSyncLock As Boolean = _isInCatchFinallyOrSyncLock
                _isInCatchFinallyOrSyncLock = True
 
                MyBase.VisitSyncLockStatement(node)
 
                _isInCatchFinallyOrSyncLock = save_m_isInCatchFinallyOrSyncLock
                Return Nothing
            End Function
 
            Public Overrides Function VisitAwaitOperator(node As BoundAwaitOperator) As BoundNode
                Debug.Assert(_binder.IsInAsyncContext())
 
                _containsAwait = True
 
                If _isInCatchFinallyOrSyncLock Then
                    ReportDiagnostic(_diagnostics, node.Syntax, ERRID.ERR_BadAwaitInTryHandler)
                End If
 
                Return MyBase.VisitAwaitOperator(node)
            End Function
 
            Public Overrides Function VisitLambda(node As BoundLambda) As BoundNode
                ' Do not dive into the lambdas.
                Return Nothing
            End Function
        End Class
 
        Public Sub ReportLambdaParameterInferredToBeObject(unboundParam As UnboundLambdaParameterSymbol, diagnostics As BindingDiagnosticBag)
            If OptionStrict = OptionStrict.On Then
                ReportDiagnostic(diagnostics, unboundParam.IdentifierSyntax, ERRID.ERR_StrictDisallowImplicitObjectLambda)
            ElseIf OptionStrict = OptionStrict.Custom Then
                ReportDiagnostic(diagnostics, unboundParam.IdentifierSyntax, ERRID.WRN_ObjectAssumedVar1, ErrorFactory.ErrorInfo(ERRID.WRN_MissingAsClauseinVarDecl))
            End If
        End Sub
 
        ''' <summary>
        ''' If we are inside a lambda in a constructor and are passing ByRef a non-LValue field, which 
        ''' would be an LValue field, if it were referred to in the constructor outside of a lambda, 
        ''' we need to report an error because the operation will result in a simulated pass by
        ''' ref (through a temp, without a copy back), which might be not the intent.
        ''' </summary>
        Public Function Report_ERRID_ReadOnlyInClosure(argument As BoundExpression) As Boolean
 
            Debug.Assert(Not argument.IsLValue())
 
            If argument.HasErrors Then
                Return False
            End If
 
            Dim containingMember As Symbol = Me.ContainingMember
            If containingMember Is Nothing Then
                Return False
            End If
 
            Dim receiverOpt As BoundExpression
            Dim field As FieldSymbol
 
            If argument.Kind = BoundKind.PropertyAccess Then
                Dim propAccess = DirectCast(argument, BoundPropertyAccess)
                Dim propSym = TryCast(propAccess.PropertySymbol, SourcePropertySymbol)
 
                If propSym Is Nothing OrElse Not propSym.IsReadOnly Then
                    Return False
                End If
 
                field = propSym.AssociatedField
                receiverOpt = propAccess.ReceiverOpt
 
                If field Is Nothing Then
                    Return False
                End If
 
            ElseIf argument.Kind = BoundKind.FieldAccess Then
                Dim fieldAccess = DirectCast(argument, BoundFieldAccess)
                receiverOpt = fieldAccess.ReceiverOpt
                field = fieldAccess.FieldSymbol
                receiverOpt = fieldAccess.ReceiverOpt
 
            Else
                Return False
 
            End If
 
            ' The business of figuring out whether a field access should be considered an LValue is rather complicated, 
            ' it is easy to get wrong and Dev10 gets it wrong for this check in many scenarios. What we will do instead, 
            ' we will recalculate LValue status for the field access in context of the binder for the constructor or 
            ' binder for a field or property initializer. 
            ' We will construct some throw-away nodes in the process, but I believe it is a good tradeoff.
 
            Dim nonLambdaBinder As Binder = Nothing
 
            If containingMember.IsLambdaMethod Then
 
                Dim binderForExpressionContainingLambda As Binder = Nothing
 
                ' Ok, we are inside a lambda. 
                ' Bubble up to the containing method or initializer.
                Do
                    binderForExpressionContainingLambda = DirectCast(containingMember, LambdaSymbol).ContainingBinder
                    containingMember = containingMember.ContainingSymbol
                    Debug.Assert(binderForExpressionContainingLambda.ContainingMember Is containingMember)
                Loop While containingMember IsNot Nothing AndAlso containingMember.IsLambdaMethod
 
                Dim containingMethodKind As MethodKind = binderForExpressionContainingLambda.KindOfContainingMethodAtRunTime()
 
                Select Case containingMethodKind
                    Case MethodKind.SharedConstructor, MethodKind.Constructor
                        nonLambdaBinder = binderForExpressionContainingLambda
                End Select
            End If
 
            If nonLambdaBinder Is Nothing Then
                ' Either we are not in a lambda or not in a constructor.
                Return False
            End If
 
            If receiverOpt Is Nothing OrElse receiverOpt.Kind <> BoundKind.FieldAccess Then
                ' Simple case only one field access in the chain.
                Return nonLambdaBinder.IsLValueFieldAccess(field, receiverOpt)
            Else
                Dim fields = ArrayBuilder(Of FieldSymbol).GetInstance()
 
                fields.Add(field)
 
                Do
                    Dim fieldAccess = DirectCast(receiverOpt, BoundFieldAccess)
                    fields.Add(fieldAccess.FieldSymbol)
                    receiverOpt = fieldAccess.ReceiverOpt
                Loop While receiverOpt IsNot Nothing AndAlso receiverOpt.Kind = BoundKind.FieldAccess
 
                For i As Integer = fields.Count - 1 To 0 Step -1
                    Dim fieldSymbol As FieldSymbol = fields(i)
                    receiverOpt = New BoundFieldAccess(argument.Syntax, receiverOpt, fieldSymbol,
                                                       nonLambdaBinder.IsLValueFieldAccess(fieldSymbol, receiverOpt),
                                                       type:=fieldSymbol.Type)
                Next
 
                fields.Free()
 
                Return receiverOpt.IsLValue()
            End If
        End Function
 
        Friend Function InferAnonymousDelegateForLambda(source As UnboundLambda) As KeyValuePair(Of NamedTypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))
            Debug.Assert(Me Is source.Binder)
 
            Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, source.WithDependencies)
 
            ' Using Void as return type, because BuildBoundLambdaParameters doesn't use it and it is as good as any other value.
            Dim targetSignature As New UnboundLambda.TargetSignature(ImmutableArray(Of ParameterSymbol).Empty, Compilation.GetSpecialType(SpecialType.System_Void), returnsByRef:=False)
            Dim parameters As ImmutableArray(Of BoundLambdaParameterSymbol) = BuildBoundLambdaParameters(source, targetSignature, diagnostics)
 
            Dim returnTypeInfo As KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))
            returnTypeInfo = source.InferReturnType(New UnboundLambda.TargetSignature(StaticCast(Of ParameterSymbol).From(parameters), targetSignature.ReturnType, targetSignature.ReturnsByRef))
            Dim returnType As TypeSymbol = returnTypeInfo.Key
 
            diagnostics.AddRange(returnTypeInfo.Value)
 
            Dim delegateType As NamedTypeSymbol = ConstructAnonymousDelegateSymbol(source, parameters, returnType, diagnostics)
 
            Return New KeyValuePair(Of NamedTypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))(delegateType, diagnostics.ToReadOnlyAndFree())
        End Function
 
        Private Function ConstructAnonymousDelegateSymbol(
            source As UnboundLambda,
            parameters As ImmutableArray(Of BoundLambdaParameterSymbol),
            returnType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As NamedTypeSymbol
            Debug.Assert(source.IsFunctionLambda = Not returnType.IsVoidType())
 
            Dim parameterDescriptors(parameters.Length) As AnonymousTypeField
            Dim i As Integer
 
            For i = 0 To parameters.Length - 1
                Dim sourceParameter = DirectCast(source.Parameters(i), UnboundLambdaParameterSymbol)
                parameterDescriptors(i) = New AnonymousTypeField(
                    parameters(i).Name, parameters(i).Type, sourceParameter.Syntax.GetLocation(), parameters(i).IsByRef)
 
                ' Verify for restricted types.
                If parameters(i).Type.IsRestrictedType() Then
                    ReportDiagnostic(diagnostics, sourceParameter.TypeSyntax, ERRID.ERR_RestrictedType1, parameters(i).Type)
                End If
            Next
 
            Dim returnParamName = AnonymousTypeDescriptor.GetReturnParameterName(source.IsFunctionLambda)
            parameterDescriptors(i) = New AnonymousTypeField(returnParamName, returnType, source.Syntax.GetLocation(), False)
 
            Dim typeDescriptor As New AnonymousTypeDescriptor(parameterDescriptors.AsImmutableOrNull(), source.Syntax.GetLocation(), True)
            Return Me.Compilation.AnonymousTypeManager.ConstructAnonymousDelegateSymbol(typeDescriptor)
        End Function
 
        Friend Function BindLambdaForErrorRecovery(source As UnboundLambda) As BoundLambda
            If source.BindingCache.ErrorRecoverySignature Is Nothing Then
                ' Let's examine what target signatures did we try to apply to this lambda and let's
                ' get common types from them.
                Dim commonReturnType As TypeSymbol = Nothing
                Dim commonParameterTypes(source.Parameters.Length - 1) As TypeSymbol
 
                For Each pair In source.BindingCache.InferredReturnType
                    Dim target As UnboundLambda.TargetSignature = pair.Key
 
                    For i As Integer = 0 To Math.Min(target.ParameterTypes.Length, commonParameterTypes.Length) - 1
                        BindLambdaForErrorRecoveryInferCommonType(commonParameterTypes(i), target.ParameterTypes(i))
                    Next
 
                    BindLambdaForErrorRecoveryInferCommonType(commonReturnType, pair.Value.Key)
                Next
 
                For Each pair In source.BindingCache.BoundLambdas
                    Dim target As UnboundLambda.TargetSignature = pair.Key
 
                    For i As Integer = 0 To Math.Min(target.ParameterTypes.Length, commonParameterTypes.Length) - 1
                        BindLambdaForErrorRecoveryInferCommonType(commonParameterTypes(i), target.ParameterTypes(i))
                    Next
 
                    BindLambdaForErrorRecoveryInferCommonType(commonReturnType, target.ReturnType)
                Next
 
                Dim isByRef = BitVector.Empty
 
                For i As Integer = 0 To commonParameterTypes.Length - 1
                    If source.Parameters(i).Type IsNot Nothing Then
                        commonParameterTypes(i) = source.Parameters(i).Type
                    ElseIf commonParameterTypes(i) Is Nothing OrElse commonParameterTypes(i) Is LambdaSymbol.ErrorRecoveryInferenceError Then
                        ' Use Object for types we couldn't infer
                        commonParameterTypes(i) = Compilation.GetSpecialType(SpecialType.System_Object)
                    End If
 
                    If source.Parameters(i).IsByRef Then
                        isByRef(i) = True
                    End If
                Next
 
                If source.ReturnType IsNot Nothing Then
                    commonReturnType = If(source.IsFunctionLambda AndAlso source.ReturnType.IsVoidType(), LambdaSymbol.ReturnTypeVoidReplacement, source.ReturnType)
                ElseIf commonReturnType Is Nothing OrElse commonReturnType Is LambdaSymbol.ErrorRecoveryInferenceError Then
                    commonReturnType = source.InferReturnType(New UnboundLambda.TargetSignature(commonParameterTypes.AsImmutableOrNull(),
                                                                                                isByRef,
                                                                                                Compilation.GetSpecialType(SpecialType.System_Void),
                                                                                                returnsByRef:=False)).Key
                End If
 
                Interlocked.CompareExchange(source.BindingCache.ErrorRecoverySignature,
                                            New UnboundLambda.TargetSignature(commonParameterTypes.AsImmutableOrNull(), isByRef, commonReturnType, returnsByRef:=False),
                                            Nothing)
            End If
 
            Return source.Bind(source.BindingCache.ErrorRecoverySignature)
        End Function
 
        Private Shared Sub BindLambdaForErrorRecoveryInferCommonType(ByRef result As TypeSymbol, candidate As TypeSymbol)
            If result Is Nothing Then
                result = candidate
            ElseIf result IsNot LambdaSymbol.ErrorRecoveryInferenceError Then
                If Not result.IsSameTypeIgnoringAll(candidate) Then
                    result = LambdaSymbol.ErrorRecoveryInferenceError
                End If
            End If
        End Sub
 
        Friend Function InferFunctionLambdaReturnType(
            source As UnboundLambda,
            targetParameters As UnboundLambda.TargetSignature
        ) As KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))
            Debug.Assert(Me Is source.Binder AndAlso source.IsFunctionLambda AndAlso
                         source.ReturnType Is Nothing AndAlso targetParameters.ReturnType.IsVoidType())
 
            ' If both Async and Iterator are specified, we cannot really infer return type.
            If source.Flags = (SourceMemberFlags.Async Or SourceMemberFlags.Iterator) Then
                ' No need to report any error because we complained about conflicting modifiers.
                Return New KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))(LambdaSymbol.ReturnTypeIsUnknown, ReadOnlyBindingDiagnostic(Of AssemblySymbol).Empty)
            End If
 
            Dim diagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, source.WithDependencies)
 
            ' Clone parameters. 
            Dim parameters As ImmutableArray(Of BoundLambdaParameterSymbol) = BuildBoundLambdaParameters(source, targetParameters, diagnostics)
 
            Dim symbol = New SourceLambdaSymbol(source.Syntax, source, parameters, LambdaSymbol.ReturnTypeIsBeingInferred, Me)
            Dim block As BoundBlock = BindLambdaBody(symbol, diagnostics, lambdaBinder:=Nothing)
 
            If block.HasErrors OrElse diagnostics.HasAnyErrors() Then
                Return New KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))(LambdaSymbol.ReturnTypeIsUnknown, diagnostics.ToReadOnlyAndFree())
            End If
 
            diagnostics.Clear()
 
            Dim lambdaReturnType As TypeSymbol
            Dim returnExpressions = ArrayBuilder(Of BoundExpression).GetInstance()
 
            LambdaReturnStatementsVisitor.CollectReturnExpressions(block, returnExpressions, source.Flags = SourceMemberFlags.Iterator)
 
            If returnExpressions.Count = 0 AndAlso source.Flags = SourceMemberFlags.Async Then
                ' It's fine if there were no return statements in an Async Function.
                ' It simply returns "Task".
                lambdaReturnType = GetWellKnownType(WellKnownType.System_Threading_Tasks_Task, source.Syntax, diagnostics)
 
            ElseIf returnExpressions.Count = 0 AndAlso source.Flags = SourceMemberFlags.Iterator Then
                ' It's fine if there were no yield statements in an Iterator Function.
                ' It simply returns IEnumerable(of Object).
                lambdaReturnType = GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T, source.Syntax, diagnostics).
                    Construct(GetSpecialType(SpecialType.System_Object, source.Syntax, diagnostics))
 
            Else
                ' Inference is different for Expression and Statement lambdas
                If source.IsSingleLine Then
                    Debug.Assert(returnExpressions.Count < 2)
 
                    Dim returnExpression As BoundExpression = Nothing
 
                    If returnExpressions.Count > 0 Then
                        returnExpression = MakeRValue(returnExpressions(0), diagnostics)
                    End If
 
                    If returnExpression IsNot Nothing AndAlso Not returnExpression.HasErrors AndAlso Not diagnostics.HasAnyErrors() Then
                        lambdaReturnType = returnExpression.Type
                    Else
                        lambdaReturnType = GetSpecialType(SpecialType.System_Object, source.Syntax, diagnostics)
                    End If
 
                    diagnostics.Clear()
 
                    Dim restrictedType As TypeSymbol = Nothing
                    If lambdaReturnType.IsRestrictedTypeOrArrayType(restrictedType) Then
                        ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_RestrictedType1, restrictedType)
                    End If
                Else
                    Dim numCandidates As Integer = 0
                    lambdaReturnType = InferDominantTypeOfExpressions(source.Syntax, returnExpressions, diagnostics, numCandidates)
 
                    Debug.Assert(lambdaReturnType IsNot Nothing OrElse numCandidates = 0)
 
                    Dim restrictedType As TypeSymbol = Nothing
                    If lambdaReturnType Is Nothing Then
                        ' "Cannot infer a return type. Specifying the return type might correct this error."
                        ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_LambdaNoType)
                        lambdaReturnType = LambdaSymbol.ReturnTypeIsUnknown
 
                    ElseIf lambdaReturnType.IsRestrictedTypeOrArrayType(restrictedType) Then
                        ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_RestrictedType1, restrictedType)
 
                    ElseIf numCandidates <> 1 Then
                        If OptionStrict = OptionStrict.On Then
                            If numCandidates = 0 Then
                                ' "Cannot infer a return type, and Option Strict On does not allow 'Object' to be assumed. Specifying the return type might correct this error."
                                ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_LambdaNoTypeObjectDisallowed)
                                Debug.Assert(lambdaReturnType.IsObjectType())
                            Else
                                ' "Cannot infer a return type because more than one type is possible. Specifying the return type might correct this error."
                                ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.ERR_LambdaTooManyTypesObjectDisallowed)
                                Debug.Assert(lambdaReturnType.IsObjectType())
                            End If
                        ElseIf OptionStrict = OptionStrict.Custom Then
                            If numCandidates = 0 Then
                                ' "Cannot infer a return type; 'Object' assumed."
                                ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.WRN_ObjectAssumed1, ErrorFactory.ErrorInfo(ERRID.WRN_LambdaNoTypeObjectAssumed))
                                Debug.Assert(lambdaReturnType.IsObjectType())
                            Else
                                ' "Cannot infer a return type because more than one type is possible; 'Object' assumed."
                                ReportDiagnostic(diagnostics, LambdaHeaderErrorNode(source), ERRID.WRN_ObjectAssumed1, ErrorFactory.ErrorInfo(ERRID.WRN_LambdaTooManyTypesObjectAssumed))
                                Debug.Assert(lambdaReturnType.IsObjectType())
                            End If
                        End If
                    End If
                End If
 
                If source.Flags = SourceMemberFlags.Async Then
                    ' There were some returns with values from Async lambda, infer Task(Of T) as return type of the lambda.
                    lambdaReturnType = GetWellKnownType(WellKnownType.System_Threading_Tasks_Task_T, source.Syntax, diagnostics).Construct(lambdaReturnType)
 
                ElseIf source.Flags = SourceMemberFlags.Iterator Then
                    ' There were some returns with values from Iterator lambda, infer IEnumerable(Of T) as return type of the lambda.
                    lambdaReturnType = GetSpecialType(SpecialType.System_Collections_Generic_IEnumerable_T, source.Syntax, diagnostics).Construct(lambdaReturnType)
 
                End If
            End If
 
            returnExpressions.Free()
 
            Return New KeyValuePair(Of TypeSymbol, ReadOnlyBindingDiagnostic(Of AssemblySymbol))(lambdaReturnType, diagnostics.ToReadOnlyAndFree())
        End Function
 
        Private Shared Function LambdaHeaderErrorNode(source As UnboundLambda) As SyntaxNode
            Dim lambdaSyntax = TryCast(source.Syntax, LambdaExpressionSyntax)
 
            If lambdaSyntax IsNot Nothing Then
                Return lambdaSyntax.SubOrFunctionHeader
            End If
 
            Return source.Syntax
        End Function
 
        Private Class LambdaReturnStatementsVisitor
            Inherits StatementWalker
 
            Private ReadOnly _builder As ArrayBuilder(Of BoundExpression)
            Private ReadOnly _isIterator As Boolean
 
            Private Sub New(builder As ArrayBuilder(Of BoundExpression), isIterator As Boolean)
                Me._builder = builder
                Me._isIterator = isIterator
            End Sub
 
            ''' <summary>
            ''' Collects expressions that are effective return values of the lambda body.
            ''' In iterators those would be arguments of Yield statements.
            ''' </summary>
            Public Shared Sub CollectReturnExpressions(lambdaBlock As BoundBlock,
                                                       arrayToFill As ArrayBuilder(Of BoundExpression),
                                                       isIterator As Boolean)
 
                Dim visitor = New LambdaReturnStatementsVisitor(arrayToFill, isIterator)
                visitor.VisitBlock(lambdaBlock)
            End Sub
 
            Public Overrides Function Visit(node As BoundNode) As BoundNode
                'Do not visit expressions
                If node Is Nothing OrElse TypeOf node Is BoundExpression Then
                    Return Nothing
                End If
 
                Return MyBase.Visit(node)
            End Function
 
            Public Overrides Function VisitLambda(node As BoundLambda) As BoundNode
                Throw ExceptionUtilities.Unreachable
            End Function
 
            Public Overrides Function VisitReturnStatement(node As BoundReturnStatement) As BoundNode
                ' not interested in Returns in an iterator.
                If _isIterator Then
                    Return Nothing
                End If
 
                Dim expr As BoundExpression = node.ExpressionOpt
 
                ' Skip synthetic return for the function variable.
                If expr Is Nothing OrElse expr.Type Is LambdaSymbol.ReturnTypeIsBeingInferred Then
                    Return Nothing
                End If
 
                _builder.Add(expr)
 
                Return Nothing
            End Function
 
            Public Overrides Function VisitYieldStatement(node As BoundYieldStatement) As BoundNode
                If _isIterator Then
                    _builder.Add(node.Expression)
                End If
 
                Return Nothing
            End Function
        End Class
    End Class
 
    ''' <summary>
    ''' Provides context for binding body of a Lambda.
    ''' </summary>
    Friend NotInheritable Class LambdaBodyBinder
        Inherits SubOrFunctionBodyBinder
 
        Private ReadOnly _functionValue As LocalSymbol
 
        Public Sub New(lambdaSymbol As LambdaSymbol, containingBinder As Binder)
            MyBase.New(lambdaSymbol, lambdaSymbol.Syntax, containingBinder)
            _functionValue = CreateFunctionValueLocal(lambdaSymbol)
        End Sub
 
        Private Shared Function CreateFunctionValueLocal(lambdaSymbol As LambdaSymbol) As LocalSymbol
            ' synthesized lambdas may not result from a LambdaExpressionSyntax (e.g. an AddressOf expression that 
            ' needs relaxation). In this case there will be no need to create a local here, this is done when generating the 
            ' lambda body.
            If lambdaSymbol.IsImplicitlyDeclared OrElse lambdaSymbol.IsSub Then
                Return Nothing
            End If
 
            Dim header As LambdaHeaderSyntax = DirectCast(lambdaSymbol.Syntax, LambdaExpressionSyntax).SubOrFunctionHeader
            Return New SynthesizedLocal(lambdaSymbol, lambdaSymbol.ReturnType, SynthesizedLocalKind.FunctionReturnValue, header)
        End Function
 
        Public Overrides Function GetLocalForFunctionValue() As LocalSymbol
            Return _functionValue
        End Function
 
        Public Overrides Function GetContinueLabel(continueSyntaxKind As SyntaxKind) As LabelSymbol
            Return Nothing
        End Function
 
        Public Overrides Function GetExitLabel(exitSyntaxKind As SyntaxKind) As LabelSymbol
            Return Nothing
        End Function
 
        Public Overrides Function GetReturnLabel() As LabelSymbol
            Return Nothing
        End Function
 
        Friend Overrides Sub LookupInSingleBinder(lookupResult As LookupResult, name As String, arity As Integer, options As LookupOptions, originalBinder As Binder,
                                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol))
            MyBase.LookupInSingleBinder(lookupResult, name, arity, options, originalBinder, useSiteInfo)
 
            If (options And LookupOptions.LabelsOnly) = LookupOptions.LabelsOnly Then
                If lookupResult.Kind = LookupResultKind.Empty Then
                    lookupResult.SetFrom(SingleLookupResult.EmptyAndStopLookup)
                End If
            End If
        End Sub
    End Class
End Namespace