Exemplo n.º 1
0
        // the sections mentioned in comments of this method are from C# specification v1.2
        public static Conversion GetImplicit(Operand op, Type to, bool onlyStandard, ITypeMapper typeMapper)
        {
            Type from = Operand.GetType(op, typeMapper);

            Type toUnderlying = Helpers.GetNullableUnderlyingType(to);

            if (to.Equals(from))
            {
                return(new Direct(typeMapper));
            }

            Type fromUnderlying = Helpers.GetNullableUnderlyingType(@from);

            if (toUnderlying != null)
            {
                if (fromUnderlying != null)
                {
                    Conversion c = GetImplicit(new FakeTypedOperand(fromUnderlying), toUnderlying, onlyStandard, typeMapper);
                    if (c.IsValid)
                    {
                        return(new ConvertNullable(typeMapper, c));
                    }
                }
                else
                {
                    Conversion c = GetImplicit(op, toUnderlying, onlyStandard, typeMapper);
                    if (c.IsValid)
                    {
                        return(new WrapNullable(typeMapper, c));
                    }
                }
            }

            // required for arrays created from TypeBuilder-s
            if (from != null && to.IsArray && from.IsArray)
            {
                if (to.GetArrayRank() == from.GetArrayRank())
                {
                    if (to.GetElementType().Equals(from.GetElementType()))
                    {
                        return(new Direct(typeMapper));
                    }
                }
            }

            TypeCode tcFrom = Type.GetTypeCode(from);
            TypeCode tcTo   = Type.GetTypeCode(to);
            byte     ct     = _convTable[(int)tcFrom][(int)tcTo];

            // section 6.1.2 - Implicit numeric conversions
            if (from != null && (from.IsPrimitive || Helpers.AreTypesEqual(from, typeof(decimal), typeMapper)) && (to.IsPrimitive || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper)))
            {
                if (ct <= I)
                {
                    if (Helpers.AreTypesEqual(from, typeof(decimal), typeMapper) || Helpers.AreTypesEqual(to, typeof(decimal), typeMapper))
                    {
                        // decimal is handled as user-defined conversion, but as it is a standard one, always enable UDC processing
                        onlyStandard = false;
                    }
                    else
                    {
                        return(new Primitive(typeMapper));
                    }
                }
            }

            IntLiteral intLit = op as IntLiteral;

            // section 6.1.3 - Implicit enumeration conversions
            if (!onlyStandard && to.IsEnum && (object)intLit != null && intLit.Value == 0)
            {
                return(new Primitive(typeMapper));
            }

            // section 6.1.4 - Implicit reference conversions
            if ((from == null || !from.IsValueType) && !to.IsValueType)
            {
                if (from == null)                 // from the null type to any reference type
                {
                    return(new Direct(typeMapper));
                }

                if (to.IsAssignableFrom(from))                  // the rest
                {
                    return(new Direct(typeMapper));
                }
            }

            if (from == null)                   // no other conversion from null type is possible
            {
                return(new Invalid(typeMapper));
            }

            // section 6.1.5 - Boxing conversions
            if (from.IsValueType)
            {
                if (to.IsAssignableFrom(from))
                {
                    return(new Boxing(typeMapper));
                }
            }

            // section 6.1.6 - Implicit constant expression conversions
            if ((object)intLit != null && Helpers.AreTypesEqual(from, typeof(int), typeMapper) && to.IsPrimitive)
            {
                int val = intLit.Value;

                switch (tcTo)
                {
                case TypeCode.SByte:
                    if (val >= sbyte.MinValue && val <= sbyte.MaxValue)
                    {
                        return(new Direct(typeMapper));
                    }
                    break;

                case TypeCode.Byte:
                    if (val >= byte.MinValue && val <= byte.MaxValue)
                    {
                        return(new Direct(typeMapper));
                    }
                    break;

                case TypeCode.Int16:
                    if (val >= short.MinValue && val <= short.MaxValue)
                    {
                        return(new Direct(typeMapper));
                    }
                    break;

                case TypeCode.UInt16:
                    if (val >= ushort.MinValue && val <= ushort.MaxValue)
                    {
                        return(new Direct(typeMapper));
                    }
                    break;

                case TypeCode.UInt32:
                    if (val >= 0)
                    {
                        return(new Direct(typeMapper));
                    }
                    break;

                case TypeCode.UInt64:
                    if (val >= 0)
                    {
                        return(new Direct(typeMapper));
                    }
                    break;
                }
            }

            // section 6.1.7 - User-defined implicit conversions (details in section 6.4.3)
            if (onlyStandard || Helpers.AreTypesEqual(from, typeof(object), typeMapper) || Helpers.AreTypesEqual(to, typeof(object), typeMapper) || from.IsInterface || to.IsInterface ||
                to.IsSubclassOf(from) || from.IsSubclassOf(to))
            {
                return(new Invalid(typeMapper));  // skip not-permitted conversion attempts (section 6.4.1)
            }
            List <UserDefined> candidates = null;

            FindCandidates(ref candidates, FindImplicitMethods(from, to, typeMapper), op, to, GetImplicit, typeMapper);

            if (candidates == null)
            {
                return(new Invalid(typeMapper));
            }

            if (candidates.Count == 1)
            {
                return(candidates[0]);
            }

            return(UserDefined.FindImplicit(candidates, @from, to, typeMapper));
        }
