MethodCompiler.vb 102.8 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
23
        Private ReadOnly _emittingPdb As Boolean
T
TomasMatousek 已提交
24 25 26
        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
        ' 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.
50
        Private ReadOnly _compilerTasks As ConcurrentStack(Of Task)
T
TomasMatousek 已提交
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

        ' 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,
81
                       emittingPdb As Boolean,
T
TomasMatousek 已提交
82 83 84 85 86 87
                       doEmitPhase As Boolean,
                       hasDeclarationErrors As Boolean,
                       diagnostics As DiagnosticBag,
                       filter As Predicate(Of Symbol),
                       cancellationToken As CancellationToken)

88 89 90 91 92 93 94 95 96 97 98
            _compilation = compilation
            _moduleBeingBuiltOpt = moduleBeingBuiltOpt
            _diagnostics = diagnostics
            _hasDeclarationErrors = hasDeclarationErrors
            _cancellationToken = cancellationToken
            _doEmitPhase = doEmitPhase
            _emittingPdb = emittingPdb
            _filterOpt = filter

            If emittingPdb Then
                _debugDocumentProvider = Function(path As String, basePath As String) moduleBeingBuiltOpt.GetOrAddDebugDocument(path, basePath, AddressOf CreateDebugDocumentForFile)
T
TomasMatousek 已提交
99 100 101
            End If

            If compilation.Options.ConcurrentBuild Then
102
                _compilerTasks = New ConcurrentStack(Of Task)()
T
TomasMatousek 已提交
103 104 105
            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,
158
                                              emittingPdb:=False,
T
TomasMatousek 已提交
159 160 161 162 163 164 165 166
                                              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,
190
                                              emittingPdb As Boolean,
T
TomasMatousek 已提交
191 192 193 194 195
                                              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 213 214 215 216 217
                                              moduleBeingBuiltOpt,
                                              emittingPdb,
                                              doEmitPhase:=True,
                                              hasDeclarationErrors:=hasDeclarationErrors,
                                              diagnostics:=diagnostics,
                                              filter:=filter,
                                              cancellationToken:=cancellationToken)
T
TomasMatousek 已提交
218

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
            Dim entryPoint = GetEntryPoint(compilation, moduleBeingBuiltOpt, diagnostics, cancellationToken)
            If moduleBeingBuiltOpt IsNot Nothing Then
247 248 249
                If entryPoint IsNot Nothing AndAlso compilation.Options.OutputKind.IsApplication Then
                    moduleBeingBuiltOpt.SetPEEntryPoint(entryPoint, diagnostics)
                End If
T
TomasMatousek 已提交
250

251
                If (compiler.GlobalHasErrors OrElse moduleBeingBuiltOpt.SourceModule.HasBadAttributes) AndAlso Not hasDeclarationErrors AndAlso Not diagnostics.HasAnyErrors Then
252 253 254
                    ' 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 已提交
255
                End If
256
            End If
T
TomasMatousek 已提交
257 258
        End Sub

C
Charles Stoner 已提交
259
        Private Shared Function GetEntryPoint(compilation As VisualBasicCompilation,
T
TomasMatousek 已提交
260 261 262 263
                                             moduleBeingBuilt As PEModuleBuilder,
                                             diagnostics As DiagnosticBag,
                                             cancellationToken As CancellationToken) As MethodSymbol

C
Charles Stoner 已提交
264 265
            Dim entryPointAndDiagnostics = compilation.GetEntryPointAndDiagnostics(cancellationToken)
            If entryPointAndDiagnostics Is Nothing Then
T
TomasMatousek 已提交
266 267 268 269
                Return Nothing
            End If

            Debug.Assert(Not entryPointAndDiagnostics.Diagnostics.IsDefault)
270 271
            diagnostics.AddRange(entryPointAndDiagnostics.Diagnostics)

C
Charles Stoner 已提交
272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290
            Dim entryPoint = entryPointAndDiagnostics.MethodSymbol
            Dim synthesizedEntryPoint = TryCast(entryPoint, SynthesizedEntryPointSymbol)
            If synthesizedEntryPoint IsNot Nothing AndAlso
                moduleBeingBuilt IsNot Nothing AndAlso
                Not diagnostics.HasAnyErrors Then
                Dim compilationState = New TypeCompilationState(compilation, moduleBeingBuilt, initializeComponentOpt:=Nothing)
                Dim body = synthesizedEntryPoint.CreateBody()
                Dim emittedBody = GenerateMethodBody(moduleBeingBuilt,
                                                 synthesizedEntryPoint,
                                                 methodOrdinal:=DebugId.UndefinedOrdinal,
                                                 block:=body,
                                                 lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
                                                 closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
                                                 stateMachineTypeOpt:=Nothing,
                                                 variableSlotAllocatorOpt:=Nothing,
                                                 debugDocumentProvider:=Nothing,
                                                 diagnostics:=diagnostics,
                                                 emittingPdb:=False)
                moduleBeingBuilt.SetMethodBody(synthesizedEntryPoint, emittedBody)
T
TomasMatousek 已提交
291 292
            End If

C
Charles Stoner 已提交
293 294
            Debug.Assert(entryPoint IsNot Nothing OrElse entryPointAndDiagnostics.Diagnostics.HasAnyErrors() OrElse Not compilation.Options.Errors.IsDefaultOrEmpty)
            Return entryPoint
T
TomasMatousek 已提交
295 296 297
        End Function

        Private Sub WaitForWorkers()
298
            Dim tasks As ConcurrentStack(Of Task) = Me._compilerTasks
T
TomasMatousek 已提交
299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314
            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 已提交
315 316 317

            Dim methodOrdinal = 0

T
TomasMatousek 已提交
318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343
            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
344
                    Dim symbol As Symbol = builder(index)
T
TomasMatousek 已提交
345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374
                    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
375
            Dim compilationState As TypeCompilationState = New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing)
T
TomasMatousek 已提交
376 377 378 379 380 381 382 383 384 385 386 387 388

            ' 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 已提交
389 390 391 392 393 394
            ' 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 已提交
395 396 397

            Dim referencedConstructor As MethodSymbol = Nothing
            CompileMethod(method,
T
TomasMatousek 已提交
398 399 400
                          methodOrdinal,
                          withEventPropertyIdDispenser,
                          delegateRelaxationIdDispenser,
T
TomasMatousek 已提交
401 402 403 404 405 406 407
                          filter:=Nothing,
                          compilationState:=compilationState,
                          processedInitializers:=Binder.ProcessedFieldOrPropertyInitializers.Empty,
                          containingTypeBinder:=sourceTypeBinder,
                          previousSubmissionFields:=Nothing,
                          referencedConstructor:=referencedConstructor)

