moving the JVM specific directory
[mono.git] / mcs / bmcs / convert.cs
index a55cc0084ea0bd657f1a02f985eba87738c42e13..a1719e1c6e244dd4a431378ce3e4f1cab189f57b 100644 (file)
@@ -205,6 +205,14 @@ namespace Mono.CSharp {
                                        
                                if (!target_type.IsValueType)
                                        return new NullCast (expr, target_type);
+
+                               // VB.NET specific: Convert Nothing to value types
+
+                               Expression e = NothingToPrimitiveConstants (expr, target_type);
+                               if (e != null)
+                                       return e;
+
+                               return new NullCast (expr, target_type);
                        }
 
                        // from any class-type S to any interface-type T.
@@ -398,22 +406,17 @@ namespace Mono.CSharp {
                        // Attempt to do the implicit constant expression conversions
 
                        if (expr is Constant){
+                               Expression e;
+
+                               e = WideningConstantConversions (target_type, (Constant) expr);
+                               if (e != null)
+                                       return e;
+                               
                                if (expr is IntConstant){
-                                       Expression e;
-                                       
                                        e = TryWideningIntConversion (target_type, (IntConstant) expr);
                                        
                                        if (e != null)
                                                return e;
-                               } else if (expr is LongConstant && target_type == TypeManager.uint64_type){
-                                       //
-                                       // Try the implicit constant expression conversion
-                                       // from long to ulong, instead of a nice routine,
-                                       // we just inline it
-                                       //
-                                       long v = ((LongConstant) expr).Value;
-                                       if (v >= 0)
-                                               return new ULongConstant ((ulong) v);
                                } 
                        }
                        
@@ -569,9 +572,9 @@ namespace Mono.CSharp {
                                // From decimal to float, double
                                //
                                if (real_target_type == TypeManager.double_type)
-                                       return new ImplicitInvocation (ec, "System", "Convert", "ToDouble", loc, expr); 
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.double_type, TypeManager.convert_to_double_decimal, expr);      
                                if (real_target_type == TypeManager.float_type)
-                                       return new ImplicitInvocation (ec, "System", "Convert" ,"ToSingle", loc, expr); 
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.float_type, TypeManager.convert_to_single_decimal, expr);       
                        }
 
                        return null;
