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); }
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); }