T
TomasMatousek 已提交
408 409 410 411 412 413
            ' Do not expect WithEvents
            Debug.Assert(withEventPropertyIdDispenser = 0)

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

T
TomasMatousek 已提交
414 415 416 417 418 419 420 421 422 423 424 425 426 427
            ' 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
428
                            For Each fieldOrProperty In initializer.FieldsOrProperties
T
TomasMatousek 已提交
429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449
                                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
450
                Dim worker As Task = CompileNamespaceAsTask(symbol)
451
                _compilerTasks.Push(worker)
T
TomasMatousek 已提交
452 453 454 455 456
            Else
                CompileNamespace(symbol)
            End If
        End Sub

457
        Private Function CompileNamespaceAsTask(symbol As NamespaceSymbol) As Task
T
TomasMatousek 已提交
458
            Return Task.Run(
459 460 461 462 463 464 465 466
                UICultureUtilities.WithCurrentUICulture(
                    Sub()
                        Try
                            CompileNamespace(symbol)
                        Catch e As Exception When FatalError.ReportUnlessCanceled(e)
                            Throw ExceptionUtilities.Unreachable
                        End Try
                    End Sub),
T
TomasMatousek 已提交
467 468 469 470
                Me._cancellationToken)
        End Function

        Private Sub CompileNamespace(symbol As NamespaceSymbol)
471
            If PassesFilter(_filterOpt, symbol) Then
T
TomasMatousek 已提交
472 473 474 475 476 477 478 479
                For Each member In symbol.GetMembersUnordered()
                    member.Accept(Me)
                Next
            End If
        End Sub

        Public Overrides Sub VisitNamedType(symbol As NamedTypeSymbol)
            _cancellationToken.ThrowIfCancellationRequested()
480
            If PassesFilter(_filterOpt, symbol) Then
T
TomasMatousek 已提交
481
                If Me._compilation.Options.ConcurrentBuild Then
482
                    Dim worker As Task = CompileNamedTypeAsTask(symbol, _filterOpt)
483
                    _compilerTasks.Push(worker)
T
TomasMatousek 已提交
484
                Else
485
                    CompileNamedType(symbol, _filterOpt)
T
TomasMatousek 已提交
486 487 488 489 490 491
                End If
            End If
        End Sub

        Private Function CompileNamedTypeAsTask(symbol As NamedTypeSymbol, filter As Predicate(Of Symbol)) As Task
            Return Task.Run(
492 493 494 495 496 497 498 499
                UICultureUtilities.WithCurrentUICulture(
                    Sub()
                        Try
                            CompileNamedType(symbol, filter)
                        Catch e As Exception When FatalError.ReportUnlessCanceled(e)
                            Throw ExceptionUtilities.Unreachable
                        End Try
                    End Sub),
T
TomasMatousek 已提交
500 501 502
                Me._cancellationToken)
        End Function

C
Charles Stoner 已提交
503 504
        Private Sub CompileNamedType(containingType As NamedTypeSymbol, filter As Predicate(Of Symbol))
            If containingType.IsEmbedded Then
T
TomasMatousek 已提交
505 506 507 508 509
                ' Don't process embedded types
                Return
            End If

            ' Find the constructor of a script class.
C
Charles Stoner 已提交
510 511 512 513 514 515 516 517
            Dim scriptCtor As SynthesizedConstructorBase = Nothing
            Dim scriptInitializer As SynthesizedInteractiveInitializerMethod = Nothing
            Dim scriptEntryPoint As SynthesizedEntryPointSymbol = Nothing
            Dim scriptCtorOrdinal = -1
            If containingType.IsScriptClass Then
                scriptCtor = containingType.GetScriptConstructor()
                scriptInitializer = containingType.GetScriptInitializer()
                scriptEntryPoint = containingType.GetScriptEntryPoint()
T
TomasMatousek 已提交
518
                Debug.Assert(scriptCtor IsNot Nothing)
C
Charles Stoner 已提交
519
                Debug.Assert(scriptInitializer IsNot Nothing)
T
TomasMatousek 已提交
520 521 522 523
            End If

            Dim processedStaticInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty
            Dim processedInstanceInitializers = Binder.ProcessedFieldOrPropertyInitializers.Empty
C
Charles Stoner 已提交
524
            Dim synthesizedSubmissionFields = If(containingType.IsSubmissionClass, New SynthesizedSubmissionFields(_compilation, containingType), Nothing)
T
TomasMatousek 已提交
525 526

            ' if this is a type symbol from source we'll try to bind the field initializers as well
C
Charles Stoner 已提交
527
            Dim sourceTypeSymbol = TryCast(containingType, SourceMemberContainerTypeSymbol)
T
TomasMatousek 已提交
528 529 530 531 532 533 534 535
            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
536
            Dim compilationState As TypeCompilationState = New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponent)
T
TomasMatousek 已提交
537 538 539 540 541 542 543 544 545 546 547 548

            ' 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)

549
                processedStaticInitializers = New Binder.ProcessedFieldOrPropertyInitializers(Binder.BindFieldAndPropertyInitializers(sourceTypeSymbol,
T
TomasMatousek 已提交
550
                                                        sourceTypeSymbol.StaticInitializers,
C
Charles Stoner 已提交
551
                                                        scriptInitializer,
552
                                                        _diagnostics))
T
TomasMatousek 已提交
553

554
                processedInstanceInitializers = New Binder.ProcessedFieldOrPropertyInitializers(Binder.BindFieldAndPropertyInitializers(sourceTypeSymbol,
T
TomasMatousek 已提交
555
                                                        sourceTypeSymbol.InstanceInitializers,
C
Charles Stoner 已提交
556
                                                        scriptInitializer,
557
                                                        _diagnostics))
T
TomasMatousek 已提交
558 559 560 561 562 563 564

                ' 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)
565
                If sharedDefaultConstructor IsNot Nothing AndAlso PassesFilter(filter, sharedDefaultConstructor) Then
T
TomasMatousek 已提交
566 567 568 569 570 571 572 573 574 575 576 577 578 579 580 581 582 583 584

                    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 已提交
