File: Binding\Binder_ObjectInitializer.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 Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
 
Namespace Microsoft.CodeAnalysis.VisualBasic
 
    Partial Friend Class Binder
        Private Function BindObjectCreationExpression(
            node As ObjectCreationExpressionSyntax,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
 
            DisallowNewOnTupleType(node.Type, diagnostics)
            Dim type As TypeSymbol = Me.BindTypeSyntax(node.Type, diagnostics)
 
            ' When the type is an error still try to bind the arguments for better data flow analysis and 
            ' to permit them to be analyzed via the binding API.
            If type.IsErrorType() Then
 
                Dim extendedErrorType = TryCast(type, ExtendedErrorTypeSymbol)
 
                If extendedErrorType IsNot Nothing AndAlso extendedErrorType.CandidateSymbols.Length = 1 AndAlso
                   extendedErrorType.CandidateSymbols(0).Kind = SymbolKind.NamedType Then
                    ' Continue binding with candidate symbol as the target type, but suppress any additional diagnostics
                    type = DirectCast(extendedErrorType.CandidateSymbols(0), TypeSymbol)
                    diagnostics = BindingDiagnosticBag.Discarded
                Else
                    Dim argumentDiagnostics = BindingDiagnosticBag.Discarded
                    Dim boundArguments As ImmutableArray(Of BoundExpression) = Nothing
                    Dim argumentNames As ImmutableArray(Of String) = Nothing
                    Dim argumentNamesLocations As ImmutableArray(Of Location) = Nothing
 
                    BindArgumentsAndNames(node.ArgumentList, boundArguments, argumentNames, argumentNamesLocations, argumentDiagnostics)
 
                    ' We also want to put into the bound bad expression node all bound arguments as 
                    ' r-values AND bound type which will be used for semantic info
                    Dim boundNodes = ArrayBuilder(Of BoundExpression).GetInstance()
 
                    ' Add all bound arguments as r-values
                    For Each arg In boundArguments
                        boundNodes.Add(MakeRValueAndIgnoreDiagnostics(arg))
                    Next
 
                    Dim boundInitializer As BoundExpression =
                        BindObjectCollectionOrMemberInitializer(node, type, Nothing, argumentDiagnostics)
                    If boundInitializer IsNot Nothing Then
                        boundNodes.Add(boundInitializer)
                    End If
 
                    argumentDiagnostics.Free()
 
                    Return BadExpression(node, boundNodes.ToImmutableAndFree(), type)
                End If
            End If
 
            Return BindObjectCreationExpression(node.Type, node.ArgumentList, type, node, diagnostics, Nothing)
        End Function
 
        Private Shared Sub DisallowNewOnTupleType(type As TypeSyntax, diagnostics As BindingDiagnosticBag)
            If type.Kind = SyntaxKind.TupleType Then
                diagnostics.Add(ERRID.ERR_NewWithTupleTypeSyntax, type.Location)
            End If
        End Sub
 
        Friend Function BindObjectCreationExpression(
            typeNode As TypeSyntax,
            argumentListOpt As ArgumentListSyntax,
            type0 As TypeSymbol,
            node As ObjectCreationExpressionSyntax,
            diagnostics As BindingDiagnosticBag,
            asNewVariablePlaceholderOpt As BoundWithLValueExpressionPlaceholder
        ) As BoundExpression
 
            Select Case type0.TypeKind
                Case TypeKind.Delegate
                    ' delegate creations need to handled differently.
                    Return BindDelegateCreationExpression(type0, argumentListOpt, node, diagnostics)
 
                Case TypeKind.Structure
                    ' SPECIAL CASE: process calls to a parameterless structure constructors separately
                    If argumentListOpt Is Nothing OrElse argumentListOpt.Arguments.Count = 0 Then
                        ' Skip overload resolution, go straight to the structure parameterless constructor if exists
                        Dim constructorSymbol As MethodSymbol = Nothing
 
                        ' NOTE: in case the structure has a constructor with all optional parameters 
                        '       we don't catch it here; this matches Dev10 behavior
 
                        Dim namedType = DirectCast(type0, NamedTypeSymbol)
                        Dim ctors = namedType.InstanceConstructors
 
                        If Not ctors.IsEmpty Then
                            For Each constructor In ctors
                                If constructor.ParameterCount = 0 Then
                                    '  the first parameterless constructor will do the job
                                    Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                                    If IsAccessible(constructor, useSiteInfo) Then
                                        ' if not accessible, just clear symbol information
                                        constructorSymbol = constructor
                                        ReportUseSite(diagnostics, node, constructorSymbol)
                                    End If
 
                                    diagnostics.Add(node, useSiteInfo)
                                    Exit For
                                End If
                            Next
                        End If
 
                        ' NOTE: we don't report an error if the constructor is inaccessible.
                        '       Emitter will just emit 'initobj' instead of constructor call instead
 
                        '  create a simplified object creation expression
                        Dim initializerOpt As BoundObjectInitializerExpressionBase = BindObjectCollectionOrMemberInitializer(node,
                                                                                type0,
                                                                                asNewVariablePlaceholderOpt,
                                                                                diagnostics)
 
                        CheckRequiredMembersInObjectInitializer(constructorSymbol, namedType, If(initializerOpt?.Initializers, ImmutableArray(Of BoundExpression).Empty), typeNode, diagnostics)
 
                        Return New BoundObjectCreationExpression(
                                        node,
                                        constructorSymbol,
                                        If(constructorSymbol Is Nothing,
                                           Nothing,
                                           New BoundMethodGroup(typeNode, Nothing,
                                                             ImmutableArray.Create(constructorSymbol), LookupResultKind.Good, Nothing,
                                                             QualificationKind.QualifiedViaTypeName)),
                                        arguments:=ImmutableArray(Of BoundExpression).Empty,
                                        defaultArguments:=BitVector.Null,
                                        initializerOpt,
                                        type0)
                    End If
 
            End Select
 
            ' Get the bound arguments and the argument names.
            Dim boundArguments As ImmutableArray(Of BoundExpression) = Nothing
            Dim argumentNames As ImmutableArray(Of String) = Nothing
            Dim argumentNamesLocations As ImmutableArray(Of Location) = Nothing
 
            BindArgumentsAndNames(argumentListOpt, boundArguments, argumentNames, argumentNamesLocations, diagnostics)
 
            Dim objectInitializerExpression = BindObjectCollectionOrMemberInitializer(node,
                                                                                      type0,
                                                                                      asNewVariablePlaceholderOpt,
                                                                                      diagnostics)
            Return BindObjectCreationExpression(typeNode,
                                                argumentListOpt,
                                                type0,
                                                node,
                                                boundArguments,
                                                argumentNames,
                                                objectInitializerExpression,
                                                diagnostics,
                                                callerInfoOpt:=typeNode)
        End Function
 
        Friend Function BindObjectCreationExpression(
            syntax As SyntaxNode,
            type As TypeSymbol,
            arguments As ImmutableArray(Of BoundExpression),
            diagnostics As BindingDiagnosticBag) As BoundExpression
            Return BindObjectCreationExpression(
                typeNode:=syntax,
                argumentListOpt:=Nothing,
                type0:=type,
                node:=syntax,
                boundArguments:=arguments,
                argumentNames:=Nothing,
                objectInitializerExpressionOpt:=Nothing,
                diagnostics:=diagnostics,
                callerInfoOpt:=Nothing)
        End Function
 
        Private Shared Function MergeBoundChildNodesWithObjectInitializerForBadNode(
            boundArguments As ImmutableArray(Of BoundExpression),
            objectInitializerExpression As BoundObjectInitializerExpressionBase
        ) As ImmutableArray(Of BoundExpression)
            Dim boundChildNodesForError = boundArguments
 
            If objectInitializerExpression IsNot Nothing Then
                boundChildNodesForError = boundChildNodesForError.Add(objectInitializerExpression)
            End If
 
            Return boundChildNodesForError
        End Function
 
        Private Function BindObjectCreationExpression(
            typeNode As SyntaxNode,
            argumentListOpt As ArgumentListSyntax,
            type0 As TypeSymbol,
            node As SyntaxNode,
            boundArguments As ImmutableArray(Of BoundExpression),
            argumentNames As ImmutableArray(Of String),
            objectInitializerExpressionOpt As BoundObjectInitializerExpressionBase,
            diagnostics As BindingDiagnosticBag,
            callerInfoOpt As VisualBasicSyntaxNode
        ) As BoundExpression
 
            Dim resultKind As LookupResultKind = LookupResultKind.Good
            Dim errorReported As Boolean = False        ' was an error already reported?
            Dim type As NamedTypeSymbol = Nothing
 
            Debug.Assert(objectInitializerExpressionOpt Is Nothing OrElse TypeSymbol.Equals(objectInitializerExpressionOpt.Type, type0, TypeCompareKind.ConsiderEverything))
 
            Select Case type0.TypeKind
                Case TypeKind.Class
                    If DirectCast(type0, NamedTypeSymbol).IsMustInherit Then
                        ReportDiagnostic(diagnostics, node, ERRID.ERR_NewOnAbstractClass)
                        resultKind = LookupResultKind.NotCreatable
                        errorReported = True
                    End If
 
                    type = DirectCast(type0, NamedTypeSymbol)
 
                Case TypeKind.Interface
                    Dim coClass As TypeSymbol = DirectCast(type0, NamedTypeSymbol).CoClassType
                    Dim diagInfo As DiagnosticInfo
                    If coClass IsNot Nothing Then
 
                        Select Case coClass.TypeKind
                            Case TypeKind.Error,
                                 TypeKind.Interface
 
                                ' Generate basic missing CoClass error
                                ' Note the same error of interfaces specified as CoClasses
                                diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_CoClassMissing2, coClass, type0)
 
                            Case TypeKind.Array
                                ' NOTE: In case of array type in CoClass Dev11 generates a call to 
                                '       Array's element type constructor which does not make any 
                                '       sense, we treat this case as a 'invalid-coclass' error
                                diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_InvalidCoClass1, coClass)
 
                            Case TypeKind.Class,
                                 TypeKind.Delegate,
                                 TypeKind.Enum,
                                 TypeKind.Module,
                                 TypeKind.Structure
 
                                ' NOTE: Dev11 does not 'see' implicit parameterless constructors in structs
                                ' NOTE: and enums while Roslyn does. This means that some edge case scenarios 
                                ' NOTE: of struct/enum CoClass types now work
 
                                Dim namedCoClass = DirectCast(coClass, NamedTypeSymbol)
                                If namedCoClass.IsUnboundGenericType Then
                                    ' Cannot use unbound generic type as a CoClass 
                                    diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_InvalidCoClass1, coClass)
                                    Exit Select
                                End If
 
                                ' Check accessibility
                                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                                Dim isInAccessible As Boolean = (Me.CheckAccessibility(namedCoClass, useSiteInfo) <> AccessCheckResult.Accessible)
                                diagnostics.Add(node, useSiteInfo)
 
                                If isInAccessible Then
                                    ' CoClass is inaccessible
                                    diagInfo = New BadSymbolDiagnostic(coClass, ERRID.ERR_InAccessibleCoClass3, coClass, type0, coClass.DeclaredAccessibility.ToDiagnosticString())
                                    Exit Select
                                End If
 
                                ' NoPIA support
                                If type0.ContainingAssembly.IsLinked Then
                                    Return BindNoPiaObjectCreationExpression(node, type0, namedCoClass, boundArguments, objectInitializerExpressionOpt, diagnostics)
                                End If
 
                                If namedCoClass.IsMustInherit Then
                                    ' NOTE: Dev11 does allow abstract classes to serve as a CoClass 
                                    ' NOTE: types and generates not verifiable code as a result
                                    diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_InvalidCoClass1, coClass)
                                    Exit Select
                                End If
 
                                type = namedCoClass
                                diagInfo = Nothing
 
                            Case Else
                                Throw ExceptionUtilities.UnexpectedValue(coClass.TypeKind)
                        End Select
 
                    Else
                        diagInfo = ErrorFactory.ErrorInfo(ERRID.ERR_NewIfNullOnNonClass)
                    End If
 
                    If diagInfo IsNot Nothing Then
                        ReportDiagnostic(diagnostics, node, diagInfo)
                        resultKind = LookupResultKind.NotCreatable
                        errorReported = True
                        type = DirectCast(type0, NamedTypeSymbol)
                    End If
 
                Case TypeKind.Error
                    Return New BoundBadExpression(node, LookupResultKind.Empty,
                                                  ImmutableArray(Of Symbol).Empty,
                                                  MergeBoundChildNodesWithObjectInitializerForBadNode(boundArguments,
                                                                                                      objectInitializerExpressionOpt),
                                                  type0, hasErrors:=True)
 
                Case TypeKind.TypeParameter
                    Dim typeParameter = DirectCast(type0, TypeParameterSymbol)
 
                    If Not typeParameter.HasConstructorConstraint AndAlso Not typeParameter.IsValueType Then
                        ' "'New' cannot be used on a type parameter that does not have a 'New' constraint."
                        ReportDiagnostic(diagnostics, typeNode, ERRID.ERR_NewIfNullOnGenericParam)
 
                    ElseIf Not boundArguments.IsEmpty Then
                        ' "Arguments cannot be passed to a 'New' used on a type parameter."
                        Dim span = argumentListOpt.Arguments.Span
                        ReportDiagnostic(diagnostics, GetLocation(span), ERRID.ERR_NewArgsDisallowedForTypeParam)
 
                    Else
                        Return New BoundNewT(node,
                                             objectInitializerExpressionOpt,
                                             typeParameter)
                    End If
 
                    resultKind = LookupResultKind.NotCreatable
                    errorReported = True
 
                Case TypeKind.Enum, TypeKind.Structure
                    type = DirectCast(type0, NamedTypeSymbol)
 
                Case TypeKind.Module
                    ' the diagnostic that a module cannot be used as a type has already been reported
                    ' so there is nothing to do here.
                    type = DirectCast(type0, NamedTypeSymbol)
                    resultKind = LookupResultKind.NotCreatable
                    errorReported = True
 
                Case TypeKind.Array
                    ' the diagnostic that AsNew cannot be used to init arrays has already been reported
                    ' so there is nothing to do here.
                    resultKind = LookupResultKind.NotCreatable
                    errorReported = True
 
                Case Else
                    Throw ExceptionUtilities.UnexpectedValue(type0.TypeKind)
 
            End Select
 
            ' TODO: handle cases of types that are not newable (see type libraries and the 
            ' System.Runtime.InteropServices.TypeLibType attribute).
            ' example: 
            ' <System.Runtime.InteropServices.TypeLibType(System.Runtime.InteropServices.TypeLibTypeFlags.FHidden)>
            ' Class test
            ' End Class
 
            ' Filter out inaccessible constructors
            Dim resultExpression As BoundExpression
            Dim constructorsGroup As BoundMethodGroup = Nothing
 
            If type IsNot Nothing AndAlso Not type.IsInterface Then
                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                Dim constructors As ImmutableArray(Of MethodSymbol) = GetAccessibleConstructors(type, useSiteInfo)
 
                diagnostics.Add(node, useSiteInfo)
 
                Dim groupResultKind As LookupResultKind = LookupResultKind.Good
 
                If constructors.Length = 0 Then
                    constructors = type.InstanceConstructors
                    groupResultKind = LookupResultKind.Inaccessible
                End If
 
                If constructors.Length > 0 Then
                    constructorsGroup = New BoundMethodGroup(typeNode, Nothing,
                                                             constructors, groupResultKind, Nothing,
                                                             QualificationKind.QualifiedViaTypeName).MakeCompilerGenerated()
                End If
            End If
 
            If constructorsGroup Is Nothing OrElse constructorsGroup.ResultKind = LookupResultKind.Inaccessible Then
                If Not errorReported Then
                    ReportDiagnostic(diagnostics, If(typeNode.IsKind(SyntaxKind.QualifiedName), DirectCast(typeNode, QualifiedNameSyntax).Right, typeNode), ErrorFactory.ErrorInfo(ERRID.ERR_NoViableOverloadCandidates1, "New"))
                End If
 
                ' Suppress any additional diagnostics
                diagnostics = BindingDiagnosticBag.Discarded
            End If
 
            If constructorsGroup Is Nothing Then
                resultExpression = New BoundBadExpression(node, LookupResult.WorseResultKind(resultKind, LookupResultKind.Empty),
                                                          ImmutableArray(Of Symbol).Empty,
                                                          MergeBoundChildNodesWithObjectInitializerForBadNode(boundArguments,
                                                                                                              objectInitializerExpressionOpt),
                                                          type0, hasErrors:=True)
            Else
                ' We rely on the asserted condition when we are merging/changing result kinds below. 
                Debug.Assert(constructorsGroup.ResultKind = LookupResultKind.Good OrElse constructorsGroup.ResultKind = LookupResultKind.Inaccessible)
 
                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                Dim results As OverloadResolution.OverloadResolutionResult = OverloadResolution.MethodInvocationOverloadResolution(constructorsGroup,
                                                                                                                                   boundArguments,
                                                                                                                                   argumentNames,
                                                                                                                                   Me,
                                                                                                                                   callerInfoOpt,
                                                                                                                                   useSiteInfo)
 
                If diagnostics.Add(node, useSiteInfo) Then
                    If constructorsGroup.ResultKind <> LookupResultKind.Inaccessible Then
                        ' Suppress additional diagnostics
                        diagnostics = BindingDiagnosticBag.Discarded
                    End If
                End If
 
                If Not results.BestResult.HasValue Then
 
                    ' Create and report the diagnostic.
                    If results.Candidates.Length = 0 Then
                        results = OverloadResolution.MethodInvocationOverloadResolution(constructorsGroup, boundArguments, argumentNames, Me, includeEliminatedCandidates:=True, callerInfoOpt:=callerInfoOpt,
                                                                                        useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded)
                    End If
 
                    ' NOTE: current services implementation expects all diagnostics to be associated with type node, not with a node itself
                    resultExpression = ReportOverloadResolutionFailureAndProduceBoundNode(node,
                                                                                          constructorsGroup,
                                                                                          boundArguments, argumentNames,
                                                                                          results, diagnostics, callerInfoOpt,
                                                                                          overrideCommonReturnType:=type0)
 
                    ' update the bad expression to also contain the bound initializer.
                    Dim badExpression = DirectCast(resultExpression, BoundBadExpression)
 
                    ' Here we have possibly three different LookupResultKinds to store
                    ' 1) LookupResultKind.NotCreatable - if the type is not creatable
                    ' 2) LookupResultKind.OverloadResolutionFailure 
                    ' 3) LookupResultKind from constructorsGroup
 
                    ' Let's preserve two worst since we only have two locations to store them.
                    Dim children = ArrayBuilder(Of BoundExpression).GetInstance()
 
