MethodCompiler.vb 102.2 KB
Newer Older
T
TomasMatousek 已提交
1
' Copyright (c) Microsoft.  All Rights Reserved.  Licensed under the Apache License, Version 2.0.  See License.txt in the project root for license information.
T
TomasMatousek 已提交
2 3 4 5 6 7 8

Imports System
Imports System.Collections.Concurrent
Imports System.Collections.Immutable
Imports System.Threading
Imports System.Threading.Tasks
Imports Microsoft.CodeAnalysis.CodeGen
9
Imports Microsoft.CodeAnalysis.Diagnostics
T
TomasMatousek 已提交
10 11 12 13 14 15 16 17 18 19 20
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.Text
Imports Microsoft.CodeAnalysis.VisualBasic.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax

Namespace Microsoft.CodeAnalysis.VisualBasic

    Friend NotInheritable Class MethodCompiler
        Inherits VisualBasicSymbolVisitor

A
angocke 已提交
21
        Private ReadOnly _compilation As VisualBasicCompilation
22
        Private ReadOnly _cancellationToken As CancellationToken
T
TomasMatousek 已提交
23 24 25 26
        Private ReadOnly _generateDebugInfo As Boolean
        Private ReadOnly _diagnostics As DiagnosticBag
        Private ReadOnly _hasDeclarationErrors As Boolean
        Private ReadOnly _namespaceScopeBuilder As NamespaceScopeBuilder
27 28
        Private ReadOnly _moduleBeingBuiltOpt As PEModuleBuilder ' Nothing if compiling for diagnostics
        Private ReadOnly _filterOpt As Predicate(Of Symbol)      ' If not Nothing, limit analysis to specific symbols
T
TomasMatousek 已提交
29 30
        Private ReadOnly _debugDocumentProvider As DebugDocumentProvider

31 32 33 34 35
        ' GetDiagnostics only needs to Bind. If we need to go further, _doEmitPhase needs to be set. 
        ' It normally happens during actual compile, but also happens when getting emit diagnostics for 
        ' testing purposes.
        Private ReadOnly _doEmitPhase As Boolean

T
TomasMatousek 已提交
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78
        ' MethodCompiler employs concurrency by following flattened fork/join pattern.
        '
        ' For every item that we want to compile in parallel a new task is forked.
        ' compileTaskQueue is used to track and observe all the tasks. 
        ' Once compileTaskQueue is empty, we know that there are no more tasks (and no more can be created)
        ' and that means we are done compiling. WaitForWorkers ensures this condition.
        '
        ' Note that while tasks may fork more tasks (nested types, lambdas, whatever else that may introduce more types),
        ' we do not want any child/parent relationship between spawned tasks and their creators. 
        ' Creator has no real dependencies on the completion of its children and should finish and release any resources
        ' as soon as it can regardless of the tasks it may have spawned.
        '
        ' Stack is used so that the wait would observe the most recently added task and have 
        ' more chances to do inlined execution.
        Private compilerTasks As ConcurrentStack(Of Task)

        ' Tracks whether any method body has hasErrors set, and used to avoid
        ' emitting if there are errors without corresponding diagnostics.
        ' NOTE: once the flag is set to true, it should never go back to false!!!
        Private _globalHasErrors As Boolean

        Private ReadOnly Property GlobalHasErrors As Boolean
            Get
                Return _globalHasErrors
            End Get
        End Property

        Private Sub SetGlobalErrorIfTrue(arg As Boolean)
            ' NOTE: this is not a volatile write
            '       for correctness we need only single threaded consistency.
            '       Within a single task - if we have got an error it may not be safe to continue with some lowerings.
            '       It is ok if other tasks will see the change after some delay or does not observe at all.
            '       Such races are unavoidable and will just result in performing some work that is safe to do
            '       but may no longer be needed.
            '       The final Join of compiling tasks cannot happen without interlocked operations and that 
            '       will that the final state of the flag is synchronized after we are done compiling.
            If arg Then
                _globalHasErrors = True
            End If
        End Sub


        ' moduleBeingBuilt can be Nothing in order to just analyze methods for errors.
A
angocke 已提交
79
        Private Sub New(compilation As VisualBasicCompilation,
80
                       moduleBeingBuiltOpt As PEModuleBuilder,
T
TomasMatousek 已提交
81 82 83 84 85 86 87 88
                       generateDebugInfo As Boolean,
                       doEmitPhase As Boolean,
                       hasDeclarationErrors As Boolean,
                       diagnostics As DiagnosticBag,
                       filter As Predicate(Of Symbol),
                       cancellationToken As CancellationToken)

            Me._compilation = compilation
89
            Me._moduleBeingBuiltOpt = moduleBeingBuiltOpt
T
TomasMatousek 已提交
90 91 92 93 94
            Me._diagnostics = diagnostics
            Me._hasDeclarationErrors = hasDeclarationErrors
            Me._cancellationToken = cancellationToken
            Me._doEmitPhase = doEmitPhase
            Me._generateDebugInfo = generateDebugInfo
95
            Me._filterOpt = filter
T
TomasMatousek 已提交
96 97

            If generateDebugInfo Then
98
                Me._debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
T
TomasMatousek 已提交
99 100 101 102 103 104 105
            End If

            If compilation.Options.ConcurrentBuild Then
                Me.compilerTasks = New ConcurrentStack(Of Task)()
            End If
        End Sub

106 107 108 109 110 111 112 113 114 115 116 117 118 119 120
        Private Shared Function IsDefinedOrImplementedInSourceTree(symbol As Symbol, tree As SyntaxTree, span As TextSpan?) As Boolean
            If symbol.IsDefinedInSourceTree(tree, span) Then
                Return True
            End If

            Dim method = TryCast(symbol, SourceMemberMethodSymbol)
            If method IsNot Nothing AndAlso
                method.IsPartialDefinition Then

                Dim implementationPart = method.PartialImplementationPart
                If implementationPart IsNot Nothing Then
                    Return implementationPart.IsDefinedInSourceTree(tree, span)
                End If
            End If

121 122 123 124 125 126
            If symbol.Kind = SymbolKind.Method AndAlso symbol.IsImplicitlyDeclared AndAlso
               DirectCast(symbol, MethodSymbol).MethodKind = MethodKind.Constructor Then
                ' Include implicitly declared constructor if containing type is included
                Return IsDefinedOrImplementedInSourceTree(symbol.ContainingType, tree, span)
            End If

127 128 129
            Return False
        End Function

T
TomasMatousek 已提交
130 131 132 133 134 135 136 137 138 139 140
        ''' <summary>
        ''' Completes binding and performs analysis of bound trees for the purpose of obtaining diagnostics.
        ''' 
        ''' NOTE: This method does not perform lowering/rewriting/emit. 
        '''       Errors from those stages require complete compile, 
        '''       but generally are not interesting during editing.
        ''' 
        ''' NOTE: the bound tree produced by this method are not stored anywhere
        '''       and immediately lost after diagnostics of a particular tree is done.
        '''       
        ''' </summary>
A
angocke 已提交
141
        Public Shared Sub GetCompileDiagnostics(compilation As VisualBasicCompilation,
T
TomasMatousek 已提交
142 143 144 145 146 147 148 149 150 151 152
                                                root As NamespaceSymbol,
                                                tree As SyntaxTree,
                                                filterSpanWithinTree As TextSpan?,
                                                hasDeclarationErrors As Boolean,
                                                diagnostics As DiagnosticBag,
                                                doEmitPhase As Boolean,
                                                cancellationToken As CancellationToken)

            Dim filter As Predicate(Of Symbol) = Nothing

            If tree IsNot Nothing Then
153
                filter = Function(sym) IsDefinedOrImplementedInSourceTree(sym, tree, filterSpanWithinTree)
T
TomasMatousek 已提交
154 155 156
            End If

            Dim compiler = New MethodCompiler(compilation,
157
                                              moduleBeingBuiltOpt:=Nothing,
T
TomasMatousek 已提交
158 159 160 161 162 163 164 165 166
                                              generateDebugInfo:=False,
                                              doEmitPhase:=doEmitPhase,
                                              hasDeclarationErrors:=hasDeclarationErrors,
                                              diagnostics:=diagnostics,
                                              filter:=filter,
                                              cancellationToken:=cancellationToken)

            root.Accept(compiler)

167 168 169 170 171 172 173 174
            If tree Is Nothing Then
                ' include entry point diagnostics if we are compiling the entire compilation, not just a single tree:
                Dim entryPointAndDiagnostics = compilation.GetEntryPointAndDiagnostics(cancellationToken)
                If entryPointAndDiagnostics IsNot Nothing Then
                    diagnostics.AddRange(entryPointAndDiagnostics.Diagnostics)
                End If
            End If

T
TomasMatousek 已提交
175 176 177 178 179 180
            compiler.WaitForWorkers()
        End Sub

        ''' <summary>
        ''' Compiles given compilation into provided module.
        ''' 