585

586 587
                    If _moduleBeingBuiltOpt IsNot Nothing Then
                        _moduleBeingBuiltOpt.AddSynthesizedDefinition(sourceTypeSymbol, sharedDefaultConstructor)
T
TomasMatousek 已提交
588 589 590 591 592 593
                    End If
                End If
            End If

            ' Constructor --> Constructor calls to be used in cycles detection
            Dim constructorCallMap As Dictionary(Of MethodSymbol, MethodSymbol) = Nothing
C
Charles Stoner 已提交
594
            Dim members = containingType.GetMembers()
T
TomasMatousek 已提交
595 596 597 598 599 600 601 602 603

            ' 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 已提交
604

605
                If Not PassesFilter(filter, member) Then
T
TomasMatousek 已提交
606 607 608
                    Continue For
                End If

T
TomasMatousek 已提交
609 610 611
                Select Case member.Kind
                    Case SymbolKind.NamedType
                        member.Accept(Me)
T
TomasMatousek 已提交
612

T
TomasMatousek 已提交
613 614
                    Case SymbolKind.Method
                        Dim method = DirectCast(member, MethodSymbol)
C
Charles Stoner 已提交
615 616 617 618 619 620 621 622
                        If method.IsScriptConstructor Then
                            Debug.Assert(scriptCtorOrdinal = -1)
                            Debug.Assert(scriptCtor Is method)
                            scriptCtorOrdinal = memberOrdinal
                            Continue For
                        End If

                        If method Is scriptEntryPoint Then
T
TomasMatousek 已提交
623 624
                            Continue For
                        End If
T
TomasMatousek 已提交
625 626

                        If method.IsPartial() Then
627 628
                            Dim impl = method.PartialImplementationPart
                            If impl IsNot method Then
629
                                If CType(method, SourceMethodSymbol).SetDiagnostics(ImmutableArray(Of Diagnostic).Empty) AndAlso impl Is Nothing Then
630 631
                                    method.DeclaringCompilation.SymbolDeclaredEvent(method)
                                End If
T
TomasMatousek 已提交
632

633 634 635
                                If impl Is Nothing Then
                                    Continue For
                                End If
T
TomasMatousek 已提交
636 637

                                method = impl
T
TomasMatousek 已提交
638 639 640 641 642 643 644 645 646
                            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
C
Charles Stoner 已提交
647
                        ElseIf method.MethodKind = MethodKind.Constructor OrElse method.IsScriptInitializer Then
T
TomasMatousek 已提交
648 649 650 651
                            processedInitializers = processedInstanceInitializers
                        End If

                        Dim referencedConstructor As MethodSymbol = Nothing
T
TomasMatousek 已提交
652 653 654 655 656 657 658 659 660 661 662

                        CompileMethod(method,
                                      memberOrdinal,
                                      withEventPropertyIdDispenser,
                                      delegateRelaxationIdDispenser,
                                      filter,
                                      compilationState,
                                      processedInitializers,
                                      sourceTypeBinder,
                                      synthesizedSubmissionFields,
                                      referencedConstructor)
T
TomasMatousek 已提交
663 664 665 666 667 668 669

                        ' 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
C
Charles Stoner 已提交
670
                            If referencedConstructor.ContainingType.Equals(containingType) Then
T
TomasMatousek 已提交
671 672 673 674 675 676 677 678 679
                                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.
680
                        If DoEmitPhase AndAlso _moduleBeingBuiltOpt IsNot Nothing Then
T
TomasMatousek 已提交
681 682
                            CreateExplicitInterfaceImplementationStubs(compilationState, method)
                        End If
T
TomasMatousek 已提交
683
                End Select
T
TomasMatousek 已提交
684 685
            Next

C
Charles Stoner 已提交
686
            Debug.Assert(containingType.IsScriptClass = (scriptCtorOrdinal >= 0))
T
TomasMatousek 已提交
687 688 689 690 691 692 693

            ' 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:
C
Charles Stoner 已提交
694 695
            If scriptCtor IsNot Nothing Then
                Debug.Assert(scriptCtorOrdinal >= 0)
T
TomasMatousek 已提交
696
                CompileMethod(scriptCtor,
C
Charles Stoner 已提交
697
                              scriptCtorOrdinal,
T
TomasMatousek 已提交
698 699 700 701
                              withEventPropertyIdDispenser,
                              delegateRelaxationIdDispenser,
                              filter,
                              compilationState,
C
Charles Stoner 已提交
702
                              Binder.ProcessedFieldOrPropertyInitializers.Empty,
T
TomasMatousek 已提交
703 704
                              sourceTypeBinder,
                              synthesizedSubmissionFields)
T
TomasMatousek 已提交
705

706
                If synthesizedSubmissionFields IsNot Nothing AndAlso _moduleBeingBuiltOpt IsNot Nothing Then
C
Charles Stoner 已提交
707
                    synthesizedSubmissionFields.AddToType(containingType, _moduleBeingBuiltOpt)
T
TomasMatousek 已提交
708 709 710 711 712
                End If
            End If

            ' Report warnings for constructors that do not call InitializeComponent
            If initializeComponent IsNot Nothing Then
C
Charles Stoner 已提交
713
                For Each member In containingType.GetMembers()
T
TomasMatousek 已提交
714 715 716 717 718 719 720 721 722
                    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
723
                        Dim location As Location = sourceMethod.NonMergedLocation
T
TomasMatousek 已提交
724 725 726 727 728 729 730 731 732 733
                        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
734
            If _moduleBeingBuiltOpt IsNot Nothing Then
T
TomasMatousek 已提交
735 736
                CompileSynthesizedMethods(compilationState)
            End If
737 738

            compilationState.Free()
T
TomasMatousek 已提交
739 740 741 742 743 744 745 746 747 748 749 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
        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)
796
                        _moduleBeingBuiltOpt.AddSynthesizedDefinition(method.ContainingType, DirectCast(matchingStub, Microsoft.Cci.IMethodDefinition))
T
TomasMatousek 已提交
797 798 799 800 801 802 803 804 805 806 807 808 809 810 811 812 813 814 815 816 817 818 819 820 821 822 823 824 825 826 827 828 829
                    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)
830
            Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing)
831

832 833
            For Each method As MethodSymbol In privateImplClass.GetMethods(Nothing)
                Dim diagnosticsThisMethod = DiagnosticBag.GetInstance()
834