Exemplo n.º 2
0
        // the sections mentioned in comments of this method are from C# specification v1.2
        public static Conversion GetImplicit(Operand op, Type to, bool onlyStandard)
        {
            try {
                Type from = Operand.GetType(op);

                if (to.Equals(from) || to.FullName == from.FullName || to.IsGenericParameter)
                {
                    return(Direct.Instance);
                }

                // required for arrays created from TypeBuilder-s
                if (from != null && to.IsArray && from.IsArray)
                {
                    if (to.GetArrayRank() == from.GetArrayRank())
                    {
                        if (to.GetElementType().Equals(from.GetElementType()))
                        {
                            return(Direct.Instance);
                        }
                    }
                }

                TypeCode tcFrom = Type.GetTypeCode(from);
                TypeCode tcTo   = Type.GetTypeCode(to);
                byte     ct     = convTable[(int)tcFrom][(int)tcTo];

                // section 6.1.2 - Implicit numeric conversions
                if ((from != null && (from.IsPrimitive || from == typeof(decimal))) && (to.IsPrimitive || to == typeof(decimal)))
                {
                    if (ct <= I)
                    {
                        if (from == typeof(decimal) || to == typeof(decimal))
                        {
                            // decimal is handled as user-defined conversion, but as it is a standard one, always enable UDC processing
                            onlyStandard = false;
                        }
                        else
                        {
                            return(Primitive.Instance);
                        }
                    }
                }

                IntLiteral intLit = op as IntLiteral;

                // section 6.1.3 - Implicit enumeration conversions
                if (!onlyStandard && !to.IsGenericType && to.IsEnum && (object)intLit != null && intLit.Value == 0)
                {
                    return(Primitive.Instance);
                }

                // section 6.1.4 - Implicit reference conversions
                if ((from == null || !from.IsValueType) && !to.IsValueType)
                {
                    if (from == null) // from the null type to any reference type
                    {
                        return(Direct.Instance);
                    }

                    if (to.IsAssignableFrom(from) || to.IsDerivedFrom(from))    // the rest
                    {
                        return(Direct.Instance);
                    }

                    if (from.Name.StartsWith("_Frame"))
                    {
                        return(Direct.Instance);
                    }

                    if (to == typeof(Operand))
                    {
                        return(UserDefined.Cast.Instance);
                    }
                }

                if (from == null)       // no other conversion from null type is possible
                {
                    return(Invalid.Instance);
                }

                // section 6.1.5 - Boxing conversions
                if (from.IsValueType)
                {
                    if (to.IsAssignableFrom(from))
                    {
                        return(Boxing.Instance);
                    }
                }

                // section 6.1.6 - Implicit constant expression conversions
                if ((object)intLit != null && from == typeof(int) && to.IsPrimitive)
                {
                    int val = intLit.Value;

                    switch (tcTo)
                    {
                    case TypeCode.SByte:
                        if (val >= sbyte.MinValue && val <= sbyte.MaxValue)
                        {
                            return(Direct.Instance);
                        }
                        break;

                    case TypeCode.Byte:
                        if (val >= byte.MinValue && val <= byte.MaxValue)
                        {
                            return(Direct.Instance);
                        }
                        break;

                    case TypeCode.Int16:
                        if (val >= short.MinValue && val <= short.MaxValue)
                        {
                            return(Direct.Instance);
                        }
                        break;

                    case TypeCode.UInt16:
                        if (val >= ushort.MinValue && val <= ushort.MaxValue)
                        {
                            return(Direct.Instance);
                        }
                        break;

                    case TypeCode.UInt32:
                        if (val >= 0)
                        {
                            return(Direct.Instance);
                        }
                        break;

                    case TypeCode.UInt64:
                        if (val >= 0)
                        {
                            return(Primitive.Instance);
                        }
                        break;
                    }
                }
                if (from == typeof(long))
                {
                    LongLiteral longLit = op as LongLiteral;
                    if ((object)longLit != null && longLit.Value > 0)
                    {
                        return(Direct.Instance);
                    }
                }

                // section 6.1.7 - User-defined implicit conversions (details in section 6.4.3)
                if (onlyStandard || from == typeof(object) || to == typeof(object) || from.IsInterface || to.IsInterface ||
                    to.IsSubclassOf(from) || from.IsSubclassOf(to))
                {
                    return(Invalid.Instance);    // skip not-permitted conversion attempts (section 6.4.1)
                }
                List <UserDefined> candidates = null;
                FindCandidates(ref candidates, FindImplicitMethods(from, to), op, to, GetImplicit);

                if (candidates == null)
                {
                    return(Invalid.Instance);
                }

                if (candidates.Count == 1)
                {
                    return(candidates[0]);
                }

                return(UserDefined.FindImplicit(candidates, from, to));
            } catch (NotSupportedException e) {
                return(Direct.Instance); // fallback to success :)
            }
        }