2004-09-28 Martin Baulig <martin@ximian.com>
authorMartin Baulig <martin@novell.com>
Tue, 28 Sep 2004 05:46:28 +0000 (05:46 -0000)
committerMartin Baulig <martin@novell.com>
Tue, 28 Sep 2004 05:46:28 +0000 (05:46 -0000)
* generic.cs
(GenericConstraints.EffectiveBaseClass): New public property.
(TypeParameter.GenericConstraints): New public property.
(ConstructedType.CheckConstraints): Improved.

* convert.cs (Convert.TypeParam_EffectiveBaseType): New private method.
(Convert.TypeParameterConversion): New private method; use this in
ImplicitReferenceConversion() and ImplicitReferenceConversionExists()
for all conversions related to type parameters.

svn path=/trunk/mcs/; revision=34463

mcs/gmcs/ChangeLog
mcs/gmcs/convert.cs
mcs/gmcs/generic.cs
mcs/gmcs/support.cs
mcs/gmcs/typemanager.cs

index f0ca4744cad96e539ccd6ac44b0ade45bd5e3b03..546261e79283ecb2e6825226fede6f24194f83d8 100755 (executable)
@@ -1,3 +1,15 @@
+2004-09-28  Martin Baulig  <martin@ximian.com>
+
+       * generic.cs
+       (GenericConstraints.EffectiveBaseClass): New public property.
+       (TypeParameter.GenericConstraints): New public property.
+       (ConstructedType.CheckConstraints): Improved.
+
+       * convert.cs (Convert.TypeParam_EffectiveBaseType): New private method.
+       (Convert.TypeParameterConversion): New private method; use this in
+       ImplicitReferenceConversion() and ImplicitReferenceConversionExists()
+       for all conversions related to type parameters.
+
 2004-09-24  Martin Baulig  <martin@ximian.com>
 
        * convert.cs (Convert.ImplicitReferenceConversion): Added implicit