835
                Dim boundBody = method.GetBoundMethodBody(diagnosticsThisMethod)
T
TomasMatousek 已提交
836

837 838
                Dim emittedBody = GenerateMethodBody(_moduleBeingBuiltOpt,
                                                     method,
839
                                                     methodOrdinal:=DebugId.UndefinedOrdinal,
840 841 842
                                                     block:=boundBody,
                                                     lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
                                                     closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
843 844
                                                     stateMachineTypeOpt:=Nothing,
                                                     variableSlotAllocatorOpt:=Nothing,
845 846
                                                     debugDocumentProvider:=Nothing,
                                                     diagnostics:=diagnosticsThisMethod,
847
                                                     emittingPdb:=False)
T
TomasMatousek 已提交
848

849 850
                _diagnostics.AddRange(diagnosticsThisMethod)
                diagnosticsThisMethod.Free()
T
TomasMatousek 已提交
851

852 853 854 855
                ' error while generating IL
                If emittedBody Is Nothing Then
                    Exit For
                End If
T
TomasMatousek 已提交
856

857 858
                _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody)
            Next
T
TomasMatousek 已提交
859 860
        End Sub

861
        Private Sub CompileSynthesizedMethods(additionalTypes As ImmutableArray(Of NamedTypeSymbol))
862 863
            Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing)

864
            Dim compilationState As New TypeCompilationState(_compilation, _moduleBeingBuiltOpt, initializeComponentOpt:=Nothing)
865
            For Each additionalType In additionalTypes
T
TomasMatousek 已提交
866 867
                Dim methodOrdinal As Integer = 0

868 869 870 871
                For Each method In additionalType.GetMethodsToEmit()
                    Dim diagnosticsThisMethod = DiagnosticBag.GetInstance()

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

A
acasey 已提交
873 874 875
                    Dim emittedBody As MethodBody = Nothing

                    If Not diagnosticsThisMethod.HasAnyErrors Then
876
                        Dim lazyVariableSlotAllocator As VariableSlotAllocator = Nothing
877 878
                        Dim statemachineTypeOpt As StateMachineTypeSymbol = Nothing

879 880
                        Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance()
                        Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance()
T
TomasMatousek 已提交
881 882
                        Dim delegateRelaxationIdDispenser = 0

883
                        Dim rewrittenBody = Rewriter.LowerBodyOrInitializer(
884
                            method,
T
TomasMatousek 已提交
885
                            methodOrdinal,
886
                            boundBody,
887 888 889
                            previousSubmissionFields:=Nothing,
                            compilationState:=compilationState,
                            diagnostics:=diagnosticsThisMethod,
890
                            lazyVariableSlotAllocator:=lazyVariableSlotAllocator,
891 892
                            lambdaDebugInfoBuilder:=lambdaDebugInfoBuilder,
                            closureDebugInfoBuilder:=closureDebugInfoBuilder,
T
TomasMatousek 已提交
893 894
                            delegateRelaxationIdDispenser:=delegateRelaxationIdDispenser,
                            stateMachineTypeOpt:=statemachineTypeOpt,
895
                            allowOmissionOfConditionalCalls:=_moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls,
896
                            isBodySynthesized:=True)
897 898

                        If Not diagnosticsThisMethod.HasAnyErrors Then
899 900
                            ' Synthesized methods have no ordinal stored in custom debug information
                            ' (only user-defined methods have ordinals).
901
                            emittedBody = GenerateMethodBody(_moduleBeingBuiltOpt,
902
                                                             method,
903
                                                             DebugId.UndefinedOrdinal,
904
                                                             rewrittenBody,
905 906
                                                             lambdaDebugInfoBuilder.ToImmutable(),
                                                             closureDebugInfoBuilder.ToImmutable(),
907
                                                             statemachineTypeOpt,
908
                                                             lazyVariableSlotAllocator,
909
                                                             debugDocumentProvider:=Nothing,
910
                                                             diagnostics:=diagnosticsThisMethod,
911
                                                             emittingPdb:=False)
912
                        End If
913 914 915

                        lambdaDebugInfoBuilder.Free()
                        closureDebugInfoBuilder.Free()
A
acasey 已提交
916
                    End If
917 918 919 920 921 922 923 924 925

                    _diagnostics.AddRange(diagnosticsThisMethod)
                    diagnosticsThisMethod.Free()

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

926
                    _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody)
T
TomasMatousek 已提交
927
                    methodOrdinal += 1
928 929 930 931 932 933 934 935 936 937
                Next
            Next

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

            compilationState.Free()
        End Sub

T
TomasMatousek 已提交
938
        Private Sub CompileSynthesizedMethods(compilationState As TypeCompilationState)
939
            Debug.Assert(_moduleBeingBuiltOpt IsNot Nothing)
T
TomasMatousek 已提交
940

941 942 943
            If Not compilationState.HasSynthesizedMethods Then
                Return
            End If
T
TomasMatousek 已提交
944

945
            For Each methodWithBody In compilationState.SynthesizedMethods
A
AlekseyTs 已提交
946 947 948 949 950 951
                If Not methodWithBody.Body.HasErrors Then
                    Dim method = methodWithBody.Method
                    Dim diagnosticsThisMethod As DiagnosticBag = DiagnosticBag.GetInstance()

                    Dim emittedBody = GenerateMethodBody(_moduleBeingBuiltOpt,
                                                         method,
952
                                                         methodOrdinal:=DebugId.UndefinedOrdinal,
953 954 955
                                                         block:=methodWithBody.Body,
                                                         lambdaDebugInfo:=ImmutableArray(Of LambdaDebugInfo).Empty,
                                                         closureDebugInfo:=ImmutableArray(Of ClosureDebugInfo).Empty,
A
AlekseyTs 已提交
956 957 958 959
                                                         stateMachineTypeOpt:=Nothing,
                                                         variableSlotAllocatorOpt:=Nothing,
                                                         debugDocumentProvider:=_debugDocumentProvider,
                                                         diagnostics:=diagnosticsThisMethod,
960
                                                         emittingPdb:=_emittingPdb)
T
TomasMatousek 已提交
961

A
AlekseyTs 已提交
962 963
                    _diagnostics.AddRange(diagnosticsThisMethod)
                    diagnosticsThisMethod.Free()
T
TomasMatousek 已提交
964

A
AlekseyTs 已提交
965 966 967 968
                    ' error while generating IL
                    If emittedBody Is Nothing Then
                        Exit For
                    End If
