File: Symbols\ConstantValueUtils.vb
Web Access
Project: src\src\roslyn\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

Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols

    Friend Class EvaluatedConstant
        Public Shared ReadOnly None As New EvaluatedConstant(Nothing, Nothing)

        Public Sub New(value As ConstantValue, type As TypeSymbol)
            ' If a value is provided, a corresponding type must be provided.
            Debug.Assert((value Is Nothing) OrElse value.IsNull OrElse (type IsNot Nothing))
            Me.Value = value
            Me.Type = type
        End Sub

        Public ReadOnly Value As ConstantValue
        Public ReadOnly Type As TypeSymbol
    End Class

    Friend Module ConstantValueUtils
        Public Function EvaluateFieldConstant(field As SourceFieldSymbol, equalsValueOrAsNewNodeRef As SyntaxReference, dependencies As ConstantFieldsInProgress.Dependencies, diagnostics As BindingDiagnosticBag) As EvaluatedConstant
#If DEBUG Then
            Debug.Assert(dependencies IsNot Nothing)
            Debug.Assert(equalsValueOrAsNewNodeRef IsNot Nothing)
#End If

            ' Set up a binder for this part of the type.
            Dim containingModule = field.ContainingSourceType.ContainingSourceModule
            Dim binder As Binder = BinderBuilder.CreateBinderForType(containingModule, equalsValueOrAsNewNodeRef.SyntaxTree, field.ContainingSourceType)
            Dim initValueSyntax As VisualBasicSyntaxNode = equalsValueOrAsNewNodeRef.GetVisualBasicSyntax()

            Dim inProgressBinder = New ConstantFieldsInProgressBinder(New ConstantFieldsInProgress(field, dependencies), binder, field)
            Dim constValue As ConstantValue = Nothing
            Dim boundValue = BindFieldOrEnumInitializer(inProgressBinder, field, initValueSyntax, diagnostics, constValue)

            Dim boundValueType As TypeSymbol

            ' if an untyped constant gets initialized with a nothing literal, it's type should be System.Object.
            If boundValue.IsNothingLiteral Then
                boundValueType = binder.GetSpecialType(SpecialType.System_Object, initValueSyntax, diagnostics)
            Else
                boundValueType = boundValue.Type
            End If

            Dim value As ConstantValue = If(constValue, ConstantValue.Bad)
            Return New EvaluatedConstant(value, boundValueType)
        End Function

        Private Function BindFieldOrEnumInitializer(binder As Binder,
                                                    fieldOrEnumSymbol As FieldSymbol,
                                                    equalsValueOrAsNewSyntax As VisualBasicSyntaxNode,
                                                    diagnostics As BindingDiagnosticBag,
                                                    <Out> ByRef constValue As ConstantValue) As BoundExpression

            Debug.Assert(TypeOf fieldOrEnumSymbol Is SourceEnumConstantSymbol OrElse TypeOf fieldOrEnumSymbol Is SourceFieldSymbol)

            Dim enumConstant = TryCast(fieldOrEnumSymbol, SourceEnumConstantSymbol)
            If enumConstant IsNot Nothing Then
                Return binder.BindFieldAndEnumConstantInitializer(enumConstant, equalsValueOrAsNewSyntax, isEnum:=True, diagnostics:=diagnostics, constValue:=constValue)
            Else
                Dim fieldConstant = DirectCast(fieldOrEnumSymbol, SourceFieldSymbol)
                Return binder.BindFieldAndEnumConstantInitializer(fieldConstant, equalsValueOrAsNewSyntax, isEnum:=False, diagnostics:=diagnostics, constValue:=constValue)
            End If
        End Function

        <DebuggerDisplay("{GetDebuggerDisplay(), nq}")>
        Friend Structure FieldInfo
            Public ReadOnly Field As SourceFieldSymbol
            Public ReadOnly StartsCycle As Boolean

            Public Sub New(field As SourceFieldSymbol, startsCycle As Boolean)
                Me.Field = field
                Me.StartsCycle = startsCycle
            End Sub

            Private Function GetDebuggerDisplay() As String
                Dim value = Field.ToString()
                If StartsCycle Then
                    value += " [cycle]"
                End If

                Return value
            End Function
        End Structure

    End Module

End Namespace