protected override Conversion ClassifyVOImplicitBuiltInConversionFromExpression(BoundExpression sourceExpression, TypeSymbol source, TypeSymbol destination, ref HashSet <DiagnosticInfo> useSiteDiagnostics) { // Parameters checks have been done in the calling code var srcType = source.SpecialType; var dstType = destination.SpecialType; bool voCast = false; bool voConvert = false; bool typeCast = false; bool vo7 = Compilation.Options.HasOption(CompilerOption.ImplicitCastsAndConversions, sourceExpression.Syntax); if (sourceExpression.Syntax != null) { var xNode = sourceExpression.Syntax.XNode; while (xNode != null) { voCast = xNode is XP.VoCastExpressionContext; if (voCast) { break; } voConvert = xNode is XP.VoConversionExpressionContext; if (voConvert) { break; } typeCast = xNode is XP.TypeCastContext; if (typeCast) { break; } xNode = xNode.Parent as IXParseTree; if (xNode is XP.StatementContext) { break; } } } if (vo7 && (typeCast || voCast || voConvert)) { // Allow cast -> BOOLEAN if (dstType == SpecialType.System_Boolean && srcType.IsIntegralType()) { if (sourceExpression is BoundExpression be && be.Type.SpecialType == SpecialType.System_Boolean) { return(Conversion.Identity); } } } // TYPE(_CAST, expr) allows almost everything // source must be PTR, Integral, IntPtr, UIntPtr // this is handled in CanVOCast if (voCast && source.CanVOCast() && destination.CanVOCast()) { // No _CAST on USUAL if (source == Compilation.UsualType()) { return(Conversion.NoConversion); } // Allow LOGIC(_CAST if (dstType == SpecialType.System_Boolean) { return(Conversion.Identity); } // Allow cast -> INTEGRAL // except from NullableTypes and Reference Types if (dstType.IsIntegralType() && !source.IsNullableType() && !source.IsReferenceType) { if (srcType.IsNumericType()) { // always implicit numeric conversion return(Conversion.ImplicitNumeric); } if (source.SpecialType == SpecialType.System_Boolean) { return(Conversion.Identity); } // Allow PTR -> Integral when size matches if (source.IsVoidPointer()) { if (dstType.SizeInBytes() == 4 && Compilation.Options.Platform == Platform.X86) { return(Conversion.Identity); } if (dstType.SizeInBytes() == 8 && Compilation.Options.Platform == Platform.X64) { return(Conversion.Identity); } } } // Allow cast -> PTR when // source is integral and source size matches the Integral size // source is Ptr, IntPtr, UintPtr // source is PSZ if (destination is PointerTypeSymbol) { if (source.IsIntegralType()) { if (Compilation.Options.Platform == Platform.X86 && srcType.SizeInBytes() == 4) { return(Conversion.Identity); } if (Compilation.Options.Platform == Platform.X64 && srcType.SizeInBytes() == 8) { return(Conversion.Identity); } return(Conversion.IntegerToPointer); } if (source.IsPointerType() || source.IsVoidPointer() || source.SpecialType == SpecialType.System_IntPtr || source.SpecialType == SpecialType.System_UIntPtr) { return(Conversion.Identity); } if (source == Compilation.PszType()) { return(Conversion.Identity); } } // Allow cast -> PSZ if (destination == Compilation.PszType()) { return(Conversion.Identity); } } if (voConvert) { // we need to convert BYTE(<p>) to dereferencing the <p> // This is done else where in Binder.BindVulcanPointerDereference() // Integer conversions if (srcType.IsNumericType() && dstType.IsNumericType() && srcType.IsIntegralType() == dstType.IsIntegralType()) { // always implicit numeric conversion return(Conversion.ImplicitNumeric); } } if (source == Compilation.UsualType()) { // Usual -> Decimal. Get the object out of the Usual and let the rest be done by Roslyn if (destination == Compilation.UsualType()) { return(Conversion.NoConversion); } if (dstType == SpecialType.System_Decimal) { return(Conversion.Boxing); } // Usual -> OBJECT. Get the object out of the Usual // Our special call will call in LocalWriter.UnBoxVOType will // convert the Unbox operation to a call to __Usual.ToObject() // This method will return the Contents of the usual as an object // and not the usual itself as an object else if (dstType == SpecialType.System_Object) { // All Objects are boxed in a usual return(Conversion.Boxing); } else if (destination.IsReferenceType && !IsClipperArgsType(destination) && !destination.IsStringType() && !destination.IsIFormatProvider()) { // all user reference types are boxed. But not the Usual[] args and not string return(Conversion.Boxing); } else if (destination.IsPointerType()) { // Not really boxed, but we handle this in LocalRewriter.UnBoxXSharpType return(Conversion.Boxing); } } if (Compilation.Options.LateBindingOrFox(sourceExpression.Syntax) || vo7) // lb or vo7 { if (srcType == SpecialType.System_Object) { if (destination.IsReferenceType && !IsClipperArgsType(destination)) { // Convert Object -> Reference allowed with /lb and with /vo7 // except when converting to array of usuals return(Conversion.ImplicitReference); } if (destination.IsPointerType() || destination.SpecialType == SpecialType.System_IntPtr) { return(Conversion.Identity); } } if (dstType == SpecialType.System_Object) { if (source.IsReferenceType) { return(Conversion.ImplicitReference); } if (source.IsPointerType() || source.SpecialType == SpecialType.System_IntPtr) { return(Conversion.Identity); } } } if (vo7) { // Convert Any Ptr -> Any Ptr if (source.IsPointerType() && destination.IsPointerType()) { return(Conversion.Identity); } } // Convert Integral type -> Ptr Type if (source.IsIntegralType() && destination.IsPointerType()) { if (Compilation.Options.Platform == Platform.X86 && srcType.SizeInBytes() <= 4) { return(Conversion.Identity); } if (Compilation.Options.Platform == Platform.X64 && srcType.SizeInBytes() <= 8) { return(Conversion.Identity); } return(Conversion.IntegerToPointer); } // When unsafe we always allow to cast void * to typed * // Is this OK ? // See ticket C425 if (source.IsVoidPointer() && destination.IsPointerType() && Compilation.Options.AllowUnsafe) { return(Conversion.Identity); } if (srcType.IsIntegralType() && dstType.IsIntegralType()) { if (srcType.SizeInBytes() < dstType.SizeInBytes() || sourceExpression is BoundConditionalOperator) // IIF expressions with literals are always seen as Int, even when the values are asmall { return(Conversion.ImplicitNumeric); } } if (destination == Compilation.PszType() || destination.IsVoidPointer()) { if (source.SpecialType == SpecialType.System_String) { return(Conversion.ImplicitReference); } } // when nothing else, then use the Core rules return(ClassifyCoreImplicitConversionFromExpression(sourceExpression, source, destination, ref useSiteDiagnostics)); }