X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=09b56abea571f6d9475bc7913a03054cebce792f;hb=8dd8c3d59a76f59d85e0bcb7ca4ca6cb5c382188;hp=32fb11b2ba4c12c1b33ba544451092d9edd80286;hpb=6f0096570b15a5d2dd35f549587540d113faaa2f;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 32fb11b2ba4..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) + 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; } @@ -266,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); @@ -278,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) || @@ -296,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); @@ -308,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); @@ -325,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); @@ -335,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); @@ -349,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 @@ -356,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 @@ -366,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) || @@ -383,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 @@ -401,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); @@ -422,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; @@ -433,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) || @@ -449,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) || @@ -464,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) || @@ -475,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) || @@ -488,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) || @@ -498,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) || @@ -510,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) || @@ -519,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) || @@ -539,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; @@ -597,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; - foreach (Type t in types){ - priv_fmet_param.SetType (t); - + if (types.Count == 1) + return (Type) types [0]; + + 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); } // @@ -731,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); } // @@ -808,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); } /// @@ -846,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; + ArrayList ret = new ArrayList (4); - op_name = "op_Implicit"; - - 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 /// @@ -922,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; + } + + most_specific_target = FindMostSpecificTarget (ec, ops, target, look_for_explicit, loc); + if (most_specific_target == null) { + method = null; + goto skip; + } - if (pd.ParameterType (0) == most_specific_source && - mi.ReturnType == most_specific_target) { - method = mb; - count++; + 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 @@ -973,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); @@ -1027,17 +1113,21 @@ namespace Mono.CSharp { if (expr.eclass == ExprClass.MethodGroup){ if (!TypeManager.IsDelegateType (target_type)){ - Report.Error (428, loc, - String.Format ( - "Cannot convert method group to `{0}', since it is not a delegate", - TypeManager.CSharpName (target_type))); return null; } - - return ImplicitDelegateCreation.Create (ec, (MethodGroupExpr) expr, target_type, loc); + + // + // 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 is NullLiteral)) + + if (expr_type == target_type && expr_type != TypeManager.null_type) return expr; e = ImplicitNumericConversion (ec, expr, target_type, loc); @@ -1052,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); } @@ -1073,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) /// @@ -1128,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) @@ -1136,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 /// @@ -1162,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){ @@ -1180,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 /// @@ -1197,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) @@ -1363,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 // @@ -1389,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; } @@ -1643,37 +1800,35 @@ namespace Mono.CSharp { // // Unboxing conversion. // - if (expr_type == TypeManager.object_type && target_type.IsValueType){ - if (expr is NullLiteral){ - // - // Skip the ExplicitReferenceConversion because we can not convert - // from Null to a ValueType, and ExplicitReference wont check against - // null literal explicitly - // - goto skip_explicit; - } + if (expr_type == TypeManager.object_type && target_type.IsValueType) return new UnboxCast (expr, target_type); + // + // 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; } - ne = ExplicitReferenceConversion (expr, target_type); - if (ne != null) - return ne; - - skip_explicit: if (ec.InUnsafe){ if (target_type.IsPointer){ if (expr_type.IsPointer) 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){ @@ -1727,7 +1882,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (target_type) + "'"); return null; } - + Error_CannotConvertType (loc, original_expr_type, target_type); return null; }