/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Lowering/ExpressionLambdaRewriter/ExpressionLambdaRewriter.vb
847 строк
45 KB
AlekseyTs
VB: Do not use overload resolution for expression tree conversion (#75490)
18 окт 2024, 18:19
Не верифицирован
18 окт 2024, 18:19
a98e8c0
Код
Авторство
О чём код?
' 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 Imports System.Collections.Generic Imports System.Collections.Immutable Imports System.Diagnostics Imports System.Linq Imports System.Runtime.InteropServices Imports System.Text Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports Roslyn.Utilities Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic ''' <summary> ''' Rewrite lambda that are being converted to LINQ expression trees (Expression(Of T)) ''' </summary> ''' <remarks> ''' A lot of code is #If False disabled until it can be tested. ''' </remarks> Partial Friend Class ExpressionLambdaRewriter Private ReadOnly _binder As Binder Private ReadOnly _factory As SyntheticBoundNodeFactory Private ReadOnly _typeMap As TypeSubstitution Private ReadOnly _expressionType As NamedTypeSymbol Private _int32Type As NamedTypeSymbol Private _objectType As NamedTypeSymbol Private _memberInfoType As NamedTypeSymbol Private _memberBindingType As NamedTypeSymbol Private _elementInitType As NamedTypeSymbol Private ReadOnly _parameterMap As Dictionary(Of ParameterSymbol, BoundExpression) = New Dictionary(Of ParameterSymbol, BoundExpression)() Private _recursionDepth As Integer Private Sub New(currentMethod As MethodSymbol, compilationState As TypeCompilationState, typeMap As TypeSubstitution, binder As Binder, node As SyntaxNode, recursionDepth As Integer, diagnostics As BindingDiagnosticBag) _binder = binder _typeMap = typeMap _factory = New SyntheticBoundNodeFactory(Nothing, currentMethod, node, compilationState, diagnostics) _expressionType = _factory.WellKnownType(WellKnownType.System_Linq_Expressions_Expression) _recursionDepth = recursionDepth End Sub Public ReadOnly Property ElementInitType As NamedTypeSymbol Get If _elementInitType Is Nothing Then _elementInitType = Me._factory.WellKnownType(WellKnownType.System_Linq_Expressions_ElementInit) End If Return _elementInitType End Get End Property Public ReadOnly Property MemberBindingType As NamedTypeSymbol Get If _memberBindingType Is Nothing Then _memberBindingType = Me._factory.WellKnownType(WellKnownType.System_Linq_Expressions_MemberBinding) End If Return _memberBindingType End Get End Property Public ReadOnly Property MemberInfoType As NamedTypeSymbol Get If _memberInfoType Is Nothing Then _memberInfoType = Me._factory.WellKnownType(WellKnownType.System_Reflection_MemberInfo) End If Return _memberInfoType End Get End Property Public ReadOnly Property Int32Type As NamedTypeSymbol Get If _int32Type Is Nothing Then _int32Type = _factory.SpecialType(SpecialType.System_Int32) End If Return _int32Type End Get End Property Public ReadOnly Property ObjectType As NamedTypeSymbol Get If _objectType Is Nothing Then _objectType = _factory.SpecialType(SpecialType.System_Object) End If Return _objectType End Get End Property ''' <summary> ''' Rewrite a bound lambda into a bound node that will create the corresponding expression tree at run time. ''' </summary> Friend Shared Function RewriteLambda(node As BoundLambda, currentMethod As MethodSymbol, delegateType As NamedTypeSymbol, compilationState As TypeCompilationState, typeMap As TypeSubstitution, diagnostics As BindingDiagnosticBag, rewrittenNodes As HashSet(Of BoundNode), recursionDepth As Integer) As BoundExpression Dim r As New ExpressionLambdaRewriter(currentMethod, compilationState, typeMap, node.LambdaSymbol.ContainingBinder, node.Syntax, recursionDepth, diagnostics) Dim expressionTree As BoundExpression = r.VisitLambdaInternal(node, delegateType) If Not expressionTree.HasErrors Then expressionTree = LocalRewriter.RewriteExpressionTree(expressionTree, currentMethod, compilationState, previousSubmissionFields:=Nothing, diagnostics:=diagnostics, rewrittenNodes:=rewrittenNodes, recursionDepth:=recursionDepth) End If Return expressionTree End Function Private ReadOnly Property Diagnostics As BindingDiagnosticBag Get Return _factory.Diagnostics End Get End Property Private Function TranslateLambdaBody(block As BoundBlock) As BoundExpression ' VB expression trees can be only one statement. Similar analysis is performed ' in DiagnosticsPass, but it does not take into account how the statements ' are rewritten, so here we recheck lowered lambda bodies as well. ' There might be a sequence point at the beginning. ' There may be a label and return statement at the end also but the expression tree ignores that. Debug.Assert(block.Statements(0).Kind <> BoundKind.SequencePoint) Debug.Assert(block.Statements.Length = 1 OrElse (block.Statements.Length = 2 AndAlso block.Statements(1).Kind = BoundKind.ReturnStatement AndAlso DirectCast(block.Statements(1), BoundReturnStatement).ExpressionOpt Is Nothing) OrElse (block.Statements.Length = 3 AndAlso block.Statements(1).Kind = BoundKind.LabelStatement AndAlso block.Statements(2).Kind = BoundKind.ReturnStatement)) ' The only local should be the Function Value. We'll ignore that. Debug.Assert(block.Locals.IsEmpty OrElse (block.Locals.Length = 1 AndAlso block.Locals(0).IsFunctionValue)) ' We only need to generate expression tree for the first statement. Dim stmt = block.Statements(0) lSelect: Select Case stmt.Kind Case BoundKind.ReturnStatement ' The Return statement is not directly expressed in the expression tree, just the expression being returned. Dim expression As BoundExpression = (DirectCast(stmt, BoundReturnStatement)).ExpressionOpt If expression IsNot Nothing Then Return Visit(expression) End If ' Otherwise fall through and generate an error Case BoundKind.ExpressionStatement Return Visit((DirectCast(stmt, BoundExpressionStatement)).Expression) Case BoundKind.Block Dim innerBlock = DirectCast(stmt, BoundBlock) If innerBlock.Locals.IsEmpty AndAlso innerBlock.Statements.Length = 1 Then stmt = innerBlock.Statements(0) GoTo lSelect End If End Select ' all the rest is not supported Debug.Assert(False) Return GenerateDiagnosticAndReturnDummyExpression(ERRID.ERR_StatementLambdaInExpressionTree, block) End Function Private Function GenerateDiagnosticAndReturnDummyExpression(code As ERRID, node As BoundNode, ParamArray args As Object()) As BoundExpression Me.Diagnostics.Add(New VBDiagnostic(ErrorFactory.ErrorInfo(code, args), node.Syntax.GetLocation())) Return VisitInternal(Me._factory.Literal("Diagnostics Generated")) End Function #Region "Visitor support" Private Function Visit(node As BoundExpression) As BoundExpression If node Is Nothing Then Return Nothing End If ' Set the syntax node for bound nodes we are generating. Dim old As SyntaxNode = _factory.Syntax _factory.Syntax = node.Syntax Dim result = VisitInternal(node) _factory.Syntax = old If result.Type Is _expressionType Then Return result End If Return _factory.Convert(_expressionType, result) End Function Private Function VisitExpressionWithoutStackGuard(node As BoundExpression) As BoundExpression Select Case node.Kind Case BoundKind.ArrayCreation Return VisitArrayCreation(DirectCast(node, BoundArrayCreation)) Case BoundKind.ArrayAccess Return VisitArrayAccess(DirectCast(node, BoundArrayAccess)) Case BoundKind.ArrayLength Return VisitArrayLength(DirectCast(node, BoundArrayLength)) Case BoundKind.BadExpression Return VisitBadExpression(DirectCast(node, BoundBadExpression)) Case BoundKind.BinaryConditionalExpression Return VisitBinaryConditionalExpression(DirectCast(node, BoundBinaryConditionalExpression)) Case BoundKind.BinaryOperator Return VisitBinaryOperator(DirectCast(node, BoundBinaryOperator)) Case BoundKind.Call Return VisitCall(DirectCast(node, BoundCall)) Case BoundKind.Conversion Return VisitConversion(DirectCast(node, BoundConversion)) Case BoundKind.DelegateCreationExpression Return VisitDelegateCreationExpression(DirectCast(node, BoundDelegateCreationExpression)) Case BoundKind.DirectCast Return VisitDirectCast(DirectCast(node, BoundDirectCast)) Case BoundKind.FieldAccess Dim fieldAccess = DirectCast(node, BoundFieldAccess) If fieldAccess.FieldSymbol.IsCapturedFrame Then Return CreateLiteralExpression(node) End If Return VisitFieldAccess(fieldAccess) Case BoundKind.Lambda Return VisitLambda(DirectCast(node, BoundLambda)) Case BoundKind.NewT Return VisitNewT(DirectCast(node, BoundNewT)) Case BoundKind.NullableIsTrueOperator Return VisitNullableIsTrueOperator(DirectCast(node, BoundNullableIsTrueOperator)) Case BoundKind.ObjectCreationExpression Return VisitObjectCreationExpression(DirectCast(node, BoundObjectCreationExpression)) Case BoundKind.Parameter Return VisitParameter(DirectCast(node, BoundParameter)) Case BoundKind.PropertyAccess Return VisitPropertyAccess(DirectCast(node, BoundPropertyAccess)) Case BoundKind.Sequence Return VisitSequence(DirectCast(node, BoundSequence)) Case BoundKind.TernaryConditionalExpression Return VisitTernaryConditionalExpression(DirectCast(node, BoundTernaryConditionalExpression)) Case BoundKind.TryCast Return VisitTryCast(DirectCast(node, BoundTryCast)) Case BoundKind.TypeOf Return VisitTypeOf(DirectCast(node, BoundTypeOf)) Case BoundKind.UnaryOperator Return VisitUnaryOperator(DirectCast(node, BoundUnaryOperator)) Case BoundKind.UserDefinedBinaryOperator Return VisitUserDefinedBinaryOperator(DirectCast(node, BoundUserDefinedBinaryOperator)) Case BoundKind.UserDefinedShortCircuitingOperator Return VisitUserDefinedShortCircuitingOperator(DirectCast(node, BoundUserDefinedShortCircuitingOperator)) Case BoundKind.UserDefinedUnaryOperator Return VisitUserDefinedUnaryOperator(DirectCast(node, BoundUserDefinedUnaryOperator)) Case BoundKind.Literal, BoundKind.Local, BoundKind.GetType, BoundKind.MethodInfo, BoundKind.FieldInfo, BoundKind.MeReference, BoundKind.MyClassReference #If DEBUG Then If node.Kind = BoundKind.GetType Then Dim gt = DirectCast(node, BoundGetType) node = gt.Update(gt.SourceType.MemberwiseClone(Of BoundTypeExpression)(), gt.GetTypeFromHandle, gt.Type) Else node = node.MemberwiseClone(Of BoundExpression)() End If #End If Return CreateLiteralExpression(node) Case BoundKind.MyBaseReference ' NOTE: All MyBase references should be processed when correspondent Call or ' DelegateCreation is being processed because only these nodes know ' method symbol, thus, can use proper type symbol for MyBase Throw ExceptionUtilities.UnexpectedValue(node.Kind) Case Else Throw ExceptionUtilities.UnexpectedValue(node.Kind) End Select End Function Private Function VisitInternal(node As BoundExpression) As BoundExpression Dim result As BoundExpression _recursionDepth += 1 #If DEBUG Then Dim saveRecursionDepth = _recursionDepth #End If If _recursionDepth > 1 Then StackGuard.EnsureSufficientExecutionStack(_recursionDepth) result = VisitExpressionWithoutStackGuard(node) Else result = VisitExpressionWithStackGuard(node) End If #If DEBUG Then Debug.Assert(saveRecursionDepth = _recursionDepth) #End If _recursionDepth -= 1 Return result End Function Private Function VisitExpressionWithStackGuard(node As BoundExpression) As BoundExpression Try Return VisitExpressionWithoutStackGuard(node) Catch ex As InsufficientExecutionStackException Throw New BoundTreeVisitor.CancelledByStackGuardException(ex, node) End Try End Function Private Function VisitLambdaInternal(node As BoundLambda, delegateType As NamedTypeSymbol) As BoundExpression Dim parameterExpressionType = _factory.WellKnownType(WellKnownType.System_Linq_Expressions_ParameterExpression) ' prepare parameters so that they can be seen later Dim locals = ArrayBuilder(Of LocalSymbol).GetInstance() Dim initializers = ArrayBuilder(Of BoundExpression).GetInstance() Dim parameters = ArrayBuilder(Of BoundExpression).GetInstance() For Each p In node.LambdaSymbol.Parameters Debug.Assert(Not p.IsByRef, "DiagnosticsPass should have reported an error") Dim param = _factory.SynthesizedLocal(parameterExpressionType) Dim parameterReference = _factory.Local(param, False) Dim parameterReferenceLValue = _factory.Local(param, True) locals.Add(param) parameters.Add(parameterReference) _parameterMap(p) = parameterReference Dim parameter As BoundExpression = ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__Parameter, _factory.[Typeof]( p.Type.InternalSubstituteTypeParameters(_typeMap).Type, _factory.WellKnownType(WellKnownType.System_Type)), _factory.Literal(p.Name)) If Not parameter.HasErrors Then initializers.Add(_factory.AssignmentExpression(parameterReferenceLValue, parameter)) End If Next Debug.Assert(Not node.LambdaSymbol.IsAsync AndAlso Not node.LambdaSymbol.IsIterator, "An error should have been reported by DiagnosticsPass") Debug.Assert(node.WasCompilerGenerated OrElse node.IsSingleLine, "An error should have been reported by DiagnosticsPass") Dim translatedBody As BoundExpression = TranslateLambdaBody(node.Body) Dim result = _factory.Sequence(locals.ToImmutableAndFree(), initializers.ToImmutableAndFree(), ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__Lambda_OfTDelegate, ImmutableArray.Create(Of TypeSymbol)(delegateType), translatedBody, _factory.Array(parameterExpressionType, parameters.ToImmutableAndFree()))) For Each p In node.LambdaSymbol.Parameters _parameterMap.Remove(p) Next Return result End Function #End Region #Region "Visitors" Private Function VisitCall(node As BoundCall) As BoundExpression Dim method As MethodSymbol = node.Method Dim receiverOpt As BoundExpression = node.ReceiverOpt If receiverOpt IsNot Nothing Then If receiverOpt.Kind = BoundKind.MyBaseReference Then #If DEBUG Then receiverOpt = receiverOpt.MemberwiseClone(Of BoundExpression)() #End If receiverOpt = CreateLiteralExpression(receiverOpt, method.ContainingType) Else receiverOpt = Visit(receiverOpt) End If End If If method.MethodKind = MethodKind.DelegateInvoke Then Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__Invoke, receiverOpt, ConvertArgumentsIntoArray(node.Arguments)) Else Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__Call, If(method.IsShared, _factory.Null(_expressionType), receiverOpt), _factory.MethodInfo(method, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)), ConvertArgumentsIntoArray(node.Arguments)) End If End Function Private Function VisitFieldAccess(node As BoundFieldAccess) As BoundExpression Dim origReceiverOpt As BoundExpression = node.ReceiverOpt Dim field As FieldSymbol = node.FieldSymbol Dim fieldIsShared As Boolean = field.IsShared Debug.Assert(origReceiverOpt IsNot Nothing OrElse fieldIsShared) Dim rewrittenReceiver As BoundExpression = Nothing If fieldIsShared Then rewrittenReceiver = _factory.Null(_expressionType) Else Debug.Assert(origReceiverOpt IsNot Nothing) If origReceiverOpt.Kind = BoundKind.MyBaseReference Then #If DEBUG Then origReceiverOpt = origReceiverOpt.MemberwiseClone(Of BoundExpression)() #End If rewrittenReceiver = CreateLiteralExpression(origReceiverOpt.MakeRValue, field.ContainingType) Else rewrittenReceiver = Visit(origReceiverOpt) End If End If Return ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__Field, rewrittenReceiver, _factory.FieldInfo(field)) End Function Private Function VisitPropertyAccess(node As BoundPropertyAccess) As BoundExpression Dim origReceiverOpt As BoundExpression = node.ReceiverOpt Dim [property] As PropertySymbol = node.PropertySymbol Dim propertyIsShared As Boolean = [property].IsShared Debug.Assert(origReceiverOpt IsNot Nothing OrElse propertyIsShared) Dim rewrittenReceiver As BoundExpression = Nothing If propertyIsShared Then rewrittenReceiver = _factory.Null(_expressionType) Else Debug.Assert(origReceiverOpt IsNot Nothing) Debug.Assert(origReceiverOpt.Kind <> BoundKind.MyBaseReference AndAlso origReceiverOpt.Kind <> BoundKind.MyClassReference) rewrittenReceiver = Visit(origReceiverOpt) End If Dim getMethod As MethodSymbol = [property].GetMostDerivedGetMethod() Return ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__Property, rewrittenReceiver, _factory.MethodInfo(getMethod, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo))) End Function Private Function VisitLambda(node As BoundLambda) As BoundExpression Throw ExceptionUtilities.Unreachable End Function Private Function VisitDelegateCreationExpression(node As BoundDelegateCreationExpression) As BoundExpression Debug.Assert(node.RelaxationLambdaOpt Is Nothing) Debug.Assert(node.RelaxationReceiverPlaceholderOpt Is Nothing) Debug.Assert(node.MethodGroupOpt Is Nothing) Dim delegateType As NamedTypeSymbol = DirectCast(node.Type, NamedTypeSymbol) Debug.Assert(delegateType.TypeKind = TYPEKIND.Delegate) Dim method As MethodSymbol = node.Method Dim receiverOpt As BoundExpression = node.ReceiverOpt Dim isStaticMethodCall As Boolean = node.Method.IsShared If isStaticMethodCall Then receiverOpt = Me._factory.Convert(Me.ObjectType, Me._factory.Null()) Else If receiverOpt.Kind = BoundKind.MyBaseReference Then ' If the receiver is MyBase we can safely rewrite it into correspondent 'Me' ' reference because the method was supposed to be transformed into wrapper receiverOpt = New BoundMeReference(receiverOpt.Syntax, method.ContainingType) ElseIf receiverOpt.IsLValue Then receiverOpt = receiverOpt.MakeRValue() End If If Not receiverOpt.Type.IsObjectType Then receiverOpt = Me._factory.Convert(Me.ObjectType, receiverOpt) End If End If Dim result As BoundExpression Dim targetMethod As MethodSymbol = If(method.CallsiteReducedFromMethod, method) Dim useSiteInfo As UseSiteInfo(Of AssemblySymbol) = Nothing Dim createDelegate = DirectCast(Binder.GetWellKnownTypeMember(Me._factory.Compilation, WellKnownMember.System_Reflection_MethodInfo__CreateDelegate, useSiteInfo), MethodSymbol) If createDelegate IsNot Nothing And useSiteInfo.DiagnosticInfo Is Nothing Then Diagnostics.AddDependencies(useSiteInfo) Dim methodInfo As BoundExpression = Me._factory.MethodInfo(targetMethod, createDelegate.ContainingType) ' beginning in 4.5, we do it this way result = Me._factory.Call(methodInfo, createDelegate, Me._factory.[Typeof](delegateType, createDelegate.Parameters(0).Type), receiverOpt) Else ' 4.0 and earlier we do it this way createDelegate = DirectCast(Me._factory.SpecialMember(SpecialMember.System_Delegate__CreateDelegate4), MethodSymbol) If createDelegate IsNot Nothing Then result = Me._factory.Call(Me._factory.Null(Me.ObjectType), createDelegate, Me._factory.[Typeof](delegateType, createDelegate.Parameters(0).Type), receiverOpt, Me._factory.MethodInfo(targetMethod, createDelegate.Parameters(2).Type), Me._factory.Literal(False)) Else Return node ' Error should have been generated by now End If End If Return Convert(Visit(result), delegateType, False) End Function Private Function VisitParameter(node As BoundParameter) As BoundExpression Return _parameterMap(node.ParameterSymbol) End Function Private Function VisitArrayAccess(node As BoundArrayAccess) As BoundExpression Dim array = Visit(node.Expression) If node.Indices.Length = 1 Then Dim arg = node.Indices(0) Dim index = Visit(arg) Debug.Assert(arg.Type Is Me.Int32Type) Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__ArrayIndex_Expression_Expression, array, index) Else Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__ArrayIndex_Expression_Expressions, array, BuildIndices(node.Indices)) End If End Function Private Function BuildIndices(expressions As ImmutableArray(Of BoundExpression)) As BoundExpression Dim count As Integer = expressions.Length Dim newExpr(count - 1) As BoundExpression For i = 0 To count - 1 Debug.Assert(expressions(i).Type Is Me.Int32Type) newExpr(i) = Visit(expressions(i)) Next Return _factory.Array(_expressionType, newExpr.AsImmutableOrNull()) End Function Private Function VisitBadExpression(node As BoundBadExpression) As BoundExpression Return node End Function Private Function VisitObjectCreationExpression(node As BoundObjectCreationExpression) As BoundExpression Dim visitedObjectCreation As BoundExpression = VisitObjectCreationExpressionInternal(node) Return VisitObjectCreationContinued(visitedObjectCreation, node.InitializerOpt) End Function Private Function VisitNewT(node As BoundNewT) As BoundExpression Return VisitObjectCreationContinued( ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__New_Type, _factory.[Typeof](node.Type, _factory.WellKnownType(WellKnownType.System_Type))), node.InitializerOpt) End Function Private Function VisitObjectCreationContinued(creation As BoundExpression, initializerOpt As BoundExpression) As BoundExpression If initializerOpt Is Nothing Then Return creation End If Select Case initializerOpt.Kind Case BoundKind.ObjectInitializerExpression Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__MemberInit, creation, VisitObjectInitializer(DirectCast(initializerOpt, BoundObjectInitializerExpression))) Case BoundKind.CollectionInitializerExpression Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__ListInit, creation, VisitCollectionInitializer(DirectCast(initializerOpt, BoundCollectionInitializerExpression))) Case Else Throw ExceptionUtilities.UnexpectedValue(initializerOpt.Kind) End Select End Function Private Function VisitObjectInitializer(initializer As BoundObjectInitializerExpression) As BoundExpression Debug.Assert(initializer.CreateTemporaryLocalForInitialization, "DiagnosticsPass should have generated an error") Dim initializers As ImmutableArray(Of BoundExpression) = initializer.Initializers Dim initializerCount As Integer = initializers.Length Dim newInitializers(initializerCount - 1) As BoundExpression For i = 0 To initializerCount - 1 Debug.Assert(initializers(i).Kind = BoundKind.AssignmentOperator) Dim assignment = DirectCast(initializers(i), BoundAssignmentOperator) Debug.Assert(assignment.LeftOnTheRightOpt Is Nothing) Dim left As BoundExpression = assignment.Left Dim leftSymbol As Symbol = Nothing Select Case left.Kind Case BoundKind.FieldAccess leftSymbol = DirectCast(assignment.Left, BoundFieldAccess).FieldSymbol Case BoundKind.PropertyAccess Debug.Assert(DirectCast(assignment.Left, BoundPropertyAccess).AccessKind = PropertyAccessKind.Set) leftSymbol = DirectCast(assignment.Left, BoundPropertyAccess).PropertySymbol Case Else Throw ExceptionUtilities.UnexpectedValue(left.Kind) End Select Debug.Assert(leftSymbol IsNot Nothing) Dim right As BoundExpression = assignment.Right Debug.Assert(initializer.PlaceholderOpt IsNot Nothing) Debug.Assert(Not BoundNodeFinder.ContainsNode(right, initializer.PlaceholderOpt, _recursionDepth, convertInsufficientExecutionStackExceptionToCancelledByStackGuardException:=True), "Should be addressed in DiagnosticsPass") Debug.Assert(leftSymbol.Kind = SymbolKind.Field OrElse leftSymbol.Kind = SymbolKind.Property) Dim memberRef As BoundExpression = If(leftSymbol.Kind = SymbolKind.Field, _factory.Convert(MemberInfoType, Me._factory.FieldInfo(DirectCast(leftSymbol, FieldSymbol))), Me._factory.MethodInfo((DirectCast(leftSymbol, PropertySymbol)).SetMethod, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo))) newInitializers(i) = _factory.Convert( MemberBindingType, ConvertRuntimeHelperToExpressionTree( If(leftSymbol.Kind = SymbolKind.Field, WellKnownMember.System_Linq_Expressions_Expression__Bind_MemberInfo, WellKnownMember.System_Linq_Expressions_Expression__Bind_MethodInfo), memberRef, Visit(right))) Next Return _factory.Array(MemberBindingType, newInitializers.AsImmutableOrNull()) End Function Private Function VisitCollectionInitializer(initializer As BoundCollectionInitializerExpression) As BoundExpression Dim initializers As ImmutableArray(Of BoundExpression) = initializer.Initializers Dim initializerCount As Integer = initializers.Length Dim newInitializers(initializerCount - 1) As BoundExpression For i = 0 To initializerCount - 1 Debug.Assert(initializers(i).Kind = BoundKind.Call) Dim [call] = DirectCast(initializers(i), BoundCall) ' Note, for extension methods we are dropping the "Me" parameter to remove ' BoundCollectionInitializerExpression.PlaceholderOpt references from the tree. ' Otherwise, IL generation fails because it doesn't know what to do with it. ' At run-time, this code is going to throw because ElementInit API doesn't accept ' shared methods. We don't fail compilation in this scenario due to backward ' compatibility reasons. newInitializers(i) = _factory.Convert( ElementInitType, ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__ElementInit, _factory.MethodInfo([call].Method, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)), ConvertArgumentsIntoArray(If([call].Method.IsShared AndAlso [call].Method.IsExtensionMethod, [call].Arguments.RemoveAt(0), [call].Arguments)))) Next Return _factory.Array(ElementInitType, newInitializers.AsImmutableOrNull()) End Function Private Function VisitObjectCreationExpressionInternal(node As BoundObjectCreationExpression) As BoundExpression If node.ConstantValueOpt IsNot Nothing Then Return CreateLiteralExpression(node) End If If node.ConstructorOpt Is Nothing OrElse (node.Arguments.Length = 0 AndAlso Not node.Type.IsStructureType() OrElse node.ConstructorOpt.IsDefaultValueTypeConstructor()) Then Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__New_Type, _factory.[Typeof](node.Type, _factory.WellKnownType(WellKnownType.System_Type))) End If Dim ctor = _factory.ConstructorInfo(node.ConstructorOpt) Dim args = ConvertArgumentsIntoArray(node.Arguments) If node.Type.IsAnonymousType AndAlso node.Arguments.Length <> 0 Then Dim anonType = DirectCast(node.Type, AnonymousTypeManager.AnonymousTypePublicSymbol) Dim properties As ImmutableArray(Of AnonymousTypeManager.AnonymousTypePropertyPublicSymbol) = anonType.Properties Debug.Assert(properties.Length = node.Arguments.Length) Dim methodInfos(properties.Length - 1) As BoundExpression For i = 0 To properties.Length - 1 methodInfos(i) = Me._factory.Convert(Me.MemberInfoType, Me._factory.MethodInfo(properties(i).GetMethod, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo))) Next Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__New_ConstructorInfo_Expressions_MemberInfos, ctor, _factory.Convert(_factory.SpecialType(SpecialType.System_Collections_Generic_IEnumerable_T).Construct(_expressionType), args), Me._factory.Array(Me.MemberInfoType, methodInfos.AsImmutableOrNull())) Else Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__New_ConstructorInfo_ArrayExpressions, ctor, args) End If End Function Private Function VisitSequence(node As BoundSequence) As BoundExpression Dim locals As ImmutableArray(Of LocalSymbol) = node.Locals Dim sideEffects As ImmutableArray(Of BoundExpression) = node.SideEffects Dim value As BoundExpression = node.ValueOpt If locals.IsEmpty AndAlso sideEffects.IsEmpty AndAlso value IsNot Nothing Then Return VisitInternal(value) End If ' All other cases are not supported, note that some cases of invalid ' sequences are handled in DiagnosticsPass, but we still want to catch ' here those sequences created in lowering Return GenerateDiagnosticAndReturnDummyExpression(ERRID.ERR_ExpressionTreeNotSupported, node) End Function Private Function VisitArrayLength(node As BoundArrayLength) As BoundExpression Dim resultType As TypeSymbol = node.Type If resultType.SpecialType = SpecialType.System_Int64 Then Return VisitCall( New BoundCall( node.Syntax, DirectCast(Me._factory.SpecialMember(SpecialMember.System_Array__LongLength), PropertySymbol).GetMethod, Nothing, node.Expression, ImmutableArray(Of BoundExpression).Empty, Nothing, isLValue:=False, suppressObjectClone:=True, type:=resultType)) Else Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__ArrayLength, Visit(node.Expression)) End If End Function Private Function VisitArrayCreation(node As BoundArrayCreation) As BoundExpression Dim arrayType = DirectCast(node.Type, ArrayTypeSymbol) Dim boundType As BoundExpression = _factory.[Typeof](arrayType.ElementType, _factory.WellKnownType(WellKnownType.System_Type)) Dim initializer As BoundArrayInitialization = node.InitializerOpt If initializer IsNot Nothing AndAlso Not initializer.Initializers.IsEmpty Then Debug.Assert(arrayType.IsSZArray, "Not SZArray should be addressed in DiagnosticsPass") Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__NewArrayInit, boundType, ConvertArgumentsIntoArray(node.InitializerOpt.Initializers)) Else Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__NewArrayBounds, boundType, ConvertArgumentsIntoArray(node.Bounds)) End If End Function Private Function ConvertArgumentsIntoArray(exprs As ImmutableArray(Of BoundExpression)) As BoundExpression Dim newArgs(exprs.Length - 1) As BoundExpression For i = 0 To exprs.Length - 1 newArgs(i) = Visit(exprs(i)) Next Return _factory.Array(_expressionType, newArgs.AsImmutableOrNull) End Function Private Function VisitTypeOf(node As BoundTypeOf) As BoundExpression Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__TypeIs, Visit(node.Operand), _factory.[Typeof](node.TargetType, _factory.WellKnownType(WellKnownType.System_Type))) End Function #End Region #Region "General utility/factory methods" ' Emit a call node Private Function [Call](receiver As BoundExpression, method As MethodSymbol, ParamArray params As BoundExpression()) As BoundExpression Return ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__Call, receiver, _factory.MethodInfo(method, _factory.WellKnownType(WellKnownType.System_Reflection_MethodInfo)), _factory.Array(_expressionType, params)) End Function ' Emit a Default node for a specific type Private Function [Default](type As TypeSymbol) As BoundExpression Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__Default, _factory.[Typeof](type, _factory.WellKnownType(WellKnownType.System_Type))) End Function ' Emit a New node to a specific type with a helper constructor and one argument Private Function [New](helper As SpecialMember, argument As BoundExpression) As BoundExpression Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__New_ConstructorInfo_ArrayExpressions, _factory.ConstructorInfo(helper), _factory.Array(_expressionType, argument)) End Function ' Emit a negate node Private Function Negate(expr As BoundExpression) As BoundExpression Return _factory.Convert(_expressionType, ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__Negate_Expression, expr)) End Function Private Function InitWithParameterlessValueTypeConstructor(type As TypeSymbol) As BoundExpression ' The "New" overload without a methodInfo automatically generates the parameterless constructor for us. Debug.Assert(type.IsValueType) Return ConvertRuntimeHelperToExpressionTree(WellKnownMember.System_Linq_Expressions_Expression__New_Type, _factory.[Typeof](type, _factory.WellKnownType(WellKnownType.System_Type))) End Function Private Function IsIntegralType(type As TypeSymbol) As Boolean Return GetUnderlyingType(type).IsIntegralType End Function Private Function GetUnderlyingType(type As TypeSymbol) As TypeSymbol Return type.GetNullableUnderlyingTypeOrSelf.GetEnumUnderlyingTypeOrSelf End Function Private Function CreateLiteralExpression(node As BoundExpression) As BoundExpression Return CreateLiteralExpression(node, node.Type) End Function Private Function CreateLiteralExpression(node As BoundExpression, type As TypeSymbol) As BoundExpression Return _factory.Convert( _expressionType, ConvertRuntimeHelperToExpressionTree( WellKnownMember.System_Linq_Expressions_Expression__Constant, _factory.Convert(Me.ObjectType, node), _factory.[Typeof](type, _factory.WellKnownType(WellKnownType.System_Type)))) End Function ''' <summary> ''' Create an Expression Tree Node with the given name and arguments ''' </summary> Private Function ConvertRuntimeHelperToExpressionTree(helperMethod As WellKnownMember, ParamArray arguments As BoundExpression()) As BoundExpression Return ConvertRuntimeHelperToExpressionTree(helperMethod, ImmutableArray(Of TypeSymbol).Empty, arguments) End Function ''' <summary> ''' Create an Expression node with the given name, type arguments, and arguments. ''' </summary> Private Function ConvertRuntimeHelperToExpressionTree(helperMethod As WellKnownMember, typeArgs As ImmutableArray(Of TypeSymbol), ParamArray arguments As BoundExpression()) As BoundExpression Dim helper As MethodSymbol = _factory.WellKnownMember(Of MethodSymbol)(helperMethod) If helper IsNot Nothing Then If Not typeArgs.IsEmpty Then helper = helper.Construct(typeArgs) End If Return New BoundCall(_factory.Syntax, helper, methodGroupOpt:=Nothing, receiverOpt:=Nothing, arguments:=ImmutableArray.Create(Of BoundExpression)(arguments), constantValueOpt:=Nothing, isLValue:=False, suppressObjectClone:=True, helper.ReturnType) End If Return _factory.BadExpression(arguments) End Function #End Region End Class End Namespace