X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=09b56abea571f6d9475bc7913a03054cebce792f;hb=8dd8c3d59a76f59d85e0bcb7ca4ca6cb5c382188;hp=5dabe481751e5a3d0a903f28413d9fe552744721;hpb=d41bec356a9a7fd7312dd31b32569fe5f8a544f0;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 5dabe481751..09b56abea57 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -19,6 +19,16 @@ namespace Mono.CSharp { // A container class for all the conversion operations // public class Convert { + // + // This is used to prettify the code: a null argument is allowed + // for ImplicitStandardConversion as long as it is known that + // no anonymous method will play a role. + // + // FIXME: renamed from `const' to `static' to allow bootstraping from older + // versions of the compiler that could not cope with this construct. + // + public static EmitContext ConstantEC = null; + static public void Error_CannotConvertType (Location loc, Type source, Type target) { Report.Error (30, loc, "Cannot convert type '" + @@ -53,13 +63,20 @@ namespace Mono.CSharp { if (expr_type.IsValueType) return new BoxedCast (expr); - if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type) + if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){ + if (expr_type == TypeManager.anonymous_method_type) + return null; return new EmptyCast (expr, target_type); + } + + return null; } else if (target_type == TypeManager.value_type) { if (expr_type.IsValueType) return new BoxedCast (expr); - if (expr is NullLiteral) - return new BoxedCast (expr); + if (expr_type == TypeManager.null_type) + return new NullCast (expr, target_type); + + return null; } else if (expr_type.IsSubclassOf (target_type)) { // // Special case: enumeration to System.Enum. @@ -70,83 +87,88 @@ namespace Mono.CSharp { return new BoxedCast (expr); return new EmptyCast (expr, target_type); - } else { + } - // This code is kind of mirrored inside ImplicitStandardConversionExists - // with the small distinction that we only probe there - // - // Always ensure that the code here and there is in sync + // This code is kind of mirrored inside ImplicitStandardConversionExists + // with the small distinction that we only probe there + // + // Always ensure that the code here and there is in sync - // from the null type to any reference-type. - if (expr is NullLiteral){ - if (target_type.IsPointer) - return NullPointer.Null; + // from the null type to any reference-type. + if (expr_type == TypeManager.null_type){ + if (target_type.IsPointer) + return new EmptyCast (NullPointer.Null, target_type); - if (!target_type.IsValueType) - return new NullCast (expr, target_type); - } + if (!target_type.IsValueType) + return new NullCast (expr, target_type); + } - // from any class-type S to any interface-type T. - if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)){ - if (expr_type.IsClass) - return new EmptyCast (expr, target_type); - else if (expr_type.IsValueType || expr_type == TypeManager.enum_type) - return new BoxedCast (expr, target_type); - else - return new EmptyCast (expr, target_type); - } + // from any class-type S to any interface-type T. + if (target_type.IsInterface) { + if (target_type != TypeManager.iconvertible_type && + expr_type.IsValueType && (expr is Constant) && + !(expr is IntLiteral || expr is BoolLiteral || + expr is FloatLiteral || expr is DoubleLiteral || + expr is LongLiteral || expr is CharLiteral || + expr is StringLiteral || expr is DecimalLiteral || + expr is UIntLiteral || expr is ULongLiteral)) { + return null; } - // from any interface type S to interface-type T. - if (expr_type.IsInterface && target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) + if (TypeManager.ImplementsInterface (expr_type, target_type)){ + if (expr_type.IsClass) return new EmptyCast (expr, target_type); + else if (expr_type.IsValueType) + return new BoxedCast (expr, target_type); else - return null; + return new EmptyCast (expr, target_type); } + } + + // from any interface type S to interface-type T. + if (expr_type.IsInterface && target_type.IsInterface) { + if (TypeManager.ImplementsInterface (expr_type, target_type)) + return new EmptyCast (expr, target_type); + else + return null; + } - // from an array-type S to an array-type of type T - if (expr_type.IsArray && target_type.IsArray) { - if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { + // from an array-type S to an array-type of type T + if (expr_type.IsArray && target_type.IsArray) { + if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { - Type expr_element_type = TypeManager.GetElementType (expr_type); + Type expr_element_type = TypeManager.GetElementType (expr_type); - if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); + if (MyEmptyExpr == null) + MyEmptyExpr = new EmptyExpression (); - MyEmptyExpr.SetType (expr_element_type); - Type target_element_type = TypeManager.GetElementType (target_type); + MyEmptyExpr.SetType (expr_element_type); + Type target_element_type = TypeManager.GetElementType (target_type); - if (!expr_element_type.IsValueType && !target_element_type.IsValueType) - if (ImplicitStandardConversionExists (MyEmptyExpr, + if (!expr_element_type.IsValueType && !target_element_type.IsValueType) + if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr, target_element_type)) - return new EmptyCast (expr, target_type); - } + return new EmptyCast (expr, target_type); } + } + // from an array-type to System.Array + if (expr_type.IsArray && target_type == TypeManager.array_type) + return new EmptyCast (expr, target_type); - // from an array-type to System.Array - if (expr_type.IsArray && target_type == TypeManager.array_type) - return new EmptyCast (expr, target_type); - - // from any delegate type to System.Delegate - if ((expr_type == TypeManager.delegate_type || - expr_type.IsSubclassOf (TypeManager.delegate_type)) && - target_type == TypeManager.delegate_type) - return new EmptyCast (expr, target_type); + // from any delegate type to System.Delegate + if ((expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) && + target_type == TypeManager.delegate_type) + return new EmptyCast (expr, target_type); - // from any array-type or delegate type into System.ICloneable. - if (expr_type.IsArray || - expr_type == TypeManager.delegate_type || - expr_type.IsSubclassOf (TypeManager.delegate_type)) - if (target_type == TypeManager.icloneable_type) - return new EmptyCast (expr, target_type); + // from any array-type or delegate type into System.ICloneable. + if (expr_type.IsArray || + expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) + if (target_type == TypeManager.icloneable_type) + return new EmptyCast (expr, target_type); - return null; - - } - return null; } @@ -164,66 +186,81 @@ namespace Mono.CSharp { if (target_type == TypeManager.object_type) { if (expr_type.IsClass || expr_type.IsValueType || expr_type.IsInterface || expr_type == TypeManager.enum_type) - return true; + if (target_type != TypeManager.anonymous_method_type) + return true; + + return false; } else if (expr_type.IsSubclassOf (target_type)) return true; - else { - // Please remember that all code below actually comes - // from ImplicitReferenceConversion so make sure code remains in sync + + // Please remember that all code below actually comes + // from ImplicitReferenceConversion so make sure code remains in sync - // from any class-type S to any interface-type T. - if (target_type.IsInterface) { - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return true; + // from any class-type S to any interface-type T. + if (target_type.IsInterface) { + if (target_type != TypeManager.iconvertible_type && + expr_type.IsValueType && (expr is Constant) && + !(expr is IntLiteral || expr is BoolLiteral || + expr is FloatLiteral || expr is DoubleLiteral || + expr is LongLiteral || expr is CharLiteral || + expr is StringLiteral || expr is DecimalLiteral || + expr is UIntLiteral || expr is ULongLiteral)) { + return false; } - // from any interface type S to interface-type T. - if (expr_type.IsInterface && target_type.IsInterface) - if (TypeManager.ImplementsInterface (expr_type, target_type)) - return true; + if (TypeManager.ImplementsInterface (expr_type, target_type)) + return true; + } + + // from any interface type S to interface-type T. + if (expr_type.IsInterface && target_type.IsInterface) + if (TypeManager.ImplementsInterface (expr_type, target_type)) + return true; - // from an array-type S to an array-type of type T - if (expr_type.IsArray && target_type.IsArray) { - if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { + // from an array-type S to an array-type of type T + if (expr_type.IsArray && target_type.IsArray) { + if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) { - Type expr_element_type = expr_type.GetElementType (); + Type expr_element_type = expr_type.GetElementType (); - if (MyEmptyExpr == null) - MyEmptyExpr = new EmptyExpression (); + if (MyEmptyExpr == null) + MyEmptyExpr = new EmptyExpression (); - MyEmptyExpr.SetType (expr_element_type); - Type target_element_type = TypeManager.GetElementType (target_type); + MyEmptyExpr.SetType (expr_element_type); + Type target_element_type = TypeManager.GetElementType (target_type); - if (!expr_element_type.IsValueType && !target_element_type.IsValueType) - if (ImplicitStandardConversionExists (MyEmptyExpr, + if (!expr_element_type.IsValueType && !target_element_type.IsValueType) + if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr, target_element_type)) - return true; - } + return true; } + } - // from an array-type to System.Array - if (expr_type.IsArray && (target_type == TypeManager.array_type)) - return true; + // from an array-type to System.Array + if (expr_type.IsArray && (target_type == TypeManager.array_type)) + return true; - // from any delegate type to System.Delegate - if ((expr_type == TypeManager.delegate_type || - expr_type.IsSubclassOf (TypeManager.delegate_type)) && - target_type == TypeManager.delegate_type) - if (target_type.IsAssignableFrom (expr_type)) - return true; + // from any delegate type to System.Delegate + if ((expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) && + target_type == TypeManager.delegate_type) + if (target_type.IsAssignableFrom (expr_type)) + return true; - // from any array-type or delegate type into System.ICloneable. - if (expr_type.IsArray || - expr_type == TypeManager.delegate_type || - expr_type.IsSubclassOf (TypeManager.delegate_type)) - if (target_type == TypeManager.icloneable_type) - return true; - - // from the null type to any reference-type. - if (expr is NullLiteral && !target_type.IsValueType && - !TypeManager.IsEnumType (target_type)) + // from any array-type or delegate type into System.ICloneable. + if (expr_type.IsArray || + expr_type == TypeManager.delegate_type || + expr_type.IsSubclassOf (TypeManager.delegate_type)) + if (target_type == TypeManager.icloneable_type) return true; + // from the null type to any reference-type. + if (expr_type == TypeManager.null_type){ + if (target_type.IsPointer) + return true; + + if (!target_type.IsValueType) + return true; } return false; } @@ -243,7 +280,6 @@ namespace Mono.CSharp { // Attempt to do the implicit constant expression conversions if (expr is Constant){ - if (expr is IntConstant){ Expression e; @@ -258,7 +294,7 @@ namespace Mono.CSharp { // we just inline it // long v = ((LongConstant) expr).Value; - if (v > 0) + if (v >= 0) return new ULongConstant ((ulong) v); } } @@ -267,7 +303,7 @@ namespace Mono.CSharp { if (expr_type == TypeManager.sbyte_type){ // - // From sbyte to short, int, long, float, double. + // From sbyte to short, int, long, float, double, decimal // if (real_target_type == TypeManager.int32_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); @@ -279,9 +315,11 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.short_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.byte_type){ // - // From byte to short, ushort, int, uint, long, ulong, float, double + // From byte to short, ushort, int, uint, long, ulong, float, double, decimal // if ((real_target_type == TypeManager.short_type) || (real_target_type == TypeManager.ushort_type) || @@ -297,9 +335,12 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); + } else if (expr_type == TypeManager.short_type){ // - // From short to int, long, float, double + // From short to int, long, float, double, decimal // if (real_target_type == TypeManager.int32_type) return new EmptyCast (expr, target_type); @@ -309,9 +350,12 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); + } else if (expr_type == TypeManager.ushort_type){ // - // From ushort to int, uint, long, ulong, float, double + // From ushort to int, uint, long, ulong, float, double, decimal // if (real_target_type == TypeManager.uint32_type) return new EmptyCast (expr, target_type); @@ -326,9 +370,11 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.int32_type){ // - // From int to long, float, double + // From int to long, float, double, decimal // if (real_target_type == TypeManager.int64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); @@ -336,9 +382,11 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.uint32_type){ // - // From uint to long, ulong, float, double + // From uint to long, ulong, float, double, decimal // if (real_target_type == TypeManager.int64_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); @@ -350,6 +398,8 @@ namespace Mono.CSharp { if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, OpCodes.Conv_R4); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.int64_type){ // // From long/ulong to float, double @@ -357,7 +407,9 @@ namespace Mono.CSharp { if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.uint64_type){ // // From ulong to float, double @@ -367,10 +419,12 @@ namespace Mono.CSharp { OpCodes.Conv_R8); if (real_target_type == TypeManager.float_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un, - OpCodes.Conv_R4); + OpCodes.Conv_R4); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.char_type){ // - // From char to ushort, int, uint, long, ulong, float, double + // From char to ushort, int, uint, long, ulong, float, double, decimal // if ((real_target_type == TypeManager.ushort_type) || (real_target_type == TypeManager.int32_type) || @@ -384,6 +438,8 @@ namespace Mono.CSharp { return new OpcodeCast (expr, target_type, OpCodes.Conv_R4); if (real_target_type == TypeManager.double_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_R8); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr); } else if (expr_type == TypeManager.float_type){ // // float to double @@ -402,7 +458,7 @@ namespace Mono.CSharp { /// public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type) { - if (ImplicitStandardConversionExists (expr, target_type)) + if (ImplicitStandardConversionExists (ec, expr, target_type)) return true; Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null); @@ -423,8 +479,10 @@ namespace Mono.CSharp { /// /// Determines if a standard implicit conversion exists from /// expr_type to target_type + /// + /// ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type. /// - public static bool ImplicitStandardConversionExists (Expression expr, Type target_type) + public static bool ImplicitStandardConversionExists (EmitContext ec, Expression expr, Type target_type) { Type expr_type = expr.Type; @@ -434,11 +492,12 @@ namespace Mono.CSharp { if (expr_type == target_type) return true; + // First numeric conversions if (expr_type == TypeManager.sbyte_type){ // - // From sbyte to short, int, long, float, double. + // From sbyte to short, int, long, float, double, decimal // if ((target_type == TypeManager.int32_type) || (target_type == TypeManager.int64_type) || @@ -450,7 +509,7 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.byte_type){ // - // From byte to short, ushort, int, uint, long, ulong, float, double + // From byte to short, ushort, int, uint, long, ulong, float, double, decimal // if ((target_type == TypeManager.short_type) || (target_type == TypeManager.ushort_type) || @@ -465,7 +524,7 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.short_type){ // - // From short to int, long, float, double + // From short to int, long, double, float, decimal // if ((target_type == TypeManager.int32_type) || (target_type == TypeManager.int64_type) || @@ -476,7 +535,7 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.ushort_type){ // - // From ushort to int, uint, long, ulong, float, double + // From ushort to int, uint, long, ulong, double, float, decimal // if ((target_type == TypeManager.uint32_type) || (target_type == TypeManager.uint64_type) || @@ -489,7 +548,7 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.int32_type){ // - // From int to long, float, double + // From int to long, double, float, decimal // if ((target_type == TypeManager.int64_type) || (target_type == TypeManager.double_type) || @@ -499,7 +558,7 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.uint32_type){ // - // From uint to long, ulong, float, double + // From uint to long, ulong, double, float, decimal // if ((target_type == TypeManager.int64_type) || (target_type == TypeManager.uint64_type) || @@ -511,7 +570,7 @@ namespace Mono.CSharp { } else if ((expr_type == TypeManager.uint64_type) || (expr_type == TypeManager.int64_type)) { // - // From long/ulong to float, double + // From long/ulong to double, float, decimal // if ((target_type == TypeManager.double_type) || (target_type == TypeManager.float_type) || @@ -520,7 +579,7 @@ namespace Mono.CSharp { } else if (expr_type == TypeManager.char_type){ // - // From char to ushort, int, uint, long, ulong, float, double + // From char to ushort, int, uint, ulong, long, float, double, decimal // if ((target_type == TypeManager.ushort_type) || (target_type == TypeManager.int32_type) || @@ -540,6 +599,21 @@ namespace Mono.CSharp { return true; } + if (expr.eclass == ExprClass.MethodGroup){ + if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){ + MethodGroupExpr mg = expr as MethodGroupExpr; + if (mg != null){ + // + // This should not happen frequently, so we can create an object + // to test compatibility + // + Expression c = ImplicitDelegateCreation.Create ( + ec, mg, target_type, true, Location.Null); + return c != null; + } + } + } + if (ImplicitReferenceConversionExists (expr, target_type)) return true; @@ -598,131 +672,137 @@ namespace Mono.CSharp { return true; } + // + // If `expr_type' implements `target_type' (which is an iface) + // see TryImplicitIntConversion + // + if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type)) + return true; + if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer) return true; + if (expr_type == TypeManager.anonymous_method_type){ + if (!TypeManager.IsDelegateType (target_type)) + return false; + + AnonymousMethod am = (AnonymousMethod) expr; + + Expression conv = am.Compatible (ec, target_type, true); + if (conv != null) + return true; + } + return false; } - // - // Used internally by FindMostEncompassedType, this is used - // to avoid creating lots of objects in the tight loop inside - // FindMostEncompassedType - // - static EmptyExpression priv_fmet_param; - /// /// Finds "most encompassed type" according to the spec (13.4.2) /// amongst the methods in the MethodGroupExpr /// - static Type FindMostEncompassedType (ArrayList types) + static Type FindMostEncompassedType (EmitContext ec, ArrayList types) { Type best = null; - if (priv_fmet_param == null) - priv_fmet_param = new EmptyExpression (); + if (types.Count == 0) + return null; + + if (types.Count == 1) + return (Type) types [0]; - foreach (Type t in types){ - priv_fmet_param.SetType (t); - + EmptyExpression expr = EmptyExpression.Grab (); + + foreach (Type t in types) { if (best == null) { best = t; continue; } - - if (ImplicitStandardConversionExists (priv_fmet_param, best)) + + expr.SetType (t); + if (ImplicitStandardConversionExists (ec, expr, best)) best = t; } + expr.SetType (best); + foreach (Type t in types) { + if (best == t) + continue; + if (!ImplicitStandardConversionExists (ec, expr, t)) { + best = null; + break; + } + } + + EmptyExpression.Release (expr); + return best; } - - // - // Used internally by FindMostEncompassingType, this is used - // to avoid creating lots of objects in the tight loop inside - // FindMostEncompassingType - // - static EmptyExpression priv_fmee_ret; - + /// /// Finds "most encompassing type" according to the spec (13.4.2) /// amongst the types in the given set /// - static Type FindMostEncompassingType (ArrayList types) + static Type FindMostEncompassingType (EmitContext ec, ArrayList types) { Type best = null; - if (priv_fmee_ret == null) - priv_fmee_ret = new EmptyExpression (); + if (types.Count == 0) + return null; + + if (types.Count == 1) + return (Type) types [0]; - foreach (Type t in types){ - priv_fmee_ret.SetType (best); + EmptyExpression expr = EmptyExpression.Grab (); + foreach (Type t in types) { if (best == null) { best = t; continue; } - if (ImplicitStandardConversionExists (priv_fmee_ret, t)) + expr.SetType (best); + if (ImplicitStandardConversionExists (ec, expr, t)) best = t; } - + + foreach (Type t in types) { + if (best == t) + continue; + expr.SetType (t); + if (!ImplicitStandardConversionExists (ec, expr, best)) { + best = null; + break; + } + } + + EmptyExpression.Release (expr); + return best; } - // - // Used to avoid creating too many objects - // - static EmptyExpression priv_fms_expr; - /// /// Finds the most specific source Sx according to the rules of the spec (13.4.4) /// by making use of FindMostEncomp* methods. Applies the correct rules separately /// for explicit and implicit conversion operators. /// - static public Type FindMostSpecificSource (MethodGroupExpr me, Expression source, - bool apply_explicit_conv_rules, + static public Type FindMostSpecificSource (EmitContext ec, IList list, + Expression source, bool apply_explicit_conv_rules, Location loc) { ArrayList src_types_set = new ArrayList (); - if (priv_fms_expr == null) - priv_fms_expr = new EmptyExpression (); - // // If any operator converts from S then Sx = S // Type source_type = source.Type; - foreach (MethodBase mb in me.Methods){ - ParameterData pd = Invocation.GetParameterData (mb); + foreach (MethodBase mb in list){ + ParameterData pd = TypeManager.GetParameterData (mb); Type param_type = pd.ParameterType (0); if (param_type == source_type) return param_type; - if (apply_explicit_conv_rules) { - // - // From the spec : - // Find the set of applicable user-defined conversion operators, U. This set - // consists of the - // user-defined implicit or explicit conversion operators declared by - // the classes or structs in D that convert from a type encompassing - // or encompassed by S to a type encompassing or encompassed by T - // - priv_fms_expr.SetType (param_type); - if (ImplicitStandardConversionExists (priv_fms_expr, source_type)) - src_types_set.Add (param_type); - else { - if (ImplicitStandardConversionExists (source, param_type)) - src_types_set.Add (param_type); - } - } else { - // - // Only if S is encompassed by param_type - // - if (ImplicitStandardConversionExists (source, param_type)) - src_types_set.Add (param_type); - } + src_types_set.Add (param_type); } // @@ -732,75 +812,41 @@ namespace Mono.CSharp { ArrayList candidate_set = new ArrayList (); foreach (Type param_type in src_types_set){ - if (ImplicitStandardConversionExists (source, param_type)) + if (ImplicitStandardConversionExists (ec, source, param_type)) candidate_set.Add (param_type); } if (candidate_set.Count != 0) - return FindMostEncompassedType (candidate_set); + return FindMostEncompassedType (ec, candidate_set); } // // Final case // if (apply_explicit_conv_rules) - return FindMostEncompassingType (src_types_set); + return FindMostEncompassingType (ec, src_types_set); else - return FindMostEncompassedType (src_types_set); + return FindMostEncompassedType (ec, src_types_set); } - - // - // Useful in avoiding proliferation of objects - // - static EmptyExpression priv_fmt_expr; /// /// Finds the most specific target Tx according to section 13.4.4 /// - static public Type FindMostSpecificTarget (MethodGroupExpr me, Type target, - bool apply_explicit_conv_rules, + static public Type FindMostSpecificTarget (EmitContext ec, IList list, + Type target, bool apply_explicit_conv_rules, Location loc) { ArrayList tgt_types_set = new ArrayList (); - if (priv_fmt_expr == null) - priv_fmt_expr = new EmptyExpression (); - // // If any operator converts to T then Tx = T // - foreach (MethodInfo mi in me.Methods){ + foreach (MethodInfo mi in list){ Type ret_type = mi.ReturnType; - if (ret_type == target) return ret_type; - if (apply_explicit_conv_rules) { - // - // From the spec : - // Find the set of applicable user-defined conversion operators, U. - // - // This set consists of the - // user-defined implicit or explicit conversion operators declared by - // the classes or structs in D that convert from a type encompassing - // or encompassed by S to a type encompassing or encompassed by T - // - priv_fms_expr.SetType (ret_type); - if (ImplicitStandardConversionExists (priv_fms_expr, target)) - tgt_types_set.Add (ret_type); - else { - priv_fms_expr.SetType (target); - if (ImplicitStandardConversionExists (priv_fms_expr, ret_type)) - tgt_types_set.Add (ret_type); - } - } else { - // - // Only if T is encompassed by param_type - // - priv_fms_expr.SetType (ret_type); - if (ImplicitStandardConversionExists (priv_fms_expr, target)) - tgt_types_set.Add (ret_type); - } + tgt_types_set.Add (ret_type); } // @@ -809,24 +855,28 @@ namespace Mono.CSharp { if (apply_explicit_conv_rules) { ArrayList candidate_set = new ArrayList (); + EmptyExpression expr = EmptyExpression.Grab (); + foreach (Type ret_type in tgt_types_set){ - priv_fmt_expr.SetType (ret_type); + expr.SetType (ret_type); - if (ImplicitStandardConversionExists (priv_fmt_expr, target)) + if (ImplicitStandardConversionExists (ec, expr, target)) candidate_set.Add (ret_type); } + EmptyExpression.Release (expr); + if (candidate_set.Count != 0) - return FindMostEncompassingType (candidate_set); + return FindMostEncompassingType (ec, candidate_set); } // // Okay, final case ! // if (apply_explicit_conv_rules) - return FindMostEncompassedType (tgt_types_set); + return FindMostEncompassedType (ec, tgt_types_set); else - return FindMostEncompassingType (tgt_types_set); + return FindMostEncompassingType (ec, tgt_types_set); } /// @@ -847,75 +897,90 @@ namespace Mono.CSharp { return UserDefinedConversion (ec, source, target, loc, true); } + static void AddConversionOperators (EmitContext ec, ArrayList list, + Expression source, Type target_type, + bool look_for_explicit, + MethodGroupExpr mg) + { + if (mg == null) + return; + + Type source_type = source.Type; + EmptyExpression expr = EmptyExpression.Grab (); + foreach (MethodInfo m in mg.Methods) { + ParameterData pd = TypeManager.GetParameterData (m); + Type return_type = m.ReturnType; + Type arg_type = pd.ParameterType (0); + + if (source_type != arg_type) { + if (!ImplicitStandardConversionExists (ec, source, arg_type)) { + if (!look_for_explicit) + continue; + expr.SetType (arg_type); + if (!ImplicitStandardConversionExists (ec, expr, source_type)) + continue; + } + } + + if (target_type != return_type) { + expr.SetType (return_type); + if (!ImplicitStandardConversionExists (ec, expr, target_type)) { + if (!look_for_explicit) + continue; + expr.SetType (target_type); + if (!ImplicitStandardConversionExists (ec, expr, return_type)) + continue; + } + } + + list.Add (m); + } + + EmptyExpression.Release (expr); + } + /// - /// Computes the MethodGroup for the user-defined conversion + /// Computes the list of the user-defined conversion /// operators from source_type to target_type. `look_for_explicit' /// controls whether we should also include the list of explicit /// operators /// - static MethodGroupExpr GetConversionOperators (EmitContext ec, - Type source_type, Type target_type, - Location loc, bool look_for_explicit) + static IList GetConversionOperators (EmitContext ec, + Expression source, Type target_type, + Location loc, bool look_for_explicit) { - Expression mg1 = null, mg2 = null; - Expression mg5 = null, mg6 = null, mg7 = null, mg8 = null; - string op_name; - - op_name = "op_Implicit"; + ArrayList ret = new ArrayList (4); - MethodGroupExpr union3; - - mg1 = Expression.MethodLookup (ec, source_type, op_name, loc); - if (source_type.BaseType != null) - mg2 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc); - - if (mg1 == null) - union3 = (MethodGroupExpr) mg2; - else if (mg2 == null) - union3 = (MethodGroupExpr) mg1; - else - union3 = Invocation.MakeUnionSet (mg1, mg2, loc); + Type source_type = source.Type; - mg1 = Expression.MethodLookup (ec, target_type, op_name, loc); - if (mg1 != null){ - if (union3 != null) - union3 = Invocation.MakeUnionSet (union3, mg1, loc); - else - union3 = (MethodGroupExpr) mg1; + if (source_type != TypeManager.decimal_type) { + AddConversionOperators (ec, ret, source, target_type, look_for_explicit, + Expression.MethodLookup ( + ec, source_type, "op_Implicit", loc) as MethodGroupExpr); + if (look_for_explicit) { + AddConversionOperators (ec, ret, source, target_type, look_for_explicit, + Expression.MethodLookup ( + ec, source_type, "op_Explicit", loc) as MethodGroupExpr); + } } - if (target_type.BaseType != null) - mg1 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc); - - if (mg1 != null){ - if (union3 != null) - union3 = Invocation.MakeUnionSet (union3, mg1, loc); - else - union3 = (MethodGroupExpr) mg1; + if (target_type != TypeManager.decimal_type) { + AddConversionOperators (ec, ret, source, target_type, look_for_explicit, + Expression.MethodLookup ( + ec, target_type, "op_Implicit", loc) as MethodGroupExpr); + if (look_for_explicit) { + AddConversionOperators (ec, ret, source, target_type, look_for_explicit, + Expression.MethodLookup ( + ec, target_type, "op_Explicit", loc) as MethodGroupExpr); + } } - MethodGroupExpr union4 = null; - - if (look_for_explicit) { - op_name = "op_Explicit"; + return ret; + } - mg5 = Expression.MemberLookup (ec, source_type, op_name, loc); - if (source_type.BaseType != null) - mg6 = Expression.MethodLookup (ec, source_type.BaseType, op_name, loc); - - mg7 = Expression.MemberLookup (ec, target_type, op_name, loc); - if (target_type.BaseType != null) - mg8 = Expression.MethodLookup (ec, target_type.BaseType, op_name, loc); - - MethodGroupExpr union5 = Invocation.MakeUnionSet (mg5, mg6, loc); - MethodGroupExpr union6 = Invocation.MakeUnionSet (mg7, mg8, loc); + static DoubleHash explicit_conv = new DoubleHash (100); + static DoubleHash implicit_conv = new DoubleHash (100); - union4 = Invocation.MakeUnionSet (union5, union6, loc); - } - - return Invocation.MakeUnionSet (union3, union4, loc); - } - /// /// User-defined conversions /// @@ -923,42 +988,62 @@ namespace Mono.CSharp { Type target, Location loc, bool look_for_explicit) { - MethodGroupExpr union; Type source_type = source.Type; - MethodBase method = null; - - union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit); - if (union == null) - return null; - - Type most_specific_source, most_specific_target; - - most_specific_source = FindMostSpecificSource (union, source, look_for_explicit, loc); - if (most_specific_source == null) - return null; - - most_specific_target = FindMostSpecificTarget (union, target, look_for_explicit, loc); - if (most_specific_target == null) - return null; - - int count = 0; - - - foreach (MethodBase mb in union.Methods){ - ParameterData pd = Invocation.GetParameterData (mb); - MethodInfo mi = (MethodInfo) mb; + MethodInfo method = null; + Type most_specific_source = null; + Type most_specific_target = null; + + object o; + DoubleHash hash = look_for_explicit ? explicit_conv : implicit_conv; + + if (!(source is Constant) && hash.Lookup (source_type, target, out o)) { + method = (MethodInfo) o; + if (method != null) { + ParameterData pd = TypeManager.GetParameterData (method); + most_specific_source = pd.ParameterType (0); + most_specific_target = method.ReturnType; + } + } else { + IList ops = GetConversionOperators (ec, source, target, loc, look_for_explicit); + if (ops == null || ops.Count == 0) { + method = null; + goto skip; + } + + most_specific_source = FindMostSpecificSource (ec, ops, source, look_for_explicit, loc); + if (most_specific_source == null) { + method = null; + goto skip; + } - if (pd.ParameterType (0) == most_specific_source && - mi.ReturnType == most_specific_target) { - method = mb; - count++; + most_specific_target = FindMostSpecificTarget (ec, ops, target, look_for_explicit, loc); + if (most_specific_target == null) { + method = null; + goto skip; } + + int count = 0; + + foreach (MethodInfo m in ops) { + ParameterData pd = TypeManager.GetParameterData (m); + + if (pd.ParameterType (0) == most_specific_source && + m.ReturnType == most_specific_target) { + method = m; + count++; + } + } + if (count > 1) + method = null; + + skip: + if (!(source is Constant)) + hash.Insert (source_type, target, method); } - - if (method == null || count > 1) + + if (method == null) return null; - // // This will do the conversion to the best match that we // found. Now we need to perform an implict standard conversion @@ -974,7 +1059,7 @@ namespace Mono.CSharp { return null; Expression e; - e = new UserCast ((MethodInfo) method, source, loc); + e = new UserCast (method, source, loc); if (e.Type != target){ if (!look_for_explicit) e = ImplicitConversionStandard (ec, e, target, loc); @@ -991,9 +1076,8 @@ namespace Mono.CSharp { /// in a context that expects a `target_type'. /// static public Expression ImplicitConversion (EmitContext ec, Expression expr, - Type target_type, Location loc) + Type target_type, Location loc) { - Type expr_type = expr.Type; Expression e; if (target_type == null) @@ -1027,7 +1111,23 @@ namespace Mono.CSharp { Type expr_type = expr.Type; Expression e; - if (expr_type == target_type && !(expr is NullLiteral)) + if (expr.eclass == ExprClass.MethodGroup){ + if (!TypeManager.IsDelegateType (target_type)){ + return null; + } + + // + // Only allow anonymous method conversions on post ISO_1 + // + if (RootContext.Version != LanguageVersion.ISO_1){ + MethodGroupExpr mg = expr as MethodGroupExpr; + if (mg != null) + return ImplicitDelegateCreation.Create ( + ec, mg, target_type, false, loc); + } + } + + if (expr_type == target_type && expr_type != TypeManager.null_type) return expr; e = ImplicitNumericConversion (ec, expr, target_type, loc); @@ -1042,7 +1142,7 @@ namespace Mono.CSharp { target_type.IsSubclassOf (TypeManager.enum_type)) && expr is IntLiteral){ IntLiteral i = (IntLiteral) expr; - + if (i.Value == 0) return new EnumConstant ((Constant) expr, target_type); } @@ -1063,19 +1163,43 @@ namespace Mono.CSharp { } if (target_type.IsPointer) { - if (expr is NullLiteral) - return new EmptyCast (expr, target_type); + if (expr_type == TypeManager.null_type) + return new EmptyCast (NullPointer.Null, target_type); if (expr_type == TypeManager.void_ptr_type) return new EmptyCast (expr, target_type); } } + if (expr_type == TypeManager.anonymous_method_type){ + if (!TypeManager.IsDelegateType (target_type)){ + Report.Error (1660, loc, + "Cannot convert anonymous method to `{0}', since it is not a delegate", + TypeManager.CSharpName (target_type)); + return null; + } + + AnonymousMethod am = (AnonymousMethod) expr; + int errors = Report.Errors; + + Expression conv = am.Compatible (ec, target_type, false); + if (conv != null) + return conv; + + // + // We return something instead of null, to avoid + // the duplicate error, since am.Compatible would have + // reported that already + // + if (errors != Report.Errors) + return new EmptyCast (expr, target_type); + } + return null; } /// - /// Attemps to perform an implict constant conversion of the IntConstant + /// Attempts to perform an implicit constant conversion of the IntConstant /// into a different data type using casts (See Implicit Constant /// Expression Conversions) /// @@ -1118,7 +1242,7 @@ namespace Mono.CSharp { // // Possibly, we need to create a different 0 literal before passing // to EnumConstant - //n + // if (underlying == TypeManager.int64_type) e = new LongLiteral (0); else if (underlying == TypeManager.uint64_type) @@ -1126,20 +1250,34 @@ namespace Mono.CSharp { return new EnumConstant (e, target_type); } + + // + // If `target_type' is an interface and the type of `ic' implements the interface + // e.g. target_type is IComparable, IConvertible, IFormattable + // + if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type)) + return new BoxedCast (ic); + return null; } static public void Error_CannotImplicitConversion (Location loc, Type source, Type target) { - string msg = "Cannot convert implicitly from `"+ - TypeManager.CSharpName (source) + "' to `" + - TypeManager.CSharpName (target) + "'"; - - Report.Error (29, loc, msg); + if (source.Name == target.Name){ + Report.ExtraInformation (loc, + String.Format ( + "The type {0} has two conflicting definitions, one comes from {1} and the other from {2}", + source.Name, source.Assembly.FullName, target.Assembly.FullName)); + + } + Report.Error (29, loc, "Cannot convert implicitly from {0} to `{1}'", + source == TypeManager.anonymous_method_type ? + "anonymous method" : "`" + TypeManager.CSharpName (source) + "'", + TypeManager.CSharpName (target)); } /// - /// Attemptes to implicityly convert `target' into `type', using + /// Attempts to implicitly convert `source' into `target_type', using /// ImplicitConversion. If there is no implicit conversion, then /// an error is signaled /// @@ -1152,10 +1290,15 @@ namespace Mono.CSharp { if (e != null) return e; - if (source is DoubleLiteral && target_type == TypeManager.float_type){ - Report.Error (664, loc, - "Double literal cannot be implicitly converted to " + - "float type, use F suffix to create a float literal"); + if (source is DoubleLiteral) { + if (target_type == TypeManager.float_type) { + Error_664 (loc, "float", "f"); + return null; + } + if (target_type == TypeManager.decimal_type) { + Error_664 (loc, "decimal", "m"); + return null; + } } if (source is Constant){ @@ -1170,6 +1313,12 @@ namespace Mono.CSharp { return null; } + static void Error_664 (Location loc, string type, string suffix) { + Report.Error (664, loc, + "Literal of type double cannot be implicitly converted to type '{0}'. Add suffix '{1}' to create a literal of this type", + type, suffix); + } + /// /// Performs the explicit numeric conversions /// @@ -1187,7 +1336,7 @@ namespace Mono.CSharp { if (TypeManager.IsEnumType (real_target_type)) real_target_type = TypeManager.EnumToUnderlying (real_target_type); - if (ImplicitStandardConversionExists (expr, real_target_type)){ + if (ImplicitStandardConversionExists (ec, expr, real_target_type)){ Expression ce = ImplicitConversionStandard (ec, expr, real_target_type, loc); if (real_target_type != target_type) @@ -1353,9 +1502,11 @@ namespace Mono.CSharp { return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8); if (real_target_type == TypeManager.char_type) return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_CH); + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr, true); } else if (expr_type == TypeManager.double_type){ // - // From double to byte, byte, short, + // From double to sbyte, byte, short, // ushort, int, uint, long, ulong, // char, float or decimal // @@ -1379,10 +1530,26 @@ namespace Mono.CSharp { return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH); if (real_target_type == TypeManager.float_type) return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_R4); - } - - // decimal is taken care of by the op_Explicit methods. - + if (real_target_type == TypeManager.decimal_type) + return new CastToDecimal (ec, expr, true); + } else if (expr_type == TypeManager.decimal_type) { + // + // From decimal to sbyte, byte, short, ushort, int, uint, + // long, ulong, char, double or float + // + if (real_target_type == TypeManager.sbyte_type || + real_target_type == TypeManager.byte_type || + real_target_type == TypeManager.short_type || + real_target_type == TypeManager.ushort_type || + real_target_type == TypeManager.int32_type || + real_target_type == TypeManager.uint32_type || + real_target_type == TypeManager.int64_type || + real_target_type == TypeManager.uint64_type || + real_target_type == TypeManager.char_type || + real_target_type == TypeManager.double_type || + real_target_type == TypeManager.float_type) + return new CastFromDecimal (ec, expr, target_type); + } return null; } @@ -1493,6 +1660,13 @@ namespace Mono.CSharp { if (source_type == TypeManager.object_type && !target_is_value_type) return new ClassCast (source, target_type); + // + // Unboxing conversion. + // + if (((source_type == TypeManager.enum_type && + !(source is EmptyCast)) || + source_type == TypeManager.value_type) && target_is_value_type) + return new UnboxCast (source, target_type); // // From any class S to any class-type T, provided S is a base class of T @@ -1587,7 +1761,7 @@ namespace Mono.CSharp { /// type is expr.Type to `target_type'. /// static public Expression ExplicitConversion (EmitContext ec, Expression expr, - Type target_type, Location loc) + Type target_type, Location loc) { Type expr_type = expr.Type; Type original_expr_type = expr_type; @@ -1626,18 +1800,19 @@ namespace Mono.CSharp { // // Unboxing conversion. // - if (expr_type == TypeManager.object_type && target_type.IsValueType){ - if (expr is NullLiteral){ - Report.Error (37, loc, "Cannot convert null to value type `" + - TypeManager.CSharpName (target_type) + "'"); - return null; - } + if (expr_type == TypeManager.object_type && target_type.IsValueType) return new UnboxCast (expr, target_type); - } - ne = ExplicitReferenceConversion (expr, target_type); - if (ne != null) - return ne; + // + // Skip the ExplicitReferenceConversion because we can not convert + // from Null to a ValueType, and ExplicitReference wont check against + // null literal explicitly + // + if (expr_type != TypeManager.null_type){ + ne = ExplicitReferenceConversion (expr, target_type); + if (ne != null) + return ne; + } if (ec.InUnsafe){ if (target_type.IsPointer){ @@ -1645,13 +1820,15 @@ namespace Mono.CSharp { return new EmptyCast (expr, target_type); if (expr_type == TypeManager.sbyte_type || - expr_type == TypeManager.byte_type || expr_type == TypeManager.short_type || - expr_type == TypeManager.ushort_type || expr_type == TypeManager.int32_type || + expr_type == TypeManager.int64_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_I); + + if (expr_type == TypeManager.ushort_type || expr_type == TypeManager.uint32_type || expr_type == TypeManager.uint64_type || - expr_type == TypeManager.int64_type) + expr_type == TypeManager.byte_type) return new OpcodeCast (expr, target_type, OpCodes.Conv_U); } if (expr_type.IsPointer){ @@ -1695,11 +1872,17 @@ namespace Mono.CSharp { } } } - + ne = ExplicitUserConversion (ec, expr, target_type, loc); if (ne != null) return ne; + if (expr is NullLiteral){ + Report.Error (37, loc, "Cannot convert null to value type `" + + TypeManager.CSharpName (target_type) + "'"); + return null; + } + Error_CannotConvertType (loc, original_expr_type, target_type); return null; }