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

            if (HasExplicitNumericConversion(fromType, toType))
            {
                // special cases to mimic Ruby behavior precisely:
                if (fromType == typeof(BigInteger))
                {
                    if (toType == typeof(int))
                    {
                        return(Methods.ConvertBignumToFixnum.OpCall(expr));
                    }
                    else if (toType == typeof(double))
                    {
                        return(Methods.ConvertBignumToFloat.OpCall(expr));
                    }
                }
                else if (fromType == typeof(double) && toType == typeof(int))
                {
                    return(Methods.ConvertDoubleToFixnum.OpCall(expr));
                }

                return(Ast.ConvertChecked(expr, toType));
            }

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

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

            if (fromType == typeof(char) && toType == typeof(string))
            {
                return(Ast.Call(null, fromType.GetMethod("ToString", BindingFlags.Public | BindingFlags.Static), expr));
            }

            if (toType == typeof(bool))
            {
                Debug.Assert(fromType != typeof(bool));
                return(fromType.IsValueType ? AstUtils.Constant(true) : Ast.NotEqual(expr, AstUtils.Constant(null)));
            }

            // TODO:
            //if (TypeConverter...(fromType, toType)) {
            //    return true;
            //}

            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);
        }
예제 #3
0
        protected void OnErrorValueCannotBeConvertedCore(ParseContext ec, SourceSpan loc, Type target, bool explicitConversion)
        {
            var sourceType = Type;

            if (TypeManager.IsGenericParameter(sourceType) &&
                TypeManager.IsGenericParameter(target) &&
                sourceType.Name == target.Name)
            {
                string sig1 = sourceType.DeclaringMethod == null?
                              TypeManager.GetCSharpName(sourceType.DeclaringType) :
                                  TypeManager.GetCSharpSignature(sourceType.DeclaringMethod);

                string sig2 = target.DeclaringMethod == null?
                              TypeManager.GetCSharpName(target.DeclaringType) :
                                  TypeManager.GetCSharpSignature(target.DeclaringMethod);

                ec.ReportError(
                    -1,
                    String.Format(
                        "The generic parameter '{0}' of '{1}' cannot be converted to the generic parameter '{0}' of '{2}'.",
                        sourceType.Name,
                        sig1,
                        sig2),
                    loc);
            }
            else if (sourceType.FullName == target.FullName)
            {
                ec.ReportError(
                    -1,
                    String.Format(
                        "The type '{0}' has two conflicting definitions, one comes from '{1}' and the other from '{2}'.",
                        sourceType.FullName,
                        sourceType.FullName,
                        target.Assembly.FullName),
                    loc);
            }

            if (explicitConversion)
            {
                ec.ReportError(
                    30,
                    string.Format(
                        "Cannot convert type '{0}' to '{1}'.",
                        TypeManager.GetCSharpName(sourceType),
                        TypeManager.GetCSharpName(target)),
                    loc);

                return;
            }

            var explicitConversionExists = (CompilerHelpers.GetExplicitConverter(sourceType, target) != null);

            if (explicitConversionExists)
            {
                ec.ReportError(
                    266,
                    string.Format(
                        "Cannot implicitly convert type '{0}' to '{1}'.  " +
                        "An explicit conversion exists (are you missing a cast?).",
                        TypeManager.GetCSharpName(sourceType),
                        TypeManager.GetCSharpName(target)),
                    loc);
                return;
            }

            ec.ReportError(
                29,
                string.Format(
                    "Cannot implicitly convert type '{0}' to '{1}'",
                    TypeManager.GetCSharpName(sourceType),
                    TypeManager.GetCSharpName(target)),
                loc);
        }