in src/Compilers/VisualBasic/Portable/Binding/Binder_Operators.vb [205:545]
) As BoundExpression
Debug.Assert(left.IsValue)
Debug.Assert(right.IsValue)
Dim originalDiagnostics = diagnostics
If (left.HasErrors OrElse right.HasErrors) Then
diagnostics = New DiagnosticBag()
End If
ConvertNothingLiterals(preliminaryOperatorKind, left, right, diagnostics)
left = MakeRValue(left, diagnostics)
right = MakeRValue(right, diagnostics)
If (left.HasErrors OrElse right.HasErrors) Then
If diagnostics Is originalDiagnostics Then
diagnostics = New DiagnosticBag()
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()
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
Dim intrinsicOperatorType As SpecialType = SpecialType.None
Dim userDefinedOperator As OverloadResolution.OverloadResolutionResult = Nothing
Dim useSiteDiagnostics As HashSet(Of DiagnosticInfo) = Nothing
Dim operatorKind As BinaryOperatorKind = OverloadResolution.ResolveBinaryOperator(preliminaryOperatorKind, left, right, Me,
True,
intrinsicOperatorType,
userDefinedOperator,
useSiteDiagnostics)
If diagnostics.Add(node, useSiteDiagnostics) Then
diagnostics = New DiagnosticBag()
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
Dim operandType As TypeSymbol
If intrinsicOperatorType = SpecialType.None Then
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
Dim operatorResultType As TypeSymbol = operandType
Dim forceToBooleanType As TypeSymbol = Nothing
Dim applyIsTrue As Boolean = False
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
If isOperandOfConditionalBranch Then
applyIsTrue = True
forceToBooleanType = booleanType
End If
Else
If Not operatorResultType.IsObjectType() Then
operatorResultType = booleanType
Else
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
If diagnostics Is originalDiagnostics Then
diagnostics = New DiagnosticBag()
End If
End If
Dim hasError As Boolean = False
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
If diagnostics Is originalDiagnostics Then
diagnostics = New DiagnosticBag()
End If
End If
ElseIf OptionStrict = VisualBasic.OptionStrict.Custom Then
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
Dim explicitSemanticForConcatArgument As Boolean = False
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)
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
operatorKind = (operatorKind And (Not BinaryOperatorKind.OpMask))
operatorKind = operatorKind Or BinaryOperatorKind.Concatenate
End If
Dim value As ConstantValue = Nothing
If Not (left.HasErrors OrElse right.HasErrors) Then
Dim integerOverflow As Boolean = False
Dim divideByZero As Boolean = False
Dim compoundLengthOutOfLimit As Boolean = False
value = OverloadResolution.TryFoldConstantBinaryOperator(operatorKind,
left,
right,
operatorResultType,
integerOverflow,
divideByZero,
compoundLengthOutOfLimit,
compoundStringLength)
If value IsNot Nothing Then
If divideByZero Then
Debug.Assert(value.IsBad)
ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ZeroDivide))
ElseIf compoundLengthOutOfLimit Then
Debug.Assert(value.IsBad)
ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ConstantStringTooLong))
ElseIf (value.IsBad OrElse integerOverflow) Then
ReportDiagnostic(diagnostics, node, ErrorFactory.ErrorInfo(ERRID.ERR_ExpressionOverflow1, operatorResultType))
If Not value.IsBad Then
value = ConstantValue.Bad
End If
End If
End If
End If
Dim result As BoundExpression = New BoundBinaryOperator(node, operatorKind, left, right, CheckOverflow, value, operatorResultType, hasError)
Debug.Assert(Not applyIsTrue OrElse forceToBooleanType IsNot Nothing)
If forceToBooleanType IsNot Nothing Then
Debug.Assert(forceToBooleanType.IsBooleanType())
If applyIsTrue Then
Return ApplyNullableIsTrueOperator(result, forceToBooleanType)
End If
result = ApplyConversion(node, forceToBooleanType, result, isExplicit:=True, diagnostics:=diagnostics)
End If
Return result
End Function