@@ -1409,34 +1412,6 @@ namespace Mono.CSharp {
                {
                        int value = ic.Value;
 
-                       if (target_type == TypeManager.sbyte_type){
-                               if (value >= SByte.MinValue && value <= SByte.MaxValue)
-                                       return new SByteConstant ((sbyte) value);
-                       } else if (target_type == TypeManager.byte_type){
-                               if (value >= Byte.MinValue && value <= Byte.MaxValue)
-                                       return new ByteConstant ((byte) value);
-                       } else if (target_type == TypeManager.short_type){
-                               if (value >= Int16.MinValue && value <= Int16.MaxValue)
-                                       return new ShortConstant ((short) value);
-                       } else if (target_type == TypeManager.ushort_type){
-                               if (value >= UInt16.MinValue && value <= UInt16.MaxValue)
-                                       return new UShortConstant ((ushort) value);
-                       } else if (target_type == TypeManager.uint32_type){
-                               if (value >= 0)
-                                       return new UIntConstant ((uint) value);
-                       } else if (target_type == TypeManager.uint64_type){
-                               //
-                               // we can optimize this case: a positive int32
-                               // always fits on a uint64.  But we need an opcode
-                               // to do it.
-                               //
-                               if (value >= 0)
-                                       return new ULongConstant ((ulong) value);
-                       } else if (target_type == TypeManager.double_type)
-                               return new DoubleConstant ((double) value);
-                       else if (target_type == TypeManager.float_type)
-                               return new FloatConstant ((float) value);
-                       
                        if (value == 0 && ic is IntLiteral && TypeManager.IsEnumType (target_type)){
                                Type underlying = TypeManager.EnumToUnderlying (target_type);
                                Constant e = (Constant) ic;
@@ -1463,6 +1438,84 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               /// <summary>
+               ///   Attempts to perform an implicit constant conversion of the IntConstant
+               ///   into a different data type using casts (See Implicit Constant
+               ///   Expression Conversions)
+               /// </summary>
+               static public Expression WideningConstantConversions (Type target_type, Constant const_expr)
+               {
+                       Constant ret_expr;
+                       
+                       Type const_expr_type = const_expr.Type;
+                       Location loc = const_expr.Location;
+
+                       if (target_type == TypeManager.byte_type){
+                               if (const_expr_type == TypeManager.short_type ||
+                                       const_expr_type == TypeManager.int32_type ||
+                                       const_expr_type == TypeManager.int64_type)
+                                               return const_expr.ToByte (loc);
+                       }
+
+                       if (target_type == TypeManager.short_type){
+                               if (const_expr_type == TypeManager.int32_type ||
+                                       const_expr_type == TypeManager.int64_type)
+                                               return const_expr.ToShort (loc);
+                       }
+
+                       if (target_type == TypeManager.int32_type){
+                               if (const_expr_type == TypeManager.int64_type)
+                                       return const_expr.ToInt (loc);
+                       } 
+
+                       if (target_type == TypeManager.float_type) {
+                               if (const_expr_type == TypeManager.double_type)
+                                       return const_expr.ToDouble (loc);
+                       }
+                       
+                       return null;
+               }
+
+               static public Constant NothingToPrimitiveConstants (Expression expr, Type target_type)
+               {
+                       NullLiteral null_literal = (NullLiteral) expr;
+                       Location loc = null_literal.Location;
+                       Type real_target_type = target_type ;
+                       Constant retval = null;
+                       
+                       if (null_literal == null) 
+                               throw new Exception ("FIXME: I was expecting that I would always get only NullLiterals");
+
+                       if (target_type.IsSubclassOf(TypeManager.enum_type))
+                               real_target_type = TypeManager.EnumToUnderlying (target_type);
+
+                       if (real_target_type == TypeManager.bool_type)
+                               retval = null_literal.ToBoolean (loc);
+                       else if (real_target_type == TypeManager.byte_type)
+                               retval = null_literal.ToByte (loc);
+                       else if (real_target_type == TypeManager.short_type)
+                               retval = null_literal.ToShort (loc);
+                       else if (real_target_type == TypeManager.int32_type)
+                               retval = null_literal.ToInt (loc);
+                       else if (real_target_type == TypeManager.int64_type)
+                               null_literal.ToLong (loc);
+                       else if (real_target_type == TypeManager.decimal_type)
+                               retval = null_literal.ToDecimal (loc);
+                       else if (real_target_type == TypeManager.float_type)
+                               retval = null_literal.ToLong (loc);
+                       else if (real_target_type == TypeManager.double_type)
+                               retval = null_literal.ToDouble (loc);
+                       else if (real_target_type == TypeManager.char_type)
+                               retval = null_literal.ToChar (loc);
+                       else if (real_target_type == TypeManager.string_type)
+                               retval = new StringConstant (null);
+                       
+                       if (real_target_type != target_type && retval != null)
+                               retval = new EnumConstant (retval, target_type);
+
+                       return retval;
+               }
+
                static public void Error_CannotWideningConversion (Location loc, Type source, Type target)
                {
                        if (source.Name == target.Name){
@@ -1721,13 +1774,13 @@ namespace Mono.CSharp {
                                // From decimal to byte, short, int, long
                                //
                                if (real_target_type == TypeManager.byte_type)
-                                       return new ImplicitInvocation (ec, "System", "Convert" , "ToByte", loc, expr);  
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.byte_type, TypeManager.convert_to_byte_decimal, expr);  
                                if (real_target_type == TypeManager.short_type)
-                                       return new ImplicitInvocation (ec, "System", "Convert", "ToInt16", loc, expr);  
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.short_type, TypeManager.convert_to_int16_decimal, expr);        
                                if (real_target_type == TypeManager.int32_type)
-                                       return new ImplicitInvocation (ec, "System", "Convert", "ToInt32", loc, expr);  
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int32_type, TypeManager.convert_to_int32_decimal, expr);        
                                if (real_target_type == TypeManager.int64_type)
-                                       return new ImplicitInvocation (ec, "System", "Convert", "ToInt64", loc, expr);  
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int64_type, TypeManager.convert_to_int64_decimal, expr);        
                        } 
 
                        return null;
@@ -1763,7 +1816,7 @@ namespace Mono.CSharp {
                                if (real_target_type == TypeManager.double_type)
                                        return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_R8);
                                if (real_target_type == TypeManager.decimal_type) {
-                                       return new ImplicitInvocation (ec, "DecimalType", "FromBoolean", loc, expr);
+                                       return new HelperMethodInvocation (ec, expr.Location, TypeManager.decimal_type, TypeManager.msvbcs_decimaltype_from_boolean, expr);
                                }
                        } if (real_target_type == TypeManager.bool_type) {
 
@@ -1780,7 +1833,7 @@ namespace Mono.CSharp {
                                        expr_type == TypeManager.double_type)
                                                return new NumericToBooleanCast (expr, expr_type);
                                if (expr_type == TypeManager.decimal_type) {
-                                       return new ImplicitInvocation (ec, "System", "Convert", "ToBoolean", loc, expr);
+                                       return new HelperMethodInvocation (ec, expr.Location, TypeManager.bool_type, TypeManager.convert_to_boolean_decimal, expr);
                                }
                        }
 