#If DEBUG Then
                    Dim foundGroup As Boolean = False
#End If
 
                    For Each child In badExpression.ChildBoundNodes
                        If child Is constructorsGroup Then
#If DEBUG Then
                            foundGroup = True
#End If
                            children.Add(constructorsGroup.Update(constructorsGroup.TypeArgumentsOpt, constructorsGroup.Methods, constructorsGroup.PendingExtensionMethodsOpt,
                                                                  LookupResult.WorseResultKind(constructorsGroup.ResultKind, badExpression.ResultKind), constructorsGroup.ReceiverOpt,
                                                                  constructorsGroup.QualificationKind))
                        Else
                            children.Add(child)
                        End If
                    Next
 
#If DEBUG Then
                    Debug.Assert(foundGroup)
#End If
 
                    If objectInitializerExpressionOpt IsNot Nothing Then
                        children.Add(objectInitializerExpressionOpt)
                    End If
 
                    resultExpression = badExpression.Update(LookupResult.WorseResultKind(resultKind, badExpression.ResultKind),
                                                            badExpression.Symbols,
                                                            children.ToImmutableAndFree(),
                                                            badExpression.Type)
                Else
 
                    Dim methodResult = results.BestResult.Value
 
                    Dim argumentInfo As (Arguments As ImmutableArray(Of BoundExpression), DefaultArguments As BitVector) = PassArguments(typeNode, methodResult, boundArguments, diagnostics)
                    boundArguments = argumentInfo.Arguments
 
                    ReportDiagnosticsIfObsoleteOrNotSupported(diagnostics, methodResult.Candidate.UnderlyingSymbol, node)
 
                    ' If a coclass was instantiated, convert the class to the interface type.
                    If type0.IsInterfaceType() Then
                        Debug.Assert(type.Equals(DirectCast(type0, NamedTypeSymbol).CoClassType))
                        ApplyImplicitConversion(node, type0, New BoundRValuePlaceholder(node, type), diagnostics)
                    Else
                        Debug.Assert(TypeSymbol.Equals(type, type0, TypeCompareKind.ConsiderEverything))
                    End If
 
                    ' If the type was not creatable, create a bad expression so that semantic model results can reflect that.
                    If resultKind <> LookupResultKind.Good Then
                        Dim children = ArrayBuilder(Of BoundExpression).GetInstance()
 
                        children.Add(constructorsGroup)
                        children.AddRange(boundArguments)
 
                        If objectInitializerExpressionOpt IsNot Nothing Then
                            children.Add(objectInitializerExpressionOpt)
                        End If
 
                        resultExpression = New BoundBadExpression(node, resultKind,
                                                                  ImmutableArray.Create(Of Symbol)(methodResult.Candidate.UnderlyingSymbol),
                                                                  children.ToImmutableAndFree(),
                                                                  type0, hasErrors:=True)
                    Else
                        Dim constructorSymbol As MethodSymbol = DirectCast(methodResult.Candidate.UnderlyingSymbol, MethodSymbol)
 
                        CheckRequiredMembersInObjectInitializer(constructorSymbol, constructorSymbol.ContainingType, If(objectInitializerExpressionOpt?.Initializers, ImmutableArray(Of BoundExpression).Empty), typeNode, diagnostics)
 
                        resultExpression = New BoundObjectCreationExpression(node,
                                                                             constructorSymbol,
                                                                             constructorsGroup,
                                                                             boundArguments,
                                                                             argumentInfo.DefaultArguments,
                                                                             objectInitializerExpressionOpt,
                                                                             type0)
                    End If
                End If
            End If
 
            Debug.Assert(resultExpression.Type.IsSameTypeIgnoringAll(type0))
            Debug.Assert(LookupResult.WorseResultKind(resultKind, resultExpression.ResultKind) = resultExpression.ResultKind)
 
            Return resultExpression
        End Function
 
        Friend Shared Sub CheckRequiredMembersInObjectInitializer(
            constructor As MethodSymbol,
            containingType As NamedTypeSymbol,
            initializers As ImmutableArray(Of BoundExpression),
            creationSyntax As SyntaxNode,
            diagnostics As BindingDiagnosticBag)
 
            ' The only time constructor will be null is if we're trying to invoke a parameterless struct ctor, and it's not accessible (such as being protected).
            Debug.Assert((constructor IsNot Nothing AndAlso ReferenceEquals(constructor.ContainingType, containingType)) OrElse containingType.IsStructureType())
 
            If constructor IsNot Nothing AndAlso constructor.HasSetsRequiredMembers Then
                Return
            End If
 
            If containingType.HasRequiredMembersError Then
                ' A use-site diagnostic will be reported on the use, so we don't need to do any more checking here.
                Return
            End If
 
            Dim requiredMembers = containingType.AllRequiredMembers
 
            If requiredMembers.Count = 0 Then
                Return
            End If
 
            Dim requiredMembersBuilder = requiredMembers.ToBuilder()
 
            If Not initializers.IsDefaultOrEmpty Then
                For Each initializer In initializers
                    Dim assignmentOperator = TryCast(initializer, BoundAssignmentOperator)
                    If assignmentOperator Is Nothing Then
                        Continue For
                    End If
 
                    Dim memberSymbol As Symbol = If(
                        DirectCast(TryCast(assignmentOperator.Left, BoundPropertyAccess)?.PropertySymbol, Symbol),
                        TryCast(assignmentOperator.Left, BoundFieldAccess)?.FieldSymbol)
 
                    If memberSymbol Is Nothing Then
                        Continue For
                    End If
 
                    Dim requiredMember As Symbol = Nothing
                    If Not requiredMembersBuilder.TryGetValue(memberSymbol.Name, requiredMember) Then
                        Continue For
                    End If
 
                    If Not memberSymbol.Equals(requiredMember, TypeCompareKind.AllIgnoreOptionsForVB) Then
                        Continue For
                    End If
 
                    requiredMembersBuilder.Remove(memberSymbol.Name)
                Next
            End If
 
            For Each kvp In requiredMembersBuilder
                diagnostics.Add(ERRID.ERR_RequiredMemberMustBeSet, creationSyntax.Location, kvp.Value)
            Next
        End Sub
 
        Private Function BindNoPiaObjectCreationExpression(
            node As SyntaxNode,
            [interface] As TypeSymbol,
            coClass As NamedTypeSymbol,
            boundArguments As ImmutableArray(Of BoundExpression),
            initializerOpt As BoundObjectInitializerExpressionBase,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
            Dim hasErrors = False
 
            Dim guidString As String = Nothing
            If Not coClass.GetGuidString(guidString) Then
                ' Match Dev11 VB by reporting ERRID_NoPIAAttributeMissing2 if guid isn't there.
                ' C# doesn't complain and instead uses zero guid.
                ReportDiagnostic(diagnostics, node, ERRID.ERR_NoPIAAttributeMissing2, coClass, AttributeDescription.GuidAttribute.FullName)
                hasErrors = True
            End If
 
            Dim expr = New BoundNoPiaObjectCreationExpression(node, guidString, initializerOpt, [interface], hasErrors)
 
            If boundArguments.Any() Then
                ' Note: Dev11 silently drops any arguments and does not report an error.
                ReportDiagnostic(diagnostics, node, ERRID.ERR_NoArgumentCountOverloadCandidates1, "New")
 
                Dim children = boundArguments.Add(expr)
                Return BadExpression(node, children, expr.Type)
            End If
 
            Return expr
        End Function
 
        ''' <summary>
        ''' Binds the object collection or member initializer from a object creation.
        ''' E.g. "new CollType() From {...}" or "new AType() With {...}"
        ''' </summary>
        ''' <param name="initializedObjectType">The type of the created object expression.</param>
        ''' <param name="syntaxNode">The object creation expression syntax.</param>
        ''' <param name="diagnostics">The diagnostics.</param>
        Private Function BindObjectCollectionOrMemberInitializer(
            syntaxNode As ObjectCreationExpressionSyntax,
            initializedObjectType As TypeSymbol,
            asNewVariablePlaceholderOpt As BoundWithLValueExpressionPlaceholder,
            diagnostics As BindingDiagnosticBag
        ) As BoundObjectInitializerExpressionBase
 
            If syntaxNode.Initializer Is Nothing Then
                Return Nothing
            End If
 
            If syntaxNode.Initializer.Kind = SyntaxKind.ObjectMemberInitializer Then
                Return BindObjectInitializer(syntaxNode, initializedObjectType, asNewVariablePlaceholderOpt, diagnostics)
 
            ElseIf syntaxNode.Initializer.Kind = SyntaxKind.ObjectCollectionInitializer Then
                Return BindCollectionInitializer(syntaxNode, initializedObjectType, diagnostics)
 
            Else
                Throw ExceptionUtilities.UnexpectedValue(syntaxNode.Initializer.Kind)
            End If
        End Function
 
        ''' <summary>
        ''' Bind the ObjectInitializer.
        ''' During the binding we basically bind the member access for each initializer, as well as the value that will be assigned.
        ''' The main information stored in the bound node is a list of assignment operators (that may contain placeholders), as
        ''' well as the information whether expression creates a temporary or not.
        ''' </summary>
        Private Function BindObjectInitializer(
            objectCreationSyntax As ObjectCreationExpressionSyntax,
            initializedObjectType As TypeSymbol,
            asNewVariablePlaceholderOpt As BoundWithLValueExpressionPlaceholder,
            diagnostics As BindingDiagnosticBag
        ) As BoundObjectInitializerExpression
 
            Dim memberInitializerSyntax = DirectCast(objectCreationSyntax.Initializer, ObjectMemberInitializerSyntax)
 
            ' We need to use a declared variable directly if it is declared using AsNew and it's type is a value type or a type 
            ' parameter with a structure constraint.
            ' Otherwise the object initializer should initialize a temporary.
            ' According to Jonathan Aneja this is a bug and should always use a temporary, but unfortunately it's what Dev10 emits
            ' (we have legacy tests that check this specifically).
            Dim createTemporary = asNewVariablePlaceholderOpt Is Nothing OrElse Not initializedObjectType.IsValueType
 
            Dim variableOrTempPlaceholder As BoundWithLValueExpressionPlaceholder = Nothing
            If createTemporary Then
                variableOrTempPlaceholder = New BoundWithLValueExpressionPlaceholder(objectCreationSyntax, initializedObjectType)
                variableOrTempPlaceholder.SetWasCompilerGenerated()
            Else
                Debug.Assert(asNewVariablePlaceholderOpt IsNot Nothing)
                variableOrTempPlaceholder = asNewVariablePlaceholderOpt
            End If
 
            Dim objectInitializerBinder = New ObjectInitializerBinder(Me, variableOrTempPlaceholder)
 
            ' bind RHS for error cases.
            If initializedObjectType.SpecialType = SpecialType.System_Object OrElse initializedObjectType.IsErrorType Then
                ' VB Spec 11.10.1:
                ' "the member access will not be late bound if the type being constructed is Object"
                If initializedObjectType.SpecialType = SpecialType.System_Object Then
                    ' BC30994: Object initializer syntax cannot be used to initialize an instance of 'System.Object'.
                    ReportDiagnostic(diagnostics, memberInitializerSyntax, ErrorFactory.ErrorInfo(ERRID.ERR_AggrInitInvalidForObject))
                End If
 
                ' Bind RHS of the assignments for the sake of error reporting
                Dim initializerCount = memberInitializerSyntax.Initializers.Count
                Dim boundAssignmentValues(initializerCount - 1) As BoundExpression
                For fieldIndex = 0 To initializerCount - 1
                    Dim boundValue = objectInitializerBinder.BindValue(DirectCast(memberInitializerSyntax.Initializers(fieldIndex),
                                                                                  NamedFieldInitializerSyntax).Expression,
                                                                       diagnostics)
                    boundAssignmentValues(fieldIndex) = MakeRValueAndIgnoreDiagnostics(boundValue)
                Next
 
                Return New BoundObjectInitializerExpression(objectCreationSyntax.Initializer,
                                                            True,
                                                            variableOrTempPlaceholder,
                                                            boundAssignmentValues.AsImmutableOrNull,
                                                            initializedObjectType,
                                                            hasErrors:=True)
            End If
 
            Dim processedMembers As New HashSet(Of String)(CaseInsensitiveComparison.Comparer)
            Dim memberAssignments = ArrayBuilder(Of BoundExpression).GetInstance
 
            ' The temporary diagnostic bag is needed to collect diagnostics until it is known that the accessed symbol
            ' is a field or property, and if so, if it is shared or not.
            ' The temporary error messages should only be shown if binding the member access itself failed, or the bound
            ' member access is usable for the initialization (non shared, writable field or property).
            ' Otherwise more specific diagnostics will be shown .
            Dim memberBindingDiagnostics = BindingDiagnosticBag.GetInstance(withDiagnostics:=True, withDependencies:=diagnostics.AccumulatesDependencies)
 
            For Each fieldInitializer In memberInitializerSyntax.Initializers
                ' NamedFieldInitializerSyntax is derived from FieldInitializerSyntax, which has this optional keyword as a member
                ' however it should not be set in case of a NamedFieldInitializerSyntax
                Debug.Assert(fieldInitializer.KeyKeyword.Kind <> SyntaxKind.KeyKeyword)
 
                Dim target As BoundExpression
                Dim namedFieldInitializer = DirectCast(fieldInitializer, NamedFieldInitializerSyntax)
                Dim fieldName As IdentifierNameSyntax = namedFieldInitializer.Name
 
                ' we're only binding the target if there were no previous diagnostics on the identifier.
                ' In that case binding the target would always fail.
                If Not fieldName.HasErrors Then
 
                    ' no need to use the memberInitializerBinder here, because there is no MemberAccessExpression 
                    target = BindMemberAccess(fieldName, variableOrTempPlaceholder, fieldName, False, memberBindingDiagnostics)
                    diagnostics.AddRange(memberBindingDiagnostics)
 
                    Dim identifierName As String = fieldName.Identifier.ValueText
 
                    If target.Kind = BoundKind.FieldAccess OrElse target.Kind = BoundKind.PropertyGroup Then
                        target = BindAssignmentTarget(fieldName,
                                                      target,
                                                      diagnostics)
 
                        Dim propertyAccess = TryCast(target, BoundPropertyAccess)
 
                        If propertyAccess IsNot Nothing Then
                            Debug.Assert(propertyAccess.AccessKind = PropertyAccessKind.Unknown)
                            ' See if we can reclassify access as writable given that this is an object initializer.
                            ' This is needed to accommodate init-only properties.
                            If propertyAccess.AccessKind <> PropertyAccessKind.Get AndAlso Not propertyAccess.IsWriteable AndAlso
                               propertyAccess.PropertySymbol.IsWritable(propertyAccess.ReceiverOpt, Me, isKnownTargetOfObjectMemberInitializer:=True) Then
 
                                propertyAccess = propertyAccess.Update(propertyAccess.PropertySymbol, propertyAccess.PropertyGroupOpt, propertyAccess.AccessKind, isWriteable:=True,
                                                                       propertyAccess.IsLValue, propertyAccess.ReceiverOpt, propertyAccess.Arguments, propertyAccess.DefaultArguments,
                                                                       propertyAccess.Type)
                                target = propertyAccess
                            End If
                        End If
 
                        If Not target.HasErrors Then
                            Dim isShared As Boolean
                            If target.Kind = BoundKind.FieldAccess Then
                                isShared = DirectCast(target, BoundFieldAccess).FieldSymbol.IsShared
                            Else
                                Dim [property] = propertyAccess.PropertySymbol
                                ' Treat extension properties as Shared in this context so we generate
                                ' an error (BC30991) that such properties cannot be used in an initializer.
                                ' Currently, there is only one extension property, InternalXmlHelper.Value:
                                ' e.g.: New List(Of XElement) With {.Value = Nothing}. Consider a specific
                                ' error for extension properties if this scenario is more common.
                                isShared = ([property].ReducedFrom IsNot Nothing) OrElse [property].IsShared
                            End If
 
                            If isShared Then
                                ' report that initializing shared members is not supported
                                ' BC30991: Member '{0}' cannot be initialized in an object initializer expression because it is shared.
                                ReportDiagnostic(diagnostics,
                                                 fieldName,
                                                 ErrorFactory.ErrorInfo(ERRID.ERR_SharedMemberAggrMemberInit1, identifierName))
                            Else
                                ' each field can only be initialized once.
                                ' only do this if the target did not show errors, to reduce noise
                                If Not processedMembers.Add(identifierName) Then
                                    ReportDiagnostic(diagnostics,
                                                     fieldName,
                                                     ErrorFactory.ErrorInfo(ERRID.ERR_DuplicateAggrMemberInit1, identifierName))
                                End If
                            End If
                        End If
                    Else
                        ' if the node already had diagnostics, report these, otherwise report that the accessed member
                        ' is not a field or property.
                        If Not memberBindingDiagnostics.HasAnyErrors Then
                            ' BC30990: Member '{0}' cannot be initialized in an object initializer expression because it is not a field or property.
                            ReportDiagnostic(diagnostics,
                                             fieldName,
                                             ErrorFactory.ErrorInfo(ERRID.ERR_NonFieldPropertyAggrMemberInit1, identifierName))
                        End If
 
                        target = BadExpression(namedFieldInitializer,
                                               target,
                                               ErrorTypeSymbol.UnknownResultType).MakeCompilerGenerated()
                    End If
                Else
                    target = BadExpression(namedFieldInitializer, ErrorTypeSymbol.UnknownResultType).MakeCompilerGenerated()
                End If
 
                ' in contrast to Dev10 Roslyn continues to bind the initialization value even if the receiver had errors.
                Dim value = objectInitializerBinder.BindValue(namedFieldInitializer.Expression, diagnostics)
                ' no need to apply an implicit conversion here, this will be done in BindAssignment
 
                Dim assignmentOperator As BoundExpression = BindAssignment(namedFieldInitializer, target, value, diagnostics)
                memberAssignments.Add(assignmentOperator)
 
                ' assert that the conversion really happened.
                Debug.Assert(TypeSymbol.Equals(DirectCast(memberAssignments.Last, BoundAssignmentOperator).Right.Type, DirectCast(memberAssignments.Last, BoundAssignmentOperator).Left.Type, TypeCompareKind.ConsiderEverything))
 
                memberBindingDiagnostics.Clear()
            Next
 
            memberBindingDiagnostics.Free()
 
            Return New BoundObjectInitializerExpression(objectCreationSyntax.Initializer,
                                                        createTemporary,
                                                        variableOrTempPlaceholder,
                                                        memberAssignments.ToImmutableAndFree,
                                                        initializedObjectType)
        End Function
 
        ''' <summary>
        ''' Binds a object collection initializer.
        ''' During the binding of this node we are binding calls to Add methods of the created object. Once the "collection" 
        ''' type passed the requirements (same as for each collection requirements + must have accessible Add method), all 
        ''' diagnostics are handled by the overload resolution.
        ''' The bound node contains a list of call expressions (that may contain placeholders).
        ''' </summary>
        Private Function BindCollectionInitializer(
            objectCreationSyntax As ObjectCreationExpressionSyntax,
            initializedObjectType As TypeSymbol,
            diagnostics As BindingDiagnosticBag
        ) As BoundCollectionInitializerExpression
 
            Dim collectionInitializerSyntax = DirectCast(objectCreationSyntax.Initializer, ObjectCollectionInitializerSyntax)
            Dim collectionType = initializedObjectType
 
            Dim unusedType As TypeSymbol = Nothing
            Dim unusedExpression As BoundExpression = Nothing
            Dim unusedLValuePlaceholder As BoundLValuePlaceholder = Nothing
            Dim unusedRValuePlaceholder As BoundRValuePlaceholder = Nothing
            Dim temporaryDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics)
            Dim matchesDesignPattern As Boolean = False
 
            ' From Dev10:
            ' Verification of collection type: first we ensure that the collection type really is a collection, i.e.
            ' basically that once we've created the collection then people will be able to "for each" over it.
            ' lwischik: WHY? All we're doing is invoking the "Add" method on something. Why even care
            ' that people can enumerate it afterwards? Was this intended to support "new Collection from MyEnumerable"?
            ' But here we're checking the collection pNewExpression, rather than "From" expression pInput->Initializer...
            ' Answer: that's what the decision was when the spec was designed. The motive was that this "From"
            ' is really intended to be used for collections, and not just for arbitrary classes that happen
            ' to have an "Add" method.
 
            ' Spec 10.9 (this comment is in answer to bug Dev10#531849): a type is considered a collection type if
            '    (1) it satisfies MatchesForEachCollectionDesignPattern (i.e. has a method named GetEnumerator() which
            '        returns a type with MoveNext/Current); or
            '    (2) it implements System.Collections.Generic.IEnumerable(Of T); or
            '    (3) it implements System.Collections.IEnumerable.
            If MatchesForEachCollectionDesignPattern(collectionType,
                                                     New BoundRValuePlaceholder(collectionInitializerSyntax, initializedObjectType),
                                                     unusedType,
                                                     unusedExpression,
                                                     unusedLValuePlaceholder,
                                                     unusedExpression,
                                                     unusedExpression,
                                                     unusedRValuePlaceholder,
                                                     temporaryDiagnostics) Then
                diagnostics.AddRange(temporaryDiagnostics)
                matchesDesignPattern = True
 
            Else
                Dim ienumerableUseSiteDiagnostics = BindingDiagnosticBag.GetInstance(diagnostics)
                Dim ienumerable = GetSpecialType(SpecialType.System_Collections_IEnumerable,
                                                 objectCreationSyntax,
                                                 ienumerableUseSiteDiagnostics)
 
                Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics)
                If IsOrInheritsFromOrImplementsInterface(collectionType, ienumerable, useSiteInfo) Then
                    diagnostics.AddRange(ienumerableUseSiteDiagnostics)
                    matchesDesignPattern = True
 
                Else
                    ReportDiagnostic(diagnostics,
                                     collectionInitializerSyntax,
                                     ErrorFactory.ErrorInfo(ERRID.ERR_NotACollection1, collectionType.Name))
                End If
 
                diagnostics.Add(collectionInitializerSyntax, useSiteInfo)
 
                ienumerableUseSiteDiagnostics.Free()
            End If
 
            Dim result = LookupResult.GetInstance
            temporaryDiagnostics.Clear()
 
            GetMemberIfMatchesRequirements(WellKnownMemberNames.CollectionInitializerAddMethodName,
                                           collectionType,
                                           Function(y As Symbol) As Boolean
                                               Return y.Kind = SymbolKind.Method
                                           End Function,
                                           result,
                                           collectionInitializerSyntax,
                                           temporaryDiagnostics)
 
            Dim initializers = collectionInitializerSyntax.Initializer.Initializers
            Dim initializerCount = initializers.Count
            Dim addInvocationExpressions As ImmutableArray(Of BoundExpression)
            Dim placeholder As BoundWithLValueExpressionPlaceholder = Nothing
 
            If result.IsGood Then
                diagnostics.AddRange(temporaryDiagnostics)
            ElseIf matchesDesignPattern Then
                ' the collection does not have a single accessible Add method.
                ' do not report this error if the collection did not match the design pattern
                ReportDiagnostic(diagnostics,
                                 collectionInitializerSyntax,
                                 ErrorFactory.ErrorInfo(ERRID.ERR_NoAddMethod1, collectionType))
            End If
 
            temporaryDiagnostics.Free()
 
            ' As long as there is a least one accessible Add method we will accept the collection and start 
            ' binding call expressions with the given arguments. All error reporting will now come from the 
            ' overload resolution.
 
            Dim addInvocations(initializerCount - 1) As BoundExpression
 
            ' iterate over the top level initializers.
            placeholder = New BoundWithLValueExpressionPlaceholder(objectCreationSyntax,
                                                                   collectionType)
            placeholder.SetWasCompilerGenerated()
 
            For initializerIndex = 0 To initializerCount - 1
                addInvocations(initializerIndex) = BindCollectionInitializerElement(initializers(initializerIndex),
                                                                                    placeholder,
                                                                                    result,
                                                                                    diagnostics)
            Next
 
            addInvocationExpressions = addInvocations.AsImmutableOrNull
            result.Free()
 
            Return New BoundCollectionInitializerExpression(objectCreationSyntax.Initializer,
                                                            placeholder,
                                                            addInvocationExpressions,
                                                            collectionType)
        End Function
 
        ''' <summary>
        ''' Binds a call expression for a given top level object collection initializer.
        ''' </summary>
        Private Function BindCollectionInitializerElement(
            topLevelInitializer As ExpressionSyntax,
            placeholder As BoundWithLValueExpressionPlaceholder,
            result As LookupResult,
            diagnostics As BindingDiagnosticBag
        ) As BoundExpression
 
            Dim arguments = ArrayBuilder(Of BoundExpression).GetInstance
            If topLevelInitializer.Kind = SyntaxKind.CollectionInitializer Then
                ' handle "... From {{1, 2, 3}, ..."
                Dim collectionInitializer = DirectCast(topLevelInitializer, CollectionInitializerSyntax)
 
                Dim initializers As SeparatedSyntaxList(Of ExpressionSyntax) = collectionInitializer.Initializers
                If initializers.IsEmpty Then
                    ReportDiagnostic(diagnostics, topLevelInitializer, ErrorFactory.ErrorInfo(ERRID.ERR_EmptyAggregateInitializer))
                Else
                    For Each expression In initializers
                        arguments.Add(BindValue(expression, diagnostics))
                    Next
                End If
            Else
                ' handle "... From {1, ..."
                arguments.Add(BindValue(topLevelInitializer, diagnostics))
            End If
 
            If result.IsGood() AndAlso Not arguments.IsEmpty Then
                Dim methodGroup As BoundMethodGroup = CreateBoundMethodGroup(topLevelInitializer,
                                                                             result,
                                                                             LookupOptions.AllMethodsOfAnyArity,
                                                                             diagnostics.AccumulatesDependencies,
                                                                             placeholder,
                                                                             Nothing,
                                                                             QualificationKind.QualifiedViaValue).MakeCompilerGenerated()
 
                Dim invocation = BindInvocationExpression(topLevelInitializer, topLevelInitializer,
                                                          TypeCharacter.None,
                                                          methodGroup,
                                                          arguments.ToImmutableAndFree,
                                                          Nothing,
                                                          diagnostics,
                                                          callerInfoOpt:=topLevelInitializer)
                invocation.SetWasCompilerGenerated()
 
                If invocation.Kind = BoundKind.LateInvocation Then
                    invocation = DirectCast(invocation, BoundLateInvocation).SetLateBoundAccessKind(LateBoundAccessKind.Call)
                End If
 
                Return invocation
            Else
                Return New BoundBadExpression(topLevelInitializer,
                                              LookupResultKind.Empty,
                                              ImmutableArray(Of Symbol).Empty,
                                              arguments.ToImmutableAndFree,
                                              ErrorTypeSymbol.UnknownResultType,
                                              hasErrors:=True).MakeCompilerGenerated()
            End If
        End Function
 
    End Class
 
    ''' <summary>
    ''' Special binder for binding ObjectInitializers. 
    ''' This binder stores a reference to the receiver of the initialization, because fields in an object initializer can be 
    ''' referenced with an omitted left expression in a member access expression (e.g. .Fieldname = .OtherFieldname).
    ''' </summary>
    Friend Class ObjectInitializerBinder
        Inherits Binder
 
        Private ReadOnly _receiver As BoundExpression
 
        Public Sub New(containingBinder As Binder, receiver As BoundExpression)
            MyBase.New(containingBinder)
 
            _receiver = receiver
        End Sub
 
        ''' <summary>
        ''' Use the receiver of the ObjectCreationExpression as the omitted left of a member access.
        ''' </summary>
        Protected Friend Overrides Function TryBindOmittedLeftForMemberAccess(
            node As MemberAccessExpressionSyntax,
            diagnostics As BindingDiagnosticBag,
            accessingBinder As Binder,
            ByRef wholeMemberAccessExpressionBound As Boolean
        ) As BoundExpression
 
            Return _receiver
        End Function
 
        Protected Friend Overrides Function TryBindOmittedLeftForXmlMemberAccess(node As XmlMemberAccessExpressionSyntax, diagnostics As BindingDiagnosticBag, accessingBinder As Binder) As BoundExpression
            Return _receiver
        End Function
 
        ''' <summary>
        ''' Use the receiver of the ObjectCreationExpression to as the omitted left of a dictionary access.
        ''' </summary>
        Protected Overrides Function TryBindOmittedLeftForDictionaryAccess(
                    node As MemberAccessExpressionSyntax,
                    accessingBinder As Binder,
                    diagnostics As BindingDiagnosticBag
                ) As BoundExpression
 
            Return _receiver
        End Function
 
        Protected Overrides Function TryBindOmittedLeftForConditionalAccess(node As ConditionalAccessExpressionSyntax, accessingBinder As Binder, diagnostics As BindingDiagnosticBag) As BoundExpression
            Return Nothing
        End Function
    End Class
End Namespace