|
' Licensed to the .NET Foundation under one or more agreements.
' The .NET Foundation licenses this file to you under the MIT license.
' See the LICENSE file in the project root for more information.
Imports System.Collections.Immutable
Imports System.Runtime.InteropServices
Imports Microsoft.CodeAnalysis.PooledObjects
Imports Microsoft.CodeAnalysis.VisualBasic.Emit
Imports Microsoft.CodeAnalysis.VisualBasic.Symbols
Imports Microsoft.CodeAnalysis.VisualBasic.Syntax
Imports ReferenceEqualityComparer = Roslyn.Utilities.ReferenceEqualityComparer
Namespace Microsoft.CodeAnalysis.VisualBasic
Partial Friend NotInheritable Class LocalRewriter
Inherits BoundTreeRewriterWithStackGuard
Private ReadOnly _topMethod As MethodSymbol
Private ReadOnly _emitModule As PEModuleBuilder
Private ReadOnly _compilationState As TypeCompilationState
Private ReadOnly _previousSubmissionFields As SynthesizedSubmissionFields
Private ReadOnly _diagnostics As BindingDiagnosticBag
Private ReadOnly _instrumenterOpt As Instrumenter
Private _symbolsCapturedWithoutCopyCtor As ISet(Of Symbol)
Private _currentMethodOrLambda As MethodSymbol
Private _rangeVariableMap As Dictionary(Of RangeVariableSymbol, BoundExpression)
Private _placeholderReplacementMapDoNotUseDirectly As Dictionary(Of BoundValuePlaceholderBase, BoundExpression)
Private _hasLambdas As Boolean
Private _inExpressionLambda As Boolean ' Are we inside a lambda converted to expression tree?
Private _staticLocalMap As Dictionary(Of LocalSymbol, KeyValuePair(Of SynthesizedStaticLocalBackingField, SynthesizedStaticLocalBackingField))
Private _xmlFixupData As New XmlLiteralFixupData()
Private _xmlImportedNamespaces As ImmutableArray(Of KeyValuePair(Of String, String))
Private _unstructuredExceptionHandling As UnstructuredExceptionHandlingState
Private _currentLineTemporary As LocalSymbol
Private _instrumentTopLevelNonCompilerGeneratedExpressionsInQuery As Boolean
Private _conditionalAccessReceiverPlaceholderId As Integer
#If DEBUG Then
''' <summary>
''' A map from SyntaxNode to corresponding visited BoundStatement.
''' Used to ensure correct generation of resumable code for Unstructured Exception Handling.
''' </summary>
Private ReadOnly _unstructuredExceptionHandlingResumableStatements As New Dictionary(Of SyntaxNode, BoundStatement)(ReferenceEqualityComparer.Instance)
Private ReadOnly _leaveRestoreUnstructuredExceptionHandlingContextTracker As New Stack(Of BoundNode)()
#End If
#If DEBUG Then
''' <summary>
''' Used to prevent multiple rewrite of the same nodes.
''' </summary>
Private _rewrittenNodes As New HashSet(Of BoundNode)(ReferenceEqualityComparer.Instance)
#End If
''' <summary>
''' Returns substitution currently used by the rewriter for a placeholder node.
''' Each occurrence of the placeholder node is replaced with the node returned.
''' Throws if there is no substitution.
''' </summary>
Private ReadOnly Property PlaceholderReplacement(placeholder As BoundValuePlaceholderBase) As BoundExpression
Get
Dim value = _placeholderReplacementMapDoNotUseDirectly(placeholder)
AssertPlaceholderReplacement(placeholder, value)
Return value
End Get
End Property
<Conditional("DEBUG")>
Private Shared Sub AssertPlaceholderReplacement(placeholder As BoundValuePlaceholderBase, value As BoundExpression)
Debug.Assert(value.Type.IsSameTypeIgnoringAll(placeholder.Type))
If placeholder.IsLValue AndAlso value.Kind <> BoundKind.MeReference Then
Debug.Assert(value.IsLValue)
Else
value.AssertRValue()
End If
End Sub
''' <summary>
''' Sets substitution used by the rewriter for a placeholder node.
''' Each occurrence of the placeholder node is replaced with the node returned.
''' Throws if there is already a substitution.
''' </summary>
Private Sub AddPlaceholderReplacement(placeholder As BoundValuePlaceholderBase, value As BoundExpression)
AssertPlaceholderReplacement(placeholder, value)
If _placeholderReplacementMapDoNotUseDirectly Is Nothing Then
_placeholderReplacementMapDoNotUseDirectly = New Dictionary(Of BoundValuePlaceholderBase, BoundExpression)()
End If
_placeholderReplacementMapDoNotUseDirectly.Add(placeholder, value)
End Sub
''' <summary>
''' Replaces substitution currently used by the rewriter for a placeholder node with a different substitution.
''' Asserts if there isn't already a substitution.
''' </summary>
Private Sub UpdatePlaceholderReplacement(placeholder As BoundValuePlaceholderBase, value As BoundExpression)
AssertPlaceholderReplacement(placeholder, value)
Debug.Assert(_placeholderReplacementMapDoNotUseDirectly.ContainsKey(placeholder))
_placeholderReplacementMapDoNotUseDirectly(placeholder) = value
End Sub
''' <summary>
''' Removes substitution currently used by the rewriter for a placeholder node.
''' Asserts if there isn't already a substitution.
''' </summary>
Private Sub RemovePlaceholderReplacement(placeholder As BoundValuePlaceholderBase)
Debug.Assert(placeholder IsNot Nothing)
Dim removed As Boolean = _placeholderReplacementMapDoNotUseDirectly.Remove(placeholder)
Debug.Assert(removed)
End Sub
Private Sub New(
topMethod As MethodSymbol,
currentMethod As MethodSymbol,
compilationState As TypeCompilationState,
previousSubmissionFields As SynthesizedSubmissionFields,
diagnostics As BindingDiagnosticBag,
flags As RewritingFlags,
instrumenterOpt As Instrumenter,
recursionDepth As Integer
)
MyBase.New(recursionDepth)
Debug.Assert(diagnostics.AccumulatesDiagnostics)
Me._topMethod = topMethod
Me._currentMethodOrLambda = currentMethod
Me._emitModule = compilationState.ModuleBuilderOpt
Me._compilationState = compilationState
Me._previousSubmissionFields = previousSubmissionFields
Me._diagnostics = diagnostics
Me._flags = flags
Debug.Assert(instrumenterOpt IsNot Instrumenter.NoOp)
Me._instrumenterOpt = instrumenterOpt
End Sub
Public ReadOnly Property OptimizationLevelIsDebug As Boolean
Get
Return Me.Compilation.Options.OptimizationLevel = OptimizationLevel.Debug
End Get
End Property
Private Shared Function RewriteNode(
node As BoundNode,
topMethod As MethodSymbol,
currentMethod As MethodSymbol,
compilationState As TypeCompilationState,
previousSubmissionFields As SynthesizedSubmissionFields,
diagnostics As BindingDiagnosticBag,
<[In], Out> ByRef rewrittenNodes As HashSet(Of BoundNode),
<Out> ByRef hasLambdas As Boolean,
<Out> ByRef symbolsCapturedWithoutCtor As ISet(Of Symbol),
flags As RewritingFlags,
instrumenterOpt As Instrumenter,
recursionDepth As Integer
) As BoundNode
Debug.Assert(node Is Nothing OrElse Not node.HasErrors, "node has errors")
Dim rewriter = New LocalRewriter(topMethod, currentMethod, compilationState, previousSubmissionFields, diagnostics, flags, instrumenterOpt, recursionDepth)
#If DEBUG Then
If rewrittenNodes IsNot Nothing Then
rewriter._rewrittenNodes = rewrittenNodes
Else
rewrittenNodes = rewriter._rewrittenNodes
End If
Debug.Assert(rewriter._leaveRestoreUnstructuredExceptionHandlingContextTracker.Count = 0)
#End If
Dim result As BoundNode = rewriter.Visit(node)
If Not rewriter._xmlFixupData.IsEmpty Then
result = InsertXmlLiteralsPreamble(result, rewriter._xmlFixupData.MaterializeAndFree())
End If
hasLambdas = rewriter._hasLambdas
symbolsCapturedWithoutCtor = rewriter._symbolsCapturedWithoutCopyCtor
Return result
End Function
Private Shared Function InsertXmlLiteralsPreamble(node As BoundNode, fixups As ImmutableArray(Of XmlLiteralFixupData.LocalWithInitialization)) As BoundBlock
Dim count As Integer = fixups.Length
Debug.Assert(count > 0)
Dim locals(count - 1) As LocalSymbol
Dim sideEffects(count) As BoundStatement
For i = 0 To count - 1
Dim fixup As XmlLiteralFixupData.LocalWithInitialization = fixups(i)
locals(i) = fixup.Local
Dim init As BoundExpression = fixup.Initialization
sideEffects(i) = New BoundExpressionStatement(init.Syntax, init)
Next
sideEffects(count) = DirectCast(node, BoundStatement)
Return New BoundBlock(node.Syntax, Nothing, locals.AsImmutable, sideEffects.AsImmutableOrNull)
End Function
Public Shared Function Rewrite(
node As BoundBlock,
topMethod As MethodSymbol,
compilationState As TypeCompilationState,
previousSubmissionFields As SynthesizedSubmissionFields,
diagnostics As BindingDiagnosticBag,
<Out> ByRef rewrittenNodes As HashSet(Of BoundNode),
<Out> ByRef hasLambdas As Boolean,
<Out> ByRef symbolsCapturedWithoutCopyCtor As ISet(Of Symbol),
flags As RewritingFlags,
instrumenterOpt As Instrumenter,
currentMethod As MethodSymbol
) As BoundBlock
Debug.Assert(rewrittenNodes Is Nothing)
Return DirectCast(RewriteNode(node,
topMethod,
If(currentMethod, topMethod),
compilationState,
previousSubmissionFields,
diagnostics,
rewrittenNodes,
hasLambdas,
symbolsCapturedWithoutCopyCtor,
flags,
instrumenterOpt,
recursionDepth:=0), BoundBlock)
End Function
Public Shared Function RewriteExpressionTree(node As BoundExpression,
method As MethodSymbol,
compilationState As TypeCompilationState,
previousSubmissionFields As SynthesizedSubmissionFields,
diagnostics As BindingDiagnosticBag,
rewrittenNodes As HashSet(Of BoundNode),
recursionDepth As Integer) As BoundExpression
Debug.Assert(rewrittenNodes IsNot Nothing)
Dim hasLambdas As Boolean = False
Dim result = DirectCast(RewriteNode(node,
method,
method,
compilationState,
previousSubmissionFields,
diagnostics,
rewrittenNodes,
hasLambdas,
SpecializedCollections.EmptySet(Of Symbol),
RewritingFlags.Default,
instrumenterOpt:=Nothing, ' don't do any instrumentation in expression tree lambdas
recursionDepth:=recursionDepth), BoundExpression)
Debug.Assert(Not hasLambdas)
Return result
End Function
Public Overrides Function Visit(node As BoundNode) As BoundNode
Debug.Assert(node Is Nothing OrElse Not node.HasErrors, "node has errors")
Dim expressionNode = TryCast(node, BoundExpression)
If expressionNode IsNot Nothing Then
Return VisitExpression(expressionNode)
Else
#If DEBUG Then
Debug.Assert(node Is Nothing OrElse Not _rewrittenNodes.Contains(node), "LocalRewriter: Rewriting the same node several times.")
#End If
Dim result = MyBase.Visit(node)
#If DEBUG Then
If result IsNot Nothing Then
If result Is node Then
result = result.MemberwiseClone(Of BoundNode)()
End If
_rewrittenNodes.Add(result)
End If
#End If
Return result
End If
End Function
Private Function VisitExpression(node As BoundExpression) As BoundExpression
#If DEBUG Then
Debug.Assert(Not _rewrittenNodes.Contains(node), "LocalRewriter: Rewriting the same node several times.")
Dim originalNode = node
#End If
Dim constantValue = node.ConstantValueOpt
Dim result As BoundExpression
Dim instrumentExpressionInQuery As Boolean =
_instrumentTopLevelNonCompilerGeneratedExpressionsInQuery AndAlso
Instrument AndAlso
Not node.WasCompilerGenerated AndAlso
node.Syntax.Kind <> SyntaxKind.GroupAggregation AndAlso
((node.Syntax.Kind = SyntaxKind.SimpleAsClause AndAlso node.Syntax.Parent.Kind = SyntaxKind.CollectionRangeVariable) OrElse
TypeOf node.Syntax Is ExpressionSyntax)
If instrumentExpressionInQuery Then
_instrumentTopLevelNonCompilerGeneratedExpressionsInQuery = False
End If
If constantValue IsNot Nothing Then
result = RewriteConstant(node, constantValue)
Else
result = VisitExpressionWithStackGuard(node)
End If
If instrumentExpressionInQuery Then
_instrumentTopLevelNonCompilerGeneratedExpressionsInQuery = True
result = _instrumenterOpt.InstrumentTopLevelExpressionInQuery(node, result)
End If
#If DEBUG Then
Debug.Assert(node.IsLValue = result.IsLValue OrElse
(result.Kind = BoundKind.MeReference AndAlso TypeOf node Is BoundLValuePlaceholderBase))
If node.Type Is Nothing Then
Debug.Assert(result.Type Is Nothing)
Else
Debug.Assert(result.Type IsNot Nothing)
If (node.Kind = BoundKind.ObjectCreationExpression OrElse node.Kind = BoundKind.NewT) AndAlso
DirectCast(node, BoundObjectCreationExpressionBase).InitializerOpt IsNot Nothing AndAlso
DirectCast(node, BoundObjectCreationExpressionBase).InitializerOpt.Kind = BoundKind.ObjectInitializerExpression AndAlso
Not DirectCast(DirectCast(node, BoundObjectCreationExpressionBase).InitializerOpt, BoundObjectInitializerExpression).CreateTemporaryLocalForInitialization Then
Debug.Assert(result.Type.IsVoidType())
Else
Debug.Assert(result.Type.IsSameTypeIgnoringAll(node.Type))
End If
End If
#End If
#If DEBUG Then
If result Is originalNode Then
Select Case result.Kind
Case BoundKind.LValuePlaceholder,
BoundKind.RValuePlaceholder,
BoundKind.WithLValueExpressionPlaceholder,
BoundKind.WithRValueExpressionPlaceholder
' do not clone these as they have special semantics and may
' be used for identity search after local rewriter is finished
Case Else
result = result.MemberwiseClone(Of BoundExpression)()
End Select
End If
_rewrittenNodes.Add(result)
#End If
Return result
End Function
Private ReadOnly Property Compilation As VisualBasicCompilation
Get
Return Me._topMethod.DeclaringCompilation
End Get
End Property
Private ReadOnly Property ContainingAssembly As SourceAssemblySymbol
Get
Return DirectCast(Me._topMethod.ContainingAssembly, SourceAssemblySymbol)
End Get
End Property
Private ReadOnly Property Instrument As Boolean
Get
Return _instrumenterOpt IsNot Nothing AndAlso Not _inExpressionLambda
End Get
End Property
Private ReadOnly Property Instrument(original As BoundNode, rewritten As BoundNode) As Boolean
Get
Return Me.Instrument AndAlso rewritten IsNot Nothing AndAlso (Not original.WasCompilerGenerated) AndAlso original.Syntax IsNot Nothing
End Get
End Property
Private ReadOnly Property Instrument(original As BoundNode) As Boolean
Get
Return Me.Instrument AndAlso (Not original.WasCompilerGenerated) AndAlso original.Syntax IsNot Nothing
End Get
End Property
Private Shared Function Concat(statement As BoundStatement, additionOpt As BoundStatement) As BoundStatement
If additionOpt Is Nothing Then
Return statement
End If
Dim block = TryCast(statement, BoundBlock)
If block IsNot Nothing Then
Dim consequenceWithEnd(block.Statements.Length) As BoundStatement
For i = 0 To block.Statements.Length - 1
consequenceWithEnd(i) = block.Statements(i)
Next
consequenceWithEnd(block.Statements.Length) = additionOpt
Return block.Update(block.StatementListSyntax, block.Locals, consequenceWithEnd.AsImmutableOrNull)
Else
Dim consequenceWithEnd(1) As BoundStatement
consequenceWithEnd(0) = statement
consequenceWithEnd(1) = additionOpt
Return New BoundStatementList(statement.Syntax, consequenceWithEnd.AsImmutableOrNull)
End If
End Function
Private Shared Function AppendToBlock(block As BoundBlock, additionOpt As BoundStatement) As BoundBlock
If additionOpt Is Nothing Then
Return block
End If
Dim consequenceWithEnd(block.Statements.Length) As BoundStatement
For i = 0 To block.Statements.Length - 1
consequenceWithEnd(i) = block.Statements(i)
Next
consequenceWithEnd(block.Statements.Length) = additionOpt
Return block.Update(block.StatementListSyntax, block.Locals, consequenceWithEnd.AsImmutableOrNull)
End Function
''' <summary>
''' Adds a prologue before stepping on the statement
''' NOTE: if the statement is a block the prologue will be outside of the scope
''' </summary>
Private Shared Function PrependWithPrologue(statement As BoundStatement, prologueOpt As BoundStatement) As BoundStatement
If prologueOpt Is Nothing Then
Return statement
End If
Return New BoundStatementList(statement.Syntax, ImmutableArray.Create(prologueOpt, statement))
End Function
Private Shared Function PrependWithPrologue(block As BoundBlock, prologueOpt As BoundStatement) As BoundBlock
If prologueOpt Is Nothing Then
Return block
End If
Return New BoundBlock(
block.Syntax,
Nothing,
ImmutableArray(Of LocalSymbol).Empty,
ImmutableArray.Create(Of BoundStatement)(prologueOpt, block))
End Function
Public Overrides Function VisitSequencePointWithSpan(node As BoundSequencePointWithSpan) As BoundNode
' NOTE: Sequence points may not be inserted in by binder, but they may be inserted when
' NOTE: code is being synthesized. In some cases, e.g. in Async rewriter and for expression
' NOTE: trees, we rewrite the tree the second time, so RewritingFlags.AllowSequencePoints
' NOTE: should be set to make sure we don't assert and rewrite the statement properly.
' NOTE: GenerateDebugInfo in this case should be False as all sequence points are
' NOTE: supposed to be generated by this time
Debug.Assert((Me._flags And RewritingFlags.AllowSequencePoints) <> 0 AndAlso _instrumenterOpt Is Nothing, "are we trying to rewrite a node more than once?")
Return node.Update(DirectCast(Me.Visit(node.StatementOpt), BoundStatement), node.Span)
End Function
Public Overrides Function VisitSequencePoint(node As BoundSequencePoint) As BoundNode
' NOTE: Sequence points may not be inserted in by binder, but they may be inserted when
' NOTE: code is being synthesized. In some cases, e.g. in Async rewriter and for expression
' NOTE: trees, we rewrite the tree the second time, so RewritingFlags.AllowSequencePoints
' NOTE: should be set to make sure we don't assert and rewrite the statement properly.
' NOTE: GenerateDebugInfo in this case should be False as all sequence points are
' NOTE: supposed to be generated by this time
Debug.Assert((Me._flags And RewritingFlags.AllowSequencePoints) <> 0 AndAlso _instrumenterOpt Is Nothing, "are we trying to rewrite a node more than once?")
Return node.Update(DirectCast(Me.Visit(node.StatementOpt), BoundStatement))
End Function
Public Overrides Function VisitBadExpression(node As BoundBadExpression) As BoundNode
' Cannot recurse into BadExpression children since the BadExpression
' may represent being unable to use the child as an lvalue or rvalue.
Throw ExceptionUtilities.Unreachable
End Function
Private Function RewriteReceiverArgumentsAndGenerateAccessorCall(
syntax As SyntaxNode,
methodSymbol As MethodSymbol,
receiverOpt As BoundExpression,
arguments As ImmutableArray(Of BoundExpression),
constantValueOpt As ConstantValue,
isLValue As Boolean,
suppressObjectClone As Boolean,
type As TypeSymbol
) As BoundExpression
UpdateMethodAndArgumentsIfReducedFromMethod(methodSymbol, receiverOpt, arguments)
Dim temporaries As ImmutableArray(Of SynthesizedLocal) = Nothing
Dim copyBack As ImmutableArray(Of BoundExpression) = Nothing
receiverOpt = VisitExpressionNode(receiverOpt)
arguments = RewriteCallArguments(arguments, methodSymbol.Parameters, temporaries, copyBack, False)
Debug.Assert(copyBack.IsDefault, "no copyback expected in accessors")
Dim result As BoundExpression = New BoundCall(syntax,
methodSymbol,
Nothing,
receiverOpt,
arguments,
constantValueOpt,
isLValue:=isLValue,
suppressObjectClone:=suppressObjectClone,
type:=type)
If Not temporaries.IsDefault Then
If methodSymbol.IsSub Then
result = New BoundSequence(syntax,
StaticCast(Of LocalSymbol).From(temporaries),
ImmutableArray.Create(result),
Nothing,
result.Type)
Else
result = New BoundSequence(syntax,
StaticCast(Of LocalSymbol).From(temporaries),
ImmutableArray(Of BoundExpression).Empty,
result,
result.Type)
End If
End If
Return result
End Function
' Generate a unique label with the given base name
Private Shared Function GenerateLabel(baseName As String) As LabelSymbol
Return New GeneratedLabelSymbol(baseName)
End Function
Public Overrides Function VisitRValuePlaceholder(node As BoundRValuePlaceholder) As BoundNode
Return PlaceholderReplacement(node)
End Function
Public Overrides Function VisitLValuePlaceholder(node As BoundLValuePlaceholder) As BoundNode
Return PlaceholderReplacement(node)
End Function
Public Overrides Function VisitCompoundAssignmentTargetPlaceholder(node As BoundCompoundAssignmentTargetPlaceholder) As BoundNode
Return PlaceholderReplacement(node)
End Function
Public Overrides Function VisitByRefArgumentPlaceholder(node As BoundByRefArgumentPlaceholder) As BoundNode
Return PlaceholderReplacement(node)
End Function
Public Overrides Function VisitLValueToRValueWrapper(node As BoundLValueToRValueWrapper) As BoundNode
Dim rewritten As BoundExpression = VisitExpressionNode(node.UnderlyingLValue)
Return rewritten.MakeRValue()
End Function
''' <summary>
''' Gets the special type.
''' </summary>
''' <param name="specialType">Special Type to get.</param><returns></returns>
Private Function GetSpecialType(specialType As SpecialType) As NamedTypeSymbol
Dim result As NamedTypeSymbol = Me._topMethod.ContainingAssembly.GetSpecialType(specialType)
Debug.Assert(Binder.GetUseSiteInfoForSpecialType(result).DiagnosticInfo Is Nothing)
Return result
End Function
Private Function GetSpecialTypeWithUseSiteDiagnostics(specialType As SpecialType, syntax As SyntaxNode) As NamedTypeSymbol
Dim result As NamedTypeSymbol = Me._topMethod.ContainingAssembly.GetSpecialType(specialType)
Dim info = Binder.GetUseSiteInfoForSpecialType(result)
Binder.ReportUseSite(_diagnostics, syntax, info)
Return result
End Function
''' <summary>
''' Gets the special type member.
''' </summary>
''' <param name="specialMember">Member of the special type.</param><returns></returns>
Private Function GetSpecialTypeMember(specialMember As SpecialMember) As Symbol
Return Me._topMethod.ContainingAssembly.GetSpecialTypeMember(specialMember)
End Function
''' <summary>
''' Checks for special member and reports diagnostics if the member is Nothing or has UseSiteError.
''' Returns True in case diagnostics was actually reported
''' </summary>
Private Function ReportMissingOrBadRuntimeHelper(node As BoundNode, specialMember As SpecialMember, memberSymbol As Symbol) As Boolean
Return ReportMissingOrBadRuntimeHelper(node, specialMember, memberSymbol, Me._diagnostics, _compilationState.Compilation.Options.EmbedVbCoreRuntime)
End Function
''' <summary>
''' Checks for special member and reports diagnostics if the member is Nothing or has UseSiteError.
''' Returns True in case diagnostics was actually reported
''' </summary>
Friend Shared Function ReportMissingOrBadRuntimeHelper(node As BoundNode, specialMember As SpecialMember, memberSymbol As Symbol, diagnostics As BindingDiagnosticBag, Optional embedVBCoreRuntime As Boolean = False) As Boolean
If memberSymbol Is Nothing Then
ReportMissingRuntimeHelper(node, specialMember, diagnostics, embedVBCoreRuntime)
Return True
Else
Return ReportUseSite(node, Binder.GetUseSiteInfoForMemberAndContainingType(memberSymbol), diagnostics)
End If
End Function
Private Shared Sub ReportMissingRuntimeHelper(node As BoundNode, specialMember As SpecialMember, diagnostics As BindingDiagnosticBag, Optional embedVBCoreRuntime As Boolean = False)
Dim descriptor = SpecialMembers.GetDescriptor(specialMember)
' TODO: If the type is generic, we might want to use VB style name rather than emitted name.
Dim typeName As String = descriptor.DeclaringTypeMetadataName
Dim memberName As String = descriptor.Name
ReportMissingRuntimeHelper(node, typeName, memberName, diagnostics, embedVBCoreRuntime)
End Sub
''' <summary>
''' Checks for well known member and reports diagnostics if the member is Nothing or has UseSiteError.
''' Returns True in case diagnostics was actually reported
''' </summary>
Private Function ReportMissingOrBadRuntimeHelper(node As BoundNode, wellKnownMember As WellKnownMember, memberSymbol As Symbol) As Boolean
Return ReportMissingOrBadRuntimeHelper(node, wellKnownMember, memberSymbol, Me._diagnostics, _compilationState.Compilation.Options.EmbedVbCoreRuntime)
End Function
''' <summary>
''' Checks for well known member and reports diagnostics if the member is Nothing or has UseSiteError.
''' Returns True in case diagnostics was actually reported
''' </summary>
Friend Shared Function ReportMissingOrBadRuntimeHelper(node As BoundNode, wellKnownMember As WellKnownMember, memberSymbol As Symbol, diagnostics As BindingDiagnosticBag, embedVBCoreRuntime As Boolean) As Boolean
If memberSymbol Is Nothing Then
ReportMissingRuntimeHelper(node, wellKnownMember, diagnostics, embedVBCoreRuntime)
Return True
Else
Return ReportUseSite(node, Binder.GetUseSiteInfoForMemberAndContainingType(memberSymbol), diagnostics)
End If
End Function
Private Shared Sub ReportMissingRuntimeHelper(node As BoundNode, wellKnownMember As WellKnownMember, diagnostics As BindingDiagnosticBag, embedVBCoreRuntime As Boolean)
Dim descriptor = WellKnownMembers.GetDescriptor(wellKnownMember)
' TODO: If the type is generic, we might want to use VB style name rather than emitted name.
Dim typeName As String = descriptor.DeclaringTypeMetadataName
Dim memberName As String = descriptor.Name
ReportMissingRuntimeHelper(node, typeName, memberName, diagnostics, embedVBCoreRuntime)
End Sub
Private Shared Sub ReportMissingRuntimeHelper(node As BoundNode, typeName As String, memberName As String, diagnostics As BindingDiagnosticBag, embedVBCoreRuntime As Boolean)
If memberName.Equals(WellKnownMemberNames.InstanceConstructorName) OrElse memberName.Equals(WellKnownMemberNames.StaticConstructorName) Then
memberName = "New"
End If
Dim diag As DiagnosticInfo
diag = GetDiagnosticForMissingRuntimeHelper(typeName, memberName, embedVBCoreRuntime)
ReportDiagnostic(node, diag, diagnostics)
End Sub
Private Shared Sub ReportDiagnostic(node As BoundNode, diagnostic As DiagnosticInfo, diagnostics As BindingDiagnosticBag)
diagnostics.Add(New VBDiagnostic(diagnostic, node.Syntax.GetLocation()))
End Sub
Private Shared Function ReportUseSite(node As BoundNode, useSiteInfo As UseSiteInfo(Of AssemblySymbol), diagnostics As BindingDiagnosticBag) As Boolean
Return diagnostics.Add(useSiteInfo, node.Syntax.GetLocation())
End Function
Private Sub ReportBadType(node As BoundNode, typeSymbol As TypeSymbol)
ReportUseSite(node, typeSymbol.GetUseSiteInfo(), Me._diagnostics)
End Sub
''
'' The following nodes should be removed from the tree.
''
Public Overrides Function VisitMethodGroup(node As BoundMethodGroup) As BoundNode
Return Nothing
End Function
Public Overrides Function VisitParenthesized(node As BoundParenthesized) As BoundNode
Debug.Assert(Not node.IsLValue)
Dim enclosed = VisitExpressionNode(node.Expression)
If enclosed.IsLValue Then
enclosed = enclosed.MakeRValue()
End If
Return enclosed
End Function
''' <summary>
''' If value is const, returns the value unchanged.
'''
''' In a case if value is not a const, a proxy temp is created and added to "locals"
''' In addition to that, code that evaluates and stores the value is added to "expressions"
''' The access expression to the proxy temp is returned.
''' </summary>
Private Shared Function CacheToLocalIfNotConst(container As Symbol,
value As BoundExpression,
locals As ArrayBuilder(Of LocalSymbol),
expressions As ArrayBuilder(Of BoundExpression),
kind As SynthesizedLocalKind,
syntaxOpt As StatementSyntax) As BoundExpression
Debug.Assert(container IsNot Nothing)
Debug.Assert(locals IsNot Nothing)
Debug.Assert(expressions IsNot Nothing)
Debug.Assert(kind = SynthesizedLocalKind.LoweringTemp OrElse syntaxOpt IsNot Nothing)
Dim constValue As ConstantValue = value.ConstantValueOpt
If constValue IsNot Nothing Then
If Not value.Type.IsDecimalType() Then
Return value
End If
Select Case constValue.DecimalValue
Case Decimal.MinusOne, Decimal.Zero, Decimal.One
Return value
End Select
End If
Dim local = New SynthesizedLocal(container, value.Type, kind, syntaxOpt)
locals.Add(local)
Dim localAccess = New BoundLocal(value.Syntax, local, local.Type)
Dim valueStore = New BoundAssignmentOperator(
value.Syntax,
localAccess,
value,
suppressObjectClone:=True,
type:=localAccess.Type
).MakeCompilerGenerated
expressions.Add(valueStore)
Return localAccess.MakeRValue()
End Function
''' <summary>
''' Helper method to create a bound sequence to represent the idea:
''' "compute this value, and then compute this side effects while discarding results"
'''
''' A Bound sequence is generated for the provided expr and side-effects, say {se1, se2, se3}, as follows:
'''
''' If expr is of void type:
''' BoundSequence { side-effects: { expr, se1, se2, se3 }, valueOpt: Nothing }
'''
''' ElseIf expr is a constant:
''' BoundSequence { side-effects: { se1, se2, se3 }, valueOpt: expr }
'''
''' Else
''' BoundSequence { side-effects: { tmp = expr, se1, se2, se3 }, valueOpt: tmp }
''' </summary>
''' <remarks>
''' NOTE: Supporting cases where side-effects change the value (or to detect such cases)
''' NOTE: could be complicated. We do not support this currently and instead require
''' NOTE: value expr to be not LValue.
''' </remarks>
Friend Shared Function GenerateSequenceValueSideEffects(container As Symbol,
value As BoundExpression,
temporaries As ImmutableArray(Of LocalSymbol),
sideEffects As ImmutableArray(Of BoundExpression)) As BoundExpression
Debug.Assert(container IsNot Nothing)
Debug.Assert(Not value.IsLValue)
Debug.Assert(value.Type IsNot Nothing)
Dim syntax = value.Syntax
Dim type = value.Type
Dim temporariesBuilder = ArrayBuilder(Of LocalSymbol).GetInstance
If Not temporaries.IsEmpty Then
temporariesBuilder.AddRange(temporaries)
End If
Dim sideEffectsBuilder = ArrayBuilder(Of BoundExpression).GetInstance
Dim valueOpt As BoundExpression
If type.SpecialType = SpecialType.System_Void Then
sideEffectsBuilder.Add(value)
valueOpt = Nothing
Else
valueOpt = CacheToLocalIfNotConst(container, value, temporariesBuilder, sideEffectsBuilder, SynthesizedLocalKind.LoweringTemp, syntaxOpt:=Nothing)
Debug.Assert(Not valueOpt.IsLValue)
End If
If Not sideEffects.IsDefaultOrEmpty Then
sideEffectsBuilder.AddRange(sideEffects)
End If
Return New BoundSequence(syntax,
locals:=temporariesBuilder.ToImmutableAndFree(),
sideEffects:=sideEffectsBuilder.ToImmutableAndFree(),
valueOpt:=valueOpt,
type:=type)
End Function
''' <summary>
''' Helper function that visits the given expression and returns a BoundExpression.
''' Please use this instead of DirectCast(Visit(expression), BoundExpression)
''' </summary>
Private Function VisitExpressionNode(expression As BoundExpression) As BoundExpression
Return DirectCast(Visit(expression), BoundExpression)
End Function
Public Overrides Function VisitAwaitOperator(node As BoundAwaitOperator) As BoundNode
If Not _inExpressionLambda Then
' Await operator expression will be rewritten in AsyncRewriter, to do
' so we need to keep placeholders unchanged in the bound Await operator
Dim awaiterInstancePlaceholder As BoundLValuePlaceholder = node.AwaiterInstancePlaceholder
Dim awaitableInstancePlaceholder As BoundRValuePlaceholder = node.AwaitableInstancePlaceholder
Debug.Assert(awaiterInstancePlaceholder IsNot Nothing)
Debug.Assert(awaitableInstancePlaceholder IsNot Nothing)
#If DEBUG Then
Me.AddPlaceholderReplacement(awaiterInstancePlaceholder,
awaiterInstancePlaceholder.MemberwiseClone(Of BoundExpression))
Me.AddPlaceholderReplacement(awaitableInstancePlaceholder,
awaitableInstancePlaceholder.MemberwiseClone(Of BoundExpression))
#Else
Me.AddPlaceholderReplacement(awaiterInstancePlaceholder, awaiterInstancePlaceholder)
Me.AddPlaceholderReplacement(awaitableInstancePlaceholder, awaitableInstancePlaceholder)
#End If
Dim result = MyBase.VisitAwaitOperator(node)
Me.RemovePlaceholderReplacement(awaiterInstancePlaceholder)
Me.RemovePlaceholderReplacement(awaitableInstancePlaceholder)
Return result
End If
Return node
End Function
Public Overrides Function VisitStopStatement(node As BoundStopStatement) As BoundNode
Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics)
Dim break As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.System_Diagnostics_Debugger__Break)
Dim rewritten As BoundStatement = node
If break IsNot Nothing Then
' Later in the codegen phase (see EmitExpression.vb), we need to insert a nop after the call to System.Diagnostics.Debugger.Break(),
' so the debugger can determine the current instruction pointer properly. In oder to do so, we do not mark this node as compiler generated.
Dim boundNode = New BoundCall(
nodeFactory.Syntax,
break,
Nothing,
Nothing,
ImmutableArray(Of BoundExpression).Empty,
Nothing,
isLValue:=False,
suppressObjectClone:=True,
type:=break.ReturnType)
rewritten = boundNode.ToStatement()
End If
If ShouldGenerateUnstructuredExceptionHandlingResumeCode(node) Then
rewritten = RegisterUnstructuredExceptionHandlingResumeTarget(node.Syntax, rewritten, canThrow:=True)
End If
If Instrument(node, rewritten) Then
rewritten = _instrumenterOpt.InstrumentStopStatement(node, rewritten)
End If
Return rewritten
End Function
Public Overrides Function VisitEndStatement(node As BoundEndStatement) As BoundNode
Dim nodeFactory As New SyntheticBoundNodeFactory(_topMethod, _currentMethodOrLambda, node.Syntax, _compilationState, _diagnostics)
Dim endApp As MethodSymbol = nodeFactory.WellKnownMember(Of MethodSymbol)(WellKnownMember.Microsoft_VisualBasic_CompilerServices_ProjectData__EndApp)
Dim rewritten As BoundStatement = node
If endApp IsNot Nothing Then
rewritten = nodeFactory.Call(Nothing, endApp, ImmutableArray(Of BoundExpression).Empty).ToStatement()
End If
If Instrument(node, rewritten) Then
rewritten = _instrumenterOpt.InstrumentEndStatement(node, rewritten)
End If
Return rewritten
End Function
Public Overrides Function VisitGetType(node As BoundGetType) As BoundNode
Debug.Assert(node.Type.ExtendedSpecialType = InternalSpecialType.System_Type OrElse
TypeSymbol.Equals(node.Type, Compilation.GetWellKnownType(WellKnownType.System_Type), TypeCompareKind.AllIgnoreOptionsForVB))
Dim result = DirectCast(MyBase.VisitGetType(node), BoundGetType)
' Emit needs this method.
Dim tryGetResult As Boolean
Dim getTypeFromHandle As MethodSymbol = Nothing
If node.Type.ExtendedSpecialType = InternalSpecialType.System_Type Then
tryGetResult = TryGetSpecialMember(Of MethodSymbol)(getTypeFromHandle, SpecialMember.System_Type__GetTypeFromHandle, node.Syntax)
Else
tryGetResult = TryGetWellknownMember(Of MethodSymbol)(getTypeFromHandle, WellKnownMember.System_Type__GetTypeFromHandle, node.Syntax)
End If
If Not tryGetResult Then
Return New BoundGetType(result.Syntax, result.SourceType, getTypeFromHandle:=Nothing, result.Type, hasErrors:=True)
End If
Debug.Assert(TypeSymbol.Equals(result.Type, getTypeFromHandle.ReturnType, TypeCompareKind.AllIgnoreOptionsForVB))
Return New BoundGetType(result.Syntax, result.SourceType, getTypeFromHandle, result.Type)
End Function
Public Overrides Function VisitArrayCreation(node As BoundArrayCreation) As BoundNode
' Drop ArrayLiteralOpt
Return MyBase.VisitArrayCreation(node.Update(node.IsParamArrayArgument,
node.Bounds,
node.InitializerOpt,
Nothing,
Nothing,
node.Type))
End Function
End Class
End Namespace
|