969

A
AlekseyTs 已提交
970
                    _moduleBeingBuiltOpt.SetMethodBody(method, emittedBody)
971 972
                End If
            Next
T
TomasMatousek 已提交
973 974 975 976 977 978 979 980 981 982 983 984 985 986 987 988 989 990 991 992 993 994 995 996
        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'
C
Charles Stoner 已提交
997
                    ' or it does not reference another constructor of this type, or there is something wrong with it;
T
TomasMatousek 已提交
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

                    ' 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.
1095
            If method.IsDefaultValueTypeConstructor() Then
T
TomasMatousek 已提交
1096 1097 1098 1099 1100 1101 1102 1103 1104 1105 1106 1107 1108 1109 1110 1111 1112 1113 1114 1115 1116 1117 1118 1119 1120 1121 1122 1123 1124
                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 已提交
1125 1126 1127
            methodOrdinal As Integer,
            ByRef withEventPropertyIdDispenser As Integer,
            ByRef delegateRelaxationIdDispenser As Integer,
T
TomasMatousek 已提交
1128 1129 1130 1131 1132 1133 1134
            filter As Predicate(Of Symbol),
            compilationState As TypeCompilationState,
            processedInitializers As Binder.ProcessedFieldOrPropertyInitializers,
            containingTypeBinder As Binder,
            previousSubmissionFields As SynthesizedSubmissionFields,
            Optional ByRef referencedConstructor As MethodSymbol = Nothing
        )
1135 1136 1137 1138
            '' TODO: add filtering as follows
            'If filter IsNot Nothing AndAlso Not filter(method) Then
            '    Return
            'End If
T
TomasMatousek 已提交
1139 1140 1141

            _cancellationToken.ThrowIfCancellationRequested()

1142 1143
            Debug.Assert(Not (method.IsPartial AndAlso method.PartialImplementationPart Is Nothing))

T
TomasMatousek 已提交
1144 1145 1146 1147 1148 1149 1150 1151 1152 1153
            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

1154 1155 1156 1157 1158 1159 1160 1161
            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 已提交
1162 1163 1164 1165 1166 1167 1168
            ' 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)

C
Charles Stoner 已提交
1169 1170 1171 1172 1173 1174 1175 1176
            ' Initializers 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)
T
TomasMatousek 已提交
1177 1178 1179 1180

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

1181 1182
            If sourceMethod IsNot Nothing AndAlso sourceMethod.SetDiagnostics(diagsForCurrentMethod.ToReadOnly()) Then
                Dim compilation = compilationState.Compilation
1183
                If compilation.ShouldAddEvent(method) Then
1184 1185 1186 1187 1188 1189 1190 1191 1192 1193 1194 1195 1196 1197
                    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)
1198
                        Dim symbolToProduce = If(method.PartialDefinitionPart, method)
N
Neal Gafter 已提交
1199
                        compilation.EventQueue.TryEnqueue(New SymbolDeclaredCompilationEvent(compilation, symbolToProduce, lazySemanticModel))
1200 1201 1202 1203
                    End If
                End If
            End If

T
TomasMatousek 已提交
1204
            If Not DoEmitPhase AndAlso sourceMethod IsNot Nothing Then
1205
                _diagnostics.AddRange(sourceMethod.Diagnostics)
T
TomasMatousek 已提交
1206 1207 1208 1209 1210
                Return
            End If

            If DoEmitPhase AndAlso Not hasErrors Then
                LowerAndEmitMethod(method,
T
TomasMatousek 已提交
1211
                                   methodOrdinal,
T
TomasMatousek 已提交
1212 1213 1214 1215 1216 1217 1218
                                   block,
                                   If(methodBinderOpt, containingTypeBinder),
                                   compilationState,
                                   diagsForCurrentMethod,
                                   processedInitializers,
                                   previousSubmissionFields,
                                   If(injectConstructorCall, referencedConstructor, Nothing),
T
TomasMatousek 已提交
1219
                                   delegateRelaxationIdDispenser)
T
TomasMatousek 已提交
1220 1221 1222

                ' if method happen to handle events of a base WithEvents, ensure that we have an overriding WithEvents property
                Dim handledEvents = method.HandledEvents
1223
                If Not handledEvents.IsEmpty Then
T
TomasMatousek 已提交
1224
                    CreateSyntheticWithEventOverridesIfNeeded(handledEvents,
T
TomasMatousek 已提交
1225 1226
                                                              delegateRelaxationIdDispenser,
                                                              withEventPropertyIdDispenser,
T
TomasMatousek 已提交
1227 1228 1229 1230 1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244
                                                              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 已提交
1245 1246
                                                              ByRef delegateRelaxationIdDispenser As Integer,
                                                              ByRef withEventPropertyIdDispenser As Integer,
1247 1248
                                                              compilationState As TypeCompilationState,
                                                              containingTypeBinder As Binder,
T
TomasMatousek 已提交
1249
                                                              diagnostics As DiagnosticBag,
1250
                                                              previousSubmissionFields As SynthesizedSubmissionFields)
T
TomasMatousek 已提交
1251

1252 1253
            Debug.Assert(_moduleBeingBuiltOpt Is Nothing OrElse _moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls)

T
TomasMatousek 已提交
1254
            For Each handledEvent In handledEvents
T
TomasMatousek 已提交
1255 1256
                If handledEvent.HandlesKind <> HandledEventKind.WithEvents Then
                    Continue For
T
TomasMatousek 已提交
1257
                End If
T
TomasMatousek 已提交
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276 1277 1278 1279 1280 1281 1282

                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)

1283 1284
                Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance()
                Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance()
T
TomasMatousek 已提交
1285 1286 1287 1288 1289 1290 1291

                setterBody = Rewriter.LowerBodyOrInitializer(setter,
                                                             withEventPropertyIdDispenser,
                                                             setterBody,
                                                             previousSubmissionFields,
                                                             compilationState,
                                                             diagnostics,
1292
                                                             lazyVariableSlotAllocator:=Nothing,
1293 1294
                                                             lambdaDebugInfoBuilder:=lambdaDebugInfoBuilder,
                                                             closureDebugInfoBuilder:=closureDebugInfoBuilder,
T
TomasMatousek 已提交
1295 1296 1297 1298 1299 1300
                                                             delegateRelaxationIdDispenser:=delegateRelaxationIdDispenser,
                                                             stateMachineTypeOpt:=Nothing,
                                                             allowOmissionOfConditionalCalls:=True,
                                                             isBodySynthesized:=True)

                ' There shall be no lambdas in the synthesized accessor but delegate relaxation conversions:
