2004-10-11 Martin Baulig <martin@ximian.com>
[mono.git] / mcs / gmcs / convert.cs
index 83ba854169de2ac11ccd85d24be8fc950fadd68a..79b69a3f9e3eb9f86ba651e042aaaae70551adf8 100644 (file)
@@ -50,6 +50,78 @@ namespace Mono.CSharp {
                        return true;
                }
 
+               static Type TypeParam_EffectiveBaseType (Type t)
+               {
+                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
+                       if (gc == null)
+                               return TypeManager.object_type;
+
+                       return TypeParam_EffectiveBaseType (gc);
+               }
+
+               static Type TypeParam_EffectiveBaseType (GenericConstraints gc)
+               {
+                       ArrayList list = new ArrayList ();
+                       list.Add (gc.EffectiveBaseClass);
+                       foreach (Type t in gc.InterfaceConstraints) {
+                               if (!t.IsGenericParameter)
+                                       continue;
+
+                               GenericConstraints new_gc = TypeManager.GetTypeParameterConstraints (t);
+                               if (new_gc != null)
+                                       list.Add (TypeParam_EffectiveBaseType (new_gc));
+                       }
+                       return FindMostEncompassedType (list);
+               }
+
+               static Expression TypeParameterConversion (Expression expr, bool is_reference, Type target_type)
+               {
+                       if (is_reference)
+                               return new EmptyCast (expr, target_type);
+                       else
+                               return new BoxedCast (expr, target_type);
+               }
+
+               static Expression ImplicitTypeParameterConversion (Expression expr, Type target_type)
+               {
+                       Type expr_type = expr.Type;
+
+                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
+
+                       if (gc == null) {
+                               if (target_type == TypeManager.object_type)
+                                       return new BoxedCast (expr);
+
+                               return null;
+                       }
+
+                       // We're converting from a type parameter which is known to be a reference type.
+                       bool is_reference = gc.IsReferenceType;
+                       Type base_type = TypeParam_EffectiveBaseType (gc);
+
+                       if (TypeManager.IsSubclassOf (base_type, target_type))
+                               return TypeParameterConversion (expr, is_reference, target_type);
+
+                       if (target_type.IsInterface) {
+                               if (TypeManager.ImplementsInterface (base_type, target_type))
+                                       return TypeParameterConversion (expr, is_reference, target_type);
+
+                               foreach (Type t in gc.InterfaceConstraints) {
+                                       if (TypeManager.IsSubclassOf (t, target_type))
+                                               return TypeParameterConversion (expr, is_reference, target_type);
+                               }
+                       }
+
+                       foreach (Type t in gc.InterfaceConstraints) {
+                               if (!t.IsGenericParameter)
+                                       continue;
+                               if (TypeManager.IsSubclassOf (t, target_type))
+                                       return TypeParameterConversion (expr, is_reference, target_type);
+                       }
+
+                       return null;
+               }
+
                static EmptyExpression MyEmptyExpr;
                static public Expression ImplicitReferenceConversion (Expression expr, Type target_type)
                {
@@ -64,6 +136,9 @@ namespace Mono.CSharp {
                        if (expr_type == TypeManager.void_type)
                                return null;
 
+                       if (expr_type.IsGenericParameter)
+                               return ImplicitTypeParameterConversion (expr, target_type);
+                               
                        //
                        // notice that it is possible to write "ValueType v = 1", the ValueType here
                        // is an abstract class, and not really a value type, so we apply the same rules.
@@ -177,26 +252,9 @@ namespace Mono.CSharp {
                                        return new EmptyCast (expr, target_type);
 
                        // from a generic type definition to a generic instance.
-                       if (TypeManager.IsEqualGenericType (expr_type, target_type))
+                       if (TypeManager.IsEqual (expr_type, target_type))
                                return new EmptyCast (expr, target_type);
 
-                       if (expr_type.IsGenericParameter) {
-                               GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
-
-                               // We're converting from a type parameter which is known to be a reference type.
-                               if ((gc != null) && gc.IsReferenceType) {
-                                       if (gc.HasClassConstraint && gc.ClassConstraint.IsSubclassOf (target_type))
-                                               return new EmptyCast (expr, target_type);
-
-                                       if (target_type.IsInterface) {
-                                               foreach (Type t in gc.InterfaceConstraints) {
-                                                       if (TypeManager.ImplementsInterface (t, target_type))
-                                                               return new EmptyCast (expr, target_type);
-                                               }
-                                       }
-                               }
-                       }
-                               
                        return null;
                }
 
@@ -208,6 +266,9 @@ namespace Mono.CSharp {
                {
                        Type expr_type = expr.Type;
 
+                       if (expr_type.IsGenericParameter)
+                               return ImplicitTypeParameterConversion (expr, target_type) != null;
+
                        //
                        // This is the boxed case.
                        //
@@ -274,26 +335,9 @@ namespace Mono.CSharp {
                                return true;
 
                        // from a generic type definition to a generic instance.
-                       if (TypeManager.IsEqualGenericType (expr_type, target_type))
+                       if (TypeManager.IsEqual (expr_type, target_type))
                                return true;
 
-                       if (expr_type.IsGenericParameter) {
-                               GenericConstraints gc = TypeManager.GetTypeParameterConstraints (expr_type);
-
-                               // We're converting from a type parameter which is known to be a reference type.
-                               if ((gc != null) && gc.IsReferenceType) {
-                                       if (gc.HasClassConstraint && gc.ClassConstraint.IsSubclassOf (target_type))
-                                               return true;
-
-                                       if (target_type.IsInterface) {
-                                               foreach (Type t in gc.InterfaceConstraints) {
-                                                       if (TypeManager.ImplementsInterface (t, target_type))
-                                                               return true;
-                                               }
-                                       }
-                               }
-                       }
-
                        return false;
                }