X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fmcs%2Fconvert.cs;h=09b56abea571f6d9475bc7913a03054cebce792f;hb=8dd8c3d59a76f59d85e0bcb7ca4ca6cb5c382188;hp=6630affc4323a36a3588721f81c41e2cd62c7985;hpb=699e59742843044f6efa1726b7cb64f19d909e64;p=mono.git diff --git a/mcs/mcs/convert.cs b/mcs/mcs/convert.cs index 6630affc432..09b56abea57 100644 --- a/mcs/mcs/convert.cs +++ b/mcs/mcs/convert.cs @@ -64,7 +64,7 @@ namespace Mono.CSharp { if (expr_type.IsValueType) return new BoxedCast (expr); if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){ - if (target_type == TypeManager.anonymous_method_type) + if (expr_type == TypeManager.anonymous_method_type) return null; return new EmptyCast (expr, target_type); } @@ -73,7 +73,7 @@ namespace Mono.CSharp { } 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; @@ -95,9 +95,9 @@ namespace Mono.CSharp { // Always ensure that the code here and there is in sync // from the null type to any reference-type. - if (expr is NullLiteral){ + if (expr_type == TypeManager.null_type){ if (target_type.IsPointer) - return NullPointer.Null; + return new EmptyCast (NullPointer.Null, target_type); if (!target_type.IsValueType) return new NullCast (expr, target_type); @@ -198,6 +198,16 @@ namespace Mono.CSharp { // 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; + } + if (TypeManager.ImplementsInterface (expr_type, target_type)) return true; } @@ -245,9 +255,13 @@ namespace Mono.CSharp { return true; // from the null type to any reference-type. - if (expr is NullLiteral && !target_type.IsValueType && !TypeManager.IsEnumType (target_type)) - return true; - + if (expr_type == TypeManager.null_type){ + if (target_type.IsPointer) + return true; + + if (!target_type.IsValueType) + return true; + } return false; } @@ -289,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); @@ -301,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) || @@ -319,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); @@ -331,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); @@ -348,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); @@ -358,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); @@ -372,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 @@ -379,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 @@ -389,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) || @@ -406,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 @@ -458,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) || @@ -474,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) || @@ -489,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) || @@ -500,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) || @@ -513,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) || @@ -523,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) || @@ -535,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) || @@ -544,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) || @@ -564,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; @@ -622,6 +672,13 @@ 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; @@ -630,23 +687,15 @@ namespace Mono.CSharp { return false; AnonymousMethod am = (AnonymousMethod) expr; - int errors = Report.Errors; 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 @@ -655,31 +704,40 @@ namespace Mono.CSharp { { 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 (ec, 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 @@ -688,77 +746,63 @@ namespace Mono.CSharp { { 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 (ec, 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 (EmitContext ec, MethodGroupExpr me, + 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 (ec, priv_fms_expr, source_type)) - src_types_set.Add (param_type); - else { - if (ImplicitStandardConversionExists (ec, source, param_type)) - src_types_set.Add (param_type); - } - } else { - // - // Only if S is encompassed by param_type - // - if (ImplicitStandardConversionExists (ec, source, param_type)) - src_types_set.Add (param_type); - } + src_types_set.Add (param_type); } // @@ -784,59 +828,25 @@ namespace Mono.CSharp { else 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 (EmitContext ec, MethodGroupExpr me, + 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 (ec, priv_fms_expr, target)) - tgt_types_set.Add (ret_type); - else { - priv_fms_expr.SetType (target); - if (ImplicitStandardConversionExists (ec, 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 (ec, priv_fms_expr, target)) - tgt_types_set.Add (ret_type); - } + tgt_types_set.Add (ret_type); } // @@ -845,13 +855,17 @@ 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 (ec, priv_fmt_expr, target)) + if (ImplicitStandardConversionExists (ec, expr, target)) candidate_set.Add (ret_type); } + EmptyExpression.Release (expr); + if (candidate_set.Count != 0) return FindMostEncompassingType (ec, candidate_set); } @@ -883,82 +897,90 @@ namespace Mono.CSharp { return UserDefinedConversion (ec, source, target, loc, true); } - static DoubleHash explicit_conv = new DoubleHash (100); - static DoubleHash implicit_conv = new DoubleHash (100); + 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; - object r; - if ((look_for_explicit ? explicit_conv : implicit_conv).Lookup (source_type, target_type, out r)) - return (MethodGroupExpr) r; - - 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"; - - 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); - - union4 = Invocation.MakeUnionSet (union5, union6, loc); - } - - MethodGroupExpr ret = Invocation.MakeUnionSet (union3, union4, loc); - (look_for_explicit ? explicit_conv : implicit_conv).Insert (source_type, target_type, ret); return ret; } - + + static DoubleHash explicit_conv = new DoubleHash (100); + static DoubleHash implicit_conv = new DoubleHash (100); + /// /// User-defined conversions /// @@ -966,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 (ec, union, source, look_for_explicit, loc); - if (most_specific_source == null) - return null; - - most_specific_target = FindMostSpecificTarget (ec, 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 @@ -1017,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); @@ -1080,11 +1122,12 @@ namespace Mono.CSharp { if (RootContext.Version != LanguageVersion.ISO_1){ MethodGroupExpr mg = expr as MethodGroupExpr; if (mg != null) - return ImplicitDelegateCreation.Create (ec, mg, target_type, loc); + 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); @@ -1120,8 +1163,8 @@ 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); @@ -1156,7 +1199,7 @@ namespace Mono.CSharp { } /// - /// 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) /// @@ -1199,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) @@ -1207,11 +1250,26 @@ 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) { + 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) + "'", @@ -1219,7 +1277,7 @@ namespace Mono.CSharp { } /// - /// 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 /// @@ -1232,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){ @@ -1250,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 /// @@ -1433,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 // @@ -1459,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; } @@ -1713,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){ @@ -1797,7 +1882,7 @@ namespace Mono.CSharp { TypeManager.CSharpName (target_type) + "'"); return null; } - + Error_CannotConvertType (loc, original_expr_type, target_type); return null; }