1301 1302
                Debug.Assert(Not lambdaDebugInfoBuilder.Any())
                Debug.Assert(Not closureDebugInfoBuilder.Any())
T
TomasMatousek 已提交
1303

1304 1305 1306
                lambdaDebugInfoBuilder.Free()
                closureDebugInfoBuilder.Free()

T
TomasMatousek 已提交
1307 1308 1309 1310 1311 1312
                compilationState.AddMethodWrapper(setter, setter, setterBody)
                _moduleBeingBuiltOpt.AddSynthesizedDefinition(containingType, setter)

                ' add property too
                _moduleBeingBuiltOpt.AddSynthesizedDefinition(containingType, prop)
                withEventPropertyIdDispenser += 1
T
TomasMatousek 已提交
1313 1314 1315 1316 1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334 1335 1336 1337
            Next
        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 已提交
1338
            methodOrdinal As Integer,
T
TomasMatousek 已提交
1339 1340 1341 1342 1343 1344 1345
            block As BoundBlock,
            binderOpt As Binder,
            compilationState As TypeCompilationState,
            diagsForCurrentMethod As DiagnosticBag,
            processedInitializers As Binder.ProcessedFieldOrPropertyInitializers,
            previousSubmissionFields As SynthesizedSubmissionFields,
            constructorToInject As MethodSymbol,
T
TomasMatousek 已提交
1346
            ByRef delegateRelaxationIdDispenser As Integer
T
TomasMatousek 已提交
1347 1348 1349 1350 1351 1352 1353 1354 1355 1356 1357 1358 1359 1360 1361
        )
            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
C
Charles Stoner 已提交
1362 1363 1364 1365 1366 1367 1368 1369 1370
                If method.IsScriptConstructor Then
                    body = block
                Else
                    ' Turns field initializers into bound assignment statements and top-level script statements into bound statements in the beginning the body. 
                    body = InitializerRewriter.BuildConstructorBody(compilationState, method, constructorInitializerOpt, processedInitializers, block)
                End If
            ElseIf method.IsScriptInitializer Then
                ' The body only includes bound initializers and a return statement. The rest is filled in later in this method.
                body = InitializerRewriter.BuildScriptInitializerBody(DirectCast(method, SynthesizedInteractiveInitializerMethod), processedInitializers, block)
T
TomasMatousek 已提交
1371 1372 1373 1374
            Else
                body = block
            End If

1375
            Dim diagnostics As DiagnosticBag = diagsForCurrentMethod
T
TomasMatousek 已提交
1376

1377 1378
            If method.IsImplicitlyDeclared AndAlso
               method.AssociatedSymbol IsNot Nothing AndAlso
T
TomasMatousek 已提交
1379
               method.AssociatedSymbol.IsMyGroupCollectionProperty Then
1380
                diagnostics = DiagnosticBag.GetInstance()
T
TomasMatousek 已提交
1381 1382
            End If

1383
            Dim lazyVariableSlotAllocator As VariableSlotAllocator = Nothing
1384
            Dim stateMachineTypeOpt As StateMachineTypeSymbol = Nothing
1385
            Dim allowOmissionOfConditionalCalls = _moduleBeingBuiltOpt Is Nothing OrElse _moduleBeingBuiltOpt.AllowOmissionOfConditionalCalls
1386 1387
            Dim lambdaDebugInfoBuilder = ArrayBuilder(Of LambdaDebugInfo).GetInstance()
            Dim closureDebugInfoBuilder = ArrayBuilder(Of ClosureDebugInfo).GetInstance()
T
TomasMatousek 已提交
1388

1389
            body = Rewriter.LowerBodyOrInitializer(method,
T
TomasMatousek 已提交
1390
                                                   methodOrdinal,
1391 1392 1393 1394
                                                   body,
                                                   previousSubmissionFields,
                                                   compilationState,
                                                   diagnostics,
1395
                                                   lazyVariableSlotAllocator,
1396 1397
                                                   lambdaDebugInfoBuilder,
                                                   closureDebugInfoBuilder,
T
TomasMatousek 已提交
1398
                                                   delegateRelaxationIdDispenser,
1399
                                                   stateMachineTypeOpt,
1400
                                                   allowOmissionOfConditionalCalls,
1401
                                                   isBodySynthesized:=False)
T
TomasMatousek 已提交
1402 1403

            ' The submission initializer has to be constructed after the body is rewritten (all previous submission references are visited):
C
Charles Stoner 已提交
1404 1405 1406
            Dim submissionInitialization = If(method.IsSubmissionConstructor,
                SynthesizedSubmissionConstructorSymbol.MakeSubmissionInitialization(block.Syntax, method, previousSubmissionFields, _compilation, diagnostics),
                ImmutableArray(Of BoundStatement).Empty)
1407
            Dim hasErrors = body.HasErrors OrElse diagsForCurrentMethod.HasAnyErrors OrElse (diagnostics IsNot diagsForCurrentMethod AndAlso diagnostics.HasAnyErrors)
T
TomasMatousek 已提交
1408 1409 1410
            SetGlobalErrorIfTrue(hasErrors)

            ' Actual emitting is only done if we have a module in which to emit and no errors so far.
1411 1412 1413 1414
            If _moduleBeingBuiltOpt Is Nothing OrElse hasErrors Then
                If diagnostics IsNot diagsForCurrentMethod Then
                    DirectCast(method.AssociatedSymbol, SynthesizedMyGroupCollectionPropertySymbol).RelocateDiagnostics(diagnostics, diagsForCurrentMethod)
                    diagnostics.Free()
T
TomasMatousek 已提交
1415 1416 1417 1418 1419 1420
                End If

                Return
            End If

            ' now we have everything we need to build complete submission
C
Charles Stoner 已提交
1421 1422
            If method.IsScriptConstructor Then
                Dim boundStatements = ArrayBuilder(Of BoundStatement).GetInstance()
T
TomasMatousek 已提交
1423 1424 1425 1426 1427 1428 1429
                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