@@ -1803,7 +1856,7 @@ namespace Mono.CSharp {
                                // From char to string
                                //
                                if (expr_type == TypeManager.char_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromChar", loc, expr);
+                                       return new HelperMethodInvocation (ec, expr.Location, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_char, expr);
                        }
 
                        if(expr_type.IsArray && (expr_type.GetElementType() == TypeManager.char_type)) {
@@ -1836,28 +1889,28 @@ namespace Mono.CSharp {
                                // float, double, decimal and date 
                                //
 
-                               if (real_target_type.IsArray && (real_target_type.GetElementType() == TypeManager.char_type))
-                                       return new ImplicitInvocation (ec, "CharArrayType", "FromString", loc, expr);
+//                             if (real_target_type.IsArray && (real_target_type.GetElementType() == TypeManager.char_type))
+//                                     return new HelperMethodInvocation (ec, loc, TypeManager.char_array_type, TypeManager.msvbcs_char_array_type_from_string, loc, expr);
                                if (real_target_type == TypeManager.bool_type)
-                                       return new ImplicitInvocation (ec, "BooleanType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.bool_type, TypeManager.msvbcs_booleantype_from_string, expr);
                                if (real_target_type == TypeManager.byte_type)
-                                       return new ImplicitInvocation (ec, "ByteType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.byte_type, TypeManager.msvbcs_bytetype_from_string, expr);
                                if (real_target_type == TypeManager.short_type)
-                                       return new ImplicitInvocation (ec, "ShortType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.short_type, TypeManager.msvbcs_shorttype_from_string, expr);
                                if (real_target_type == TypeManager.char_type)
-                                       return new ImplicitInvocation (ec, "CharType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.char_type, TypeManager.msvbcs_chartype_from_string, expr);
                                if (real_target_type == TypeManager.int32_type)
-                                       return new ImplicitInvocation (ec, "IntegerType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int32_type, TypeManager.msvbcs_integertype_from_string, expr);
                                if (real_target_type == TypeManager.int64_type)
-                                       return new ImplicitInvocation (ec, "LongType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int64_type, TypeManager.msvbcs_longtype_from_string, expr);
                                if (real_target_type == TypeManager.float_type)
-                                       return new ImplicitInvocation (ec, "SingleType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.float_type, TypeManager.msvbcs_singletype_from_string, expr);
                                if (real_target_type == TypeManager.double_type)
-                                       return new ImplicitInvocation (ec, "DoubleType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.double_type, TypeManager.msvbcs_doubletype_from_string, expr);
                                if (real_target_type == TypeManager.decimal_type)
-                                       return new ImplicitInvocation (ec, "DecimalType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.decimal_type, TypeManager.msvbcs_decimaltype_from_string, expr);
                                if (real_target_type == TypeManager.date_type)
-                                       return new ImplicitInvocation (ec, "DateType", "FromString", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.date_type, TypeManager.msvbcs_datetype_from_string, expr);
                        } if (real_target_type == TypeManager.string_type) {
 
                                //
@@ -1867,28 +1920,83 @@ namespace Mono.CSharp {
                                //
 
                                if (expr_type == TypeManager.bool_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromBoolean", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_boolean, expr);
                                if (expr_type == TypeManager.byte_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromByte", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_byte, expr);
                                if (expr_type == TypeManager.short_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromShort", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_short, expr);
                                if (expr_type == TypeManager.int32_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromInteger", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_integer, expr);
                                if (expr_type == TypeManager.int64_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromLong", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_long, expr);
                                if (expr_type == TypeManager.float_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromSingle", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_single, expr);
                                if (expr_type == TypeManager.double_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromDouble", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_double, expr);
                                if (expr_type == TypeManager.decimal_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromDecimal", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_decimal, expr);
                                if (expr_type == TypeManager.date_type)
-                                       return new ImplicitInvocation (ec, "StringType", "FromDate", loc, expr);
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_date, expr);
                        }
 
                        return null;
                }
 
+
+               /// <summary> 
+               /// VB.NET specific: Conversions from Object to Primitive Types
+               /// </summary>
+
+               static public Expression ObjectTypeToPrimitiveTypes (EmitContext ec, Expression expr,
+                                                                   Type target_type, Location loc)
+               {
+                       Type expr_type = expr.Type;
+                       Type real_target_type = target_type;
+                       MethodInfo helper_method = null;
+                       Expression retexpr;
+
+                       if (expr_type != TypeManager.object_type)
+                               return null;
+
+                       if (target_type.IsSubclassOf (TypeManager.enum_type))
+                               real_target_type = TypeManager.EnumToUnderlying (target_type);
+                       
+
+                       if (real_target_type == TypeManager.bool_type)
+                               helper_method = TypeManager.msvbcs_booleantype_fromobject_object;
+                       if (real_target_type == TypeManager.byte_type)
+                               helper_method = TypeManager.msvbcs_bytetype_fromobject_object;
+                       if (real_target_type == TypeManager.short_type)
+                               helper_method = TypeManager.msvbcs_shorttype_fromobject_object;
+                       if (real_target_type == TypeManager.char_type)
+                               helper_method = TypeManager.msvbcs_chartype_fromobject_object;
+                       if (real_target_type == TypeManager.int32_type)
+                               helper_method = TypeManager.msvbcs_integertype_fromobject_object;
+                       if (real_target_type == TypeManager.int64_type)
+                               helper_method = TypeManager.msvbcs_longtype_fromobject_object;
+                       if (real_target_type == TypeManager.float_type)
+                               helper_method = TypeManager.msvbcs_singletype_fromobject_object;
+                       if (real_target_type == TypeManager.double_type)
+                               helper_method = TypeManager.msvbcs_doubletype_fromobject_object;
+                       if (real_target_type == TypeManager.decimal_type)
+                               helper_method = TypeManager.msvbcs_decimaltype_fromobject_object;
+                       if (real_target_type == TypeManager.date_type)
+                               helper_method = TypeManager.msvbcs_datetype_fromobject_object;
+                       if (real_target_type == TypeManager.string_type)
+                               helper_method = TypeManager.msvbcs_stringtype_fromobject_object;
+
+                       if (helper_method !=  null) {
+                               retexpr = new HelperMethodInvocation (ec, loc, real_target_type, helper_method, expr);
+                               if (target_type != real_target_type)
+                                       retexpr = new EmptyCast (retexpr, target_type);
+
+                               return retexpr;
+                       }
+
+                       return null;
+               }
+               
+
                /// <summary>
                ///  Returns whether an explicit reference conversion can be performed
                ///  from source_type to target_type
@@ -2164,6 +2272,17 @@ namespace Mono.CSharp {
                        //
                        // Unboxing conversion.
                        //
+
+                       //
+                       // VB.NET treats conversions from object to
+                       // the primitive types using the helper
+                       // routines in Microsoft.VisualBasic.dll
+                       //
+
+                       ne = ObjectTypeToPrimitiveTypes(ec, expr, target_type, loc);
+                       if (ne != null)
+                               return ne;
+                       
                        if (expr_type == TypeManager.object_type && target_type.IsValueType)
                                return new UnboxCast (expr, target_type);