index 83ba854169de2ac11ccd85d24be8fc950fadd68a..2639009ec3418e45209d32089c3aa44b5471d6f6 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.
@@ -180,23 +255,6 @@ namespace Mono.CSharp {
                        if (TypeManager.IsEqualGenericType (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.
                        //
@@ -277,23 +338,6 @@ namespace Mono.CSharp {
                        if (TypeManager.IsEqualGenericType (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;
                }
 
index 32cc2b038e077507eec679cc8e3b2b05859b3b67..0fbd8ec4d6ecce036978dea18131da007de339dd 100644 (file)
@@ -32,7 +32,7 @@ namespace Mono.CSharp {
                        get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
                }
 
-               public bool HasClassConstraint {
+               public virtual bool HasClassConstraint {
                        get { return ClassConstraint != null; }
                }
 
@@ -44,6 +44,10 @@ namespace Mono.CSharp {
                        get;
                }
 
+               public abstract Type EffectiveBaseClass {
+                       get;
+               }
+
                // <summary>
                //   Returns whether the type parameter is "known to be a reference type".
                // </summary>
@@ -147,6 +151,7 @@ namespace Mono.CSharp {
                int num_constraints, first_constraint;
                Type class_constraint_type;
                Type[] iface_constraint_types;
+               Type effective_base_type;
 
                public bool Resolve (DeclSpace ds)
                {
@@ -327,10 +332,12 @@ namespace Mono.CSharp {
                                }
                        }
 
-                       if (HasReferenceTypeConstraint)
-                               class_constraint_type = TypeManager.object_type;
+                       if (class_constraint_type != null)
+                               effective_base_type = class_constraint_type;
                        else if (HasValueTypeConstraint)
-                               class_constraint_type = TypeManager.value_type;
+                               effective_base_type = TypeManager.value_type;
+                       else
+                               effective_base_type = TypeManager.object_type;
 
                        return true;
                }
@@ -395,6 +402,10 @@ namespace Mono.CSharp {
                        get { return attrs; }
                }
 
+               public override bool HasClassConstraint {
+                       get { return class_constraint != null; }
+               }
+
                public override Type ClassConstraint {
                        get { return class_constraint_type; }
                }
@@ -403,6 +414,10 @@ namespace Mono.CSharp {
                        get { return iface_constraint_types; }
                }
 
+               public override Type EffectiveBaseClass {
+                       get { return effective_base_type; }
+               }
+
                internal bool IsSubclassOf (Type t)
                {
                        if ((class_constraint_type != null) &&
@@ -428,6 +443,8 @@ namespace Mono.CSharp {
                        if (gc.Attributes != attrs)
                                return false;
 
+                       if (HasClassConstraint != gc.HasClassConstraint)
+                               return false;
                        if (HasClassConstraint && !gc.ClassConstraint.Equals (ClassConstraint))
                                return false;
 
@@ -461,6 +478,7 @@ namespace Mono.CSharp {
        //
        public class TypeParameter : MemberCore, IMemberContainer {
                string name;
+               GenericConstraints gc;
                Constraints constraints;
                Location loc;
                GenericTypeParameterBuilder type;
@@ -474,6 +492,12 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public GenericConstraints GenericConstraints {
+                       get {
+                               return gc != null ? gc : constraints;
+                       }
+               }
+
                public Constraints Constraints {
                        get {
                                return constraints;
@@ -520,8 +544,6 @@ namespace Mono.CSharp {
                public bool DefineType (EmitContext ec, MethodBuilder builder,
                                        MethodInfo implementing, bool is_override)
                {
-                       GenericConstraints gc;
-
                        if (implementing != null) {
                                if (is_override && (constraints != null)) {
                                        Report.Error (
@@ -977,41 +999,39 @@ namespace Mono.CSharp {
 
                        Expression aexpr = new EmptyExpression (atype);
 
-                       Type parent = ptype.BaseType;
+                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (ptype);
+                       if (gc == null)
+                               return true;
 
                        //
                        // First, check the `class' and `struct' constraints.
                        //
-                       if (parent == TypeManager.object_type) {
-                               if (!atype.IsClass) {
-                                       Report.Error (452, loc, "The type `{0}' must be " +
-                                                     "a reference type in order to use it " +
-                                                     "as type parameter `{1}' in the " +
-                                                     "generic type or method `{2}'.",
-                                                     atype, ptype, DeclarationName);
-                                       return false;
-                               }
-                       } else if (parent == TypeManager.value_type) {
-                               if (!atype.IsValueType) {
-                                       Report.Error (453, loc, "The type `{0}' must be " +
-                                                     "a value type in order to use it " +
-                                                     "as type parameter `{1}' in the " +
-                                                     "generic type or method `{2}'.",
-                                                     atype, ptype, DeclarationName);
-                                       return false;
-                               }
+                       if (gc.HasReferenceTypeConstraint && !atype.IsClass) {
+                               Report.Error (452, loc, "The type `{0}' must be " +
+                                             "a reference type in order to use it " +
+                                             "as type parameter `{1}' in the " +
+                                             "generic type or method `{2}'.",
+                                             atype, ptype, DeclarationName);
+                               return false;
+                       } else if (gc.HasValueTypeConstraint && !atype.IsValueType) {
+                               Report.Error (453, loc, "The type `{0}' must be " +
+                                             "a value type in order to use it " +
+                                             "as type parameter `{1}' in the " +
+                                             "generic type or method `{2}'.",
+                                             atype, ptype, DeclarationName);
+                               return false;
                        }
 
                        //
                        // The class constraint comes next.
                        //
-                       if ((parent != null) && (parent != TypeManager.object_type)) {
-                               if (!CheckConstraint (ec, ptype, aexpr, parent)) {
+                       if (gc.HasClassConstraint) {
+                               if (!CheckConstraint (ec, ptype, aexpr, gc.ClassConstraint)) {
                                        Report.Error (309, loc, "The type `{0}' must be " +
                                                      "convertible to `{1}' in order to " +
                                                      "use it as parameter `{2}' in the " +
                                                      "generic type or method `{3}'",
-                                                     atype, parent, ptype, DeclarationName);
+                                                     atype, gc.ClassConstraint, ptype, DeclarationName);
                                        return false;
                                }
                        }
@@ -1019,7 +1039,7 @@ namespace Mono.CSharp {
                        //
                        // Now, check the interface constraints.
                        //
-                       foreach (Type it in TypeManager.GetInterfaces (ptype)) {
+                       foreach (Type it in gc.InterfaceConstraints) {
                                Type itype;
                                if (it.IsGenericParameter)
                                        itype = atypes [it.GenericParameterPosition];
@@ -1040,7 +1060,7 @@ namespace Mono.CSharp {
                        // Finally, check the constructor constraint.
                        //
 
-                       if (!TypeManager.HasConstructorConstraint (ptype))
+                       if (!gc.HasConstructorConstraint)
                                return true;
 
                        if (TypeManager.IsBuiltinType (atype))
index 2aedf4c9435f8c1ce55cbe5ca122ae2ee7f2ed48..41f1b6e0b158871a2287d43037d61c51382fcfeb 100755 (executable)
@@ -285,6 +285,7 @@ namespace Mono.CSharp {
        public class ReflectionConstraints : GenericConstraints
        {
                GenericParameterAttributes attrs;
+               Type base_type;
                Type class_constraint;
                Type[] iface_constraints;
 
@@ -298,6 +299,13 @@ namespace Mono.CSharp {
                        } else
                                iface_constraints = constraints;
                        attrs = t.GenericParameterAttributes;
+
+                       if (HasValueTypeConstraint)
+                               base_type = TypeManager.value_type;
+                       else if (class_constraint != null)
+                               base_type = class_constraint;
+                       else
+                               base_type = TypeManager.object_type;
                }
 
                public override GenericParameterAttributes Attributes {
@@ -308,6 +316,10 @@ namespace Mono.CSharp {
                        get { return class_constraint; }
                }
 
+               public override Type EffectiveBaseClass {
+                       get { return base_type; }
+               }
+
                public override Type[] InterfaceConstraints {
                        get { return iface_constraints; }
                }
index 328f234799c0882c70b0678e81112eac72ede798..9c7659b865c38e37640df2c64c8ca3a99acb6477 100755 (executable)
@@ -568,7 +568,7 @@ public class TypeManager {
 
                TypeParameter tparam = LookupTypeParameter (t);
                if (tparam != null)
-                       return tparam.Constraints;
+                       return tparam.GenericConstraints;
 
                return new ReflectionConstraints (t);
        }