File: Binding\Binder_Initializers.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 Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    Partial Friend Class Binder
 
        ''' <summary>
        ''' Used to store the bound field and property initializers and the associated list of
        ''' bound assignment statements because they are reused for multiple constructors
        ''' </summary>
        Friend NotInheritable Class ProcessedFieldOrPropertyInitializers
            Friend ReadOnly BoundInitializers As ImmutableArray(Of BoundInitializer)
 
            ''' <summary> 
            ''' Indicate the fact that binding of initializers produced a tree with errors. 
            ''' This property does not indicate whether or not a diagnostic was produced during the 
            ''' binding of the initializers. 
            ''' </summary>
            Friend ReadOnly HasAnyErrors As Boolean
 
            Private _loweredInitializers As ImmutableArray(Of BoundStatement)
            Friend Property InitializerStatements As ImmutableArray(Of BoundStatement)
                Get
                    Return _loweredInitializers
                End Get
                Set(value As ImmutableArray(Of BoundStatement))
                    Debug.Assert(Not value.IsDefault)
                    Debug.Assert(_loweredInitializers.IsDefault)
                    _loweredInitializers = value
                End Set
            End Property
 
            Friend Shared ReadOnly Empty As ProcessedFieldOrPropertyInitializers = New ProcessedFieldOrPropertyInitializers()
 
            Private Sub New()
                Me.BoundInitializers = ImmutableArray(Of BoundInitializer).Empty
                Me.HasAnyErrors = False
                Me._loweredInitializers = ImmutableArray(Of BoundStatement).Empty
            End Sub
 
            Friend Sub New(boundInitializers As ImmutableArray(Of BoundInitializer))
                Debug.Assert(Not boundInitializers.IsDefault)
                Me.BoundInitializers = boundInitializers
                Me.HasAnyErrors = boundInitializers.Any(Function(i) i.HasErrors)
            End Sub
 
            Private _analyzed As Boolean = False
            Friend Sub EnsureInitializersAnalyzed(method As MethodSymbol, diagnostics As DiagnosticBag)
                Debug.Assert(method IsNot Nothing)
 
                If Not _analyzed Then
                    If Not Me.BoundInitializers.IsEmpty Then
                        ' Create a dummy block
                        Dim block As New BoundBlock(Me.BoundInitializers(0).Syntax,
                                                    Nothing,
                                                    ImmutableArray(Of LocalSymbol).Empty,
                                                    StaticCast(Of BoundStatement).From(Me.BoundInitializers))
 
                        Analyzer.AnalyzeMethodBody(method, block, diagnostics)
                        DiagnosticsPass.IssueDiagnostics(block, diagnostics, method)
                    End If
 
                    _analyzed = True
                End If
            End Sub
        End Class
 
        ''' <summary>
        ''' Binds all field initializers of a <see cref="SourceNamedTypeSymbol"/>.
        ''' </summary>
        ''' <param name="symbol">The named type symbol where the field initializers are declared.</param>
        ''' <param name="scriptInitializerOpt">Script initializer or Nothing if not binding top-level statements.</param>
        ''' <param name="initializers">The initializers itself. For each partial type declaration there is an array of 
        ''' field initializers</param>
        ''' <param name="diagnostics">The diagnostics.</param>
        Friend Shared Function BindFieldAndPropertyInitializers(
            symbol As SourceMemberContainerTypeSymbol,
            initializers As ImmutableArray(Of ImmutableArray(Of FieldOrPropertyInitializer)),
            scriptInitializerOpt As SynthesizedInteractiveInitializerMethod,
            diagnostics As BindingDiagnosticBag
        ) As ImmutableArray(Of BoundInitializer)
            Debug.Assert((scriptInitializerOpt IsNot Nothing) = symbol.IsScriptClass)
 
            If initializers.IsDefaultOrEmpty Then
                Return ImmutableArray(Of BoundInitializer).Empty
            End If
 
            Dim moduleSymbol = DirectCast(symbol.ContainingModule, SourceModuleSymbol)
            Dim compilation = moduleSymbol.ContainingSourceAssembly.DeclaringCompilation
 
            Dim boundInitializers = ArrayBuilder(Of BoundInitializer).GetInstance()
            For i = 0 To initializers.Length - 1
                Dim siblingInitializers = initializers(i)
 
                ' All sibling initializers share the same parent node and tree
                ' so we can reuse the parent binder across siblings.
                Dim parentBinder As Binder = Nothing
 
                For j = 0 To siblingInitializers.Length - 1
                    Dim initializer = siblingInitializers(j)
 
                    If Not initializer.FieldsOrProperties.IsDefault AndAlso initializer.FieldsOrProperties.First.ContainingType.IsEnumType Then
                        Continue For
                    End If
 
                    Dim syntaxRef = initializer.Syntax
                    Dim syntaxTree = syntaxRef.SyntaxTree
                    Dim initializerNode = DirectCast(syntaxRef.GetSyntax(), VisualBasicSyntaxNode)
 
                    If parentBinder Is Nothing Then
                        ' use binder for type, not ctor - no access to ctor parameters
                        parentBinder = BinderBuilder.CreateBinderForType(moduleSymbol, syntaxTree, symbol)
 
                        If scriptInitializerOpt IsNot Nothing Then
                            parentBinder = New TopLevelCodeBinder(scriptInitializerOpt, parentBinder)
                        End If
                    Else
                        Debug.Assert(parentBinder.SyntaxTree Is syntaxTree, "sibling initializer array contains initializers from two different syntax trees.")
                    End If
 
                    If initializer.FieldsOrProperties.IsDefault Then
                        ' use the binder of the Script class for global statements
                        Dim isLast = (i = initializers.Length - 1 AndAlso j = siblingInitializers.Length - 1)
                        boundInitializers.Add(parentBinder.BindGlobalStatement(scriptInitializerOpt, DirectCast(initializerNode, StatementSyntax), diagnostics, isLast))
                        Continue For
                    End If
 
                    Dim firstFieldOrProperty = initializer.FieldsOrProperties.First
                    Dim additionalSymbols = If(initializer.FieldsOrProperties.Length > 1, initializer.FieldsOrProperties.RemoveAt(0), ImmutableArray(Of Symbol).Empty)
                    Dim initializerBinder = BinderBuilder.CreateBinderForInitializer(parentBinder, firstFieldOrProperty, additionalSymbols)
                    If initializerNode.Kind = SyntaxKind.ModifiedIdentifier Then
                        ' Array field with no explicit initializer.
                        Debug.Assert(initializer.FieldsOrProperties.Length = 1)
                        Debug.Assert(firstFieldOrProperty.Kind = SymbolKind.Field)
 
                        Dim fieldSymbol = DirectCast(firstFieldOrProperty, SourceFieldSymbol)
                        Debug.Assert(fieldSymbol.HasDeclaredType)
                        Debug.Assert(fieldSymbol.Type.IsArrayType())
 
                        initializerBinder.BindArrayFieldImplicitInitializer(fieldSymbol, boundInitializers, diagnostics)
                    ElseIf firstFieldOrProperty.Kind = SymbolKind.Field Then
                        Dim fieldSymbol = DirectCast(firstFieldOrProperty, SourceFieldSymbol)
                        If fieldSymbol.IsConst Then
                            ' Bind constant to ensure diagnostics are captured,
                            ' only generate a field initializer for decimals and dates, because they can't be compile time
                            ' constant in CLR/IL.
                            BindConstFieldInitializer(fieldSymbol,
                                                      initializerNode,
                                                      boundInitializers)
 
                            If fieldSymbol.Type.SpecialType = SpecialType.System_DateTime Then
                                '  report proper diagnostics for System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor if needed
                                initializerBinder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DateTimeConstantAttribute__ctor,
                                                                                            initializerNode,
                                                                                            diagnostics)
                            ElseIf fieldSymbol.Type.SpecialType = SpecialType.System_Decimal Then
                                '  report proper diagnostics for System_Runtime_CompilerServices_DecimalConstantAttribute__ctor if needed
                                initializerBinder.ReportUseSiteInfoForSynthesizedAttribute(WellKnownMember.System_Runtime_CompilerServices_DecimalConstantAttribute__ctor,
                                                                                            initializerNode,
                                                                                            diagnostics)
                            End If
 
                        Else
                            If fieldSymbol.Type.IsObjectType() AndAlso
                               initializerBinder.OptionStrict <> VisualBasic.OptionStrict.On AndAlso
                               fieldSymbol.Syntax IsNot Nothing AndAlso
                               fieldSymbol.Syntax.Kind = SyntaxKind.ModifiedIdentifier Then
                                Dim identifier = DirectCast(fieldSymbol.Syntax, ModifiedIdentifierSyntax)
 
                                If identifier.Nullable.Node IsNot Nothing AndAlso identifier.Parent IsNot Nothing AndAlso
                                   identifier.Parent.Kind = SyntaxKind.VariableDeclarator AndAlso
                                   DirectCast(identifier.Parent, VariableDeclaratorSyntax).AsClause Is Nothing Then
                                    ReportDiagnostic(diagnostics, identifier, ERRID.ERR_NullableTypeInferenceNotSupported)
                                End If
                            End If
 
                            initializerBinder.BindFieldInitializer(initializer.FieldsOrProperties.Cast(Of FieldSymbol).ToImmutableArray(),
                                                                   initializerNode,
                                                                   boundInitializers,
                                                                   diagnostics)
                        End If
                    Else
                        initializerBinder.BindPropertyInitializer(initializer.FieldsOrProperties.Cast(Of PropertySymbol).ToImmutableArray(),
                                                                  initializerNode,
                                                                  boundInitializers,
                                                                  diagnostics)
 
                    End If
                Next
            Next
 
            Return boundInitializers.ToImmutableAndFree()
        End Function
 
        Private Function BindGlobalStatement(
            scriptInitializerOpt As SynthesizedInteractiveInitializerMethod,
            statementNode As StatementSyntax,
            diagnostics As BindingDiagnosticBag,
            isLast As Boolean) As BoundInitializer
 
            Dim boundStatement As BoundStatement = Me.BindStatement(statementNode, diagnostics)
 
            If Me.Compilation.IsSubmission AndAlso isLast AndAlso boundStatement.Kind = BoundKind.ExpressionStatement AndAlso Not boundStatement.HasErrors Then
                ' insert an implicit conversion to the submission return type (if needed):
                Dim expression = (DirectCast(boundStatement, BoundExpressionStatement)).Expression
                If expression.Type Is Nothing OrElse expression.Type.SpecialType <> SpecialType.System_Void Then
                    Dim submissionReturnType = scriptInitializerOpt.ResultType
                    expression = ApplyImplicitConversion(expression.Syntax, submissionReturnType, expression, diagnostics)
                    boundStatement = New BoundExpressionStatement(boundStatement.Syntax, expression, expression.HasErrors)
                End If
            End If
 
            Return New BoundGlobalStatementInitializer(statementNode, boundStatement)
        End Function
 
        ''' <summary>
        ''' Bind an initializer for an implicitly allocated array field (for example: Private F(2) As Object).
        ''' </summary>
        Public Sub BindArrayFieldImplicitInitializer(
            fieldSymbol As SourceFieldSymbol,
            boundInitializers As ArrayBuilder(Of BoundInitializer),
            diagnostics As BindingDiagnosticBag)
 
            Debug.Assert(fieldSymbol.Syntax.Kind = SyntaxKind.ModifiedIdentifier)
            Debug.Assert(fieldSymbol.Type.Kind = SymbolKind.ArrayType)
 
            Dim syntax = DirectCast(fieldSymbol.Syntax, ModifiedIdentifierSyntax)
 
            Debug.Assert(syntax.ArrayBounds IsNot Nothing)
            Dim arraySize = BindArrayBounds(syntax.ArrayBounds, diagnostics)
            Dim arrayCreation = New BoundArrayCreation(syntax, arraySize, Nothing, fieldSymbol.Type)
            arrayCreation.SetWasCompilerGenerated()
 
            Dim boundReceiver = If(fieldSymbol.IsShared, Nothing, CreateMeReference(syntax, isSynthetic:=True))
            Dim boundFieldAccessExpression = New BoundFieldAccess(syntax, boundReceiver, fieldSymbol, True, fieldSymbol.Type)
            boundFieldAccessExpression.SetWasCompilerGenerated()
 
            Dim initializer = New BoundFieldInitializer(syntax,
                                                        ImmutableArray.Create(Of FieldSymbol)(fieldSymbol),
                                                        boundFieldAccessExpression,
                                                        arrayCreation,
                                                        binderOpt:=Nothing)
 
            boundInitializers.Add(initializer)
        End Sub
 
        ''' <summary>
        ''' Binds the field initializer. A bound field initializer contains the bound field access and bound init value.
        ''' </summary>
        ''' <param name="fieldSymbols">The field symbol.</param>
        ''' <param name="equalsValueOrAsNewSyntax">The syntax node for the optional initialization.</param>
        ''' <param name="boundInitializers">The array of bound initializers to add the newly bound ones to.</param>
        ''' <param name="diagnostics">The diagnostics.</param>
        Friend Sub BindFieldInitializer(
            fieldSymbols As ImmutableArray(Of FieldSymbol),
            equalsValueOrAsNewSyntax As SyntaxNode,
            boundInitializers As ArrayBuilder(Of BoundInitializer),
            diagnostics As BindingDiagnosticBag,
            Optional bindingForSemanticModel As Boolean = False
        )
            Debug.Assert(Not fieldSymbols.IsEmpty)
            Dim firstFieldSymbol = DirectCast(fieldSymbols.First, SourceFieldSymbol)
            Debug.Assert(bindingForSemanticModel OrElse Not firstFieldSymbol.IsConst)
 
            Dim boundReceiver = If(firstFieldSymbol.IsShared,
                                   Nothing,
                                   CreateMeReference(firstFieldSymbol.Syntax, isSynthetic:=True))
 
            ' Always generate a field access for the first symbol. In cases were we have multiple variables declared we will not
            ' use it (we don't store it in the bound initializer node), but we still need it for e.g. the data flow analysis
            ' (stored in the bound lvalue placeholder).
            Dim fieldAccess As BoundExpression = New BoundFieldAccess(firstFieldSymbol.Syntax,
                                                                      boundReceiver,
                                                                      firstFieldSymbol,
                                                                      True,
                                                                      firstFieldSymbol.Type)
            fieldAccess.SetWasCompilerGenerated()
 
            Dim boundInitExpression As BoundExpression = BindFieldInitializerExpression(equalsValueOrAsNewSyntax, firstFieldSymbol, diagnostics)
            Dim hasErrors = False
 
            ' In speculative semantic model scenarios equalsValueOrAsNewSyntax might have no parent.
            If equalsValueOrAsNewSyntax.Parent IsNot Nothing Then
                Debug.Assert(Me.IsSemanticModelBinder OrElse
                             fieldSymbols.Length = DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names.Count)
 
                If equalsValueOrAsNewSyntax.Kind() = SyntaxKind.AsNewClause Then
                    For Each name In DirectCast(equalsValueOrAsNewSyntax.Parent, VariableDeclaratorSyntax).Names
                        If Not (name.ArrayRankSpecifiers.IsEmpty AndAlso name.ArrayBounds Is Nothing) Then
                            ' Arrays cannot be declared with AsNew syntax
                            ReportDiagnostic(diagnostics, name, ERRID.ERR_AsNewArray)
                            hasErrors = True
                        End If
                    Next
                End If
            End If
 
            boundInitializers.Add(New BoundFieldInitializer(
                equalsValueOrAsNewSyntax,
                fieldSymbols,
                If(fieldSymbols.Length = 1, fieldAccess, Nothing),
                boundInitExpression,
                Me,
                hasErrors))
        End Sub
 
        Friend Function BindFieldInitializerExpression(equalsValueOrAsNewSyntax As SyntaxNode, fieldSymbol As FieldSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression
            Dim asNewVariablePlaceholder As BoundWithLValueExpressionPlaceholder = Nothing
            If equalsValueOrAsNewSyntax.Kind = SyntaxKind.AsNewClause Then
                ' CONSIDER: using a bound field access directly instead of a placeholder for AsNew declarations
                '           with just one variable
 
                asNewVariablePlaceholder = New BoundWithLValueExpressionPlaceholder(equalsValueOrAsNewSyntax,
                                                                                    fieldSymbol.Type)
                asNewVariablePlaceholder.SetWasCompilerGenerated()
            End If
 
            Dim boundInitExpression As BoundExpression = BindFieldOrPropertyInitializerExpression(equalsValueOrAsNewSyntax,
                                                                                                  fieldSymbol.Type,
                                                                                                  asNewVariablePlaceholder,
                                                                                                  diagnostics)
            Return boundInitExpression
        End Function
 
        Friend Sub BindPropertyInitializer(
            propertySymbols As ImmutableArray(Of PropertySymbol),
            initValueOrAsNewNode As SyntaxNode,
            boundInitializers As ArrayBuilder(Of BoundInitializer),
            diagnostics As BindingDiagnosticBag
        )
            Dim propertySymbol = DirectCast(propertySymbols.First, PropertySymbol)
            Dim syntaxNode As SyntaxNode = initValueOrAsNewNode
 
            Dim boundReceiver = If(propertySymbol.IsShared, Nothing, CreateMeReference(syntaxNode, isSynthetic:=True))
 
            ' If the property has parameters, BC36759 should have already
            ' been reported for the auto-implemented property.
            Dim hasError = propertySymbol.ParameterCount > 0
            Dim boundPropertyOrFieldAccess As BoundExpression
 
            If propertySymbol.IsReadOnly AndAlso propertySymbol.AssociatedField IsNot Nothing Then
                ' For ReadOnly auto-implemented properties we have to write directly to the backing field.
                Debug.Assert(TypeSymbol.Equals(propertySymbol.Type, propertySymbol.AssociatedField.Type, TypeCompareKind.ConsiderEverything))
                Debug.Assert(propertySymbols.Length = 1)
                boundPropertyOrFieldAccess = New BoundFieldAccess(syntaxNode,
                                                                  boundReceiver,
                                                                  propertySymbol.AssociatedField,
                                                                  isLValue:=True,
                                                                  type:=propertySymbol.Type,
                                                                  hasErrors:=hasError)
 
            Else
                boundPropertyOrFieldAccess = New BoundPropertyAccess(syntaxNode,
                                                                     propertySymbol,
                                                                     propertyGroupOpt:=Nothing,
                                                                     accessKind:=PropertyAccessKind.Set,
                                                                     isWriteable:=propertySymbol.HasSet,
                                                                     receiverOpt:=boundReceiver,
                                                                     arguments:=ImmutableArray(Of BoundExpression).Empty,
                                                                     hasErrors:=hasError)
            End If
 
            boundPropertyOrFieldAccess = BindAssignmentTarget(syntaxNode, boundPropertyOrFieldAccess, diagnostics)
            Dim isError As Boolean
            boundPropertyOrFieldAccess = AdjustAssignmentTarget(syntaxNode, boundPropertyOrFieldAccess, diagnostics, isError)
            boundPropertyOrFieldAccess.SetWasCompilerGenerated()
 
            Dim boundInitExpression As BoundExpression = BindPropertyInitializerExpression(initValueOrAsNewNode, propertySymbol, diagnostics)
            boundInitializers.Add(New BoundPropertyInitializer(initValueOrAsNewNode,
                                                               propertySymbols,
                                                               If(propertySymbols.Length = 1, boundPropertyOrFieldAccess, Nothing),
                                                               boundInitExpression,
                                                               Me))
        End Sub
 
        Friend Function BindPropertyInitializerExpression(initValueOrAsNewNode As SyntaxNode, propertySymbol As PropertySymbol, diagnostics As BindingDiagnosticBag) As BoundExpression
            Return BindFieldOrPropertyInitializerExpression(initValueOrAsNewNode,
                                                            propertySymbol.Type,
                                                            Nothing,
                                                            diagnostics)
        End Function
 
        Private Function BindFieldOrPropertyInitializerExpression(
            equalsValueOrAsNewSyntax As SyntaxNode,
            targetType As TypeSymbol,
            asNewVariablePlaceholderOpt As BoundWithLValueExpressionPlaceholder,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            Dim boundInitExpression As BoundExpression = Nothing
 
            Dim fieldInitializerSyntax As VisualBasicSyntaxNode
 
            If equalsValueOrAsNewSyntax.Kind = SyntaxKind.AsNewClause Then
                Dim asNew = DirectCast(equalsValueOrAsNewSyntax, AsNewClauseSyntax)
                Select Case asNew.NewExpression.Kind
                    Case SyntaxKind.ObjectCreationExpression
                        DisallowNewOnTupleType(asNew.Type, diagnostics)
 
                        Dim objectCreationExpressionSyntax = DirectCast(asNew.NewExpression, ObjectCreationExpressionSyntax)
                        boundInitExpression = BindObjectCreationExpression(asNew.NewExpression.Type,
                                                                           objectCreationExpressionSyntax.ArgumentList,
                                                                           targetType,
                                                                           objectCreationExpressionSyntax,
                                                                           diagnostics,
                                                                           asNewVariablePlaceholderOpt)
                    Case SyntaxKind.AnonymousObjectCreationExpression
                        boundInitExpression = BindAnonymousObjectCreationExpression(
                                                    DirectCast(asNew.NewExpression, AnonymousObjectCreationExpressionSyntax), diagnostics)
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(asNew.NewExpression.Kind)
                End Select
 
                fieldInitializerSyntax = asNew
            Else
                Dim valueSyntax = DirectCast(equalsValueOrAsNewSyntax, EqualsValueSyntax)
                fieldInitializerSyntax = valueSyntax.Value
                boundInitExpression = BindValue(DirectCast(fieldInitializerSyntax, ExpressionSyntax), diagnostics)
            End If
 
            If targetType IsNot Nothing Then
                boundInitExpression = ApplyImplicitConversion(boundInitExpression.Syntax,
                                                              targetType,
                                                              boundInitExpression,
                                                              diagnostics)
            Else
                ' Try to reclassify boundInitValue if we still can.
                boundInitExpression = MakeRValueAndIgnoreDiagnostics(boundInitExpression)
            End If
 
            Return boundInitExpression
        End Function
 
        ''' <summary>
        ''' Checks for errors in the constant initialization of a field, and only returns a BoundFieldOrPropertyInitializer for
        ''' decimals and dates because they aren't compile time constant in CLR. Other data type end up directly in metadata and 
        ''' do not cause a BoundFieldOrPropertyInitializer node.
        ''' </summary>
        ''' <param name="fieldSymbol">The field symbol.</param>
        ''' <param name="equalsValueOrAsNewSyntax">The syntax node for the optional initialization.</param>
        ''' <param name="boundInitializers">The array of bound initializers to add the newly bound ones to.</param>
        Private Shared Sub BindConstFieldInitializer(
            fieldSymbol As SourceFieldSymbol,
            equalsValueOrAsNewSyntax As VisualBasicSyntaxNode,
            boundInitializers As ArrayBuilder(Of BoundInitializer))
            Debug.Assert(fieldSymbol.IsConst)
 
            If Not fieldSymbol.IsConstButNotMetadataConstant Then
                Return
            End If
 
            ' Const fields of type Date or Decimal will get initialized in the synthesized shared constructor
            ' because their value is not regarded as compile time constant by the CLR.
            ' This will produce sequence points in the shared constructor which is exactly what Dev10 does.
            Dim constantValue = fieldSymbol.GetConstantValue(VisualBasic.ConstantFieldsInProgress.Empty)
 
            If constantValue IsNot Nothing Then
                Dim meSymbol As ParameterSymbol = Nothing
                Dim boundFieldAccessExpr = New BoundFieldAccess(equalsValueOrAsNewSyntax,
                                                                Nothing,
                                                                fieldSymbol,
                                                                True,
                                                                fieldSymbol.Type)
                boundFieldAccessExpr.SetWasCompilerGenerated()
 
                Dim boundInitValue = New BoundLiteral(equalsValueOrAsNewSyntax,
                                                      constantValue,
                                                      fieldSymbol.Type)
 
                boundInitializers.Add(New BoundFieldInitializer(equalsValueOrAsNewSyntax,
                                                                ImmutableArray.Create(Of FieldSymbol)(fieldSymbol),
                                                                boundFieldAccessExpr,
                                                                boundInitValue,
                                                                binderOpt:=Nothing))
            End If
        End Sub
 
        ''' <summary>
        ''' Binds constant initialization value of the field.
        ''' </summary>
        ''' <param name="fieldSymbol">The symbol.</param>
        ''' <param name="equalsValueOrAsNewSyntax">The initialization syntax.</param>
        ''' <param name="diagnostics">The diagnostics.</param><returns></returns>
        Friend Function BindFieldAndEnumConstantInitializer(
            fieldSymbol As FieldSymbol,
            equalsValueOrAsNewSyntax As VisualBasicSyntaxNode,
            isEnum As Boolean,
            diagnostics As BindingDiagnosticBag,
            <Out> ByRef constValue As ConstantValue
        ) As BoundExpression
            constValue = Nothing
            Dim boundInitValue As BoundExpression = Nothing
            Dim initValueDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=diagnostics.AccumulatesDependencies)
 
            If equalsValueOrAsNewSyntax.Kind = SyntaxKind.EqualsValue Then
                Dim equalsValueSyntax As EqualsValueSyntax = DirectCast(equalsValueOrAsNewSyntax, EqualsValueSyntax)
                boundInitValue = BindValue(equalsValueSyntax.Value, initValueDiagnostics)
            Else
                ' illegal case, const fields cannot be initialized with AsNew
                ' all diagnostics here will be ignored because we are just binding for the purpose of storing
                ' the bound node in a BoundBadNode. The required diagnostics have already been reported in 
                ' SourceFieldSymbol.Type
                Dim asNewSyntax = DirectCast(equalsValueOrAsNewSyntax, AsNewClauseSyntax)
                Dim fieldType = If(fieldSymbol.HasDeclaredType, fieldSymbol.Type, GetSpecialType(SpecialType.System_Object, asNewSyntax, BindingDiagnosticBag.Discarded)) ' prevent recursion if field type is inferred.
                Select Case asNewSyntax.NewExpression.Kind
                    Case SyntaxKind.ObjectCreationExpression
                        Dim objectCreationExpressionSyntax = DirectCast(asNewSyntax.NewExpression,
                                                                        ObjectCreationExpressionSyntax)
                        boundInitValue = BindObjectCreationExpression(asNewSyntax.Type,
                                                                      objectCreationExpressionSyntax.ArgumentList,
                                                                      fieldType,
                                                                      objectCreationExpressionSyntax,
                                                                      BindingDiagnosticBag.Discarded,
                                                                      Nothing)
                    Case SyntaxKind.AnonymousObjectCreationExpression
                        boundInitValue = BindAnonymousObjectCreationExpression(
                                                DirectCast(asNewSyntax.NewExpression, AnonymousObjectCreationExpressionSyntax), BindingDiagnosticBag.Discarded)
                    Case Else
                        Throw ExceptionUtilities.UnexpectedValue(asNewSyntax.NewExpression.Kind)
                End Select
 
                boundInitValue = New BoundBadExpression(boundInitValue.Syntax,
                                                        LookupResultKind.Empty,
                                                        ImmutableArray(Of Symbol).Empty,
                                                        ImmutableArray.Create(boundInitValue),
                                                        fieldType,
                                                        hasErrors:=True)
            End If
 
            If Not boundInitValue.HasErrors Then
                Dim targetType As TypeSymbol
 
                If fieldSymbol.HasDeclaredType Then
                    targetType = fieldSymbol.Type
 
                    If isEnum Then
                        targetType = targetType.GetEnumUnderlyingTypeOrSelf
                    End If
 
                    boundInitValue = ApplyImplicitConversion(boundInitValue.Syntax, targetType, boundInitValue, initValueDiagnostics)
                Else
                    targetType = If(boundInitValue.Type, ErrorTypeSymbol.UnknownResultType)
                End If
 
                Dim boundInitValueHasErrorsOrConstTypeIsWrong As Boolean =
                    initValueDiagnostics.HasAnyResolvedErrors OrElse fieldSymbol.HasDeclaredType AndAlso Not targetType.IsValidTypeForConstField()
 
                ' NOTE: we'll only report ERR_RequiredConstConversion2 ("Conversion from '...' to '.' cannot occur in 
                ' NOTE: a constant expression") and ERR_RequiredConstExpr ("Constant expression is required") in case
                ' NOTE: the type (if declared) is a valid type for const fields. This is different from Dev10 that sometimes
                ' NOTE: reported issues and sometimes not
                ' NOTE: e.g. reports in "const goo as DelegateType = AddressOf methodName" (ERR_ConstAsNonConstant + ERR_RequiredConstExpr)
                ' NOTE: only type diagnostics for "const s as StructureType = nothing"
 
                If boundInitValueHasErrorsOrConstTypeIsWrong Then
                    constValue = Me.GetExpressionConstantValueIfAny(boundInitValue, BindingDiagnosticBag.Discarded, ConstantContext.Default)
                Else
                    constValue = Me.GetExpressionConstantValueIfAny(boundInitValue, initValueDiagnostics, ConstantContext.Default)
                End If
 
                ' e.g. the init value of "Public goo as Byte = 2.2" is still considered as constant and therefore a CByte(2)
                ' is being assigned as the constant value of this field/enum. However in case of Option Strict On there has 
                ' been a diagnostics in the call to ApplyImplicitConversion.
                If constValue Is Nothing Then
                    ' set hasErrors to indicate later check not to add more diagnostics.
                    boundInitValue = BadExpression(boundInitValue.Syntax, boundInitValue, targetType)
                End If
            End If
 
            diagnostics.AddRange(initValueDiagnostics)
            initValueDiagnostics.Free()
 
            Return boundInitValue
        End Function
 
        ''' <summary>
        ''' Binds a constant local's value. 
        ''' </summary>
        ''' <param name="symbol">The local symbol.</param>
        ''' <param name="type">The local symbol's type. It is passed in because this method is called while the type is being resolved and before it is set.</param>
        Friend Function BindLocalConstantInitializer(symbol As LocalSymbol,
                                                type As TypeSymbol,
                                                name As ModifiedIdentifierSyntax,
                                                equalsValueOpt As EqualsValueSyntax,
                                                diagnostics As BindingDiagnosticBag,
                                                <Out> ByRef constValue As ConstantValue) As BoundExpression
            constValue = Nothing
 
            Dim valueExpression As BoundExpression = Nothing
 
            If equalsValueOpt IsNot Nothing Then
                Dim valueSyntax = equalsValueOpt.Value
 
                If IsBindingImplicitlyTypedLocal(symbol) Then
                    ReportDiagnostic(diagnostics, name, ERRID.ERR_CircularEvaluation1, symbol)
                    Return BadExpression(valueSyntax, ErrorTypeSymbol.UnknownResultType)
                End If
 
                Dim binder = New LocalInProgressBinder(Me, symbol)
 
                valueExpression = binder.BindValue(valueSyntax, diagnostics)
 
                ' When inferring the type, the type is nothing.  Only apply conversion if there is a type. If there isn't a type then the
                ' constant gets the expression type and there is no need to apply a conversion.
                If type IsNot Nothing Then
                    valueExpression = binder.ApplyImplicitConversion(valueSyntax, type, valueExpression, diagnostics)
                End If
 
                If Not valueExpression.HasErrors Then
 
                    ' ExpressionIsConstant is called to report diagnostics at the correct location in the expression.
                    ' Only call ExpressionIsConstant if the expression is good to avoid reporting a bad expression is not
                    ' a constant. 
                    If (valueExpression.Type Is Nothing OrElse Not valueExpression.Type.IsErrorType) Then
                        constValue = binder.GetExpressionConstantValueIfAny(valueExpression, diagnostics, ConstantContext.Default)
                        If constValue IsNot Nothing Then
                            Return valueExpression
                        End If
                    End If
 
                    ' The result is not a constant and is not marked with hasErrors so return a BadExpression.
                    Return BadExpression(valueSyntax, valueExpression, ErrorTypeSymbol.UnknownResultType).MakeCompilerGenerated()
 
                End If
 
            Else
                valueExpression = BadExpression(name, ErrorTypeSymbol.UnknownResultType).MakeCompilerGenerated()
                ReportDiagnostic(diagnostics, name, ERRID.ERR_ConstantWithNoValue)
            End If
 
            Return valueExpression
        End Function
 
        ''' <summary>
        ''' Binds a parameter's default value syntax
        ''' </summary>
        Friend Function BindParameterDefaultValue(
            targetType As TypeSymbol,
            equalsValueSyntax As EqualsValueSyntax,
            diagnostics As BindingDiagnosticBag,
            <Out> ByRef constValue As ConstantValue
        ) As BoundExpression
            constValue = Nothing
 
            Dim boundInitValue As BoundExpression = BindValue(equalsValueSyntax.Value, diagnostics)
 
            If Not boundInitValue.HasErrors Then
 
                ' Check if the constant can be converted to the parameter type.
                If Not targetType.IsErrorType Then
                    boundInitValue = ApplyImplicitConversion(boundInitValue.Syntax, targetType, boundInitValue, diagnostics)
                End If
 
                ' Report errors if value is not a constant.
                constValue = GetExpressionConstantValueIfAny(boundInitValue, diagnostics, ConstantContext.ParameterDefaultValue)
                If constValue Is Nothing Then
                    boundInitValue = BadExpression(boundInitValue.Syntax, boundInitValue, targetType)
                End If
            End If
 
            Return boundInitValue
        End Function
 
    End Class
End Namespace