181
        ''' NOTE: it is ok for moduleBeingBuiltOpt to be Nothing. 
T
TomasMatousek 已提交
182 183 184 185 186 187
        '''       In such case the only results of this method would be diagnostics for complete compile.
        ''' 
        ''' NOTE: the bound/lowered trees produced by this method are not stored anywhere and
        '''       immediately lost after obtaining method bodies and diagnostics for a particular
        '''       tree.
        ''' </summary>
A
angocke 已提交
188
        Friend Shared Sub CompileMethodBodies(compilation As VisualBasicCompilation,
189
                                              moduleBeingBuiltOpt As PEModuleBuilder,
T
TomasMatousek 已提交
190 191 192 193 194 195
                                              generateDebugInfo As Boolean,
                                              hasDeclarationErrors As Boolean,
                                              filter As Predicate(Of Symbol),
                                              diagnostics As DiagnosticBag,
                                              Optional cancellationToken As CancellationToken = Nothing)

196 197 198
            If compilation.PreviousSubmission IsNot Nothing Then
                ' In case there is a previous submission, we should ensure 
                ' it has already created anonymous type/delegates templates
T
TomasMatousek 已提交
199

200 201
                ' NOTE: if there are any errors, we will pick up what was created anyway
                compilation.PreviousSubmission.EnsureAnonymousTypeTemplates(cancellationToken)
T
TomasMatousek 已提交
202

203 204
                ' TODO: revise to use a loop instead of a recursion
            End If
T
TomasMatousek 已提交
205 206

#If DEBUG Then
207
            compilation.EmbeddedSymbolManager.AssertMarkAllDeferredSymbolsAsReferencedIsCalled()
T
TomasMatousek 已提交
208 209
#End If

210
            Dim compiler = New MethodCompiler(compilation,
211 212
                                                  moduleBeingBuiltOpt,
                                                  generateDebugInfo,
T
TomasMatousek 已提交
213 214 215 216 217 218
                                                  doEmitPhase:=True,
                                                  hasDeclarationErrors:=hasDeclarationErrors,
                                                  diagnostics:=diagnostics,
                                                  filter:=filter,
                                                  cancellationToken:=cancellationToken)

219 220
            compilation.SourceModule.GlobalNamespace.Accept(compiler)
            compiler.WaitForWorkers()
T
TomasMatousek 已提交
221

222 223 224 225 226
            If moduleBeingBuiltOpt IsNot Nothing Then
                Dim additionalTypes = moduleBeingBuiltOpt.GetAdditionalTopLevelTypes()
                If Not additionalTypes.IsEmpty Then
                    compiler.CompileSynthesizedMethods(additionalTypes)
                End If
227

228 229
                compilation.AnonymousTypeManager.AssignTemplatesNamesAndCompile(compiler, moduleBeingBuiltOpt, diagnostics)
                compiler.WaitForWorkers()
T
TomasMatousek 已提交
230

231 232 233 234
                ' Process symbols from embedded code if needed.
                If compilation.EmbeddedSymbolManager.Embedded <> EmbeddedSymbolKind.None Then
                    compiler.ProcessEmbeddedMethods()
                End If
T
TomasMatousek 已提交
235

236 237 238 239
                Dim privateImplClass = moduleBeingBuiltOpt.PrivateImplClass
                If privateImplClass IsNot Nothing Then
                    ' all threads that were adding methods must be finished now, we can freeze the class:
                    privateImplClass.Freeze()
T
TomasMatousek 已提交
240

241
                    compiler.CompileSynthesizedMethods(privateImplClass)
T
TomasMatousek 已提交
242
                End If
243
            End If
T
TomasMatousek 已提交
244

245 246 247
            Dim entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, diagnostics, cancellationToken)
            If moduleBeingBuiltOpt IsNot Nothing Then
                moduleBeingBuiltOpt.SetEntryPoint(entryPoint)
T
TomasMatousek 已提交
248

249 250 251 252
                If compiler.GlobalHasErrors AndAlso Not hasDeclarationErrors AndAlso Not diagnostics.HasAnyErrors Then
                    ' If there were errors but no diagnostics, explicitly add
                    ' a "Failed to emit module" error to prevent emitting.
                    diagnostics.Add(ERRID.ERR_ModuleEmitFailure, NoLocation.Singleton, moduleBeingBuiltOpt.SourceModule.Name)
T
TomasMatousek 已提交
253
                End If
254
            End If
T
TomasMatousek 已提交
255 256
        End Sub

A
angocke 已提交
257
        Friend Shared Function GetEntryPoint(compilation As VisualBasicCompilation,
T
TomasMatousek 已提交
258 259 260 261
                                             moduleBeingBuilt As PEModuleBuilder,
                                             diagnostics As DiagnosticBag,
                                             cancellationToken As CancellationToken) As MethodSymbol

A
angocke 已提交
262
            Dim options As VisualBasicCompilationOptions = compilation.Options
T
TomasMatousek 已提交
263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280
            If Not options.OutputKind.IsApplication() Then
                Debug.Assert(compilation.GetEntryPointAndDiagnostics(Nothing) Is Nothing)

                If compilation.IsSubmission Then
                    Dim submissionReturnType As TypeSymbol = compilation.GetSubmissionReturnType()
                    Return DefineScriptEntryPoint(compilation, moduleBeingBuilt, submissionReturnType, diagnostics)
                End If

                Return Nothing
            End If

            Debug.Assert(Not compilation.IsSubmission)
            Debug.Assert(options.OutputKind.IsApplication())

            Dim entryPointAndDiagnostics = compilation.GetEntryPointAndDiagnostics(cancellationToken)
            Debug.Assert(entryPointAndDiagnostics IsNot Nothing)
            Debug.Assert(Not entryPointAndDiagnostics.Diagnostics.IsDefault)

281 282
            diagnostics.AddRange(entryPointAndDiagnostics.Diagnostics)

T
TomasMatousek 已提交
283 284 285 286 287 288 289 290 291
            If compilation.ScriptClass IsNot Nothing Then
                Debug.Assert(entryPointAndDiagnostics.MethodSymbol Is Nothing)
                Return DefineScriptEntryPoint(compilation, moduleBeingBuilt, compilation.GetSpecialType(SpecialType.System_Void), diagnostics)
            End If

            Debug.Assert(entryPointAndDiagnostics.MethodSymbol IsNot Nothing OrElse entryPointAndDiagnostics.Diagnostics.HasAnyErrors() OrElse Not compilation.Options.Errors.IsDefaultOrEmpty)
            Return entryPointAndDiagnostics.MethodSymbol
        End Function

A
angocke 已提交
292
        Friend Shared Function DefineScriptEntryPoint(compilation As VisualBasicCompilation, moduleBeingBuilt As PEModuleBuilder, returnType As TypeSymbol, diagnostics As DiagnosticBag) As MethodSymbol
T
TomasMatousek 已提交
293
            Dim scriptEntryPoint = New SynthesizedEntryPointSymbol(compilation.ScriptClass, returnType)
294 295
            If moduleBeingBuilt IsNot Nothing AndAlso Not diagnostics.HasAnyErrors Then
                Dim compilationState = New TypeCompilationState(compilation, moduleBeingBuilt, initializeComponentOpt:=Nothing)
T
TomasMatousek 已提交
296 297
                Dim body = scriptEntryPoint.CreateBody()

298
                Dim emittedBody = GenerateMethodBody(moduleBeingBuilt,
299
                                                     scriptEntryPoint,
300 301 302 303
                                                     methodOrdinal:=MethodDebugId.UndefinedOrdinal,
                                                     block:=body,
                                                     lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
                                                     closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
304
                                                     stateMachineTypeOpt:=Nothing,
305
                                                     variableSlotAllocatorOpt:=Nothing,
306 307
                                                     debugDocumentProvider:=Nothing,
                                                     diagnostics:=diagnostics,
T
TomasMatousek 已提交
308
                                                     generateDebugInfo:=False)
T
TomasMatousek 已提交
309

310
                moduleBeingBuilt.SetMethodBody(scriptEntryPoint, emittedBody)
T
TomasMatousek 已提交
311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334
                moduleBeingBuilt.AddSynthesizedDefinition(compilation.ScriptClass, scriptEntryPoint)
            End If

            Return scriptEntryPoint
        End Function

        Private Sub WaitForWorkers()
            Dim tasks As ConcurrentStack(Of Task) = Me.compilerTasks
            If tasks Is Nothing Then
                Return
            End If

            Dim curTask As Task = Nothing
            While tasks.TryPop(curTask)
                curTask.GetAwaiter().GetResult()
            End While
        End Sub

#Region "Embedded symbols processing"

        Private Sub ProcessEmbeddedMethods()
            Dim manager = _compilation.EmbeddedSymbolManager
            Dim processedSymbols As New ConcurrentSet(Of Symbol)(ReferenceEqualityComparer.Instance)

T
TomasMatousek 已提交
335 336 337

            Dim methodOrdinal = 0

T
TomasMatousek 已提交
338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363
            Dim builder = ArrayBuilder(Of Symbol).GetInstance
            Do
                ' We iterate all the symbols for embedded code that are CURRENTLY known
                ' to be referenced by user code or already emitted embedded code. 
                '
                ' If this the first full emit of the current compilation and there are no 
                ' concurrent emits this collection will consist of embedded symbols referenced 
                ' from attributes on compilation source symbols (by directly using embedded 
                ' attributes OR referencing embedded types from attributes' arguments via
                ' 'GetType(EmbeddedTypeName)' expressions).
                ' 
                ' The consecutive iterations may also see new embedded symbols referenced
                ' as we compile and emit embedded methods.
                '
                ' If there are concurrent emits in place more referenced symbols may be returned 
                ' by GetCurrentReferencedSymbolsSnapshot than in simple case described above,
                ' thus reducing the number of iterations of the outer Do loop.
                '
                ' Note that GetCurrentReferencedSymbolsSnapshot actually makes a snapshot
                ' of the referenced symbols.
                manager.GetCurrentReferencedSymbolsSnapshot(builder, processedSymbols)
                If builder.Count = 0 Then
                    Exit Do
                End If

                For index = 0 To builder.Count - 1
T
TomasMatousek 已提交
364
                    Dim symbol As symbol = builder(index)
T
TomasMatousek 已提交
365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
                    processedSymbols.Add(symbol)

#If DEBUG Then
                    ' In DEBUG assert that the type does not have 
                    ' field initializers except those in const fields
                    If symbol.Kind = SymbolKind.NamedType Then
                        Dim embeddedType = DirectCast(symbol, EmbeddedSymbolManager.EmbeddedNamedTypeSymbol)
                        AssertAllInitializersAreConstants(embeddedType.StaticInitializers)
                        AssertAllInitializersAreConstants(embeddedType.InstanceInitializers)
                    End If
#End If
                    ' Compile method
                    If symbol.Kind = SymbolKind.Method Then
                        Dim embeddedMethod = DirectCast(symbol, MethodSymbol)
                        EmbeddedSymbolManager.ValidateMethod(embeddedMethod)
                        VisitEmbeddedMethod(embeddedMethod)
                    End If
                Next

                builder.Clear()
            Loop
            builder.Free()

            ' Seal the referenced symbol collection
            manager.SealCollection()
        End Sub

        Private Sub VisitEmbeddedMethod(method As MethodSymbol)
            ' Lazily created collection of synthetic methods which 
            ' may be created during compilation of methods
395
            Dim compilationState As TypeCompilationState = New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing)
T
TomasMatousek 已提交
396 397 398 399 400 401 402 403 404 405 406 407 408

            ' Containing type binder

            ' NOTE: we need to provide type binder for the constructor compilation,
            '       so we create it for each constructor, but it does not seem to be a 
            '       problem since current embedded types have only one constructor per 
            '       type; this might need to be revised later if this assumption changes
            Dim sourceTypeBinder As Binder = If(method.MethodKind = MethodKind.Ordinary, Nothing,
                                                    BinderBuilder.CreateBinderForType(
                                                        DirectCast(method.ContainingModule, SourceModuleSymbol),
                                                        method.ContainingType.Locations(0).PossiblyEmbeddedOrMySourceTree(),
                                                        method.ContainingType))

T
TomasMatousek 已提交
409 410 411 412 413 414
            ' Since embedded method bodies don't produce synthesized methods (see the assertion below)
            ' there is no need to assign an ordinal to embedded methods.
            Const methodOrdinal As Integer = -1

            Dim withEventPropertyIdDispenser = 0
            Dim delegateRelaxationIdDispenser = 0
T
TomasMatousek 已提交
415 416 417

            Dim referencedConstructor As MethodSymbol = Nothing
            CompileMethod(method,
T
TomasMatousek 已提交
418 419 420
                          methodOrdinal,
                          withEventPropertyIdDispenser,
                          delegateRelaxationIdDispenser,
T
TomasMatousek 已提交
421 422 423 424 425 426 427
                          filter:=Nothing,
                          compilationState:=compilationState,
                          processedInitializers:=Binder.ProcessedFieldOrPropertyInitializers.Empty,
                          containingTypeBinder:=sourceTypeBinder,
                          previousSubmissionFields:=Nothing,
                          referencedConstructor:=referencedConstructor)

T
TomasMatousek 已提交
428 429 430 431 432 433
            ' Do not expect WithEvents
            Debug.Assert(withEventPropertyIdDispenser = 0)

            ' Do not expect delegate relaxation stubs
            Debug.Assert(delegateRelaxationIdDispenser = 0)

T
TomasMatousek 已提交
434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469
            ' Do not expect constructor --> constructor calls for embedded types
            Debug.Assert(referencedConstructor Is Nothing OrElse
                         Not referencedConstructor.ContainingType.Equals(method.ContainingType))

            ' Don't expect any synthetic methods created for embedded types
            Debug.Assert(Not compilationState.HasSynthesizedMethods)
        End Sub

        <Conditional("DEBUG")>
        Private Sub AssertAllInitializersAreConstants(initializers As ImmutableArray(Of ImmutableArray(Of FieldOrPropertyInitializer)))
            If Not initializers.IsDefaultOrEmpty Then
                For Each initializerGroup In initializers
                    If Not initializerGroup.IsEmpty Then
                        For Each initializer In initializerGroup
                            For Each fieldOrProperty In initializer.FieldsOrProperty
                                Debug.Assert(fieldOrProperty.Kind = SymbolKind.Field)
                                Debug.Assert(DirectCast(fieldOrProperty, FieldSymbol).IsConst)
                            Next
                        Next
                    End If
                Next
            End If
        End Sub

#End Region

        Private ReadOnly Property DoEmitPhase() As Boolean
            Get
                Return _doEmitPhase
            End Get
        End Property

        Public Overrides Sub VisitNamespace(symbol As NamespaceSymbol)
            _cancellationToken.ThrowIfCancellationRequested()

            If Me._compilation.Options.ConcurrentBuild Then
470
                Dim worker As Task = CompileNamespaceAsTask(symbol)
T
TomasMatousek 已提交
471 472 473 474 475 476
                compilerTasks.Push(worker)
            Else
                CompileNamespace(symbol)
            End If
        End Sub

477
        Private Function CompileNamespaceAsTask(symbol As NamespaceSymbol) As Task
T
TomasMatousek 已提交
478
            Return Task.Run(
479 480 481 482 483 484 485 486
                UICultureUtilities.WithCurrentUICulture(
                    Sub()
                        Try
                            CompileNamespace(symbol)
                        Catch e As Exception When FatalError.ReportUnlessCanceled(e)
                            Throw ExceptionUtilities.Unreachable
                        End Try
                    End Sub),
T
TomasMatousek 已提交
487 488 489 490
                Me._cancellationToken)
        End Function

        Private Sub CompileNamespace(symbol As NamespaceSymbol)
491
            If PassesFilter(_filterOpt, symbol) Then
T
TomasMatousek 已提交
492 493 494 495 496 497 498 499
                For Each member In symbol.GetMembersUnordered()
                    member.Accept(Me)
                Next
            End If
        End Sub

        Public Overrides Sub VisitNamedType(symbol As NamedTypeSymbol)
            _cancellationToken.ThrowIfCancellationRequested()
500
            If PassesFilter(_filterOpt, symbol) Then
T
TomasMatousek 已提交
501
                If Me._compilation.Options.ConcurrentBuild Then
502
                    Dim worker As Task = CompileNamedTypeAsTask(symbol, _filterOpt)
T
TomasMatousek 已提交
503 504
                    compilerTasks.Push(worker)
                Else
505
                    CompileNamedType(symbol, _filterOpt)
T
TomasMatousek 已提交
506 507 508 509 510 511
                End If
            End If
        End Sub

        Private Function CompileNamedTypeAsTask(symbol As NamedTypeSymbol, filter As Predicate(Of Symbol)) As Task
            Return Task.Run(
512 513 514 515 516 517 518 519
                UICultureUtilities.WithCurrentUICulture(
                    Sub()
                        Try
                            CompileNamedType(symbol, filter)
                        Catch e As Exception When FatalError.ReportUnlessCanceled(e)
                            Throw ExceptionUtilities.Unreachable
                        End Try
                    End Sub),
T
TomasMatousek 已提交
520 521 522 523 524 525 526 527 528 529 530
                Me._cancellationToken)
        End Function

        Private Sub CompileNamedType(symbol As NamedTypeSymbol, filter As Predicate(Of Symbol))
            If symbol.IsEmbedded Then
                ' Don't process embedded types
                Return
            End If

            ' Find the constructor of a script class.
            Dim scriptCtor As MethodSymbol = Nothing
T
TomasMatousek 已提交
531
            Dim submissionCtorOrdinal = -1
T
TomasMatousek 已提交
532 533 534 535 536 537 538
            If symbol.IsScriptClass Then
                scriptCtor = symbol.InstanceConstructors(0)
                Debug.Assert(scriptCtor IsNot Nothing)
            End If

            Dim processedStaticInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty
            Dim processedInstanceInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty
T
TomasMatousek 已提交
539
            Dim synthesizedSubmissionFields = If(symbol.IsSubmissionClass, New synthesizedSubmissionFields(_compilation, symbol), Nothing)
T
TomasMatousek 已提交
540 541 542 543 544 545 546 547 548 549 550

            ' if this is a type symbol from source we'll try to bind the field initializers as well
            Dim sourceTypeSymbol = TryCast(symbol, SourceMemberContainerTypeSymbol)
            Dim initializeComponent As MethodSymbol = Nothing

            If sourceTypeSymbol IsNot Nothing AndAlso DoEmitPhase Then
                initializeComponent = GetDesignerInitializeComponentMethod(sourceTypeSymbol)
            End If

            ' Lazily created collection of synthetic methods which 
            ' may be created during compilation of methods
551
            Dim compilationState As TypeCompilationState = New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponent)
T
TomasMatousek 已提交
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581

            ' Containing type binder
            Dim sourceTypeBinder As Binder = Nothing

            If sourceTypeSymbol IsNot Nothing Then

                Debug.Assert(sourceTypeSymbol.Locations.Length > 0)
                sourceTypeBinder = BinderBuilder.CreateBinderForType(
                                        DirectCast(sourceTypeSymbol.ContainingModule, SourceModuleSymbol),
                                        sourceTypeSymbol.Locations(0).PossiblyEmbeddedOrMySourceTree,
                                        sourceTypeSymbol)

                Binder.BindFieldAndPropertyInitializers(sourceTypeSymbol,
                                                        sourceTypeSymbol.StaticInitializers,
                                                        scriptCtor,
                                                        processedStaticInitializers,
                                                        _diagnostics)

                Binder.BindFieldAndPropertyInitializers(sourceTypeSymbol,
                                                        sourceTypeSymbol.InstanceInitializers,
                                                        scriptCtor,
                                                        processedInstanceInitializers,
                                                        _diagnostics)

                ' TODO: any flow analysis for initializers?

                ' const fields of type date or decimal require a shared constructor. We decided that this constructor
                ' should not be part of the type's member list. If there is not already a shared constructor, we're 
                ' creating one and call CompileMethod to rewrite the field initializers. 
                Dim sharedDefaultConstructor = sourceTypeSymbol.CreateSharedConstructorsForConstFieldsIfRequired(sourceTypeBinder, _diagnostics)
582
                If sharedDefaultConstructor IsNot Nothing AndAlso PassesFilter(filter, sharedDefaultConstructor) Then
T
TomasMatousek 已提交
583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600 601

                    Dim sharedConstructorWithEventPropertyIdDispenser = 0
                    Dim sharedConstructorDelegateRelaxationIdDispenser = 0

                    CompileMethod(sharedDefaultConstructor,
                                  -1,
                                  sharedConstructorWithEventPropertyIdDispenser,
                                  sharedConstructorDelegateRelaxationIdDispenser,
                                  filter,
                                  compilationState,
                                  processedStaticInitializers,
                                  sourceTypeBinder,
                                  synthesizedSubmissionFields)

                    ' Default shared constructor shall not have any Handles clause
                    Debug.Assert(sharedConstructorWithEventPropertyIdDispenser = 0)

                    ' Default shared constructor shall not produce delegate relaxation stubs
                    Debug.Assert(sharedConstructorDelegateRelaxationIdDispenser = 0)
T
TomasMatousek 已提交
602

603 604
                    If _moduleBeingBuiltOpt IsNot Nothing Then
                        _moduleBeingBuiltOpt.AddSynthesizedDefinition(sourceTypeSymbol, sharedDefaultConstructor)
T
TomasMatousek 已提交
605 606 607 608 609 610
                    End If
                End If
            End If

            ' Constructor --> Constructor calls to be used in cycles detection
            Dim constructorCallMap As Dictionary(Of MethodSymbol, MethodSymbol) = Nothing
T
TomasMatousek 已提交
611 612 613 614 615 616 617 618 619 620
            Dim members = symbol.GetMembers()

            ' Unique ids assigned to synthesized overrides of WithEvents properties.
            Dim withEventPropertyIdDispenser = 0

            ' Unique ids assigned to synthesized delegate relaxation stubs.
            Dim delegateRelaxationIdDispenser = 0

            For memberOrdinal = 0 To members.Length - 1
                Dim member = members(memberOrdinal)
T
TomasMatousek 已提交
621

622
                If Not PassesFilter(filter, member) Then
T
TomasMatousek 已提交
623 624 625
                    Continue For
                End If

T
TomasMatousek 已提交
626 627 628
                Select Case member.Kind
                    Case SymbolKind.NamedType
                        member.Accept(Me)
T
TomasMatousek 已提交
629

T
TomasMatousek 已提交
630 631 632 633 634 635 636
                    Case SymbolKind.Method
                        Dim method = DirectCast(member, MethodSymbol)
                        If method.IsSubmissionConstructor Then
                            Debug.Assert(submissionCtorOrdinal = -1)
                            submissionCtorOrdinal = memberOrdinal
                            Continue For
                        End If
T
TomasMatousek 已提交
637 638

                        If method.IsPartial() Then
639 640 641 642 643
                            Dim impl = method.PartialImplementationPart
                            If impl IsNot method Then
                                If CType(method, SourceMethodSymbol).SetDiagnostics(ImmutableArray(Of Diagnostic).Empty) Then
                                    method.DeclaringCompilation.SymbolDeclaredEvent(method)
                                End If
T
TomasMatousek 已提交
644

645 646 647
                                If impl Is Nothing Then
                                    Continue For
                                End If
T
TomasMatousek 已提交
648 649

                                method = impl
T
TomasMatousek 已提交
650 651 652 653 654 655 656 657 658 659 660 661 662 663
                            End If
                        End If

                        ' pass correct processed initializers for the static or instance constructors, 
                        ' otherwise pass nothing
                        Dim processedInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty

                        If method.MethodKind = MethodKind.SharedConstructor Then
                            processedInitializers = processedStaticInitializers
                        ElseIf method.MethodKind = MethodKind.Constructor Then
                            processedInitializers = processedInstanceInitializers
                        End If

                        Dim referencedConstructor As MethodSymbol = Nothing
T
TomasMatousek 已提交
664 665 666 667 668 669 670 671 672 673 674

                        CompileMethod(method,
                                      memberOrdinal,
                                      withEventPropertyIdDispenser,
                                      delegateRelaxationIdDispenser,
                                      filter,
                                      compilationState,
                                      processedInitializers,
                                      sourceTypeBinder,
                                      synthesizedSubmissionFields,
                                      referencedConstructor)
T
TomasMatousek 已提交
675 676 677 678 679 680 681 682 683 684 685 686 687 688 689 690 691

                        ' If 'referencedConstructor' is returned by 'CompileMethod', the method just compiled 
                        ' was a constructor which references the returned symbol. We might want to store 
                        ' some of those constructors in 'constructorCallMap' to process later for cycle detection
                        If referencedConstructor IsNot Nothing Then

                            '  If base class constructor is called, the constructor cannot be part of a cycle
                            If referencedConstructor.ContainingType.Equals(symbol) Then
                                If constructorCallMap Is Nothing Then
                                    constructorCallMap = New Dictionary(Of MethodSymbol, MethodSymbol)
                                End If
                                constructorCallMap.Add(method, referencedConstructor)
                            End If

                        End If

                        ' Create exact signature stubs for interface implementations.
692
                        If DoEmitPhase AndAlso _moduleBeingBuiltOpt IsNot Nothing Then
T
TomasMatousek 已提交
693 694
                            CreateExplicitInterfaceImplementationStubs(compilationState, method)
                        End If
T
TomasMatousek 已提交
695
                End Select
T
TomasMatousek 已提交
696 697 698 699 700 701 702 703 704 705 706
            Next

            Debug.Assert(symbol.TypeKind <> TypeKind.Submission OrElse (scriptCtor IsNot Nothing AndAlso scriptCtor.IsSubmissionConstructor))

            ' Detect and report cycles in constructor calls
            If constructorCallMap IsNot Nothing Then
                DetectAndReportCyclesInConstructorCalls(constructorCallMap, _diagnostics)
            End If

            ' Compile submission constructor last so that synthesized submission fields are collected from all script methods:
            If scriptCtor IsNot Nothing AndAlso scriptCtor.IsSubmissionConstructor Then
T
TomasMatousek 已提交
707 708 709 710 711 712 713 714 715
                CompileMethod(scriptCtor,
                              submissionCtorOrdinal,
                              withEventPropertyIdDispenser,
                              delegateRelaxationIdDispenser,
                              filter,
                              compilationState,
                              processedInstanceInitializers,
                              sourceTypeBinder,
                              synthesizedSubmissionFields)
T
TomasMatousek 已提交
716

717 718
                If synthesizedSubmissionFields IsNot Nothing AndAlso _moduleBeingBuiltOpt IsNot Nothing Then
                    synthesizedSubmissionFields.AddToType(symbol, _moduleBeingBuiltOpt)
T
TomasMatousek 已提交
719 720 721 722 723 724 725 726 727 728 729 730 731 732 733
                End If
            End If

            ' Report warnings for constructors that do not call InitializeComponent
            If initializeComponent IsNot Nothing Then
                For Each member In symbol.GetMembers()
                    If member.IsShared OrElse Not member.IsFromCompilation(_compilation) OrElse member.Kind <> SymbolKind.Method Then
                        Continue For
                    End If

                    Dim sourceMethod = TryCast(member, SourceMemberMethodSymbol)

                    If sourceMethod IsNot Nothing AndAlso
                       sourceMethod.MethodKind = MethodKind.Constructor AndAlso
                       Not compilationState.CallsInitializeComponent(sourceMethod) Then
T
TomasMatousek 已提交
734
                        Dim location As location = sourceMethod.NonMergedLocation
T
TomasMatousek 已提交
735 736 737 738 739 740 741 742 743 744
                        Debug.Assert(location IsNot Nothing)

                        If location IsNot Nothing Then
                            Binder.ReportDiagnostic(_diagnostics, location, ERRID.WRN_ExpectedInitComponentCall2, sourceMethod, sourceTypeSymbol)
                        End If
                    End If
                Next
            End If

            ' Add synthetic methods created for this type in above calls to CompileMethod
745
            If _moduleBeingBuiltOpt IsNot Nothing Then
T
TomasMatousek 已提交
746 747
                CompileSynthesizedMethods(compilationState)
            End If
748 749

            compilationState.Free()
T
TomasMatousek 已提交
750 751 752 753 754 755 756 757 758 759 760 761 762 763 764 765 766 767 768 769 770 771 772 773 774 775 776 777 778 779 780 781 782 783 784 785 786 787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
        End Sub

        Private Sub CreateExplicitInterfaceImplementationStubs(compilationState As TypeCompilationState, method As MethodSymbol)
            ' It is not common to have signature mismatch, let's avoid any extra work
            ' and allocations until we know that we have a mismatch.
            Dim stubs As ArrayBuilder(Of SynthesizedInterfaceImplementationStubSymbol) = Nothing

            For Each implemented In method.ExplicitInterfaceImplementations
                If Not MethodSignatureComparer.CustomModifiersAndParametersAndReturnTypeSignatureComparer.Equals(method, implemented) Then
                    If stubs Is Nothing Then
                        stubs = ArrayBuilder(Of SynthesizedInterfaceImplementationStubSymbol).GetInstance()
                    End If

                    Dim matchingStub As SynthesizedInterfaceImplementationStubSymbol = Nothing

                    For Each candidate In stubs
                        If MethodSignatureComparer.CustomModifiersAndParametersAndReturnTypeSignatureComparer.Equals(candidate, implemented) Then
                            matchingStub = candidate
                            Exit For
                        End If
                    Next

                    If matchingStub Is Nothing Then
                        matchingStub = New SynthesizedInterfaceImplementationStubSymbol(method, implemented)
                        stubs.Add(matchingStub)

                        Dim f = New SyntheticBoundNodeFactory(matchingStub, matchingStub, method.Syntax, compilationState, New DiagnosticBag())

                        Dim methodToInvoke As MethodSymbol
                        If method.IsGenericMethod Then
                            methodToInvoke = method.Construct(matchingStub.TypeArguments)
                        Else
                            methodToInvoke = method
                        End If

                        Dim arguments = ArrayBuilder(Of BoundExpression).GetInstance(matchingStub.ParameterCount)

                        For Each param In matchingStub.Parameters
                            Dim parameterExpression = f.Parameter(param)

                            If Not param.IsByRef Then
                                parameterExpression = parameterExpression.MakeRValue()
                            End If

                            arguments.Add(parameterExpression)
                        Next

                        Dim invocation = f.Call(f.Me, methodToInvoke, arguments.ToImmutableAndFree())
                        Dim body As BoundBlock

                        If method.IsSub Then
                            body = f.Block(f.ExpressionStatement(invocation), f.Return())
                        Else
                            body = f.Block(f.Return(invocation))
                        End If

                        f.CloseMethod(body)
807
                        _moduleBeingBuiltOpt.AddSynthesizedDefinition(method.ContainingType, DirectCast(matchingStub, Microsoft.Cci.IMethodDefinition))
T
TomasMatousek 已提交
808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839 840
                    End If

                    matchingStub.AddImplementedMethod(implemented)
                End If
            Next

            If stubs IsNot Nothing Then
                For Each stub In stubs
                    stub.Seal()
                Next

                stubs.Free()
            End If
        End Sub

        Private Shared Function GetDesignerInitializeComponentMethod(sourceTypeSymbol As SourceMemberContainerTypeSymbol) As MethodSymbol

            If sourceTypeSymbol.TypeKind = TypeKind.Class AndAlso sourceTypeSymbol.GetAttributes().IndexOfAttribute(sourceTypeSymbol, AttributeDescription.DesignerGeneratedAttribute) > -1 Then
                For Each member As Symbol In sourceTypeSymbol.GetMembers("InitializeComponent")
                    If member.Kind = SymbolKind.Method Then
                        Dim method = DirectCast(member, MethodSymbol)

                        If method.IsSub AndAlso Not method.IsShared AndAlso Not method.IsGenericMethod AndAlso method.ParameterCount = 0 Then
                            Return method
                        End If
                    End If
                Next
            End If

            Return Nothing
        End Function

        Private Sub CompileSynthesizedMethods(privateImplClass As PrivateImplementationDetails)
841
            Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing)
842

843 844
            For Each method As MethodSymbol In privateImplClass.GetMethods(Nothing)
                Dim diagnosticsThisMethod = DiagnosticBag.GetInstance()
845

846
                Dim boundBody = method.GetBoundMethodBody(diagnosticsThisMethod)
T
TomasMatousek 已提交
847

848 849
                Dim emittedBody = GenerateMethodBody(_moduleBeingBuiltOpt,
                                                     method,
850 851 852 853
                                                     methodOrdinal:=MethodDebugId.UndefinedOrdinal,
                                                     block:=boundBody,
                                                     lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
                                                     closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
854 855
                                                     stateMachineTypeOpt:=Nothing,
                                                     variableSlotAllocatorOpt:=Nothing,
856 857
                                                     debugDocumentProvider:=Nothing,
                                                     diagnostics:=diagnosticsThisMethod,
T
TomasMatousek 已提交
858
                                                     generateDebugInfo:=False)
T
TomasMatousek 已提交
859

860 861
                _diagnostics.AddRange(diagnosticsThisMethod)
                diagnosticsThisMethod.Free()
T
TomasMatousek 已提交
862

863 864 865 866
                ' error while generating IL
                If emittedBody Is Nothing Then
                    Exit For
                End If
T
TomasMatousek 已提交
867

868 869
                _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody)
            Next
T
TomasMatousek 已提交
870 871
        End Sub

872
        Private Sub CompileSynthesizedMethods(additionalTypes As ImmutableArray(Of NamedTypeSymbol))
873 874
            Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing)

875
            Dim compilationState As New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing)
876
            For Each additionalType In additionalTypes
T
TomasMatousek 已提交
877 878
                Dim methodOrdinal As Integer = 0

879 880 881 882
                For Each method In additionalType.GetMethodsToEmit()
                    Dim diagnosticsThisMethod = DiagnosticBag.GetInstance()

                    Dim boundBody = method.GetBoundMethodBody(diagnosticsThisMethod)
A
acasey 已提交
883

A
acasey 已提交
884 885 886
                    Dim emittedBody As MethodBody = Nothing

                    If Not diagnosticsThisMethod.HasAnyErrors Then
887
                        Dim lazyVariableSlotAllocator As VariableSlotAllocator = Nothing
888 889
                        Dim statemachineTypeOpt As StateMachineTypeSymbol = Nothing

890 891
                        Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance()
                        Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance()
T
TomasMatousek 已提交
892 893
                        Dim delegateRelaxationIdDispenser = 0

894
                        Dim rewrittenBody = Rewriter.LowerBodyOrInitializer(
895
                            method,
T
TomasMatousek 已提交
896
                            methodOrdinal,
897
                            boundBody,
898 899 900
                            previousSubmissionFields:=Nothing,
                            compilationState:=compilationState,
                            diagnostics:=diagnosticsThisMethod,
901
                            lazyVariableSlotAllocator:=lazyVariableSlotAllocator,
902 903
                            lambdaDebugInfoBuilder:=lambdaDebugInfoBuilder,
                            closureDebugInfoBuilder:=closureDebugInfoBuilder,
T
TomasMatousek 已提交
904 905
                            delegateRelaxationIdDispenser:=delegateRelaxationIdDispenser,
                            stateMachineTypeOpt:=statemachineTypeOpt,
906
                            allowOmissionOfConditionalCalls:=_moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls,
907
                            isBodySynthesized:=True)
908 909

                        If Not diagnosticsThisMethod.HasAnyErrors Then
910 911
                            ' Synthesized methods have no ordinal stored in custom debug information
                            ' (only user-defined methods have ordinals).
912
                            emittedBody = GenerateMethodBody(_moduleBeingBuiltOpt,
913
                                                             method,
914
                                                             MethodDebugId.UndefinedOrdinal,
915
                                                             rewrittenBody,
916 917
                                                             lambdaDebugInfoBuilder.ToImmutable(),
                                                             closureDebugInfoBuilder.ToImmutable(),
918
                                                             statemachineTypeOpt,
919
                                                             lazyVariableSlotAllocator,
920
                                                             debugDocumentProvider:=Nothing,
921
                                                             diagnostics:=diagnosticsThisMethod,
T
TomasMatousek 已提交
922
                                                             generateDebugInfo:=False)
923
                        End If
924 925 926

                        lambdaDebugInfoBuilder.Free()
                        closureDebugInfoBuilder.Free()
A
acasey 已提交
927
                    End If
928 929 930 931 932 933 934 935 936

                    _diagnostics.AddRange(diagnosticsThisMethod)
                    diagnosticsThisMethod.Free()

                    ' error while generating IL
                    If emittedBody Is Nothing Then
                        Exit For
                    End If

937
                    _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody)
T
TomasMatousek 已提交
938
                    methodOrdinal += 1
939 940 941 942 943 944 945 946 947 948
                Next
            Next

            If Not _diagnostics.HasAnyErrors() Then
                CompileSynthesizedMethods(compilationState)
            End If

            compilationState.Free()
        End Sub

T
TomasMatousek 已提交
949
        Private Sub CompileSynthesizedMethods(compilationState As TypeCompilationState)
950
            Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing)
T
TomasMatousek 已提交
951

952 953 954
            If Not compilationState.HasSynthesizedMethods Then
                Return
            End If
T
TomasMatousek 已提交
955

956
            For Each methodWithBody In compilationState.SynthesizedMethods
A
AlekseyTs 已提交
957 958 959 960 961 962
                If Not methodWithBody.Body.HasErrors Then
                    Dim method = methodWithBody.Method
                    Dim diagnosticsThisMethod As DiagnosticBag = DiagnosticBag.GetInstance()

                    Dim emittedBody = GenerateMethodBody(_moduleBeingBuiltOpt,
                                                         method,
963 964 965 966
                                                         methodOrdinal:=MethodDebugId.UndefinedOrdinal,
                                                         block:=methodWithBody.Body,
                                                         lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
                                                         closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
A
AlekseyTs 已提交
967 968 969 970
                                                         stateMachineTypeOpt:=Nothing,
                                                         variableSlotAllocatorOpt:=Nothing,
                                                         debugDocumentProvider:=_debugDocumentProvider,
                                                         diagnostics:=diagnosticsThisMethod,
T
TomasMatousek 已提交
971
                                                         generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo)
T
TomasMatousek 已提交
972

A
AlekseyTs 已提交
973 974
                    _diagnostics.AddRange(diagnosticsThisMethod)
                    diagnosticsThisMethod.Free()
T
TomasMatousek 已提交
975

A
AlekseyTs 已提交
976 977 978 979
                    ' error while generating IL
                    If emittedBody Is Nothing Then
                        Exit For
                    End If
980

A
AlekseyTs 已提交
981
                    _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody)
982 983
                End If
            Next
T
TomasMatousek 已提交
984 985 986 987 988 989 990 991 992 993 994 995 996 997 998 999 1000 1001 1002 1003 1004 1005 1006 1007 1008 1009 1010 1011 1012 1013 1014 1015 1016 1017 1018 1019 1020 1021 1022 1023 1024 1025 1026 1027 1028 1029 1030 1031 1032 1033 1034 1035 1036 1037 1038 1039 1040 1041 1042 1043 1044 1045 1046 1047 1048 1049 1050 1051 1052 1053 1054 1055 1056 1057 1058 1059 1060 1061 1062 1063 1064 1065 1066 1067 1068 1069 1070 1071 1072 1073 1074 1075 1076 1077 1078 1079 1080 1081 1082 1083 1084 1085 1086 1087 1088 1089 1090 1091 1092 1093 1094 1095 1096 1097 1098 1099 1100 1101 1102 1103 1104 1105
        End Sub

        ''' <summary>
        ''' Detects cycles in constructor invocations based on the 'constructor-calls-constructor' 
        ''' map provided in 'constructorCallMap', reports errors if found.
        ''' 
        ''' NOTE: 'constructorCallMap' is being mutated by this method
        ''' </summary>
        Private Sub DetectAndReportCyclesInConstructorCalls(constructorCallMap As Dictionary(Of MethodSymbol, MethodSymbol), diagnostics As DiagnosticBag)

            Debug.Assert(constructorCallMap.Count > 0)

            Dim constructorsInPath As New Dictionary(Of MethodSymbol, Integer)
            Dim constructorsPath = ArrayBuilder(Of MethodSymbol).GetInstance()

            Dim currentMethod As MethodSymbol = constructorCallMap.Keys.First()

            ' Cycle constructor calls
            Do
                '  Where this constructor points to?
                Dim currentMethodPointTo As MethodSymbol = Nothing
                If Not constructorCallMap.TryGetValue(currentMethod, currentMethodPointTo) Then

                    ' We didn't find anything, which means we maybe already processed 'currentMethod'
                    ' or it does not reference another constructor of this type, or there is somethig wrong with it;

                    ' In any case we can restart iteration, none of the constructors in path are part of cycles

                Else
                    ' 'currentMethod' references another constructor; we may safely remove 'currentMethod' 
                    ' from 'constructorCallMap' because we won't need to process it again
                    constructorCallMap.Remove(currentMethod)

                    constructorsInPath.Add(currentMethod, constructorsPath.Count)
                    constructorsPath.Add(currentMethod)

                    Dim foundAt As Integer
                    If constructorsInPath.TryGetValue(currentMethodPointTo, foundAt) Then

                        ' We found a cycle which starts at 'foundAt' and goes to the end of constructorsPath
                        constructorsPath.Add(currentMethodPointTo)
                        ReportConstructorCycles(foundAt, constructorsPath.Count - 1, constructorsPath, diagnostics)

                        ' We can restart iteration, none of the constructors 
                        ' in path may be part of other cycles

                    Else
                        ' No cycles so far, just move to the next constructor
                        currentMethod = currentMethodPointTo
                        Continue Do
                    End If

                End If

                ' Restart iteration 
                constructorsInPath.Clear()
                constructorsPath.Clear()

                If constructorCallMap.Count = 0 Then
                    ' Nothing left
                    constructorsPath.Free()
                    Exit Sub
                End If

                currentMethod = constructorCallMap.Keys.First()
            Loop

            Throw ExceptionUtilities.Unreachable

        End Sub

        ''' <summary> All the constructors in the cycle will be reported </summary>
        Private Sub ReportConstructorCycles(startsAt As Integer, endsAt As Integer,
                                            path As ArrayBuilder(Of MethodSymbol),
                                            diagnostics As DiagnosticBag)

            ' Cycle is: constructorsCycle(startsAt) --> 
            '               constructorsCycle(startsAt + 1) --> 
            '                   ....
            '                       constructorsCycle(endsAt) = constructorsCycle(startsAt)
            '
            ' In case the constructor constructorsCycle(startsAt) calls itself, startsAt = endsAt + 1

            Debug.Assert(startsAt <= endsAt)
            Debug.Assert(path(startsAt).Equals(path(endsAt)))

            '  Generate cycle info
            Dim diagnosticInfos = ArrayBuilder(Of DiagnosticInfo).GetInstance()
            Dim referencingMethod As MethodSymbol = path(startsAt)
            For i = startsAt + 1 To endsAt
                Dim referencedMethod As MethodSymbol = path(i)
                diagnosticInfos.Add(ErrorFactory.ErrorInfo(ERRID.ERR_SubNewCycle2, referencingMethod, referencedMethod))
                referencingMethod = referencedMethod
            Next

            '  Report Errors for all constructors in the cycle
            For i = startsAt To endsAt - 1
                referencingMethod = path(i)

                '  Report an error
                diagnostics.Add(
                    New VBDiagnostic(ErrorFactory.ErrorInfo(ERRID.ERR_SubNewCycle1, referencingMethod,
                                                          New CompoundDiagnosticInfo(diagnosticInfos.ToArray())),
                                   referencingMethod.Locations(0)))

                '  Rotate 'diagnosticInfos' for the next constructor
                If diagnosticInfos.Count > 1 Then
                    Dim diagnostic = diagnosticInfos(0)
                    diagnosticInfos.RemoveAt(0)
                    diagnosticInfos.Add(diagnostic)
                End If
            Next

            diagnosticInfos.Free()
        End Sub

        Friend Shared Function CanBindMethod(method As MethodSymbol) As Boolean
            If method.IsExternalMethod OrElse method.IsMustOverride Then
                Return False
            End If

            ' Synthesized struct constructors are not emitted.
