File: Symbols\AnonymousTypes\SynthesizedSymbols\AnonymousDelegate_TemplateSymbol.vb
Web Access
Project: src\src\Compilers\VisualBasic\Portable\Microsoft.CodeAnalysis.VisualBasic.vbproj (Microsoft.CodeAnalysis.VisualBasic)
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
 
Imports System.Collections.Generic
Imports System.Collections.Immutable
Imports Microsoft.CodeAnalysis
Imports Microsoft.CodeAnalysis.Emit
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Emit
 
Namespace Microsoft.CodeAnalysis.VisualBasic.Symbols
    Partial Friend NotInheritable Class AnonymousTypeManager
 
        Private Class AnonymousDelegateTemplateSymbol
            Inherits AnonymousTypeOrDelegateTemplateSymbol
 
            Protected ReadOnly TypeDescr As AnonymousTypeDescriptor
            Private ReadOnly _members As ImmutableArray(Of SynthesizedDelegateMethodSymbol)
 
            Friend Shared Function Create(manager As AnonymousTypeManager, typeDescr As AnonymousTypeDescriptor) As AnonymousDelegateTemplateSymbol
                Dim parameters = typeDescr.Parameters
                Return If(parameters.Length = 1 AndAlso parameters.IsSubDescription(),
                    New NonGenericAnonymousDelegateSymbol(manager, typeDescr),
                    New AnonymousDelegateTemplateSymbol(manager, typeDescr))
            End Function
 
            Public Sub New(manager As AnonymousTypeManager,
                           typeDescr As AnonymousTypeDescriptor)
                MyBase.New(manager, typeDescr)
 
                Debug.Assert(typeDescr.Parameters.Length > 1 OrElse
                             Not typeDescr.Parameters.IsSubDescription() OrElse
                             TypeOf Me Is NonGenericAnonymousDelegateSymbol)
 
                Me.TypeDescr = typeDescr
 
                Dim parameterDescriptors As ImmutableArray(Of AnonymousTypeField) = typeDescr.Parameters
                Dim returnType As TypeSymbol = If(parameterDescriptors.IsSubDescription(), DirectCast(manager.System_Void, TypeSymbol), Me.TypeParameters.Last)
                Dim parameters = ArrayBuilder(Of ParameterSymbol).GetInstance(parameterDescriptors.Length + 1)
                Dim i As Integer
 
                ' A delegate has the following members: (see CLI spec 13.6)
                ' (1) a method named Invoke with the specified signature
                Dim delegateInvoke = New SynthesizedDelegateMethodSymbol(WellKnownMemberNames.DelegateInvokeName,
                                                                         Me,
                                                                         SourceNamedTypeSymbol.DelegateCommonMethodFlags Or SourceMemberFlags.MethodKindDelegateInvoke,
                                                                         returnType)
 
                For i = 0 To parameterDescriptors.Length - 2
                    parameters.Add(New AnonymousTypeOrDelegateParameterSymbol(delegateInvoke,
                                                                              Me.TypeParameters(i),
                                                                              i,
                                                                              parameterDescriptors(i).IsByRef,
                                                                              parameterDescriptors(i).Name,
                                                                              i))
                Next
 
                delegateInvoke.SetParameters(parameters.ToImmutable())
                parameters.Clear()
 
                ' (2) a constructor with argument types (object, System.IntPtr)
                Dim delegateCtor = New SynthesizedDelegateMethodSymbol(WellKnownMemberNames.InstanceConstructorName,
                                                                       Me,
                                                                       SourceNamedTypeSymbol.DelegateConstructorMethodFlags,
                                                                       manager.System_Void)
 
                delegateCtor.SetParameters(
                    ImmutableArray.Create(Of ParameterSymbol)(
                           New AnonymousTypeOrDelegateParameterSymbol(delegateCtor, manager.System_Object, 0, False, StringConstants.DelegateConstructorInstanceParameterName),
                           New AnonymousTypeOrDelegateParameterSymbol(delegateCtor, manager.System_IntPtr, 1, False, StringConstants.DelegateConstructorMethodParameterName)
                           ))
 
                Dim delegateBeginInvoke As SynthesizedDelegateMethodSymbol
                Dim delegateEndInvoke As SynthesizedDelegateMethodSymbol
 
                ' Don't add Begin/EndInvoke members to winmd compilations.
                ' Invoke must be the last member, regardless.
                If Me.IsCompilationOutputWinMdObj() Then
                    delegateBeginInvoke = Nothing
                    delegateEndInvoke = Nothing
                    _members = ImmutableArray.Create(delegateCtor, delegateInvoke)
                Else
                    ' (3) BeginInvoke
                    delegateBeginInvoke = New SynthesizedDelegateMethodSymbol(WellKnownMemberNames.DelegateBeginInvokeName,
                                                                                  Me,
                                                                                  SourceNamedTypeSymbol.DelegateCommonMethodFlags Or SourceMemberFlags.MethodKindOrdinary,
                                                                                  manager.System_IAsyncResult)
 
                    For i = 0 To delegateInvoke.ParameterCount - 1
                        Dim parameter As ParameterSymbol = delegateInvoke.Parameters(i)
                        parameters.Add(New AnonymousTypeOrDelegateParameterSymbol(delegateBeginInvoke, parameter.Type, i, parameter.IsByRef(), parameter.Name, i))
                    Next
 
                    parameters.Add(New AnonymousTypeOrDelegateParameterSymbol(delegateBeginInvoke, manager.System_AsyncCallback, i, False, StringConstants.DelegateMethodCallbackParameterName))
                    i += 1
                    parameters.Add(New AnonymousTypeOrDelegateParameterSymbol(delegateBeginInvoke, manager.System_Object, i, False, StringConstants.DelegateMethodInstanceParameterName))
                    delegateBeginInvoke.SetParameters(parameters.ToImmutable())
                    parameters.Clear()
 
                    ' and (4) EndInvoke methods
                    delegateEndInvoke = New SynthesizedDelegateMethodSymbol(WellKnownMemberNames.DelegateEndInvokeName,
                                                                                Me,
                                                                                SourceNamedTypeSymbol.DelegateCommonMethodFlags Or SourceMemberFlags.MethodKindOrdinary,
                                                                                returnType)
                    Dim ordinal As Integer = 0
                    For i = 0 To delegateInvoke.ParameterCount - 1
                        Dim parameter As ParameterSymbol = delegateInvoke.Parameters(i)
 
                        If parameter.IsByRef Then
                            parameters.Add(New AnonymousTypeOrDelegateParameterSymbol(delegateEndInvoke, parameter.Type, ordinal, parameter.IsByRef(), parameter.Name, i))
                            ordinal += 1
                        End If
                    Next
 
                    parameters.Add(New AnonymousTypeOrDelegateParameterSymbol(delegateEndInvoke, manager.System_IAsyncResult, ordinal, False, StringConstants.DelegateMethodResultParameterName))
                    delegateEndInvoke.SetParameters(parameters.ToImmutable())
 
                    _members = ImmutableArray.Create(delegateCtor, delegateBeginInvoke, delegateEndInvoke, delegateInvoke)
                End If
 
                Debug.Assert(_members.All(Function(m) m IsNot Nothing))
                parameters.Free()
            End Sub
 
            Friend Overrides Function GetAnonymousTypeKey() As AnonymousTypeKey
                Dim parameters = TypeDescr.Parameters.SelectAsArray(Function(p) New AnonymousTypeKeyField(p.Name, isKey:=p.IsByRef, ignoreCase:=True))
                Return New AnonymousTypeKey(parameters, isDelegate:=True)
            End Function
 
            Public Overrides Function GetMembers() As ImmutableArray(Of Symbol)
                Return StaticCast(Of Symbol).From(_members)
            End Function
 
            Friend NotOverridable Overrides Function GetFieldsToEmit() As IEnumerable(Of FieldSymbol)
                Return SpecializedCollections.EmptyEnumerable(Of FieldSymbol)()
            End Function
 
            Friend Overrides ReadOnly Property GeneratedNamePrefix As String
                Get
                    Return GeneratedNameConstants.AnonymousDelegateTemplateNamePrefix
                End Get
            End Property
 
            Friend Overrides Function MakeAcyclicBaseType(diagnostics As BindingDiagnosticBag) As NamedTypeSymbol
                Return Manager.System_MulticastDelegate
            End Function
 
            Friend Overrides Function MakeAcyclicInterfaces(diagnostics As BindingDiagnosticBag) As ImmutableArray(Of NamedTypeSymbol)
                Return ImmutableArray(Of NamedTypeSymbol).Empty
            End Function
 
            Public Overrides ReadOnly Property DelegateInvokeMethod As MethodSymbol
                Get
                    ' The invoke method is always the last method, in regular or winmd scenarios
                    Return _members(_members.Length - 1)
                End Get
            End Property
 
            Public Overrides ReadOnly Property TypeKind As TypeKind
                Get
                    Return TypeKind.Delegate
                End Get
            End Property
 
            Friend Overrides ReadOnly Property IsInterface As Boolean
                Get
                    Return False
                End Get
            End Property
 
            Friend Overrides Sub AddSynthesizedAttributes(moduleBuilder As PEModuleBuilder, ByRef attributes As ArrayBuilder(Of SynthesizedAttributeData))
                MyBase.AddSynthesizedAttributes(moduleBuilder, attributes)
 
                ' Attribute: System.Runtime.CompilerServices.CompilerGeneratedAttribute()
                AddSynthesizedAttribute(attributes, Manager.Compilation.TrySynthesizeAttribute(
                    WellKnownMember.System_Runtime_CompilerServices_CompilerGeneratedAttribute__ctor))
 
                ' Attribute: System.Diagnostics.DebuggerDisplayAttribute("<generated method>",Type := "<generated method>")
                Dim value As New TypedConstant(Manager.System_String, TypedConstantKind.Primitive, "<generated method>")
                AddSynthesizedAttribute(attributes, Manager.Compilation.TrySynthesizeAttribute(
                    WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__ctor,
                    ImmutableArray.Create(value),
                    ImmutableArray.Create(New KeyValuePair(Of WellKnownMember, TypedConstant)(
                        WellKnownMember.System_Diagnostics_DebuggerDisplayAttribute__Type, value))))
            End Sub
        End Class
 
        ''' <summary>
        ''' This is a symbol to represent Anonymous Delegate for a lambda
        ''' like:
        '''        Sub() ...
        ''' 
        ''' This delegate type doesn't have generic parameters. Unlike generic anonymous types,
        ''' for which we are constructing new instance of substituted symbol for each use site 
        ''' with reference to the location, we are creating new instance of this symbol with its
        ''' own location for each use site. But all of them are representing the same delegate 
        ''' type and are going to be equal to each other. 
        ''' </summary>
        Private NotInheritable Class NonGenericAnonymousDelegateSymbol
            Inherits AnonymousDelegateTemplateSymbol
 
            Public Sub New(manager As AnonymousTypeManager,
                           typeDescr As AnonymousTypeDescriptor)
                MyBase.New(manager, typeDescr)
                Debug.Assert(typeDescr.Parameters.Length = 1)
                Debug.Assert(typeDescr.Parameters.IsSubDescription())
            End Sub
 
            Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location)
                Get
                    Return ImmutableArray.Create(TypeDescr.Location)
                End Get
            End Property
 
            Public Overrides Function GetHashCode() As Integer
                Return Manager.GetHashCode()
            End Function
 
            Public Overrides Function Equals(obj As TypeSymbol, comparison As TypeCompareKind) As Boolean
                If obj Is Me Then
                    Return True
                End If
 
                Dim other = TryCast(obj, NonGenericAnonymousDelegateSymbol)
 
                Return other IsNot Nothing AndAlso other.Manager Is Me.Manager
            End Function
        End Class
 
    End Class
End Namespace