2005-01-31 Zoltan Varga <vargaz@freemail.hu>
[mono.git] / mcs / gmcs / convert.cs
index dc3bd4ee5da15d275cf6ca5ad4745d5b82a2f414..4580d57e28bbf9a865157de6d7fae0290eb3f14d 100644 (file)
@@ -29,7 +29,7 @@ namespace Mono.CSharp {
                //
                public static EmitContext ConstantEC = null;
                
-               static void Error_CannotConvertType (Location loc, Type source, Type target)
+               static public void Error_CannotConvertType (Location loc, Type source, Type target)
                {
                        Report.Error (30, loc, "Cannot convert type '" +
                                      TypeManager.CSharpName (source) + "' to '" +
@@ -52,12 +52,16 @@ namespace Mono.CSharp {
 
                static bool TypeParameter_to_Null (Type target_type)
                {
-                       if ((target_type.BaseType == null) ||
-                           (target_type.BaseType == TypeManager.value_type) ||
-                           target_type.BaseType.IsValueType)
+                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (target_type);
+                       if (gc == null)
                                return false;
 
-                       return true;
+                       if (gc.HasReferenceTypeConstraint)
+                               return true;
+                       if (gc.HasClassConstraint && !TypeManager.IsValueType (gc.ClassConstraint))
+                               return true;
+
+                       return false;
                }
 
                static Type TypeParam_EffectiveBaseType (EmitContext ec, Type t)
@@ -164,7 +168,7 @@ namespace Mono.CSharp {
                                if (TypeManager.IsValueType (expr_type))
                                        return new BoxedCast (expr);
                                if (expr_type.IsClass || expr_type.IsInterface || expr_type == TypeManager.enum_type){
-                                       if (target_type == TypeManager.anonymous_method_type)
+                                       if (expr_type == TypeManager.anonymous_method_type)
                                                return null;
                                        return new EmptyCast (expr, target_type);
                                }
@@ -173,7 +177,7 @@ namespace Mono.CSharp {
                        } else if (target_type == TypeManager.value_type) {
                                if (TypeManager.IsValueType (expr_type))
                                        return new BoxedCast (expr);
-                               if (expr is NullLiteral)
+                               if (expr_type == TypeManager.null_type)
                                        return new NullCast (expr, target_type);
 
                                return null;
@@ -195,9 +199,9 @@ namespace Mono.CSharp {
                        // Always ensure that the code here and there is in sync
 
                        // from the null type to any reference-type.
-                       if (expr is NullLiteral){
+                       if (expr_type == TypeManager.null_type){
                                if (target_type.IsPointer)
-                                       return NullPointer.Null;
+                                       return new EmptyCast (expr, target_type);
                                        
                                if (!target_type.IsValueType)
                                        return new NullCast (expr, target_type);
@@ -301,6 +305,16 @@ namespace Mono.CSharp {
                                
                        // from any class-type S to any interface-type T.
                        if (target_type.IsInterface) {
+                               if (target_type != TypeManager.iconvertible_type &&
+                                   expr_type.IsValueType && (expr is Constant) &&
+                                   !(expr is IntLiteral || expr is BoolLiteral ||
+                                     expr is FloatLiteral || expr is DoubleLiteral ||
+                                     expr is LongLiteral || expr is CharLiteral ||
+                                     expr is StringLiteral || expr is DecimalLiteral ||
+                                     expr is UIntLiteral || expr is ULongLiteral)) {
+                                       return false;
+                               }
+                               
                                if (TypeManager.ImplementsInterface (expr_type, target_type))
                                        return true;
                        }
@@ -346,8 +360,13 @@ namespace Mono.CSharp {
                                        return true;
                                
                        // from the null type to any reference-type.
-                       if (expr is NullLiteral && !target_type.IsValueType && !TypeManager.IsEnumType (target_type))
-                               return true;
+                       if (expr_type == TypeManager.null_type){
+                               if (target_type.IsPointer)
+                                       return true;
+                       
+                               if (!target_type.IsValueType)
+                                       return true;
+                       }
 
                        // from a generic type definition to a generic instance.
                        if (TypeManager.IsEqual (expr_type, target_type))
@@ -568,6 +587,7 @@ namespace Mono.CSharp {
                        if (expr_type.Equals (target_type))
                                return true;
 
+
                        // First numeric conversions 
 
                        if (expr_type == TypeManager.sbyte_type){
@@ -674,6 +694,20 @@ namespace Mono.CSharp {
                                        return true;
                        }       
                        
+                       if (expr.eclass == ExprClass.MethodGroup){
+                               if (TypeManager.IsDelegateType (target_type) && RootContext.Version != LanguageVersion.ISO_1){
+                                       MethodGroupExpr mg = expr as MethodGroupExpr;
+                                       if (mg != null){
+                                               //
+                                               // This should not happen frequently, so we can create an object
+                                               // to test compatibility
+                                               //
+                                               Expression c = ImplicitDelegateCreation.Create (ec, mg, target_type, Location.Null);
+                                               return c != null;
+                                       }
+                               }
+                       }
+                       
                        if (ImplicitReferenceConversionExists (ec, expr, target_type))
                                return true;
 
@@ -732,6 +766,13 @@ namespace Mono.CSharp {
                                        return true;
                        }
 
+                       //
+                       // If `expr_type' implements `target_type' (which is an iface)
+                       // see TryImplicitIntConversion
+                       // 
+                       if (target_type.IsInterface && target_type.IsAssignableFrom (expr_type))
+                               return true;
+
                        if (target_type == TypeManager.void_ptr_type && expr_type.IsPointer)
                                return true;
 
@@ -740,13 +781,12 @@ namespace Mono.CSharp {
                                        return false;
 
                                AnonymousMethod am = (AnonymousMethod) expr;
-                               int errors = Report.Errors;
 
                                Expression conv = am.Compatible (ec, target_type, true);
                                if (conv != null)
                                        return true;
                        }
-                       
+
                        return false;
                }
 
@@ -1197,7 +1237,7 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (expr_type.Equals (target_type) && !(expr is NullLiteral))
+                       if (expr_type.Equals (target_type) && !TypeManager.IsNullType (expr_type))
                                return expr;
 
                        e = ImplicitNumericConversion (ec, expr, target_type, loc);
@@ -1233,7 +1273,7 @@ namespace Mono.CSharp {
                                }
                                
                                if (target_type.IsPointer) {
-                                       if (expr is NullLiteral)
+                                       if (expr_type == TypeManager.null_type)
                                                return new EmptyCast (expr, target_type);
 
                                        if (expr_type == TypeManager.void_ptr_type)
@@ -1269,7 +1309,7 @@ namespace Mono.CSharp {
                }
 
                /// <summary>
-               ///   Attemps to perform an implict constant conversion of the IntConstant
+               ///   Attempts to perform an implicit constant conversion of the IntConstant
                ///   into a different data type using casts (See Implicit Constant
                ///   Expression Conversions)
                /// </summary>
@@ -1312,7 +1352,7 @@ namespace Mono.CSharp {
                                //
                                // Possibly, we need to create a different 0 literal before passing
                                // to EnumConstant
-                               //n
+                               //
                                if (underlying == TypeManager.int64_type)
                                        e = new LongLiteral (0);
                                else if (underlying == TypeManager.uint64_type)
@@ -1320,11 +1360,26 @@ namespace Mono.CSharp {
 
                                return new EnumConstant (e, target_type);
                        }
+
+                       //
+                       // If `target_type' is an interface and the type of `ic' implements the interface
+                       // e.g. target_type is IComparable, IConvertible, IFormattable
+                       //
+                       if (target_type.IsInterface && target_type.IsAssignableFrom (ic.Type))
+                               return new BoxedCast (ic);
+
                        return null;
                }
 
                static public void Error_CannotImplicitConversion (Location loc, Type source, Type target)
                {
+                       if (source.Name == target.Name){
+                               Report.ExtraInformation (loc,
+                                        String.Format (
+                                               "The type {0} has two conflicting definitons, one comes from {0} and the other from {1}",
+                                               source.Assembly.FullName, target.Assembly.FullName));
+                                                        
+                       }
                        Report.Error (29, loc, "Cannot convert implicitly from {0} to `{1}'",
                                      source == TypeManager.anonymous_method_type ?
                                      "anonymous method" : "`" + TypeManager.CSharpName (source) + "'",
@@ -1332,7 +1387,7 @@ namespace Mono.CSharp {
                }
 
                /// <summary>
-               ///   Attemptes to implicityly convert `target' into `type', using
+               ///   Attempts to implicitly convert `source' into `target_type', using
                ///   ImplicitConversion.  If there is no implicit conversion, then
                ///   an error is signaled
                /// </summary>
@@ -1348,10 +1403,15 @@ namespace Mono.CSharp {
                        if (e != null)
                                return e;
 
-                       if (source is DoubleLiteral && target_type == TypeManager.float_type){
-                               Report.Error (664, loc,
-                                             "Double literal cannot be implicitly converted to " +
-                                             "float type, use F suffix to create a float literal");
+                       if (source is DoubleLiteral) {
+                               if (target_type == TypeManager.float_type) {
+                                       Error_664 (loc, "float", "f");
+                                       return null;
+                               }
+                               if (target_type == TypeManager.decimal_type) {
+                                       Error_664 (loc, "decimal", "m");
+                                       return null;
+                               }
                        }
 
                        if (source is Constant){
@@ -1366,6 +1426,12 @@ namespace Mono.CSharp {
                        return null;
                }
 
+               static void Error_664 (Location loc, string type, string suffix) {
+                       Report.Error (664, loc,
+                               "Literal of type double cannot be implicitly converted to type '{0}'. Add suffix '{1}' to create a literal of this type",
+                               type, suffix);
+               }
+
                /// <summary>
                ///   Performs the explicit numeric conversions
                /// </summary>
@@ -1846,23 +1912,20 @@ namespace Mono.CSharp {
                        //
                        // Unboxing conversion.
                        //
-                       if (expr_type == TypeManager.object_type && target_type.IsValueType){
-                               if (expr is NullLiteral){
-                                       //
-                                       // Skip the ExplicitReferenceConversion because we can not convert
-                                       // from Null to a ValueType, and ExplicitReference wont check against
-                                       // null literal explicitly
-                                       //
-                                       goto skip_explicit;
-                               }
+                       if (expr_type == TypeManager.object_type && target_type.IsValueType)
                                return new UnboxCast (expr, target_type);
 
+                       //
+                       // Skip the ExplicitReferenceConversion because we can not convert
+                       // from Null to a ValueType, and ExplicitReference wont check against
+                       // null literal explicitly
+                       //
+                       if (expr_type != TypeManager.null_type){
+                               ne = ExplicitReferenceConversion (expr, target_type);
+                               if (ne != null)
+                                       return ne;
                        }
 
-                       ne = ExplicitReferenceConversion (expr, target_type);
-                       if (ne != null)
-                               return ne;
-
                skip_explicit:
                        if (ec.InUnsafe){
                                if (target_type.IsPointer){