/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Lowering/UseTwiceRewriter.vb
563 строки
30 KB
AlekseyTs
Fix capitalization in recently added comments. (#70678)
02 ноя 2023, 20:56
Не верифицирован
02 ноя 2023, 20:56
f3d6ae1
Код
Авторство
О чём код?
' 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.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.CodeGen Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Friend NotInheritable Class UseTwiceRewriter Public Structure Result Public Sub New(first As BoundExpression, second As BoundExpression) Me.First = first Me.Second = second End Sub Public ReadOnly First As BoundExpression Public ReadOnly Second As BoundExpression End Structure Private Sub New() End Sub ''' <summary> ''' Given an expression that produces some result and ''' has some observable evaluation side effects, return two expressions: ''' 1) First - produces the same result with the same observable side effects, ''' 2) Second - produces the same result, but without observable side effects, whenever possible. ''' ''' This is used for compound assignment, method call ByRef parameter copy back, etc. ''' </summary> Public Shared Function UseTwice( containingMember As Symbol, value As BoundExpression, isForRegularCompoundAssignment As Boolean, temporaries As ArrayBuilder(Of SynthesizedLocal) ) As Result Debug.Assert(value.IsValue()) Select Case value.Kind Case BoundKind.XmlMemberAccess Dim memberAccess = DirectCast(value, BoundXmlMemberAccess) Dim result = UseTwice(containingMember, memberAccess.MemberAccess, isForRegularCompoundAssignment, temporaries) Return New Result(memberAccess.Update(result.First), memberAccess.Update(result.Second)) Case BoundKind.PropertyAccess Return UseTwicePropertyAccess(containingMember, DirectCast(value, BoundPropertyAccess), isForRegularCompoundAssignment, temporaries) Case BoundKind.LateInvocation Return UseTwiceLateInvocation(containingMember, DirectCast(value, BoundLateInvocation), temporaries) Case BoundKind.LateMemberAccess Return UseTwiceLateMember(containingMember, DirectCast(value, BoundLateMemberAccess), temporaries) Case Else Debug.Assert(value.Kind <> BoundKind.ByRefArgumentWithCopyBack AndAlso value.Kind <> BoundKind.LateBoundArgumentSupportingAssignmentWithCapture) Dim result = UseTwiceExpression(containingMember, value, temporaries) ' LValue-ness of expressions must be preserved Debug.Assert(result.First.IsLValue = result.Second.IsLValue AndAlso result.Second.IsLValue = value.IsLValue) Return result End Select End Function ' receiver of latebound operation Private Shared Function UseTwiceLateBoundReceiver( containingMember As Symbol, receiverOpt As BoundExpression, temporaries As ArrayBuilder(Of SynthesizedLocal) ) As Result Dim receiver As Result If receiverOpt Is Nothing Then receiver = New Result(Nothing, Nothing) ElseIf receiverOpt.IsLValue AndAlso receiverOpt.Type.IsReferenceType Then Dim boundTemp As BoundLocal = Nothing Dim capture As BoundAssignmentOperator = CaptureInATemp(containingMember, receiverOpt.MakeRValue(), temporaries, boundTemp) boundTemp = boundTemp.Update(boundTemp.LocalSymbol, isLValue:=True, type:=boundTemp.Type) receiver = New Result(New BoundSequence(capture.Syntax, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(Of BoundExpression)(capture), boundTemp, boundTemp.Type), boundTemp) ElseIf Not receiverOpt.IsLValue AndAlso Not receiverOpt.Type.IsReferenceType AndAlso Not receiverOpt.Type.IsValueType Then Dim boundTemp As BoundLocal = Nothing Dim capture As BoundAssignmentOperator = CaptureInATemp(containingMember, receiverOpt.MakeRValue(), temporaries, boundTemp) boundTemp = boundTemp.Update(boundTemp.LocalSymbol, isLValue:=True, type:=boundTemp.Type) receiver = New Result(New BoundSequence(capture.Syntax, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(Of BoundExpression)(capture), boundTemp, boundTemp.Type), boundTemp) Else receiver = UseTwiceExpression(containingMember, receiverOpt, temporaries) End If ' LValue-ness of a receiver should be preserved because it affects how helper method is called. Debug.Assert(receiver.Second Is Nothing OrElse (receiverOpt.IsLValue = receiver.First.IsLValue AndAlso receiverOpt.IsLValue = receiver.Second.IsLValue)) Return receiver End Function Private Shared Function UseTwiceExpression( containingMember As Symbol, value As BoundExpression, temporaries As ArrayBuilder(Of SynthesizedLocal) ) As Result If Not value.IsLValue Then Return UseTwiceRValue(containingMember, value, temporaries) End If Select Case value.Kind Case BoundKind.Call Return UseTwiceCall(containingMember, DirectCast(value, BoundCall), temporaries) Case BoundKind.ArrayAccess Return UseTwiceArrayAccess(containingMember, DirectCast(value, BoundArrayAccess), temporaries) Case BoundKind.FieldAccess Return UseTwiceFieldAccess(containingMember, DirectCast(value, BoundFieldAccess), temporaries) Case BoundKind.Local, BoundKind.Parameter, BoundKind.PseudoVariable, BoundKind.WithLValueExpressionPlaceholder Return New Result(value, value) Case Else Debug.Assert(False) ' Add tests if this assert fires Return UseTwiceRValue(containingMember, value, temporaries) End Select End Function Private Shared Function CaptureInATemp( containingMember As Symbol, value As BoundExpression, type As TypeSymbol, temporaries As ArrayBuilder(Of SynthesizedLocal), ByRef referToTemp As BoundLocal ) As BoundAssignmentOperator Debug.Assert(type IsNot Nothing AndAlso Not type.IsVoidType() AndAlso value.Type Is type) Dim temp = New SynthesizedLocal(containingMember, type, SynthesizedLocalKind.LoweringTemp) temporaries.Add(temp) referToTemp = New BoundLocal(value.Syntax, temp, type) referToTemp.SetWasCompilerGenerated() Dim capture = (New BoundAssignmentOperator(value.Syntax, referToTemp, value, suppressObjectClone:=True, type:=type)).MakeCompilerGenerated() ' Make sure we will not try to write to this local or pass it ByRef. referToTemp = referToTemp.MakeRValue() Return capture End Function Private Shared Function CaptureInATemp( containingMember As Symbol, value As BoundExpression, temporaries As ArrayBuilder(Of SynthesizedLocal), ByRef referToTemp As BoundLocal ) As BoundAssignmentOperator Return CaptureInATemp(containingMember, value, value.Type, temporaries, referToTemp) End Function Private Shared Function UseTwiceRValue(containingMember As Symbol, value As BoundExpression, arg As ArrayBuilder(Of SynthesizedLocal)) As Result Dim kind As BoundKind = value.Kind If kind = BoundKind.BadVariable OrElse kind = BoundKind.MeReference OrElse kind = BoundKind.MyBaseReference OrElse kind = BoundKind.MyClassReference OrElse kind = BoundKind.Literal Then Return New Result(value, value) ElseIf value.IsValue AndAlso value.Type IsNot Nothing AndAlso Not value.Type.IsVoidType() Then Debug.Assert(Not value.IsLValue) Debug.Assert(Not value.IsPropertyOrXmlPropertyAccess() OrElse (value.GetAccessKind() = PropertyAccessKind.Get)) Debug.Assert(Not value.IsLateBound() OrElse (value.GetLateBoundAccessKind() = LateBoundAccessKind.Get)) Dim constantValue As ConstantValue = value.ConstantValueOpt If constantValue IsNot Nothing Then Debug.Assert(value.Kind <> BoundKind.Literal) Dim second = New BoundLiteral(value.Syntax, constantValue, value.Type) second.SetWasCompilerGenerated() Return New Result(value, second) End If ' TODO: Might need to do some optimization for compiler generated locals. ' For example, no reason to recapture a local that is already a capture. ' Something to try when we implement WITH statement. Dim boundTemp As BoundLocal = Nothing Dim first = CaptureInATemp(containingMember, value, arg, boundTemp) Debug.Assert(Not first.IsLValue AndAlso Not boundTemp.IsLValue) Return New Result(first, boundTemp) End If Throw ExceptionUtilities.Unreachable End Function Private Shared Function UseTwiceCall(containingMember As Symbol, node As BoundCall, arg As ArrayBuilder(Of SynthesizedLocal)) As Result Debug.Assert(node.IsLValue) Return UseTwiceLValue(containingMember, node, arg) End Function Private Shared Function UseTwiceArrayAccess(containingMember As Symbol, node As BoundArrayAccess, arg As ArrayBuilder(Of SynthesizedLocal)) As Result Debug.Assert(node.IsLValue) #If DONT_USE_BYREF_LOCALS_FOR_USE_TWICE Then #Else If IsInvariantArray(node.Expression.Type) Then Return UseTwiceLValue(containingMember, node, arg) End If #End If ' Note, as an alternative we could capture reference to the array element in a ByRef temp. ' However, without an introduction of an indirect assignment node, IL-gen is unable to distinguish ' when it should assign indirect or should assign a reference. For now, decided to not introduce ' special bound nodes for this purpose. Besides, it is not clear whether ByRef temps will make Async ' easier to implement. Dim boundArrayTemp As BoundLocal = Nothing Dim storeArray = CaptureInATemp(containingMember, node.Expression, arg, boundArrayTemp) Dim n = node.Indices.Length Dim indicesFirst(n - 1) As BoundExpression Dim indicesSecond(n - 1) As BoundExpression For i = 0 To n - 1 Dim result = UseTwiceRValue(containingMember, node.Indices(i), arg) indicesFirst(i) = result.First indicesSecond(i) = result.Second Next Dim second = node.Update(boundArrayTemp, indicesSecond.AsImmutableOrNull(), node.IsLValue, node.Type) Dim first = node.Update(storeArray, indicesFirst.AsImmutableOrNull(), node.IsLValue, node.Type) Debug.Assert(first.IsLValue AndAlso second.IsLValue) Return New Result(first, second) End Function Private Shared Function IsInvariantArray(type As TypeSymbol) As Boolean Dim value = TryCast(type, ArrayTypeSymbol)?.ElementType.IsNotInheritable Return value.GetValueOrDefault() End Function Private Shared Function UseTwiceLValue(containingMember As Symbol, lvalue As BoundExpression, temporaries As ArrayBuilder(Of SynthesizedLocal)) As Result Debug.Assert(lvalue.IsLValue) Dim temp = New SynthesizedLocal(containingMember, lvalue.Type, SynthesizedLocalKind.LoweringTemp, isByRef:=True) Dim first = New BoundReferenceAssignment(lvalue.Syntax, New BoundLocal(lvalue.Syntax, temp, temp.Type).MakeCompilerGenerated(), lvalue, isLValue:=True, type:=lvalue.Type).MakeCompilerGenerated() temporaries.Add(temp) Dim second = New BoundLocal(lvalue.Syntax, temp, isLValue:=True, type:=lvalue.Type).MakeCompilerGenerated() Return New Result(first, second) End Function Private Shared Function UseTwiceFieldAccess(containingMember As Symbol, node As BoundFieldAccess, arg As ArrayBuilder(Of SynthesizedLocal)) As Result Debug.Assert(node.IsLValue) Dim fieldSymbol = node.FieldSymbol If fieldSymbol.IsShared AndAlso node.ReceiverOpt IsNot Nothing Then ' Get rid of the receiver on second use of the shared field. ' It could be an expression that we don't want to visit twice. Dim second = node.Update(Nothing, fieldSymbol, node.IsLValue, node.SuppressVirtualCalls, constantsInProgressOpt:=Nothing, node.Type) Debug.Assert(second.IsLValue) Return New Result(node, second) ElseIf node.ReceiverOpt Is Nothing Then Return New Result(node, node) Else #If DONT_USE_BYREF_LOCALS_FOR_USE_TWICE Then ' Note, as an alternative we could capture reference to the field in a ByRef temp. ' However, without an introduction of an indirect assignment node, IL-gen is unable to distinguish ' when it should assign indirect or should assign a reference. For now, decided to not introduce ' special bound nodes for this purpose. Besides, it is not clear whether ByRef temps will make Async ' easier to implement. Dim receiver As Result = UseTwiceReceiver(containingMember, node.ReceiverOpt, arg) Dim first = node.Update(receiver.First, fieldSymbol, node.IsLValue, suppressVirtualCalls:=False, node.ConstantsInProgressOpt, node.Type) Dim second = node.Update(receiver.Second, fieldSymbol, node.IsLValue, suppressVirtualCalls:=False, node.ConstantsInProgressOpt, node.Type) Debug.Assert(first.IsLValue AndAlso second.IsLValue) Return New Result(first, second) #Else Return UseTwiceLValue(containingMember, node, arg) #End If End If End Function ' We only want to rewrite property access at the top of the expression, not within ' the expression. (For instance, P1 should not be rewritten in M(x.P1.P2).) Private Shared Function UseTwicePropertyAccess(containingMember As Symbol, node As BoundPropertyAccess, isForRegularCompoundAssignment As Boolean, arg As ArrayBuilder(Of SynthesizedLocal)) As Result Dim propertySymbol = node.PropertySymbol ' Visit receiver. Dim receiverOpt As BoundExpression = node.ReceiverOpt Dim receiver As Result If receiverOpt Is Nothing Then receiver = New Result(Nothing, Nothing) ElseIf node.PropertySymbol.IsShared Then receiver = New Result(receiverOpt, Nothing) ElseIf receiverOpt.IsLValue AndAlso receiverOpt.Type.IsReferenceType Then Dim boundTemp As BoundLocal = Nothing receiver = New Result(CaptureInATemp(containingMember, receiverOpt.MakeRValue(), arg, boundTemp), boundTemp) ElseIf Not receiverOpt.IsLValue AndAlso Not receiverOpt.Type.IsReferenceType AndAlso Not receiverOpt.Type.IsValueType Then Dim boundTemp As BoundLocal = Nothing Dim capture As BoundAssignmentOperator = CaptureInATemp(containingMember, receiverOpt.MakeRValue(), arg, boundTemp) boundTemp = boundTemp.Update(boundTemp.LocalSymbol, isLValue:=True, type:=boundTemp.Type) receiver = New Result(New BoundSequence(capture.Syntax, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(Of BoundExpression)(capture), boundTemp, boundTemp.Type), boundTemp) ElseIf receiverOpt.IsLValue AndAlso CodeGenerator.IsPossibleReferenceTypeReceiverOfConstrainedCall(receiverOpt) AndAlso Not CodeGenerator.ReceiverIsKnownToReferToTempIfReferenceType(receiverOpt) AndAlso Not (isForRegularCompoundAssignment AndAlso CodeGenerator.IsSafeToDereferenceReceiverRefAfterEvaluatingArguments(node.Arguments)) Then Debug.Assert(Not receiverOpt.Type.IsReferenceType) ' A case where T is actually a class must be handled specially. ' Taking a reference to a class instance is fragile because the value behind the ' reference might change while arguments are evaluated. However, the call should be ' performed on the instance that is behind reference at the time we push the ' reference to the stack. So, for a class we need to emit a reference to a temporary ' location, rather than to the original location receiver = UseTwiceExpression(containingMember, receiverOpt, arg) Dim cloneTemp As BoundLocal = Nothing Dim clone As BoundAssignmentOperator = CaptureInATemp(containingMember, receiver.Second.MakeRValue(), arg, cloneTemp) Dim complexReceiverFirst = New BoundComplexConditionalAccessReceiver(receiverOpt.Syntax, receiver.Second, New BoundSequence(receiverOpt.Syntax, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(Of BoundExpression)(clone), cloneTemp.Update(cloneTemp.LocalSymbol, isLValue:=True, cloneTemp.Type), cloneTemp.Type).MakeCompilerGenerated(), receiverOpt.Type).MakeCompilerGenerated() Dim complexReceiverSecond = New BoundComplexConditionalAccessReceiver(receiverOpt.Syntax, receiver.Second, cloneTemp.Update(cloneTemp.LocalSymbol, isLValue:=True, cloneTemp.Type), receiverOpt.Type).MakeCompilerGenerated() receiver = New Result(New BoundSequence(receiverOpt.Syntax, ImmutableArray(Of LocalSymbol).Empty, ImmutableArray.Create(Of BoundExpression)(receiver.First.MakeRValue()), complexReceiverFirst, receiverOpt.Type).MakeCompilerGenerated(), complexReceiverSecond) Else receiver = UseTwiceExpression(containingMember, receiverOpt, arg) End If ' Visit args. Dim firstArgs As ImmutableArray(Of BoundExpression) Dim secondArgs As ImmutableArray(Of BoundExpression) If node.Arguments.IsEmpty Then firstArgs = ImmutableArray(Of BoundExpression).Empty secondArgs = ImmutableArray(Of BoundExpression).Empty Else Dim nArgs = node.Arguments.Length Dim firstArgsArray(nArgs - 1) As BoundExpression Dim secondArgsArray(nArgs - 1) As BoundExpression For i = 0 To nArgs - 1 Dim boundArgument As BoundExpression = node.Arguments(i) If boundArgument.Kind = BoundKind.ArrayCreation AndAlso DirectCast(boundArgument, BoundArrayCreation).IsParamArrayArgument Then ' ParamArray argument UseTwiceParamArrayArgument(containingMember, DirectCast(boundArgument, BoundArrayCreation), arg, firstArgsArray(i), secondArgsArray(i)) Else ' Regular argument UseTwiceRegularArgument(containingMember, boundArgument, arg, firstArgsArray(i), secondArgsArray(i)) End If Next firstArgs = firstArgsArray.AsImmutableOrNull() secondArgs = secondArgsArray.AsImmutableOrNull() End If ' Generate PropertyAccess nodes. Dim first = node.Update( propertySymbol, node.PropertyGroupOpt, node.AccessKind, isWriteable:=node.IsWriteable, isLValue:=node.IsLValue, receiverOpt:=receiver.First, arguments:=firstArgs, defaultArguments:=node.DefaultArguments, type:=node.Type) Dim second = node.Update( propertySymbol, node.PropertyGroupOpt, node.AccessKind, isWriteable:=node.IsWriteable, isLValue:=node.IsLValue, receiverOpt:=receiver.Second, arguments:=secondArgs, defaultArguments:=node.DefaultArguments, type:=node.Type) Return New Result(first, second) End Function Private Shared Function UseTwiceLateInvocation(containingMember As Symbol, node As BoundLateInvocation, arg As ArrayBuilder(Of SynthesizedLocal)) As Result ' Visit receiver. Dim receiver As Result If node.Member.Kind = BoundKind.LateMemberAccess Then receiver = UseTwiceLateMember(containingMember, DirectCast(node.Member, BoundLateMemberAccess), arg) Else receiver = UseTwiceLateBoundReceiver(containingMember, node.Member, arg) End If ' Visit args. Dim firstArgs As ImmutableArray(Of BoundExpression) Dim secondArgs As ImmutableArray(Of BoundExpression) If node.ArgumentsOpt.IsEmpty Then firstArgs = ImmutableArray(Of BoundExpression).Empty secondArgs = ImmutableArray(Of BoundExpression).Empty Else Dim nArgs = node.ArgumentsOpt.Length Dim firstArgsArray(nArgs - 1) As BoundExpression Dim secondArgsArray(nArgs - 1) As BoundExpression For i = 0 To nArgs - 1 Dim boundArgument As BoundExpression = node.ArgumentsOpt(i) ' LateBound argument If Not boundArgument.IsSupportingAssignment() Then UseTwiceRegularArgument(containingMember, boundArgument, arg, firstArgsArray(i), secondArgsArray(i)) Else Dim temp = New SynthesizedLocal(containingMember, boundArgument.Type, SynthesizedLocalKind.LoweringTemp) arg.Add(temp) firstArgsArray(i) = New BoundLateBoundArgumentSupportingAssignmentWithCapture(boundArgument.Syntax, boundArgument, temp, boundArgument.Type) secondArgsArray(i) = New BoundLocal(boundArgument.Syntax, temp, isLValue:=False, type:=temp.Type) End If Next firstArgs = firstArgsArray.AsImmutableOrNull() secondArgs = secondArgsArray.AsImmutableOrNull() End If ' Generate nodes. Dim first = node.Update( receiver.First, firstArgs, node.ArgumentNamesOpt, node.AccessKind, node.MethodOrPropertyGroupOpt, node.Type) Dim second = node.Update( receiver.Second, secondArgs, node.ArgumentNamesOpt, node.AccessKind, node.MethodOrPropertyGroupOpt, node.Type) Return New Result(first, second) End Function Private Shared Function UseTwiceLateMember(containingMember As Symbol, node As BoundLateMemberAccess, arg As ArrayBuilder(Of SynthesizedLocal)) As Result ' Visit receiver. Dim receiver As Result = UseTwiceLateBoundReceiver(containingMember, node.ReceiverOpt, arg) ' Generate nodes. Dim first = node.Update(node.NameOpt, node.ContainerTypeOpt, receiver.First, node.TypeArgumentsOpt, node.AccessKind, node.Type) Dim second = node.Update(node.NameOpt, node.ContainerTypeOpt, receiver.Second, node.TypeArgumentsOpt, node.AccessKind, node.Type) Return New Result(first, second) End Function Private Shared Sub UseTwiceRegularArgument(containingMember As Symbol, boundArgument As BoundExpression, arg As ArrayBuilder(Of SynthesizedLocal), ByRef first As BoundExpression, ByRef second As BoundExpression) Debug.Assert(Not boundArgument.IsLValue) Dim result = UseTwiceRValue(containingMember, boundArgument, arg) Debug.Assert(Not result.First.IsLValue AndAlso Not result.Second.IsLValue) Debug.Assert(result.First.HasErrors = result.Second.HasErrors AndAlso boundArgument.HasErrors = result.First.HasErrors) Debug.Assert(result.First.HasErrors OrElse (result.Second.Kind = BoundKind.Literal AndAlso result.First.ConstantValueOpt IsNot Nothing) OrElse (result.Second.Kind = BoundKind.Local AndAlso result.Second.WasCompilerGenerated AndAlso DirectCast(result.Second, BoundLocal).LocalSymbol.IsCompilerGenerated AndAlso result.First.Kind = BoundKind.AssignmentOperator AndAlso result.First.WasCompilerGenerated AndAlso DirectCast(result.First, BoundAssignmentOperator).Left.Kind = BoundKind.Local AndAlso DirectCast(result.Second, BoundLocal).LocalSymbol Is DirectCast(DirectCast(result.First, BoundAssignmentOperator).Left, BoundLocal).LocalSymbol)) first = result.First second = result.Second End Sub Private Shared Sub UseTwiceParamArrayArgument(containingMember As Symbol, boundArray As BoundArrayCreation, arg As ArrayBuilder(Of SynthesizedLocal), ByRef first As BoundExpression, ByRef second As BoundExpression) Debug.Assert(Not boundArray.IsLValue) Debug.Assert(boundArray.InitializerOpt IsNot Nothing) Debug.Assert(boundArray.ArrayLiteralOpt Is Nothing) Dim initializer As BoundArrayInitialization = boundArray.InitializerOpt Dim initializerSize As Integer = initializer.Initializers.Length Dim firstArgsArray(initializerSize - 1) As BoundExpression Dim secondArgsArray(initializerSize - 1) As BoundExpression ' Process arguments from bound array creation initializer For index = 0 To initializerSize - 1 UseTwiceRegularArgument(containingMember, initializer.Initializers(index), arg, firstArgsArray(index), secondArgsArray(index)) Next ' query will be removed in Production Debug.Assert(boundArray.Bounds.All(Function(expr) expr.Kind = BoundKind.Literal)) ' Finally, duplicate array creation expression with updated initializers first = boundArray.Update(boundArray.IsParamArrayArgument, boundArray.Bounds, initializer.Update(firstArgsArray.AsImmutableOrNull(), initializer.Type), Nothing, Nothing, boundArray.Type) second = boundArray.Update(boundArray.IsParamArrayArgument, boundArray.Bounds, initializer.Update(secondArgsArray.AsImmutableOrNull(), initializer.Type), Nothing, Nothing, boundArray.Type) End Sub #If DONT_USE_BYREF_LOCALS_FOR_USE_TWICE Then Private Shared Function UseTwiceReceiver(containingMember As Symbol, receiverOpt As BoundExpression, arg As ArrayBuilder(Of SynthesizedLocal)) As Result If receiverOpt Is Nothing Then Return New Result(Nothing, Nothing) ElseIf receiverOpt.IsLValue AndAlso receiverOpt.Type.IsReferenceType Then Dim boundTemp As BoundLocal = Nothing Dim first = CaptureInATemp(containingMember, receiverOpt.MakeRValue(), arg, boundTemp) Return New Result(first, boundTemp) Else Return UseTwiceExpression(containingMember, receiverOpt, arg) End If End Function #End If End Class End Namespace