/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Operations/VisualBasicOperationFactory_Methods.vb
689 строк
41 KB
Tomáš Matoušek
Clean up KeyValuePair polyfills (#78872)
24 июн 2025, 03:17
Не верифицирован
24 июн 2025, 03:17
f294360
Код
Авторство
О чём код?
' 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 Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.VisualBasic Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Symbols.AnonymousTypeManager Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.Operations Partial Friend NotInheritable Class VisualBasicOperationFactory Private Shared Function IsMidStatement(node As BoundNode) As Boolean If node.Kind = BoundKind.Conversion Then node = DirectCast(node, BoundConversion).Operand If node.Kind = BoundKind.UserDefinedConversion Then node = DirectCast(node, BoundUserDefinedConversion).Operand End If End If Return node.Kind = BoundKind.MidResult End Function Friend Function CreateCompoundAssignmentRightOperand(boundAssignment As BoundAssignmentOperator) As IOperation Dim binaryOperator As BoundExpression = Nothing Select Case boundAssignment.Right.Kind Case BoundKind.Conversion Dim inConversionNode = DirectCast(boundAssignment.Right, BoundConversion) binaryOperator = GetConversionOperand(inConversionNode) Case BoundKind.UserDefinedBinaryOperator, BoundKind.BinaryOperator binaryOperator = boundAssignment.Right Case Else Throw ExceptionUtilities.UnexpectedValue(boundAssignment.Kind) End Select Dim operatorInfo As BinaryOperatorInfo Select Case binaryOperator.Kind Case BoundKind.BinaryOperator operatorInfo = GetBinaryOperatorInfo(DirectCast(binaryOperator, BoundBinaryOperator)) Return Create(operatorInfo.RightOperand) Case BoundKind.UserDefinedBinaryOperator Dim userDefinedOperator = DirectCast(binaryOperator, BoundUserDefinedBinaryOperator) operatorInfo = GetUserDefinedBinaryOperatorInfo(userDefinedOperator) Return GetUserDefinedBinaryOperatorChild(userDefinedOperator, operatorInfo.RightOperand) Case Else Throw ExceptionUtilities.UnexpectedValue(boundAssignment.Kind) End Select End Function Private Function CreateCompoundAssignment(boundAssignment As BoundAssignmentOperator) As ICompoundAssignmentOperation Debug.Assert(boundAssignment.LeftOnTheRightOpt IsNot Nothing) Dim inConversion = New Conversion(Conversions.Identity) Dim outConversion As Conversion = inConversion Dim binaryOperator As BoundExpression = Nothing Select Case boundAssignment.Right.Kind Case BoundKind.Conversion Dim inConversionNode = DirectCast(boundAssignment.Right, BoundConversion) outConversion = CreateConversion(inConversionNode) binaryOperator = GetConversionOperand(inConversionNode) Case BoundKind.UserDefinedBinaryOperator, BoundKind.BinaryOperator binaryOperator = boundAssignment.Right Case Else Throw ExceptionUtilities.UnexpectedValue(boundAssignment.Kind) End Select Dim operatorInfo As BinaryOperatorInfo Select Case binaryOperator.Kind Case BoundKind.BinaryOperator operatorInfo = GetBinaryOperatorInfo(DirectCast(binaryOperator, BoundBinaryOperator)) Case BoundKind.UserDefinedBinaryOperator Dim userDefinedOperator = DirectCast(binaryOperator, BoundUserDefinedBinaryOperator) operatorInfo = GetUserDefinedBinaryOperatorInfo(userDefinedOperator) Case Else Throw ExceptionUtilities.UnexpectedValue(boundAssignment.Kind) End Select Dim leftOnTheRight As BoundExpression = operatorInfo.LeftOperand If leftOnTheRight.Kind = BoundKind.Conversion Then Dim outConversionNode = DirectCast(leftOnTheRight, BoundConversion) inConversion = CreateConversion(outConversionNode) leftOnTheRight = GetConversionOperand(outConversionNode) End If Debug.Assert(leftOnTheRight Is boundAssignment.LeftOnTheRightOpt) Dim target As IOperation = Create(boundAssignment.Left) Dim value As IOperation = CreateCompoundAssignmentRightOperand(boundAssignment) Dim syntax As SyntaxNode = boundAssignment.Syntax Dim type As ITypeSymbol = boundAssignment.Type Dim isImplicit As Boolean = boundAssignment.WasCompilerGenerated Return New CompoundAssignmentOperation(inConversion, outConversion, operatorInfo.OperatorKind, operatorInfo.IsLifted, operatorInfo.IsChecked, operatorInfo.OperatorMethod, constrainedToType:=Nothing, target, value, _semanticModel, syntax, type, isImplicit) End Function Private Structure BinaryOperatorInfo Public Sub New(leftOperand As BoundExpression, rightOperand As BoundExpression, binaryOperatorKind As BinaryOperatorKind, operatorMethod As MethodSymbol, isLifted As Boolean, isChecked As Boolean, isCompareText As Boolean) Me.LeftOperand = leftOperand Me.RightOperand = rightOperand Me.OperatorKind = binaryOperatorKind Me.OperatorMethod = operatorMethod Me.IsLifted = isLifted Me.IsChecked = isChecked Me.IsCompareText = isCompareText End Sub Public ReadOnly LeftOperand As BoundExpression Public ReadOnly RightOperand As BoundExpression Public ReadOnly OperatorKind As BinaryOperatorKind Public ReadOnly OperatorMethod As MethodSymbol Public ReadOnly IsLifted As Boolean Public ReadOnly IsChecked As Boolean Public ReadOnly IsCompareText As Boolean End Structure Private Shared Function GetBinaryOperatorInfo(boundBinaryOperator As BoundBinaryOperator) As BinaryOperatorInfo Return New BinaryOperatorInfo( leftOperand:=boundBinaryOperator.Left, rightOperand:=boundBinaryOperator.Right, binaryOperatorKind:=Helper.DeriveBinaryOperatorKind(boundBinaryOperator.OperatorKind, boundBinaryOperator.Left), operatorMethod:=Nothing, isLifted:=(boundBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.Lifted) <> 0, isChecked:=boundBinaryOperator.Checked, isCompareText:=(boundBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.CompareText) <> 0) End Function Private Shared Function GetUserDefinedBinaryOperatorInfo(boundUserDefinedBinaryOperator As BoundUserDefinedBinaryOperator) As BinaryOperatorInfo Return New BinaryOperatorInfo( leftOperand:=GetUserDefinedBinaryOperatorChildBoundNode(boundUserDefinedBinaryOperator, 0), rightOperand:=GetUserDefinedBinaryOperatorChildBoundNode(boundUserDefinedBinaryOperator, 1), binaryOperatorKind:=Helper.DeriveBinaryOperatorKind(boundUserDefinedBinaryOperator.OperatorKind, leftOpt:=Nothing), operatorMethod:=If(boundUserDefinedBinaryOperator.UnderlyingExpression.Kind = BoundKind.Call, boundUserDefinedBinaryOperator.Call.Method, Nothing), isLifted:=(boundUserDefinedBinaryOperator.OperatorKind And VisualBasic.BinaryOperatorKind.Lifted) <> 0, isChecked:=boundUserDefinedBinaryOperator.Checked, isCompareText:=False) End Function Private Function GetUserDefinedBinaryOperatorChild([operator] As BoundUserDefinedBinaryOperator, child As BoundExpression) As IOperation If child IsNot Nothing Then Return Create(child) End If Dim isImplicit As Boolean = [operator].UnderlyingExpression.WasCompilerGenerated Return OperationFactory.CreateInvalidOperation(_semanticModel, [operator].UnderlyingExpression.Syntax, ImmutableArray(Of IOperation).Empty, isImplicit) End Function Private Shared Function GetUserDefinedBinaryOperatorChildBoundNode([operator] As BoundUserDefinedBinaryOperator, index As Integer) As BoundExpression If [operator].UnderlyingExpression.Kind = BoundKind.Call Then If index = 0 Then Return [operator].Left ElseIf index = 1 Then Return [operator].Right Else Throw ExceptionUtilities.UnexpectedValue(index) End If End If Return GetChildOfBadExpressionBoundNode([operator].UnderlyingExpression, index) End Function Friend Function DeriveArguments(boundNode As BoundNode) As ImmutableArray(Of IArgumentOperation) Select Case boundNode.Kind Case BoundKind.Call Dim boundCall = DirectCast(boundNode, BoundCall) Return DeriveArguments(boundCall.Arguments, boundCall.Method.Parameters, boundCall.DefaultArguments) Case BoundKind.ObjectCreationExpression Dim boundCreation = DirectCast(boundNode, BoundObjectCreationExpression) If boundCreation.Arguments.IsDefault Then Return ImmutableArray(Of IArgumentOperation).Empty End If Return If(boundCreation.ConstructorOpt Is Nothing, ImmutableArray(Of IArgumentOperation).Empty, DeriveArguments(boundCreation.Arguments, boundCreation.ConstructorOpt.Parameters, boundCreation.DefaultArguments)) Case BoundKind.PropertyAccess Dim boundProperty = DirectCast(boundNode, BoundPropertyAccess) Return If(boundProperty.Arguments.Length = 0, ImmutableArray(Of IArgumentOperation).Empty, DeriveArguments(boundProperty.Arguments, boundProperty.PropertySymbol.Parameters, boundProperty.DefaultArguments)) Case BoundKind.RaiseEventStatement Dim boundRaiseEvent = DirectCast(boundNode, BoundRaiseEventStatement) Return DeriveArguments(DirectCast(boundRaiseEvent.EventInvocation, BoundCall)) Case BoundKind.Attribute Dim boundAttribute = DirectCast(boundNode, BoundAttribute) Return DeriveArguments(boundAttribute.ConstructorArguments, boundAttribute.Constructor.Parameters, boundAttribute.ConstructorDefaultArguments) Case Else Throw ExceptionUtilities.UnexpectedValue(boundNode.Kind) End Select End Function Friend Function DeriveArguments(boundArguments As ImmutableArray(Of BoundExpression), parameters As ImmutableArray(Of VisualBasic.Symbols.ParameterSymbol), ByRef defaultArguments As BitVector) As ImmutableArray(Of IArgumentOperation) Dim argumentsLength As Integer = boundArguments.Length Debug.Assert(argumentsLength = parameters.Length) Dim arguments As ArrayBuilder(Of IArgumentOperation) = ArrayBuilder(Of IArgumentOperation).GetInstance(argumentsLength) For index As Integer = 0 To argumentsLength - 1 Step 1 arguments.Add(DeriveArgument(index, boundArguments(index), parameters, defaultArguments(index))) Next Return arguments.ToImmutableAndFree() End Function Private Function DeriveArgument( index As Integer, argument As BoundExpression, parameters As ImmutableArray(Of VisualBasic.Symbols.ParameterSymbol), isDefault As Boolean ) As IArgumentOperation Dim isImplicit As Boolean = argument.WasCompilerGenerated AndAlso argument.Syntax.Kind <> SyntaxKind.OmittedArgument Select Case argument.Kind Case BoundKind.ByRefArgumentWithCopyBack Dim byRefArgument = DirectCast(argument, BoundByRefArgumentWithCopyBack) Dim parameter = parameters(index) Return CreateArgumentOperation( ArgumentKind.Explicit, parameter, byRefArgument.OriginalArgument, CreateConversion(byRefArgument.InConversion), CreateConversion(byRefArgument.OutConversion), isImplicit) Case Else Dim lastParameterIndex = parameters.Length - 1 Dim kind As ArgumentKind = ArgumentKind.Explicit If argument.WasCompilerGenerated Then If isDefault Then kind = ArgumentKind.DefaultValue ElseIf argument.Kind = BoundKind.ArrayCreation AndAlso DirectCast(argument, BoundArrayCreation).IsParamArrayArgument Then kind = ArgumentKind.ParamArray End If End If Return CreateArgumentOperation( kind, parameters(index), argument, New Conversion(Conversions.Identity), New Conversion(Conversions.Identity), isImplicit) End Select End Function Private Function CreateArgumentOperation( kind As ArgumentKind, parameter As IParameterSymbol, valueNode As BoundNode, inConversion As Conversion, outConversion As Conversion, isImplicit As Boolean) As IArgumentOperation ' put argument syntax to argument operation Dim syntax = If(valueNode.Syntax.Kind = SyntaxKind.OmittedArgument, valueNode.Syntax, TryCast(valueNode.Syntax?.Parent, ArgumentSyntax)) Dim value = Create(valueNode) If syntax Is Nothing Then syntax = value.Syntax isImplicit = True End If Return New ArgumentOperation( kind, parameter, value, inConversion, outConversion, _semanticModel, syntax, isImplicit) End Function Friend Function CreateReceiverOperation(node As BoundNode, symbol As ISymbol) As IOperation If node Is Nothing OrElse node.Kind = BoundKind.TypeExpression Then Return Nothing End If If symbol IsNot Nothing AndAlso node.WasCompilerGenerated AndAlso symbol.IsStatic AndAlso (node.Kind = BoundKind.MeReference OrElse node.Kind = BoundKind.WithLValueExpressionPlaceholder OrElse node.Kind = BoundKind.WithRValueExpressionPlaceholder) Then Return Nothing End If Return Create(node) End Function Private Function GetChildOfBadExpression(parent As BoundNode, index As Integer) As IOperation Dim child = Create(GetChildOfBadExpressionBoundNode(parent, index)) If child IsNot Nothing Then Return child End If Dim isImplicit As Boolean = parent.WasCompilerGenerated Return OperationFactory.CreateInvalidOperation(_semanticModel, parent.Syntax, ImmutableArray(Of IOperation).Empty, isImplicit) End Function Private Shared Function GetChildOfBadExpressionBoundNode(parent As BoundNode, index As Integer) As BoundExpression Dim badParent As BoundBadExpression = TryCast(parent, BoundBadExpression) If badParent?.ChildBoundNodes.Length > index Then Return badParent.ChildBoundNodes(index) End If Return Nothing End Function Friend Function GetAnonymousTypeCreationInitializers(expression As BoundAnonymousTypeCreationExpression) As ImmutableArray(Of IOperation) ' For error cases and non-assignment initializers, the binder generates only the argument. Debug.Assert(expression.Arguments.Length >= expression.Declarations.Length) Dim properties = DirectCast(expression.Type, AnonymousTypePublicSymbol).Properties Debug.Assert(properties.Length = expression.Arguments.Length) Dim builder = ArrayBuilder(Of IOperation).GetInstance(expression.Arguments.Length) Dim currentDeclarationIndex = 0 For i As Integer = 0 To expression.Arguments.Length - 1 Dim [property] As IPropertySymbol = properties(i) Dim value As IOperation = Create(expression.Arguments(i)) Dim target As IOperation Dim isImplicitAssignment As Boolean ' Find matching declaration for the current argument If currentDeclarationIndex >= expression.Declarations.Length OrElse i <> expression.Declarations(currentDeclarationIndex).PropertyIndex Then ' No matching declaration, synthesize a property reference with an implicit receiver to be assigned. Dim instance As IInstanceReferenceOperation = CreateAnonymousTypePropertyAccessImplicitReceiverOperation([property], expression.Syntax) target = New PropertyReferenceOperation( [property], constrainedToType:=Nothing, ImmutableArray(Of IArgumentOperation).Empty, instance, _semanticModel, value.Syntax, [property].Type, isImplicit:=True) isImplicitAssignment = True Else Debug.Assert(i = expression.Declarations(currentDeclarationIndex).PropertyIndex) target = CreateBoundAnonymousTypePropertyAccessOperation(expression.Declarations(currentDeclarationIndex), [property]) currentDeclarationIndex = currentDeclarationIndex + 1 isImplicitAssignment = expression.WasCompilerGenerated End If Dim isRef As Boolean = False Dim syntax As SyntaxNode = If(value.Syntax?.Parent, expression.Syntax) Dim type As ITypeSymbol = target.Type Dim constantValue As ConstantValue = value.GetConstantValue() Dim assignment = New SimpleAssignmentOperation(isRef, target, value, _semanticModel, syntax, type, constantValue, isImplicitAssignment) builder.Add(assignment) Next i Debug.Assert(currentDeclarationIndex = expression.Declarations.Length) Return builder.ToImmutableAndFree() End Function Private Shared Function GetSingleValueCaseClauseValue(clause As BoundSingleValueCaseClause) As BoundExpression Return GetCaseClauseValue(clause.ValueOpt, clause.ConditionOpt) End Function Friend Shared Function GetCaseClauseValue(valueOpt As BoundExpression, conditionOpt As BoundExpression) As BoundExpression If valueOpt IsNot Nothing Then Return valueOpt End If Select Case conditionOpt.Kind Case BoundKind.BinaryOperator Dim binaryOp As BoundBinaryOperator = DirectCast(conditionOpt, BoundBinaryOperator) Return binaryOp.Right Case BoundKind.UserDefinedBinaryOperator Dim binaryOp As BoundUserDefinedBinaryOperator = DirectCast(conditionOpt, BoundUserDefinedBinaryOperator) Return GetUserDefinedBinaryOperatorChildBoundNode(binaryOp, 1) Case Else Throw ExceptionUtilities.UnexpectedValue(conditionOpt.Kind) End Select End Function Friend Function GetVariableDeclarationStatementVariables(declarations As ImmutableArray(Of BoundLocalDeclarationBase)) As ImmutableArray(Of IVariableDeclarationOperation) ' Group the declarations by their VariableDeclaratorSyntaxes. The issue we're compensating for here is that the ' the declarations that are BoundLocalDeclaration nodes have a ModifiedIdentifierSyntax as their syntax nodes, ' not a VariableDeclaratorSyntax. We want to group BoundLocalDeclarations by their parent VariableDeclaratorSyntax ' nodes, and deduplicate based on that. As an example: ' ' Dim x, y = 1 ' ' This is an error scenario, but if we just use the BoundLocalDeclaration.Syntax.Parent directly, without deduplicating, ' we'll end up with two IVariableDeclarators that have the same syntax node. So, we group by VariableDeclaratorSyntax ' to put x and y in the same IMultiVariableDeclaration Dim groupedDeclarations = declarations.GroupBy(Function(declaration) If declaration.Kind = BoundKind.LocalDeclaration AndAlso declaration.Syntax.IsKind(SyntaxKind.ModifiedIdentifier) Then Debug.Assert(declaration.Syntax.Parent.IsKind(SyntaxKind.VariableDeclarator)) Return declaration.Syntax.Parent Else Return declaration.Syntax End If End Function) Dim builder = ArrayBuilder(Of IVariableDeclarationOperation).GetInstance() For Each declarationGroup In groupedDeclarations Dim first = declarationGroup.First() Dim declarators As ImmutableArray(Of IVariableDeclaratorOperation) = Nothing Dim initializer As IVariableInitializerOperation = Nothing If first.Kind = BoundKind.LocalDeclaration Then declarators = declarationGroup.Cast(Of BoundLocalDeclaration).SelectAsArray(AddressOf GetVariableDeclarator) ' The initializer we use for this group is the initializer attached to the last declaration in this declarator, as that's ' where it will be parsed in an error case. ' Initializer is only created if it's not the array initializer for the variable. That initializer is the initializer ' of the VariableDeclarator child. Dim last = DirectCast(declarationGroup.Last(), BoundLocalDeclaration) If last.DeclarationInitializerOpt IsNot Nothing Then Debug.Assert(last.Syntax.IsKind(SyntaxKind.ModifiedIdentifier)) Dim declaratorSyntax = DirectCast(last.Syntax.Parent, VariableDeclaratorSyntax) Dim initializerSyntax As SyntaxNode = declaratorSyntax.Initializer ' As New clauses with a single variable are bound as BoundLocalDeclarations, so adjust appropriately Dim isImplicit As Boolean = False If last.InitializedByAsNew Then initializerSyntax = declaratorSyntax.AsClause ElseIf initializerSyntax Is Nothing Then ' There is no explicit syntax for the initializer, so we use the initializerValue's syntax and mark the operation as implicit. initializerSyntax = last.InitializerOpt.Syntax isImplicit = True End If Debug.Assert(last.InitializerOpt IsNot Nothing) Dim value = Create(last.InitializerOpt) initializer = New VariableInitializerOperation(locals:=ImmutableArray(Of ILocalSymbol).Empty, value, _semanticModel, initializerSyntax, isImplicit) End If Else Dim asNewDeclarations = DirectCast(first, BoundAsNewLocalDeclarations) declarators = asNewDeclarations.LocalDeclarations.SelectAsArray(AddressOf GetVariableDeclarator) Dim initializerSyntax As AsClauseSyntax = DirectCast(asNewDeclarations.Syntax, VariableDeclaratorSyntax).AsClause Dim initializerValue As IOperation = Create(asNewDeclarations.Initializer) Debug.Assert(asNewDeclarations.Initializer IsNot Nothing) Dim value = Create(asNewDeclarations.Initializer) initializer = New VariableInitializerOperation(locals:=ImmutableArray(Of ILocalSymbol).Empty, value, _semanticModel, initializerSyntax, isImplicit:=False) End If builder.Add(New VariableDeclarationOperation(declarators, initializer, ImmutableArray(Of IOperation).Empty, _semanticModel, declarationGroup.Key, isImplicit:=False)) Next Return builder.ToImmutableAndFree() End Function Private Function GetVariableDeclarator(boundLocalDeclaration As BoundLocalDeclaration) As IVariableDeclaratorOperation Dim initializer As IVariableInitializerOperation = Nothing If boundLocalDeclaration.IdentifierInitializerOpt IsNot Nothing Then Dim syntax = boundLocalDeclaration.Syntax Dim initializerValue As IOperation = Create(boundLocalDeclaration.IdentifierInitializerOpt) initializer = New VariableInitializerOperation(locals:=ImmutableArray(Of ILocalSymbol).Empty, initializerValue, _semanticModel, syntax, isImplicit:=True) End If Dim ignoredArguments = ImmutableArray(Of IOperation).Empty Return New VariableDeclaratorOperation(boundLocalDeclaration.LocalSymbol, initializer, ignoredArguments, _semanticModel, boundLocalDeclaration.Syntax, isImplicit:=boundLocalDeclaration.WasCompilerGenerated) End Function Private Function GetUsingStatementDeclaration(resourceList As ImmutableArray(Of BoundLocalDeclarationBase), syntax As SyntaxNode) As IVariableDeclarationGroupOperation Return New VariableDeclarationGroupOperation( GetVariableDeclarationStatementVariables(resourceList), _semanticModel, syntax, isImplicit:=False) ' Declaration is always explicit End Function Friend Function GetAddRemoveHandlerStatementExpression(statement As BoundAddRemoveHandlerStatement) As IOperation Dim eventReference As IOperation = Create(statement.EventAccess) Dim handlerValue As IOperation = Create(statement.Handler) Dim adds = statement.Kind = BoundKind.AddHandlerStatement Return New EventAssignmentOperation(eventReference, handlerValue, adds, _semanticModel, statement.Syntax, type:=Nothing, isImplicit:=True) End Function #Region "Conversions" ''' <summary> ''' Creates the Lazy IOperation from a delegate creation operand or a bound conversion operand, handling when the conversion ''' is actually a delegate creation. ''' </summary> Private Function GetConversionInfo(boundConversion As BoundConversionOrCast ) As (Operation As IOperation, Conversion As Conversion, IsDelegateCreation As Boolean) Dim conversion = CreateConversion(boundConversion) Dim boundOperand = GetConversionOperand(boundConversion) If conversion.IsIdentity AndAlso boundConversion.ExplicitCastInCode Then Dim adjustedInfo = TryGetAdjustedConversionInfo(boundConversion, boundOperand) If adjustedInfo.Operation IsNot Nothing Then Return adjustedInfo End If End If If IsDelegateCreation(boundConversion.Syntax, boundOperand, boundConversion.Type) Then Return (CreateDelegateCreationConversionOperand(boundOperand), conversion, IsDelegateCreation:=True) Else Return (Create(boundOperand), conversion, IsDelegateCreation:=False) End If End Function Private Function TryGetAdjustedConversionInfo(topLevelConversion As BoundConversionOrCast, boundOperand As BoundExpression ) As (Operation As IOperation, Conversion As Conversion, IsDelegateCreation As Boolean) ' Dig through the bound tree to see if this is an artificial nested conversion. If so, let's erase the nested conversion. ' Artificial conversions are added on top of BoundConvertedTupleLiteral in Binder.ReclassifyTupleLiteral, or in ' ReclassifyUnboundLambdaExpression and the like. We need to use conversion information from the nested conversion ' because that is where the real conversion information is stored. If boundOperand.Kind = BoundKind.Parenthesized Then Dim adjustedInfo = TryGetAdjustedConversionInfo(topLevelConversion, DirectCast(boundOperand, BoundParenthesized).Expression) If adjustedInfo.Operation IsNot Nothing Then Return (Operation:=New ParenthesizedOperation(adjustedInfo.Operation, _semanticModel, boundOperand.Syntax, adjustedInfo.Operation.Type, boundOperand.ConstantValueOpt, boundOperand.WasCompilerGenerated), adjustedInfo.Conversion, adjustedInfo.IsDelegateCreation) End If ElseIf boundOperand.Kind = topLevelConversion.Kind Then Dim nestedConversion = DirectCast(boundOperand, BoundConversionOrCast) Dim nestedOperand As BoundExpression = GetConversionOperand(nestedConversion) If nestedConversion.Syntax Is nestedOperand.Syntax AndAlso Not TypeSymbol.Equals(nestedConversion.Type, nestedOperand.Type, TypeCompareKind.ConsiderEverything) AndAlso nestedConversion.ExplicitCastInCode AndAlso TypeSymbol.Equals(topLevelConversion.Type, nestedConversion.Type, TypeCompareKind.ConsiderEverything) Then Return GetConversionInfo(nestedConversion) End If ElseIf boundOperand.Syntax.IsKind(SyntaxKind.AddressOfExpression) AndAlso TypeSymbol.Equals(topLevelConversion.Type, boundOperand.Type, TypeCompareKind.ConsiderEverything) AndAlso IsDelegateCreation(topLevelConversion.Syntax, boundOperand, boundOperand.Type) Then Return (CreateDelegateCreationConversionOperand(boundOperand), Conversion:=Nothing, IsDelegateCreation:=True) End If Return Nothing End Function ''' <summary> ''' Gets the operand from a BoundConversion, compensating for if the conversion is a user-defined conversion ''' </summary> Private Shared Function GetConversionOperand(boundConversion As BoundConversionOrCast) As BoundExpression If (boundConversion.ConversionKind And ConversionKind.UserDefined) = ConversionKind.UserDefined Then Dim userDefinedConversion = DirectCast(boundConversion.Operand, BoundUserDefinedConversion) Return userDefinedConversion.Operand Else Return boundConversion.Operand End If End Function Private Function CreateDelegateCreationConversionOperand(operand As BoundExpression) As IOperation If operand.Kind = BoundKind.DelegateCreationExpression Then ' If the child is a BoundDelegateCreationExpression, we don't want to generate a nested IDelegateCreationExpression. ' So, the operand for the conversion will be the child of the BoundDelegateCreationExpression. ' We see this in this syntax: Dim x = New Action(AddressOf M2) ' This should be semantically equivalent to: Dim x = AddressOf M2 ' However, if we didn't fix this up, we would have nested IDelegateCreationExpressions here for the former case. Return CreateBoundDelegateCreationExpressionChildOperation(DirectCast(operand, BoundDelegateCreationExpression)) Else Return Create(operand) End If End Function Private Shared Function CreateConversion(expression As BoundExpression) As Conversion If expression.Kind = BoundKind.Conversion Then Dim conversion = DirectCast(expression, BoundConversion) Dim conversionKind = conversion.ConversionKind Dim method As MethodSymbol = Nothing If conversionKind.HasFlag(VisualBasic.ConversionKind.UserDefined) AndAlso conversion.Operand.Kind = BoundKind.UserDefinedConversion Then method = DirectCast(conversion.Operand, BoundUserDefinedConversion).Call.Method End If Return New Conversion(KeyValuePair.Create(conversionKind, method)) ElseIf expression.Kind = BoundKind.TryCast OrElse expression.Kind = BoundKind.DirectCast Then Return New Conversion(KeyValuePair.Create(Of ConversionKind, MethodSymbol)(DirectCast(expression, BoundConversionOrCast).ConversionKind, Nothing)) End If Return New Conversion(Conversions.Identity) End Function Private Shared Function IsDelegateCreation(conversionSyntax As SyntaxNode, operand As BoundNode, targetType As TypeSymbol) As Boolean If Not targetType.IsDelegateType() Then Return False End If ' Any of the explicit cast types, as well as New DelegateType(AddressOf Method) ' Additionally, AddressOf, if the child AddressOf is the same SyntaxNode (ie, an implicit delegate creation) ' In the case of AddressOf, the operand can be a BoundDelegateCreationExpression, a BoundAddressOfOperator, or ' a BoundBadExpression. For simplicity, we just do a syntax check to make sure it's an AddressOfExpression so ' we don't have to compare against all 3 BoundKinds Dim validAddressOfConversionSyntax = operand.Syntax.Kind() = SyntaxKind.AddressOfExpression AndAlso (conversionSyntax.Kind() = SyntaxKind.CTypeExpression OrElse conversionSyntax.Kind() = SyntaxKind.DirectCastExpression OrElse conversionSyntax.Kind() = SyntaxKind.TryCastExpression OrElse conversionSyntax.Kind() = SyntaxKind.ObjectCreationExpression OrElse (conversionSyntax.Kind() = SyntaxKind.AddressOfExpression AndAlso conversionSyntax Is operand.Syntax)) Dim validLambdaConversionNode = operand.Kind = BoundKind.Lambda OrElse operand.Kind = BoundKind.QueryLambda OrElse operand.Kind = BoundKind.UnboundLambda Return validAddressOfConversionSyntax OrElse validLambdaConversionNode End Function #End Region Friend Class Helper Friend Shared Function DeriveUnaryOperatorKind(operatorKind As VisualBasic.UnaryOperatorKind) As UnaryOperatorKind Select Case operatorKind And VisualBasic.UnaryOperatorKind.OpMask Case VisualBasic.UnaryOperatorKind.Plus Return UnaryOperatorKind.Plus Case VisualBasic.UnaryOperatorKind.Minus Return UnaryOperatorKind.Minus Case VisualBasic.UnaryOperatorKind.Not Return UnaryOperatorKind.Not Case VisualBasic.UnaryOperatorKind.IsTrue Return UnaryOperatorKind.True Case VisualBasic.UnaryOperatorKind.IsFalse Return UnaryOperatorKind.False Case Else Return UnaryOperatorKind.None End Select End Function Friend Shared Function DeriveBinaryOperatorKind(operatorKind As VisualBasic.BinaryOperatorKind, leftOpt As BoundExpression) As BinaryOperatorKind Select Case operatorKind And VisualBasic.BinaryOperatorKind.OpMask Case VisualBasic.BinaryOperatorKind.Add Return BinaryOperatorKind.Add Case VisualBasic.BinaryOperatorKind.Subtract Return BinaryOperatorKind.Subtract Case VisualBasic.BinaryOperatorKind.Multiply Return BinaryOperatorKind.Multiply Case VisualBasic.BinaryOperatorKind.Divide Return BinaryOperatorKind.Divide Case VisualBasic.BinaryOperatorKind.IntegerDivide Return BinaryOperatorKind.IntegerDivide Case VisualBasic.BinaryOperatorKind.Modulo Return BinaryOperatorKind.Remainder Case VisualBasic.BinaryOperatorKind.And Return BinaryOperatorKind.And Case VisualBasic.BinaryOperatorKind.Or Return BinaryOperatorKind.Or Case VisualBasic.BinaryOperatorKind.Xor Return BinaryOperatorKind.ExclusiveOr Case VisualBasic.BinaryOperatorKind.AndAlso Return BinaryOperatorKind.ConditionalAnd Case VisualBasic.BinaryOperatorKind.OrElse Return BinaryOperatorKind.ConditionalOr Case VisualBasic.BinaryOperatorKind.LeftShift Return BinaryOperatorKind.LeftShift Case VisualBasic.BinaryOperatorKind.RightShift Return BinaryOperatorKind.RightShift Case VisualBasic.BinaryOperatorKind.LessThan Return BinaryOperatorKind.LessThan Case VisualBasic.BinaryOperatorKind.LessThanOrEqual Return BinaryOperatorKind.LessThanOrEqual Case VisualBasic.BinaryOperatorKind.Equals Return If(leftOpt?.Type?.SpecialType = SpecialType.System_Object, BinaryOperatorKind.ObjectValueEquals, BinaryOperatorKind.Equals) Case VisualBasic.BinaryOperatorKind.NotEquals Return If(leftOpt?.Type?.SpecialType = SpecialType.System_Object, BinaryOperatorKind.ObjectValueNotEquals, BinaryOperatorKind.NotEquals) Case VisualBasic.BinaryOperatorKind.Is Return BinaryOperatorKind.Equals Case VisualBasic.BinaryOperatorKind.IsNot Return BinaryOperatorKind.NotEquals Case VisualBasic.BinaryOperatorKind.GreaterThanOrEqual Return BinaryOperatorKind.GreaterThanOrEqual Case VisualBasic.BinaryOperatorKind.GreaterThan Return BinaryOperatorKind.GreaterThan Case VisualBasic.BinaryOperatorKind.Power Return BinaryOperatorKind.Power Case VisualBasic.BinaryOperatorKind.Like Return BinaryOperatorKind.Like Case VisualBasic.BinaryOperatorKind.Concatenate Return BinaryOperatorKind.Concatenate Case Else Return BinaryOperatorKind.None End Select End Function End Class End Class End Namespace