1106
            If method.IsDefaultValueTypeConstructor() Then
T
TomasMatousek 已提交
1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124 1125 1126 1127 1128 1129 1130 1131 1132 1133 1134 1135
                Return False
            End If

            If method.IsPartialWithoutImplementation Then
                ' Exclude partial methods without implementation
                Return False
            End If

            If Not method.IsImplicitlyDeclared Then
                ' Only compile the method if the method has a body.
                Dim sourceMethod = TryCast(method, SourceMethodSymbol)
                If sourceMethod Is Nothing OrElse sourceMethod.BlockSyntax Is Nothing Then
                    Return False
                End If
            End If

            Return True
        End Function

        ''' <summary>
        ''' Compiles the method.
        ''' </summary>
        ''' <param name="referencedConstructor">
        ''' If the method being compiled is a constructor, CompileMethod returns in this parameter 
        ''' the symbol of the constructor called from the one being compiled either explicitly or implicitly. 
        ''' For structure constructors calling parameterless constructor returns the synthesized constructor symbol.
        ''' </param>
        Private Sub CompileMethod(
            method As MethodSymbol,
T
TomasMatousek 已提交
1136 1137 1138
            methodOrdinal As Integer,
            ByRef withEventPropertyIdDispenser As Integer,
            ByRef delegateRelaxationIdDispenser As Integer,
T
TomasMatousek 已提交
1139 1140 1141 1142 1143 1144 1145
            filter As Predicate(Of Symbol),
            compilationState As TypeCompilationState,
            processedInitializers As Binder.ProcessedFieldOrPropertyInitializers,
            containingTypeBinder As Binder,
            previousSubmissionFields As SynthesizedSubmissionFields,
            Optional ByRef referencedConstructor As MethodSymbol = Nothing
        )
