moving the JVM specific directory
[mono.git] / mcs / bmcs / convert.cs
index 4580d57e28bbf9a865157de6d7fae0290eb3f14d..a1719e1c6e244dd4a431378ce3e4f1cab189f57b 100644 (file)
@@ -138,7 +138,7 @@ namespace Mono.CSharp {
                }
 
                static EmptyExpression MyEmptyExpr;
-               static public Expression ImplicitReferenceConversion (EmitContext ec, Expression expr, Type target_type)
+               static public Expression WideningReferenceConversion (EmitContext ec, Expression expr, Type target_type)
                {
                        Type expr_type = expr.Type;
 
@@ -193,7 +193,7 @@ namespace Mono.CSharp {
                                return new EmptyCast (expr, target_type);
                        }
 
-                       // This code is kind of mirrored inside ImplicitStandardConversionExists
+                       // This code is kind of mirrored inside WideningStandardConversionExists
                        // with the small distinction that we only probe there
                        //
                        // Always ensure that the code here and there is in sync
@@ -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.
@@ -234,7 +242,7 @@ namespace Mono.CSharp {
                                else
                                        return null;
                        }
-                               
+
                        // from an array-type S to an array-type of type T
                        if (expr_type.IsArray && target_type.IsArray) {
                                if (expr_type.GetArrayRank () == target_type.GetArrayRank ()) {
@@ -248,7 +256,7 @@ namespace Mono.CSharp {
                                        Type target_element_type = TypeManager.GetElementType (target_type);
 
                                        if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
-                                               if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
+                                               if (WideningStandardConversionExists (ConstantEC, MyEmptyExpr,
                                                                                      target_element_type))
                                                        return new EmptyCast (expr, target_type);
                                }
@@ -257,7 +265,11 @@ namespace Mono.CSharp {
                        // from an array-type to System.Array
                        if (expr_type.IsArray && target_type == TypeManager.array_type)
                                return new EmptyCast (expr, target_type);
-                               
+
+                       // from an array-type of type T to IEnumerable<T>
+                       if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
+                               return new EmptyCast (expr, target_type);
+
                        // from any delegate type to System.Delegate
                        if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
                            target_type == TypeManager.delegate_type)
@@ -280,7 +292,7 @@ namespace Mono.CSharp {
                // Tests whether an implicit reference conversion exists between expr_type
                // and target_type
                //
-               public static bool ImplicitReferenceConversionExists (EmitContext ec, Expression expr, Type target_type)
+               public static bool WideningReferenceConversionExists (EmitContext ec, Expression expr, Type target_type)
                {
                        Type expr_type = expr.Type;
 
@@ -301,7 +313,7 @@ namespace Mono.CSharp {
                                return true;
 
                        // Please remember that all code below actually comes
-                       // from ImplicitReferenceConversion so make sure code remains in sync
+                       // from WideningReferenceConversion so make sure code remains in sync
                                
                        // from any class-type S to any interface-type T.
                        if (target_type.IsInterface) {
@@ -337,7 +349,7 @@ namespace Mono.CSharp {
                                        Type target_element_type = TypeManager.GetElementType (target_type);
                                                
                                        if (!expr_element_type.IsValueType && !target_element_type.IsValueType)
-                                               if (ImplicitStandardConversionExists (ConstantEC, MyEmptyExpr,
+                                               if (WideningStandardConversionExists (ConstantEC, MyEmptyExpr,
                                                                                      target_element_type))
                                                        return true;
                                }
@@ -346,7 +358,11 @@ namespace Mono.CSharp {
                        // from an array-type to System.Array
                        if (expr_type.IsArray && (target_type == TypeManager.array_type))
                                return true;
-                               
+
+                       // from an array-type of type T to IEnumerable<T>
+                       if (expr_type.IsArray && TypeManager.IsIEnumerable (expr_type, target_type))
+                               return true;
+
                        // from any delegate type to System.Delegate
                        if ((expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)) &&
                            target_type == TypeManager.delegate_type)
@@ -381,7 +397,7 @@ namespace Mono.CSharp {
                ///   expr is the expression to convert, returns a new expression of type
                ///   target_type or null if an implicit conversion is not possible.
                /// </summary>
-               static public Expression ImplicitNumericConversion (EmitContext ec, Expression expr,
+               static public Expression WideningNumericConversion (EmitContext ec, Expression expr,
                                                                    Type target_type, Location loc)
                {
                        Type expr_type = expr.Type;
@@ -390,27 +406,50 @@ 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 = TryImplicitIntConversion (target_type, (IntConstant) expr);
+                                       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);
                                } 
                        }
                        
                        Type real_target_type = target_type;
 
+                       // VB.NET specific: Convert an enum to it's
+                       // underlying numeric type or any type that
+                       // it's underlyinmg type has widening
+                       // conversion to.
+
+                       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);
+                               } 
+
+                               //
+                               // 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;
+
+                               if (expr_type == target_type)
+                                       return expr;
+                       }
+
                        if (expr_type == TypeManager.sbyte_type){
                                //
                                // From sbyte to short, int, long, float, double.
@@ -443,6 +482,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 ImplicitNew (ec, "System", "Decimal", loc, expr);
                        } else if (expr_type == TypeManager.short_type){
                                //
                                // From short to int, long, float, double
@@ -455,6 +496,8 @@ 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 ImplicitNew (ec, "System", "Decimal", loc, expr);
                        } else if (expr_type == TypeManager.ushort_type){
                                //
                                // From ushort to int, uint, long, ulong, float, double
@@ -482,6 +525,8 @@ 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 ImplicitNew (ec, "System", "Decimal", loc, expr);
                        } else if (expr_type == TypeManager.uint32_type){
                                //
                                // From uint to long, ulong, float, double
@@ -496,14 +541,6 @@ namespace Mono.CSharp {
                                if (real_target_type == TypeManager.float_type)
                                        return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
                                                               OpCodes.Conv_R4);
-                       } else if (expr_type == TypeManager.int64_type){
-                               //
-                               // From long/ulong to float, double
-                               //
-                               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);     
                        } else if (expr_type == TypeManager.uint64_type){
                                //
                                // From ulong to float, double
@@ -514,28 +551,30 @@ namespace Mono.CSharp {
                                if (real_target_type == TypeManager.float_type)
                                        return new OpcodeCast (expr, target_type, OpCodes.Conv_R_Un,
                                                               OpCodes.Conv_R4);        
-                       } else if (expr_type == TypeManager.char_type){
+                       } else if (expr_type == TypeManager.int64_type){
+                               //
+                               // From long/ulong to float, double
                                //
-                               // From char to ushort, int, uint, long, ulong, float, double
-                               // 
-                               if ((real_target_type == TypeManager.ushort_type) ||
-                                   (real_target_type == TypeManager.int32_type) ||
-                                   (real_target_type == TypeManager.uint32_type))
-                                       return new EmptyCast (expr, target_type);
-                               if (real_target_type == TypeManager.uint64_type)
-                                       return new OpcodeCast (expr, target_type, OpCodes.Conv_U8);
-                               if (real_target_type == TypeManager.int64_type)
-                                       return new OpcodeCast (expr, target_type, OpCodes.Conv_I8);
-                               if (real_target_type == TypeManager.float_type)
-                                       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.float_type)
+                                       return new OpcodeCast (expr, target_type, OpCodes.Conv_R4);     
+                               if (real_target_type == TypeManager.decimal_type)
+                                       return new ImplicitNew (ec, "System", "Decimal", loc, expr);    
                        } else if (expr_type == TypeManager.float_type){
                                //
                                // float to double
                                //
                                if (real_target_type == TypeManager.double_type)
                                        return new OpcodeCast (expr, target_type, OpCodes.Conv_R8);
+                       } else if (expr_type == TypeManager.decimal_type){
+                               //
+                               // From decimal to float, double
+                               //
+                               if (real_target_type == TypeManager.double_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.double_type, TypeManager.convert_to_double_decimal, expr);      
+                               if (real_target_type == TypeManager.float_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.float_type, TypeManager.convert_to_single_decimal, expr);       
                        }
 
                        return null;
@@ -543,31 +582,44 @@ namespace Mono.CSharp {
 
 
                /// <summary>
-               ///  Same as ImplicitStandardConversionExists except that it also looks at
+               ///  Same as WideningStandardConversionExists except that it also looks at
                ///  implicit user defined conversions - needed for overload resolution
                /// </summary>
-               public static bool ImplicitConversionExists (EmitContext ec, Expression expr, Type target_type)
+               public static bool WideningConversionExists (EmitContext ec, Expression expr, Type target_type)
                {
-                       if ((expr is NullLiteral) && target_type.IsGenericParameter)
-                               return TypeParameter_to_Null (target_type);
+                       if (expr is NullLiteral) {
+                               if (target_type.IsGenericParameter)
+                                       return TypeParameter_to_Null (target_type);
+
+                               if (TypeManager.IsNullableType (target_type))
+                                       return true;
+                       }
 
-                       if (ImplicitStandardConversionExists (ec, expr, target_type))
+                       if (WideningStandardConversionExists (ec, expr, target_type))
                                return true;
 
-                       Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
+                       //
+                       // VB.NET has no notion of User defined conversions
+                       //
 
-                       if (dummy != null)
-                               return true;
+//                     Expression dummy = ImplicitUserConversion (ec, expr, target_type, Location.Null);
+
+//                     if (dummy != null)
+//                             return true;
 
                        return false;
                }
 
-               public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
-               {
-                       Expression dummy = ImplicitUserConversion (
-                               ec, new EmptyExpression (source), target, Location.Null);
-                       return dummy != null;
-               }
+               //
+               // VB.NET has no notion of User defined conversions
+               //
+
+//             public static bool ImplicitUserConversionExists (EmitContext ec, Type source, Type target)
+//             {
+//                     Expression dummy = ImplicitUserConversion (
+//                             ec, new EmptyExpression (source), target, Location.Null);
+//                     return dummy != null;
+//             }
 
                /// <summary>
                ///  Determines if a standard implicit conversion exists from
@@ -575,7 +627,7 @@ namespace Mono.CSharp {
                ///
                ///  ec should point to a real EmitContext if expr.Type is TypeManager.anonymous_method_type.
                /// </summary>
-               public static bool ImplicitStandardConversionExists (EmitContext ec, Expression expr, Type target_type)
+               public static bool WideningStandardConversionExists (EmitContext ec, Expression expr, Type target_type)
                {
                        Type expr_type = expr.Type;
 
@@ -708,7 +760,7 @@ namespace Mono.CSharp {
                                }
                        }
                        
-                       if (ImplicitReferenceConversionExists (ec, expr, target_type))
+                       if (WideningReferenceConversionExists (ec, expr, target_type))
                                return true;
 
                        //
@@ -768,7 +820,7 @@ namespace Mono.CSharp {
 
                        //
                        // If `expr_type' implements `target_type' (which is an iface)
-                       // see TryImplicitIntConversion
+                       // see TryWideningIntConversion
                        // 
                        if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
                                return true;
@@ -776,6 +828,9 @@ namespace Mono.CSharp {
                        if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
                                return true;
 
+                       if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
+                               return true;
+
                        if (expr_type == TypeManager.anonymous_method_type){
                                if (!TypeManager.IsDelegateType (target_type))
                                        return false;
@@ -816,7 +871,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
                                
-                               if (ImplicitStandardConversionExists (ec, priv_fmet_param, best))
+                               if (WideningStandardConversionExists (ec, priv_fmet_param, best))
                                        best = t;
                        }
 
@@ -849,7 +904,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               if (ImplicitStandardConversionExists (ec, priv_fmee_ret, t))
+                               if (WideningStandardConversionExists (ec, priv_fmee_ret, t))
                                        best = t;
                        }
                        
@@ -896,17 +951,17 @@ namespace Mono.CSharp {
                                        // 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))
+                                       if (WideningStandardConversionExists (ec, priv_fms_expr, source_type))
                                                src_types_set.Add (param_type);
                                        else {
-                                               if (ImplicitStandardConversionExists (ec, source, param_type))
+                                               if (WideningStandardConversionExists (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))
+                                       if (WideningStandardConversionExists (ec, source, param_type))
                                                src_types_set.Add (param_type);
                                }
                        }
@@ -918,7 +973,7 @@ namespace Mono.CSharp {
                                ArrayList candidate_set = new ArrayList ();
 
                                foreach (Type param_type in src_types_set){
-                                       if (ImplicitStandardConversionExists (ec, source, param_type))
+                                       if (WideningStandardConversionExists (ec, source, param_type))
                                                candidate_set.Add (param_type);
                                }
 
@@ -972,11 +1027,11 @@ namespace Mono.CSharp {
                                        // 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))
+                                       if (WideningStandardConversionExists (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))
+                                               if (WideningStandardConversionExists (ec, priv_fms_expr, ret_type))
                                                        tgt_types_set.Add (ret_type);
                                        }
                                } else {
@@ -984,7 +1039,7 @@ namespace Mono.CSharp {
                                        // Only if T is encompassed by param_type
                                        //
                                        priv_fms_expr.SetType (ret_type);
-                                       if (ImplicitStandardConversionExists (ec, priv_fms_expr, target))
+                                       if (WideningStandardConversionExists (ec, priv_fms_expr, target))
                                                tgt_types_set.Add (ret_type);
                                }
                        }
@@ -998,7 +1053,7 @@ namespace Mono.CSharp {
                                foreach (Type ret_type in tgt_types_set){
                                        priv_fmt_expr.SetType (ret_type);
                                        
-                                       if (ImplicitStandardConversionExists (ec, priv_fmt_expr, target))
+                                       if (WideningStandardConversionExists (ec, priv_fmt_expr, target))
                                                candidate_set.Add (ret_type);
                                }
 
@@ -1018,20 +1073,30 @@ namespace Mono.CSharp {
                /// <summary>
                ///  User-defined Implicit conversions
                /// </summary>
-               static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
-                                                                Type target, Location loc)
-               {
-                       return UserDefinedConversion (ec, source, target, loc, false);
-               }
+
+               //
+               // VB.NET has no notion of User defined conversions
+               //
+
+//             static public Expression ImplicitUserConversion (EmitContext ec, Expression source,
+//                                                              Type target, Location loc)
+//             {
+//                     return UserDefinedConversion (ec, source, target, loc, false);
+//             }
 
                /// <summary>
                ///  User-defined Explicit conversions
                /// </summary>
-               static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
-                                                                Type target, Location loc)
-               {
-                       return UserDefinedConversion (ec, source, target, loc, true);
-               }
+
+               //
+               // VB.NET has no notion of User defined conversions
+               //
+
+//             static public Expression ExplicitUserConversion (EmitContext ec, Expression source,
+//                                                              Type target, Location loc)
+//             {
+//                     return UserDefinedConversion (ec, source, target, loc, true);
+//             }
 
                static DoubleHash explicit_conv = new DoubleHash (100);
                static DoubleHash implicit_conv = new DoubleHash (100);
@@ -1112,6 +1177,10 @@ namespace Mono.CSharp {
                /// <summary>
                ///   User-defined conversions
                /// </summary>
+
+               //
+               // VB.NET has no notion of User defined conversions. This method is not used.
+               //
                static public Expression UserDefinedConversion (EmitContext ec, Expression source,
                                                                Type target, Location loc,
                                                                bool look_for_explicit)
@@ -1120,6 +1189,10 @@ namespace Mono.CSharp {
                        Type source_type = source.Type;
                        MethodBase method = null;
 
+                       if (TypeManager.IsNullableType (source_type) && TypeManager.IsNullableType (target))
+                               return new Nullable.LiftedConversion (
+                                       source, target, true, look_for_explicit, loc).Resolve (ec);
+
                        union = GetConversionOperators (ec, source_type, target, loc, look_for_explicit);
                        if (union == null)
                                return null;
@@ -1159,9 +1232,9 @@ namespace Mono.CSharp {
                        // by target.
                        //
                        if (look_for_explicit)
-                               source = ExplicitConversionStandard (ec, source, most_specific_source, loc);
+                               source = WideningAndNarrowingConversionStandard (ec, source, most_specific_source, loc);
                        else
-                               source = ImplicitConversionStandard (ec, source, most_specific_source, loc);
+                               source = WideningConversionStandard (ec, source, most_specific_source, loc);
 
                        if (source == null)
                                return null;
@@ -1170,9 +1243,9 @@ namespace Mono.CSharp {
                        e =  new UserCast ((MethodInfo) method, source, loc);
                        if (e.Type != target){
                                if (!look_for_explicit)
-                                       e = ImplicitConversionStandard (ec, e, target, loc);
+                                       e = WideningConversionStandard (ec, e, target, loc);
                                else
-                                       e = ExplicitConversionStandard (ec, e, target, loc);
+                                       e = WideningAndNarrowingConversionStandard (ec, e, target, loc);
                        }
 
                        return e;
@@ -1183,7 +1256,7 @@ namespace Mono.CSharp {
                ///   `target_type'.  It returns a new expression that can be used
                ///   in a context that expects a `target_type'. 
                /// </summary>
-               static public Expression ImplicitConversion (EmitContext ec, Expression expr,
+               static public Expression WideningConversion (EmitContext ec, Expression expr,
                                                             Type target_type, Location loc)
                {
                        Expression e;
@@ -1191,13 +1264,17 @@ namespace Mono.CSharp {
                        if (target_type == null)
                                throw new Exception ("Target type is null");
 
-                       e = ImplicitConversionStandard (ec, expr, target_type, loc);
+                       e = WideningConversionStandard (ec, expr, target_type, loc);
                        if (e != null)
                                return e;
 
-                       e = ImplicitUserConversion (ec, expr, target_type, loc);
-                       if (e != null)
-                               return e;
+                       //
+                       // VB.NET has no notion of User defined conversions
+                       //
+
+//                     e = ImplicitUserConversion (ec, expr, target_type, loc);
+//                     if (e != null)
+//                             return e;
 
                        return null;
                }
@@ -1210,17 +1287,26 @@ namespace Mono.CSharp {
                ///   that can be used in a context that expects a
                ///   `target_type'.
                ///
-               ///   This is different from `ImplicitConversion' in that the
+               ///   This is different from `WideningConversion' in that the
                ///   user defined implicit conversions are excluded. 
                /// </summary>
-               static public Expression ImplicitConversionStandard (EmitContext ec, Expression expr,
+               static public Expression WideningConversionStandard (EmitContext ec, Expression expr,
                                                                     Type target_type, Location loc)
                {
                        Type expr_type = expr.Type;
                        Expression e;
 
-                       if ((expr is NullLiteral) && target_type.IsGenericParameter)
-                               return TypeParameter_to_Null (expr, target_type, loc);
+                       if (expr is NullLiteral) {
+                               if (target_type.IsGenericParameter)
+                                       return TypeParameter_to_Null (expr, target_type, loc);
+
+                               if (TypeManager.IsNullableType (target_type))
+                                       return new Nullable.NullableLiteral (target_type, loc);
+                       }
+
+                       if (TypeManager.IsNullableType (expr_type) && TypeManager.IsNullableType (target_type))
+                               return new Nullable.LiftedConversion (
+                                       expr, target_type, false, false, loc).Resolve (ec);
 
                        if (expr.eclass == ExprClass.MethodGroup){
                                if (!TypeManager.IsDelegateType (target_type)){
@@ -1240,11 +1326,11 @@ namespace Mono.CSharp {
                        if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
                                return expr;
 
-                       e = ImplicitNumericConversion (ec, expr, target_type, loc);
+                       e = WideningNumericConversion (ec, expr, target_type, loc);
                        if (e != null)
                                return e;
 
-                       e = ImplicitReferenceConversion (ec, expr, target_type);
+                       e = WideningReferenceConversion (ec, expr, target_type);
                        if (e != null)
                                return e;
                        
@@ -1304,6 +1390,15 @@ namespace Mono.CSharp {
                                if (errors != Report.Errors)
                                        return new EmptyCast (expr, target_type);
                        }
+
+                       //
+                       // VB.NET specific conversions
+                       //
+
+                       e = WideningStringConversions (ec, expr, target_type, loc);
+                       if (e != null)
+                               return e;
+
                        
                        return null;
                }
@@ -1313,38 +1408,10 @@ namespace Mono.CSharp {
                ///   into a different data type using casts (See Implicit Constant
                ///   Expression Conversions)
                /// </summary>
-               static public Expression TryImplicitIntConversion (Type target_type, IntConstant ic)
+               static public Expression TryWideningIntConversion (Type target_type, IntConstant ic)
                {
                        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;
@@ -1371,7 +1438,85 @@ namespace Mono.CSharp {
                        return null;
                }
 
-               static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
+               /// <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){
                                Report.ExtraInformation (loc,
@@ -1388,16 +1533,16 @@ namespace Mono.CSharp {
 
                /// <summary>
                ///   Attempts to implicitly convert `source' into `target_type', using
-               ///   ImplicitConversion.  If there is no implicit conversion, then
+               ///   WideningConversion.  If there is no implicit conversion, then
                ///   an error is signaled
                /// </summary>
-               static public Expression ImplicitConversionRequired (EmitContext ec, Expression source,
+               static public Expression WideningConversionRequired (EmitContext ec, Expression source,
                                                                     Type target_type, Location loc)
                {
                        Expression e;
 
                        int errors = Report.Errors;
-                       e = ImplicitConversion (ec, source, target_type, loc);
+                       e = WideningConversion (ec, source, target_type, loc);
                        if (Report.Errors > errors)
                                return null;
                        if (e != null)
@@ -1421,7 +1566,7 @@ namespace Mono.CSharp {
                                return null;
                        }
                        
-                       Error_CannotImplicitConversion (loc, source.Type, target_type);
+                       Error_CannotWideningConversion (loc, source.Type, target_type);
 
                        return null;
                }
@@ -1435,7 +1580,11 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Performs the explicit numeric conversions
                /// </summary>
-               static Expression ExplicitNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
+
+               /// <summary>
+               ///   Performs the explicit numeric conversions
+               /// </summary>
+               static Expression NarrowingNumericConversion (EmitContext ec, Expression expr, Type target_type, Location loc)
                {
                        Type expr_type = expr.Type;
 
@@ -1449,8 +1598,8 @@ namespace Mono.CSharp {
                        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 (WideningStandardConversionExists (ec, expr, real_target_type)){
+                               Expression ce = WideningConversionStandard (ec, expr, real_target_type, loc);
 
                                if (real_target_type != target_type)
                                        return new EmptyCast (ce, target_type);
@@ -1477,11 +1626,9 @@ namespace Mono.CSharp {
                                //
                                if (real_target_type == TypeManager.sbyte_type)
                                        return new ConvCast (ec, 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);
                        } else if (expr_type == TypeManager.short_type){
                                //
-                               // From short to sbyte, byte, ushort, uint, ulong, char
+                               // From short to byte
                                //
                                if (real_target_type == TypeManager.sbyte_type)
                                        return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_I1);
@@ -1493,8 +1640,6 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, 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);
-                               if (real_target_type == TypeManager.char_type)
-                                       return new ConvCast (ec, expr, target_type, ConvCast.Mode.I2_CH);
                        } else if (expr_type == TypeManager.ushort_type){
                                //
                                // From ushort to sbyte, byte, short, char
@@ -1509,7 +1654,7 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, expr, target_type, ConvCast.Mode.U2_CH);
                        } else if (expr_type == TypeManager.int32_type){
                                //
-                               // From int to sbyte, byte, short, ushort, uint, ulong, char
+                               // From int to byte, short
                                //
                                if (real_target_type == TypeManager.sbyte_type)
                                        return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_I1);
@@ -1523,8 +1668,6 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, 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);
-                               if (real_target_type == TypeManager.char_type)
-                                       return new ConvCast (ec, expr, target_type, ConvCast.Mode.I4_CH);
                        } else if (expr_type == TypeManager.uint32_type){
                                //
                                // From uint to sbyte, byte, short, ushort, int, char
@@ -1543,7 +1686,7 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, 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
+                               // From long to byte, short, int
                                //
                                if (real_target_type == TypeManager.sbyte_type)
                                        return new ConvCast (ec, expr, target_type, ConvCast.Mode.I8_I1);
@@ -1559,8 +1702,6 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, 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);
-                               if (real_target_type == TypeManager.char_type)
-                                       return new ConvCast (ec, 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
@@ -1581,52 +1722,38 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, 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);
-                       } 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);
-                               if (real_target_type == TypeManager.byte_type)
-                                       return new ConvCast (ec, 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);
                        } else if (expr_type == TypeManager.float_type){
                                //
-                               // From float to sbyte, byte, short,
-                               // ushort, int, uint, long, ulong, char
-                               // or decimal
+                               // From float to byte, short, int, long, decimal
                                //
                                if (real_target_type == TypeManager.sbyte_type)
                                        return new ConvCast (ec, 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 FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_U1);
                                if (real_target_type == TypeManager.short_type)
-                                       return new ConvCast (ec, expr, target_type, ConvCast.Mode.R4_I2);
+                                       return new FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I2);
                                if (real_target_type == TypeManager.ushort_type)
                                        return new ConvCast (ec, 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 FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I4);
                                if (real_target_type == TypeManager.uint32_type)
                                        return new ConvCast (ec, 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 FloatingToFixedCast (ec, expr, target_type, ConvCast.Mode.R8_I8);
                                if (real_target_type == TypeManager.uint64_type)
                                        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 ImplicitNew (ec, "System", "Decimal", loc, expr);    
                        } else if (expr_type == TypeManager.double_type){
                                //
-                               // From double to byte, byte, short,
-                               // ushort, int, uint, long, ulong,
-                               // char, float or decimal
+                               // From double to byte, short, int, long, float, decimal
                                //
                                if (real_target_type == TypeManager.sbyte_type)
                                        return new ConvCast (ec, 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 FloatingToFixedCast (ec, 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 FloatingToFixedCast (ec, 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);
                                if (real_target_type == TypeManager.int32_type)
@@ -1637,28 +1764,256 @@ namespace Mono.CSharp {
                                        return new ConvCast (ec, 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);
-                               if (real_target_type == TypeManager.char_type)
-                                       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);
+                               if (real_target_type == TypeManager.decimal_type)
+                                       return new ImplicitNew (ec, "System", "Decimal", loc, expr);
+                       } else if (expr_type == TypeManager.decimal_type){
+                               //
+                               // From decimal to byte, short, int, long
+                               //
+                               if (real_target_type == TypeManager.byte_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.byte_type, TypeManager.convert_to_byte_decimal, expr);  
+                               if (real_target_type == TypeManager.short_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.short_type, TypeManager.convert_to_int16_decimal, expr);        
+                               if (real_target_type == TypeManager.int32_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int32_type, TypeManager.convert_to_int32_decimal, expr);        
+                               if (real_target_type == TypeManager.int64_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int64_type, TypeManager.convert_to_int64_decimal, expr);        
                        } 
 
-                       // decimal is taken care of by the op_Explicit methods.
+                       return null;
+               }
+
+               /// <summary> 
+               /// VB.NET specific: Convert to and from boolean
+               /// </summary>
+
+               static public Expression BooleanConversions (EmitContext ec, Expression expr,
+                                                                   Type target_type, Location loc)
+               {
+                       Type expr_type = expr.Type;
+                       Type real_target_type = target_type;
+
+                       if (expr_type == TypeManager.bool_type) {
+
+                               //
+                               // From boolean to byte, short, int,
+                               // long, float, double, decimal
+                               //
+
+                               if (real_target_type == TypeManager.byte_type)
+                                       return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_U1);
+                               if (real_target_type == TypeManager.short_type)
+                                       return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_I2);
+                               if (real_target_type == TypeManager.int32_type)
+                                       return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_I4);
+                               if (real_target_type == TypeManager.int64_type)
+                                       return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_I8);
+                               if (real_target_type == TypeManager.float_type)
+                                       return new BooleanToNumericCast (expr, target_type, OpCodes.Conv_R4);
+                               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 HelperMethodInvocation (ec, expr.Location, TypeManager.decimal_type, TypeManager.msvbcs_decimaltype_from_boolean, expr);
+                               }
+                       } if (real_target_type == TypeManager.bool_type) {
+
+                               //
+                               // From byte, short, int, long, float,
+                               // double, decimal to boolean
+                               //
+
+                               if (expr_type == TypeManager.byte_type ||
+                                       expr_type == TypeManager.short_type ||
+                                       expr_type == TypeManager.int32_type ||
+                                       expr_type == TypeManager.int64_type || 
+                                       expr_type == TypeManager.float_type || 
+                                       expr_type == TypeManager.double_type)
+                                               return new NumericToBooleanCast (expr, expr_type);
+                               if (expr_type == TypeManager.decimal_type) {
+                                       return new HelperMethodInvocation (ec, expr.Location, TypeManager.bool_type, TypeManager.convert_to_boolean_decimal, expr);
+                               }
+                       }
+
+                       return null;
+               }
+
+               /// <summary> 
+               /// VB.NET specific: Widening conversions to string
+               /// </summary>
+
+               static public Expression WideningStringConversions (EmitContext ec, Expression expr,
+                                                                   Type target_type, Location loc)
+
+               {
+                       Type expr_type = expr.Type;
+                       Type real_target_type = target_type;
+
+                       if (real_target_type == TypeManager.string_type) {
+                               //
+                               // From char to string
+                               //
+                               if (expr_type == TypeManager.char_type)
+                                       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)) {
+                               //
+                               // From char array to string
+                               //
+                               return new ImplicitNew (ec, "System", "String", loc, expr);
+                       }
+
+                       return null;
+               }
+               
+               /// <summary> 
+               /// VB.NET specific: Narrowing conversions involving strings
+               /// </summary>
+
+               static public Expression NarrowingStringConversions (EmitContext ec, Expression expr,
+                                                                   Type target_type, Location loc)
+               {
+                       Type expr_type = expr.Type;
+                       Type real_target_type = target_type;
+
+                       // FIXME: Need to take care of Constants
+
+                       if (expr_type == TypeManager.string_type) {
+
+                               //
+                               // From string to chararray, bool,
+                               // byte, short, char, int, long,
+                               // float, double, decimal and date 
+                               //
+
+//                             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 HelperMethodInvocation (ec, loc, TypeManager.bool_type, TypeManager.msvbcs_booleantype_from_string, expr);
+                               if (real_target_type == TypeManager.byte_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.byte_type, TypeManager.msvbcs_bytetype_from_string, expr);
+                               if (real_target_type == TypeManager.short_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.short_type, TypeManager.msvbcs_shorttype_from_string, expr);
+                               if (real_target_type == TypeManager.char_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.char_type, TypeManager.msvbcs_chartype_from_string, expr);
+                               if (real_target_type == TypeManager.int32_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int32_type, TypeManager.msvbcs_integertype_from_string, expr);
+                               if (real_target_type == TypeManager.int64_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.int64_type, TypeManager.msvbcs_longtype_from_string, expr);
+                               if (real_target_type == TypeManager.float_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.float_type, TypeManager.msvbcs_singletype_from_string, expr);
+                               if (real_target_type == TypeManager.double_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.double_type, TypeManager.msvbcs_doubletype_from_string, expr);
+                               if (real_target_type == TypeManager.decimal_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.decimal_type, TypeManager.msvbcs_decimaltype_from_string, expr);
+                               if (real_target_type == TypeManager.date_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.date_type, TypeManager.msvbcs_datetype_from_string, expr);
+                       } if (real_target_type == TypeManager.string_type) {
+
+                               //
+                               // From bool, byte, short, char, int,
+                               // long, float, double, decimal and
+                               // date to string
+                               //
+
+                               if (expr_type == TypeManager.bool_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_boolean, expr);
+                               if (expr_type == TypeManager.byte_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_byte, expr);
+                               if (expr_type == TypeManager.short_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_short, expr);
+                               if (expr_type == TypeManager.int32_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_integer, expr);
+                               if (expr_type == TypeManager.int64_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_long, expr);
+                               if (expr_type == TypeManager.float_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_single, expr);
+                               if (expr_type == TypeManager.double_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_double, expr);
+                               if (expr_type == TypeManager.decimal_type)
+                                       return new HelperMethodInvocation (ec, loc, TypeManager.string_type, TypeManager.msvbcs_stringtype_from_decimal, expr);
+                               if (expr_type == TypeManager.date_type)
+                                       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
                /// </summary>
-               public static bool ExplicitReferenceConversionExists (Type source_type, Type target_type)
+               public static bool NarrowingReferenceConversionExists (Type source_type, Type target_type)
                {
                        bool target_is_type_param = target_type.IsGenericParameter;
                        bool target_is_value_type = target_type.IsValueType;
                        
                        if (source_type == target_type)
                                return true;
+                       
+                       //
+                       // From generic parameter to any type
+                       //
+                       if (source_type.IsGenericParameter)
+                               return true;
 
                        //
                        // From object to a generic parameter
@@ -1715,9 +2070,10 @@ namespace Mono.CSharp {
                                        
                                        Type source_element_type = TypeManager.GetElementType (source_type);
                                        Type target_element_type = TypeManager.GetElementType (target_type);
-                                       
-                                       if (!source_element_type.IsValueType && !target_element_type.IsValueType)
-                                               if (ExplicitReferenceConversionExists (source_element_type,
+
+                                       if (source_element_type.IsGenericParameter ||
+                                           (!source_element_type.IsValueType && !target_element_type.IsValueType))
+                                               if (NarrowingReferenceConversionExists (source_element_type,
                                                                                       target_element_type))
                                                        return true;
                                }
@@ -1751,7 +2107,7 @@ namespace Mono.CSharp {
                /// <summary>
                ///   Implements Explicit Reference conversions
                /// </summary>
-               static Expression ExplicitReferenceConversion (Expression source, Type target_type)
+               static Expression NarrowingReferenceConversion (Expression source, Type target_type)
                {
                        Type source_type = source.Type;
                        bool target_is_type_param = target_type.IsGenericParameter;
@@ -1834,7 +2190,7 @@ namespace Mono.CSharp {
                                        Type target_element_type = TypeManager.GetElementType (target_type);
                                        
                                        if (!source_element_type.IsValueType && !target_element_type.IsValueType)
-                                               if (ExplicitReferenceConversionExists (source_element_type,
+                                               if (NarrowingReferenceConversionExists (source_element_type,
                                                                                       target_element_type))
                                                        return new ClassCast (source, target_type);
                                }
@@ -1869,7 +2225,7 @@ namespace Mono.CSharp {
                ///   Performs an explicit conversion of the expression `expr' whose
                ///   type is expr.Type to `target_type'.
                /// </summary>
-               static public Expression ExplicitConversion (EmitContext ec, Expression expr,
+               static public Expression WideningAndNarrowingConversion (EmitContext ec, Expression expr,
                                                             Type target_type, Location loc)
                {
                        Type expr_type = expr.Type;
@@ -1898,30 +2254,45 @@ namespace Mono.CSharp {
                        }
 
                        int errors = Report.Errors;
-                       Expression ne = ImplicitConversionStandard (ec, expr, target_type, loc);
+                       Expression ne = WideningConversionStandard (ec, expr, target_type, loc);
                        if (Report.Errors > errors)
                                return null;
 
                        if (ne != null)
                                return ne;
 
-                       ne = ExplicitNumericConversion (ec, expr, 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 = NarrowingNumericConversion (ec, expr, target_type, loc);
                        if (ne != null)
                                return ne;
 
                        //
                        // 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);
 
                        //
-                       // Skip the ExplicitReferenceConversion because we can not convert
+                       // Skip the NarrowingReferenceConversion 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);
+                               ne = NarrowingReferenceConversion (expr, target_type);
                                if (ne != null)
                                        return ne;
                        }
@@ -1966,12 +2337,12 @@ namespace Mono.CSharp {
                                        if (e != null){
                                                Expression ci, ce;
 
-                                               ci = ImplicitConversionStandard (ec, e, target_type, loc);
+                                               ci = WideningConversionStandard (ec, e, target_type, loc);
 
                                                if (ci != null)
                                                        return ci;
 
-                                               ce = ExplicitNumericConversion (ec, e, target_type, loc);
+                                               ce = NarrowingNumericConversion (ec, e, target_type, loc);
                                                if (ce != null)
                                                        return ce;
                                                //
@@ -1983,10 +2354,27 @@ namespace Mono.CSharp {
                                        }
                                }
                        }
-                       
-                       ne = ExplicitUserConversion (ec, expr, target_type, loc);
+
+                       //
+                       // VB.NET specific conversions
+                       //
+
+                       ne = BooleanConversions (ec, expr, target_type, loc);
+                       if (ne != null)
+                               return ne;
+
+                       ne = NarrowingStringConversions (ec, expr, target_type, loc);
                        if (ne != null)
                                return ne;
+                       
+                       
+                       //
+                       // VB.NET has no notion of User defined conversions
+                       //
+
+//                     ne = ExplicitUserConversion (ec, expr, target_type, loc);
+//                     if (ne != null)
+//                             return ne;
 
                        if (expr is NullLiteral){
                                Report.Error (37, loc, "Cannot convert null to value type `" +
@@ -1999,29 +2387,94 @@ namespace Mono.CSharp {
                }
 
                /// <summary>
-               ///   Same as ExplicitConversion, only it doesn't include user defined conversions
+               ///   Same as WideningAndNarrowingConversion, only it doesn't include user defined conversions
                /// </summary>
-               static public Expression ExplicitConversionStandard (EmitContext ec, Expression expr,
+               static public Expression WideningAndNarrowingConversionStandard (EmitContext ec, Expression expr,
                                                                     Type target_type, Location l)
                {
                        int errors = Report.Errors;
-                       Expression ne = ImplicitConversionStandard (ec, expr, target_type, l);
+                       Expression ne = WideningConversionStandard (ec, expr, target_type, l);
                        if (Report.Errors > errors)
                                return null;
 
                        if (ne != null)
                                return ne;
 
-                       ne = ExplicitNumericConversion (ec, expr, target_type, l);
+                       if (TypeManager.IsNullableType (expr.Type) && TypeManager.IsNullableType (target_type))
+                               return new Nullable.LiftedConversion (
+                                       expr, target_type, false, true, l).Resolve (ec);
+
+                       ne = NarrowingNumericConversion (ec, expr, target_type, l);
                        if (ne != null)
                                return ne;
 
-                       ne = ExplicitReferenceConversion (expr, target_type);
+                       ne = NarrowingReferenceConversion (expr, target_type);
                        if (ne != null)
                                return ne;
 
                        Error_CannotConvertType (l, expr.Type, target_type);
                        return null;
                }
+
+               /// <summary>
+               ///   Entry point for VB.NET specific implicit conversions
+               /// </summary>
+               static public Expression ImplicitVBConversion (EmitContext ec, Expression expr,
+                                                            Type target_type, Location loc)
+               {
+                       if (RootContext.StricterTypeChecking)
+                               return WideningConversion (ec, expr, target_type, loc);
+                       else
+                               return WideningAndNarrowingConversion(ec, expr, target_type, loc);
+               }
+
+               /// <summary>
+               ///   Mandates VB.NET specific implicit conversions
+               /// </summary>
+               static public Expression ImplicitVBConversionRequired (EmitContext ec, Expression source,
+                                                                    Type target_type, Location loc)
+               {
+                       Expression e;
+
+
+                       int errors = Report.Errors;
+                       e = ImplicitVBConversion (ec, source, target_type, loc);
+                       if (Report.Errors > errors)
+                               return null;
+                       if (e != null)
+                               return e;
+
+                       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){
+                               Constant c = (Constant) source;
+
+                               Expression.Error_ConstantValueCannotBeConverted (loc, c.AsString (), target_type);
+                               return null;
+                       }
+                       
+                       Error_CannotWideningConversion (loc, source.Type, target_type);
+
+                       return null;
+               }
+
+               /// <summary>
+               ///   Entry point for VB.NET specific explicit conversions
+               /// </summary>
+               static public Expression ExplicitVBConversion (EmitContext ec, Expression expr,
+                                                            Type target_type, Location loc)
+               {
+                               return WideningAndNarrowingConversion(ec, expr, target_type, loc);
+               }
+
        }
 }