예제 #1
0
        internal static Expression ImplicitConvert(Expression /*!*/ expr, Type /*!*/ fromType, Type /*!*/ toType)
        {
            expr = AstUtils.Convert(expr, fromType);

            if (toType.IsAssignableFrom(fromType))
            {
                return(AstUtils.Convert(expr, toType));
            }

            if (HasImplicitNumericConversion(fromType, toType))
            {
                return(Ast.Convert(expr, toType));
            }

            MethodInfo converter = CompilerHelpers.GetImplicitConverter(fromType, toType);

            if (converter != null)
            {
                return(Ast.Call(null, converter, expr));
            }

            return(null);
        }
예제 #2
0
        internal static Convertibility CanConvertFrom(DynamicMetaObject fromArg, Type /*!*/ fromType, Type /*!*/ toType, bool toNotNullable,
                                                      NarrowingLevel level, bool explicitProtocolConversions, bool implicitProtocolConversions)
        {
            ContractUtils.RequiresNotNull(fromType, "fromType");
            ContractUtils.RequiresNotNull(toType, "toType");

            var metaConvertible     = fromArg as IConvertibleMetaObject;
            var rubyMetaConvertible = fromArg as IConvertibleRubyMetaObject;

            //
            // narrowing level 0:
            //

            if (toType == fromType)
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (fromType == typeof(DynamicNull))
            {
                if (toNotNullable)
                {
                    return(Convertibility.NotConvertible);
                }

                if (toType.IsGenericType && toType.GetGenericTypeDefinition() == typeof(Nullable <>))
                {
                    return(Convertibility.AlwaysConvertible);
                }

                if (!toType.IsValueType)
                {
                    // null convertible to any reference type:
                    return(Convertibility.AlwaysConvertible);
                }
                else if (toType == typeof(bool))
                {
                    return(Convertibility.AlwaysConvertible);
                }
                else if (!ProtocolConversionAction.HasDefaultConversion(toType))
                {
                    // null not convertible to a value type unless a protocol conversion is allowed:
                    return(Convertibility.NotConvertible);
                }
            }

            // blocks:
            if (fromType == typeof(MissingBlockParam))
            {
                return(new Convertibility(toType == typeof(BlockParam) && !toNotNullable, null));
            }

            if (fromType == typeof(BlockParam) && toType == typeof(MissingBlockParam))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (toType.IsAssignableFrom(fromType))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (HasImplicitNumericConversion(fromType, toType))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (CompilerHelpers.GetImplicitConverter(fromType, toType) != null)
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (rubyMetaConvertible != null)
            {
                return(rubyMetaConvertible.IsConvertibleTo(toType, false));
            }
            else if (metaConvertible != null)
            {
                return(new Convertibility(metaConvertible.CanConvertTo(toType, false), null));
            }

            //
            // narrowing level 1:
            //

            if (level < NarrowingLevel.One)
            {
                return(Convertibility.NotConvertible);
            }

            if (explicitProtocolConversions && ProtocolConversionAction.HasDefaultConversion(toType))
            {
                return(Convertibility.AlwaysConvertible);
            }

            //
            // narrowing level 2:
            //

            if (level < NarrowingLevel.Two)
            {
                return(Convertibility.NotConvertible);
            }

            if (HasExplicitNumericConversion(fromType, toType))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (CompilerHelpers.GetExplicitConverter(fromType, toType) != null)
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (CompilerHelpers.HasTypeConverter(fromType, toType))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (fromType == typeof(char) && toType == typeof(string))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (toType == typeof(bool))
            {
                return(Convertibility.AlwaysConvertible);
            }

            if (rubyMetaConvertible != null)
            {
                return(rubyMetaConvertible.IsConvertibleTo(toType, true));
            }
            else if (metaConvertible != null)
            {
                return(new Convertibility(metaConvertible.CanConvertTo(toType, true), null));
            }

            //
            // narrowing level 3:
            //

            if (level < NarrowingLevel.Three)
            {
                return(Convertibility.NotConvertible);
            }

            if (implicitProtocolConversions && ProtocolConversionAction.HasDefaultConversion(toType))
            {
                return(Convertibility.AlwaysConvertible);
            }

            // A COM object can potentially be converted to the given interface, but might also be not so use this only as the last resort:
            if (TypeUtils.IsComObjectType(fromType) && toType.IsInterface)
            {
                return(Convertibility.AlwaysConvertible);
            }

            return(Convertibility.NotConvertible);
        }