1430
            Dim methodBody As MethodBody = GenerateMethodBody(_moduleBeingBuiltOpt,
T
TomasMatousek 已提交
1431
                                                              method,
1432
                                                              methodOrdinal,
T
TomasMatousek 已提交
1433
                                                              body,
1434 1435
                                                              lambdaDebugInfoBuilder.ToImmutable(),
                                                              closureDebugInfoBuilder.ToImmutable(),
1436
                                                              stateMachineTypeOpt,
1437
                                                              lazyVariableSlotAllocator,
1438 1439
                                                              _debugDocumentProvider,
                                                              diagnostics,
1440
                                                              emittingPdb:=_emittingPdb)
1441 1442 1443 1444

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

1447
            _moduleBeingBuiltOpt.SetMethodBody(If(method.PartialDefinitionPart, method), methodBody)
1448 1449 1450

            lambdaDebugInfoBuilder.Free()
            closureDebugInfoBuilder.Free()
T
TomasMatousek 已提交
1451 1452
        End Sub

1453
        Friend Shared Function GenerateMethodBody(moduleBuilder As PEModuleBuilder,
T
TomasMatousek 已提交
1454
                                                  method As MethodSymbol,
1455
                                                  methodOrdinal As Integer,
T
TomasMatousek 已提交
1456
                                                  block As BoundStatement,
1457 1458
                                                  lambdaDebugInfo As ImmutableArray(Of LambdaDebugInfo),
                                                  closureDebugInfo As ImmutableArray(Of ClosureDebugInfo),
1459
                                                  stateMachineTypeOpt As StateMachineTypeSymbol,
1460
                                                  variableSlotAllocatorOpt As VariableSlotAllocator,
T
TomasMatousek 已提交
1461
                                                  debugDocumentProvider As DebugDocumentProvider,
1462
                                                  diagnostics As DiagnosticBag,
1463
                                                  emittingPdb As Boolean) As MethodBody
T
TomasMatousek 已提交
1464

1465
            Dim compilation = moduleBuilder.Compilation
1466
            Dim localSlotManager = New LocalSlotManager(variableSlotAllocatorOpt)
1467 1468 1469 1470 1471 1472 1473
            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 已提交
1474 1475

            Try
1476
                Debug.Assert(Not diagnostics.HasAnyErrors)
T
TomasMatousek 已提交
1477 1478

                Dim asyncDebugInfo As Cci.AsyncMethodBodyDebugInfo = Nothing
1479
                Dim codeGen = New CodeGen.CodeGenerator(method, block, builder, moduleBuilder, diagnostics, optimizations, emittingPdb)
1480

1481 1482 1483 1484
                If diagnostics.HasAnyErrors() Then
                    Return Nothing
                End If

1485 1486
                ' We need to save additional debugging information for MoveNext of an async state machine.
                Dim stateMachineMethod = TryCast(method, SynthesizedStateMachineMethod)
W
wochae 已提交
1487 1488 1489

                Dim isStateMachineMoveNextMethod As Boolean = stateMachineMethod IsNot Nothing AndAlso method.Name = WellKnownMemberNames.MoveNextMethodName
                If isStateMachineMoveNextMethod AndAlso stateMachineMethod.StateMachineType.KickoffMethod.IsAsync Then
T
TomasMatousek 已提交
1490 1491 1492 1493 1494

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

1495
                    codeGen.Generate(asyncCatchHandlerOffset, asyncYieldPoints, asyncResumePoints)
T
TomasMatousek 已提交
1496

1497
                    Dim kickoffMethod = stateMachineMethod.StateMachineType.KickoffMethod
T
TomasMatousek 已提交
1498

1499 1500
                    ' 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).
1501 1502 1503 1504 1505 1506 1507 1508 1509 1510 1511

                    ' 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)
1512 1513
                Else
                    codeGen.Generate()
T
TomasMatousek 已提交
1514 1515
                End If

1516 1517 1518 1519 1520 1521 1522
                ' Translate the imports even if we are not writing PDBs. The translation has an impact on generated metadata 
                ' and we don't want to emit different metadata depending on whether or we emit with PDB stream.
                ' TODO (https://github.com/dotnet/roslyn/issues/2846): This will need to change for member initializers in partial class.
                Dim importScopeOpt = If(method.Syntax IsNot Nothing AndAlso method.Syntax.SyntaxTree IsNot VisualBasicSyntaxTree.DummySyntaxTree.Dummy,
                                        moduleBuilder.SourceModule.GetSourceFile(method.Syntax.SyntaxTree).Translate(moduleBuilder, diagnostics),
                                        Nothing)

1523
                If diagnostics.HasAnyErrors() Then
T
TomasMatousek 已提交
1524 1525 1526 1527
                    Return Nothing
                End If

                ' We will only save the IL builders when running tests.
1528 1529
                If moduleBuilder.SaveTestData Then
                    moduleBuilder.SetMethodTestData(method, builder.GetSnapshot())
T
TomasMatousek 已提交
1530 1531
                End If

W
wochae 已提交
1532 1533 1534 1535
                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)
1536 1537
                    GetStateMachineSlotDebugInfo(moduleBuilder, moduleBuilder.GetSynthesizedFields(stateMachineTypeOpt), variableSlotAllocatorOpt, diagnostics, stateMachineHoistedLocalSlots, stateMachineAwaiterSlots)
                    Debug.Assert(Not diagnostics.HasAnyErrors())
W
wochae 已提交
1538 1539
                End If

1540
                Dim localScopes = builder.GetAllScopes()
T
TomasMatousek 已提交
1541 1542 1543 1544

                Return New MethodBody(builder.RealizedIL,
                                      builder.MaxStack,
                                      If(method.PartialDefinitionPart, method),
1545
                                      If(variableSlotAllocatorOpt?.MethodId, New DebugId(methodOrdinal, moduleBuilder.CurrentGenerationOrdinal)),
T
TomasMatousek 已提交
1546 1547 1548 1549
                                      builder.LocalSlotManager.LocalsInOrder(),
                                      builder.RealizedSequencePoints,
                                      debugDocumentProvider,
                                      builder.RealizedExceptionHandlers,
T
TomasMatousek 已提交
1550
                                      localScopes,
1551
                                      hasDynamicLocalVariables:=False,
1552
                                      importScopeOpt:=importScopeOpt,
1553 1554
                                      lambdaDebugInfo:=lambdaDebugInfo,
                                      closureDebugInfo:=closureDebugInfo,
1555
                                      stateMachineTypeNameOpt:=stateMachineTypeOpt?.Name, ' TODO: remove or update AddedOrChangedMethodInfo
1556
                                      stateMachineHoistedLocalScopes:=Nothing,
W
wochae 已提交
1557 1558
                                      stateMachineHoistedLocalSlots:=stateMachineHoistedLocalSlots,
                                      stateMachineAwaiterSlots:=stateMachineAwaiterSlots,
T
TomasMatousek 已提交
1559 1560 1561 1562 1563 1564 1565
                                      asyncMethodDebugInfo:=asyncDebugInfo)
            Finally
                ' Free resources used by the basic blocks in the builder.
                builder.FreeBasicBlocks()
            End Try
        End Function