1146 1147 1148 1149
            '' TODO: add filtering as follows
            'If filter IsNot Nothing AndAlso Not filter(method) Then
            '    Return
            'End If
T
TomasMatousek 已提交
1150 1151 1152 1153 1154 1155 1156 1157 1158 1159 1160 1161 1162

            _cancellationToken.ThrowIfCancellationRequested()

            Dim sourceMethod = TryCast(method, SourceMethodSymbol)
            'get cached diagnostics if not building and we have 'em
            If Not DoEmitPhase AndAlso (sourceMethod IsNot Nothing) Then
                Dim cachedDiagnostics = sourceMethod.Diagnostics
                If Not cachedDiagnostics.IsDefault Then
                    Me._diagnostics.AddRange(cachedDiagnostics)
                    Return
                End If
            End If

1163 1164 1165 1166 1167 1168 1169 1170
            If Not CanBindMethod(method) Then
                If sourceMethod IsNot Nothing AndAlso sourceMethod.SetDiagnostics(ImmutableArray(Of Diagnostic).Empty) Then
                    sourceMethod.DeclaringCompilation.SymbolDeclaredEvent(method)
                End If

                Return
            End If

T
TomasMatousek 已提交
1171 1172 1173 1174 1175 1176 1177 1178 1179 1180 1181 1182 1183 1184 1185 1186 1187 1188 1189 1190 1191 1192
            ' In order to avoid generating code for methods with errors, we create a diagnostic bag just for this method.
            Dim diagsForCurrentMethod As DiagnosticBag = DiagnosticBag.GetInstance()

            Dim methodBinderOpt As Binder = Nothing
            Dim injectConstructorCall As Boolean
            Dim block = BindAndAnalyzeMethodBody(method, compilationState, diagsForCurrentMethod, containingTypeBinder, referencedConstructor, injectConstructorCall, methodBinderOpt)

            If method.MethodKind = MethodKind.Constructor OrElse method.MethodKind = MethodKind.SharedConstructor Then
                ' If this is a constructor and we do have initializers they need to be flow-analyzed for 
                ' warnings like 'Function '??' doesn't return a value on all code paths' or unreferenced variables. 

                ' Because if there are any initializers they will eventually get to one or more constructors
                ' it does not matter which constructor is being used as a method symbol for their analysis, 
                ' so we don't perform any analysis of which constructor symbol to pass to EnsureInitializersAnalyzed,
                ' but call this method for on all constructor symbols making sure instance/static initializers 
                ' are analyzed on the first instance/static constructor processed
                processedInitializers.EnsureInitializersAnalyzed(method, diagsForCurrentMethod)
            End If

            Dim hasErrors = _hasDeclarationErrors OrElse diagsForCurrentMethod.HasAnyErrors() OrElse processedInitializers.HasAnyErrors OrElse block.HasErrors
            SetGlobalErrorIfTrue(hasErrors)

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214
            If sourceMethod IsNot Nothing AndAlso sourceMethod.SetDiagnostics(diagsForCurrentMethod.ToReadOnly()) Then
                Dim compilation = compilationState.Compilation
                If compilation.EventQueue IsNot Nothing Then
                    If block Is Nothing Then
                        compilation.SymbolDeclaredEvent(sourceMethod)
                    Else
                        'create a compilation event that caches the already-computed bound tree
                        Dim lazySemanticModel = New Lazy(Of SemanticModel)(
                            Function()
                                Dim syntax = block.Syntax
                                Dim semanticModel = CType(compilation.GetSemanticModel(syntax.SyntaxTree), SyntaxTreeSemanticModel)
                                Dim memberModel = CType(semanticModel.GetMemberSemanticModel(syntax), MethodBodySemanticModel)
                                If memberModel IsNot Nothing Then
                                    memberModel.CacheBoundNodes(block, syntax)
                                End If
                                Return semanticModel
                            End Function)
                        compilation.EventQueue.Enqueue(New SymbolDeclaredCompilationEvent(compilation, method, lazySemanticModel))
                    End If
                End If
            End If

