Example #1
0
        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));
        }