/
githubmirror
/
roslyn
Обзор
Документация
Войти
/
githubmirror
/
roslyn
Код
Запросы
0
Пакеты
0
Релизы
0
Аналитика
Безопасность
main
src/Compilers/VisualBasic/Portable/Semantics/Operators.vb
3 448 строк
182 KB
Cyrus Najmabadi
Update code to use GetFirstLocation() instead of Locations[0] or Locations.First() (#80709)
21 окт 2025, 00:00
Не верифицирован
21 окт 2025, 00:00
3a723bb
Код
Авторство
О чём код?
' 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.Diagnostics Imports System.Linq Imports System.Runtime.InteropServices Imports Microsoft.CodeAnalysis.Collections Imports Microsoft.CodeAnalysis.PooledObjects Imports Microsoft.CodeAnalysis.Text Imports Microsoft.CodeAnalysis.VisualBasic.Symbols Imports Microsoft.CodeAnalysis.VisualBasic.Syntax Imports TypeKind = Microsoft.CodeAnalysis.TypeKind Namespace Microsoft.CodeAnalysis.VisualBasic Partial Friend Class OverloadResolution ''' <summary> ''' A map from Operator name to number of parameters and kind. ''' </summary> Private Shared ReadOnly s_operatorNames As Dictionary(Of String, OperatorInfo) ''' <summary> ''' Operator kind and expected number of parameters. ''' </summary> Friend Structure OperatorInfo Private ReadOnly _Id As Integer Public Sub New(op As UnaryOperatorKind) _Id = (1 Or (op << 2)) End Sub Public Sub New(op As BinaryOperatorKind) _Id = (2 Or (op << 2)) End Sub Public ReadOnly Property ParamCount As Integer Get Return (_Id And 3) End Get End Property Public ReadOnly Property IsBinary As Boolean Get Return ParamCount = 2 End Get End Property Public ReadOnly Property IsUnary As Boolean Get Return ParamCount = 1 End Get End Property Public ReadOnly Property UnaryOperatorKind As UnaryOperatorKind Get If Not IsUnary Then Return UnaryOperatorKind.Error End If Return CType(_Id >> 2, UnaryOperatorKind) End Get End Property Public ReadOnly Property BinaryOperatorKind As BinaryOperatorKind Get If Not IsBinary Then Return BinaryOperatorKind.Error End If Return CType(_Id >> 2, BinaryOperatorKind) End Get End Property End Structure Friend Shared Function GetOperatorInfo(name As String) As OperatorInfo Dim result As OperatorInfo = Nothing If name.Length > 3 AndAlso IdentifierComparison.Equals("op_", name.Substring(0, 3)) AndAlso s_operatorNames.TryGetValue(name, result) Then Return result End If Return Nothing End Function Shared Sub New() Dim operators As New Dictionary(Of String, OperatorInfo)(IdentifierComparison.Comparer) operators.Add(WellKnownMemberNames.OnesComplementOperatorName, New OperatorInfo(UnaryOperatorKind.Not)) operators.Add(WellKnownMemberNames.TrueOperatorName, New OperatorInfo(UnaryOperatorKind.IsTrue)) operators.Add(WellKnownMemberNames.FalseOperatorName, New OperatorInfo(UnaryOperatorKind.IsFalse)) operators.Add(WellKnownMemberNames.UnaryPlusOperatorName, New OperatorInfo(UnaryOperatorKind.Plus)) operators.Add(WellKnownMemberNames.AdditionOperatorName, New OperatorInfo(BinaryOperatorKind.Add)) operators.Add(WellKnownMemberNames.UnaryNegationOperatorName, New OperatorInfo(UnaryOperatorKind.Minus)) operators.Add(WellKnownMemberNames.SubtractionOperatorName, New OperatorInfo(BinaryOperatorKind.Subtract)) operators.Add(WellKnownMemberNames.MultiplyOperatorName, New OperatorInfo(BinaryOperatorKind.Multiply)) operators.Add(WellKnownMemberNames.DivisionOperatorName, New OperatorInfo(BinaryOperatorKind.Divide)) operators.Add(WellKnownMemberNames.IntegerDivisionOperatorName, New OperatorInfo(BinaryOperatorKind.IntegerDivide)) operators.Add(WellKnownMemberNames.ModulusOperatorName, New OperatorInfo(BinaryOperatorKind.Modulo)) operators.Add(WellKnownMemberNames.ExponentOperatorName, New OperatorInfo(BinaryOperatorKind.Power)) operators.Add(WellKnownMemberNames.EqualityOperatorName, New OperatorInfo(BinaryOperatorKind.Equals)) operators.Add(WellKnownMemberNames.InequalityOperatorName, New OperatorInfo(BinaryOperatorKind.NotEquals)) operators.Add(WellKnownMemberNames.LessThanOperatorName, New OperatorInfo(BinaryOperatorKind.LessThan)) operators.Add(WellKnownMemberNames.GreaterThanOperatorName, New OperatorInfo(BinaryOperatorKind.GreaterThan)) operators.Add(WellKnownMemberNames.LessThanOrEqualOperatorName, New OperatorInfo(BinaryOperatorKind.LessThanOrEqual)) operators.Add(WellKnownMemberNames.GreaterThanOrEqualOperatorName, New OperatorInfo(BinaryOperatorKind.GreaterThanOrEqual)) operators.Add(WellKnownMemberNames.LikeOperatorName, New OperatorInfo(BinaryOperatorKind.Like)) operators.Add(WellKnownMemberNames.ConcatenateOperatorName, New OperatorInfo(BinaryOperatorKind.Concatenate)) operators.Add(WellKnownMemberNames.BitwiseAndOperatorName, New OperatorInfo(BinaryOperatorKind.And)) operators.Add(WellKnownMemberNames.BitwiseOrOperatorName, New OperatorInfo(BinaryOperatorKind.Or)) operators.Add(WellKnownMemberNames.ExclusiveOrOperatorName, New OperatorInfo(BinaryOperatorKind.Xor)) operators.Add(WellKnownMemberNames.LeftShiftOperatorName, New OperatorInfo(BinaryOperatorKind.LeftShift)) operators.Add(WellKnownMemberNames.RightShiftOperatorName, New OperatorInfo(BinaryOperatorKind.RightShift)) operators.Add(WellKnownMemberNames.ImplicitConversionName, New OperatorInfo(UnaryOperatorKind.Implicit)) operators.Add(WellKnownMemberNames.ExplicitConversionName, New OperatorInfo(UnaryOperatorKind.Explicit)) ' These cannot be declared in source, but can be imported. operators.Add(WellKnownMemberNames.LogicalNotOperatorName, New OperatorInfo(UnaryOperatorKind.Not)) operators.Add(WellKnownMemberNames.LogicalAndOperatorName, New OperatorInfo(BinaryOperatorKind.And)) operators.Add(WellKnownMemberNames.LogicalOrOperatorName, New OperatorInfo(BinaryOperatorKind.Or)) operators.Add(WellKnownMemberNames.UnsignedLeftShiftOperatorName, New OperatorInfo(BinaryOperatorKind.LeftShift)) operators.Add(WellKnownMemberNames.UnsignedRightShiftOperatorName, New OperatorInfo(BinaryOperatorKind.RightShift)) s_operatorNames = operators End Sub Friend Shared Function GetOperatorTokenKind(name As String) As SyntaxKind Dim opInfo As OperatorInfo = GetOperatorInfo(name) Return GetOperatorTokenKind(opInfo) End Function Friend Shared Function GetOperatorTokenKind(opInfo As OperatorInfo) As SyntaxKind If opInfo.IsUnary Then Return GetOperatorTokenKind(opInfo.UnaryOperatorKind) Else Return GetOperatorTokenKind(opInfo.BinaryOperatorKind) End If End Function Friend Shared Function GetOperatorTokenKind(op As UnaryOperatorKind) As SyntaxKind Select Case op Case UnaryOperatorKind.IsFalse Return SyntaxKind.IsFalseKeyword Case UnaryOperatorKind.IsTrue Return SyntaxKind.IsTrueKeyword Case UnaryOperatorKind.Minus Return SyntaxKind.MinusToken Case UnaryOperatorKind.Not Return SyntaxKind.NotKeyword Case UnaryOperatorKind.Plus Return SyntaxKind.PlusToken Case UnaryOperatorKind.Implicit, UnaryOperatorKind.Explicit Return SyntaxKind.CTypeKeyword Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select End Function Friend Shared Function GetOperatorTokenKind(op As BinaryOperatorKind) As SyntaxKind Select Case op Case BinaryOperatorKind.Add Return SyntaxKind.PlusToken Case BinaryOperatorKind.Subtract Return SyntaxKind.MinusToken Case BinaryOperatorKind.Multiply Return SyntaxKind.AsteriskToken Case BinaryOperatorKind.Divide Return SyntaxKind.SlashToken Case BinaryOperatorKind.IntegerDivide Return SyntaxKind.BackslashToken Case BinaryOperatorKind.Modulo Return SyntaxKind.ModKeyword Case BinaryOperatorKind.Power Return SyntaxKind.CaretToken Case BinaryOperatorKind.Equals Return SyntaxKind.EqualsToken Case BinaryOperatorKind.NotEquals Return SyntaxKind.LessThanGreaterThanToken Case BinaryOperatorKind.LessThan Return SyntaxKind.LessThanToken Case BinaryOperatorKind.GreaterThan Return SyntaxKind.GreaterThanToken Case BinaryOperatorKind.LessThanOrEqual Return SyntaxKind.LessThanEqualsToken Case BinaryOperatorKind.GreaterThanOrEqual Return SyntaxKind.GreaterThanEqualsToken Case BinaryOperatorKind.Like Return SyntaxKind.LikeKeyword Case BinaryOperatorKind.Concatenate Return SyntaxKind.AmpersandToken Case BinaryOperatorKind.And Return SyntaxKind.AndKeyword Case BinaryOperatorKind.Or Return SyntaxKind.OrKeyword Case BinaryOperatorKind.Xor Return SyntaxKind.XorKeyword Case BinaryOperatorKind.LeftShift Return SyntaxKind.LessThanLessThanToken Case BinaryOperatorKind.RightShift Return SyntaxKind.GreaterThanGreaterThanToken Case BinaryOperatorKind.AndAlso Return SyntaxKind.AndAlsoKeyword Case BinaryOperatorKind.OrElse Return SyntaxKind.OrElseKeyword Case BinaryOperatorKind.Is Return SyntaxKind.IsKeyword Case BinaryOperatorKind.IsNot Return SyntaxKind.IsNotKeyword Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select End Function Friend Shared Function TryGetOperatorName(op As BinaryOperatorKind, isChecked As Boolean) As String Select Case (op And BinaryOperatorKind.OpMask) Case BinaryOperatorKind.Add Return If(isChecked, WellKnownMemberNames.CheckedAdditionOperatorName, WellKnownMemberNames.AdditionOperatorName) Case BinaryOperatorKind.Concatenate Return WellKnownMemberNames.ConcatenateOperatorName Case BinaryOperatorKind.Like Return WellKnownMemberNames.LikeOperatorName Case BinaryOperatorKind.Equals Return WellKnownMemberNames.EqualityOperatorName Case BinaryOperatorKind.NotEquals Return WellKnownMemberNames.InequalityOperatorName Case BinaryOperatorKind.LessThanOrEqual Return WellKnownMemberNames.LessThanOrEqualOperatorName Case BinaryOperatorKind.GreaterThanOrEqual Return WellKnownMemberNames.GreaterThanOrEqualOperatorName Case BinaryOperatorKind.LessThan Return WellKnownMemberNames.LessThanOperatorName Case BinaryOperatorKind.GreaterThan Return WellKnownMemberNames.GreaterThanOperatorName Case BinaryOperatorKind.Subtract Return If(isChecked, WellKnownMemberNames.CheckedSubtractionOperatorName, WellKnownMemberNames.SubtractionOperatorName) Case BinaryOperatorKind.Multiply Return If(isChecked, WellKnownMemberNames.CheckedMultiplyOperatorName, WellKnownMemberNames.MultiplyOperatorName) Case BinaryOperatorKind.Power Return WellKnownMemberNames.ExponentOperatorName Case BinaryOperatorKind.Divide Return WellKnownMemberNames.DivisionOperatorName Case BinaryOperatorKind.Modulo Return WellKnownMemberNames.ModulusOperatorName Case BinaryOperatorKind.IntegerDivide Return If(isChecked, WellKnownMemberNames.CheckedDivisionOperatorName, WellKnownMemberNames.IntegerDivisionOperatorName) Case BinaryOperatorKind.LeftShift Return WellKnownMemberNames.LeftShiftOperatorName Case BinaryOperatorKind.RightShift Return WellKnownMemberNames.RightShiftOperatorName Case BinaryOperatorKind.Xor Return WellKnownMemberNames.ExclusiveOrOperatorName Case BinaryOperatorKind.Or Return WellKnownMemberNames.BitwiseOrOperatorName Case BinaryOperatorKind.And Return WellKnownMemberNames.BitwiseAndOperatorName Case Else Return Nothing 'Case BinaryOperatorKind.OrElse 'Case BinaryOperatorKind.AndAlso 'Case BinaryOperatorKind.Is 'Case BinaryOperatorKind.IsNot End Select End Function Friend Shared Function TryGetOperatorName(op As UnaryOperatorKind, isChecked As Boolean) As String Select Case (op And UnaryOperatorKind.OpMask) Case UnaryOperatorKind.Plus Return WellKnownMemberNames.UnaryPlusOperatorName Case UnaryOperatorKind.Minus Return If(isChecked, WellKnownMemberNames.CheckedUnaryNegationOperatorName, WellKnownMemberNames.UnaryNegationOperatorName) Case UnaryOperatorKind.Not Return WellKnownMemberNames.OnesComplementOperatorName Case UnaryOperatorKind.Implicit Return WellKnownMemberNames.ImplicitConversionName Case UnaryOperatorKind.Explicit Return WellKnownMemberNames.ExplicitConversionName Case UnaryOperatorKind.IsTrue Return WellKnownMemberNames.TrueOperatorName Case UnaryOperatorKind.IsFalse Return WellKnownMemberNames.FalseOperatorName Case Else Return Nothing End Select End Function Friend Shared Function ValidateOverloadedOperator( method As MethodSymbol, opInfo As OperatorInfo ) As Boolean Return ValidateOverloadedOperator(method, opInfo, diagnosticsOpt:=Nothing, assemblyBeingBuiltOpt:=Nothing) End Function Friend Shared Function ValidateOverloadedOperator( method As MethodSymbol, opInfo As OperatorInfo, diagnosticsOpt As BindingDiagnosticBag, assemblyBeingBuiltOpt As AssemblySymbol ) As Boolean Debug.Assert(method.IsMethodKindBasedOnSyntax OrElse diagnosticsOpt Is Nothing) Debug.Assert(opInfo.ParamCount <> 0) Debug.Assert(diagnosticsOpt Is Nothing OrElse assemblyBeingBuiltOpt IsNot Nothing) If method.ParameterCount <> opInfo.ParamCount Then Return False End If Dim result As Boolean = True Dim containingType As NamedTypeSymbol = method.ContainingType Dim targetsContainingType As Boolean = False Dim targetMismatchError As ERRID Dim isConversion As Boolean = False Dim useSiteInfo = If(diagnosticsOpt IsNot Nothing, New CompoundUseSiteInfo(Of AssemblySymbol)(diagnosticsOpt, assemblyBeingBuiltOpt), CompoundUseSiteInfo(Of AssemblySymbol).Discarded) If opInfo.IsUnary Then Select Case opInfo.UnaryOperatorKind Case UnaryOperatorKind.Implicit, UnaryOperatorKind.Explicit isConversion = True targetMismatchError = ERRID.ERR_ConvParamMustBeContainingType1 If OverloadedOperatorTargetsContainingType(containingType, method.ReturnType) Then targetsContainingType = True End If Case Else targetMismatchError = ERRID.ERR_UnaryParamMustBeContainingType1 If Not method.ReturnType.IsBooleanType() Then Select Case opInfo.UnaryOperatorKind Case UnaryOperatorKind.IsTrue If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OperatorRequiresBoolReturnType1, SyntaxFacts.GetText(SyntaxKind.IsTrueKeyword)), method.GetFirstLocation()) result = False Else Return False End If Case UnaryOperatorKind.IsFalse If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OperatorRequiresBoolReturnType1, SyntaxFacts.GetText(SyntaxKind.IsFalseKeyword)), method.GetFirstLocation()) result = False Else Return False End If End Select End If End Select Else Debug.Assert(opInfo.IsBinary) targetMismatchError = ERRID.ERR_BinaryParamMustBeContainingType1 Select Case opInfo.BinaryOperatorKind Case BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift If method.Parameters(1).Type.GetNullableUnderlyingTypeOrSelf().SpecialType <> Microsoft.CodeAnalysis.SpecialType.System_Int32 Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_OperatorRequiresIntegerParameter1, SyntaxFacts.GetText(If(opInfo.BinaryOperatorKind = BinaryOperatorKind.LeftShift, SyntaxKind.LessThanLessThanToken, SyntaxKind.GreaterThanGreaterThanToken))), method.GetFirstLocation()) result = False Else Return False End If End If End Select End If For Each param In method.Parameters If OverloadedOperatorTargetsContainingType(containingType, param.Type) Then targetsContainingType = True End If If param.IsByRef Then If diagnosticsOpt IsNot Nothing Then ' Diagnostic has been reported when we were interpreting parameter's modifiers. Debug.Assert(Not method.IsMethodKindBasedOnSyntax) result = False Else Return False End If End If Next If Not targetsContainingType Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(targetMismatchError, method.ContainingSymbol), method.GetFirstLocation()) result = False Else Return False End If ElseIf isConversion Then ' Conversion operators specific checks Dim sourceType As TypeSymbol = method.Parameters(0).Type Dim targetType As TypeSymbol = method.ReturnType If sourceType.IsObjectType() Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ConversionFromObject), method.GetFirstLocation()) result = False Else Return False End If ElseIf targetType.IsObjectType() Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ConversionToObject), method.GetFirstLocation()) result = False Else Return False End If ElseIf sourceType.IsInterfaceType() Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ConversionFromInterfaceType), method.GetFirstLocation()) result = False Else Return False End If ElseIf targetType.IsInterfaceType() Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ConversionToInterfaceType), method.GetFirstLocation()) result = False Else Return False End If ElseIf If(containingType.SpecialType = SpecialType.System_Nullable_T, sourceType Is targetType, sourceType.GetNullableUnderlyingTypeOrSelf() Is targetType.GetNullableUnderlyingTypeOrSelf()) Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(ERRID.ERR_ConversionToSameType), method.GetFirstLocation()) result = False Else Return False End If ElseIf (sourceType.Kind = SymbolKind.NamedType OrElse sourceType.Kind = SymbolKind.TypeParameter) AndAlso (targetType.Kind = SymbolKind.NamedType OrElse targetType.Kind = SymbolKind.TypeParameter) Then If Conversions.HasWideningDirectCastConversionButNotEnumTypeConversion(targetType, sourceType, useSiteInfo) Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(If(targetType Is method.ContainingSymbol, ERRID.ERR_ConversionFromBaseType, ERRID.ERR_ConversionToDerivedType)), method.GetFirstLocation()) result = False Else Return False End If ElseIf Conversions.HasWideningDirectCastConversionButNotEnumTypeConversion(sourceType, targetType, useSiteInfo) Then If diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(ErrorFactory.ErrorInfo(If(targetType Is method.ContainingSymbol, ERRID.ERR_ConversionFromDerivedType, ERRID.ERR_ConversionToBaseType)), method.GetFirstLocation()) result = False Else Return False End If End If End If End If If result AndAlso diagnosticsOpt IsNot Nothing Then diagnosticsOpt.Add(method.GetFirstLocation(), useSiteInfo) End If Return result End Function Private Shared Function OverloadedOperatorTargetsContainingType(containingType As NamedTypeSymbol, typeFromSignature As TypeSymbol) As Boolean If containingType.SpecialType = SpecialType.System_Nullable_T Then Return typeFromSignature Is containingType Else Return TypeSymbol.Equals(typeFromSignature.GetNullableUnderlyingTypeOrSelf().GetTupleUnderlyingTypeOrSelf(), containingType.GetTupleUnderlyingTypeOrSelf(), TypeCompareKind.ConsiderEverything) End If End Function Public Shared Function MapUnaryOperatorKind(opCode As SyntaxKind) As UnaryOperatorKind Dim result As UnaryOperatorKind Select Case opCode Case SyntaxKind.UnaryPlusExpression result = UnaryOperatorKind.Plus Case SyntaxKind.UnaryMinusExpression result = UnaryOperatorKind.Minus Case SyntaxKind.NotExpression result = UnaryOperatorKind.Not Case Else Throw ExceptionUtilities.UnexpectedValue(opCode) End Select Return result End Function ''' <summary> ''' Returns UnaryOperatorKind.Error in case of error, otherwise adjusted operator kind. ''' </summary> Public Shared Function ResolveUnaryOperator( opCode As UnaryOperatorKind, operand As BoundExpression, binder As Binder, <Out()> ByRef intrinsicOperatorType As SpecialType, <Out()> ByRef userDefinedOperator As OverloadResolutionResult, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As UnaryOperatorKind Debug.Assert((opCode And UnaryOperatorKind.IntrinsicOpMask) = opCode AndAlso opCode <> UnaryOperatorKind.Error) opCode = (opCode And UnaryOperatorKind.IntrinsicOpMask) intrinsicOperatorType = SpecialType.None userDefinedOperator = Nothing Dim operandType = operand.Type ' First, dig through Nullable Dim nullableUnderlying = operandType.GetNullableUnderlyingTypeOrSelf() Dim operandIsNullable = (operandType IsNot nullableUnderlying) ' Now dig through Enum Dim enumUnderlying = nullableUnderlying.GetEnumUnderlyingTypeOrSelf() Dim operandIsEnum = (enumUnderlying IsNot nullableUnderlying) ' Filter out unexpected underlying types for Nullable and enum types If (operandIsEnum OrElse operandIsNullable) AndAlso (enumUnderlying.IsStringType() OrElse enumUnderlying.IsObjectType()) Then Return UnaryOperatorKind.Error End If Dim sourceType = enumUnderlying If sourceType.SpecialType <> SpecialType.System_Object AndAlso Not sourceType.IsIntrinsicType() Then If operandType.CanContainUserDefinedOperators(useSiteInfo) Then userDefinedOperator = ResolveUserDefinedUnaryOperator(operand, opCode, binder, includeEliminatedCandidates:=False, useSiteInfo:=useSiteInfo) If Not userDefinedOperator.BestResult.HasValue AndAlso userDefinedOperator.Candidates.Length = 0 Then userDefinedOperator = ResolveUserDefinedUnaryOperator(operand, opCode, binder, includeEliminatedCandidates:=True, useSiteInfo:=useSiteInfo) If userDefinedOperator.Candidates.Length = 0 Then Return UnaryOperatorKind.Error End If End If Return UnaryOperatorKind.UserDefined End If Return UnaryOperatorKind.Error End If Dim result As UnaryOperatorKind = UnaryOperatorKind.Error If operandIsEnum AndAlso opCode = UnaryOperatorKind.Not AndAlso sourceType.IsIntegralType() Then '§11.17 Logical Operators 'The enumerated type operators do the bitwise operation on the underlying type of 'the enumerated type, but the return value is the enumerated type. result = UnaryOperatorKind.Not Else intrinsicOperatorType = ResolveNotLiftedIntrinsicUnaryOperator(opCode, sourceType.SpecialType) If intrinsicOperatorType <> SpecialType.None Then result = opCode End If End If If result <> UnaryOperatorKind.Error AndAlso operandIsNullable Then result = result Or UnaryOperatorKind.Lifted End If Return result End Function ''' <summary> ''' Returns result type of the operator or SpecialType.None if operator is not supported. ''' </summary> Friend Shared Function ResolveNotLiftedIntrinsicUnaryOperator( opCode As UnaryOperatorKind, operandSpecialType As SpecialType ) As SpecialType Dim intrinsicOperatorType As SpecialType Select Case opCode Case UnaryOperatorKind.Not '§11.17 Logical Operators 'Bo SB By Sh US In UI Lo UL De Si Do Da Ch St Ob 'Bo SB By Sh US In UI Lo UL Lo Lo Lo Err Err Lo Ob Select Case operandSpecialType Case SpecialType.System_Boolean, SpecialType.System_SByte, SpecialType.System_Byte, SpecialType.System_Int16, SpecialType.System_UInt16, SpecialType.System_Int32, SpecialType.System_UInt32, SpecialType.System_Int64, SpecialType.System_UInt64, SpecialType.System_Object intrinsicOperatorType = operandSpecialType Case SpecialType.System_Decimal, SpecialType.System_Single, SpecialType.System_Double, SpecialType.System_String intrinsicOperatorType = SpecialType.System_Int64 Case Else intrinsicOperatorType = SpecialType.None End Select Case UnaryOperatorKind.Plus '§11.13.1 Unary Plus Operator 'Bo SB By Sh US In UI Lo UL De Si Do Da Ch St Ob 'Sh SB By Sh US In UI Lo UL De Si Do Err Err Do Ob Select Case operandSpecialType Case SpecialType.System_Boolean intrinsicOperatorType = SpecialType.System_Int16 Case SpecialType.System_SByte, SpecialType.System_Byte, SpecialType.System_Int16, SpecialType.System_UInt16, SpecialType.System_Int32, SpecialType.System_UInt32, SpecialType.System_Int64, SpecialType.System_UInt64, SpecialType.System_Decimal, SpecialType.System_Single, SpecialType.System_Double, SpecialType.System_Object intrinsicOperatorType = operandSpecialType Case SpecialType.System_String intrinsicOperatorType = SpecialType.System_Double Case Else intrinsicOperatorType = SpecialType.None End Select Case UnaryOperatorKind.Minus '§11.13.2 Unary Minus Operator 'Bo SB By Sh US In UI Lo UL De Si Do Da Ch St Ob 'Sh SB Sh Sh In In Lo Lo De De Si Do Err Err Do Ob Select Case operandSpecialType Case SpecialType.System_Boolean, SpecialType.System_Byte intrinsicOperatorType = SpecialType.System_Int16 Case SpecialType.System_SByte, SpecialType.System_Int16, SpecialType.System_Int32, SpecialType.System_Int64, SpecialType.System_Decimal, SpecialType.System_Single, SpecialType.System_Double, SpecialType.System_Object intrinsicOperatorType = operandSpecialType Case SpecialType.System_UInt16 intrinsicOperatorType = SpecialType.System_Int32 Case SpecialType.System_UInt32 intrinsicOperatorType = SpecialType.System_Int64 Case SpecialType.System_UInt64 intrinsicOperatorType = SpecialType.System_Decimal Case SpecialType.System_String intrinsicOperatorType = SpecialType.System_Double Case Else intrinsicOperatorType = SpecialType.None End Select Case Else Throw ExceptionUtilities.UnexpectedValue(opCode) End Select Return intrinsicOperatorType End Function ''' <summary> ''' Attempts to fold unary operator applied to a constant expression. ''' ''' Returns Nothing if operator cannot be folded. ''' ''' If folding failed due to non-integer overflow, ConstantValue.Bad is returned. Consumer ''' is responsible for reporting appropriate diagnostics. ''' ''' If integer overflow occurs, integerOverflow is set to True and ConstantValue for overflowed result is returned. ''' Consumer is responsible for reporting appropriate diagnostics and potentially discarding the result. ''' </summary> Public Shared Function TryFoldConstantUnaryOperator( op As UnaryOperatorKind, operand As BoundExpression, resultType As TypeSymbol, ByRef integerOverflow As Boolean ) As ConstantValue Debug.Assert(operand IsNot Nothing) Debug.Assert(resultType IsNot Nothing) integerOverflow = False Dim operandValue As ConstantValue = operand.ConstantValueOpt If operandValue Is Nothing OrElse operandValue.IsBad OrElse resultType.IsErrorType() Then ' Not a constant Return Nothing End If Dim operandType = operand.Type Dim result As ConstantValue = Nothing Dim underlyingResultType = resultType.GetEnumUnderlyingTypeOrSelf() If operandType.AllowsCompileTimeOperations() AndAlso underlyingResultType.AllowsCompileTimeOperations() Then Debug.Assert(underlyingResultType.IsValidForConstantValue(operandValue)) ' Attempt folding If underlyingResultType.IsIntegralType() Then Dim value As Int64 = GetConstantValueAsInt64(operandValue) Select Case (op And UnaryOperatorKind.IntrinsicOpMask) Case UnaryOperatorKind.Plus ' Nothing to do Case UnaryOperatorKind.Minus Debug.Assert(Not underlyingResultType.IsUnsignedIntegralType()) If value = Int64.MinValue Then integerOverflow = True End If value = -value Case UnaryOperatorKind.Not value = Not value Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select Dim detectedIntegerOverflow = integerOverflow Dim discriminator = underlyingResultType.GetConstantValueTypeDiscriminator() result = GetConstantValue(discriminator, NarrowIntegralResult(value, discriminator, discriminator, integerOverflow)) integerOverflow = (op And UnaryOperatorKind.IntrinsicOpMask) = UnaryOperatorKind.Minus AndAlso (integerOverflow OrElse detectedIntegerOverflow) ElseIf underlyingResultType.IsFloatingType Then Dim value As Double = If(underlyingResultType.IsSingleType(), operandValue.SingleValue, operandValue.DoubleValue) Select Case (op And UnaryOperatorKind.IntrinsicOpMask) Case UnaryOperatorKind.Plus ' Nothing to do Case UnaryOperatorKind.Minus value = -value Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select Dim overflow As Boolean = False value = NarrowFloatingResult(value, underlyingResultType.GetConstantValueTypeDiscriminator(), overflow) ' We have decided to ignore overflows in compile-time evaluation ' of floating expressions. If underlyingResultType.IsSingleType() Then result = ConstantValue.Create(CType(value, Single)) Else result = ConstantValue.Create(value) End If ElseIf underlyingResultType.IsDecimalType() Then Dim value As Decimal = operandValue.DecimalValue Select Case (op And UnaryOperatorKind.IntrinsicOpMask) Case UnaryOperatorKind.Plus ' Nothing to do Case UnaryOperatorKind.Minus value = Decimal.Negate(value) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select result = ConstantValue.Create(value) ElseIf underlyingResultType.IsBooleanType() Then Debug.Assert((op And UnaryOperatorKind.IntrinsicOpMask) = UnaryOperatorKind.Not) result = ConstantValue.Create(Not operandValue.BooleanValue) End If End If Return result End Function Public Shared Function MapBinaryOperatorKind(opCode As SyntaxKind) As BinaryOperatorKind Dim result As BinaryOperatorKind Select Case opCode Case SyntaxKind.AddExpression : result = BinaryOperatorKind.Add Case SyntaxKind.ConcatenateExpression : result = BinaryOperatorKind.Concatenate Case SyntaxKind.LikeExpression : result = BinaryOperatorKind.Like Case SyntaxKind.EqualsExpression : result = BinaryOperatorKind.Equals Case SyntaxKind.NotEqualsExpression : result = BinaryOperatorKind.NotEquals Case SyntaxKind.LessThanOrEqualExpression : result = BinaryOperatorKind.LessThanOrEqual Case SyntaxKind.GreaterThanOrEqualExpression : result = BinaryOperatorKind.GreaterThanOrEqual Case SyntaxKind.LessThanExpression : result = BinaryOperatorKind.LessThan Case SyntaxKind.GreaterThanExpression : result = BinaryOperatorKind.GreaterThan Case SyntaxKind.SubtractExpression : result = BinaryOperatorKind.Subtract Case SyntaxKind.MultiplyExpression : result = BinaryOperatorKind.Multiply Case SyntaxKind.ExponentiateExpression : result = BinaryOperatorKind.Power Case SyntaxKind.DivideExpression : result = BinaryOperatorKind.Divide Case SyntaxKind.ModuloExpression : result = BinaryOperatorKind.Modulo Case SyntaxKind.IntegerDivideExpression : result = BinaryOperatorKind.IntegerDivide Case SyntaxKind.LeftShiftExpression : result = BinaryOperatorKind.LeftShift Case SyntaxKind.RightShiftExpression : result = BinaryOperatorKind.RightShift Case SyntaxKind.ExclusiveOrExpression : result = BinaryOperatorKind.Xor Case SyntaxKind.OrExpression : result = BinaryOperatorKind.Or Case SyntaxKind.OrElseExpression : result = BinaryOperatorKind.OrElse Case SyntaxKind.AndExpression : result = BinaryOperatorKind.And Case SyntaxKind.AndAlsoExpression : result = BinaryOperatorKind.AndAlso Case Else Throw ExceptionUtilities.UnexpectedValue(opCode) End Select Return result End Function ''' <summary> ''' Returns UnaryOperatorKind.Error in case of error, otherwise adjusted operator kind. ''' ''' For comparison operators, the operator 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. ''' </summary> Public Shared Function ResolveBinaryOperator( opCode As BinaryOperatorKind, left As BoundExpression, right As BoundExpression, binder As Binder, considerUserDefinedOrLateBound As Boolean, <Out()> ByRef intrinsicOperatorType As SpecialType, <Out()> ByRef userDefinedOperator As OverloadResolutionResult, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As BinaryOperatorKind Debug.Assert((opCode And BinaryOperatorKind.OpMask) = opCode AndAlso opCode <> BinaryOperatorKind.Error) opCode = (opCode And BinaryOperatorKind.OpMask) intrinsicOperatorType = SpecialType.None userDefinedOperator = Nothing Dim leftType As TypeSymbol = left.Type Dim rightType As TypeSymbol = right.Type ' First, dig through Nullable Dim leftNullableUnderlying = leftType.GetNullableUnderlyingTypeOrSelf() Dim leftIsNullable = (leftType IsNot leftNullableUnderlying) Dim rightNullableUnderlying = rightType.GetNullableUnderlyingTypeOrSelf() Dim rightIsNullable = (rightType IsNot rightNullableUnderlying) ' Now dig through Enum Dim leftEnumUnderlying = leftNullableUnderlying.GetEnumUnderlyingTypeOrSelf() Dim leftIsEnum = (leftEnumUnderlying IsNot leftNullableUnderlying) Dim rightEnumUnderlying = rightNullableUnderlying.GetEnumUnderlyingTypeOrSelf() Dim rightIsEnum = (rightEnumUnderlying IsNot rightNullableUnderlying) ' Filter out unexpected underlying types for Nullable and enum types If ((leftIsEnum OrElse leftIsNullable) AndAlso (leftEnumUnderlying.IsStringType() OrElse leftEnumUnderlying.IsObjectType() OrElse leftEnumUnderlying.IsCharSZArray())) OrElse ((rightIsEnum OrElse rightIsNullable) AndAlso (rightEnumUnderlying.IsStringType() OrElse rightEnumUnderlying.IsObjectType() OrElse rightEnumUnderlying.IsCharSZArray())) Then Return BinaryOperatorKind.Error End If If UseUserDefinedBinaryOperators(opCode, leftType, rightType) Then If considerUserDefinedOrLateBound Then If leftType.CanContainUserDefinedOperators(useSiteInfo) OrElse rightType.CanContainUserDefinedOperators(useSiteInfo) OrElse (opCode = BinaryOperatorKind.Subtract AndAlso leftType.GetNullableUnderlyingTypeOrSelf().IsDateTimeType() AndAlso rightType.GetNullableUnderlyingTypeOrSelf().IsDateTimeType()) Then ' Let (Date - Date) use operator overloading. userDefinedOperator = ResolveUserDefinedBinaryOperator(left, right, opCode, binder, includeEliminatedCandidates:=False, useSiteInfo:=useSiteInfo) If userDefinedOperator.ResolutionIsLateBound Then intrinsicOperatorType = SpecialType.System_Object Return opCode ElseIf Not userDefinedOperator.BestResult.HasValue AndAlso userDefinedOperator.Candidates.Length = 0 Then userDefinedOperator = ResolveUserDefinedBinaryOperator(left, right, opCode, binder, includeEliminatedCandidates:=True, useSiteInfo:=CompoundUseSiteInfo(Of AssemblySymbol).Discarded) If userDefinedOperator.Candidates.Length = 0 Then Return BinaryOperatorKind.Error End If End If Return BinaryOperatorKind.UserDefined Else ' An operator with an Object operand and a Type Parameter operand ' is latebound if the Type Parameter has no class constraint. Dim latebound As Boolean = False If leftType.IsObjectType() Then If rightType.IsTypeParameter() AndAlso DirectCast(rightType, TypeParameterSymbol).GetNonInterfaceConstraint(useSiteInfo) Is Nothing Then latebound = True End If ElseIf rightType.IsObjectType() Then If leftType.IsTypeParameter() AndAlso DirectCast(leftType, TypeParameterSymbol).GetNonInterfaceConstraint(useSiteInfo) Is Nothing Then latebound = True End If End If If latebound Then intrinsicOperatorType = SpecialType.System_Object Return opCode End If End If End If Return BinaryOperatorKind.Error End If Dim result As BinaryOperatorKind = BinaryOperatorKind.Error If leftIsEnum AndAlso rightIsEnum AndAlso (opCode = BinaryOperatorKind.Xor OrElse opCode = BinaryOperatorKind.And OrElse opCode = BinaryOperatorKind.Or) AndAlso leftNullableUnderlying.IsSameTypeIgnoringAll(rightNullableUnderlying) Then '§11.17 Logical Operators 'The enumerated type operators do the bitwise operation on the underlying 'type of the enumerated type, but the return value is the enumerated type. result = opCode If leftIsNullable OrElse rightIsNullable Then result = result Or BinaryOperatorKind.Lifted End If Else Dim leftSpecialType = leftEnumUnderlying.SpecialType Dim rightSpecialType = rightEnumUnderlying.SpecialType ' Operands of type 1-dimensional array of Char are treated as if they ' were of type String. If leftSpecialType = SpecialType.None AndAlso leftEnumUnderlying.IsCharSZArray() Then leftSpecialType = SpecialType.System_String End If If rightSpecialType = SpecialType.None AndAlso rightEnumUnderlying.IsCharSZArray() Then rightSpecialType = SpecialType.System_String End If intrinsicOperatorType = ResolveNotLiftedIntrinsicBinaryOperator(opCode, leftSpecialType, rightSpecialType) If intrinsicOperatorType <> SpecialType.None Then result = opCode End If ' Like and '&' don't have lifted form. ' Disallow nullable lifting if result is not a value type If result <> BinaryOperatorKind.Error AndAlso (leftIsNullable OrElse rightIsNullable) AndAlso intrinsicOperatorType <> SpecialType.None AndAlso intrinsicOperatorType <> SpecialType.System_String AndAlso intrinsicOperatorType <> SpecialType.System_Object AndAlso opCode <> BinaryOperatorKind.Concatenate AndAlso opCode <> BinaryOperatorKind.Like Then result = result Or BinaryOperatorKind.Lifted End If End If Return result End Function Public Shared Function UseUserDefinedBinaryOperators(opCode As BinaryOperatorKind, leftType As TypeSymbol, rightType As TypeSymbol) As Boolean Dim leftEnumUnderlying = leftType.GetNullableUnderlyingTypeOrSelf().GetEnumUnderlyingTypeOrSelf() Dim rightEnumUnderlying = rightType.GetNullableUnderlyingTypeOrSelf().GetEnumUnderlyingTypeOrSelf() ' Operands of type 1-dimensional array of Char are treated as if they ' were of type String. If (leftEnumUnderlying.SpecialType <> SpecialType.System_Object AndAlso Not leftEnumUnderlying.IsIntrinsicType() AndAlso Not leftEnumUnderlying.IsCharSZArray()) OrElse (rightEnumUnderlying.SpecialType <> SpecialType.System_Object AndAlso Not rightEnumUnderlying.IsIntrinsicType() AndAlso Not rightEnumUnderlying.IsCharSZArray()) OrElse (leftEnumUnderlying.IsDateTimeType() AndAlso rightEnumUnderlying.IsDateTimeType() AndAlso opCode = BinaryOperatorKind.Subtract) Then ' Let (Date - Date) use operator overloading. Return True End If Return False End Function ''' <summary> ''' Attempts to fold binary operator applied to constant expressions. ''' ''' Returns Nothing if operator cannot be folded. ''' ''' If folding failed due to non-integer overflow or divide by zero, ''' ConstantValue.Bad is returned. Consumer is responsible for reporting appropriate diagnostics. ''' ''' If divide by zero occurs, divideByZero is set to True. ''' ''' If integer overflow occurs, integerOverflow is set to True and ConstantValue for overflowed result is returned. ''' Consumer is responsible for reporting appropriate diagnostics and potentially discarding the result. ''' </summary> Public Shared Function TryFoldConstantBinaryOperator( operatorKind As BinaryOperatorKind, left As BoundExpression, right As BoundExpression, resultType As TypeSymbol, ByRef integerOverflow As Boolean, ByRef divideByZero As Boolean, ByRef lengthOutOfLimit As Boolean ) As ConstantValue Debug.Assert(left IsNot Nothing) Debug.Assert(right IsNot Nothing) Debug.Assert(resultType IsNot Nothing) integerOverflow = False divideByZero = False lengthOutOfLimit = False Dim leftConstantValue As ConstantValue = left.ConstantValueOpt Dim rightConstantValue As ConstantValue = right.ConstantValueOpt If leftConstantValue Is Nothing OrElse leftConstantValue.IsBad OrElse rightConstantValue Is Nothing OrElse rightConstantValue.IsBad OrElse resultType.IsErrorType() Then ' Not a constant Return Nothing End If Dim leftType = left.Type Dim rightType = right.Type Dim op As BinaryOperatorKind = (operatorKind And BinaryOperatorKind.OpMask) Dim result As ConstantValue = Nothing If op <> BinaryOperatorKind.Like AndAlso (operatorKind And BinaryOperatorKind.CompareText) = 0 AndAlso leftType.AllowsCompileTimeOperations() AndAlso rightType.AllowsCompileTimeOperations() AndAlso resultType.AllowsCompileTimeOperations() Then Debug.Assert(leftType.IsSameTypeIgnoringAll(rightType) OrElse op = BinaryOperatorKind.LeftShift OrElse op = BinaryOperatorKind.RightShift) Dim leftUnderlying = leftType.GetEnumUnderlyingTypeOrSelf() Dim resultUnderlying = resultType.GetEnumUnderlyingTypeOrSelf() If leftUnderlying.IsIntegralType() OrElse leftUnderlying.IsCharType() OrElse leftUnderlying.IsDateTimeType() Then result = FoldIntegralCharOrDateTimeBinaryOperator( op, leftConstantValue, rightConstantValue, leftUnderlying, resultUnderlying, integerOverflow, divideByZero) ElseIf leftUnderlying.IsFloatingType() Then result = FoldFloatingBinaryOperator( op, leftConstantValue, rightConstantValue, leftUnderlying, resultUnderlying) ElseIf leftUnderlying.IsDecimalType() Then result = FoldDecimalBinaryOperator( op, leftConstantValue, rightConstantValue, resultUnderlying, divideByZero) ElseIf leftUnderlying.IsStringType() Then ' During normal compilation we never fold string comparison with ' Option Compare Text in effect. However, it looks like Dev10 goes through ' this code path in EE and folds comparison regardless of Option Compare. ' I am not sure if we need this in Roslyn, will ignore Option Compare Text for now. Debug.Assert((operatorKind And BinaryOperatorKind.CompareText) = 0) result = FoldStringBinaryOperator( op, leftConstantValue, rightConstantValue) If result.IsBad Then lengthOutOfLimit = True End If ElseIf leftUnderlying.IsBooleanType() Then result = FoldBooleanBinaryOperator( op, leftConstantValue, rightConstantValue) End If Debug.Assert(result IsNot Nothing) End If Return result End Function Private Shared Function FoldIntegralCharOrDateTimeBinaryOperator( op As BinaryOperatorKind, left As ConstantValue, right As ConstantValue, operandType As TypeSymbol, resultType As TypeSymbol, ByRef integerOverflow As Boolean, ByRef divideByZero As Boolean ) As ConstantValue Debug.Assert(operandType.IsIntegralType() OrElse operandType.IsCharType() OrElse operandType.IsDateTimeType()) Debug.Assert((op And BinaryOperatorKind.OpMask) = op) Debug.Assert(Not integerOverflow) Debug.Assert(Not divideByZero) Dim result As ConstantValue Dim leftValue As Long = GetConstantValueAsInt64(left) Dim rightValue As Long = GetConstantValueAsInt64(right) If resultType.IsBooleanType() Then Dim resultValue As Boolean Select Case op Case BinaryOperatorKind.Equals resultValue = If(operandType.IsUnsignedIntegralType(), UncheckedCULng(leftValue) = UncheckedCULng(rightValue), leftValue = rightValue) Case BinaryOperatorKind.NotEquals resultValue = If(operandType.IsUnsignedIntegralType(), UncheckedCULng(leftValue) <> UncheckedCULng(rightValue), leftValue <> rightValue) Case BinaryOperatorKind.LessThanOrEqual resultValue = If(operandType.IsUnsignedIntegralType(), UncheckedCULng(leftValue) <= UncheckedCULng(rightValue), leftValue <= rightValue) Case BinaryOperatorKind.GreaterThanOrEqual resultValue = If(operandType.IsUnsignedIntegralType(), UncheckedCULng(leftValue) >= UncheckedCULng(rightValue), leftValue >= rightValue) Case BinaryOperatorKind.LessThan resultValue = If(operandType.IsUnsignedIntegralType(), UncheckedCULng(leftValue) < UncheckedCULng(rightValue), leftValue < rightValue) Case BinaryOperatorKind.GreaterThan resultValue = If(operandType.IsUnsignedIntegralType(), UncheckedCULng(leftValue) > UncheckedCULng(rightValue), leftValue > rightValue) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select result = ConstantValue.Create(resultValue) Else ' Compute the result in 64-bit arithmetic, and determine if the ' operation overflows the result type. Dim resultValue As Long Dim leftDiscriminator = operandType.GetConstantValueTypeDiscriminator() Dim resultDiscriminator = resultType.GetConstantValueTypeDiscriminator() Select Case op Case BinaryOperatorKind.Add resultValue = NarrowIntegralResult(leftValue + rightValue, leftDiscriminator, resultDiscriminator, integerOverflow) If Not resultType.IsUnsignedIntegralType() Then If (rightValue > 0 AndAlso resultValue < leftValue) OrElse (rightValue < 0 AndAlso resultValue > leftValue) Then integerOverflow = True End If ElseIf UncheckedCULng(resultValue) < UncheckedCULng(leftValue) Then integerOverflow = True End If Case BinaryOperatorKind.Subtract resultValue = NarrowIntegralResult(leftValue - rightValue, leftDiscriminator, resultDiscriminator, integerOverflow) If Not resultType.IsUnsignedIntegralType() Then If (rightValue > 0 AndAlso resultValue > leftValue) OrElse (rightValue < 0 AndAlso resultValue < leftValue) Then integerOverflow = True End If ElseIf UncheckedCULng(resultValue) > UncheckedCULng(leftValue) Then integerOverflow = True End If Case BinaryOperatorKind.Multiply resultValue = Multiply(leftValue, rightValue, leftDiscriminator, resultDiscriminator, integerOverflow) Case BinaryOperatorKind.IntegerDivide If rightValue = 0 Then divideByZero = True Else resultValue = NarrowIntegralResult( If(resultType.IsUnsignedIntegralType(), UncheckedCLng(UncheckedCULng(leftValue) \ UncheckedCULng(rightValue)), UncheckedIntegralDiv(leftValue, rightValue)), leftDiscriminator, resultDiscriminator, integerOverflow) If Not resultType.IsUnsignedIntegralType() AndAlso leftValue = Int64.MinValue AndAlso rightValue = -1 Then integerOverflow = True End If End If Case BinaryOperatorKind.Modulo If rightValue = 0 Then divideByZero = True Else If resultType.IsUnsignedIntegralType() Then resultValue = UncheckedCLng(UncheckedCULng(leftValue) Mod UncheckedCULng(rightValue)) ' // 64-bit processors crash on 0, -1 (Bug: dd71694) ElseIf rightValue <> -1L Then resultValue = leftValue Mod rightValue Else resultValue = 0 End If End If Case BinaryOperatorKind.Xor resultValue = leftValue Xor rightValue Case BinaryOperatorKind.Or resultValue = leftValue Or rightValue Case BinaryOperatorKind.And resultValue = leftValue And rightValue Case BinaryOperatorKind.LeftShift resultValue = leftValue << (CType(rightValue, Integer) And CodeGen.CodeGenerator.GetShiftSizeMask(operandType)) ' // Round-trip the result through a cast. We do this for two reasons: ' // a) Bits may have shifted off the end and need to be stripped away. ' // b) The sign bit may have changed which requires the result to be sign-extended. Dim overflowTemp As Boolean = False resultValue = NarrowIntegralResult(resultValue, leftDiscriminator, resultDiscriminator, overflowTemp) Case BinaryOperatorKind.RightShift If resultType.IsUnsignedIntegralType() Then resultValue = UncheckedCLng((UncheckedCULng(leftValue) >> (CType(rightValue, Integer) And CodeGen.CodeGenerator.GetShiftSizeMask(operandType)))) Else resultValue = leftValue >> (CType(rightValue, Integer) And CodeGen.CodeGenerator.GetShiftSizeMask(operandType)) End If Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select If divideByZero Then result = ConstantValue.Bad Else result = GetConstantValue(resultDiscriminator, resultValue) End If End If Return result End Function Private Shared Function FoldFloatingBinaryOperator( op As BinaryOperatorKind, left As ConstantValue, right As ConstantValue, operandType As TypeSymbol, resultType As TypeSymbol ) As ConstantValue Debug.Assert(operandType.IsFloatingType()) Debug.Assert((op And BinaryOperatorKind.OpMask) = op) Dim result As ConstantValue Dim leftValue As Double = If(operandType.IsSingleType, left.SingleValue, left.DoubleValue) Dim rightValue As Double = If(operandType.IsSingleType, right.SingleValue, right.DoubleValue) If resultType.IsBooleanType() Then Dim resultValue As Boolean Select Case op Case BinaryOperatorKind.Equals resultValue = (leftValue = rightValue) Case BinaryOperatorKind.NotEquals resultValue = (leftValue <> rightValue) Case BinaryOperatorKind.LessThanOrEqual resultValue = (leftValue <= rightValue) Case BinaryOperatorKind.GreaterThanOrEqual resultValue = (leftValue >= rightValue) Case BinaryOperatorKind.LessThan resultValue = (leftValue < rightValue) Case BinaryOperatorKind.GreaterThan resultValue = (leftValue > rightValue) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select result = ConstantValue.Create(resultValue) Else ' Compute the result in 64-bit arithmetic, and determine if the ' operation overflows the result type. Dim resultValue As Double = 0 Select Case op Case BinaryOperatorKind.Add resultValue = leftValue + rightValue Case BinaryOperatorKind.Subtract resultValue = leftValue - rightValue Case BinaryOperatorKind.Multiply resultValue = leftValue * rightValue Case BinaryOperatorKind.Power ' VSW#463059: Special case CRT changes to match CLR behavior. If Double.IsInfinity(rightValue) Then If leftValue.Equals(1.0) Then resultValue = leftValue Exit Select End If If leftValue.Equals(-1.0) Then resultValue = Double.NaN Exit Select End If ElseIf ( Double.IsNaN(rightValue) ) Then resultValue = Double.NaN Exit Select End If resultValue = Math.Pow(leftValue, rightValue) Case BinaryOperatorKind.Divide ' We have decided not to detect zerodivide in compile-time ' evaluation of floating expressions. resultValue = leftValue / rightValue Case BinaryOperatorKind.Modulo ' We have decided not to detect zerodivide in compile-time ' evaluation of floating expressions. ' Note, that Math.IEEERemainder(leftValue, rightValue) might give different result. ' Dev10 compiler used fmod function here and it behaves differently. It looks like ' ILOpCode.Rem operation, that we use to emit Mod operator, produces result consistent ' with fmod. resultValue = leftValue Mod rightValue Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select Dim overflow As Boolean = False resultValue = NarrowFloatingResult(resultValue, resultType.GetConstantValueTypeDiscriminator(), overflow) ' We have decided not to detect overflow in compile-time ' evaluation of floating expressions. If resultType.IsSingleType() Then result = ConstantValue.Create(CType(resultValue, Single)) Else result = ConstantValue.Create(resultValue) End If End If Return result End Function Private Shared Function FoldDecimalBinaryOperator( op As BinaryOperatorKind, left As ConstantValue, right As ConstantValue, resultType As TypeSymbol, ByRef divideByZero As Boolean ) As ConstantValue Debug.Assert((op And BinaryOperatorKind.OpMask) = op) Debug.Assert(Not divideByZero) Dim result As ConstantValue Dim leftValue As Decimal = left.DecimalValue Dim rightValue As Decimal = right.DecimalValue If resultType.IsBooleanType() Then Dim resultValue As Boolean = False Dim comparisonResult As Integer = leftValue.CompareTo(rightValue) Select Case op Case BinaryOperatorKind.Equals resultValue = (comparisonResult = 0) Case BinaryOperatorKind.NotEquals resultValue = Not (comparisonResult = 0) Case BinaryOperatorKind.LessThanOrEqual resultValue = (comparisonResult <= 0) Case BinaryOperatorKind.GreaterThanOrEqual resultValue = (comparisonResult >= 0) Case BinaryOperatorKind.LessThan resultValue = (comparisonResult < 0) Case BinaryOperatorKind.GreaterThan resultValue = (comparisonResult > 0) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select result = ConstantValue.Create(resultValue) Else Dim resultValue As Decimal Dim overflow As Boolean = False Try Select Case op Case BinaryOperatorKind.Add resultValue = Decimal.Add(leftValue, rightValue) Case BinaryOperatorKind.Subtract resultValue = Decimal.Subtract(leftValue, rightValue) Case BinaryOperatorKind.Multiply resultValue = Decimal.Multiply(leftValue, rightValue) Case BinaryOperatorKind.Divide resultValue = Decimal.Divide(leftValue, rightValue) Case BinaryOperatorKind.Modulo resultValue = Decimal.Remainder(leftValue, rightValue) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select Catch ex As OverflowException overflow = True Catch ex As DivideByZeroException divideByZero = True End Try If overflow OrElse divideByZero Then result = ConstantValue.Bad Else result = ConstantValue.Create(resultValue) End If End If Return result End Function ''' <summary> ''' Returns ConstantValue.Bad if, and only if, compound string length is out of supported limit. ''' </summary> Private Shared Function FoldStringBinaryOperator( op As BinaryOperatorKind, left As ConstantValue, right As ConstantValue ) As ConstantValue Debug.Assert((op And BinaryOperatorKind.OpMask) = op) Dim result As ConstantValue Select Case op Case BinaryOperatorKind.Concatenate Dim leftValue As Rope = If(left.IsNothing, Rope.Empty, left.RopeValue) Dim rightValue As Rope = If(right.IsNothing, Rope.Empty, right.RopeValue) Dim newLength = CLng(leftValue.Length) + CLng(rightValue.Length) If newLength > Integer.MaxValue Then Return ConstantValue.Bad End If Try result = ConstantValue.CreateFromRope(Rope.Concat(leftValue, rightValue)) Catch e As System.OutOfMemoryException Return ConstantValue.Bad End Try Case BinaryOperatorKind.GreaterThan, BinaryOperatorKind.LessThan, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.Equals, BinaryOperatorKind.NotEquals Dim leftValue As String = If(left.IsNothing, String.Empty, left.StringValue) Dim rightValue As String = If(right.IsNothing, String.Empty, right.StringValue) Dim stringComparisonSucceeds As Boolean = False Dim comparisonResult As Integer = String.Compare(leftValue, rightValue, StringComparison.Ordinal) Select Case op Case BinaryOperatorKind.Equals stringComparisonSucceeds = (comparisonResult = 0) Case BinaryOperatorKind.NotEquals stringComparisonSucceeds = (comparisonResult <> 0) Case BinaryOperatorKind.GreaterThan stringComparisonSucceeds = (comparisonResult > 0) Case BinaryOperatorKind.GreaterThanOrEqual stringComparisonSucceeds = (comparisonResult >= 0) Case BinaryOperatorKind.LessThan stringComparisonSucceeds = (comparisonResult < 0) Case BinaryOperatorKind.LessThanOrEqual stringComparisonSucceeds = (comparisonResult <= 0) End Select result = ConstantValue.Create(stringComparisonSucceeds) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select Debug.Assert(Not result.IsBad) Return result End Function Private Shared Function FoldBooleanBinaryOperator( op As BinaryOperatorKind, left As ConstantValue, right As ConstantValue ) As ConstantValue Debug.Assert((op And BinaryOperatorKind.OpMask) = op) Dim result As ConstantValue Dim leftValue As Boolean = left.BooleanValue Dim rightValue As Boolean = right.BooleanValue Dim operationSucceeds As Boolean = False Select Case op Case BinaryOperatorKind.Equals operationSucceeds = (leftValue = rightValue) Case BinaryOperatorKind.NotEquals operationSucceeds = (leftValue <> rightValue) Case BinaryOperatorKind.GreaterThan ' Amazingly, False > True. operationSucceeds = (leftValue = False AndAlso rightValue = True) Case BinaryOperatorKind.GreaterThanOrEqual operationSucceeds = (leftValue = False OrElse rightValue = True) Case BinaryOperatorKind.LessThan operationSucceeds = (leftValue = True AndAlso rightValue = False) Case BinaryOperatorKind.LessThanOrEqual operationSucceeds = (leftValue = True OrElse rightValue = False) Case BinaryOperatorKind.Xor operationSucceeds = (leftValue Xor rightValue) Case BinaryOperatorKind.OrElse, BinaryOperatorKind.Or operationSucceeds = (leftValue OrElse rightValue) Case BinaryOperatorKind.AndAlso, BinaryOperatorKind.And operationSucceeds = (leftValue AndAlso rightValue) Case Else Throw ExceptionUtilities.UnexpectedValue(op) End Select result = ConstantValue.Create(operationSucceeds) Return result End Function ''' <summary> ''' Returns result type of the operator or SpecialType.None if operator is not supported. ''' </summary> Friend Shared Function ResolveNotLiftedIntrinsicBinaryOperator( opCode As BinaryOperatorKind, left As SpecialType, right As SpecialType ) As SpecialType Dim leftIndex = left.TypeToIndex() Dim rightIndex = right.TypeToIndex() If Not (leftIndex.HasValue AndAlso rightIndex.HasValue) Then Return SpecialType.None End If Dim tableKind As BinaryOperatorTables.TableKind Select Case opCode Case BinaryOperatorKind.Add tableKind = BinaryOperatorTables.TableKind.Addition Case BinaryOperatorKind.Subtract, BinaryOperatorKind.Multiply, BinaryOperatorKind.Modulo tableKind = BinaryOperatorTables.TableKind.SubtractionMultiplicationModulo Case BinaryOperatorKind.Divide tableKind = BinaryOperatorTables.TableKind.Division Case BinaryOperatorKind.IntegerDivide tableKind = BinaryOperatorTables.TableKind.IntegerDivision Case BinaryOperatorKind.Power tableKind = BinaryOperatorTables.TableKind.Power Case BinaryOperatorKind.LeftShift, BinaryOperatorKind.RightShift tableKind = BinaryOperatorTables.TableKind.Shift Case BinaryOperatorKind.OrElse, BinaryOperatorKind.AndAlso tableKind = BinaryOperatorTables.TableKind.Logical Case BinaryOperatorKind.Concatenate, BinaryOperatorKind.Like tableKind = BinaryOperatorTables.TableKind.ConcatenationLike Case BinaryOperatorKind.Equals, BinaryOperatorKind.NotEquals, BinaryOperatorKind.LessThanOrEqual, BinaryOperatorKind.GreaterThanOrEqual, BinaryOperatorKind.LessThan, BinaryOperatorKind.GreaterThan tableKind = BinaryOperatorTables.TableKind.Relational Case BinaryOperatorKind.Xor, BinaryOperatorKind.Or, BinaryOperatorKind.And tableKind = BinaryOperatorTables.TableKind.Bitwise Case Else Throw ExceptionUtilities.UnexpectedValue(opCode) End Select Return CType(BinaryOperatorTables.Table(tableKind, leftIndex.Value, rightIndex.Value), SpecialType) End Function Private Class BinaryOperatorTables Public Enum TableKind Addition SubtractionMultiplicationModulo Division Power IntegerDivision Shift Logical Bitwise Relational ConcatenationLike End Enum ' PERF: Using SByte instead of SpecialType because we want the compiler to use array literal initialization. ' The most natural type choice, Enum arrays, are not blittable due to a CLR limitation. Public Shared ReadOnly Table(,,) As SByte Shared Sub New() Const tErr As SByte = SpecialType.None Const tObj As SByte = SpecialType.System_Object Const tStr As SByte = SpecialType.System_String Const tDbl As SByte = SpecialType.System_Double Const tSBy As SByte = SpecialType.System_SByte Const tShr As SByte = SpecialType.System_Int16 Const tInt As SByte = SpecialType.System_Int32 Const tLng As SByte = SpecialType.System_Int64 Const tDec As SByte = SpecialType.System_Decimal Const tSng As SByte = SpecialType.System_Single Const tByt As SByte = SpecialType.System_Byte Const tUSh As SByte = SpecialType.System_UInt16 Const tUIn As SByte = SpecialType.System_UInt32 Const tULn As SByte = SpecialType.System_UInt64 Const tBoo As SByte = SpecialType.System_Boolean Const tChr As SByte = SpecialType.System_Char Const tDat As SByte = SpecialType.System_DateTime Table = { ' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Addition {tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj}, ' Obj {tObj, tStr, tDbl, tStr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tStr}, ' Str {tObj, tDbl, tShr, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Bool {tObj, tStr, tErr, tStr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tDbl, tSBy, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' SByt {tObj, tDbl, tShr, tErr, tShr, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Shrt {tObj, tDbl, tInt, tErr, tInt, tInt, tInt, tLng, tInt, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Int {tObj, tDbl, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Long {tObj, tDbl, tShr, tErr, tShr, tShr, tInt, tLng, tByt, tUSh, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' Byte {tObj, tDbl, tInt, tErr, tInt, tInt, tInt, tLng, tUSh, tUSh, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' UShr {tObj, tDbl, tLng, tErr, tLng, tLng, tLng, tLng, tUIn, tUIn, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' UInt {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tULn, tULn, tULn, tULn, tSng, tDbl, tDec, tErr}, ' ULng {tObj, tDbl, tSng, tErr, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tDbl, tSng, tErr}, ' Sngl {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Dbl {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tSng, tDbl, tDec, tErr}, ' Dec {tObj, tStr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tStr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Subtraction, Multiplication, and Modulo {tObj, tObj, tObj, tErr, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tErr}, ' Obj {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Str {tObj, tDbl, tShr, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tDbl, tSBy, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' SByt {tObj, tDbl, tShr, tErr, tShr, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Shrt {tObj, tDbl, tInt, tErr, tInt, tInt, tInt, tLng, tInt, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Int {tObj, tDbl, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Long {tObj, tDbl, tShr, tErr, tShr, tShr, tInt, tLng, tByt, tUSh, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' Byte {tObj, tDbl, tInt, tErr, tInt, tInt, tInt, tLng, tUSh, tUSh, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' UShr {tObj, tDbl, tLng, tErr, tLng, tLng, tLng, tLng, tUIn, tUIn, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' UInt {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tULn, tULn, tULn, tULn, tSng, tDbl, tDec, tErr}, ' ULng {tObj, tDbl, tSng, tErr, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tDbl, tSng, tErr}, ' Sngl {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Dbl {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tSng, tDbl, tDec, tErr}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date }, ' Special Note: Date - Date is actually TimeSpan, but that cannot be encoded in this table.^^^^ { ' Division {tObj, tObj, tObj, tErr, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tErr}, ' Obj {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Str {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' SByt {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' Shrt {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' Int {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' Long {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' Byte {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' UShr {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' UInt {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tSng, tDbl, tDec, tErr}, ' ULng {tObj, tDbl, tSng, tErr, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tDbl, tSng, tErr}, ' Sngl {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Dbl {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tSng, tDbl, tDec, tErr}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Power {tObj, tObj, tObj, tErr, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tErr}, ' Obj {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Str {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' SByt {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Shrt {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Int {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Long {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Byte {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' UShr {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' UInt {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' ULng {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Sngl {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Dbl {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Integer Division {tObj, tObj, tObj, tErr, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tErr}, ' Obj {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Str {tObj, tLng, tShr, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tLng, tSBy, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' SByt {tObj, tLng, tShr, tErr, tShr, tShr, tInt, tLng, tShr, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' Shrt {tObj, tLng, tInt, tErr, tInt, tInt, tInt, tLng, tInt, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' Int {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Long {tObj, tLng, tShr, tErr, tShr, tShr, tInt, tLng, tByt, tUSh, tUIn, tULn, tLng, tLng, tLng, tErr}, ' Byte {tObj, tLng, tInt, tErr, tInt, tInt, tInt, tLng, tUSh, tUSh, tUIn, tULn, tLng, tLng, tLng, tErr}, ' UShr {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tUIn, tUIn, tUIn, tULn, tLng, tLng, tLng, tErr}, ' UInt {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tULn, tULn, tULn, tULn, tLng, tLng, tLng, tErr}, ' ULng {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Sngl {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Dbl {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Shift. Note: The right operand serves little purpose in this table, however a table is utilized nonetheless to make the most use of already existing code which analyzes binary operators. {tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj}, ' Obj {tObj, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng}, ' Str {tObj, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy, tSBy}, ' SByt {tObj, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr, tShr}, ' Shrt {tObj, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt, tInt}, ' Int {tObj, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng}, ' Long {tObj, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt, tByt}, ' Byte {tObj, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh, tUSh}, ' UShr {tObj, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn, tUIn}, ' UInt {tObj, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn, tULn}, ' ULng {tObj, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng}, ' Sngl {tObj, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng}, ' Dbl {tObj, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Logical Operators {tObj, tObj, tObj, tErr, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tErr}, ' Obj {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Str {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' SByt {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Shrt {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Int {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Long {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Byte {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' UShr {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' UInt {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' ULng {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Sngl {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Dbl {tObj, tBoo, tBoo, tErr, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tBoo, tErr}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Bitwise Operators {tObj, tObj, tObj, tErr, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tErr}, ' Obj {tObj, tLng, tBoo, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Str {tObj, tBoo, tBoo, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' Bool {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tLng, tSBy, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' SByt {tObj, tLng, tShr, tErr, tShr, tShr, tInt, tLng, tShr, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' Shrt {tObj, tLng, tInt, tErr, tInt, tInt, tInt, tLng, tInt, tInt, tLng, tLng, tLng, tLng, tLng, tErr}, ' Int {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Long {tObj, tLng, tShr, tErr, tShr, tShr, tInt, tLng, tByt, tUSh, tUIn, tULn, tLng, tLng, tLng, tErr}, ' Byte {tObj, tLng, tInt, tErr, tInt, tInt, tInt, tLng, tUSh, tUSh, tUIn, tULn, tLng, tLng, tLng, tErr}, ' UShr {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tUIn, tUIn, tUIn, tULn, tLng, tLng, tLng, tErr}, ' UInt {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tULn, tULn, tULn, tULn, tLng, tLng, tLng, tErr}, ' ULng {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Sngl {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Dbl {tObj, tLng, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tErr}, ' Dec {tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Relational Operators -- This one is a little unusual because it lists the type of the relational operation, even though the result type is always boolean {tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj}, ' Obj {tObj, tStr, tBoo, tStr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDat}, ' Str {tObj, tBoo, tBoo, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Bool {tObj, tStr, tErr, tChr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr}, ' Char {tObj, tDbl, tSBy, tErr, tSBy, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' SByt {tObj, tDbl, tShr, tErr, tShr, tShr, tInt, tLng, tShr, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Shrt {tObj, tDbl, tInt, tErr, tInt, tInt, tInt, tLng, tInt, tInt, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Int {tObj, tDbl, tLng, tErr, tLng, tLng, tLng, tLng, tLng, tLng, tLng, tDec, tSng, tDbl, tDec, tErr}, ' Long {tObj, tDbl, tShr, tErr, tShr, tShr, tInt, tLng, tByt, tUSh, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' Byte {tObj, tDbl, tInt, tErr, tInt, tInt, tInt, tLng, tUSh, tUSh, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' UShr {tObj, tDbl, tLng, tErr, tLng, tLng, tLng, tLng, tUIn, tUIn, tUIn, tULn, tSng, tDbl, tDec, tErr}, ' UInt {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tULn, tULn, tULn, tULn, tSng, tDbl, tDec, tErr}, ' ULng {tObj, tDbl, tSng, tErr, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tSng, tDbl, tSng, tErr}, ' Sngl {tObj, tDbl, tDbl, tErr, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tDbl, tErr}, ' Dbl {tObj, tDbl, tDec, tErr, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tDec, tSng, tDbl, tDec, tErr}, ' Dec {tObj, tDat, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tErr, tDat} ' Date },' Obj Str Bool Char SByt Shrt Int Long Byte UShr UInt ULng Sngl Dbl Dec Date { ' Concatenation and Like {tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj, tObj}, ' Obj {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Str {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Bool {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Char {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' SByt {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Shrt {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Int {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Long {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Byte {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' UShr {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' UInt {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' ULng {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Sngl {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Dbl {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr}, ' Date {tObj, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr, tStr} ' Dec } } End Sub End Class Public Shared Function ResolveUserDefinedConversion( source As TypeSymbol, destination As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As KeyValuePair(Of ConversionKind, MethodSymbol) Debug.Assert(Not source.IsErrorType()) Debug.Assert(Not destination.IsErrorType()) Dim result As KeyValuePair(Of ConversionKind, MethodSymbol) = Nothing Dim opSet = ArrayBuilder(Of MethodSymbol).GetInstance() ' 8.11 User-Defined Conversions ' When determining what user-defined conversion to use, the most specific widening conversion will be used; ' if no widening conversion is most specific, the most specific narrowing conversion will be used. If there ' is no most specific narrowing conversion, then the conversion is undefined and a compile-time error occurs. ' When collecting the candidate user-defined conversions for a type T?, the user-defined conversion operators ' defined by T are used instead. If the type being converted to is also a nullable value type, then any of ' T's user-defined conversions operators that involve only non-nullable value types are lifted. A conversion ' operator from T to S is lifted to be a conversion from T? to S? ' ' !!! Dev10 implementation doesn't match the spec here (the behavior is duplicated): ' !!! 1) If there were applicable Widening CType operators applicable according to the ' !!! "Most Specific Widening Conversion" section, Narrowing CType operators are not considered at all. ' !!! Nullable lifting isn't considered too. ' !!! 2) With "Most Specific Narrowing Conversion" behavior is slightly different. If there is a conversion ' !!! operator that converts from the most specific source type to the most specific target type, then ' !!! nullable lifting isn't considered. CollectUserDefinedConversionOperators(source, destination, opSet, useSiteInfo) If opSet.Count = 0 Then opSet.Free() Return result End If Dim conversionKinds = ArrayBuilder(Of KeyValuePair(Of ConversionKind, ConversionKind)).GetInstance() conversionKinds.ZeroInit(opSet.Count) Dim applicable = BitVector.Create(opSet.Count) Dim bestMatch As MethodSymbol = Nothing If DetermineMostSpecificWideningConversion(source, destination, opSet, conversionKinds, applicable, bestMatch, suppressViabilityChecks:=False, useSiteInfo:=useSiteInfo) Then If bestMatch IsNot Nothing Then result = New KeyValuePair(Of ConversionKind, MethodSymbol)(ConversionKind.Widening Or ConversionKind.UserDefined, bestMatch) End If GoTo Done ElseIf opSet.Count = 0 Then GoTo Done End If If DetermineMostSpecificNarrowingConversion(source, destination, opSet, conversionKinds, applicable, bestMatch, suppressViabilityChecks:=False, useSiteInfo:=useSiteInfo) Then If bestMatch IsNot Nothing Then result = New KeyValuePair(Of ConversionKind, MethodSymbol)(ConversionKind.Narrowing Or ConversionKind.UserDefined, bestMatch) End If GoTo Done ElseIf opSet.Count = 0 Then GoTo Done End If ' Try nullable lifting. If source.IsNullableType() AndAlso destination.IsNullableType() Then applicable.Clear() conversionKinds.ZeroInit(opSet.Count) Dim sourceUnderlying As TypeSymbol = source.GetNullableUnderlyingType() Dim destinationUnderlying As TypeSymbol = destination.GetNullableUnderlyingType() If Not (sourceUnderlying.IsErrorType() OrElse destinationUnderlying.IsErrorType()) Then ' All candidates applicable to the underlying types should be applicable to the original types, no reason to ' do viability checks for the second time. If DetermineMostSpecificWideningConversion(sourceUnderlying, destinationUnderlying, opSet, conversionKinds, applicable, bestMatch, suppressViabilityChecks:=True, useSiteInfo:=useSiteInfo) Then If bestMatch IsNot Nothing Then Debug.Assert(Not bestMatch.Parameters(0).Type.IsNullableType()) Debug.Assert(Not bestMatch.ReturnType.IsNullableType()) result = New KeyValuePair(Of ConversionKind, MethodSymbol)(ConversionKind.Widening Or ConversionKind.UserDefined Or ConversionKind.Nullable, bestMatch) End If ElseIf DetermineMostSpecificNarrowingConversion(sourceUnderlying, destinationUnderlying, opSet, conversionKinds, applicable, bestMatch, suppressViabilityChecks:=True, useSiteInfo:=useSiteInfo) Then If bestMatch IsNot Nothing Then Debug.Assert(Not bestMatch.Parameters(0).Type.IsNullableType()) Debug.Assert(Not bestMatch.ReturnType.IsNullableType()) result = New KeyValuePair(Of ConversionKind, MethodSymbol)(ConversionKind.Narrowing Or ConversionKind.UserDefined Or ConversionKind.Nullable, bestMatch) End If End If End If End If Done: conversionKinds.Free() opSet.Free() Return result End Function ''' <summary> ''' Returns True if resolution of user defined conversions is complete, i.e. there were operators ''' applicable for the "Most Specific Widening Conversion" purposes. ''' This, however, doesn't mean that resolution is successful. ''' </summary> Private Shared Function DetermineMostSpecificWideningConversion( source As TypeSymbol, destination As TypeSymbol, opSet As ArrayBuilder(Of MethodSymbol), conversionKinds As ArrayBuilder(Of KeyValuePair(Of ConversionKind, ConversionKind)), <[In]()> ByRef applicable As BitVector, <Out()> ByRef bestMatch As MethodSymbol, suppressViabilityChecks As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean #If DEBUG Then Debug.Assert(bestMatch Is Nothing) For i As Integer = 0 To opSet.Count - 1 Debug.Assert(Not applicable(i)) Next #End If bestMatch = Nothing Dim bestMatchDegreeOfGenericity As Integer = -1 ' (-1) - unknown, 0 - neither type refers to generic type parameters, 1 - one type, 2 - two types Dim bestMatchIsAmbiguous As Boolean = False Dim mostSpecificSourceType As TypeSymbol = Nothing Dim mostSpecificTargetType As TypeSymbol = Nothing Dim applicableCount As Integer = 0 ' 8.11.1 Most Specific Widening Conversion ' - First, all of the candidate conversion operators are collected. The candidate conversion operators are all ' of the user-defined widening conversion operators in the source type and all of the user-defined widening ' conversion operators in the target type. ' - Then, all non-applicable conversion operators are removed from the set. A conversion operator is applicable ' to a source type and target type if there is an intrinsic widening conversion operator from the source type ' to the operand type and there is an intrinsic widening conversion operator from the result of the operator ' to the target type. If there are no applicable conversion operators, then there is no most specific widening ' conversion. ' - Then, the most specific source type of the applicable conversion operators is determined: ' - If any of the conversion operators convert directly from the source type, then the source type is the ' most specific source type. ' - Otherwise, the most specific source type is the most encompassed type in the combined set of source types ' of the conversion operators. If no most encompassed type can be found, then there is no most specific ' widening conversion. ' - Then, the most specific target type of the applicable conversion operators is determined: ' - If any of the conversion operators convert directly to the target type, then the target type is the most ' specific target type. ' - Otherwise, the most specific target type is the most encompassing type in the combined set of target types ' of the conversion operators. If no most encompassing type can be found, then there is no most specific ' widening conversion. ' - Then, if exactly one conversion operator converts from the most specific source type to the most specific target ' type, then this is the most specific conversion operator. If more than one such operator exists, then there is ' no most specific widening conversion. ' 8.11 User-Defined Conversions ' - If an intrinsic widening conversion exists from a type A to a type B, ' and if neither A nor B are interfaces, then A is encompassed by B, and ' B encompasses A. ' - The most encompassing type in a set of types is the one type that encompasses ' all other types in the set. If no single type encompasses all other types, then ' the set has no most encompassing type. In intuitive terms, the most encompassing ' type is the "largest" type in the set—the one type to which each of the other ' types can be converted through a widening conversion. ' - The most encompassed type in a set of types is the one type that is encompassed ' by all other types in the set. If no single type is encompassed by all other types, ' then the set has no most encompassed type. In intuitive terms, the most encompassed ' type is the "smallest" type in the set—the one type that can be converted from each ' of the other types through a narrowing conversion. Dim viableCandidates As Integer = 0 For i As Integer = 0 To opSet.Count - 1 Dim method As MethodSymbol = opSet(i) Dim currentIndex As Integer = viableCandidates viableCandidates += 1 If currentIndex < i Then Debug.Assert(Not suppressViabilityChecks) opSet(currentIndex) = method Else Debug.Assert(currentIndex = i) End If If Not IsWidening(method) Then Continue For End If Dim conversionIn As ConversionKind Dim conversionOut As ConversionKind If ClassifyConversionOperatorInOutConversions(source, destination, method, conversionIn, conversionOut, suppressViabilityChecks, useSiteInfo) Then conversionKinds(currentIndex) = New KeyValuePair(Of ConversionKind, ConversionKind)(conversionIn, conversionOut) Else 'opSet(currentIndex) = Nothing Debug.Assert(Not suppressViabilityChecks) viableCandidates = currentIndex Continue For End If If bestMatch Is Nothing Then If Not (Conversions.IsWideningConversion(conversionIn) AndAlso Conversions.IsWideningConversion(conversionOut)) Then Continue For End If Else If Not (Conversions.IsIdentityConversion(conversionIn) AndAlso Conversions.IsIdentityConversion(conversionOut)) Then Continue For End If ' Potential ambiguity, let's attempt to resolve based on genericity. bestMatch = LeastGenericConversionOperator(bestMatch, method, bestMatchDegreeOfGenericity, bestMatchIsAmbiguous) If bestMatchIsAmbiguous AndAlso bestMatchDegreeOfGenericity = 0 Then ' We will not be able to get rid of this ambiguity. Exit For End If Continue For End If If Conversions.IsIdentityConversion(conversionIn) AndAlso Conversions.IsIdentityConversion(conversionOut) Then Debug.Assert(bestMatch Is Nothing) bestMatch = method applicable.Clear() applicableCount = 0 Else If Conversions.IsIdentityConversion(conversionIn) Then mostSpecificSourceType = source End If If Conversions.IsIdentityConversion(conversionOut) Then mostSpecificTargetType = destination End If applicable(currentIndex) = True applicableCount += 1 End If Next opSet.Clip(viableCandidates) conversionKinds.Clip(viableCandidates) #If DEBUG Then For i As Integer = 0 To opSet.Count - 1 Debug.Assert(opSet(i) IsNot Nothing) Next #End If If bestMatch IsNot Nothing Then If bestMatchIsAmbiguous Then bestMatch = Nothing End If Return True End If If applicableCount > 0 Then Debug.Assert(bestMatch Is Nothing) Debug.Assert(Not bestMatchIsAmbiguous) If applicableCount > 1 Then ' Try to choose most specific among applicable candidates. Dim typeSet As ArrayBuilder(Of TypeSymbol) = Nothing If mostSpecificSourceType Is Nothing Then typeSet = ArrayBuilder(Of TypeSymbol).GetInstance() For i As Integer = 0 To opSet.Count - 1 If Not applicable(i) Then Continue For End If typeSet.Add(opSet(i).Parameters(0).Type) Next Debug.Assert(typeSet.Count = applicableCount) mostSpecificSourceType = MostEncompassed(typeSet, useSiteInfo) End If If mostSpecificTargetType Is Nothing AndAlso mostSpecificSourceType IsNot Nothing Then If typeSet Is Nothing Then typeSet = ArrayBuilder(Of TypeSymbol).GetInstance() Else typeSet.Clear() End If For i As Integer = 0 To opSet.Count - 1 If Not applicable(i) Then Continue For End If typeSet.Add(opSet(i).ReturnType) Next Debug.Assert(typeSet.Count = applicableCount) mostSpecificTargetType = MostEncompassing(typeSet, useSiteInfo) End If If typeSet IsNot Nothing Then typeSet.Free() End If If mostSpecificSourceType IsNot Nothing AndAlso mostSpecificTargetType IsNot Nothing Then bestMatch = ChooseMostSpecificConversionOperator(opSet, applicable, mostSpecificSourceType, mostSpecificTargetType, bestMatchIsAmbiguous) End If If bestMatch IsNot Nothing AndAlso bestMatchIsAmbiguous Then bestMatch = Nothing End If Else For i As Integer = 0 To opSet.Count - 1 If applicable(i) Then bestMatch = opSet(i) Exit For End If Next Debug.Assert(bestMatch IsNot Nothing) End If Return True End If Debug.Assert(bestMatch Is Nothing) Return False End Function Private Shared Function ChooseMostSpecificConversionOperator( opSet As ArrayBuilder(Of MethodSymbol), applicable As BitVector, mostSpecificSourceType As TypeSymbol, mostSpecificTargetType As TypeSymbol, <Out()> ByRef bestMatchIsAmbiguous As Boolean ) As MethodSymbol Dim bestMatchDegreeOfGenericity As Integer = -1 ' (-1) - unknown, 0 - neither type refers to generic type parameters, 1 - one type, 2 - two types Dim bestMatch As MethodSymbol = Nothing bestMatchIsAmbiguous = False For i As Integer = 0 To opSet.Count - 1 If Not applicable(i) Then Continue For End If Dim method As MethodSymbol = opSet(i) If Not (mostSpecificSourceType.IsSameTypeIgnoringAll(method.Parameters(0).Type) AndAlso mostSpecificTargetType.IsSameTypeIgnoringAll(method.ReturnType)) Then Continue For End If If bestMatch Is Nothing Then bestMatch = method Else ' Potential ambiguity, let's attempt to resolve based on genericity. bestMatch = LeastGenericConversionOperator(bestMatch, method, bestMatchDegreeOfGenericity, bestMatchIsAmbiguous) If bestMatchIsAmbiguous AndAlso bestMatchDegreeOfGenericity = 0 Then ' We will not be able to get rid of this ambiguity. Exit For End If End If Next Return bestMatch End Function ''' <summary> ''' Returns false if operator should be ignored. ''' </summary> Private Shared Function ClassifyConversionOperatorInOutConversions( source As TypeSymbol, destination As TypeSymbol, method As MethodSymbol, <Out()> ByRef conversionIn As ConversionKind, <Out()> ByRef conversionOut As ConversionKind, suppressViabilityChecks As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean Dim inputType As TypeSymbol = method.Parameters(0).Type Dim outputType As TypeSymbol = method.ReturnType If Not suppressViabilityChecks Then If Not IsConversionOperatorViableBasedOnTypesInvolved(method, inputType, outputType, useSiteInfo) Then conversionIn = Nothing conversionOut = Nothing Return False End If Else Debug.Assert(IsConversionOperatorViableBasedOnTypesInvolved(method, inputType, outputType, CompoundUseSiteInfo(Of AssemblySymbol).Discarded)) End If ' If source is an array literal then use ClassifyArrayLiteralConversion Dim arrayLiteralType = TryCast(source, ArrayLiteralTypeSymbol) If arrayLiteralType IsNot Nothing Then Dim arrayLiteral = arrayLiteralType.ArrayLiteral conversionIn = Conversions.ClassifyArrayLiteralConversion(arrayLiteral, inputType, arrayLiteral.Binder, useSiteInfo) If Conversions.IsWideningConversion(conversionIn) AndAlso IsSameTypeIgnoringAll(arrayLiteralType, inputType) Then conversionIn = ConversionKind.Identity End If Else conversionIn = Conversions.ClassifyPredefinedConversion(source, inputType, useSiteInfo) End If conversionOut = Conversions.ClassifyPredefinedConversion(outputType, destination, useSiteInfo) Return True End Function Private Shared Function IsConversionOperatorViableBasedOnTypesInvolved( method As MethodSymbol, inputType As TypeSymbol, outputType As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean If inputType.IsErrorType() OrElse outputType.IsErrorType() Then Return False End If ' Ignore user defined conversions between types that already have intrinsic conversions. ' This could happen for generics after generic param substitution. If Not method.ContainingType.IsDefinition Then Dim localUseSiteInfo = If(useSiteInfo.AccumulatesDependencies, New CompoundUseSiteInfo(Of AssemblySymbol)(useSiteInfo.AssemblyBeingBuilt), CompoundUseSiteInfo(Of AssemblySymbol).DiscardedDependencies) If Conversions.ConversionExists(Conversions.ClassifyPredefinedConversion(inputType, outputType, localUseSiteInfo)) OrElse Not localUseSiteInfo.Diagnostics.IsNullOrEmpty Then useSiteInfo.MergeAndClear(localUseSiteInfo) Return False End If useSiteInfo.MergeAndClear(localUseSiteInfo) End If Return True End Function ''' <summary> ''' Returns True if resolution of user defined conversions is complete, i.e. there was an operator ''' that converts from the most specific source type to the most specific target type. ''' This, however, doesn't mean that resolution is successful. ''' </summary> Private Shared Function DetermineMostSpecificNarrowingConversion( source As TypeSymbol, destination As TypeSymbol, opSet As ArrayBuilder(Of MethodSymbol), conversionKinds As ArrayBuilder(Of KeyValuePair(Of ConversionKind, ConversionKind)), <[In]()> ByRef applicable As BitVector, <Out()> ByRef bestMatch As MethodSymbol, suppressViabilityChecks As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As Boolean #If DEBUG Then Debug.Assert(bestMatch Is Nothing) For i As Integer = 0 To opSet.Count - 1 Debug.Assert(Not applicable(i)) Next #End If bestMatch = Nothing Dim bestMatchDegreeOfGenericity As Integer = -1 ' (-1) - unknown, 0 - neither type refers to generic type parameters, 1 - one type, 2 - two types Dim bestMatchIsAmbiguous As Boolean = False Dim mostSpecificSourceType As TypeSymbol = Nothing Dim mostSpecificTargetType As TypeSymbol = Nothing Dim applicableCount As Integer = 0 ' 8.11.2 Most Specific Narrowing Conversion ' Determining the most specific user-defined narrowing conversion operator between two types is accomplished using the following steps: ' - First, all of the candidate conversion operators are collected. The candidate conversion operators are all ' of the user-defined conversion operators in the source type and all of the user-defined conversion operators ' in the target type. ' - Then, all non-applicable conversion operators are removed from the set. A conversion operator is applicable ' to a source type and target type if there is an intrinsic conversion operator from the source type to the ' operand type and there is an intrinsic conversion operator from the result of the operator to the target type. ' If there are no applicable conversion operators, then there is no most specific narrowing conversion. ' - Then, the most specific source type of the applicable conversion operators is determined: ' - If any of the conversion operators convert directly from the source type, then the source type is ' the most specific source type. ' - Otherwise, if any of the conversion operators convert from types that encompass the source type, ' then the most specific source type is the most encompassed type in the combined set of source types ' of those conversion operators. If no most encompassed type can be found, then there is no most ' specific narrowing conversion. ' - Otherwise, the most specific source type is the most encompassing type in the combined set of source ' types of the conversion operators. If no most encompassing type can be found, then there is no most ' specific narrowing conversion. ' - Then, the most specific target type of the applicable conversion operators is determined: ' - If any of the conversion operators convert directly to the target type, then the target type is ' the most specific target type. ' - Otherwise, if any of the conversion operators convert to types that are encompassed by the target type, ' then the most specific target type is the most encompassing type in the combined set of source types of ' those conversion operators. If no most encompassing type can be found, then there is no most specific ' narrowing conversion. ' - Otherwise, the most specific target type is the most encompassed type in the combined set of target ' types of the conversion operators. If no most encompassed type can be found, then there is no most ' specific narrowing conversion. ' - Then, if exactly one conversion operator converts from the most specific source type to the most specific ' target type, then this is the most specific conversion operator. If more than one such operator exists, ' then there is no most specific narrowing conversion. ' 8.11 User-Defined Conversions ' - If an intrinsic widening conversion exists from a type A to a type B, ' and if neither A nor B are interfaces, then A is encompassed by B, and ' B encompasses A. ' - The most encompassing type in a set of types is the one type that encompasses ' all other types in the set. If no single type encompasses all other types, then ' the set has no most encompassing type. In intuitive terms, the most encompassing ' type is the "largest" type in the set—the one type to which each of the other ' types can be converted through a widening conversion. ' - The most encompassed type in a set of types is the one type that is encompassed ' by all other types in the set. If no single type is encompassed by all other types, ' then the set has no most encompassed type. In intuitive terms, the most encompassed ' type is the "smallest" type in the set—the one type that can be converted from each ' of the other types through a narrowing conversion. Dim haveWideningInConversions As Integer = 0 Dim haveWideningOutConversions As Integer = 0 Dim viableCandidates As Integer = 0 For i As Integer = 0 To opSet.Count - 1 Dim method As MethodSymbol = opSet(i) Dim currentIndex As Integer = viableCandidates viableCandidates += 1 If currentIndex < i Then Debug.Assert(Not suppressViabilityChecks) opSet(currentIndex) = method conversionKinds(currentIndex) = conversionKinds(i) Else Debug.Assert(currentIndex = i) End If Dim conversionIn As ConversionKind Dim conversionOut As ConversionKind If IsWidening(method) Then ' When we reach this point, a widening operator is either removed from the opSet (because it was "bad" in one way or another) ' or it was not applicable for the purpose of the "Most Specific Widening Conversion", but conversion information should have been ' captured in conversionKinds for it. Dim conversion As KeyValuePair(Of ConversionKind, ConversionKind) = conversionKinds(currentIndex) conversionIn = conversion.Key conversionOut = conversion.Value ' If the operator would be an acceptable candidate for the "Most Specific Widening Conversion", we shouldn't have ' reached this place. Debug.Assert(Not (Conversions.IsWideningConversion(conversionIn) AndAlso Conversions.IsWideningConversion(conversionOut))) ElseIf ClassifyConversionOperatorInOutConversions(source, destination, method, conversionIn, conversionOut, suppressViabilityChecks, useSiteInfo) Then conversionKinds(currentIndex) = New KeyValuePair(Of ConversionKind, ConversionKind)(conversionIn, conversionOut) Else 'opSet(currentIndex) = Nothing Debug.Assert(Not suppressViabilityChecks) viableCandidates = currentIndex Continue For End If If bestMatch Is Nothing Then If Not (Conversions.ConversionExists(conversionIn) AndAlso Conversions.ConversionExists(conversionOut)) Then Continue For End If Else If Not (Conversions.IsIdentityConversion(conversionIn) AndAlso Conversions.IsIdentityConversion(conversionOut)) Then Continue For End If ' Potential ambiguity, let's attempt to resolve based on genericity. bestMatch = LeastGenericConversionOperator(bestMatch, method, bestMatchDegreeOfGenericity, bestMatchIsAmbiguous) If bestMatchIsAmbiguous AndAlso bestMatchDegreeOfGenericity = 0 Then ' We will not be able to get rid of this ambiguity. Exit For End If Continue For End If If Conversions.IsIdentityConversion(conversionIn) AndAlso Conversions.IsIdentityConversion(conversionOut) Then Debug.Assert(bestMatch Is Nothing) bestMatch = method applicable.Clear() applicableCount = 0 Else If Conversions.IsWideningConversion(conversionIn) Then If Conversions.IsIdentityConversion(conversionIn) Then mostSpecificSourceType = source Else haveWideningInConversions += 1 End If If Conversions.IsWideningConversion(conversionOut) Then If Conversions.IsIdentityConversion(conversionOut) Then mostSpecificTargetType = destination Else haveWideningOutConversions += 1 End If Else Debug.Assert(Conversions.IsNarrowingConversion(conversionOut)) End If Else Debug.Assert(Conversions.IsNarrowingConversion(conversionIn)) If Conversions.IsIdentityConversion(conversionOut) Then mostSpecificTargetType = destination ElseIf Not Conversions.IsNarrowingConversion(conversionOut) Then Debug.Assert(Conversions.IsWideningConversion(conversionOut) AndAlso Not Conversions.IsIdentityConversion(conversionOut)) ' Note that {Narrowing in, Widening (non-identity) out} operator is not considered as an applicable candidate. ' In fact, an operator like this cannot exist unless nullable in/out conversions are involved. ' Basically we would be dealing with an operator that converts from type derived from source to type derived from destination, ' it would have to be defined in one of those types. When we collect operators we only visit source, destination and their ' bases. So, in order for such an operator to be found, there must be an inheritance relationship between source and ' destination and the operator must be defined in a type that is in between of them in the inheritance hierarchy. Thus, ' there would be an inheritance relationship between parameter type ant return type of the operator, which makes the operator ' inapplicable - there would be a predefined conversion between the types. ' Ignoring an operator like this even when nullable conversions are involved, allows us to consider it as a candidate for a ' lifting, otherwise it would be treated as a not-lifted narrowing. Continue For Else Debug.Assert(Conversions.IsNarrowingConversion(conversionOut)) ' When intrinsic types are involved, conversion from intrinsic type T to Nullable(Of S) can be narrowing, ' it is always widening (if exists) for user-defined types. For reasons described above, we might need to ignore ' an operator like this. If source.IsNullableType() AndAlso destination.IsNullableType() AndAlso method.ReturnType.IsIntrinsicType() Then Continue For End If End If End If applicable(currentIndex) = True applicableCount += 1 End If Next opSet.Clip(viableCandidates) conversionKinds.Clip(viableCandidates) #If DEBUG Then For i As Integer = 0 To opSet.Count - 1 Debug.Assert(opSet(i) IsNot Nothing) Next #End If If bestMatch IsNot Nothing Then If bestMatchIsAmbiguous Then bestMatch = Nothing End If Return True End If If applicableCount > 0 Then Debug.Assert(bestMatch Is Nothing) Debug.Assert(Not bestMatchIsAmbiguous) If applicableCount > 1 Then ' Try to choose most specific among applicable candidates. Dim typeSet As ArrayBuilder(Of TypeSymbol) = Nothing If mostSpecificSourceType Is Nothing Then typeSet = ArrayBuilder(Of TypeSymbol).GetInstance() For i As Integer = 0 To opSet.Count - 1 If Not applicable(i) Then Continue For End If If haveWideningInConversions <> 0 Then If Not Conversions.IsWideningConversion(conversionKinds(i).Key) Then Continue For End If Else Debug.Assert(Conversions.IsNarrowingConversion(conversionKinds(i).Key)) End If typeSet.Add(opSet(i).Parameters(0).Type) Next Debug.Assert(typeSet.Count = applicableCount OrElse (haveWideningInConversions <> 0 AndAlso typeSet.Count = haveWideningInConversions)) If haveWideningInConversions <> 0 Then mostSpecificSourceType = MostEncompassed(typeSet, useSiteInfo) Else mostSpecificSourceType = MostEncompassing(typeSet, useSiteInfo) End If End If If mostSpecificTargetType Is Nothing AndAlso mostSpecificSourceType IsNot Nothing Then If typeSet Is Nothing Then typeSet = ArrayBuilder(Of TypeSymbol).GetInstance() Else typeSet.Clear() End If For i As Integer = 0 To opSet.Count - 1 If Not applicable(i) Then Continue For End If If haveWideningOutConversions <> 0 Then If Not Conversions.IsWideningConversion(conversionKinds(i).Value) Then Continue For End If Else Debug.Assert(Conversions.IsNarrowingConversion(conversionKinds(i).Value)) End If typeSet.Add(opSet(i).ReturnType) Next Debug.Assert(typeSet.Count = applicableCount OrElse (haveWideningOutConversions <> 0 AndAlso typeSet.Count = haveWideningOutConversions)) If haveWideningOutConversions <> 0 Then mostSpecificTargetType = MostEncompassing(typeSet, useSiteInfo) Else mostSpecificTargetType = MostEncompassed(typeSet, useSiteInfo) End If End If If typeSet IsNot Nothing Then typeSet.Free() End If If mostSpecificSourceType IsNot Nothing AndAlso mostSpecificTargetType IsNot Nothing Then bestMatch = ChooseMostSpecificConversionOperator(opSet, applicable, mostSpecificSourceType, mostSpecificTargetType, bestMatchIsAmbiguous) End If If bestMatch IsNot Nothing AndAlso bestMatchIsAmbiguous Then bestMatch = Nothing Return True End If Else For i As Integer = 0 To opSet.Count - 1 If applicable(i) Then bestMatch = opSet(i) Exit For End If Next Debug.Assert(bestMatch IsNot Nothing) End If End If Return bestMatch IsNot Nothing End Function ''' <summary> ''' The most encompassed type in a set of types is the one type that is encompassed ''' by all other types in the set. If no single type is encompassed by all other types, ''' then the set has no most encompassed type. In intuitive terms, the most encompassed ''' type is the "smallest" type in the set—the one type that can be converted from each ''' of the other types through a narrowing conversion. ''' </summary> Private Shared Function MostEncompassed(typeSet As ArrayBuilder(Of TypeSymbol), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As TypeSymbol Dim best As TypeSymbol = Nothing For i As Integer = 0 To typeSet.Count - 1 Dim type As TypeSymbol = typeSet(i) If best IsNot Nothing AndAlso best.IsSameTypeIgnoringAll(type) Then Continue For End If Debug.Assert(Not type.IsErrorType()) For j As Integer = 0 To typeSet.Count - 1 If i = j Then Continue For End If Dim conv As ConversionKind = Conversions.ClassifyPredefinedConversion(type, typeSet(j), useSiteInfo) If Not Conversions.IsWideningConversion(conv) Then ' type is not encompassed by the other type GoTo Next_i End If Next If best Is Nothing Then best = type Else Debug.Assert(Not best.IsSameTypeIgnoringAll(type)) best = Nothing ' More than one type Exit For End If Next_i: Next Return best End Function ''' <summary> ''' The most encompassing type in a set of types is the one type that encompasses ''' all other types in the set. If no single type encompasses all other types, then ''' the set has no most encompassing type. In intuitive terms, the most encompassing ''' type is the "largest" type in the set—the one type to which each of the other ''' types can be converted through a widening conversion. ''' </summary> Private Shared Function MostEncompassing(typeSet As ArrayBuilder(Of TypeSymbol), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As TypeSymbol Dim best As TypeSymbol = Nothing For i As Integer = 0 To typeSet.Count - 1 Dim type As TypeSymbol = typeSet(i) If best IsNot Nothing AndAlso best.IsSameTypeIgnoringAll(type) Then Continue For End If Debug.Assert(Not type.IsErrorType()) For j As Integer = 0 To typeSet.Count - 1 If i = j Then Continue For End If Dim conv As ConversionKind = Conversions.ClassifyPredefinedConversion(typeSet(j), type, useSiteInfo) If Not Conversions.IsWideningConversion(conv) Then ' type is not encompassing the other type GoTo Next_i End If Next If best Is Nothing Then best = type Else Debug.Assert(Not best.IsSameTypeIgnoringAll(type)) best = Nothing ' More than one type Exit For End If Next_i: Next Return best End Function Private Shared Function LeastGenericConversionOperator( method1 As MethodSymbol, method2 As MethodSymbol, <[In], Out()> ByRef bestDegreeOfGenericity As Integer, <[In], Out()> ByRef isAmbiguous As Boolean ) As MethodSymbol If bestDegreeOfGenericity = -1 Then bestDegreeOfGenericity = DetermineConversionOperatorDegreeOfGenericity(method1) End If Dim method2DegreeOfGenericity As Integer = DetermineConversionOperatorDegreeOfGenericity(method2) ' The less degree of genericity, the better. If bestDegreeOfGenericity < method2DegreeOfGenericity Then ' isAmbiguous state doesn't change. Return method1 ElseIf method2DegreeOfGenericity < bestDegreeOfGenericity Then isAmbiguous = False bestDegreeOfGenericity = method2DegreeOfGenericity Return method2 End If isAmbiguous = True Return method1 End Function ''' <summary> ''' Returns number of types in the list of {input type, output type} that refer to a generic type parameter. ''' </summary> Private Shared Function DetermineConversionOperatorDegreeOfGenericity(method As MethodSymbol) As Integer If Not method.ContainingType.IsGenericType Then Return 0 End If Dim result As Integer = 0 Dim definition As MethodSymbol = method.OriginalDefinition If DetectReferencesToGenericParameters(definition.Parameters(0).Type, TypeParameterKind.Type, BitVector.Null) <> TypeParameterKind.None Then result += 1 End If If DetectReferencesToGenericParameters(definition.ReturnType, TypeParameterKind.Type, BitVector.Null) <> TypeParameterKind.None Then result += 1 End If Debug.Assert(result > 0) Return result End Function ''' <summary> ''' A quick check whether given conversion operator is a widening operator. ''' </summary> Friend Shared Function IsWidening(method As MethodSymbol) As Boolean Debug.Assert(method.MethodKind = MethodKind.Conversion) Dim forth As Char = method.Name(3) If forth = "I"c OrElse forth = "i"c Then Return True End If Debug.Assert(forth = "E"c OrElse forth = "e"c) Return False End Function ''' <summary> ''' Collect user-defined conversion operators. ''' Operators declared in the same type are grouped together. ''' Within a group, widening operators are followed by narrowing operators. ''' </summary> Private Shared Sub CollectUserDefinedConversionOperators( source As TypeSymbol, destination As TypeSymbol, opSet As ArrayBuilder(Of MethodSymbol), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) CollectUserDefinedOperators(source, destination, MethodKind.Conversion, WellKnownMemberNames.ImplicitConversionName, New OperatorInfo(UnaryOperatorKind.Implicit), WellKnownMemberNames.ExplicitConversionName, New OperatorInfo(UnaryOperatorKind.Explicit), opSet, useSiteInfo) End Sub ''' <summary> ''' Collect user-defined operators. ''' Operators declared in the same type are grouped together. ''' Within a group, name1 operators are followed by name2 operators. ''' </summary> Friend Shared Sub CollectUserDefinedOperators( type1 As TypeSymbol, type2 As TypeSymbol, opKind As MethodKind, name1 As String, name1Info As OperatorInfo, name2Opt As String, name2InfoOpt As OperatorInfo, opSet As ArrayBuilder(Of MethodSymbol), <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) type1 = GetTypeToLookForOperatorsIn(type1, useSiteInfo) If type2 IsNot Nothing Then type2 = GetTypeToLookForOperatorsIn(type2, useSiteInfo) End If Dim commonAncestor As NamedTypeSymbol = Nothing If type1 IsNot Nothing AndAlso type1.Kind = SymbolKind.NamedType AndAlso Not type1.IsInterfaceType() Then Dim current = DirectCast(type1, NamedTypeSymbol) Do If type2 IsNot Nothing AndAlso commonAncestor Is Nothing AndAlso type2.IsOrDerivedFrom(current, useSiteInfo) Then commonAncestor = current End If ' Note, intentionally using non-short-circuiting Or operator. If CollectUserDefinedOperators(current, name1, opKind, name1Info, opSet) Or (name2Opt IsNot Nothing AndAlso CollectUserDefinedOperators(current, name2Opt, opKind, name2InfoOpt, opSet)) Then Exit Do End If current = current.BaseTypeWithDefinitionUseSiteDiagnostics(useSiteInfo) Loop While current IsNot Nothing End If If type2 IsNot Nothing AndAlso type2.Kind = SymbolKind.NamedType AndAlso Not type2.IsInterfaceType() Then Dim current = DirectCast(type2, NamedTypeSymbol) Do If commonAncestor IsNot Nothing AndAlso commonAncestor.IsSameTypeIgnoringAll(current) Then Exit Do End If ' Note, intentionally using non-short-circuiting Or operator. If CollectUserDefinedOperators(current, name1, opKind, name1Info, opSet) Or (name2Opt IsNot Nothing AndAlso CollectUserDefinedOperators(current, name2Opt, opKind, name2InfoOpt, opSet)) Then Exit Do End If current = current.BaseTypeWithDefinitionUseSiteDiagnostics(useSiteInfo) Loop While current IsNot Nothing End If End Sub ''' <summary> ''' Returns True if we should stop climbing inheritance hierarchy. ''' </summary> Private Shared Function CollectUserDefinedOperators( type As TypeSymbol, opName As String, opKind As MethodKind, opInfo As OperatorInfo, opSet As ArrayBuilder(Of MethodSymbol) ) As Boolean Dim stopClimbing As Boolean = False For Each member In type.GetMembers(opName) If member.Kind = SymbolKind.Method Then Dim method = DirectCast(member, MethodSymbol) If method.MethodKind = opKind Then If method.IsShadows Then stopClimbing = True End If ' Operators that were declared in syntax may not satisfy all the constraints on user-defined operators - ' they require extra validation. If Not method.IsMethodKindBasedOnSyntax OrElse ValidateOverloadedOperator(method.OriginalDefinition, opInfo) Then opSet.Add(method) End If End If End If Next Return stopClimbing End Function ''' <summary> ''' Given the type of operator's argument, return corresponding type to ''' look for operator in. Can return Nothing. ''' </summary> Private Shared Function GetTypeToLookForOperatorsIn(type As TypeSymbol, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As TypeSymbol type = type.GetNullableUnderlyingTypeOrSelf() If type.Kind = SymbolKind.TypeParameter Then type = DirectCast(type, TypeParameterSymbol).GetNonInterfaceConstraint(useSiteInfo) End If Return type End Function Public Shared Function ResolveIsTrueOperator(argument As BoundExpression, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As OverloadResolutionResult Dim opSet = ArrayBuilder(Of MethodSymbol).GetInstance() CollectUserDefinedOperators(argument.Type, Nothing, MethodKind.UserDefinedOperator, WellKnownMemberNames.TrueOperatorName, New OperatorInfo(UnaryOperatorKind.IsTrue), Nothing, Nothing, opSet, useSiteInfo) Dim result = OperatorInvocationOverloadResolution(opSet, argument, Nothing, binder, lateBindingIsAllowed:=False, includeEliminatedCandidates:=False, useSiteInfo:=useSiteInfo) opSet.Free() Return result End Function Public Shared Function ResolveIsFalseOperator(argument As BoundExpression, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol)) As OverloadResolutionResult Dim opSet = ArrayBuilder(Of MethodSymbol).GetInstance() CollectUserDefinedOperators(argument.Type, Nothing, MethodKind.UserDefinedOperator, WellKnownMemberNames.FalseOperatorName, New OperatorInfo(UnaryOperatorKind.IsFalse), Nothing, Nothing, opSet, useSiteInfo) Dim result = OperatorInvocationOverloadResolution(opSet, argument, Nothing, binder, lateBindingIsAllowed:=False, includeEliminatedCandidates:=False, useSiteInfo:=useSiteInfo) opSet.Free() Return result End Function Public Shared Function ResolveUserDefinedUnaryOperator( argument As BoundExpression, opKind As UnaryOperatorKind, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional includeEliminatedCandidates As Boolean = False ) As OverloadResolutionResult Dim opSet = ArrayBuilder(Of MethodSymbol).GetInstance() Select Case opKind Case UnaryOperatorKind.Not Dim opInfo As New OperatorInfo(UnaryOperatorKind.Not) CollectUserDefinedOperators(argument.Type, Nothing, MethodKind.UserDefinedOperator, WellKnownMemberNames.OnesComplementOperatorName, opInfo, WellKnownMemberNames.LogicalNotOperatorName, opInfo, opSet, useSiteInfo) Case UnaryOperatorKind.Minus CollectUserDefinedOperators(argument.Type, Nothing, MethodKind.UserDefinedOperator, WellKnownMemberNames.UnaryNegationOperatorName, New OperatorInfo(UnaryOperatorKind.Minus), Nothing, Nothing, opSet, useSiteInfo) Case UnaryOperatorKind.Plus CollectUserDefinedOperators(argument.Type, Nothing, MethodKind.UserDefinedOperator, WellKnownMemberNames.UnaryPlusOperatorName, New OperatorInfo(UnaryOperatorKind.Minus), Nothing, Nothing, opSet, useSiteInfo) Case Else Throw ExceptionUtilities.UnexpectedValue(opKind) End Select Dim result = OperatorInvocationOverloadResolution(opSet, argument, Nothing, binder, lateBindingIsAllowed:=False, includeEliminatedCandidates:=includeEliminatedCandidates, useSiteInfo:=useSiteInfo) opSet.Free() Return result End Function Public Shared Function ResolveUserDefinedBinaryOperator( left As BoundExpression, right As BoundExpression, opKind As BinaryOperatorKind, binder As Binder, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol), Optional includeEliminatedCandidates As Boolean = False ) As OverloadResolutionResult Dim opSet = ArrayBuilder(Of MethodSymbol).GetInstance() Select Case opKind Case BinaryOperatorKind.Add CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.AdditionOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Subtract CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.SubtractionOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Multiply CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.MultiplyOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Divide CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.DivisionOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.IntegerDivide CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.IntegerDivisionOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Modulo CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.ModulusOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Power CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.ExponentOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Equals CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.EqualityOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.NotEquals CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.InequalityOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.LessThan CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.LessThanOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.GreaterThan CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.GreaterThanOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.LessThanOrEqual CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.LessThanOrEqualOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.GreaterThanOrEqual CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.GreaterThanOrEqualOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Like CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.LikeOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.Concatenate CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.ConcatenateOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.And, BinaryOperatorKind.AndAlso Dim opInfo As New OperatorInfo(opKind) CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.BitwiseAndOperatorName, opInfo, WellKnownMemberNames.LogicalAndOperatorName, opInfo, opSet, useSiteInfo) Case BinaryOperatorKind.Or, BinaryOperatorKind.OrElse Dim opInfo As New OperatorInfo(opKind) CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.BitwiseOrOperatorName, opInfo, WellKnownMemberNames.LogicalOrOperatorName, opInfo, opSet, useSiteInfo) Case BinaryOperatorKind.Xor CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.ExclusiveOrOperatorName, New OperatorInfo(opKind), Nothing, Nothing, opSet, useSiteInfo) Case BinaryOperatorKind.LeftShift Dim opInfo As New OperatorInfo(opKind) CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.LeftShiftOperatorName, opInfo, WellKnownMemberNames.UnsignedLeftShiftOperatorName, opInfo, opSet, useSiteInfo) Case BinaryOperatorKind.RightShift Dim opInfo As New OperatorInfo(opKind) CollectUserDefinedOperators(left.Type, right.Type, MethodKind.UserDefinedOperator, WellKnownMemberNames.RightShiftOperatorName, opInfo, WellKnownMemberNames.UnsignedRightShiftOperatorName, opInfo, opSet, useSiteInfo) Case Else Throw ExceptionUtilities.UnexpectedValue(opKind) End Select Dim result = OperatorInvocationOverloadResolution(opSet, left, right, binder, lateBindingIsAllowed:=True, includeEliminatedCandidates:=includeEliminatedCandidates, useSiteInfo:=useSiteInfo) opSet.Free() Return result End Function Private Shared Function OperatorInvocationOverloadResolution( opSet As ArrayBuilder(Of MethodSymbol), argument1 As BoundExpression, argument2 As BoundExpression, binder As Binder, lateBindingIsAllowed As Boolean, includeEliminatedCandidates As Boolean, <[In], Out> ByRef useSiteInfo As CompoundUseSiteInfo(Of AssemblySymbol) ) As OverloadResolutionResult If opSet.Count = 0 Then If lateBindingIsAllowed Then Return New OverloadResolutionResult(ImmutableArray(Of CandidateAnalysisResult).Empty, argument1.Type.IsObjectType OrElse argument2.Type.IsObjectType, False, asyncLambdaSubToFunctionMismatch:=Nothing) Else Return New OverloadResolutionResult(ImmutableArray(Of CandidateAnalysisResult).Empty, False, False, asyncLambdaSubToFunctionMismatch:=Nothing) End If End If Dim nullableOfT As NamedTypeSymbol = opSet(0).ContainingAssembly.GetSpecialType(SpecialType.System_Nullable_T) Dim liftOperators As Boolean = nullableOfT.GetUseSiteInfo().DiagnosticInfo Is Nothing Dim candidates = ArrayBuilder(Of CandidateAnalysisResult).GetInstance() Dim someCandidatesHaveOverloadResolutionPriority As Boolean = InternalSyntax.Parser.CheckFeatureAvailability(binder.Compilation.LanguageVersion, InternalSyntax.Feature.OverloadResolutionPriority) AndAlso opSet.Any(Function(candidate) candidate.OverloadResolutionPriority <> 0) For Each method In opSet Debug.Assert(method.ParameterCount = If(argument2 Is Nothing, 1, 2)) Debug.Assert(method.Arity = 0) Debug.Assert(Not method.IsSub) If method.HasUnsupportedMetadata Then If includeEliminatedCandidates Then candidates.Add(New CandidateAnalysisResult(New OperatorCandidate(method), CandidateAnalysisResultState.HasUnsupportedMetadata)) End If Continue For End If Dim methodUseSiteInfo As UseSiteInfo(Of AssemblySymbol) = method.GetUseSiteInfo() useSiteInfo.Add(methodUseSiteInfo) If methodUseSiteInfo.DiagnosticInfo IsNot Nothing Then If includeEliminatedCandidates Then candidates.Add(New CandidateAnalysisResult(New OperatorCandidate(method), CandidateAnalysisResultState.HasUseSiteError)) End If Continue For End If CombineCandidates(candidates, New CandidateAnalysisResult(New OperatorCandidate(method)), method.ParameterCount, argumentNames:=Nothing, someCandidatesHaveOverloadResolutionPriority, useSiteInfo) If liftOperators Then Dim param1 As ParameterSymbol = method.Parameters(0) Dim type1 As TypeSymbol = param1.Type Dim isNullable1 As Boolean = type1.IsNullableType() Dim canLift1 As Boolean = Not isNullable1 AndAlso type1.IsValueType() AndAlso Not type1.IsRestrictedType() Dim param2 As ParameterSymbol = Nothing Dim type2 As TypeSymbol = Nothing Dim isNullable2 As Boolean = False Dim canLift2 As Boolean = False If argument2 IsNot Nothing AndAlso Not isNullable1 Then param2 = method.Parameters(1) type2 = param2.Type isNullable2 = type2.IsNullableType() canLift2 = Not isNullable2 AndAlso type2.IsValueType() AndAlso Not type2.IsRestrictedType() End If If (canLift1 OrElse canLift2) AndAlso Not isNullable1 AndAlso Not isNullable2 Then ' Should lift this operator. If canLift1 Then param1 = LiftParameterSymbol(param1, nullableOfT) End If If canLift2 Then param2 = LiftParameterSymbol(param2, nullableOfT) End If Dim returnType As TypeSymbol = method.ReturnType If CanLiftType(returnType) Then returnType = nullableOfT.Construct(returnType) End If CombineCandidates(candidates, New CandidateAnalysisResult(New LiftedOperatorCandidate(method, If(argument2 Is Nothing, ImmutableArray.Create(param1), ImmutableArray.Create(Of ParameterSymbol)(param1, param2)), returnType)), method.ParameterCount, argumentNames:=Nothing, someCandidatesHaveOverloadResolutionPriority, useSiteInfo) End If End If Next ' TODO: Need to get rid of dependency on method group. For now create fake one. Dim methodGroup = New BoundMethodGroup(argument1.Syntax, Nothing, ImmutableArray(Of MethodSymbol).Empty, LookupResultKind.Good, Nothing, QualificationKind.Unqualified) Dim result As OverloadResolutionResult = ResolveOverloading(methodGroup, candidates, If(argument2 Is Nothing, ImmutableArray.Create(argument1), ImmutableArray.Create(Of BoundExpression)(argument1, argument2)), argumentNames:=Nothing, someCandidatesHaveOverloadResolutionPriority, delegateReturnType:=Nothing, lateBindingIsAllowed, binder:=binder, asyncLambdaSubToFunctionMismatch:=Nothing, callerInfoOpt:=Nothing, forceExpandedForm:=False, useSiteInfo:=useSiteInfo) candidates.Free() Return result End Function Friend Shared Function CanLiftType(type As TypeSymbol) As Boolean Return Not type.IsNullableType AndAlso type.IsValueType() AndAlso Not type.IsRestrictedType() End Function Friend Shared Function IsValidInLiftedSignature(type As TypeSymbol) As Boolean Return type.IsNullableType() ' Note, Dev11 has changed implementation of this function, I've taken this into account. End Function Private Shared Function LiftParameterSymbol(param As ParameterSymbol, nullableOfT As NamedTypeSymbol) As ParameterSymbol If param.IsDefinition Then Return New LiftedParameterSymbol(param, nullableOfT.Construct(param.Type)) Else Dim definition As ParameterSymbol = param.OriginalDefinition Return SubstitutedParameterSymbol.CreateMethodParameter(DirectCast(param.ContainingSymbol, SubstitutedMethodSymbol), New LiftedParameterSymbol(definition, nullableOfT.Construct(definition.Type))) End If End Function Private NotInheritable Class LiftedParameterSymbol Inherits ParameterSymbol Private ReadOnly _parameterToLift As ParameterSymbol Private ReadOnly _type As TypeSymbol Public Sub New(parameter As ParameterSymbol, type As TypeSymbol) Debug.Assert(parameter.IsDefinition) Debug.Assert(type.IsNullableType()) _parameterToLift = parameter _type = type End Sub Public Overrides ReadOnly Property Name As String Get Return _parameterToLift.Name End Get End Property Friend Overrides Function GetUseSiteInfo() As UseSiteInfo(Of AssemblySymbol) Return _parameterToLift.GetUseSiteInfo() End Function Public Overrides ReadOnly Property ContainingSymbol As Symbol Get Return _parameterToLift.ContainingSymbol End Get End Property Public Overrides ReadOnly Property CustomModifiers As ImmutableArray(Of CustomModifier) Get Return _parameterToLift.CustomModifiers End Get End Property Public Overrides ReadOnly Property RefCustomModifiers As ImmutableArray(Of CustomModifier) Get Return _parameterToLift.RefCustomModifiers End Get End Property Public Overrides ReadOnly Property DeclaringSyntaxReferences As ImmutableArray(Of SyntaxReference) Get Return ImmutableArray(Of SyntaxReference).Empty End Get End Property Friend Overrides ReadOnly Property ExplicitDefaultConstantValue(inProgress As SymbolsInProgress(Of ParameterSymbol)) As ConstantValue Get Return _parameterToLift.ExplicitDefaultConstantValue(inProgress) End Get End Property Public Overrides ReadOnly Property HasExplicitDefaultValue As Boolean Get Return _parameterToLift.HasExplicitDefaultValue End Get End Property Public Overrides ReadOnly Property IsByRef As Boolean Get Return _parameterToLift.IsByRef End Get End Property Friend Overrides ReadOnly Property IsExplicitByRef As Boolean Get Return _parameterToLift.IsExplicitByRef End Get End Property Public Overrides ReadOnly Property IsOptional As Boolean Get Return _parameterToLift.IsOptional End Get End Property Friend Overrides ReadOnly Property IsMetadataOut As Boolean Get Return _parameterToLift.IsMetadataOut End Get End Property Friend Overrides ReadOnly Property IsMetadataIn As Boolean Get Return _parameterToLift.IsMetadataIn End Get End Property Friend Overrides ReadOnly Property MarshallingInformation As MarshalPseudoCustomAttributeData Get Return _parameterToLift.MarshallingInformation End Get End Property Friend Overrides ReadOnly Property HasOptionCompare As Boolean Get Return _parameterToLift.HasOptionCompare End Get End Property Friend Overrides ReadOnly Property IsIDispatchConstant As Boolean Get Return _parameterToLift.IsIDispatchConstant End Get End Property Friend Overrides ReadOnly Property IsIUnknownConstant As Boolean Get Return _parameterToLift.IsIUnknownConstant End Get End Property Friend Overrides ReadOnly Property IsCallerLineNumber As Boolean Get Return _parameterToLift.IsCallerLineNumber End Get End Property Friend Overrides ReadOnly Property IsCallerMemberName As Boolean Get Return _parameterToLift.IsCallerMemberName End Get End Property Friend Overrides ReadOnly Property IsCallerFilePath As Boolean Get Return _parameterToLift.IsCallerFilePath End Get End Property Friend Overrides ReadOnly Property CallerArgumentExpressionParameterIndex As Integer Get Throw ExceptionUtilities.Unreachable End Get End Property Public Overrides ReadOnly Property IsParamArray As Boolean Get Return _parameterToLift.IsParamArray End Get End Property Public Overrides ReadOnly Property Locations As ImmutableArray(Of Location) Get Return ImmutableArray(Of Location).Empty End Get End Property Public Overrides ReadOnly Property Ordinal As Integer Get Return _parameterToLift.Ordinal End Get End Property Public Overrides ReadOnly Property Type As TypeSymbol Get Return _type End Get End Property End Class End Class End Namespace