File: Symbols\Metadata\PE\PETypeParameterSymbol.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.Generic
Imports System.Collections.Immutable
Imports System.Threading
Imports System.Reflection.Metadata
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports System.Reflection
Imports System.Reflection.Metadata.Ecma335
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.Collections
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols.Metadata.PE
 
    ''' <summary>
    ''' The class to represent all generic type parameters imported from a PE/module.
    ''' </summary>
    ''' <remarks></remarks>
    Friend NotInheritable Class PETypeParameterSymbol
        Inherits SubstitutableTypeParameterSymbol
 
        Private ReadOnly _containingSymbol As Symbol ' Could be PENamedType or a PEMethod
        Private ReadOnly _handle As GenericParameterHandle
        Private _lazyCustomAttributes As ImmutableArray(Of VisualBasicAttributeData)
 
#Region "Metadata"
        Private ReadOnly _name As String
        Private ReadOnly _ordinal As UShort ' 0 for first, 1 for second, ...
        Private ReadOnly _flags As GenericParameterAttributes
#End Region
 
        Private _lazyConstraintTypes As ImmutableArray(Of TypeSymbol)
 
        ''' <summary>
        ''' Actually stores <see cref="ThreeState"/>
        ''' </summary>
        Private _lazyHasIsUnmanagedConstraint As Byte
 
        ''' <summary>
        ''' First error calculating bounds.
        ''' </summary>
        Private _lazyCachedBoundsUseSiteInfo As CachedUseSiteInfo(Of AssemblySymbol) = CachedUseSiteInfo(Of AssemblySymbol).Uninitialized ' Indicates unknown state. 
 
        Friend Sub New(
            moduleSymbol As PEModuleSymbol,
            definingNamedType As PENamedTypeSymbol,
            ordinal As UShort,
            handle As GenericParameterHandle
        )
            Me.New(moduleSymbol, DirectCast(definingNamedType, Symbol), ordinal, handle)
        End Sub
 
        Friend Sub New(
            moduleSymbol As PEModuleSymbol,
            definingMethod As PEMethodSymbol,
            ordinal As UShort,
            handle As GenericParameterHandle
        )
            Me.New(moduleSymbol, DirectCast(definingMethod, Symbol), ordinal, handle)
        End Sub
 
        Private Sub New(
            moduleSymbol As PEModuleSymbol,
            definingSymbol As Symbol,
            ordinal As UShort,
            handle As GenericParameterHandle
        )
            Debug.Assert(moduleSymbol IsNot Nothing)
            Debug.Assert(definingSymbol IsNot Nothing)
            Debug.Assert(ordinal >= 0)
            Debug.Assert(Not handle.IsNil)
 
            _containingSymbol = definingSymbol
 
            Dim flags As GenericParameterAttributes
 
            Try
                moduleSymbol.Module.GetGenericParamPropsOrThrow(handle, _name, flags)
            Catch mrEx As BadImageFormatException
                If _name Is Nothing Then
                    _name = String.Empty
                End If
 
                _lazyCachedBoundsUseSiteInfo.Initialize(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me))
            End Try
 
            ' Clear the '.ctor' flag if both '.ctor' and 'valuetype' are
            ' set since '.ctor' is redundant in that case.
            _flags = If((flags And GenericParameterAttributes.NotNullableValueTypeConstraint) = 0, flags, flags And Not GenericParameterAttributes.DefaultConstructorConstraint)
 
            _ordinal = ordinal
            _handle = handle
        End Sub
 
        Public Overrides ReadOnly Property TypeParameterKind As TypeParameterKind
            Get
                Return If(Me.ContainingSymbol.Kind = SymbolKind.Method,
                          TypeParameterKind.Method,
                          TypeParameterKind.Type)
            End Get
        End Property
 
        Public Overrides ReadOnly Property Ordinal As Integer
            Get
                Return _ordinal
            End Get
        End Property
 
        Public Overrides ReadOnly Property Name As String
            Get
                Return _name
            End Get
        End Property
 
        Public Overrides ReadOnly Property MetadataToken As Integer
            Get
                Return MetadataTokens.GetToken(_handle)
            End Get
        End Property
 
        Friend ReadOnly Property Handle As GenericParameterHandle
            Get
                Return Me._handle
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingSymbol As Symbol
            Get
                Return _containingSymbol
            End Get
        End Property
 
        Public Overrides ReadOnly Property ContainingAssembly As AssemblySymbol
            Get
                Return _containingSymbol.ContainingAssembly
            End Get
        End Property
 
        Public Overloads Overrides Function GetAttributes() As ImmutableArray(Of VisualBasicAttributeData)
            If _lazyCustomAttributes.IsDefault Then
                Dim containingPEModuleSymbol = DirectCast(ContainingModule(), PEModuleSymbol)
                containingPEModuleSymbol.LoadCustomAttributes(_handle, _lazyCustomAttributes)
            End If
            Return _lazyCustomAttributes
        End Function
 
        Friend Overrides ReadOnly Property ConstraintTypesNoUseSiteDiagnostics As ImmutableArray(Of TypeSymbol)
            Get
                EnsureAllConstraintsAreResolved()
                Return _lazyConstraintTypes
            End Get
        End Property
 
        Friend Overrides ReadOnly Property HasUnmanagedTypeConstraint As Boolean
            Get
                EnsureAllConstraintsAreResolved()
                Return CType(Volatile.Read(_lazyHasIsUnmanagedConstraint), ThreeState).Value()
            End Get
        End Property
 
        Private Function GetDeclaredConstraints(<Out> ByRef hasUnmanagedModreqPattern As Boolean) As ImmutableArray(Of TypeParameterConstraint)
            Dim constraintsBuilder = ArrayBuilder(Of TypeParameterConstraint).GetInstance()
 
            hasUnmanagedModreqPattern = False
 
            If HasConstructorConstraint Then
                constraintsBuilder.Add(New TypeParameterConstraint(TypeParameterConstraintKind.Constructor, Nothing))
            End If
 
            If HasReferenceTypeConstraint Then
                constraintsBuilder.Add(New TypeParameterConstraint(TypeParameterConstraintKind.ReferenceType, Nothing))
            End If
 
            If HasValueTypeConstraint Then
                constraintsBuilder.Add(New TypeParameterConstraint(TypeParameterConstraintKind.ValueType, Nothing))
            End If
 
            Dim containingMethod As PEMethodSymbol = Nothing
            Dim containingType As PENamedTypeSymbol
 
            If _containingSymbol.Kind = SymbolKind.Method Then
                containingMethod = DirectCast(_containingSymbol, PEMethodSymbol)
                containingType = DirectCast(containingMethod.ContainingSymbol, PENamedTypeSymbol)
            Else
                containingType = DirectCast(_containingSymbol, PENamedTypeSymbol)
            End If
 
            Dim moduleSymbol = containingType.ContainingPEModule
            Dim metadataReader = moduleSymbol.Module.MetadataReader
            Dim constraints As GenericParameterConstraintHandleCollection
 
            Try
                constraints = metadataReader.GetGenericParameter(_handle).GetConstraints()
            Catch mrEx As BadImageFormatException
                constraints = Nothing
                _lazyCachedBoundsUseSiteInfo.InterlockedInitializeFromSentinel(primaryDependency:=Nothing, New UseSiteInfo(Of AssemblySymbol)(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me)))
            End Try
 
            If constraints.Count > 0 Then
                Dim tokenDecoder As MetadataDecoder
                If containingMethod IsNot Nothing Then
                    tokenDecoder = New MetadataDecoder(moduleSymbol, containingMethod)
                Else
                    tokenDecoder = New MetadataDecoder(moduleSymbol, containingType)
                End If
 
                For Each constraintHandle In constraints
                    Dim typeSymbol As TypeSymbol = GetConstraintType(metadataReader, tokenDecoder, constraintHandle, hasUnmanagedModreqPattern)
 
                    ' Drop 'System.ValueType' constraint type if the 'valuetype' constraint was also specified.
                    If ((_flags And GenericParameterAttributes.NotNullableValueTypeConstraint) <> 0) AndAlso
                        (typeSymbol.SpecialType = Microsoft.CodeAnalysis.SpecialType.System_ValueType) Then
                        Continue For
                    End If
 
                    typeSymbol = TupleTypeDecoder.DecodeTupleTypesIfApplicable(typeSymbol,
                                                                               constraintHandle,
                                                                               moduleSymbol)
 
                    constraintsBuilder.Add(New TypeParameterConstraint(typeSymbol, Nothing))
                Next
            End If
 
            ' - presence of unmanaged pattern has to be matched with `valuetype`
            ' - IsUnmanagedAttribute is allowed if there is an unmanaged pattern
            If (hasUnmanagedModreqPattern AndAlso (_flags And GenericParameterAttributes.NotNullableValueTypeConstraint) = 0) OrElse
               hasUnmanagedModreqPattern <> moduleSymbol.Module.HasIsUnmanagedAttribute(_handle) Then
                ' we do not recognize these combinations as "unmanaged"
                hasUnmanagedModreqPattern = False
                _lazyCachedBoundsUseSiteInfo.InterlockedInitializeFromSentinel(primaryDependency:=Nothing, New UseSiteInfo(Of AssemblySymbol)(ErrorFactory.ErrorInfo(ERRID.ERR_UnsupportedType1, Me)))
            End If
 
            Return constraintsBuilder.ToImmutableAndFree()
        End Function
 
        Private Shared Function GetConstraintType(
            metadataReader As MetadataReader,
            tokenDecoder As MetadataDecoder,
            constraintHandle As GenericParameterConstraintHandle,
            ByRef hasUnmanagedModreqPattern As Boolean
        ) As TypeSymbol
 
            Dim constraint = metadataReader.GetGenericParameterConstraint(constraintHandle)
            Dim modifiers As ImmutableArray(Of ModifierInfo(Of TypeSymbol)) = Nothing
            Dim typeSymbol = tokenDecoder.DecodeGenericParameterConstraint(constraint.Type, modifiers)
 
            If Not modifiers.IsDefaultOrEmpty AndAlso modifiers.Length > 1 Then
                typeSymbol = New UnsupportedMetadataTypeSymbol()
            ElseIf typeSymbol.SpecialType = SpecialType.System_ValueType Then
                ' recognize "(class [mscorlib]System.ValueType modreq([mscorlib]System.Runtime.InteropServices.UnmanagedType" pattern as "unmanaged"
                If Not modifiers.IsDefaultOrEmpty Then
                    Dim m As ModifierInfo(Of TypeSymbol) = modifiers.Single()
                    If Not m.IsOptional AndAlso m.Modifier.IsWellKnownTypeUnmanagedType() Then
                        hasUnmanagedModreqPattern = True
                    Else
                        ' Any other modifiers, optional or not, are not allowed
                        typeSymbol = New UnsupportedMetadataTypeSymbol()
                    End If
                End If
            ElseIf Not modifiers.IsDefaultOrEmpty Then
                ' Any other modifiers, optional or not, are not allowed
                typeSymbol = New UnsupportedMetadataTypeSymbol()
            End If
 
            Return typeSymbol
        End Function
 
        Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location)
            Get
                Return _containingSymbol.Locations
            End Get
        End Property
 
        Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference)
            Get
                Return ImmutableArray(Of SyntaxReference).Empty
            End Get
        End Property
 
        Public Overrides ReadOnly Property HasConstructorConstraint As Boolean
            Get
                Return (_flags And GenericParameterAttributes.DefaultConstructorConstraint) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property HasReferenceTypeConstraint As Boolean
            Get
                Return (_flags And GenericParameterAttributes.ReferenceTypeConstraint) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property HasValueTypeConstraint As Boolean
            Get
                Return (_flags And GenericParameterAttributes.NotNullableValueTypeConstraint) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property AllowsRefLikeType As Boolean
            Get
                Return (_flags And MetadataHelpers.GenericParameterAttributesAllowByRefLike) <> 0
            End Get
        End Property
 
        Public Overrides ReadOnly Property Variance As VarianceKind
            Get
                Return CType((_flags And GenericParameterAttributes.VarianceMask), VarianceKind)
            End Get
        End Property
 
        Friend Overrides Sub EnsureAllConstraintsAreResolved()
            If RoslynImmutableInterlocked.VolatileRead(_lazyConstraintTypes).IsDefault Then
                Dim typeParameters = If(_containingSymbol.Kind = SymbolKind.Method,
                                        DirectCast(_containingSymbol, PEMethodSymbol).TypeParameters,
                                        DirectCast(_containingSymbol, PENamedTypeSymbol).TypeParameters)
                EnsureAllConstraintsAreResolved(typeParameters)
            End If
        End Sub
 
        Friend Overrides Sub ResolveConstraints(inProgress As ConsList(Of TypeParameterSymbol))
            Debug.Assert(Not inProgress.Contains(Me))
            Debug.Assert(Not inProgress.Any() OrElse inProgress.Head.ContainingSymbol Is ContainingSymbol)
 
            If RoslynImmutableInterlocked.VolatileRead(_lazyConstraintTypes).IsDefault Then
                Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance()
                Dim inherited = (_containingSymbol.Kind = SymbolKind.Method) AndAlso DirectCast(_containingSymbol, MethodSymbol).IsOverrides
                Dim hasUnmanagedModreqPattern As Boolean = False
 
                ' Check direct constraints on the type parameter to generate any use-site errors
                ' (for example, the cycle in ".class public A<(!T)T>"). It's necessary to check for such
                ' errors because invalid constraints are dropped in those cases so use of such
                ' types/methods is otherwise valid. It shouldn't be necessary to check indirect
                ' constraints because any indirect constraints are retained, even if invalid, so
                ' references to such types/methods cannot be satisfied for specific type arguments.
                ' (An example of an indirect constraint conflict, U in ".class public C<(A)T, (!T, B)U>",
                ' which cannot be satisfied if A and B are from different hierarchies.) It also isn't
                ' necessary to report redundant constraints since redundant constraints are still
                ' valid. Redundant constraints are dropped silently.
                Dim constraints = Me.RemoveDirectConstraintConflicts(GetDeclaredConstraints(hasUnmanagedModreqPattern), inProgress.Prepend(Me), DirectConstraintConflictKind.None, diagnosticsBuilder)
                Dim primaryDependency As AssemblySymbol = Me.PrimaryDependency
 
                Dim useSiteInfo As New UseSiteInfo(Of AssemblySymbol)(primaryDependency)
 
                For Each pair In diagnosticsBuilder
                    MergeUseSiteInfo(useSiteInfo, pair.UseSiteInfo)
                    If useSiteInfo.DiagnosticInfo IsNot Nothing Then
                        Exit For
                    End If
                Next
 
                diagnosticsBuilder.Free()
 
                _lazyCachedBoundsUseSiteInfo.InterlockedInitializeFromSentinel(primaryDependency, useSiteInfo)
                _lazyHasIsUnmanagedConstraint = hasUnmanagedModreqPattern.ToThreeState()
 
                ' Note, we are relying on the fact that _lazyConstraintTypes is initialized last, and
                ' we depend on the memory barrier from this interlocked operation to prevent write reordering
                ImmutableInterlocked.InterlockedInitialize(_lazyConstraintTypes, GetConstraintTypesOnly(constraints))
            End If
 
            Debug.Assert(_lazyCachedBoundsUseSiteInfo.IsInitialized)
        End Sub
 
        Friend Overrides Function GetConstraintsUseSiteInfo() As UseSiteInfo(Of AssemblySymbol)
            EnsureAllConstraintsAreResolved()
            Debug.Assert(_lazyCachedBoundsUseSiteInfo.IsInitialized)
            Return _lazyCachedBoundsUseSiteInfo.ToUseSiteInfo(PrimaryDependency)
        End Function
 
        Friend Function DeriveCompilerFeatureRequiredDiagnostic(decoder As MetadataDecoder) As DiagnosticInfo
            Return DeriveCompilerFeatureRequiredAttributeDiagnostic(Me, DirectCast(ContainingModule, PEModuleSymbol), Handle, CompilerFeatureRequiredFeatures.None, decoder)
        End Function
 
        ''' <remarks>
        ''' This is for perf, not for correctness.
        ''' </remarks>
        Friend Overrides ReadOnly Property DeclaringCompilation As VisualBasicCompilation
            Get
                Return Nothing
            End Get
        End Property
 
        Public Overrides ReadOnly Property HasUnsupportedMetadata As Boolean
            Get
                Dim containingModule = DirectCast(Me.ContainingModule, PEModuleSymbol)
                Dim containingMethod = TryCast(Me.ContainingSymbol, PEMethodSymbol)
                Dim decoder = If(containingMethod IsNot Nothing,
                    New MetadataDecoder(containingModule, containingMethod),
                    New MetadataDecoder(containingModule, DirectCast(ContainingSymbol, PENamedTypeSymbol)))
                Dim info As DiagnosticInfo = DeriveCompilerFeatureRequiredDiagnostic(decoder)
 
                Return info IsNot Nothing AndAlso info.Code = DirectCast(ERRID.ERR_UnsupportedCompilerFeature, Integer) OrElse MyBase.HasUnsupportedMetadata
            End Get
        End Property
 
    End Class
 
End Namespace