File: Symbols\ConstraintsHelper.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.Diagnostics
Imports System.Runtime.CompilerServices
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
 
    ''' <summary>
    ''' A tuple of TypeParameterSymbol and DiagnosticInfo, created for errors
    ''' reported from ConstraintsHelper rather than creating Diagnostics directly.
    ''' This decouples constraints checking from syntax and Locations, and supports
    ''' callers that may want to create Location instances lazily or not at all.
    ''' </summary>
    Friend Structure TypeParameterDiagnosticInfo
 
        Public Sub New(typeParameter As TypeParameterSymbol, useSiteInfo As UseSiteInfo(Of AssemblySymbol))
            Me.TypeParameter = typeParameter
            Me.UseSiteInfo = useSiteInfo
        End Sub
 
        Public Sub New(typeParameter As TypeParameterSymbol, diagnostic As DiagnosticInfo)
            Me.New(typeParameter, New UseSiteInfo(Of AssemblySymbol)(diagnostic))
        End Sub
 
        Public Sub New(typeParameter As TypeParameterSymbol, constraint As TypeParameterConstraint, diagnostic As DiagnosticInfo)
            Me.New(typeParameter, diagnostic)
            Me.Constraint = constraint
        End Sub
 
        Public ReadOnly TypeParameter As TypeParameterSymbol
        Public ReadOnly Constraint As TypeParameterConstraint
        Public ReadOnly UseSiteInfo As UseSiteInfo(Of AssemblySymbol)
    End Structure
 
    <Flags()>
    Friend Enum DirectConstraintConflictKind
        None = 0
        DuplicateTypeConstraint = 1 << 0
        RedundantConstraint = 1 << 1
        All = (1 << 2) - 1
    End Enum
 
    ''' <summary>
    ''' Helper methods for generic type parameter constraints. There are two sets of methods: one
    ''' set for resolving constraint "bounds" (that is, determining the effective base type, interface set,
    ''' etc.), and another set for checking for constraint violations in type and method references.
    ''' 
    ''' Bounds are resolved by calling one of the ResolveBounds overloads. Typically bounds are
    ''' resolved by each TypeParameterSymbol at, or before, one of the corresponding properties
    ''' (BaseType, Interfaces, etc.) is accessed. Resolving bounds may result in errors (cycles,
    ''' inconsistent constraints, etc.) and it is the responsibility of the caller to report any such
    ''' errors as declaration errors or use-site errors (depending on whether the type parameter
    ''' was from source or metadata) and to ensure bounds are resolved for source type parameters
    ''' even if the corresponding properties are never accessed directly.
    ''' 
    ''' Constraints are checked by calling one of the CheckConstraints or CheckAllConstraints
    ''' overloads for any generic type or method reference from source. In some circumstances,
    ''' references are checked at the time the generic type or generic method is bound and constructed
    ''' by the Binder. In those case, it is sufficient to call one of the CheckConstraints overloads
    ''' since compound types (such as A(Of T).B(Of U) or A(Of B(Of T))) are checked incrementally
    ''' as each part is bound. In other cases however, constraint checking needs to be delayed to
    ''' prevent cycles where checking constraints requires binding the syntax that is currently
    ''' being bound (such as the constraint in Class C(Of T As C(Of T)). In those cases, the caller
    ''' must lazily check constraints, and since the types may be compound types, it is necessary
    ''' to call CheckAllConstraints.
    ''' </summary>
    Friend Module ConstraintsHelper
 
        ''' <summary>
        ''' Enum used internally by RemoveDirectConstraintConflicts to
        ''' track what type constraint has been seen, to report conflicts
        ''' between { 'Structure', 'Class', [explicit type] }. The 'New'
        ''' constraint does not need to be tracked for those conflicts.
        ''' </summary>
        Private Enum DirectTypeConstraintKind
            None
            ReferenceTypeConstraint
            ValueTypeConstraint
            ExplicitType
        End Enum
 
        ''' <summary>
        ''' Return the constraints for the type parameter with any cycles
        ''' or conflicting constraints reported as errors and removed.
        ''' </summary>
        <Extension()>
        Public Function RemoveDirectConstraintConflicts(
                                     typeParameter As TypeParameterSymbol,
                                     constraints As ImmutableArray(Of TypeParameterConstraint),
                                     inProgress As ConsList(Of TypeParameterSymbol),
                                     reportConflicts As DirectConstraintConflictKind,
                                     diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo)) As ImmutableArray(Of TypeParameterConstraint)
            If constraints.Length > 0 Then
                Dim constraintsBuilder = ArrayBuilder(Of TypeParameterConstraint).GetInstance()
                Dim containingSymbol = typeParameter.ContainingSymbol
                Dim explicitKind = DirectTypeConstraintKind.None
                Dim reportRedundantConstraints = (reportConflicts And DirectConstraintConflictKind.RedundantConstraint) <> 0
 
                For Each constraint In constraints
                    ' See Bindable::ValidateDirectConstraint.
                    Select Case constraint.Kind
                        Case TypeParameterConstraintKind.ReferenceType
                            If reportRedundantConstraints Then
                                If explicitKind = DirectTypeConstraintKind.None Then
                                    explicitKind = DirectTypeConstraintKind.ReferenceTypeConstraint
                                Else
                                    ' Combinations of {Class, Structure} should have
                                    ' been caught and discarded during binding.
                                    Debug.Assert(explicitKind = DirectTypeConstraintKind.ExplicitType)
 
                                    ' "'Class' constraint and a specific class type constraint cannot be combined."
                                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                           constraint,
                                                                                           ErrorFactory.ErrorInfo(ERRID.ERR_RefAndClassTypeConstrCombined)))
                                    Continue For
                                End If
                            End If
 
                        Case TypeParameterConstraintKind.ValueType
                            If reportRedundantConstraints Then
                                If explicitKind = DirectTypeConstraintKind.None Then
                                    explicitKind = DirectTypeConstraintKind.ValueTypeConstraint
                                Else
                                    ' Combinations of {Class, Structure} should have
                                    ' been caught and discarded during binding.
                                    Debug.Assert(explicitKind = DirectTypeConstraintKind.ExplicitType)
 
                                    ' "'Structure' constraint and a specific class type constraint cannot be combined."
                                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                           constraint,
                                                                                           ErrorFactory.ErrorInfo(ERRID.ERR_ValueAndClassTypeConstrCombined)))
                                    Continue For
                                End If
                            End If
 
                        Case TypeParameterConstraintKind.None
                            Dim constraintType = constraint.TypeConstraint
                            Dim duplicate As Boolean = ContainsTypeConstraint(constraintsBuilder, constraintType)
 
                            ' Check for duplicate type constraints.
                            If duplicate Then
                                If (reportConflicts And DirectConstraintConflictKind.DuplicateTypeConstraint) <> 0 Then
                                    ' "Constraint type '{0}' already specified for this type parameter.'
                                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                           constraint,
                                                                                           ErrorFactory.ErrorInfo(ERRID.ERR_ConstraintAlreadyExists1, constraintType)))
                                End If
 
                                ' Continue with other checks for this constraint type, even
                                ' though it's a duplicate, for consistency with Dev10.
                            End If
 
                            Select Case constraintType.TypeKind
                                Case TypeKind.Class
                                    If reportRedundantConstraints Then
                                        Select Case explicitKind
                                            Case DirectTypeConstraintKind.None
                                                Dim classType = DirectCast(constraintType, NamedTypeSymbol)
                                                If classType.IsNotInheritable Then
                                                    ' "Type constraint cannot be a 'NotInheritable' class."
                                                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                                           constraint,
                                                                                                           ErrorFactory.ErrorInfo(ERRID.ERR_ClassConstraintNotInheritable1)))
 
                                                Else
                                                    Select Case constraintType.SpecialType
                                                        Case SpecialType.System_Object,
                                                            SpecialType.System_ValueType,
                                                            SpecialType.System_Enum,
                                                            SpecialType.System_Delegate,
                                                            SpecialType.System_MulticastDelegate,
                                                            SpecialType.System_Array
                                                            ' "'{0}' cannot be used as a type constraint."
                                                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                                                   constraint,
                                                                                                                   ErrorFactory.ErrorInfo(ERRID.ERR_ConstraintIsRestrictedType1, constraintType)))
                                                    End Select
 
                                                End If
 
                                                explicitKind = DirectTypeConstraintKind.ExplicitType
 
                                            Case DirectTypeConstraintKind.ReferenceTypeConstraint
                                                ' "'Class' constraint and a specific class type constraint cannot be combined."
                                                diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                                       constraint,
                                                                                                       ErrorFactory.ErrorInfo(ERRID.ERR_RefAndClassTypeConstrCombined)))
                                                Continue For
 
                                            Case DirectTypeConstraintKind.ValueTypeConstraint
                                                ' "'Structure' constraint and a specific class type constraint cannot be combined."
                                                diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                                       constraint,
                                                                                                       ErrorFactory.ErrorInfo(ERRID.ERR_ValueAndClassTypeConstrCombined)))
                                                Continue For
 
                                            Case DirectTypeConstraintKind.ExplicitType
                                                ' "Type parameter '{0}' can only have one constraint that is a class."
                                                diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                                       constraint,
                                                                                                       ErrorFactory.ErrorInfo(ERRID.ERR_MultipleClassConstraints1, typeParameter)))
                                                Continue For
 
                                        End Select
                                    End If
 
                                Case TypeKind.Interface,
                                    TypeKind.Error
 
                                Case TypeKind.Module
                                    ' No error reported for Module. If the type reference was in source, BC30371
                                    ' ERR_ModuleAsType1 will have been reported binding the type reference.
 
                                Case TypeKind.TypeParameter
                                    Dim constraintTypeParameter = DirectCast(constraintType, TypeParameterSymbol)
 
                                    If constraintTypeParameter.ContainingSymbol = containingSymbol Then
                                        ' The constraint type parameter is from the same containing type or method.
                                        If inProgress.ContainsReference(constraintTypeParameter) Then
                                            ' "Type parameter '{0}' cannot be constrained to itself: {1}"
                                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(constraintTypeParameter,
                                                                                                   constraint,
                                                                                                   ErrorFactory.ErrorInfo(ERRID.ERR_ConstraintCycle2, constraintTypeParameter, GetConstraintCycleInfo(inProgress))))
                                            Continue For
                                        Else
                                            ' Traverse constraint type parameter constraints to detect cycles.
                                            constraintTypeParameter.ResolveConstraints(inProgress)
                                        End If
                                    End If
 
                                    If reportRedundantConstraints AndAlso constraintTypeParameter.HasValueTypeConstraint Then
                                        ' "Type parameter with a 'Structure' constraint cannot be used as a constraint."
                                        diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(constraintTypeParameter,
                                                                                               constraint,
                                                                                               ErrorFactory.ErrorInfo(ERRID.ERR_TypeParamWithStructConstAsConst)))
                                        Continue For
                                    End If
 
                                Case TypeKind.Array,
                                    TypeKind.Delegate,
                                    TypeKind.Enum,
                                    TypeKind.Structure
                                    If reportRedundantConstraints Then
                                        ' "Type constraint '{0}' must be either a class, interface or type parameter."
                                        diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                               constraint,
                                                                                               ErrorFactory.ErrorInfo(ERRID.ERR_ConstNotClassInterfaceOrTypeParam1, constraintType)))
                                    End If
 
                                Case Else
                                    Throw ExceptionUtilities.UnexpectedValue(constraintType.TypeKind)
 
                            End Select
 
                            If duplicate Then
                                Continue For
                            End If
 
                    End Select
 
                    constraintsBuilder.Add(constraint)
                Next
 
                If constraintsBuilder.Count <> constraints.Length Then
                    constraints = constraintsBuilder.ToImmutable()
                End If
 
                constraintsBuilder.Free()
            End If
 
            Return constraints
        End Function
 
        ' Currently, this method should be called for SourceTypeParameterSymbols
        ' only, not PETypeParameterSymbols. If that changes, and this method is
        ' called for type parameters from metadata, we need to ensure a use-site
        ' error is generated if conflicts are found. Add a unit test if that's the case.
        ' See Bindable::ValidateIndirectConstraints.
        <Extension()>
        Public Sub ReportIndirectConstraintConflicts(
                                     typeParameter As SourceTypeParameterSymbol,
                                     diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                     <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo))
 
            Dim constraints = ArrayBuilder(Of TypeParameterAndConstraint).GetInstance()
            typeParameter.GetAllConstraints(constraints, fromConstraintOpt:=Nothing)
 
            Dim n = constraints.Count
            For i = 0 To n - 1
                Dim pair1 = constraints(i)
                If pair1.IsBad Then
                    Continue For
                End If
 
                For j = i + 1 To n - 1
                    Dim pair2 = constraints(j)
                    If pair2.IsBad Then
                        Continue For
                    End If
 
                    Dim bad = False
 
                    Dim useSiteInfo As New CompoundUseSiteInfo(Of AssemblySymbol)(typeParameter.ContainingAssembly)
 
                    If (pair1.TypeParameter Is typeParameter) AndAlso (pair2.TypeParameter Is typeParameter) Then
                        ' Check direct constraints to handle inherited constraints on overridden methods.
                        If HasConflict(pair1.Constraint, pair2.Constraint, useSiteInfo) Then
                            ' "Constraint '{0}' conflicts with the constraint '{1}' already specified for type parameter '{2}'."
                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                   pair2.Constraint,
                                                                                   ErrorFactory.ErrorInfo(
                                                                                       ERRID.ERR_ConflictingDirectConstraints3,
                                                                                       pair2.Constraint.ToDisplayFormat(),
                                                                                       pair1.Constraint.ToDisplayFormat(),
                                                                                       typeParameter)))
                            bad = True
                        End If
 
                    ElseIf (pair1.TypeParameter Is pair2.TypeParameter) Then
                        ' Skip other cases where both constraints are from the same type
                        ' parameter but not the current type parameter since those cases
                        ' will be reported directly on the other type parameter.
 
                    ElseIf HasConflict(pair1.Constraint, pair2.Constraint, useSiteInfo) Then
                        If pair1.TypeParameter Is typeParameter Then
                            ' "Constraint '{0}' conflicts with the indirect constraint '{1}' obtained from the type parameter constraint '{2}'."
                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                   pair1.Constraint,
                                                                                   ErrorFactory.ErrorInfo(
                                                                                       ERRID.ERR_ConstraintClashDirectIndirect3,
                                                                                       pair1.Constraint.ToDisplayFormat(),
                                                                                       pair2.Constraint.ToDisplayFormat(),
                                                                                       pair2.TypeParameter)))
                            bad = True
 
                        ElseIf pair2.TypeParameter Is typeParameter Then
                            ' "Indirect constraint '{0}' obtained from the type parameter constraint '{1}' conflicts with the constraint '{2}'."
                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                   pair1.Constraint,
                                                                                   ErrorFactory.ErrorInfo(
                                                                                       ERRID.ERR_ConstraintClashIndirectDirect3,
                                                                                       pair1.Constraint.ToDisplayFormat(),
                                                                                       pair1.TypeParameter,
                                                                                       pair2.Constraint.ToDisplayFormat())))
                            bad = True
 
                        Else
                            ' "Indirect constraint '{0}' obtained from the type parameter constraint '{1}' conflicts with the indirect constraint '{2}' obtained from the type parameter constraint '{3}'."
                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                                   pair2.Constraint,
                                                                                   ErrorFactory.ErrorInfo(
                                                                                       ERRID.ERR_ConstraintClashIndirectIndirect4,
                                                                                       pair2.Constraint.ToDisplayFormat(),
                                                                                       pair2.TypeParameter,
                                                                                       pair1.Constraint.ToDisplayFormat(),
                                                                                       pair1.TypeParameter)))
                            bad = True
 
                        End If
                    End If
 
                    If AppendUseSiteInfo(useSiteInfo, typeParameter, useSiteDiagnosticsBuilder) Then
                        bad = True
                    End If
 
                    If bad Then
                        constraints(j) = pair2.ToBad()
                    End If
                Next
            Next
 
            constraints.Free()
        End Sub
 
        <Extension()>
        Public Sub CheckAllConstraints(
                                        type As TypeSymbol,
                                        languageVersion As LanguageVersion,
                                        loc As Location,
                                        diagnostics As BindingDiagnosticBag,
                                        template As CompoundUseSiteInfo(Of AssemblySymbol))
            Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance()
            Dim useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo) = Nothing
            type.CheckAllConstraints(languageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
 
            If useSiteDiagnosticsBuilder IsNot Nothing Then
                diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder)
            End If
 
            For Each diagnostic In diagnosticsBuilder
                diagnostics.Add(diagnostic.UseSiteInfo, loc)
            Next
 
            diagnosticsBuilder.Free()
        End Sub
 
        ''' <summary>
        ''' Check all generic constraints on the given type and any containing types
        ''' (such as A(Of T) in A(Of T).B(Of U)). This includes checking constraints
        ''' on generic types within the type (such as B(Of T) in A(Of B(Of T)())).
        ''' </summary>
        <Extension()>
        Public Sub CheckAllConstraints(
                                        type As TypeSymbol,
                                        languageVersion As LanguageVersion,
                                        diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        template As CompoundUseSiteInfo(Of AssemblySymbol))
            Dim diagnostics As New CheckConstraintsDiagnosticsBuilders()
            diagnostics.diagnosticsBuilder = diagnosticsBuilder
            diagnostics.useSiteDiagnosticsBuilder = useSiteDiagnosticsBuilder
            diagnostics.template = template
            diagnostics.languageVersion = languageVersion
 
            type.VisitType(s_checkConstraintsSingleTypeFunc, diagnostics)
 
            useSiteDiagnosticsBuilder = diagnostics.useSiteDiagnosticsBuilder
        End Sub
 
        Private Class CheckConstraintsDiagnosticsBuilders
            Public diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo)
            Public useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo)
            Public template As CompoundUseSiteInfo(Of AssemblySymbol)
            Public languageVersion As LanguageVersion
        End Class
 
        Private ReadOnly s_checkConstraintsSingleTypeFunc As Func(Of TypeSymbol, CheckConstraintsDiagnosticsBuilders, Boolean) = AddressOf CheckConstraintsSingleType
 
        Private Function CheckConstraintsSingleType(type As TypeSymbol, diagnostics As CheckConstraintsDiagnosticsBuilders) As Boolean
            If type.Kind = SymbolKind.NamedType Then
                DirectCast(type, NamedTypeSymbol).CheckConstraints(
                    diagnostics.languageVersion, diagnostics.diagnosticsBuilder, diagnostics.useSiteDiagnosticsBuilder, diagnostics.template)
            End If
            Return False ' continue walking types
        End Function
 
        <Extension()>
        Public Sub CheckConstraints(
                                    tuple As TupleTypeSymbol,
                                    syntaxNode As SyntaxNode,
                                    elementLocations As ImmutableArray(Of Location),
                                    diagnostics As BindingDiagnosticBag,
                                    template As CompoundUseSiteInfo(Of AssemblySymbol))
            Dim type As NamedTypeSymbol = tuple.TupleUnderlyingType
            If Not RequiresChecking(type) Then
                Return
            End If
 
            If syntaxNode.HasErrors Then
                Return
            End If
 
            Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance()
            Dim underlyingTupleTypeChain = ArrayBuilder(Of NamedTypeSymbol).GetInstance
            TupleTypeSymbol.GetUnderlyingTypeChain(type, underlyingTupleTypeChain)
 
            Dim offset As Integer = 0
            For Each underlyingTuple In underlyingTupleTypeChain
                Dim useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo) = Nothing
                CheckTypeConstraints(underlyingTuple,
                                     DirectCast(syntaxNode.SyntaxTree.Options, VisualBasicParseOptions).LanguageVersion,
                                     diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
 
                If useSiteDiagnosticsBuilder IsNot Nothing Then
                    diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder)
                End If
 
                For Each diagnostic In diagnosticsBuilder
                    Dim ordinal = diagnostic.TypeParameter.Ordinal
 
                    ' If this is the TRest type parameter, we report it on 
                    ' the entire type syntax as it does not map to any tuple element.
                    Dim location = If(ordinal = TupleTypeSymbol.RestIndex, syntaxNode.Location, elementLocations(ordinal + offset))
                    diagnostics.Add(diagnostic.UseSiteInfo, location)
                Next
 
                diagnosticsBuilder.Clear()
 
                offset += TupleTypeSymbol.RestIndex
            Next
 
            underlyingTupleTypeChain.Free()
            diagnosticsBuilder.Free()
        End Sub
 
        <Extension()>
        Public Function CheckConstraintsForNonTuple(
                                        type As NamedTypeSymbol,
                                        languageVersion As LanguageVersion,
                                        typeArgumentsSyntax As SeparatedSyntaxList(Of TypeSyntax),
                                        diagnostics As BindingDiagnosticBag,
                                        template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Debug.Assert(Not type.IsTupleType)
            Debug.Assert(typeArgumentsSyntax.Count = type.Arity)
            If Not RequiresChecking(type) Then
                Return True
            End If
 
            Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance()
            Dim useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo) = Nothing
            Dim result = CheckTypeConstraints(type, languageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
 
            If useSiteDiagnosticsBuilder IsNot Nothing Then
                diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder)
            End If
 
            For Each diagnostic In diagnosticsBuilder
                Dim ordinal = diagnostic.TypeParameter.Ordinal
                Dim location = typeArgumentsSyntax(ordinal).GetLocation()
                diagnostics.Add(diagnostic.UseSiteInfo, location)
            Next
 
            diagnosticsBuilder.Free()
            Return result
        End Function
 
        <Extension()>
        Public Function CheckConstraints(
                                        type As NamedTypeSymbol,
                                        languageVersion As LanguageVersion,
                                        diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            ' We do not report element locations in method parameters and return types
            ' so we will simply unwrap the type if it was a tuple. We are relying on
            ' TypeSymbolExtensions.VisitType to dig into the "Rest" tuple so that they
            ' will be recursively unwrapped as well.
            type = DirectCast(type.GetTupleUnderlyingTypeOrSelf(), NamedTypeSymbol)
 
            If Not RequiresChecking(type) Then
                Return True
            End If
            Return CheckTypeConstraints(type, languageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
        End Function
 
        <Extension()>
        Public Function CheckConstraints(
                                        method As MethodSymbol,
                                        languageVersion As LanguageVersion,
                                        diagnosticLocation As Location,
                                        diagnostics As BindingDiagnosticBag,
                                        template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            If Not RequiresChecking(method) Then
                Return True
            End If
 
            Dim diagnosticsBuilder = ArrayBuilder(Of TypeParameterDiagnosticInfo).GetInstance()
            Dim useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo) = Nothing
            Dim result = CheckMethodConstraints(method, languageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
 
            If useSiteDiagnosticsBuilder IsNot Nothing Then
                diagnosticsBuilder.AddRange(useSiteDiagnosticsBuilder)
            End If
 
            For Each diagnostic In diagnosticsBuilder
                diagnostics.Add(diagnostic.UseSiteInfo, diagnosticLocation)
            Next
 
            diagnosticsBuilder.Free()
            Return result
        End Function
 
        <Extension()>
        Public Function CheckConstraints(
                                        method As MethodSymbol,
                                        languageVersion As LanguageVersion,
                                        diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            If Not RequiresChecking(method) Then
                Return True
            End If
            Return CheckMethodConstraints(method, languageVersion, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
        End Function
 
        Private Function CheckTypeConstraints(
                                        type As NamedTypeSymbol,
                                        languageVersion As LanguageVersion,
                                        diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Dim substitution = type.TypeSubstitution
            Return CheckConstraints(type, languageVersion, substitution, type.OriginalDefinition.TypeParameters, type.TypeArgumentsNoUseSiteDiagnostics, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
        End Function
 
        Private Function CheckMethodConstraints(
                                        method As MethodSymbol,
                                        languageVersion As LanguageVersion,
                                        diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                        template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Dim substitution = DirectCast(method, SubstitutedMethodSymbol).TypeSubstitution
            Return CheckConstraints(method, languageVersion, substitution, method.OriginalDefinition.TypeParameters, method.TypeArguments, diagnosticsBuilder, useSiteDiagnosticsBuilder, template)
        End Function
 
        ''' <summary>
        ''' Check type parameters for the containing type or method symbol.
        ''' The type parameters are assumed to be the original definitions of type
        ''' parameters from the containing type or method, and the TypeSubstitution
        ''' instance is used for substituting type parameters within the constraints
        ''' of those type parameters, so the substitution should map from type
        ''' parameters to type arguments.
        ''' </summary>
        <Extension()>
        Public Function CheckConstraints(
                                         constructedSymbol As Symbol,
                                         languageVersion As LanguageVersion,
                                         substitution As TypeSubstitution,
                                         typeParameters As ImmutableArray(Of TypeParameterSymbol),
                                         typeArguments As ImmutableArray(Of TypeSymbol),
                                         diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                         <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                         template As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Debug.Assert(typeParameters.Length = typeArguments.Length)
 
            Dim n = typeParameters.Length
            Dim succeeded = True
 
            For i = 0 To n - 1
                Dim typeArgument = typeArguments(i)
                Dim typeParameter = typeParameters(i)
                Dim useSiteInfo As New CompoundUseSiteInfo(Of AssemblySymbol)(template)
                If Not CheckConstraints(constructedSymbol, languageVersion, substitution, typeParameter, typeArgument, diagnosticsBuilder, useSiteInfo) Then
                    succeeded = False
                End If
 
                If AppendUseSiteInfo(useSiteInfo, typeParameter, useSiteDiagnosticsBuilder) Then
                    succeeded = False
                End If
            Next
 
            Return succeeded
        End Function
 
        Public Function CheckConstraints(
                                 constructedSymbol As Symbol,
                                 languageVersion As LanguageVersion,
                                 substitution As TypeSubstitution,
                                 typeParameter As TypeParameterSymbol,
                                 typeArgument As TypeSymbol,
                                 diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                 <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            ' The type parameters must be original definitions of type parameters from the containing symbol.
            Debug.Assert(((constructedSymbol Is Nothing) AndAlso (substitution Is Nothing)) OrElse
                         (typeParameter.ContainingSymbol Is constructedSymbol.OriginalDefinition))
 
            If typeArgument.IsErrorType() Then
                Return True
            End If
 
            Dim succeeded = True
 
            If typeArgument.IsRestrictedType() Then
                If diagnosticsBuilder IsNot Nothing Then
                    ' "'{0}' cannot be made nullable, and cannot be used as the data type of an array element, field, anonymous type member, type argument, 'ByRef' parameter, or return statement."
                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_RestrictedType1, typeArgument)))
                End If
                succeeded = False
            End If
 
            If typeParameter.HasConstructorConstraint AndAlso Not SatisfiesConstructorConstraint(typeParameter, typeArgument, diagnosticsBuilder) Then
                succeeded = False
            End If
 
            If typeParameter.HasReferenceTypeConstraint AndAlso Not SatisfiesReferenceTypeConstraint(typeParameter, typeArgument, diagnosticsBuilder) Then
                succeeded = False
            End If
 
            If typeParameter.HasUnmanagedTypeConstraint Then
 
                If Not InternalSyntax.Parser.CheckFeatureAvailability(languageVersion, InternalSyntax.Feature.UnmanagedConstraint) Then
                    useSiteInfo.AddDiagnosticInfo(InternalSyntax.Parser.GetFeatureAvailabilityError(InternalSyntax.Feature.UnmanagedConstraint, languageVersion))
                    succeeded = False
                End If
 
                Dim managedKind = typeArgument.GetManagedKind(useSiteInfo)
 
                If managedKind = ManagedKind.Managed Then
                    If diagnosticsBuilder IsNot Nothing Then
                        diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_UnmanagedConstraintNotSatisfied, typeArgument, typeParameter)))
                    End If
 
                    succeeded = False
                End If
            End If
 
            If typeParameter.HasValueTypeConstraint AndAlso Not SatisfiesValueTypeConstraint(constructedSymbol, typeParameter, typeArgument, diagnosticsBuilder, useSiteInfo) Then
                succeeded = False
            End If
 
            ' The type parameters for a constructed type/method are the type parameters of the ConstructedFrom
            ' type/method, so the constraint types are not substituted. For instance with "Class C(Of T As U, U)",
            ' the type parameter for T in "C(Of Object, Integer)" has constraint "U", not "Integer". We need to
            ' substitute the type parameter constraints from the original definition of the type parameters
            ' using the TypeSubstitution from the constructed type/method.
            For Each t In typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(useSiteInfo)
                Dim constraintType = t.InternalSubstituteTypeParameters(substitution).Type
 
                If Not SatisfiesTypeConstraint(typeArgument, constraintType, useSiteInfo) Then
                    If diagnosticsBuilder IsNot Nothing Then
                        ' "Type argument '{0}' does not inherit from or implement the constraint type '{1}'."
                        diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_GenericConstraintNotSatisfied2, typeArgument, constraintType)))
                    End If
                    succeeded = False
                End If
            Next
 
            Return succeeded
        End Function
 
        Private Function AppendUseSiteInfo(
            useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol),
            typeParameter As TypeParameterSymbol,
            <[In], Out> ByRef useSiteDiagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo)
        ) As Boolean
 
            Dim hasErrors As Boolean = useSiteInfo.AccumulatesDiagnostics AndAlso Not useSiteInfo.Diagnostics.IsNullOrEmpty
 
            If Not hasErrors AndAlso (Not useSiteInfo.AccumulatesDependencies OrElse useSiteInfo.Dependencies.IsNullOrEmpty) Then
                Return False
            End If
 
            If useSiteDiagnosticsBuilder Is Nothing Then
                useSiteDiagnosticsBuilder = New ArrayBuilder(Of TypeParameterDiagnosticInfo)()
            End If
 
            If Not hasErrors Then
                If useSiteInfo.AccumulatesDependencies AndAlso Not useSiteInfo.Dependencies.IsNullOrEmpty() Then
                    useSiteDiagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter,
                                                                              If(useSiteInfo.Dependencies.Count = 1,
                                                                                  New UseSiteInfo(Of AssemblySymbol)(useSiteInfo.Dependencies.Single()),
                                                                                  New UseSiteInfo(Of AssemblySymbol)(useSiteInfo.Dependencies.ToImmutableHashSet()))))
                End If
 
                Return False
            End If
 
            For Each info In useSiteInfo.Diagnostics
                Debug.Assert(info.Severity = DiagnosticSeverity.Error)
                useSiteDiagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, info))
            Next
 
            Return True
        End Function
 
        ''' <summary>
        ''' Return the most derived type from the set of constraint types on this type
        ''' parameter and any type parameter it depends on. Returns Nothing if there
        ''' are no concrete constraint types. If there are multiple constraints, returns
        ''' the most derived, ignoring any subsequent constraints that are neither
        ''' more or less derived. This method assumes there are no constraint cycles.
        ''' </summary>
        <Extension()>
        Public Function GetNonInterfaceConstraint(typeParameter As TypeParameterSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As TypeSymbol
            Dim result As TypeSymbol = Nothing
 
            For Each constraint In typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(useSiteInfo)
 
                Dim candidate As TypeSymbol = Nothing
 
                Select Case constraint.Kind
                    Case SymbolKind.ErrorType
                        Continue For
 
                    Case SymbolKind.TypeParameter
                        candidate = DirectCast(constraint, TypeParameterSymbol).GetNonInterfaceConstraint(useSiteInfo)
 
                    Case Else
                        If Not constraint.IsInterfaceType() Then
                            candidate = constraint
                        End If
                End Select
 
                If result Is Nothing Then
                    result = candidate
                ElseIf candidate IsNot Nothing Then
                    ' Pick the most derived type
                    If result.IsClassType AndAlso Conversions.IsDerivedFrom(candidate, result, useSiteInfo) Then
                        result = candidate
                    End If
                End If
            Next
 
            Return result
        End Function
 
        <Extension()>
        Public Function HasInterfaceConstraint(typeParameter As TypeParameterSymbol) As Boolean
            Dim result As TypeSymbol = Nothing
 
            For Each constraint In typeParameter.ConstraintTypesNoUseSiteDiagnostics
                Select Case constraint.Kind
                    Case SymbolKind.ErrorType
                        Continue For
 
                    Case SymbolKind.TypeParameter
                        If DirectCast(constraint, TypeParameterSymbol).HasInterfaceConstraint() Then
                            Return True
                        End If
 
                    Case Else
                        If constraint.IsInterfaceType() Then
                            Return True
                        End If
                End Select
            Next
 
            Return False
        End Function
 
        ''' <summary>
        ''' Return the most derived class type from the set of constraint types on this type
        ''' parameter and any type parameter it depends on. Returns Nothing if there are
        ''' no concrete constraint types. If there are multiple constraints, returns the most
        ''' derived, ignoring any subsequent constraints that are neither more or less derived.
        ''' This method assumes there are no constraint cycles. Unlike GetBaseConstraintType,
        ''' this method will always return a NamedTypeSymbol representing a class: returning
        ''' System.ValueType for value types, System.Array for arrays, and System.Enum for enums.
        ''' </summary>
        <Extension()>
        Public Function GetClassConstraint(typeParameter As TypeParameterSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As NamedTypeSymbol
            Dim baseType = typeParameter.GetNonInterfaceConstraint(useSiteInfo)
 
            If baseType Is Nothing Then
                Return Nothing
            End If
 
            Select Case baseType.TypeKind
                Case TypeKind.Array,
                    TypeKind.Enum,
                    TypeKind.Structure
                    Return baseType.BaseTypeWithDefinitionUseSiteDiagnostics(useSiteInfo)
 
                Case Else
                    Debug.Assert(Not baseType.IsInterfaceType())
                    Debug.Assert(baseType.TypeKind <> TypeKind.TypeParameter)
                    Return DirectCast(baseType, NamedTypeSymbol)
 
            End Select
        End Function
 
        ''' <summary>
        ''' Populate the collection with all constraints for the type parameter, traversing
        ''' any constraints that are also type parameters. The result is a collection of type
        ''' and flag constraints, with no type parameter references. This method assumes
        ''' there are no constraint cycles.
        ''' </summary>
        <Extension()>
        Private Sub GetAllConstraints(
                                     typeParameter As TypeParameterSymbol,
                                     constraintsBuilder As ArrayBuilder(Of TypeParameterAndConstraint),
                                     fromConstraintOpt As TypeParameterConstraint?)
            Dim constraints = ArrayBuilder(Of TypeParameterConstraint).GetInstance()
            typeParameter.GetConstraints(constraints)
 
            For Each constraint In constraints
                Dim type = constraint.TypeConstraint
 
                If type IsNot Nothing Then
                    Select Case type.TypeKind
                        Case TypeKind.TypeParameter
                            ' Add constraints from type parameter.
                            DirectCast(type, TypeParameterSymbol).GetAllConstraints(constraintsBuilder, If(fromConstraintOpt.HasValue, fromConstraintOpt.Value, constraint))
                            Continue For
 
                        Case TypeKind.Error
                            ' Skip error types.
                            Continue For
 
                    End Select
                End If
 
                constraintsBuilder.Add(
                    If(fromConstraintOpt.HasValue,
                       New TypeParameterAndConstraint(DirectCast(fromConstraintOpt.Value.TypeConstraint, TypeParameterSymbol), constraint.AtLocation(fromConstraintOpt.Value.LocationOpt)),
                       New TypeParameterAndConstraint(typeParameter, constraint)))
            Next
 
            constraints.Free()
        End Sub
 
        ''' <summary>
        ''' A tuple of type parameter and constraint type.
        ''' </summary>
        Private Structure TypeParameterAndConstraint
            Public Sub New(typeParameter As TypeParameterSymbol, constraint As TypeParameterConstraint, Optional isBad As Boolean = False)
                Me.TypeParameter = typeParameter
                Me.Constraint = constraint
                Me.IsBad = isBad
            End Sub
 
            Public ReadOnly TypeParameter As TypeParameterSymbol
            Public ReadOnly Constraint As TypeParameterConstraint
            Public ReadOnly IsBad As Boolean
 
            Public Function ToBad() As TypeParameterAndConstraint
                Debug.Assert(Not IsBad)
                Return New TypeParameterAndConstraint(TypeParameter, Constraint, True)
            End Function
 
            Public Overrides Function ToString() As String
                Dim result = String.Format("{0} : {1}", TypeParameter, Constraint)
                If IsBad Then
                    result = result & " (bad)"
                End If
                Return result
            End Function
        End Structure
 
        Private Function SatisfiesTypeConstraint(
            typeArgument As TypeSymbol,
            constraintType As TypeSymbol,
            <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)
        ) As Boolean
            If constraintType.IsErrorType() Then
                constraintType.AddUseSiteInfo(useSiteInfo)
                Return False
            End If
 
            Return Conversions.HasWideningDirectCastConversionButNotEnumTypeConversion(typeArgument, constraintType, useSiteInfo)
        End Function
 
        ' See Bindable::ValidateNewConstraintForType.
        Private Function SatisfiesConstructorConstraint(
                                                       typeParameter As TypeParameterSymbol,
                                                       typeArgument As TypeSymbol,
                                                       diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo)) As Boolean
            Debug.Assert(typeParameter.HasConstructorConstraint)
 
            Select Case typeArgument.TypeKind
                Case TypeKind.Enum
                    Return True
 
                Case TypeKind.TypeParameter
                    If DirectCast(typeArgument, TypeParameterSymbol).HasConstructorConstraint OrElse typeArgument.IsValueType Then
                        Return True
                    Else
                        If diagnosticsBuilder IsNot Nothing Then
                            ' "Type parameter '{0}' must have either a 'New' constraint or a 'Structure' constraint to satisfy the 'New' constraint for type parameter '{1}'."
                            diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_BadGenericParamForNewConstraint2, typeArgument, typeParameter)))
                        End If
                        Return False
                    End If
 
                Case Else
                    Dim isStructure As Boolean = typeArgument.TypeKind = TypeKind.Structure
 
                    Dim constraintError = ConstructorConstraintError.NoPublicParameterlessConstructor
 
                    If typeArgument.TypeKind = TypeKind.Class OrElse isStructure Then
                        Dim namedType = DirectCast(typeArgument, NamedTypeSymbol)
                        constraintError = HasPublicParameterlessConstructor(namedType)
 
                        If constraintError = ConstructorConstraintError.None AndAlso namedType.IsMustInherit Then
                            constraintError = ConstructorConstraintError.MustInheritType
                        End If
                    End If
 
                    If diagnosticsBuilder IsNot Nothing Then
                        Select Case constraintError
                            Case ConstructorConstraintError.NoPublicParameterlessConstructor
                                ' "Type argument '{0}' must have a public parameterless instance constructor to satisfy the 'New' constraint for type parameter '{1}'."
                                diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_NoSuitableNewForNewConstraint2, typeArgument, typeParameter)))
                            Case ConstructorConstraintError.MustInheritType
                                ' "Type argument '{0}' is declared 'MustInherit' and does not satisfy the 'New' constraint for type parameter '{1}'."
                                diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_MustInheritForNewConstraint2, typeArgument, typeParameter)))
                            Case ConstructorConstraintError.HasRequiredMembers
                                ' '{2}' cannot satisfy the 'New' constraint on parameter '{1}' in the generic type or or method '{0}' because '{2}' has required members.
                                diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_NewConstraintCannotHaveRequiredMembers, typeParameter.ContainingSymbol, typeParameter, typeArgument)))
                            Case ConstructorConstraintError.None
                            Case Else
                                Throw ExceptionUtilities.UnexpectedValue(constraintError)
                        End Select
                    End If
 
                    Return constraintError = ConstructorConstraintError.None
 
            End Select
        End Function
 
        ' See Bindable::ValidateReferenceConstraintForType.
        Private Function SatisfiesReferenceTypeConstraint(
                                                       typeParameter As TypeParameterSymbol,
                                                       typeArgument As TypeSymbol,
                                                       diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo)) As Boolean
            Debug.Assert((typeParameter Is Nothing) OrElse typeParameter.HasReferenceTypeConstraint)
 
            If Not typeArgument.IsReferenceType Then
                If diagnosticsBuilder IsNot Nothing Then
                    ' "Type argument '{0}' does not satisfy the 'Class' constraint for type parameter '{1}'."
                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_BadTypeArgForRefConstraint2, typeArgument, typeParameter)))
                End If
 
                Return False
            End If
 
            Return True
        End Function
 
        ' See Bindable::ValidateValueConstraintForType.
        Private Function SatisfiesValueTypeConstraint(
                                                     constructedSymbol As Symbol,
                                                     typeParameter As TypeParameterSymbol,
                                                     typeArgument As TypeSymbol,
                                                     diagnosticsBuilder As ArrayBuilder(Of TypeParameterDiagnosticInfo),
                                                     <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Debug.Assert((typeParameter Is Nothing) OrElse typeParameter.HasValueTypeConstraint)
 
            If Not typeArgument.IsValueType Then
                If diagnosticsBuilder IsNot Nothing Then
                    Dim containingType = TryCast(constructedSymbol, TypeSymbol)
 
                    If (containingType IsNot Nothing) AndAlso containingType.IsNullableType() Then
                        ' "Type '{0}' must be a value type or a type argument constrained to 'Structure' in order to be used with 'Nullable' or nullable modifier '?'."
                        diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_BadTypeArgForStructConstraintNull, typeArgument)))
                    Else
                        ' "Type argument '{0}' does not satisfy the 'Structure' constraint for type parameter '{1}'."
                        diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_BadTypeArgForStructConstraint2, typeArgument, typeParameter)))
                    End If
                End If
 
                Return False
 
            ElseIf IsNullableTypeOrTypeParameter(typeArgument, useSiteInfo) Then
                If diagnosticsBuilder IsNot Nothing Then
                    ' "'System.Nullable' does not satisfy the 'Structure' constraint for type parameter '{0}'. Only non-nullable 'Structure' types are allowed."
                    diagnosticsBuilder.Add(New TypeParameterDiagnosticInfo(typeParameter, ErrorFactory.ErrorInfo(ERRID.ERR_NullableDisallowedForStructConstr1, typeParameter)))
                End If
 
                Return False
            End If
 
            Return True
        End Function
 
        ' See Bindable::ConstraintsConflict.
        Private Function HasConflict(constraint1 As TypeParameterConstraint, constraint2 As TypeParameterConstraint, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
 
            Dim constraintType1 = constraint1.TypeConstraint
            Dim constraintType2 = constraint2.TypeConstraint
 
            If (constraintType1 IsNot Nothing) AndAlso (constraintType1.IsInterfaceType()) Then
                Return False
            End If
 
            If (constraintType2 IsNot Nothing) AndAlso (constraintType2.IsInterfaceType()) Then
                Return False
            End If
 
            If constraint1.IsValueTypeConstraint Then
                If HasValueTypeConstraintConflict(constraint2, useSiteInfo) Then
                    Return True
                End If
            ElseIf constraint2.IsValueTypeConstraint Then
                If HasValueTypeConstraintConflict(constraint1, useSiteInfo) Then
                    Return True
                End If
            End If
 
            If constraint1.IsReferenceTypeConstraint Then
                If HasReferenceTypeConstraintConflict(constraint2) Then
                    Return True
                End If
            ElseIf constraint2.IsReferenceTypeConstraint Then
                If HasReferenceTypeConstraintConflict(constraint1) Then
                    Return True
                End If
            End If
 
            If (constraintType1 IsNot Nothing) AndAlso
                (constraintType2 IsNot Nothing) AndAlso
                Not SatisfiesTypeConstraint(constraintType1, constraintType2, useSiteInfo) AndAlso
                Not SatisfiesTypeConstraint(constraintType2, constraintType1, useSiteInfo) Then
                Return True
            End If
 
            Return False
        End Function
 
        Private Function HasValueTypeConstraintConflict(constraint As TypeParameterConstraint, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            Dim constraintType = constraint.TypeConstraint
            If constraintType Is Nothing Then
                Return False
            End If
 
            If SatisfiesValueTypeConstraint(constructedSymbol:=Nothing, typeParameter:=Nothing, typeArgument:=constraintType,
                                            diagnosticsBuilder:=Nothing,
                                            useSiteInfo:=useSiteInfo) Then
                Return False
            End If
 
            Select Case constraintType.SpecialType
                Case SpecialType.System_Object, SpecialType.System_ValueType
                    Return False
            End Select
 
            Return True
        End Function
 
        Private Function HasReferenceTypeConstraintConflict(constraint As TypeParameterConstraint) As Boolean
            Dim constraintType = constraint.TypeConstraint
            If constraintType Is Nothing Then
                Return False
            End If
 
            If SatisfiesReferenceTypeConstraint(typeParameter:=Nothing, typeArgument:=constraintType, diagnosticsBuilder:=Nothing) Then
                Return False
            End If
 
            Return True
        End Function
 
        Private Function IsNullableTypeOrTypeParameter(type As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As Boolean
            If type.TypeKind = TypeKind.TypeParameter Then
                Dim typeParameter = DirectCast(type, TypeParameterSymbol)
 
                Dim constraintTypes = typeParameter.ConstraintTypesWithDefinitionUseSiteDiagnostics(useSiteInfo)
                For Each constraintType In constraintTypes
                    If IsNullableTypeOrTypeParameter(constraintType, useSiteInfo) Then
                        Return True
                    End If
                Next
                Return False
            Else
                Return type.IsNullableType()
            End If
        End Function
 
        Private Function GetConstraintCycleInfo(cycle As ConsList(Of TypeParameterSymbol)) As CompoundDiagnosticInfo
            Debug.Assert(cycle.Any())
            Dim previous As TypeParameterSymbol = Nothing
            Dim builder = ArrayBuilder(Of DiagnosticInfo).GetInstance()
            builder.Add(Nothing) ' Placeholder for first entry added later.
            For Each typeParameter In cycle
                If previous IsNot Nothing Then
                    builder.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ConstraintCycleLink2, typeParameter, previous))
                End If
                previous = typeParameter
            Next
            builder(0) = ErrorFactory.ErrorInfo(ERRID.ERR_ConstraintCycleLink2, cycle.Head, previous)
            Dim diagnostics = builder.ToArrayAndFree()
            Array.Reverse(diagnostics)
            Return New CompoundDiagnosticInfo(diagnostics)
        End Function
 
        Public Enum ConstructorConstraintError
            None
            NoPublicParameterlessConstructor
            MustInheritType
            HasRequiredMembers
        End Enum
 
        ''' <summary>
        ''' Return true if the class type has a public parameterless constructor.
        ''' </summary>
        Public Function HasPublicParameterlessConstructor(type As NamedTypeSymbol) As ConstructorConstraintError
            type = type.OriginalDefinition
            Debug.Assert(type.TypeKind = TypeKind.Class OrElse type.TypeKind = TypeKind.Structure)
 
            Dim sourceClass = If(type.TypeKind = TypeKind.Class, TryCast(type, SourceNamedTypeSymbol), Nothing)
 
            If sourceClass IsNot Nothing AndAlso Not sourceClass.MembersHaveBeenCreated Then
                ' When we are dealing with group classes and synthetic entry points,
                ' we can end up here while we are building the set of members for the type.
                ' Using InstanceConstructors property will send us into an infinite loop.
                If sourceClass.InferFromSyntaxIfClassWillHavePublicParameterlessConstructor() Then
                    Return ConstructorConstraintError.None
                Else
                    Return ConstructorConstraintError.NoPublicParameterlessConstructor
                End If
            End If
 
            Dim hasRequiredMembers = type.AllRequiredMembers.Count > 0 OrElse type.HasRequiredMembersError
 
            For Each constructor In type.InstanceConstructors
                If constructor.ParameterCount = 0 Then
                    If constructor.DeclaredAccessibility <> Accessibility.Public Then
                        Return ConstructorConstraintError.NoPublicParameterlessConstructor
                    ElseIf hasRequiredMembers AndAlso Not constructor.HasSetsRequiredMembers Then
                        Return ConstructorConstraintError.HasRequiredMembers
                    Else
                        Return ConstructorConstraintError.None
                    End If
                End If
            Next
 
            If Not type.TypeKind = TypeKind.Structure Then
                Return ConstructorConstraintError.NoPublicParameterlessConstructor
            ElseIf hasRequiredMembers Then
                Return ConstructorConstraintError.HasRequiredMembers
            Else
                Return ConstructorConstraintError.None
            End If
        End Function
 
        ''' <summary>
        ''' Return true if the constraints collection contains the given type constraint.
        ''' </summary>
        Private Function ContainsTypeConstraint(constraints As ArrayBuilder(Of TypeParameterConstraint), constraintType As TypeSymbol) As Boolean
            Debug.Assert(constraintType IsNot Nothing)
            For Each constraint In constraints
                Dim type = constraint.TypeConstraint
                If (type IsNot Nothing) AndAlso constraintType.IsSameTypeIgnoringAll(type) Then
                    Return True
                End If
            Next
            Return False
        End Function
 
        Private Function RequiresChecking(type As NamedTypeSymbol) As Boolean
            If type.Arity = 0 Then
                Return False
            End If
 
            ' If type is the original definition, there is no need
            ' to check constraints. In the following for instance:
            ' Class A(Of T As Structure)
            '     Dim F As New A(Of T)()
            ' End Class
            If type.OriginalDefinition Is type Then
                Return False
            End If
 
            Debug.Assert(Not TypeSymbol.Equals(type.ConstructedFrom, type, TypeCompareKind.ConsiderEverything))
            Return True
        End Function
 
        Private Function RequiresChecking(method As MethodSymbol) As Boolean
            If Not method.IsGenericMethod Then
                Return False
            End If
 
            ' If method is the original definition, there is no need
            ' to check constraints. In the following for instance:
            ' Sub M(Of T As Class)()
            '     M(Of T)()
            ' End Function
            If method.OriginalDefinition Is method Then
                Return False
            End If
 
            Debug.Assert(method.ConstructedFrom <> method)
            Return True
        End Function
 
    End Module
 
End Namespace