T
TomasMatousek 已提交
1215
            If Not DoEmitPhase AndAlso sourceMethod IsNot Nothing Then
1216
                _diagnostics.AddRange(sourceMethod.Diagnostics)
T
TomasMatousek 已提交
1217 1218 1219 1220 1221
                Return
            End If

            If DoEmitPhase AndAlso Not hasErrors Then
                LowerAndEmitMethod(method,
T
TomasMatousek 已提交
1222
                                   methodOrdinal,
T
TomasMatousek 已提交
1223 1224 1225 1226 1227 1228 1229
                                   block,
                                   If(methodBinderOpt, containingTypeBinder),
                                   compilationState,
                                   diagsForCurrentMethod,
                                   processedInitializers,
                                   previousSubmissionFields,
                                   If(injectConstructorCall, referencedConstructor, Nothing),
T
TomasMatousek 已提交
1230
                                   delegateRelaxationIdDispenser)
T
TomasMatousek 已提交
1231 1232 1233

                ' if method happen to handle events of a base WithEvents, ensure that we have an overriding WithEvents property
                Dim handledEvents = method.HandledEvents
1234
                If Not handledEvents.IsEmpty Then
T
TomasMatousek 已提交
1235
                    CreateSyntheticWithEventOverridesIfNeeded(handledEvents,
T
TomasMatousek 已提交
1236 1237
                                                              delegateRelaxationIdDispenser,
                                                              withEventPropertyIdDispenser,
T
TomasMatousek 已提交
1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253 1254 1255
                                                              compilationState,
                                                              containingTypeBinder,
                                                              diagsForCurrentMethod,
                                                              previousSubmissionFields)
                End If
            End If

            ' Add the generated diagnostics into the full diagnostic bag.
            _diagnostics.AddRange(diagsForCurrentMethod)
            diagsForCurrentMethod.Free()
        End Sub

        ''' <summary> 
        ''' If any of the "Handles" in the list have synthetic WithEvent override
        ''' as a container, then this method will (if not done already) inject 
        ''' property/accessors symbol into the emit module and assign bodies to the accessors.
        ''' </summary>
        Private Sub CreateSyntheticWithEventOverridesIfNeeded(handledEvents As ImmutableArray(Of HandledEvent),
T
TomasMatousek 已提交
1256 1257
                                                              ByRef delegateRelaxationIdDispenser As Integer,
                                                              ByRef withEventPropertyIdDispenser As Integer,
1258 1259
                                                              compilationState As TypeCompilationState,
                                                              containingTypeBinder As Binder,
T
TomasMatousek 已提交
1260
                                                              diagnostics As DiagnosticBag,
1261
                                                              previousSubmissionFields As SynthesizedSubmissionFields)
T
TomasMatousek 已提交
1262

1263 1264
            Debug.Assert(_moduleBeingBuiltOpt Is Nothing OrElse _moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls)

1265 1266 1267
            Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance()
            Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance()

T
TomasMatousek 已提交
1268
            For Each handledEvent In handledEvents
T
TomasMatousek 已提交
1269 1270
                If handledEvent.HandlesKind <> HandledEventKind.WithEvents Then
                    Continue For
T
TomasMatousek 已提交
1271
                End If
T
TomasMatousek 已提交
1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282 1283 1284 1285 1286 1287 1288 1289 1290 1291 1292 1293 1294 1295 1296 1297 1298 1299 1300 1301 1302 1303 1304 1305

                Dim prop = TryCast(handledEvent.hookupMethod.AssociatedSymbol, SynthesizedOverridingWithEventsProperty)
                If prop Is Nothing Then
                    Continue For
                End If

                Dim getter = prop.GetMethod
                If compilationState.HasMethodWrapper(getter) Then
                    Continue For
                End If

                Dim setter = prop.SetMethod
                Dim containingType = prop.ContainingType
                Debug.Assert(containingType Is getter.ContainingType AndAlso containingType Is setter.ContainingType)

                Dim getterBody = getter.GetBoundMethodBody(diagnostics, containingTypeBinder)

                ' no need to rewrite getter, they are pretty simple and 
                ' are already in a lowered form.
                compilationState.AddMethodWrapper(getter, getter, getterBody)
                _moduleBeingBuiltOpt.AddSynthesizedDefinition(containingType, getter)

                ' setter needs to rewritten as it may require lambda conversions
                Dim setterBody = setter.GetBoundMethodBody(diagnostics, containingTypeBinder)

                Dim lambdaOrdinalDispenser = 0
                Dim scopeOrdinalDispenser = 0

                setterBody = Rewriter.LowerBodyOrInitializer(setter,
                                                             withEventPropertyIdDispenser,
                                                             setterBody,
                                                             previousSubmissionFields,
                                                             compilationState,
                                                             diagnostics,
1306
                                                             lazyVariableSlotAllocator:=Nothing,
1307 1308
                                                             lambdaDebugInfoBuilder:=lambdaDebugInfoBuilder,
                                                             closureDebugInfoBuilder:=closureDebugInfoBuilder,
T
TomasMatousek 已提交
1309 1310 1311 1312 1313 1314
                                                             delegateRelaxationIdDispenser:=delegateRelaxationIdDispenser,
                                                             stateMachineTypeOpt:=Nothing,
                                                             allowOmissionOfConditionalCalls:=True,
                                                             isBodySynthesized:=True)

                ' There shall be no lambdas in the synthesized accessor but delegate relaxation conversions:
1315 1316
                Debug.Assert(Not lambdaDebugInfoBuilder.Any())
                Debug.Assert(Not closureDebugInfoBuilder.Any())
T
TomasMatousek 已提交
1317 1318 1319 1320 1321 1322 1323

                compilationState.AddMethodWrapper(setter, setter, setterBody)
                _moduleBeingBuiltOpt.AddSynthesizedDefinition(containingType, setter)

                ' add property too
                _moduleBeingBuiltOpt.AddSynthesizedDefinition(containingType, prop)
                withEventPropertyIdDispenser += 1
T
TomasMatousek 已提交
1324
            Next
1325 1326 1327

            lambdaDebugInfoBuilder.Free()
            closureDebugInfoBuilder.Free()
T
TomasMatousek 已提交
1328 1329 1330 1331 1332 1333 1334 1335 1336 1337 1338 1339 1340 1341 1342 1343 1344 1345 1346 1347 1348 1349 1350 1351
        End Sub

        ''' <summary> 
        ''' Assuming the statement is a constructor call wrapped in bound expression 
        ''' statement, get the method symbol being called 
        ''' </summary>
        Private Shared Function TryGetMethodCalledInBoundExpressionStatement(stmt As BoundExpressionStatement) As MethodSymbol

            '  No statement provided or has errors
            If stmt Is Nothing OrElse stmt.HasErrors Then
                Return Nothing
            End If

            '  Statement is not a call
            Dim expression As BoundExpression = stmt.Expression
            If expression.Kind <> BoundKind.Call Then
                Return Nothing
            End If

            Return DirectCast(expression, BoundCall).Method
        End Function

        Private Sub LowerAndEmitMethod(
            method As MethodSymbol,
T
TomasMatousek 已提交
1352
            methodOrdinal As Integer,
T
TomasMatousek 已提交
1353 1354 1355 1356 1357 1358 1359
            block As BoundBlock,
            binderOpt As Binder,
            compilationState As TypeCompilationState,
            diagsForCurrentMethod As DiagnosticBag,
            processedInitializers As Binder.ProcessedFieldOrPropertyInitializers,
            previousSubmissionFields As SynthesizedSubmissionFields,
            constructorToInject As MethodSymbol,
T
TomasMatousek 已提交
1360
            ByRef delegateRelaxationIdDispenser As Integer
T
TomasMatousek 已提交
1361 1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372 1373 1374 1375 1376 1377
        )
            Dim constructorInitializerOpt = If(constructorToInject Is Nothing,
                                               Nothing,
                                               BindDefaultConstructorInitializer(method, constructorToInject, diagsForCurrentMethod, binderOpt))

            If diagsForCurrentMethod.HasAnyErrors Then
                Return
            End If

            If constructorInitializerOpt IsNot Nothing AndAlso constructorInitializerOpt.HasErrors Then
                Return
            End If

            Dim body As BoundBlock
            If method.MethodKind = MethodKind.Constructor OrElse method.MethodKind = MethodKind.SharedConstructor Then
                ' Turns field initializers into bound assignment statements and top-level script statements into bound statements in the beginning the body. 
                ' For submission constructor, the body only includes bound initializers and a return statement. The rest is filled in later.
1378 1379 1380
                body = InitializerRewriter.BuildConstructorBody(
                    compilationState,
                    method,
T
TomasMatousek 已提交
1381
                    If(method.IsSubmissionConstructor, Nothing, constructorInitializerOpt), processedInitializers, block)
T
TomasMatousek 已提交
1382 1383 1384 1385
            Else
                body = block
            End If

1386
            Dim diagnostics As DiagnosticBag = diagsForCurrentMethod
T
TomasMatousek 已提交
1387

1388 1389
            If method.IsImplicitlyDeclared AndAlso
               method.AssociatedSymbol IsNot Nothing AndAlso
T
TomasMatousek 已提交
1390
               method.AssociatedSymbol.IsMyGroupCollectionProperty Then
1391
                diagnostics = DiagnosticBag.GetInstance()
T
TomasMatousek 已提交
1392 1393
            End If

1394
            Dim lazyVariableSlotAllocator As VariableSlotAllocator = Nothing
1395
            Dim stateMachineTypeOpt As StateMachineTypeSymbol = Nothing
1396
            Dim allowOmissionOfConditionalCalls = _moduleBeingBuiltOpt Is Nothing OrElse _moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls
1397 1398
            Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance()
            Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance()
T
TomasMatousek 已提交
1399

1400
            body = Rewriter.LowerBodyOrInitializer(method,
T
TomasMatousek 已提交
1401
                                                   methodOrdinal,
1402 1403 1404 1405
                                                   body,
                                                   previousSubmissionFields,
                                                   compilationState,
                                                   diagnostics,
1406
                                                   lazyVariableSlotAllocator,
1407 1408
                                                   lambdaDebugInfoBuilder,
                                                   closureDebugInfoBuilder,
T
TomasMatousek 已提交
1409
                                                   delegateRelaxationIdDispenser,
1410
                                                   stateMachineTypeOpt,                                                   
1411
                                                   allowOmissionOfConditionalCalls,
1412
                                                   isBodySynthesized:=False)
T
TomasMatousek 已提交
1413 1414 1415 1416

            ' The submission initializer has to be constructed after the body is rewritten (all previous submission references are visited):
            Dim submissionInitialization As ImmutableArray(Of BoundStatement)
            If method.IsSubmissionConstructor Then
1417
                submissionInitialization = SynthesizedSubmissionConstructorSymbol.MakeSubmissionInitialization(block.Syntax, method, previousSubmissionFields, _compilation, diagnostics)
T
TomasMatousek 已提交
1418 1419 1420 1421
            Else
                submissionInitialization = Nothing
            End If

1422
            Dim hasErrors = body.HasErrors OrElse diagsForCurrentMethod.HasAnyErrors OrElse (diagnostics IsNot diagsForCurrentMethod AndAlso diagnostics.HasAnyErrors)
T
TomasMatousek 已提交
1423 1424 1425
            SetGlobalErrorIfTrue(hasErrors)

            ' Actual emitting is only done if we have a module in which to emit and no errors so far.
1426 1427 1428 1429
            If _moduleBeingBuiltOpt Is Nothing OrElse hasErrors Then
                If diagnostics IsNot diagsForCurrentMethod Then
                    DirectCast(method.AssociatedSymbol, SynthesizedMyGroupCollectionPropertySymbol).RelocateDiagnostics(diagnostics, diagsForCurrentMethod)
                    diagnostics.Free()
T
TomasMatousek 已提交
1430 1431 1432 1433 1434 1435 1436 1437 1438 1439 1440 1441 1442 1443 1444 1445 1446
                End If

                Return
            End If

            ' now we have everything we need to build complete submission
            If method.IsSubmissionConstructor Then
                Debug.Assert(previousSubmissionFields IsNot Nothing)

                Dim boundStatements = ArrayBuilder(Of BoundStatement).GetInstance(1 + submissionInitialization.Length + 1)
                boundStatements.Add(constructorInitializerOpt)
                boundStatements.AddRange(submissionInitialization)
                boundStatements.Add(body)
                body = New BoundBlock(body.Syntax, Nothing, ImmutableArray(Of LocalSymbol).Empty, boundStatements.ToImmutableAndFree(), body.HasErrors).MakeCompilerGenerated()
            End If

            ' NOTE: additional check for statement.HasErrors is needed to identify parse errors which didn't get into diagsForCurrentMethod
1447
            Dim methodBody As MethodBody = GenerateMethodBody(_moduleBeingBuiltOpt,
T
TomasMatousek 已提交
1448
                                                              method,
1449
                                                              methodOrdinal,
T
TomasMatousek 已提交
1450
                                                              body,
1451 1452
                                                              lambdaDebugInfoBuilder.ToImmutable(),
                                                              closureDebugInfoBuilder.ToImmutable(),
1453
                                                              stateMachineTypeOpt,
1454
                                                              lazyVariableSlotAllocator,
1455 1456
                                                              _debugDocumentProvider,
                                                              diagnostics,
T
TomasMatousek 已提交
1457
                                                              generateDebugInfo:=_generateDebugInfo AndAlso method.GenerateDebugInfo)
1458 1459 1460 1461

            If diagnostics IsNot diagsForCurrentMethod Then
                DirectCast(method.AssociatedSymbol, SynthesizedMyGroupCollectionPropertySymbol).RelocateDiagnostics(diagnostics, diagsForCurrentMethod)
                diagnostics.Free()
T
TomasMatousek 已提交
1462 1463
            End If

1464
            _moduleBeingBuiltOpt.SetMethodBody(If(method.PartialDefinitionPart, method), methodBody)
1465 1466 1467

            lambdaDebugInfoBuilder.Free()
            closureDebugInfoBuilder.Free()
T
TomasMatousek 已提交
1468 1469
        End Sub

1470
        Friend Shared Function GenerateMethodBody(moduleBuilder As PEModuleBuilder,
T
TomasMatousek 已提交
1471
                                                  method As MethodSymbol,
1472
                                                  methodOrdinal As Integer,
T
TomasMatousek 已提交
1473
                                                  block As BoundStatement,
1474 1475
                                                  lambdaDebugInfo As ImmutableArray(Of LambdaDebugInfo),
                                                  closureDebugInfo As ImmutableArray(Of ClosureDebugInfo),
1476
                                                  stateMachineTypeOpt As StateMachineTypeSymbol,
1477
                                                  variableSlotAllocatorOpt As VariableSlotAllocator,
T
TomasMatousek 已提交
1478
                                                  debugDocumentProvider As DebugDocumentProvider,
1479
                                                  diagnostics As DiagnosticBag,
T
TomasMatousek 已提交
1480
                                                  generateDebugInfo As Boolean) As MethodBody
T
TomasMatousek 已提交
1481

1482
            Dim compilation = moduleBuilder.Compilation
T
TomasMatousek 已提交
1483
            Dim localSlotManager = New localSlotManager(variableSlotAllocatorOpt)
1484 1485 1486 1487 1488 1489 1490
            Dim optimizations = compilation.Options.OptimizationLevel

            If method.IsEmbedded Then
                optimizations = OptimizationLevel.Release
            End If

            Dim builder As ILBuilder = New ILBuilder(moduleBuilder, localSlotManager, optimizations)
T
TomasMatousek 已提交
1491 1492

            Try
1493
                Debug.Assert(Not diagnostics.HasAnyErrors)
T
TomasMatousek 已提交
1494 1495

                Dim asyncDebugInfo As Cci.AsyncMethodBodyDebugInfo = Nothing
T
TomasMatousek 已提交
1496
                Dim codeGen = New codeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, generateDebugInfo)
1497 1498 1499

                ' We need to save additional debugging information for MoveNext of an async state machine.
                Dim stateMachineMethod = TryCast(method, SynthesizedStateMachineMethod)
W
wochae 已提交
1500 1501 1502

                Dim isStateMachineMoveNextMethod As Boolean = stateMachineMethod IsNot Nothing AndAlso method.Name = WellKnownMemberNames.MoveNextMethodName
                If isStateMachineMoveNextMethod AndAlso stateMachineMethod.StateMachineType.KickoffMethod.IsAsync Then
T
TomasMatousek 已提交
1503 1504 1505 1506 1507

                    Dim asyncCatchHandlerOffset As Integer = -1
                    Dim asyncYieldPoints As ImmutableArray(Of Integer) = Nothing
                    Dim asyncResumePoints As ImmutableArray(Of Integer) = Nothing

1508
                    codeGen.Generate(asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints)
T
TomasMatousek 已提交
1509

1510
                    Dim kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod
T
TomasMatousek 已提交
1511

1512 1513
                    ' In VB async method may be partial. Debug info needs to be associated with the emitted definition, 
                    ' but the kickoff method is the method implementation (the part with body).
1514 1515 1516 1517 1518 1519 1520 1521 1522 1523 1524

                    ' The exception handler IL offset is used by the debugger to treat exceptions caught by the marked catch block as "user unhandled".
                    ' This is important for async void because async void exceptions generally result in the process being terminated,
                    ' but without anything useful on the call stack. Async Task methods on the other hand return exceptions as the result of the Task.
                    ' So it is undesirable to consider these exceptions "user unhandled" since there may well be user code that is awaiting the task.
                    ' This is a heuristic since it's possible that there is no user code awaiting the task.
                    asyncDebugInfo = New Cci.AsyncMethodBodyDebugInfo(
                        If(kickoffMethod.PartialDefinitionPart, kickoffMethod),
                        If(kickoffMethod.IsSub, asyncCatchHandlerOffset, -1),
                        asyncYieldPoints,
                        asyncResumePoints)
1525 1526
                Else
                    codeGen.Generate()
T
TomasMatousek 已提交
1527 1528
                End If

1529
                If diagnostics.HasAnyErrors() Then
T
TomasMatousek 已提交
1530 1531 1532 1533
                    Return Nothing
                End If

                ' We will only save the IL builders when running tests.
1534 1535
                If moduleBuilder.SaveTestData Then
                    moduleBuilder.SetMethodTestData(method, builder.GetSnapshot())
T
TomasMatousek 已提交
1536 1537
                End If

W
wochae 已提交
1538 1539 1540 1541 1542 1543 1544
                Dim stateMachineHoistedLocalSlots As ImmutableArray(Of EncHoistedLocalInfo) = Nothing
                Dim stateMachineAwaiterSlots As ImmutableArray(Of Cci.ITypeReference) = Nothing
                If optimizations = OptimizationLevel.Debug AndAlso stateMachineTypeOpt IsNot Nothing Then
                    Debug.Assert(method.IsAsync OrElse method.IsIterator)
                    GetStateMachineSlotDebugInfo(moduleBuilder.GetSynthesizedFields(stateMachineTypeOpt), stateMachineHoistedLocalSlots, stateMachineAwaiterSlots)
                End If

T
TomasMatousek 已提交
1545 1546
                Dim namespaceScopes = If(generateDebugInfo, moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree), Nothing)

T
TomasMatousek 已提交
1547 1548 1549 1550 1551 1552 1553 1554 1555 1556 1557 1558 1559 1560 1561 1562 1563 1564 1565 1566 1567
                ' edgeInclusive must be true as that is what VB EE expects.

                '<PdbUtil.cpp>
                'HRESULT()
                'PdbUtil::IsScopeInOffset(
                '    _In_ ISymUnmanagedScope* pScope,
                '    _In_ DWORD offset,
                '    _Out_ bool* inOffset)
                '{
                '    VerifyInPtr(pScope);
                '    VerifyOutPtr(inOffset);

                '    HRESULT hr;
                '    ULONG32 start, end;

                '    IfFailGo( pScope->GetStartOffset(&start) );
                '    IfFailGo( pScope->GetEndOffset(&end) );
                '    *inOffset = (end >= offset) && (offset >= start);      <====  HERE
                'Error:
                '    return hr;
                '}
1568
                Dim localScopes = builder.GetAllScopes()
T
TomasMatousek 已提交
1569 1570 1571 1572

                Return New MethodBody(builder.RealizedIL,
                                      builder.MaxStack,
                                      If(method.PartialDefinitionPart, method),
1573
                                      methodOrdinal,
T
TomasMatousek 已提交
1574 1575 1576 1577
                                      builder.LocalSlotManager.LocalsInOrder(),
                                      builder.RealizedSequencePoints,
                                      debugDocumentProvider,
                                      builder.RealizedExceptionHandlers,
T
TomasMatousek 已提交
1578
                                      localScopes,
1579
                                      hasDynamicLocalVariables:=False,
T
TomasMatousek 已提交
1580
                                      importScopeOpt:=namespaceScopes,
1581 1582
                                      lambdaDebugInfo:=lambdaDebugInfo,
                                      closureDebugInfo:=closureDebugInfo,
1583
                                      stateMachineTypeNameOpt:=stateMachineTypeOpt?.Name, ' TODO: remove or update AddedOrChangedMethodInfo
1584
                                      stateMachineHoistedLocalScopes:=Nothing,
W
wochae 已提交
1585 1586
                                      stateMachineHoistedLocalSlots:=stateMachineHoistedLocalSlots,
                                      stateMachineAwaiterSlots:=stateMachineAwaiterSlots,
T
TomasMatousek 已提交
1587 1588 1589 1590 1591 1592 1593
                                      asyncMethodDebugInfo:=asyncDebugInfo)
            Finally
                ' Free resources used by the basic blocks in the builder.
                builder.FreeBasicBlocks()
            End Try
        End Function

W
wochae 已提交
1594 1595 1596 1597 1598 1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611 1612 1613 1614 1615 1616 1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627
        Private Shared Sub GetStateMachineSlotDebugInfo(fieldDefs As IEnumerable(Of Cci.IFieldDefinition),
                                                        ByRef hoistedVariableSlots As ImmutableArray(Of EncHoistedLocalInfo),
                                                        ByRef awaiterSlots As ImmutableArray(Of Cci.ITypeReference))

            Dim hoistedVariables = ArrayBuilder(Of EncHoistedLocalInfo).GetInstance()
            Dim awaiters = ArrayBuilder(Of Cci.ITypeReference).GetInstance()

            For Each field As StateMachineFieldSymbol In fieldDefs
                Dim index = field.SlotIndex

                If field.SlotDebugInfo.SynthesizedKind = SynthesizedLocalKind.AwaiterField Then
                    Debug.Assert(index >= 0)

                    While index >= awaiters.Count
                        awaiters.Add(Nothing)
                    End While

                    awaiters(index) = TryCast(field.Type, Cci.ITypeReference)
                ElseIf Not field.SlotDebugInfo.Id.IsNone Then
                    Debug.Assert(index >= 0 AndAlso field.SlotDebugInfo.SynthesizedKind.IsLongLived())

                    While index >= hoistedVariables.Count
                        ' Empty slots may be present if variables were deleted during EnC.
                        hoistedVariables.Add(New EncHoistedLocalInfo())
                    End While

                    hoistedVariables(index) = New EncHoistedLocalInfo(field.SlotDebugInfo, TryCast(field.Type, Cci.ITypeReference))
                End If
            Next

            hoistedVariableSlots = hoistedVariables.ToImmutableAndFree()
            awaiterSlots = awaiters.ToImmutableAndFree()
        End Sub

T
TomasMatousek 已提交
1628 1629 1630 1631 1632 1633 1634 1635 1636 1637 1638 1639 1640 1641 1642 1643 1644 1645 1646
        Friend Shared Function BindAndAnalyzeMethodBody(method As MethodSymbol,
                                                       compilationState As TypeCompilationState,
                                                       diagnostics As DiagnosticBag,
                                                       containingTypeBinder As Binder,
                                                       ByRef referencedConstructor As MethodSymbol,
                                                       ByRef injectDefaultConstructorCall As Boolean,
                                                       ByRef methodBodyBinder As Binder) As BoundBlock

            referencedConstructor = Nothing
            injectDefaultConstructorCall = False
            methodBodyBinder = Nothing

            Dim body = method.GetBoundMethodBody(diagnostics, methodBodyBinder)
            Debug.Assert(body IsNot Nothing)

            Analyzer.AnalyzeMethodBody(method, body, diagnostics)
            DiagnosticsPass.IssueDiagnostics(body, diagnostics, method)

            Debug.Assert(method.IsFromCompilation(compilationState.Compilation))
1647
            If Not method.IsShared AndAlso compilationState.InitializeComponentOpt IsNot Nothing AndAlso
T
TomasMatousek 已提交
1648 1649 1650 1651 1652 1653 1654
               Not method.IsImplicitlyDeclared Then
                InitializeComponentCallTreeBuilder.CollectCallees(compilationState, method, body)
            End If

            '  Instance constructor should return the referenced constructor in 'referencedConstructor'
            If method.MethodKind = MethodKind.Constructor Then

1655 1656
                ' class constructors must inject call to the base
                injectDefaultConstructorCall = Not method.ContainingType.IsValueType
T
TomasMatousek 已提交
1657 1658 1659 1660 1661 1662 1663 1664 1665 1666 1667 1668 1669 1670 1671 1672 1673 1674 1675 1676 1677 1678 1679 1680 1681 1682 1683 1684 1685 1686 1687 1688 1689 1690 1691 1692 1693 1694 1695 1696 1697 1698 1699 1700 1701 1702 1703 1704 1705 1706 1707 1708 1709 1710 1711 1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724 1725 1726 1727 1728 1729 1730 1731 1732

                ' Try find explicitly called constructor, it should be the first statement in the block
                If body IsNot Nothing AndAlso body.Statements.Length > 0 Then

                    Dim theFirstStatement As BoundStatement = body.Statements(0)

                    '  Must be BoundExpressionStatement/BoundCall
                    If theFirstStatement.HasErrors Then
                        injectDefaultConstructorCall = False

                    ElseIf theFirstStatement.Kind = BoundKind.ExpressionStatement Then

                        Dim referencedMethod As MethodSymbol = TryGetMethodCalledInBoundExpressionStatement(DirectCast(theFirstStatement, BoundExpressionStatement))
                        If referencedMethod IsNot Nothing AndAlso referencedMethod.MethodKind = MethodKind.Constructor Then
                            referencedConstructor = referencedMethod
                            injectDefaultConstructorCall = False
                        End If
                    End If

                End If

                ' If we didn't find explicitly referenced constructor, use implicitly generated call
                If injectDefaultConstructorCall Then

                    ' NOTE: We might generate an error in this call in case there is 
                    '       no parameterless constructor suitable for calling
                    referencedConstructor = FindConstructorToCallByDefault(method, diagnostics, If(methodBodyBinder, containingTypeBinder))
                End If

            End If

            Return body
        End Function

        Private Class InitializeComponentCallTreeBuilder
            Inherits BoundTreeWalker

            Private m_CalledMethods As HashSet(Of MethodSymbol)
            Private ReadOnly m_ContainingType As NamedTypeSymbol

            Private Sub New(containingType As NamedTypeSymbol)
                m_ContainingType = containingType
            End Sub

            Public Shared Sub CollectCallees(compilationState As TypeCompilationState, method As MethodSymbol, block As BoundBlock)
                Dim visitor As New InitializeComponentCallTreeBuilder(method.ContainingType)
                visitor.VisitBlock(block)

                If visitor.m_CalledMethods IsNot Nothing Then
                    compilationState.AddToInitializeComponentCallTree(method, visitor.m_CalledMethods.ToArray().AsImmutableOrNull())
                End If
            End Sub

            Public Overrides Function VisitCall(node As BoundCall) As BoundNode
                If node.ReceiverOpt IsNot Nothing AndAlso
                   (node.ReceiverOpt.Kind = BoundKind.MeReference OrElse node.ReceiverOpt.Kind = BoundKind.MyClassReference) AndAlso
                   Not node.Method.IsShared AndAlso node.Method.OriginalDefinition.ContainingType Is m_ContainingType Then

                    If m_CalledMethods Is Nothing Then
                        m_CalledMethods = New HashSet(Of MethodSymbol)(ReferenceEqualityComparer.Instance)
                    End If

                    m_CalledMethods.Add(node.Method.OriginalDefinition)
                End If

                Return MyBase.VisitCall(node)
            End Function
        End Class

        ' This method may force completion of attributes to calculate if a symbol is Obsolete. Since this method is only called during
        ' lowering of default constructors, this should not cause any cycles.
        Private Shared Function FindConstructorToCallByDefault(constructor As MethodSymbol, diagnostics As DiagnosticBag, Optional binderForAccessibilityCheckOpt As Binder = Nothing) As MethodSymbol
            Debug.Assert(constructor IsNot Nothing)
            Debug.Assert(constructor.MethodKind = MethodKind.Constructor)

            Dim containingType As NamedTypeSymbol = constructor.ContainingType
1733
            Debug.Assert(Not containingType.IsValueType)
T
TomasMatousek 已提交
1734 1735 1736 1737 1738 1739 1740 1741 1742

            If containingType.IsSubmissionClass Then
                ' TODO (tomat): report errors if not available
                Dim objectType = constructor.ContainingAssembly.GetSpecialType(SpecialType.System_Object)
                Return objectType.InstanceConstructors.Single()
            End If

            ' If the type is a structure, then invoke the default constructor on the current type.
            ' Otherwise, invoke the default constructor on the base type.
1743
            Dim defaultConstructorType As NamedTypeSymbol = containingType.BaseTypeNoUseSiteDiagnostics
T
TomasMatousek 已提交
1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787 1788 1789 1790 1791 1792 1793 1794 1795 1796 1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840 1841
            If defaultConstructorType Is Nothing OrElse defaultConstructorType.IsErrorType Then
                ' possible if class System.Object in source doesn't have an explicit constructor
                Return Nothing
            End If

            ' If 'binderForAccessibilityCheckOpt' is not specified, containing type must be System.Object
            If binderForAccessibilityCheckOpt Is Nothing Then
                Debug.Assert(defaultConstructorType.IsObjectType)
            End If

            Dim candidate As MethodSymbol = Nothing
            Dim atLeastOneAccessibleCandidateFound As Boolean = False
            For Each m In defaultConstructorType.InstanceConstructors

                ' NOTE: Generic constructors are disallowed, but in case they 
                '       show up because of bad metadata, ignore them.
                If m.IsGenericMethod Then
                    Continue For
                End If

                If binderForAccessibilityCheckOpt IsNot Nothing Then
                    ' Use binder to check accessibility
                    If Not binderForAccessibilityCheckOpt.IsAccessible(m, useSiteDiagnostics:=Nothing, accessThroughType:=containingType) Then
                        Continue For
                    End If
                Else
                    ' If there is no binder, just check if the method is public
                    If m.DeclaredAccessibility <> Accessibility.Public Then
                        Continue For
                    End If

                    ' NOTE: if there is no binder, we will only be able to emit a call to parameterless 
                    '       constructor, but not for constructors with  optional parameters and/or ParamArray
                    If m.ParameterCount <> 0 Then
                        atLeastOneAccessibleCandidateFound = True  ' it is still accessible
                        Continue For
                    End If
                End If

                ' The constructor is accessible
                atLeastOneAccessibleCandidateFound = True

                ' Class constructors can be called with no parameters when the parameters are optional or paramarray.  However, for structures
                ' there cannot be any parameters.
                Dim canBeCalledWithNoParameters = If(containingType.IsReferenceType, m.CanBeCalledWithNoParameters(), m.ParameterCount = 0)

                If canBeCalledWithNoParameters Then

                    If candidate Is Nothing Then
                        candidate = m
                    Else
                        ' Too many candidates, use different errors for synthesized and regular constructors
                        If constructor.IsImplicitlyDeclared Then
                            ' Synthesized constructor
                            diagnostics.Add(New VBDiagnostic(
                                                ErrorFactory.ErrorInfo(ERRID.ERR_NoUniqueConstructorOnBase2, containingType, containingType.BaseTypeNoUseSiteDiagnostics),
                                                containingType.Locations(0)))
                        Else
                            ' Regular constructor
                            diagnostics.Add(New VBDiagnostic(
                                                ErrorFactory.ErrorInfo(ERRID.ERR_RequiredNewCallTooMany2, defaultConstructorType, containingType),
                                                constructor.Locations(0)))
                        End If

                        Return candidate
                    End If

                End If
            Next

            ' Generate an error 
            If candidate Is Nothing Then

                If atLeastOneAccessibleCandidateFound Then

                    ' Different errors for synthesized and regular constructors
                    If constructor.IsImplicitlyDeclared Then
                        ' Synthesized constructor
                        diagnostics.Add(New VBDiagnostic(
                                            ErrorFactory.ErrorInfo(ERRID.ERR_NoConstructorOnBase2, containingType, containingType.BaseTypeNoUseSiteDiagnostics),
                                            containingType.Locations(0)))
                    Else
                        ' Regular constructor
                        diagnostics.Add(New VBDiagnostic(
                                            ErrorFactory.ErrorInfo(ERRID.ERR_RequiredNewCall2, defaultConstructorType, containingType),
                                            constructor.Locations(0)))
                    End If

                Else
                    ' No accessible constructor
                    ' NOTE: Dev10 generates this error in 'Inherits' clause of the type, but it is not available 
                    '       in *all* cases, so changing the error location to containingType's location
                    diagnostics.Add(New VBDiagnostic(
                                        ErrorFactory.ErrorInfo(ERRID.ERR_NoAccessibleConstructorOnBase, containingType.BaseTypeNoUseSiteDiagnostics),
                                        containingType.Locations(0)))
                End If
            End If

1842
            Debug.Assert(candidate <> constructor)
T
TomasMatousek 已提交
1843 1844 1845 1846 1847 1848 1849 1850 1851 1852 1853 1854 1855 1856 1857 1858 1859 1860 1861 1862 1863 1864 1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879 1880 1881 1882 1883 1884 1885 1886 1887 1888 1889 1890 1891 1892 1893 1894 1895 1896 1897 1898 1899 1900 1901

            ' If the candidate is Obsolete then report diagnostics.
            If candidate IsNot Nothing Then
                candidate.ForceCompleteObsoleteAttribute()

                If candidate.ObsoleteState = ThreeState.True Then
                    Dim data = candidate.ObsoleteAttributeData

                    ' If we have a synthesized constructor then give an error saying that there is no non-obsolete
                    ' base constructor. If we have a user-defined constructor then ask the user to explcitly call a
                    ' constructor so that they have a chance to call a non-obsolete base constructor.
                    If constructor.IsImplicitlyDeclared Then
                        ' Synthesized constructor.
                        If String.IsNullOrEmpty(data.Message) Then
                            diagnostics.Add(If(data.IsError, ERRID.ERR_NoNonObsoleteConstructorOnBase3, ERRID.WRN_NoNonObsoleteConstructorOnBase3),
                                            containingType.Locations(0),
                                            containingType,
                                            candidate,
                                            containingType.BaseTypeNoUseSiteDiagnostics)
                        Else
                            diagnostics.Add(If(data.IsError, ERRID.ERR_NoNonObsoleteConstructorOnBase4, ERRID.WRN_NoNonObsoleteConstructorOnBase4),
                                            containingType.Locations(0),
                                            containingType,
                                            candidate,
                                            containingType.BaseTypeNoUseSiteDiagnostics,
                                            data.Message)
                        End If
                    Else
                        ' Regular constructor.
                        If String.IsNullOrEmpty(data.Message) Then
                            diagnostics.Add(If(data.IsError, ERRID.ERR_RequiredNonObsoleteNewCall3, ERRID.WRN_RequiredNonObsoleteNewCall3),
                                            constructor.Locations(0),
                                            candidate,
                                            containingType.BaseTypeNoUseSiteDiagnostics,
                                            containingType)
                        Else
                            diagnostics.Add(If(data.IsError, ERRID.ERR_RequiredNonObsoleteNewCall4, ERRID.WRN_RequiredNonObsoleteNewCall4),
                                            constructor.Locations(0),
                                            candidate,
                                            containingType.BaseTypeNoUseSiteDiagnostics,
                                            containingType,
                                            data.Message)
                        End If
                    End If
                End If
            End If

            Return candidate
        End Function

        Private Shared Function BindDefaultConstructorInitializer(constructor As MethodSymbol,
                                                                  constructorToCall As MethodSymbol,
                                                                  diagnostics As DiagnosticBag,
                                                                  Optional binderOpt As Binder = Nothing) As BoundExpressionStatement

            Dim voidType As NamedTypeSymbol = constructor.ContainingAssembly.GetSpecialType(SpecialType.System_Void)
            ' NOTE: we can ignore use site errors in this place because they should have already be reported 
            '       either in real or synthesized constructor

A
angocke 已提交
1902
            Dim syntaxNode As VisualBasicSyntaxNode = constructor.Syntax
T
TomasMatousek 已提交
1903 1904 1905 1906 1907 1908 1909 1910 1911 1912 1913 1914 1915 1916 1917 1918 1919 1920 1921 1922 1923 1924 1925 1926 1927 1928 1929 1930 1931 1932 1933 1934 1935 1936 1937 1938 1939 1940 1941 1942 1943 1944 1945 1946 1947 1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960 1961 1962 1963 1964

            Dim thisRef As New BoundMeReference(syntaxNode, constructor.ContainingType)
            thisRef.SetWasCompilerGenerated()

            Dim baseInvocation As BoundExpression = Nothing
            If constructorToCall.ParameterCount = 0 Then

                ' If this is parameterless constructor, we can build a call directly
                baseInvocation = New BoundCall(syntaxNode, constructorToCall, Nothing, thisRef, ImmutableArray(Of BoundExpression).Empty, Nothing, voidType)

            Else

                ' Otherwise we should bind invocation exprerssion
                ' Binder must be passed in 'binderOpt'
                Debug.Assert(binderOpt IsNot Nothing)

                '  Build a method group
                Dim group As New BoundMethodGroup(constructor.Syntax,
                                                  typeArgumentsOpt:=Nothing,
                                                  methods:=ImmutableArray.Create(Of MethodSymbol)(constructorToCall),
                                                  resultKind:=LookupResultKind.Good,
                                                  receiverOpt:=thisRef,
                                                  qualificationKind:=QualificationKind.QualifiedViaValue)

                baseInvocation = binderOpt.BindInvocationExpression(constructor.Syntax,
                                                                    Nothing,
                                                                    TypeCharacter.None,
                                                                    group,
                                                                    ImmutableArray(Of BoundExpression).Empty,
                                                                    Nothing,
                                                                    diagnostics,
                                                                    callerInfoOpt:=Nothing,
                                                                    allowConstructorCall:=True)
            End If
            baseInvocation.SetWasCompilerGenerated()

            Dim statement As New BoundExpressionStatement(syntaxNode, baseInvocation)
            statement.SetWasCompilerGenerated()
            Return statement
        End Function

        Friend Shared Function BindDefaultConstructorInitializer(constructor As MethodSymbol, diagnostics As DiagnosticBag) As BoundExpressionStatement
            ' NOTE: this method is only called from outside

            ' NOTE: Because we don't pass a binder into this method, we assume that (a) containing type of 
            '       the constructor is a reference type inherited from System.Object (later is asserted 
            '       in 'FindConstructorToCallByDefault'), and (b) System.Object must have Public parameterless 
            '       constructor (asserted in 'BindDefaultConstructorInitializer')

            ' NOTE: We might generate an error in this call in case there is 
            '       no parameterless constructor suitable for calling
            Dim baseConstructor As MethodSymbol = FindConstructorToCallByDefault(constructor, diagnostics)
            If baseConstructor Is Nothing Then
                Return Nothing
            End If

            Return BindDefaultConstructorInitializer(constructor, baseConstructor, diagnostics)
        End Function

        Private Shared Function CreateDebugDocumentForFile(normalizedPath As String) As Cci.DebugSourceDocument
            Return New Cci.DebugSourceDocument(normalizedPath, Cci.DebugSourceDocument.CorSymLanguageTypeBasic)
        End Function
1965 1966 1967 1968

        Private Shared Function PassesFilter(filterOpt As Predicate(Of Symbol), symbol As Symbol) As Boolean
            Return filterOpt Is Nothing OrElse filterOpt(symbol)
        End Function
T
TomasMatousek 已提交
1969 1970
    End Class
End Namespace