| File: Lowering\LocalRewriter\LocalRewriter_AsNewLocalDeclarations.vb | Web Access |
| Project: src\roslyn\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.Diagnostics Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend NotInheritable Class LocalRewriter Public Overrides Function VisitAsNewLocalDeclarations(node As BoundAsNewLocalDeclarations) As BoundNode Dim builder = ArrayBuilder(Of BoundStatement).GetInstance() Dim localDeclarations = node.LocalDeclarations For declarationIndex = 0 To localDeclarations.Length - 1 Dim localDeclaration = localDeclarations(declarationIndex) Debug.Assert(localDeclaration.InitializerOpt Is Nothing) Dim rewrittenInitializer As BoundNode Dim localSymbol = localDeclaration.LocalSymbol Dim staticLocalBackingFields As KeyValuePair(Of SynthesizedStaticLocalBackingField, SynthesizedStaticLocalBackingField) = Nothing If localSymbol.IsStatic Then staticLocalBackingFields = CreateBackingFieldsForStaticLocal(localSymbol, hasInitializer:=True) End If Dim initializerToRewrite As BoundExpression If declarationIndex = 0 Then initializerToRewrite = node.Initializer Else ' For all variables except the first one we rebind the initializer ' and throw away diagnostics, those are supposed to be reported in the first ' binding and don't need to be duplicated as Dev10/11 does ' ' Note that we have to rebind the initializers because current implementation of lambda ' rewriter does not handle correctly blocks and locals which are reused in bound tree. ' Actually it seems to heavily rely on an assumption that the bound tree is a tree, not ' a DAG, with just minor deviations. Thus, the natural way of just rewriting bound ' initializer stored in node.Initializer simply does not work because rewriting *may* ' keep many blocks and locals unchanged and reuse them in all rewritten initializers, ' in which case if we have a lambda inside the initializer lambda rewriter simply throws. ' ' Another option to satisfy lambda rewriter would be to deep-clone bound tree, but ' in this case we will also have to clone all locals and all references to locals. ' We might want to look into this option later. Debug.Assert(node.Syntax IsNot Nothing) Debug.Assert(node.Syntax.Kind = SyntaxKind.VariableDeclarator) Dim varDecl = DirectCast(node.Syntax, VariableDeclaratorSyntax) Dim asNew = DirectCast(varDecl.AsClause, AsNewClauseSyntax) ' Rebind and discard diagnostics initializerToRewrite = node.Binder.BindVariableDeclaration(varDecl, varDecl.Names(declarationIndex), asNew, Nothing, BindingDiagnosticBag.Discarded, skipAsNewInitializer:=False).InitializerOpt End If ' The initializer expression may contain placeholder values and typically they are replaced with bound locals that ' get created in the local rewriter when rewriting the expression. ' ' There is one case where the placeholder does not get replaced by a bound temporary and needs to be replaced by ' the currently declared local. This is the case for an object creation expression with a object initializer if it's ' used in an AsNew declaration and the type is a value type, e.g.: ' Dim x As New ValType() With {...} ' or ' Dim x, y As New ValType() With {...} ' Because only this method knows the bound local that the placeholder will be replaced with, we need to fill ' the replacement map here, before rewriting the local declaration (there is a special case, because the first ' example will be bound to a BoundLocalDeclaration, see LocalRewriter.VisitLocalDeclaration for the special case). ' Dim objectInitializer As BoundObjectInitializerExpression = GetBoundObjectInitializerFromInitializer(initializerToRewrite) ' rewrite the initializer for each declared variable because the initializer may contain placeholders that need ' to be replaced with the current bound local If objectInitializer IsNot Nothing Then Debug.Assert(objectInitializer.PlaceholderOpt IsNot Nothing) Dim placeholder As BoundWithLValueExpressionPlaceholder = objectInitializer.PlaceholderOpt If Not objectInitializer.CreateTemporaryLocalForInitialization Then AddPlaceholderReplacement(placeholder, VisitExpressionNode(New BoundLocal(localDeclaration.Syntax, localSymbol, localSymbol.Type))) End If rewrittenInitializer = Me.VisitAndGenerateObjectCloneIfNeeded(initializerToRewrite) If Not objectInitializer.CreateTemporaryLocalForInitialization Then RemovePlaceholderReplacement(placeholder) End If Else rewrittenInitializer = Me.VisitAndGenerateObjectCloneIfNeeded(initializerToRewrite) End If Dim initialization = RewriteLocalDeclarationAsInitializer( localDeclaration, DirectCast(rewrittenInitializer, BoundExpression), staticLocalBackingFields, objectInitializer Is Nothing OrElse objectInitializer.CreateTemporaryLocalForInitialization) builder.Add(initialization) Next Return New BoundStatementList(node.Syntax, builder.ToImmutableAndFree()) End Function Private Shared Function GetBoundObjectInitializerFromInitializer(initializer As BoundExpression) As BoundObjectInitializerExpression If initializer IsNot Nothing AndAlso (initializer.Kind = BoundKind.ObjectCreationExpression OrElse initializer.Kind = BoundKind.NewT) Then Dim objectCreationExpression = DirectCast(initializer, BoundObjectCreationExpressionBase) Return TryCast(objectCreationExpression.InitializerOpt, BoundObjectInitializerExpression) End If Return Nothing End Function End Class End Namespace