2004-11-17 Atsushi Enomoto <atsushi@ximian.com>
[mono.git] / mcs / gmcs / generic.cs
index b920cd862a99ed4e2e55ce7322eea530646867cb..0720906b141f82ce771ef12a67b85c39e3342eff 100644 (file)
@@ -15,6 +15,102 @@ using System.Text;
        
 namespace Mono.CSharp {
 
+       public abstract class GenericConstraints {
+               public abstract GenericParameterAttributes Attributes {
+                       get;
+               }
+
+               public bool HasConstructorConstraint {
+                       get { return (Attributes & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
+               }
+
+               public bool HasReferenceTypeConstraint {
+                       get { return (Attributes & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
+               }
+
+               public bool HasValueTypeConstraint {
+                       get { return (Attributes & GenericParameterAttributes.ValueTypeConstraint) != 0; }
+               }
+
+               public virtual bool HasClassConstraint {
+                       get { return ClassConstraint != null; }
+               }
+
+               public abstract Type ClassConstraint {
+                       get;
+               }
+
+               public abstract Type[] InterfaceConstraints {
+                       get;
+               }
+
+               public abstract Type EffectiveBaseClass {
+                       get;
+               }
+
+               // <summary>
+               //   Returns whether the type parameter is "known to be a reference type".
+               // </summary>
+               public virtual bool IsReferenceType {
+                       get {
+                               if (HasReferenceTypeConstraint)
+                                       return true;
+                               if (HasValueTypeConstraint)
+                                       return false;
+
+                               if (ClassConstraint != null) {
+                                       if (ClassConstraint.IsValueType)
+                                               return false;
+
+                                       if (ClassConstraint != TypeManager.object_type)
+                                               return true;
+                               }
+
+                               foreach (Type t in InterfaceConstraints) {
+                                       if (!t.IsGenericParameter)
+                                               continue;
+
+                                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
+                                       if ((gc != null) && gc.IsReferenceType)
+                                               return true;
+                               }
+
+                               return false;
+                       }
+               }
+
+               // <summary>
+               //   Returns whether the type parameter is "known to be a value type".
+               // </summary>
+               public virtual bool IsValueType {
+                       get {
+                               if (HasValueTypeConstraint)
+                                       return true;
+                               if (HasReferenceTypeConstraint)
+                                       return false;
+
+                               if (ClassConstraint != null) {
+                                       if (!ClassConstraint.IsValueType)
+                                               return false;
+
+                                       if (ClassConstraint != TypeManager.value_type)
+                                               return true;
+                               }
+
+                               foreach (Type t in InterfaceConstraints) {
+                                       if (!t.IsGenericParameter)
+                                               continue;
+
+                                       GenericConstraints gc = TypeManager.GetTypeParameterConstraints (t);
+                                       if ((gc != null) && gc.IsValueType)
+                                               return true;
+                               }
+
+                               return false;
+                       }
+               }
+       }
+
        public enum SpecialConstraint
        {
                Constructor,
@@ -55,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)
                {
@@ -98,7 +195,7 @@ namespace Mono.CSharp {
                                        continue;
                                }
 
-                               TypeExpr expr = ds.ResolveTypeExpr ((Expression) obj, false, loc);
+                               TypeExpr expr = ds.ResolveTypeExpr ((Expression) obj, loc);
                                if (expr == null)
                                        return false;
 
@@ -235,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;
                }
@@ -273,8 +372,8 @@ namespace Mono.CSharp {
                                Type t2 = constraints.ClassConstraint;
                                TypeExpr e2 = constraints.class_constraint;
 
-                               if (!Convert.ImplicitReferenceConversionExists (e1, t2) &&
-                                   !Convert.ImplicitReferenceConversionExists (e2, t1)) {
+                               if (!Convert.ImplicitReferenceConversionExists (ec, e1, t2) &&
+                                   !Convert.ImplicitReferenceConversionExists (ec, e2, t1)) {
                                        Report.Error (455, loc,
                                                      "Type parameter `{0}' inherits " +
                                                      "conflicting constraints `{1}' and `{2}'",
@@ -299,34 +398,26 @@ namespace Mono.CSharp {
                        type.SetGenericParameterAttributes (attrs);
                }
 
-               public GenericParameterAttributes Attributes {
+               public override GenericParameterAttributes Attributes {
                        get { return attrs; }
                }
 
-               public bool HasConstructorConstraint {
-                       get { return (attrs & GenericParameterAttributes.DefaultConstructorConstraint) != 0; }
-               }
-
-               public bool HasReferenceTypeConstraint {
-                       get { return (attrs & GenericParameterAttributes.ReferenceTypeConstraint) != 0; }
-               }
-
-               public bool HasValueTypeConstraint {
-                       get { return (attrs & GenericParameterAttributes.ValueTypeConstraint) != 0; }
-               }
-
-               public bool HasClassConstraint {
-                       get { return class_constraint_type != null; }
+               public override bool HasClassConstraint {
+                       get { return class_constraint != null; }
                }
 
-               public Type ClassConstraint {
+               public override Type ClassConstraint {
                        get { return class_constraint_type; }
                }
 
-               public Type[] InterfaceConstraints {
+               public override Type[] InterfaceConstraints {
                        get { return iface_constraint_types; }
                }
 
+               public override Type EffectiveBaseClass {
+                       get { return effective_base_type; }
+               }
+
                internal bool IsSubclassOf (Type t)
                {
                        if ((class_constraint_type != null) &&
@@ -352,7 +443,9 @@ namespace Mono.CSharp {
                        if (gc.Attributes != attrs)
                                return false;
 
-                       if (HasClassConstraint && !gc.ClassConstraint.Equals (ClassConstraint))
+                       if (HasClassConstraint != gc.HasClassConstraint)
+                               return false;
+                       if (HasClassConstraint && !TypeManager.IsEqual (gc.ClassConstraint, ClassConstraint))
                                return false;
 
                        int gc_icount = gc.InterfaceConstraints != null ?
@@ -366,7 +459,7 @@ namespace Mono.CSharp {
                        foreach (Type iface in gc.InterfaceConstraints) {
                                bool ok = false;
                                foreach (Type check in InterfaceConstraints) {
-                                       if (iface.Equals (check)) {
+                                       if (TypeManager.IsEqual (iface, check)) {
                                                ok = true;
                                                break;
                                        }
@@ -385,6 +478,7 @@ namespace Mono.CSharp {
        //
        public class TypeParameter : MemberCore, IMemberContainer {
                string name;
+               GenericConstraints gc;
                Constraints constraints;
                Location loc;
                GenericTypeParameterBuilder type;
@@ -398,6 +492,12 @@ namespace Mono.CSharp {
                        this.loc = loc;
                }
 
+               public GenericConstraints GenericConstraints {
+                       get {
+                               return gc != null ? gc : constraints;
+                       }
+               }
+
                public Constraints Constraints {
                        get {
                                return constraints;
@@ -429,11 +529,17 @@ namespace Mono.CSharp {
 
                public void Define (GenericTypeParameterBuilder type)
                {
+                       if (this.type != null)
+                               throw new InvalidOperationException ();
+
                        this.type = type;
-                       Type[] ifaces = null;
+                       TypeManager.AddTypeParameter (type, this);
+               }
+
+               public void DefineConstraints ()
+               {
                        if (constraints != null)
                                constraints.Define (type);
-                       TypeManager.AddTypeParameter (type, this);
                }
 
                public bool DefineType (EmitContext ec)
@@ -444,8 +550,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 (
@@ -462,17 +566,22 @@ namespace Mono.CSharp {
 
                                int pos = type.GenericParameterPosition;
                                ParameterData pd = Invocation.GetParameterData (mb);
-                               gc = pd.GenericConstraints (pos);
+                               GenericConstraints temp_gc = pd.GenericConstraints (pos);
                                Type mparam = mb.GetGenericArguments () [pos];
 
+                               if (temp_gc != null)
+                                       gc = new InflatedConstraints (temp_gc, implementing.DeclaringType);
+                               else if (constraints != null)
+                                       gc = new InflatedConstraints (constraints, implementing.DeclaringType);
+
                                bool ok = true;
                                if (constraints != null) {
-                                       if (gc == null)
+                                       if (temp_gc == null)
                                                ok = false;
                                        else if (!constraints.CheckInterfaceMethod (ec, gc))
                                                ok = false;
                                } else {
-                                       if (!is_override && (gc != null))
+                                       if (!is_override && (temp_gc != null))
                                                ok = false;
                                }
 
@@ -554,7 +663,7 @@ namespace Mono.CSharp {
                        get { return Name; }
                }
 
-               IMemberContainer IMemberContainer.ParentContainer {
+               MemberCache IMemberContainer.ParentCache {
                        get { return null; }
                }
 
@@ -613,6 +722,82 @@ namespace Mono.CSharp {
                {
                        return "TypeParameter[" + name + "]";
                }
+
+               protected class InflatedConstraints : GenericConstraints
+               {
+                       GenericConstraints gc;
+                       Type base_type;
+                       Type class_constraint;
+                       Type[] iface_constraints;
+                       Type[] dargs;
+                       Type declaring;
+
+                       public InflatedConstraints (GenericConstraints gc, Type declaring)
+                       {
+                               this.gc = gc;
+                               this.declaring = declaring;
+
+                               dargs = TypeManager.GetTypeArguments (declaring);
+
+                               ArrayList list = new ArrayList ();
+                               if (gc.HasClassConstraint)
+                                       list.Add (inflate (gc.ClassConstraint));
+                               foreach (Type iface in gc.InterfaceConstraints)
+                                       list.Add (inflate (iface));
+
+                               bool has_class_constr = false;
+                               if (list.Count > 0) {
+                                       Type first = (Type) list [0];
+                                       has_class_constr = !first.IsInterface && !first.IsGenericParameter;
+                               }
+
+                               if ((list.Count > 0) && has_class_constr) {
+                                       class_constraint = (Type) list [0];
+                                       iface_constraints = new Type [list.Count - 1];
+                                       list.CopyTo (1, iface_constraints, 0, list.Count - 1);
+                               } else {
+                                       iface_constraints = new Type [list.Count];
+                                       list.CopyTo (iface_constraints, 0);
+                               }
+
+                               if (HasValueTypeConstraint)
+                                       base_type = TypeManager.value_type;
+                               else if (class_constraint != null)
+                                       base_type = class_constraint;
+                               else
+                                       base_type = TypeManager.object_type;
+                       }
+
+                       Type inflate (Type t)
+                       {
+                               if (t == null)
+                                       return null;
+                               if (t.IsGenericParameter)
+                                       return dargs [t.GenericParameterPosition];
+                               if (t.IsGenericInstance) {
+                                       t = t.GetGenericTypeDefinition ();
+                                       t = t.BindGenericParameters (dargs);
+                               }
+
+                               return t;
+                       }
+
+                       public override GenericParameterAttributes Attributes {
+                               get { return gc.Attributes; }
+                       }
+
+                       public override Type ClassConstraint {
+                               get { return class_constraint; }
+                       }
+
+                       public override Type EffectiveBaseClass {
+                               get { return base_type; }
+                       }
+
+                       public override Type[] InterfaceConstraints {
+                               get { return iface_constraints; }
+                       }
+               }
        }
 
        //
@@ -652,6 +837,11 @@ namespace Mono.CSharp {
                        get { return false; }
                }
 
+               public override bool CheckAccessLevel (DeclSpace ds)
+               {
+                       return true;
+               }
+
                public void Error_CannotUseAsUnmanagedType (Location loc)
                {
                        Report.Error (-203, loc, "Can not use type parameter as unamanged type");
@@ -764,8 +954,7 @@ namespace Mono.CSharp {
                        atypes = new Type [count];
 
                        for (int i = 0; i < count; i++){
-                               TypeExpr te = ds.ResolveTypeExpr (
-                                       (Expression) args [i], false, Location);
+                               TypeExpr te = ((Expression) args [i]).ResolveAsTypeTerminal (ec);
                                if (te == null) {
                                        ok = false;
                                        continue;
@@ -888,7 +1077,7 @@ namespace Mono.CSharp {
                                        return false;
                        }
 
-                       return Convert.ImplicitStandardConversionExists (expr, ctype);
+                       return Convert.ImplicitStandardConversionExists (ec, expr, ctype);
                }
 
                protected bool CheckConstraints (EmitContext ec, int index)
@@ -901,41 +1090,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;
                                }
                        }
@@ -943,7 +1130,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];
@@ -964,7 +1151,7 @@ namespace Mono.CSharp {
                        // Finally, check the constructor constraint.
                        //
 
-                       if (!TypeManager.HasConstructorConstraint (ptype))
+                       if (!gc.HasConstructorConstraint)
                                return true;
 
                        if (TypeManager.IsBuiltinType (atype))
@@ -989,8 +1176,10 @@ namespace Mono.CSharp {
 
                public override TypeExpr DoResolveAsTypeStep (EmitContext ec)
                {
-                       if (gt != null)
+                       if (type != null)
                                return this;
+                       if (gt != null)
+                               return DoResolveType (ec);
 
                        //
                        // First, resolve the generic type.
@@ -1008,7 +1197,7 @@ namespace Mono.CSharp {
                                new_args.Add (args);
 
                                args = new_args;
-                               return this;
+                               return DoResolveType (ec);
                        }
 
                        Type t;
@@ -1016,12 +1205,8 @@ namespace Mono.CSharp {
 
                        SimpleName sn = new SimpleName (name, loc);
                        TypeExpr resolved = sn.ResolveAsTypeTerminal (ec);
-                       if ((resolved == null) || (resolved.Type == null)) {
-                               Report.Error (246, loc,
-                                             "The type or namespace name `{0}<...>' "+
-                                             "could not be found", Basename);
+                       if (resolved == null)
                                return null;
-                       }
 
                        t = resolved.Type;
                        if (t == null) {
@@ -1040,16 +1225,11 @@ namespace Mono.CSharp {
                        }
 
                        gt = t.GetGenericTypeDefinition ();
-                       return this;
+                       return DoResolveType (ec);
                }
 
-               public override Type ResolveType (EmitContext ec)
+               TypeExpr DoResolveType (EmitContext ec)
                {
-                       if (type != null)
-                               return type;
-                       if (DoResolveAsTypeStep (ec) == null)
-                               return null;
-
                        //
                        // Resolve the arguments.
                        //
@@ -1077,7 +1257,7 @@ namespace Mono.CSharp {
                        // Now bind the parameters.
                        //
                        type = gt.BindGenericParameters (atypes);
-                       return type;
+                       return this;
                }
 
                public Expression GetSimpleName (EmitContext ec)
@@ -1165,7 +1345,7 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               public bool Define (MethodBuilder mb)
+               public bool Define (MethodBuilder mb, Type return_type)
                {
                        if (!Define ())
                                return false;
@@ -1176,6 +1356,9 @@ namespace Mono.CSharp {
                        for (int i = 0; i < TypeParameters.Length; i++)
                                TypeParameters [i].Define (gen_params [i]);
 
+                       ec = new EmitContext (
+                               this, this, Location, null, return_type, ModFlags, false);
+
                        return true;
                }
 
@@ -1237,7 +1420,11 @@ namespace Mono.CSharp {
 
                public override Expression DoResolve (EmitContext ec)
                {
-                       type = ec.DeclSpace.ResolveType (expr, false, loc);
+                       TypeExpr texpr = expr.ResolveAsTypeTerminal (ec);
+                       if (texpr == null)
+                               return null;
+
+                       type = texpr.ResolveType (ec);
                        if (type == null)
                                return null;