1566 1567 1568 1569
        Private Shared Sub GetStateMachineSlotDebugInfo(moduleBuilder As PEModuleBuilder,
                                                        fieldDefs As IEnumerable(Of Cci.IFieldDefinition),
                                                        variableSlotAllocatorOpt As VariableSlotAllocator,
                                                        diagnostics As DiagnosticBag,
W
wochae 已提交
1570 1571 1572 1573 1574 1575 1576 1577 1578 1579 1580 1581 1582 1583 1584 1585
                                                        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

1586
                    awaiters(index) = moduleBuilder.EncTranslateLocalVariableType(field.Type, diagnostics)
W
wochae 已提交
1587 1588 1589 1590 1591 1592 1593 1594
                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

1595
                    hoistedVariables(index) = New EncHoistedLocalInfo(field.SlotDebugInfo, moduleBuilder.EncTranslateLocalVariableType(field.Type, diagnostics))
W
wochae 已提交
1596 1597 1598
                End If
            Next

1599 1600 1601 1602 1603 1604 1605 1606 1607 1608 1609 1610 1611
            ' Fill in empty slots for variables deleted during EnC that are not followed by an existing variable
            If variableSlotAllocatorOpt IsNot Nothing Then
                Dim previousAwaiterCount = variableSlotAllocatorOpt.PreviousAwaiterSlotCount
                While awaiters.Count < previousAwaiterCount
                    awaiters.Add(Nothing)
                End While

                Dim previousAwaiterSlotCount = variableSlotAllocatorOpt.PreviousHoistedLocalSlotCount
                While hoistedVariables.Count < previousAwaiterSlotCount
                    hoistedVariables.Add(New EncHoistedLocalInfo(True))
                End While
            End If

W
wochae 已提交
1612 1613 1614 1615
            hoistedVariableSlots = hoistedVariables.ToImmutableAndFree()
            awaiterSlots = awaiters.ToImmutableAndFree()
        End Sub

C
Charles Stoner 已提交
1616
        Private Shared Function BindAndAnalyzeMethodBody(method As MethodSymbol,
T
TomasMatousek 已提交
1617 1618 1619 1620 1621 1622 1623 1624 1625 1626 1627 1628 1629 1630 1631 1632 1633 1634
                                                       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))
1635
            If Not method.IsShared AndAlso compilationState.InitializeComponentOpt IsNot Nothing AndAlso
T
TomasMatousek 已提交
1636
               Not method.IsImplicitlyDeclared Then
1637 1638 1639 1640 1641
                Try
                    InitializeComponentCallTreeBuilder.CollectCallees(compilationState, method, body)
                Catch ex As BoundTreeVisitor.CancelledByStackGuardException
                    ex.AddAnError(diagnostics)
                End Try
T
TomasMatousek 已提交
1642 1643 1644 1645 1646
            End If

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

1647 1648
                ' class constructors must inject call to the base
                injectDefaultConstructorCall = Not method.ContainingType.IsValueType
T
TomasMatousek 已提交
1649 1650 1651 1652 1653 1654 1655 1656 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

                ' 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

1683 1684
        Private NotInheritable Class InitializeComponentCallTreeBuilder
            Inherits BoundTreeWalkerWithStackGuardWithoutRecursionOnTheLeftOfBinaryOperator
T
TomasMatousek 已提交
1685

1686 1687
            Private _calledMethods As HashSet(Of MethodSymbol)
            Private ReadOnly _containingType As NamedTypeSymbol
T
TomasMatousek 已提交
1688 1689

            Private Sub New(containingType As NamedTypeSymbol)
1690
                _containingType = containingType
T
TomasMatousek 已提交
1691 1692 1693 1694 1695 1696
            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)

1697 1698
                If visitor._calledMethods IsNot Nothing Then
                    compilationState.AddToInitializeComponentCallTree(method, visitor._calledMethods.ToArray().AsImmutableOrNull())
T
TomasMatousek 已提交
1699 1700 1701 1702 1703 1704
                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
1705
                   Not node.Method.IsShared AndAlso node.Method.OriginalDefinition.ContainingType Is _containingType Then
T
TomasMatousek 已提交
1706

1707 1708
                    If _calledMethods Is Nothing Then
                        _calledMethods = New HashSet(Of MethodSymbol)(ReferenceEqualityComparer.Instance)
T
TomasMatousek 已提交
1709 1710
                    End If

1711
                    _calledMethods.Add(node.Method.OriginalDefinition)
T
TomasMatousek 已提交
1712 1713 1714 1715 1716 1717 1718 1719 1720 1721 1722 1723 1724
                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
1725
            Debug.Assert(Not containingType.IsValueType)
T
TomasMatousek 已提交
1726 1727 1728 1729 1730 1731 1732 1733 1734

            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.
1735
            Dim defaultConstructorType As NamedTypeSymbol = containingType.BaseTypeNoUseSiteDiagnostics
T
TomasMatousek 已提交
1736 1737 1738 1739 1740 1741 1742 1743 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
            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

1834
            Debug.Assert(candidate <> constructor)
T
TomasMatousek 已提交
1835 1836 1837 1838 1839 1840 1841 1842 1843

            ' 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
C
Charles Stoner 已提交
1844
                    ' base constructor. If we have a user-defined constructor then ask the user to explicitly call a
T
TomasMatousek 已提交
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
                    ' 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 已提交
1894
            Dim syntaxNode As VisualBasicSyntaxNode = constructor.Syntax
T
TomasMatousek 已提交
1895 1896 1897 1898 1899 1900 1901 1902 1903 1904 1905 1906

            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

C
Charles Stoner 已提交
1907
                ' Otherwise we should bind invocation expression
T
TomasMatousek 已提交
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
                ' 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
1957 1958 1959 1960

        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 已提交
1961 1962
    End Class
End Namespace