X-Git-Url: http://wien.tomnetworks.com/gitweb/?a=blobdiff_plain;f=mcs%2Fgmcs%2Fconvert.cs;h=c6c625d01ca228b6f539f0eb424fa568c590f285;hb=4a9ecda075e6914d55f4621a87073299b3baa1e3;hp=7ac630671a57e9ba6f032bd9bdf1449b0d02d275;hpb=675ed0f76f4c711f4d1d38183bda62c07ad9dfa6;p=mono.git diff --git a/mcs/gmcs/convert.cs b/mcs/gmcs/convert.cs index 7ac630671a5..c6c625d01ca 100644 --- a/mcs/gmcs/convert.cs +++ b/mcs/gmcs/convert.cs @@ -29,13 +29,6 @@ namespace Mono.CSharp { // public static EmitContext ConstantEC = null; - static public void Error_CannotConvertType (Location loc, Type source, Type target) - { - Report.Error (30, loc, "Cannot convert type '" + - TypeManager.CSharpName (source) + "' to '" + - TypeManager.CSharpName (target) + "'"); - } - static Expression TypeParameter_to_Null (Expression expr, Type target_type, Location loc) { @@ -88,7 +81,7 @@ namespace Mono.CSharp { if (gc == null) { if (target_type == TypeManager.object_type) - return new BoxedCast (expr); + return new BoxedCast (expr, target_type); return null; } @@ -97,15 +90,15 @@ namespace Mono.CSharp { Type base_type = TypeParam_EffectiveBaseType (ec, gc); if (TypeManager.IsSubclassOf (base_type, target_type)) - return new BoxedCast (expr, target_type); + return new ClassCast (expr, target_type); if (target_type.IsInterface) { if (TypeManager.ImplementsInterface (base_type, target_type)) - return new BoxedCast (expr, target_type); + return new ClassCast (expr, target_type); foreach (Type t in gc.InterfaceConstraints) { if (TypeManager.IsSubclassOf (t, target_type)) - return new BoxedCast (expr, target_type); + return new ClassCast (expr, target_type); } } @@ -113,7 +106,7 @@ namespace Mono.CSharp { if (!t.IsGenericParameter) continue; if (TypeManager.IsSubclassOf (t, target_type)) - return new BoxedCast (expr, target_type); + return new ClassCast (expr, target_type); } return null; @@ -148,7 +141,7 @@ namespace Mono.CSharp { return null; if (TypeManager.IsValueType (expr_type)) - return new BoxedCast (expr); + return new BoxedCast (expr, target_type); if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){ if (expr_type == TypeManager.anonymous_method_type) return null; @@ -158,7 +151,7 @@ namespace Mono.CSharp { return null; } else if (target_type == TypeManager.value_type) { if (TypeManager.IsValueType (expr_type)) - return new BoxedCast (expr); + return new BoxedCast (expr, target_type); if (expr_type == TypeManager.null_type) return new NullCast (expr, target_type); @@ -170,7 +163,7 @@ namespace Mono.CSharp { // a boxing conversion // if (expr_type.IsEnum || expr_type.IsGenericParameter) - return new BoxedCast (expr); + return new BoxedCast (expr, target_type); return new EmptyCast (expr, target_type); } @@ -268,6 +261,9 @@ namespace Mono.CSharp { // public static bool ImplicitReferenceConversionExists (EmitContext ec, Expression expr, Type target_type) { + if (target_type.IsValueType) + return false; + Type expr_type = expr.Type; if (expr_type.IsGenericParameter) @@ -372,7 +368,7 @@ namespace Mono.CSharp { /// target_type or null if an implicit conversion is not possible. /// static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr, - Type target_type, Location loc) + Type target_type) { Type expr_type = expr.Type; @@ -395,7 +391,7 @@ namespace Mono.CSharp { // long v = ((LongConstant) expr).Value; if (v >= 0) - return new ULongConstant ((ulong) v); + return new ULongConstant ((ulong) v, expr.Location); } } @@ -416,7 +412,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.byte_type){ // // From byte to short, ushort, int, uint, long, ulong, float, double, decimal @@ -436,7 +432,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.short_type){ // @@ -451,7 +447,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.ushort_type){ // @@ -471,7 +467,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.int32_type){ // // From int to long, float, double, decimal @@ -483,7 +479,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.uint32_type){ // // From uint to long, ulong, float, double, decimal @@ -499,7 +495,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.int64_type){ // // From long/ulong to float, double @@ -509,7 +505,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.uint64_type){ // // From ulong to float, double @@ -521,7 +517,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.char_type){ // // From char to ushort, int, uint, long, ulong, float, double, decimal @@ -539,7 +535,7 @@ namespace Mono.CSharp { 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); + return new CastToDecimal (expr); } else if (expr_type == TypeManager.float_type){ // // float to double @@ -551,7 +547,6 @@ namespace Mono.CSharp { return null; } - /// /// Same as ImplicitStandardConversionExists except that it also looks at /// implicit user defined conversions - needed for overload resolution @@ -579,9 +574,7 @@ namespace Mono.CSharp { public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target) { - Expression dummy = ImplicitUserConversion ( - ec, new EmptyExpression (source), target, Location.Null); - return dummy != null; + return ImplicitUserConversion (ec, new EmptyExpression (source), target, Location.Null) != null; } /// @@ -737,7 +730,7 @@ namespace Mono.CSharp { if (value >= SByte.MinValue && value <= SByte.MaxValue) return true; } else if (target_type == TypeManager.byte_type){ - if (Byte.MinValue >= 0 && value <= Byte.MaxValue) + if (value >= 0 && value <= Byte.MaxValue) return true; } else if (target_type == TypeManager.short_type){ if (value >= Int16.MinValue && value <= Int16.MaxValue) @@ -769,7 +762,7 @@ namespace Mono.CSharp { // we just inline it // long v = ((LongConstant) expr).Value; - if (v > 0) + if (v >= 0) return true; } @@ -899,8 +892,7 @@ namespace Mono.CSharp { /// for explicit and implicit conversion operators. /// static public Type FindMostSpecificSource (EmitContext ec, IList list, - Expression source, bool apply_explicit_conv_rules, - Location loc) + Expression source, bool apply_explicit_conv_rules) { ArrayList src_types_set = new ArrayList (); @@ -946,8 +938,7 @@ namespace Mono.CSharp { /// Finds the most specific target Tx according to section 13.4.4 /// static public Type FindMostSpecificTarget (EmitContext ec, IList list, - Type target, bool apply_explicit_conv_rules, - Location loc) + Type target, bool apply_explicit_conv_rules) { ArrayList tgt_types_set = new ArrayList (); @@ -1053,42 +1044,60 @@ namespace Mono.CSharp { } /// - /// 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 + /// Compute the user-defined conversion operator from source_type to target_type. + /// `look_for_explicit' controls whether we should also include the list of explicit operators /// - static IList GetConversionOperators (EmitContext ec, - Expression source, Type target_type, - Location loc, bool look_for_explicit) + static MethodInfo GetConversionOperator (EmitContext ec, Expression source, Type target_type, bool look_for_explicit) { - ArrayList ret = new ArrayList (4); + ArrayList ops = new ArrayList (4); Type source_type = source.Type; 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); + AddConversionOperators (ec, ops, source, target_type, look_for_explicit, + Expression.MethodLookup (ec, source_type, "op_Implicit", Location.Null) as MethodGroupExpr); if (look_for_explicit) { - AddConversionOperators (ec, ret, source, target_type, look_for_explicit, + AddConversionOperators (ec, ops, source, target_type, look_for_explicit, Expression.MethodLookup ( - ec, source_type, "op_Explicit", loc) as MethodGroupExpr); + ec, source_type, "op_Explicit", Location.Null) as MethodGroupExpr); } } 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); + AddConversionOperators (ec, ops, source, target_type, look_for_explicit, + Expression.MethodLookup (ec, target_type, "op_Implicit", Location.Null) as MethodGroupExpr); if (look_for_explicit) { - AddConversionOperators (ec, ret, source, target_type, look_for_explicit, + AddConversionOperators (ec, ops, source, target_type, look_for_explicit, Expression.MethodLookup ( - ec, target_type, "op_Explicit", loc) as MethodGroupExpr); + ec, target_type, "op_Explicit", Location.Null) as MethodGroupExpr); } } - return ret; + if (ops.Count == 0) + return null; + + Type most_specific_source = FindMostSpecificSource (ec, ops, source, look_for_explicit); + if (most_specific_source == null) + return null; + + Type most_specific_target = FindMostSpecificTarget (ec, ops, target_type, look_for_explicit); + if (most_specific_target == null) + return null; + + MethodInfo method = null; + + foreach (MethodInfo m in ops) { + if (m.ReturnType != most_specific_target) + continue; + if (TypeManager.GetParameterData (m).ParameterType (0) != most_specific_source) + continue; + // Ambiguous: more than one conversion operator satisfies the signature. + if (method != null) + return null; + method = m; + } + + return method; } static DoubleHash explicit_conv = new DoubleHash (100); @@ -1103,8 +1112,6 @@ namespace Mono.CSharp { { Type source_type = source.Type; MethodInfo method = null; - Type most_specific_source = null; - Type most_specific_target = null; if (TypeManager.IsNullableType (source_type) && TypeManager.IsNullableType (target)) return new Nullable.LiftedConversion ( @@ -1115,45 +1122,8 @@ namespace Mono.CSharp { 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; - } - - 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: + method = GetConversionOperator (ec, source, target, look_for_explicit); if (!(source is Constant)) hash.Insert (source_type, target, method); } @@ -1161,6 +1131,8 @@ namespace Mono.CSharp { if (method == null) return null; + Type most_specific_source = TypeManager.GetParameterData (method).ParameterType (0); + // // This will do the conversion to the best match that we // found. Now we need to perform an implict standard conversion @@ -1259,7 +1231,7 @@ namespace Mono.CSharp { if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type)) return expr; - e = ImplicitNumericConversion (ec, expr, target_type, loc); + e = ImplicitNumericConversion (ec, expr, target_type); if (e != null) return e; @@ -1288,16 +1260,13 @@ namespace Mono.CSharp { if (target_type.IsPointer){ if (TypeManager.GetElementType(target_type) == TypeManager.GetElementType(expr_type)) return expr; + + //return null; } } - if (target_type.IsPointer) { - 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.null_type && target_type.IsPointer) + return new EmptyCast (NullPointer.Null, target_type); } if (expr_type == TypeManager.anonymous_method_type){ @@ -1338,19 +1307,19 @@ namespace Mono.CSharp { if (target_type == TypeManager.sbyte_type){ if (value >= SByte.MinValue && value <= SByte.MaxValue) - return new SByteConstant ((sbyte) value); + return new SByteConstant ((sbyte) value, ic.Location); } else if (target_type == TypeManager.byte_type){ if (value >= Byte.MinValue && value <= Byte.MaxValue) - return new ByteConstant ((byte) value); + return new ByteConstant ((byte) value, ic.Location); } else if (target_type == TypeManager.short_type){ if (value >= Int16.MinValue && value <= Int16.MaxValue) - return new ShortConstant ((short) value); + return new ShortConstant ((short) value, ic.Location); } else if (target_type == TypeManager.ushort_type){ if (value >= UInt16.MinValue && value <= UInt16.MaxValue) - return new UShortConstant ((ushort) value); + return new UShortConstant ((ushort) value, ic.Location); } else if (target_type == TypeManager.uint32_type){ if (value >= 0) - return new UIntConstant ((uint) value); + return new UIntConstant ((uint) value, ic.Location); } else if (target_type == TypeManager.uint64_type){ // // we can optimize this case: a positive int32 @@ -1358,11 +1327,11 @@ namespace Mono.CSharp { // to do it. // if (value >= 0) - return new ULongConstant ((ulong) value); + return new ULongConstant ((ulong) value, ic.Location); } else if (target_type == TypeManager.double_type) - return new DoubleConstant ((double) value); + return new DoubleConstant ((double) value, ic.Location); else if (target_type == TypeManager.float_type) - return new FloatConstant ((float) value); + return new FloatConstant ((float) value, ic.Location); if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){ Type underlying = TypeManager.EnumToUnderlying (target_type); @@ -1373,9 +1342,9 @@ namespace Mono.CSharp { // to EnumConstant // if (underlying == TypeManager.int64_type) - e = new LongLiteral (0); + e = new LongLiteral (0, ic.Location); else if (underlying == TypeManager.uint64_type) - e = new ULongLiteral (0); + e = new ULongLiteral (0, ic.Location); return new EnumConstant (e, target_type); } @@ -1385,26 +1354,11 @@ namespace Mono.CSharp { // e.g. target_type is IComparable, IConvertible, IFormattable // if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type)) - return new BoxedCast (ic); + return new BoxedCast (ic, target_type); return null; } - static public void Error_CannotImplicitConversion (Location loc, Type source, Type target) - { - if (source.FullName == target.FullName){ - 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 implicitly convert type {0} to `{1}'", - source == TypeManager.anonymous_method_type ? - "anonymous method" : "`" + TypeManager.CSharpName (source) + "'", - TypeManager.CSharpName (target)); - } - /// /// Attempts to implicitly convert `source' into `target_type', using /// ImplicitConversion. If there is no implicit conversion, then @@ -1433,15 +1387,7 @@ namespace Mono.CSharp { } } - if (source is Constant){ - Constant c = (Constant) source; - - Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type); - return null; - } - - Error_CannotImplicitConversion (loc, source.Type, target_type); - + source.Error_ValueCannotBeConverted (loc, target_type, false); return null; } @@ -1454,162 +1400,145 @@ namespace Mono.CSharp { /// /// Performs the explicit numeric conversions /// - static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc) + public static Expression ExplicitNumericConversion (Expression expr, Type target_type) { Type expr_type = expr.Type; - - // - // If we have an enumeration, extract the underlying type, - // use this during the comparison, but wrap around the original - // target_type - // Type real_target_type = target_type; - if (TypeManager.IsEnumType (real_target_type)) - real_target_type = TypeManager.EnumToUnderlying (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) - return new EmptyCast (ce, target_type); - return ce; - } - if (expr_type == TypeManager.sbyte_type){ // // From sbyte to byte, ushort, uint, ulong, char // if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U1); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U2); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U4); if (real_target_type == TypeManager.uint64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_U8); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I1_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.I1_CH); } else if (expr_type == TypeManager.byte_type){ // // From byte to sbyte and char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U1_I1); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U1_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.U1_CH); } else if (expr_type == TypeManager.short_type){ // // From short to sbyte, byte, ushort, uint, ulong, char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U1); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U2); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U4); if (real_target_type == TypeManager.uint64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_U8); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.I2_CH); } else if (expr_type == TypeManager.ushort_type){ // // From ushort to sbyte, byte, short, char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_I2); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.U2_CH); } else if (expr_type == TypeManager.int32_type){ // // From int to sbyte, byte, short, ushort, uint, ulong, char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_I2); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U2); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U4); if (real_target_type == TypeManager.uint64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_U8); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.I4_CH); } else if (expr_type == TypeManager.uint32_type){ // // From uint to sbyte, byte, short, ushort, int, char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I2); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_U2); if (real_target_type == TypeManager.int32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_I4); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U4_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.U4_CH); } else if (expr_type == TypeManager.int64_type){ // // From long to sbyte, byte, short, ushort, int, uint, ulong, char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I2); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U2); if (real_target_type == TypeManager.int32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_I4); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U4); if (real_target_type == TypeManager.uint64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_U8); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.I8_CH); } else if (expr_type == TypeManager.uint64_type){ // // From ulong to sbyte, byte, short, ushort, int, uint, long, char // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I2); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_U2); if (real_target_type == TypeManager.int32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I4); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_U4); if (real_target_type == TypeManager.int64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_I8); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.U8_CH); + return new ConvCast (expr, target_type, ConvCast.Mode.U8_CH); } else if (expr_type == TypeManager.char_type){ // // From char to sbyte, byte, short // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.CH_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.CH_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.CH_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.CH_I2); } else if (expr_type == TypeManager.float_type){ // // From float to sbyte, byte, short, @@ -1617,25 +1546,25 @@ namespace Mono.CSharp { // or decimal // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I2); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U2); if (real_target_type == TypeManager.int32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I4); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_U4); if (real_target_type == TypeManager.int64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_I8); if (real_target_type == TypeManager.uint64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_U8); + return new ConvCast (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); + return new ConvCast (expr, target_type, ConvCast.Mode.R4_CH); if (real_target_type == TypeManager.decimal_type) - return new CastToDecimal (ec, expr, true); + return new CastToDecimal (expr, true); } else if (expr_type == TypeManager.double_type){ // // From double to sbyte, byte, short, @@ -1643,44 +1572,29 @@ namespace Mono.CSharp { // char, float or decimal // if (real_target_type == TypeManager.sbyte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I1); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I1); if (real_target_type == TypeManager.byte_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U1); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U1); if (real_target_type == TypeManager.short_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I2); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I2); if (real_target_type == TypeManager.ushort_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U2); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U2); if (real_target_type == TypeManager.int32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I4); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I4); if (real_target_type == TypeManager.uint32_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U4); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U4); if (real_target_type == TypeManager.int64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_I8); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_I8); if (real_target_type == TypeManager.uint64_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_U8); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_U8); if (real_target_type == TypeManager.char_type) - return new ConvCast (ec, expr, target_type, ConvCast.Mode.R8_CH); + return new ConvCast (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); + return new ConvCast (expr, target_type, ConvCast.Mode.R8_R4); if (real_target_type == TypeManager.decimal_type) - return new CastToDecimal (ec, expr, true); + return new CastToDecimal (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 new CastFromDecimal (expr, target_type).Resolve (); } return null; } @@ -1913,56 +1827,40 @@ namespace Mono.CSharp { /// Performs an explicit conversion of the expression `expr' whose /// type is expr.Type to `target_type'. /// - static public Expression ExplicitConversion (EmitContext ec, Expression expr, + static public Expression ExplicitConversionCore (EmitContext ec, Expression expr, Type target_type, Location loc) { Type expr_type = expr.Type; - Type original_expr_type = expr_type; - - if (expr_type.IsSubclassOf (TypeManager.enum_type)){ - if (target_type == TypeManager.enum_type || - target_type == TypeManager.object_type) { - if (expr is EnumConstant) - expr = ((EnumConstant) expr).Child; - // We really need all these casts here .... :-( - expr = new BoxedCast (new EmptyCast (expr, expr_type)); - return new EmptyCast (expr, target_type); - } else if ((expr_type == TypeManager.enum_type) && target_type.IsValueType && - target_type.IsSubclassOf (TypeManager.enum_type)) - return new UnboxCast (expr, target_type); - - // - // Notice that we have kept the expr_type unmodified, which is only - // used later on to - if (expr is EnumConstant) - expr = ((EnumConstant) expr).Child; - else - expr = new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)); - expr_type = expr.Type; - } - int errors = Report.Errors; + // Explicit conversion includes implicit conversion and it used for enum underlying types too Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc); - if (Report.Errors > errors) - return null; - if (ne != null) return ne; - if (TypeManager.IsNullableType (expr.Type) && TypeManager.IsNullableType (target_type)) + // + // Unboxing conversions; only object types can be convertible to enum + // + if (expr_type == TypeManager.object_type && target_type.IsValueType || expr_type == TypeManager.enum_type) + return new UnboxCast (expr, target_type); + + if (TypeManager.IsEnumType (expr_type)) { + if (expr is EnumConstant) + return ExplicitConversionCore (ec, ((EnumConstant) expr).Child, target_type, loc); + + return ExplicitConversionCore (ec, new EmptyCast (expr, TypeManager.EnumToUnderlying (expr_type)), target_type, loc); + } + + if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type)) return new Nullable.LiftedConversion ( expr, target_type, false, true, loc).Resolve (ec); - ne = ExplicitNumericConversion (ec, expr, target_type, loc); + if (TypeManager.IsEnumType (target_type)) + return new EmptyCast (ExplicitConversionCore (ec, expr, TypeManager.EnumToUnderlying (target_type), loc), target_type); + + ne = ExplicitNumericConversion (expr, target_type); if (ne != null) return ne; - // - // Unboxing conversion. - // - 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 @@ -1975,75 +1873,58 @@ namespace Mono.CSharp { } 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.short_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.byte_type) - return new OpcodeCast (expr, target_type, OpCodes.Conv_U); - } - if (expr_type.IsPointer){ - Expression e = null; - - if (target_type == TypeManager.sbyte_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_I1); - else if (target_type == TypeManager.byte_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_U1); - else if (target_type == TypeManager.short_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_I2); - else if (target_type == TypeManager.ushort_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_U2); - else if (target_type == TypeManager.int32_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_I4); - else if (target_type == TypeManager.uint32_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_U4); - else if (target_type == TypeManager.uint64_type) - e = new OpcodeCast (expr, target_type, OpCodes.Conv_U8); - else if (target_type == TypeManager.int64_type){ - e = new OpcodeCast (expr, target_type, OpCodes.Conv_I8); - } + ne = ExplicitUnsafe (expr, target_type); + if (ne != null) + return ne; + } - if (e != null){ - Expression ci, ce; + ne = ExplicitUserConversion (ec, expr, target_type, loc); + if (ne != null) + return ne; - ci = ImplicitConversionStandard (ec, e, target_type, loc); + return null; + } - if (ci != null) - return ci; + public static Expression ExplicitUnsafe (Expression expr, Type target_type) + { + Type expr_type = expr.Type; - ce = ExplicitNumericConversion (ec, e, target_type, loc); - if (ce != null) - return ce; - // - // We should always be able to go from an uint32 - // implicitly or explicitly to the other integral - // types - // - throw new Exception ("Internal compiler error"); - } - } + if (target_type.IsPointer){ + if (expr_type.IsPointer) + return new EmptyCast (expr, target_type); + + if (expr_type == TypeManager.sbyte_type || + expr_type == TypeManager.short_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.byte_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_U); } - ne = ExplicitUserConversion (ec, expr, target_type, loc); - if (ne != null) - return ne; - - if (expr is NullLiteral){ - Report.Error (37, loc, "Cannot convert null to `{0}' because it is a value type", - TypeManager.CSharpName (target_type)); - return null; + if (expr_type.IsPointer){ + if (target_type == TypeManager.sbyte_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_I1); + else if (target_type == TypeManager.byte_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_U1); + else if (target_type == TypeManager.short_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_I2); + else if (target_type == TypeManager.ushort_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_U2); + else if (target_type == TypeManager.int32_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_I4); + else if (target_type == TypeManager.uint32_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_U4); + else if (target_type == TypeManager.uint64_type) + return new OpcodeCast (expr, target_type, OpCodes.Conv_U8); + else if (target_type == TypeManager.int64_type){ + return new OpcodeCast (expr, target_type, OpCodes.Conv_I8); + } } - - Error_CannotConvertType (loc, original_expr_type, target_type); return null; } @@ -2065,7 +1946,7 @@ namespace Mono.CSharp { return new Nullable.LiftedConversion ( expr, target_type, false, true, l).Resolve (ec); - ne = ExplicitNumericConversion (ec, expr, target_type, l); + ne = ExplicitNumericConversion (expr, target_type); if (ne != null) return ne; @@ -2073,7 +1954,25 @@ namespace Mono.CSharp { if (ne != null) return ne; - Error_CannotConvertType (l, expr.Type, target_type); + if (ec.InUnsafe && expr.Type == TypeManager.void_ptr_type && target_type.IsPointer) + return new EmptyCast (expr, target_type); + + expr.Error_ValueCannotBeConverted (l, target_type, true); + return null; + } + + /// + /// Performs an explicit conversion of the expression `expr' whose + /// type is expr.Type to `target_type'. + /// + static public Expression ExplicitConversion (EmitContext ec, Expression expr, + Type target_type, Location loc) + { + Expression e = ExplicitConversionCore (ec, expr, target_type, loc); + if (e != null) + return e; + + expr.Error_ValueCannotBeConverted (loc, target_type, true); return null; } }