/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Binding/Binder_Operators.vb
1 291 строка
67 KB
Jan Jones
Suppress Lock conversion warnings when using object equality operators (#72459)
13 мар 2024, 12:12
Не верифицирован
13 мар 2024, 12:12
c40aa62
Код
Авторство
О чём код?
' 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.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Namespace Microsoft.CodeAnalysis.VisualBasic ' Binding of binary and unary operators is implemented in this part. Partial Friend Class Binder Private Function BindIsExpression( node As BinaryExpressionSyntax, diagnostics As BindingDiagnosticBag ) As BoundExpression Debug.Assert(node.Kind = SyntaxKind.IsExpression OrElse node.Kind = SyntaxKind.IsNotExpression) Dim [isNot] As Boolean = (node.Kind = SyntaxKind.IsNotExpression) ' The function below will make sure they are RValues. Dim left As BoundExpression = BindExpression(node.Left, diagnostics) Dim right As BoundExpression = BindExpression(node.Right, diagnostics) Return BindIsExpression(left, right, node, [isNot], diagnostics) End Function Private Function BindIsExpression( left As BoundExpression, right As BoundExpression, node As SyntaxNode, [isNot] As Boolean, diagnostics As BindingDiagnosticBag ) As BoundExpression left = MakeRValue(left, diagnostics) right = MakeRValue(right, diagnostics) ' Suppress Lock conversion warnings for Is operator. Dim needsFilterDiagnostics = diagnostics.AccumulatesDiagnostics Dim conversionDiagnostics = If(needsFilterDiagnostics, BindingDiagnosticBag.GetInstance(diagnostics), diagnostics) left = ValidateAndConvertIsExpressionArgument(left, right, [isNot], conversionDiagnostics) right = ValidateAndConvertIsExpressionArgument(right, left, [isNot], conversionDiagnostics) If needsFilterDiagnostics Then Debug.Assert(conversionDiagnostics IsNot diagnostics) diagnostics.AddDependencies(conversionDiagnostics) Dim sourceBag = conversionDiagnostics.DiagnosticBag Debug.Assert(sourceBag IsNot Nothing) If Not sourceBag.IsEmptyWithoutResolution Then For Each diagnostic In sourceBag.AsEnumerableWithoutResolution() Dim code As Integer Dim diagnosticWithInfo = TryCast(diagnostic, DiagnosticWithInfo) If diagnosticWithInfo IsNot Nothing AndAlso diagnosticWithInfo.HasLazyInfo Then code = diagnosticWithInfo.LazyInfo.Code Else code = diagnostic.Code End If If code <> ERRID.WRN_ConvertingLock Then diagnostics.Add(diagnostic) End If Next End If conversionDiagnostics.Free() End If Dim result As BoundExpression Dim booleanType = GetSpecialType(SpecialType.System_Boolean, node, diagnostics) result = New BoundBinaryOperator(node, If([isNot], BinaryOperatorKind.IsNot, BinaryOperatorKind.Is), left, right, checked:=False, type:=booleanType, hasErrors:=booleanType.IsErrorType()) ' TODO: Add rewrite for Nullable. Return result End Function ''' <summary> ''' Validate and apply appropriate conversion for the target argument of Is/IsNot expression. ''' </summary> Private Function ValidateAndConvertIsExpressionArgument( targetArgument As BoundExpression, otherArgument As BoundExpression, [isNot] As Boolean, diagnostics As BindingDiagnosticBag ) As BoundExpression Dim targetArgumentType As TypeSymbol = targetArgument.Type Dim result As BoundExpression If targetArgument.IsNothingLiteral() Then result = targetArgument ElseIf targetArgumentType.IsErrorType() Then result = targetArgument ElseIf targetArgumentType.IsReferenceType Then result = ApplyImplicitConversion(targetArgument.Syntax, GetSpecialType(SpecialType.System_Object, targetArgument.Syntax, diagnostics), targetArgument, diagnostics) ElseIf targetArgumentType.IsNullableType() Then If Not otherArgument.HasErrors AndAlso Not otherArgument.IsNothingLiteral() Then ReportDiagnostic(diagnostics, targetArgument.Syntax, If([isNot], ERRID.ERR_IsNotOperatorNullable1, ERRID.ERR_IsOperatorNullable1), targetArgumentType) End If result = targetArgument ElseIf targetArgumentType.IsTypeParameter() AndAlso Not targetArgumentType.IsValueType Then If Not otherArgument.HasErrors AndAlso Not otherArgument.IsNothingLiteral() Then ReportDiagnostic(diagnostics, targetArgument.Syntax, If([isNot], ERRID.ERR_IsNotOperatorGenericParam1, ERRID.ERR_IsOperatorGenericParam1), targetArgumentType) End If ' If any of the left or right operands of the Is or IsNot operands ' are entities of type parameters types, then they need to be boxed. result = ApplyImplicitConversion(targetArgument.Syntax, GetSpecialType(SpecialType.System_Object, targetArgument.Syntax, diagnostics), targetArgument, diagnostics) Else ReportDiagnostic(diagnostics, targetArgument.Syntax, If([isNot], ERRID.ERR_IsNotOpRequiresReferenceTypes1, ERRID.ERR_IsOperatorRequiresReferenceTypes1), targetArgumentType) result = targetArgument End If Return result End Function Private Function BindBinaryOperator( node As BinaryExpressionSyntax, isOperandOfConditionalBranch As Boolean, diagnostics As BindingDiagnosticBag ) As BoundExpression ' Some tools, such as ASP .NET, generate expressions containing thousands ' of string concatenations. For this reason, for string concatenations, ' avoid the usual recursion along the left side of the parse. Also, attempt ' to flatten whole sequences of string literal concatenations to avoid ' allocating space for intermediate results. Dim preliminaryOperatorKind As BinaryOperatorKind = OverloadResolution.MapBinaryOperatorKind(node.Kind) Dim propagateIsOperandOfConditionalBranch = isOperandOfConditionalBranch AndAlso (preliminaryOperatorKind = BinaryOperatorKind.AndAlso OrElse preliminaryOperatorKind = BinaryOperatorKind.OrElse) Dim binary As BinaryExpressionSyntax = node Dim child As ExpressionSyntax Do child = binary.Left Select Case child.Kind Case SyntaxKind.AddExpression, SyntaxKind.ConcatenateExpression, SyntaxKind.LikeExpression, SyntaxKind.EqualsExpression, SyntaxKind.NotEqualsExpression, SyntaxKind.LessThanOrEqualExpression, SyntaxKind.GreaterThanOrEqualExpression, SyntaxKind.LessThanExpression, SyntaxKind.GreaterThanExpression, SyntaxKind.SubtractExpression, SyntaxKind.MultiplyExpression, SyntaxKind.ExponentiateExpression, SyntaxKind.DivideExpression, SyntaxKind.ModuloExpression, SyntaxKind.IntegerDivideExpression, SyntaxKind.LeftShiftExpression, SyntaxKind.RightShiftExpression, SyntaxKind.ExclusiveOrExpression, SyntaxKind.OrExpression, SyntaxKind.AndExpression If propagateIsOperandOfConditionalBranch Then Exit Do End If Case SyntaxKind.OrElseExpression, SyntaxKind.AndAlsoExpression Exit Select Case Else Exit Do End Select binary = DirectCast(child, BinaryExpressionSyntax) Loop Dim left As BoundExpression = BindValue(child, diagnostics, propagateIsOperandOfConditionalBranch) Do binary = DirectCast(child.Parent, BinaryExpressionSyntax) Dim right As BoundExpression = BindValue(binary.Right, diagnostics, propagateIsOperandOfConditionalBranch) left = BindBinaryOperator(binary, left, right, binary.OperatorToken.Kind, OverloadResolution.MapBinaryOperatorKind(binary.Kind), If(binary Is node, isOperandOfConditionalBranch, propagateIsOperandOfConditionalBranch), diagnostics) child = binary Loop While child IsNot node Return left End Function Private Function BindBinaryOperator( node As SyntaxNode, left As BoundExpression, right As BoundExpression, operatorTokenKind As SyntaxKind, preliminaryOperatorKind As BinaryOperatorKind, isOperandOfConditionalBranch As Boolean, diagnostics As BindingDiagnosticBag, Optional isSelectCase As Boolean = False ) As BoundExpression Debug.Assert(left.IsValue) Debug.Assert(right.IsValue) Dim originalDiagnostics = diagnostics If (left.HasErrors OrElse right.HasErrors) Then ' Suppress any additional diagnostics by overriding DiagnosticBag. diagnostics = BindingDiagnosticBag.Discarded End If ' Deal with NOTHING literal as an input. ConvertNothingLiterals(preliminaryOperatorKind, left, right, diagnostics) left = MakeRValue(left, diagnostics) right = MakeRValue(right, diagnostics) If (left.HasErrors OrElse right.HasErrors) Then ' Suppress any additional diagnostics by overriding DiagnosticBag. If diagnostics Is originalDiagnostics Then diagnostics = BindingDiagnosticBag.Discarded End If End If Dim leftType As TypeSymbol = left.Type Dim rightType As TypeSymbol = right.Type Dim leftIsDBNull As Boolean = leftType.IsDBNullType() Dim rightIsDBNull As Boolean = rightType.IsDBNullType() '§11.16 Concatenation Operator 'A System.DBNull value is converted to the literal Nothing typed as String. If (preliminaryOperatorKind = BinaryOperatorKind.Concatenate AndAlso leftIsDBNull <> rightIsDBNull) OrElse (preliminaryOperatorKind = BinaryOperatorKind.Add AndAlso ((leftType.IsStringType() AndAlso rightIsDBNull) OrElse (leftIsDBNull AndAlso rightType.IsStringType))) Then Debug.Assert(leftIsDBNull Xor rightIsDBNull) If leftIsDBNull Then leftType = SubstituteDBNullWithNothingString(left, rightType, diagnostics) Else rightType = SubstituteDBNullWithNothingString(right, leftType, diagnostics) End If End If ' For comparison operators, the result type computed here is not ' the result type of the comparison (which is typically boolean), ' but is the type to which the operands are to be converted. For ' other operators, the type computed here is both the result type ' and the common operand type. Dim intrinsicOperatorType As SpecialType = SpecialType.None Dim userDefinedOperator As OverloadResolution.OverloadResolutionResult = Nothing Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) Dim operatorKind As BinaryOperatorKind = OverloadResolution.ResolveBinaryOperator(preliminaryOperatorKind, left, right, Me, True, intrinsicOperatorType, userDefinedOperator, useSiteInfo) If diagnostics.Add(node, useSiteInfo) Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If If operatorKind = BinaryOperatorKind.UserDefined Then Dim bestCandidate As OverloadResolution.Candidate = If(userDefinedOperator.BestResult.HasValue, userDefinedOperator.BestResult.Value.Candidate, Nothing) If bestCandidate Is Nothing OrElse Not bestCandidate.IsLifted OrElse (OverloadResolution.IsValidInLiftedSignature(bestCandidate.Parameters(0).Type) AndAlso OverloadResolution.IsValidInLiftedSignature(bestCandidate.Parameters(1).Type) AndAlso OverloadResolution.IsValidInLiftedSignature(bestCandidate.ReturnType)) Then If preliminaryOperatorKind = BinaryOperatorKind.AndAlso OrElse preliminaryOperatorKind = BinaryOperatorKind.OrElse Then Return BindUserDefinedShortCircuitingOperator(node, preliminaryOperatorKind, left, right, userDefinedOperator, diagnostics) Else Return BindUserDefinedNonShortCircuitingBinaryOperator(node, preliminaryOperatorKind, left, right, userDefinedOperator, diagnostics) End If End If operatorKind = BinaryOperatorKind.Error End If If operatorKind = BinaryOperatorKind.Error Then ReportUndefinedOperatorError(node, left, right, operatorTokenKind, preliminaryOperatorKind, diagnostics) Return New BoundBinaryOperator(node, preliminaryOperatorKind Or BinaryOperatorKind.Error, left, right, CheckOverflow, ErrorTypeSymbol.UnknownResultType, hasErrors:=True) End If ' We are dealing with intrinsic operator ' Get the symbol for operand type Dim operandType As TypeSymbol If intrinsicOperatorType = SpecialType.None Then ' Must be a bitwise operation with enum type. Debug.Assert(leftType.GetNullableUnderlyingTypeOrSelf().IsEnumType() AndAlso leftType.GetNullableUnderlyingTypeOrSelf().IsSameTypeIgnoringAll(rightType.GetNullableUnderlyingTypeOrSelf())) If (operatorKind And BinaryOperatorKind.Lifted) = 0 OrElse leftType.IsNullableType() Then operandType = leftType Else Debug.Assert(rightType.IsNullableType()) operandType = rightType End If Else operandType = GetSpecialTypeForBinaryOperator(node, leftType, rightType, intrinsicOperatorType, (operatorKind And BinaryOperatorKind.Lifted) <> 0, diagnostics) End If ' Get the symbol for result type Dim operatorResultType As TypeSymbol = operandType Dim forceToBooleanType As TypeSymbol = Nothing Select Case preliminaryOperatorKind Case BinaryOperatorKind.Equals, BinaryOperatorKind.NotEquals, BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThan, BinaryOperatorKind.GreaterThan, BinaryOperatorKind.Like If OptionCompareText AndAlso (operandType.IsObjectType() OrElse operandType.IsStringType()) Then operatorKind = operatorKind Or BinaryOperatorKind.CompareText End If If Not operatorResultType.IsObjectType() OrElse (isOperandOfConditionalBranch AndAlso preliminaryOperatorKind <> BinaryOperatorKind.Like) Then Dim booleanType As TypeSymbol = GetSpecialTypeForBinaryOperator(node, leftType, rightType, SpecialType.System_Boolean, False, diagnostics) If (operatorKind And BinaryOperatorKind.Lifted) <> 0 Then operatorResultType = GetNullableTypeForBinaryOperator(leftType, rightType, booleanType) If (preliminaryOperatorKind = BinaryOperatorKind.Equals OrElse preliminaryOperatorKind = BinaryOperatorKind.NotEquals) AndAlso (IsKnownToBeNullableNothing(left) OrElse IsKnownToBeNullableNothing(right)) Then ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo( If(preliminaryOperatorKind = BinaryOperatorKind.Equals, ERRID.WRN_EqualToLiteralNothing, ERRID.WRN_NotEqualToLiteralNothing))) End If Else If Not operatorResultType.IsObjectType() Then operatorResultType = booleanType Else ' I believe this is just an optimization to prevent Object from bubbling up the tree. Debug.Assert(isOperandOfConditionalBranch AndAlso preliminaryOperatorKind <> BinaryOperatorKind.Like) forceToBooleanType = booleanType End If End If End If End Select If operandType.GetNullableUnderlyingTypeOrSelf().IsErrorType() OrElse operatorResultType.GetNullableUnderlyingTypeOrSelf().IsErrorType() OrElse (forceToBooleanType IsNot Nothing AndAlso forceToBooleanType.GetNullableUnderlyingTypeOrSelf().IsErrorType()) Then ' Suppress any additional diagnostics by overriding DiagnosticBag. If diagnostics Is originalDiagnostics Then diagnostics = BindingDiagnosticBag.Discarded End If End If Dim hasError As Boolean = False ' Option Strict disallows all operations on Object operands. Or, at least, warn. If OptionStrict = VisualBasic.OptionStrict.On Then Dim reportedAnEror As Boolean = False If leftType.IsObjectType Then ReportBinaryOperatorOnObject(operatorTokenKind, left, preliminaryOperatorKind, diagnostics) reportedAnEror = True End If If rightType.IsObjectType() Then ReportBinaryOperatorOnObject(operatorTokenKind, right, preliminaryOperatorKind, diagnostics) reportedAnEror = True End If If reportedAnEror Then hasError = True ' Suppress any additional diagnostics by overriding DiagnosticBag. If diagnostics Is originalDiagnostics Then diagnostics = BindingDiagnosticBag.Discarded End If End If ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then 'warn if option strict is off If Not isSelectCase OrElse preliminaryOperatorKind <> BinaryOperatorKind.OrElse Then Dim errorId = If(isSelectCase, ERRID.WRN_ObjectMathSelectCase, If(preliminaryOperatorKind = BinaryOperatorKind.Equals, ERRID.WRN_ObjectMath1, If(preliminaryOperatorKind = BinaryOperatorKind.NotEquals, ERRID.WRN_ObjectMath1Not, ERRID.WRN_ObjectMath2))) If leftType.IsObjectType Then ReportDiagnostic(diagnostics, left.Syntax, ErrorFactory.ErrorInfo(errorId, operatorTokenKind)) End If If rightType.IsObjectType Then ReportDiagnostic(diagnostics, right.Syntax, ErrorFactory.ErrorInfo(errorId, operatorTokenKind)) End If End If End If ' Apply conversions to operands. Dim explicitSemanticForConcatArgument As Boolean = False ' Concatenation will apply conversions to its operands as if the ' conversions were explicit. Effectively, the use of the concatenation ' operator is treated as an explicit conversion to String. If preliminaryOperatorKind = BinaryOperatorKind.Concatenate Then explicitSemanticForConcatArgument = True Debug.Assert((operatorKind And BinaryOperatorKind.Lifted) = 0) If operandType.IsStringType() Then If left.Type.IsNullableType Then left = ForceLiftToEmptyString(left, operandType, diagnostics) End If If right.Type.IsNullableType Then right = ForceLiftToEmptyString(right, operandType, diagnostics) End If End If End If Dim beforeConversion As BoundExpression = left left = ApplyConversion(left.Syntax, operandType, left, explicitSemanticForConcatArgument, diagnostics, explicitSemanticForConcatArgument:=explicitSemanticForConcatArgument) If explicitSemanticForConcatArgument AndAlso left IsNot beforeConversion AndAlso left.Kind = BoundKind.Conversion Then Dim conversion = DirectCast(left, BoundConversion) left = conversion.Update(conversion.Operand, conversion.ConversionKind, conversion.Checked, explicitCastInCode:=False, constantValueOpt:=conversion.ConstantValueOpt, extendedInfoOpt:=conversion.ExtendedInfoOpt, type:=conversion.Type) End If If (preliminaryOperatorKind = BinaryOperatorKind.LeftShift OrElse preliminaryOperatorKind = BinaryOperatorKind.RightShift) AndAlso Not operandType.IsObjectType() Then Dim rightTargetType As TypeSymbol = GetSpecialTypeForBinaryOperator(node, leftType, rightType, SpecialType.System_Int32, False, diagnostics) '§11.18 Shift Operators 'The type of the right operand must be implicitly convertible to Integer ' If operator is lifted, convert right operand to Nullable(Of Integer) If (operatorKind And BinaryOperatorKind.Lifted) <> 0 Then rightTargetType = GetNullableTypeForBinaryOperator(leftType, rightType, rightTargetType) End If right = ApplyImplicitConversion(right.Syntax, rightTargetType, right, diagnostics) Else beforeConversion = right right = ApplyConversion(right.Syntax, operandType, right, explicitSemanticForConcatArgument, diagnostics, explicitSemanticForConcatArgument:=explicitSemanticForConcatArgument) If explicitSemanticForConcatArgument AndAlso right IsNot beforeConversion AndAlso right.Kind = BoundKind.Conversion Then Dim conversion = DirectCast(right, BoundConversion) right = conversion.Update(conversion.Operand, conversion.ConversionKind, conversion.Checked, explicitCastInCode:=False, constantValueOpt:=conversion.ConstantValueOpt, extendedInfoOpt:=conversion.ExtendedInfoOpt, type:=conversion.Type) End If End If If (operatorKind And BinaryOperatorKind.OpMask) = BinaryOperatorKind.Add AndAlso operatorResultType.IsStringType() Then ' Transform the addition into a string concatenation. This won't use a runtime helper - it will turn into System.String::Concat operatorKind = (operatorKind And (Not BinaryOperatorKind.OpMask)) operatorKind = operatorKind Or BinaryOperatorKind.Concatenate End If ' Perform constant folding. Dim value As ConstantValue = Nothing If Not (left.HasErrors OrElse right.HasErrors) Then Dim integerOverflow As Boolean = False Dim divideByZero As Boolean = False Dim lengthOutOfLimit As Boolean = False value = OverloadResolution.TryFoldConstantBinaryOperator(operatorKind, left, right, operatorResultType, integerOverflow, divideByZero, lengthOutOfLimit) If value IsNot Nothing Then If divideByZero Then Debug.Assert(value.IsBad) ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ZeroDivide)) ElseIf lengthOutOfLimit Then Debug.Assert(value.IsBad) ReportDiagnostic(diagnostics, right.Syntax, ErrorFactory.ErrorInfo(ERRID.ERR_ConstantStringTooLong)) ElseIf (value.IsBad OrElse integerOverflow) Then ' Overflows are reported regardless of the value of OptionRemoveIntegerOverflowChecks, Dev10 behavior. ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ExpressionOverflow1, operatorResultType)) ' there should be no constant value in case of overflows. If Not value.IsBad Then value = ConstantValue.Bad End If End If End If End If Dim result As BoundExpression = New BoundBinaryOperator(node, operatorKind Or If(isOperandOfConditionalBranch, BinaryOperatorKind.IsOperandOfConditionalBranch, Nothing), left, right, CheckOverflow, value, operatorResultType, hasError) If forceToBooleanType IsNot Nothing Then Debug.Assert(forceToBooleanType.IsBooleanType()) result = ApplyConversion(node, forceToBooleanType, result, isExplicit:=True, diagnostics:=diagnostics) End If Return result End Function ''' <summary> ''' This helper is used to wrap nullable argument into something that would return null string if argument is null. ''' ''' Unlike conversion to a string where nullable nulls result in an exception, ''' concatenation requires that nullable nulls are treated as null strings. ''' Note that conversion is treated as explicit conversion. ''' </summary> Private Function ForceLiftToEmptyString(left As BoundExpression, stringType As TypeSymbol, diagnostics As BindingDiagnosticBag) As BoundExpression Debug.Assert(stringType.IsStringType) Dim nothingStr = New BoundLiteral(left.Syntax, ConstantValue.Nothing, stringType).MakeCompilerGenerated() Return AnalyzeConversionAndCreateBinaryConditionalExpression(left.Syntax, left, nothingStr, Nothing, stringType, False, diagnostics, explicitConversion:=True).MakeCompilerGenerated() End Function Private Function BindUserDefinedNonShortCircuitingBinaryOperator( node As SyntaxNode, opKind As BinaryOperatorKind, left As BoundExpression, right As BoundExpression, <[In]> ByRef userDefinedOperator As OverloadResolution.OverloadResolutionResult, diagnostics As BindingDiagnosticBag ) As BoundUserDefinedBinaryOperator Debug.Assert(userDefinedOperator.Candidates.Length > 0) opKind = opKind Or BinaryOperatorKind.UserDefined Dim result As BoundExpression If userDefinedOperator.BestResult.HasValue Then Dim bestCandidate As OverloadResolution.CandidateAnalysisResult = userDefinedOperator.BestResult.Value result = CreateBoundCallOrPropertyAccess(node, node, TypeCharacter.None, New BoundMethodGroup(node, Nothing, ImmutableArray.Create(Of MethodSymbol)( DirectCast(bestCandidate.Candidate.UnderlyingSymbol, MethodSymbol)), LookupResultKind.Good, Nothing, QualificationKind.Unqualified).MakeCompilerGenerated(), ImmutableArray.Create(Of BoundExpression)(left, right), bestCandidate, userDefinedOperator.AsyncLambdaSubToFunctionMismatch, diagnostics) If bestCandidate.Candidate.IsLifted Then opKind = opKind Or BinaryOperatorKind.Lifted End If Else result = ReportOverloadResolutionFailureAndProduceBoundNode(node, LookupResultKind.Good, ImmutableArray.Create(Of BoundExpression)(left, right), Nothing, userDefinedOperator, diagnostics, callerInfoOpt:=Nothing) End If Return New BoundUserDefinedBinaryOperator(node, opKind, result, CheckOverflow, result.Type) End Function ''' <summary> ''' This function builds a bound tree representing an overloaded short circuiting expression ''' after determining that the necessary semantic conditions are met. ''' ''' An expression of the form: ''' ''' x AndAlso y (where the type of x is X and the type of y is Y) ''' ''' is an overloaded short circuit operation if X and Y are user-defined types and an ''' applicable operator And exists after applying normal operator resolution rules. ''' ''' Given an applicable And operator declared in type T, the following must be true: ''' ''' - The return type and parameter types must be T. ''' - T must contain a declaration of operator IsFalse. ''' ''' If these conditions are met, the expression "x AndAlso y" is translated into: ''' ''' !T.IsFalse(temp = x) ? T.And(temp, y) : temp ''' ''' The temporary is necessary for evaluating x only once. Similarly, "x OrElse y" is ''' translated into: ''' ''' !T.IsTrue(temp = x) ? T.Or(temp, y) : temp ''' </summary> Private Function BindUserDefinedShortCircuitingOperator( node As SyntaxNode, opKind As BinaryOperatorKind, left As BoundExpression, right As BoundExpression, <[In]> ByRef bitwiseOperator As OverloadResolution.OverloadResolutionResult, diagnostics As BindingDiagnosticBag ) As BoundUserDefinedShortCircuitingOperator Debug.Assert(opKind = BinaryOperatorKind.AndAlso OrElse opKind = BinaryOperatorKind.OrElse) Debug.Assert(bitwiseOperator.Candidates.Length > 0) Dim bitwiseKind As BinaryOperatorKind = If(opKind = BinaryOperatorKind.AndAlso, BinaryOperatorKind.And, BinaryOperatorKind.Or) Or BinaryOperatorKind.UserDefined Dim operatorType As TypeSymbol Dim leftOperand As BoundExpression = Nothing Dim leftPlaceholder As BoundRValuePlaceholder = Nothing Dim test As BoundExpression = Nothing Dim bitwise As BoundUserDefinedBinaryOperator Dim hasErrors As Boolean = False If Not bitwiseOperator.BestResult.HasValue Then ' This will take care of the diagnostic. bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator, diagnostics) operatorType = bitwise.Type hasErrors = True GoTo Done End If Dim bitwiseAnalysis As OverloadResolution.CandidateAnalysisResult = bitwiseOperator.BestResult.Value Dim bitwiseCandidate As OverloadResolution.Candidate = bitwiseAnalysis.Candidate operatorType = bitwiseCandidate.ReturnType If bitwiseCandidate.IsLifted Then bitwiseKind = bitwiseKind Or BinaryOperatorKind.Lifted End If If Not operatorType.IsSameTypeIgnoringAll(bitwiseCandidate.Parameters(0).Type) OrElse Not operatorType.IsSameTypeIgnoringAll(bitwiseCandidate.Parameters(1).Type) Then ReportDiagnostic(diagnostics, node, ERRID.ERR_UnacceptableLogicalOperator3, bitwiseCandidate.UnderlyingSymbol, bitwiseCandidate.UnderlyingSymbol.ContainingType, SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.AndAlsoKeyword, SyntaxKind.OrElseKeyword))) bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator, BindingDiagnosticBag.Discarded) ' Ignore any additional diagnostics. hasErrors = True GoTo Done End If leftPlaceholder = New BoundRValuePlaceholder(left.Syntax, operatorType).MakeCompilerGenerated() ' Find IsTrue/IsFalse operator Dim leftCheckOperator As OverloadResolution.OverloadResolutionResult Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) If opKind = BinaryOperatorKind.AndAlso Then leftCheckOperator = OverloadResolution.ResolveIsFalseOperator(leftPlaceholder, Me, useSiteInfo) Else leftCheckOperator = OverloadResolution.ResolveIsTrueOperator(leftPlaceholder, Me, useSiteInfo) End If If diagnostics.Add(node, useSiteInfo) Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If If Not leftCheckOperator.BestResult.HasValue Then ReportDiagnostic(diagnostics, node, ERRID.ERR_ConditionOperatorRequired3, operatorType, SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.IsFalseKeyword, SyntaxKind.IsTrueKeyword)), SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.AndAlsoKeyword, SyntaxKind.OrElseKeyword))) bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator, BindingDiagnosticBag.Discarded) ' Ignore any additional diagnostics. leftPlaceholder = Nothing hasErrors = True GoTo Done End If Dim checkCandidate As OverloadResolution.Candidate = leftCheckOperator.BestResult.Value.Candidate Debug.Assert(checkCandidate.ReturnType.IsBooleanType() OrElse checkCandidate.ReturnType.IsNullableOfBoolean()) If Not operatorType.IsSameTypeIgnoringAll(checkCandidate.Parameters(0).Type) Then ReportDiagnostic(diagnostics, node, ERRID.ERR_BinaryOperands3, SyntaxFacts.GetText(If(opKind = BinaryOperatorKind.AndAlso, SyntaxKind.AndAlsoKeyword, SyntaxKind.OrElseKeyword)), left.Type, right.Type) hasErrors = True diagnostics = BindingDiagnosticBag.Discarded ' Ignore any additional diagnostics. bitwise = BindUserDefinedNonShortCircuitingBinaryOperator(node, bitwiseKind, left, right, bitwiseOperator, diagnostics) Else ' Convert the operands to the operator type. Dim argumentInfo As (Arguments As ImmutableArray(Of BoundExpression), DefaultArguments As BitVector) = PassArguments(node, bitwiseAnalysis, ImmutableArray.Create(Of BoundExpression)(left, right), diagnostics) Debug.Assert(argumentInfo.DefaultArguments.IsNull) bitwiseAnalysis.ConversionsOpt = Nothing bitwise = New BoundUserDefinedBinaryOperator(node, bitwiseKind, CreateBoundCallOrPropertyAccess(node, node, TypeCharacter.None, New BoundMethodGroup(node, Nothing, ImmutableArray.Create(Of MethodSymbol)( DirectCast(bitwiseCandidate.UnderlyingSymbol, MethodSymbol)), LookupResultKind.Good, Nothing, QualificationKind.Unqualified).MakeCompilerGenerated(), ImmutableArray.Create(Of BoundExpression)(leftPlaceholder, argumentInfo.Arguments(1)), bitwiseAnalysis, bitwiseOperator.AsyncLambdaSubToFunctionMismatch, diagnostics), CheckOverflow, operatorType) leftOperand = argumentInfo.Arguments(0) End If Dim testOp As BoundUserDefinedUnaryOperator = BindUserDefinedUnaryOperator(node, If(opKind = BinaryOperatorKind.AndAlso, UnaryOperatorKind.IsFalse, UnaryOperatorKind.IsTrue), leftPlaceholder, leftCheckOperator, diagnostics).MakeCompilerGenerated() testOp.UnderlyingExpression.SetWasCompilerGenerated() If hasErrors Then leftPlaceholder = Nothing End If If checkCandidate.IsLifted Then test = ApplyNullableIsTrueOperator(testOp, checkCandidate.ReturnType.GetNullableUnderlyingTypeOrSelf()) Else test = testOp End If Done: Debug.Assert(hasErrors OrElse (leftOperand IsNot Nothing AndAlso leftPlaceholder IsNot Nothing AndAlso test IsNot Nothing)) Debug.Assert(Not hasErrors OrElse (leftOperand Is Nothing AndAlso leftPlaceholder Is Nothing)) bitwise.UnderlyingExpression.SetWasCompilerGenerated() bitwise.SetWasCompilerGenerated() Return New BoundUserDefinedShortCircuitingOperator(node, leftOperand, leftPlaceholder, test, bitwise, operatorType, hasErrors) End Function Private Shared Sub ReportBinaryOperatorOnObject( operatorTokenKind As SyntaxKind, operand As BoundExpression, preliminaryOperatorKind As BinaryOperatorKind, diagnostics As BindingDiagnosticBag ) ReportDiagnostic(diagnostics, operand.Syntax, ErrorFactory.ErrorInfo( If(preliminaryOperatorKind = BinaryOperatorKind.Equals OrElse preliminaryOperatorKind = BinaryOperatorKind.NotEquals, ERRID.ERR_StrictDisallowsObjectComparison1, ERRID.ERR_StrictDisallowsObjectOperand1), operatorTokenKind)) End Sub ''' <summary> ''' Returns Symbol for String type. ''' </summary> Private Function SubstituteDBNullWithNothingString( ByRef dbNullOperand As BoundExpression, otherOperandType As TypeSymbol, diagnostics As BindingDiagnosticBag ) As TypeSymbol Dim stringType As TypeSymbol If otherOperandType.IsStringType() Then stringType = otherOperandType Else stringType = GetSpecialType(SpecialType.System_String, dbNullOperand.Syntax, diagnostics) End If dbNullOperand = New BoundConversion(dbNullOperand.Syntax, dbNullOperand, ConversionKind.Widening, checked:=False, explicitCastInCode:=False, type:=stringType, constantValueOpt:=ConstantValue.Nothing) Return stringType End Function ''' <summary> ''' Get symbol for a special type, reuse symbols for operand types to avoid type ''' lookups and construction of new instances of symbols. ''' </summary> Private Function GetSpecialTypeForBinaryOperator( node As SyntaxNode, leftType As TypeSymbol, rightType As TypeSymbol, specialType As SpecialType, makeNullable As Boolean, diagnostics As BindingDiagnosticBag ) As TypeSymbol Debug.Assert(specialType <> Microsoft.CodeAnalysis.SpecialType.None) Debug.Assert(Not makeNullable OrElse leftType.IsNullableType() OrElse rightType.IsNullableType()) Dim resultType As TypeSymbol Dim leftNullableUnderlying = leftType.GetNullableUnderlyingTypeOrSelf() Dim leftSpecialType = leftNullableUnderlying.SpecialType Dim rightNullableUnderlying = rightType.GetNullableUnderlyingTypeOrSelf() Dim rightSpecialType = rightNullableUnderlying.SpecialType If leftSpecialType = specialType Then If Not makeNullable Then resultType = leftNullableUnderlying ElseIf leftType.IsNullableType() Then resultType = leftType ElseIf rightSpecialType = specialType Then Debug.Assert(makeNullable AndAlso rightType.IsNullableType()) resultType = rightType Else Debug.Assert(makeNullable AndAlso rightType.IsNullableType() AndAlso Not leftType.IsNullableType()) resultType = DirectCast(rightType.OriginalDefinition, NamedTypeSymbol).Construct(leftType) End If ElseIf rightSpecialType = specialType Then If Not makeNullable Then resultType = rightNullableUnderlying ElseIf rightType.IsNullableType() Then resultType = rightType Else Debug.Assert(makeNullable AndAlso Not rightType.IsNullableType() AndAlso leftType.IsNullableType()) resultType = DirectCast(leftType.OriginalDefinition, NamedTypeSymbol).Construct(rightNullableUnderlying) End If Else resultType = GetSpecialType(specialType, node, diagnostics) If makeNullable Then If leftType.IsNullableType() Then resultType = DirectCast(leftType.OriginalDefinition, NamedTypeSymbol).Construct(resultType) Else Debug.Assert(rightType.IsNullableType()) resultType = DirectCast(rightType.OriginalDefinition, NamedTypeSymbol).Construct(resultType) End If End If End If Return resultType End Function ''' <summary> ''' Get symbol for a Nullable type of particular type, reuse symbols for operand types to avoid type ''' lookups and construction of new instances of symbols. ''' </summary> Private Shared Function GetNullableTypeForBinaryOperator( leftType As TypeSymbol, rightType As TypeSymbol, ofType As TypeSymbol ) As TypeSymbol Dim leftIsNullable = leftType.IsNullableType() Dim rightIsNullable = rightType.IsNullableType() Dim ofSpecialType = ofType.SpecialType Debug.Assert(leftIsNullable OrElse rightIsNullable) If ofSpecialType <> SpecialType.None Then If leftIsNullable AndAlso leftType.GetNullableUnderlyingType().SpecialType = ofSpecialType Then Return leftType ElseIf rightIsNullable AndAlso rightType.GetNullableUnderlyingType().SpecialType = ofSpecialType Then Return rightType End If End If If leftIsNullable Then Return DirectCast(leftType.OriginalDefinition, NamedTypeSymbol).Construct(ofType) Else Return DirectCast(rightType.OriginalDefinition, NamedTypeSymbol).Construct(ofType) End If End Function Private Shared Function IsKnownToBeNullableNothing(expr As BoundExpression) As Boolean Dim cast = expr ' TODO: Add handling for TryCast, similar to DirectCast While cast.Kind = BoundKind.Conversion OrElse cast.Kind = BoundKind.DirectCast If cast.HasErrors Then Return False End If Dim resultType As TypeSymbol = Nothing Select Case cast.Kind Case BoundKind.Conversion Dim conv = DirectCast(cast, BoundConversion) resultType = conv.Type cast = conv.Operand Case BoundKind.DirectCast Dim conv = DirectCast(cast, BoundDirectCast) resultType = conv.Type cast = conv.Operand End Select If resultType Is Nothing OrElse Not (resultType.IsNullableType() OrElse resultType.IsObjectType()) Then Return False End If End While Return cast.IsNothingLiteral() End Function Private Sub ReportUndefinedOperatorError( syntax As SyntaxNode, left As BoundExpression, right As BoundExpression, operatorTokenKind As SyntaxKind, operatorKind As BinaryOperatorKind, diagnostics As BindingDiagnosticBag ) Dim leftType = left.Type Dim rightType = right.Type Debug.Assert(leftType IsNot Nothing) Debug.Assert(rightType IsNot Nothing) If leftType.IsErrorType() OrElse rightType.IsErrorType() Then Return ' Let's not report more errors. End If Dim operatorTokenText = SyntaxFacts.GetText(operatorTokenKind) If OverloadResolution.UseUserDefinedBinaryOperators(operatorKind, leftType, rightType) AndAlso Not leftType.CanContainUserDefinedOperators(useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded) AndAlso Not rightType.CanContainUserDefinedOperators(useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded) AndAlso (operatorKind = BinaryOperatorKind.Equals OrElse operatorKind = BinaryOperatorKind.NotEquals) AndAlso leftType.IsReferenceType() AndAlso rightType.IsReferenceType() Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_ReferenceComparison3, operatorTokenText, leftType, rightType) ElseIf IsIEnumerableOfXElement(leftType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_BinaryOperandsForXml4, operatorTokenText, leftType, rightType, leftType) ElseIf IsIEnumerableOfXElement(rightType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded) Then ReportDiagnostic(diagnostics, syntax, ERRID.ERR_BinaryOperandsForXml4, operatorTokenText, leftType, rightType, rightType) Else ReportDiagnostic(diagnostics, syntax, ERRID.ERR_BinaryOperands3, operatorTokenText, leftType, rightType) End If End Sub ''' <summary> ''' §11.12.2 Object Operands ''' The value Nothing is treated as the default value of the type of ''' the other operand in a binary operator expression. In a unary operator expression, ''' or if both operands are Nothing in a binary operator expression, ''' the type of the operation is Integer or the only result type of the operator, ''' if the operator does not result in Integer. ''' </summary> Private Sub ConvertNothingLiterals( operatorKind As BinaryOperatorKind, ByRef left As BoundExpression, ByRef right As BoundExpression, diagnostics As BindingDiagnosticBag ) Debug.Assert((operatorKind And BinaryOperatorKind.OpMask) = operatorKind AndAlso operatorKind <> 0) Dim rightType As TypeSymbol Dim leftType As TypeSymbol If left.IsNothingLiteral() Then If right.IsNothingLiteral() Then ' Both are NOTHING Dim defaultRightSpecialType As SpecialType Select Case operatorKind Case BinaryOperatorKind.Concatenate, BinaryOperatorKind.Like defaultRightSpecialType = SpecialType.System_String Case BinaryOperatorKind.OrElse, BinaryOperatorKind.AndAlso defaultRightSpecialType = SpecialType.System_Boolean Case BinaryOperatorKind.Add, BinaryOperatorKind.Equals, BinaryOperatorKind.NotEquals, BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThan, BinaryOperatorKind.GreaterThan, BinaryOperatorKind.Subtract, BinaryOperatorKind.Multiply, BinaryOperatorKind.Power, BinaryOperatorKind.Divide, BinaryOperatorKind.Modulo, BinaryOperatorKind.IntegerDivide, BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift, BinaryOperatorKind.Xor, BinaryOperatorKind.Or, BinaryOperatorKind.And defaultRightSpecialType = SpecialType.System_Int32 Case Else Throw ExceptionUtilities.UnexpectedValue(operatorKind) End Select rightType = GetSpecialType(defaultRightSpecialType, right.Syntax, diagnostics) right = ApplyImplicitConversion(right.Syntax, rightType, right, diagnostics) Else rightType = right.Type If rightType Is Nothing Then Return End If End If Debug.Assert(rightType IsNot Nothing) Dim defaultLeftSpecialType As SpecialType = SpecialType.None Select Case operatorKind Case BinaryOperatorKind.Concatenate, BinaryOperatorKind.Like If rightType.GetNullableUnderlyingTypeOrSelf().GetEnumUnderlyingTypeOrSelf().IsIntrinsicType() OrElse rightType.IsCharSZArray() OrElse rightType.IsDBNullType() Then ' For & and Like, a Nothing operand is typed String unless the other operand ' is non-intrinsic (VSW#240203). ' The same goes for DBNull (VSW#278518) ' The same goes for enum types (VSW#288077) defaultLeftSpecialType = SpecialType.System_String End If Case BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift ' Nothing should default to Integer for Shift operations. defaultLeftSpecialType = SpecialType.System_Int32 End Select If defaultLeftSpecialType = SpecialType.None OrElse defaultLeftSpecialType = rightType.SpecialType Then leftType = rightType Else leftType = GetSpecialType(defaultLeftSpecialType, left.Syntax, diagnostics) End If left = ApplyImplicitConversion(left.Syntax, leftType, left, diagnostics) ElseIf right.IsNothingLiteral() Then leftType = left.Type If leftType Is Nothing Then Return End If rightType = leftType Select Case operatorKind Case BinaryOperatorKind.Concatenate, BinaryOperatorKind.Like If leftType.GetNullableUnderlyingTypeOrSelf().GetEnumUnderlyingTypeOrSelf().IsIntrinsicType() OrElse leftType.IsCharSZArray() OrElse leftType.IsDBNullType() Then ' For & and Like, a Nothing operand is typed String unless the other operand ' is non-intrinsic (VSW#240203). ' The same goes for DBNull (VSW#278518) ' The same goes for enum types (VSW#288077) If leftType.SpecialType <> SpecialType.System_String Then rightType = GetSpecialType(SpecialType.System_String, right.Syntax, diagnostics) End If End If End Select right = ApplyImplicitConversion(right.Syntax, rightType, right, diagnostics) End If End Sub Private Function BindUnaryOperator(node As UnaryExpressionSyntax, diagnostics As BindingDiagnosticBag) As BoundExpression Dim operand As BoundExpression = BindValue(node.Operand, diagnostics) Dim preliminaryOperatorKind As UnaryOperatorKind = OverloadResolution.MapUnaryOperatorKind(node.Kind) If Not operand.HasErrors AndAlso operand.IsNothingLiteral Then '§11.12.2 Object Operands 'In a unary operator expression, or if both operands are Nothing in a 'binary operator expression, the type of the operation is Integer Dim int32Type = GetSpecialType(SpecialType.System_Int32, node.Operand, diagnostics) operand = ApplyImplicitConversion(node.Operand, int32Type, operand, diagnostics) Else operand = MakeRValue(operand, diagnostics) End If If operand.HasErrors Then ' Suppress any additional diagnostics by overriding DiagnosticBag. diagnostics = BindingDiagnosticBag.Discarded End If Dim intrinsicOperatorType As SpecialType = SpecialType.None Dim userDefinedOperator As OverloadResolution.OverloadResolutionResult = Nothing Dim useSiteInfo = GetNewCompoundUseSiteInfo(diagnostics) Dim operatorKind As UnaryOperatorKind = OverloadResolution.ResolveUnaryOperator(preliminaryOperatorKind, operand, Me, intrinsicOperatorType, userDefinedOperator, useSiteInfo) If diagnostics.Add(node, useSiteInfo) Then ' Suppress additional diagnostics diagnostics = BindingDiagnosticBag.Discarded End If If operatorKind = UnaryOperatorKind.UserDefined Then Dim bestCandidate As OverloadResolution.Candidate = If(userDefinedOperator.BestResult.HasValue, userDefinedOperator.BestResult.Value.Candidate, Nothing) If bestCandidate Is Nothing OrElse Not bestCandidate.IsLifted OrElse (OverloadResolution.IsValidInLiftedSignature(bestCandidate.Parameters(0).Type) AndAlso OverloadResolution.IsValidInLiftedSignature(bestCandidate.ReturnType)) Then Return BindUserDefinedUnaryOperator(node, preliminaryOperatorKind, operand, userDefinedOperator, diagnostics) End If operatorKind = UnaryOperatorKind.Error End If If operatorKind = UnaryOperatorKind.Error Then ReportUndefinedOperatorError(node, operand, diagnostics) Return New BoundUnaryOperator(node, preliminaryOperatorKind Or UnaryOperatorKind.Error, operand, CheckOverflow, ErrorTypeSymbol.UnknownResultType, HasErrors:=True) End If ' We are dealing with intrinsic operator Dim operandType As TypeSymbol = operand.Type Dim resultType As TypeSymbol = Nothing If intrinsicOperatorType = SpecialType.None Then Debug.Assert(operandType.GetNullableUnderlyingTypeOrSelf().IsEnumType()) resultType = operandType Else If operandType.GetNullableUnderlyingTypeOrSelf().SpecialType = intrinsicOperatorType Then resultType = operandType Else resultType = GetSpecialType(intrinsicOperatorType, node.Operand, diagnostics) If operandType.IsNullableType() Then resultType = DirectCast(operandType.OriginalDefinition, NamedTypeSymbol).Construct(resultType) End If End If End If Debug.Assert(((operatorKind And UnaryOperatorKind.Lifted) <> 0) = resultType.IsNullableType()) ' Option Strict disallows all unary operations on Object operands. Otherwise just warn. If operandType.SpecialType = SpecialType.System_Object Then If OptionStrict = VisualBasic.OptionStrict.On Then ReportDiagnostic(diagnostics, node.Operand, ErrorFactory.ErrorInfo(ERRID.ERR_StrictDisallowsObjectOperand1, node.OperatorToken)) ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then ReportDiagnostic(diagnostics, node.Operand, ErrorFactory.ErrorInfo(ERRID.WRN_ObjectMath2, node.OperatorToken)) End If End If operand = ApplyImplicitConversion(node.Operand, resultType, operand, diagnostics) Dim constantValue As ConstantValue = Nothing If Not operand.HasErrors Then Dim integerOverflow As Boolean = False constantValue = OverloadResolution.TryFoldConstantUnaryOperator(operatorKind, operand, resultType, integerOverflow) ' Overflows are reported regardless of the value of OptionRemoveIntegerOverflowChecks, Dev10 behavior. If constantValue IsNot Nothing AndAlso (constantValue.IsBad OrElse integerOverflow) Then ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ExpressionOverflow1, resultType)) ' there should be no constant value in case of overflows. If Not constantValue.IsBad Then constantValue = constantValue.Bad End If End If End If Return New BoundUnaryOperator(node, operatorKind, operand, CheckOverflow, constantValue, resultType) End Function Private Function BindUserDefinedUnaryOperator( node As SyntaxNode, opKind As UnaryOperatorKind, operand As BoundExpression, <[In]> ByRef userDefinedOperator As OverloadResolution.OverloadResolutionResult, diagnostics As BindingDiagnosticBag ) As BoundUserDefinedUnaryOperator Debug.Assert(userDefinedOperator.Candidates.Length > 0) Dim result As BoundExpression opKind = opKind Or UnaryOperatorKind.UserDefined If userDefinedOperator.BestResult.HasValue Then Dim bestCandidate As OverloadResolution.CandidateAnalysisResult = userDefinedOperator.BestResult.Value result = CreateBoundCallOrPropertyAccess(node, node, TypeCharacter.None, New BoundMethodGroup(node, Nothing, ImmutableArray.Create(Of MethodSymbol)( DirectCast(bestCandidate.Candidate.UnderlyingSymbol, MethodSymbol)), LookupResultKind.Good, Nothing, QualificationKind.Unqualified).MakeCompilerGenerated(), ImmutableArray.Create(Of BoundExpression)(operand), bestCandidate, userDefinedOperator.AsyncLambdaSubToFunctionMismatch, diagnostics) If bestCandidate.Candidate.IsLifted Then opKind = opKind Or UnaryOperatorKind.Lifted End If Else result = ReportOverloadResolutionFailureAndProduceBoundNode(node, LookupResultKind.Good, ImmutableArray.Create(Of BoundExpression)(operand), Nothing, userDefinedOperator, diagnostics, callerInfoOpt:=Nothing) End If Return New BoundUserDefinedUnaryOperator(node, opKind, result, result.Type) End Function Private Shared Sub ReportUndefinedOperatorError( syntax As UnaryExpressionSyntax, operand As BoundExpression, diagnostics As BindingDiagnosticBag ) If operand.Type.IsErrorType() Then Return ' Let's not report more errors. End If ReportDiagnostic(diagnostics, syntax, ErrorFactory.ErrorInfo(ERRID.ERR_UnaryOperand2, syntax.OperatorToken, operand.Type)) End Sub End Class End Namespace