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