2009-02-16 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / generic.cs
index d1bbaf8bfdb223c5c7d9c9c7a7b01e1546c3ba4b..9bdcc1d77fc33725dde6203eae64c7e32a2ca3c8 100644 (file)
@@ -124,6 +124,13 @@ namespace Mono.CSharp {
                }
        }
 
+       public enum Variance
+       {
+               None,
+               Covariant,
+               Contravariant
+       }
+
        public enum SpecialConstraint
        {
                Constructor,
@@ -577,13 +584,18 @@ namespace Mono.CSharp {
                Constraints constraints;
                GenericTypeParameterBuilder type;
                MemberCache member_cache;
+               Variance variance;
 
                public TypeParameter (DeclSpace parent, DeclSpace decl, string name,
-                                     Constraints constraints, Attributes attrs, Location loc)
+                                     Constraints constraints, Attributes attrs, Variance variance, Location loc)
                        : base (parent, new MemberName (name, loc), attrs)
                {
                        this.decl = decl;
                        this.constraints = constraints;
+                       this.variance = variance;
+                       if (variance != Variance.None && !(decl is Interface) && !(decl is Delegate)) {
+                               Report.Error (-36, loc, "Generic variance can only be used with interfaces and delegates");
+                       }
                }
 
                public GenericConstraints GenericConstraints {
@@ -598,6 +610,10 @@ namespace Mono.CSharp {
                        get { return decl; }
                }
 
+               public Variance Variance {
+                       get { return variance; }
+               }
+
                public Type Type {
                        get { return type; }
                }
@@ -746,17 +762,28 @@ namespace Mono.CSharp {
                                gc = (GenericConstraints) constraints;
                        }
 
-                       if (gc == null)
-                               return true;
+                       SetConstraints (type);
+                       return true;
+               }
 
-                       if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
-                               type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
+               public void SetConstraints (GenericTypeParameterBuilder type)
+               {
+                       GenericParameterAttributes attr = GenericParameterAttributes.None;
+                       if (variance == Variance.Contravariant)
+                               attr |= GenericParameterAttributes.Contravariant;
+                       else if (variance == Variance.Covariant)
+                               attr |= GenericParameterAttributes.Covariant;
 
-                       type.SetInterfaceConstraints (gc.InterfaceConstraints);
-                       type.SetGenericParameterAttributes (gc.Attributes);
-                       TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+                       if (gc != null) {
+                               if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
+                                       type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
 
-                       return true;
+                               attr |= gc.Attributes;
+                               type.SetInterfaceConstraints (gc.InterfaceConstraints);
+                               TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+                       }
+                       
+                       type.SetGenericParameterAttributes (attr);
                }
 
                /// <summary>
@@ -1167,11 +1194,18 @@ namespace Mono.CSharp {
        public class TypeParameterName : SimpleName
        {
                Attributes attributes;
+               Variance variance;
 
                public TypeParameterName (string name, Attributes attrs, Location loc)
+                       : this (name, attrs, Variance.None, loc)
+               {
+               }
+
+               public TypeParameterName (string name, Attributes attrs, Variance variance, Location loc)
                        : base (name, loc)
                {
                        attributes = attrs;
+                       this.variance = variance;
                }
 
                public Attributes OptAttributes {
@@ -1179,6 +1213,12 @@ namespace Mono.CSharp {
                                return attributes;
                        }
                }
+
+               public Variance Variance {
+                       get {
+                               return variance;
+                       }
+               }
        }
 
        /// <summary>
@@ -1263,6 +1303,42 @@ namespace Mono.CSharp {
                        return ConstraintChecker.CheckConstraints (ec, open_type, gen_params, args.Arguments, loc);
                }
 
+               static bool IsVariant (Type type)
+               {
+                       return (type.GenericParameterAttributes & GenericParameterAttributes.VarianceMask) != 0;
+               }
+       
+               static bool IsCovariant (Type type)
+               {
+                       return (type.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0;
+               }
+       
+               static bool IsContravariant (Type type)
+               {
+                       return (type.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0;
+               }
+       
+               public bool VerifyVariantTypeParameters ()
+               {
+                       for (int i = 0; i < args.Count; i++) {
+                               Type argument = args.Arguments[i];
+                               if (argument.IsGenericParameter && IsVariant (argument)) {
+                                       if (IsContravariant (argument) && !IsContravariant (gen_params[i])) {
+                                               Report.Error (-34, loc, "Contravariant type parameters can only be used " +
+                                             "as type arguments in contravariant positions");
+                                               return false;
+                                       }
+                                       else if (IsCovariant (argument) && !IsCovariant (gen_params[i])) {
+                                               Report.Error (-35, loc, "Covariant type parameters can only be used " +
+                                             "as type arguments in covariant positions");
+                                               return false;
+                                       }
+                               }
+                       }
+                       return true;
+               }
+
+               
                public override bool CheckAccessLevel (DeclSpace ds)
                {
                        return ds.CheckAccessLevel (open_type);
@@ -1283,7 +1359,7 @@ namespace Mono.CSharp {
                }
 
                public override bool IsValueType {
-                       get { return open_type.IsValueType; }
+                       get { return TypeManager.IsStruct (open_type); }
                }
 
                public override bool IsInterface {
@@ -1370,7 +1446,7 @@ namespace Mono.CSharp {
                                if (!atype.IsGenericType)
 #endif
                                is_class = atype.IsClass || atype.IsInterface;
-                               is_struct = atype.IsValueType && !TypeManager.IsNullableType (atype);
+                               is_struct = TypeManager.IsValueType (atype) && !TypeManager.IsNullableType (atype);
                        }
 
                        //
@@ -1421,7 +1497,7 @@ namespace Mono.CSharp {
                        if (!gc.HasConstructorConstraint)
                                return true;
 
-                       if (TypeManager.IsBuiltinType (atype) || atype.IsValueType)
+                       if (TypeManager.IsBuiltinType (atype) || TypeManager.IsValueType (atype))
                                return true;
 
                        if (HasDefaultConstructor (atype))
@@ -1463,7 +1539,12 @@ namespace Mono.CSharp {
                                ctype = ct.Type;
                        } else if (ctype.IsGenericParameter) {
                                int pos = ctype.GenericParameterPosition;
-                               ctype = atypes [pos];
+                               if (ctype.DeclaringMethod == null) {
+                                       // FIXME: Implement
+                                       return true;
+                               } else {                                
+                                       ctype = atypes [pos];
+                               }
                        }
 
                        if (Convert.ImplicitStandardConversionExists (expr, ctype))
@@ -1613,10 +1694,10 @@ namespace Mono.CSharp {
        public class GenericMethod : DeclSpace
        {
                FullNamedExpression return_type;
-               Parameters parameters;
+               ParametersCompiled parameters;
 
                public GenericMethod (NamespaceEntry ns, DeclSpace parent, MemberName name,
-                                     FullNamedExpression return_type, Parameters parameters)
+                                     FullNamedExpression return_type, ParametersCompiled parameters)
                        : base (ns, parent, name, null)
                {
                        this.return_type = return_type;
@@ -1641,7 +1722,7 @@ namespace Mono.CSharp {
                ///   Define and resolve the type parameters.
                ///   We're called from Method.Define().
                /// </summary>
-               public bool Define (MethodBuilder mb)
+               public bool Define (MethodOrOperator m)
                {
                        TypeParameterName[] names = MemberName.TypeArguments.GetDeclarations ();
                        string[] snames = new string [names.Length];
@@ -1649,14 +1730,18 @@ namespace Mono.CSharp {
                                string type_argument_name = names[i].Name;
                                int idx = parameters.GetParameterIndexByName (type_argument_name);
                                if (idx >= 0) {
-                                       Error_ParameterNameCollision (parameters [i].Location, type_argument_name, "method parameter");
-                                       return false;
+                                       Block b = m.Block;
+                                       if (b == null)
+                                               b = new Block (null);
+
+                                       b.Error_AlreadyDeclaredTypeParameter (parameters [i].Location,
+                                               type_argument_name, "method parameter");
                                }
                                
                                snames[i] = type_argument_name;
                        }
 
-                       GenericTypeParameterBuilder[] gen_params = mb.DefineGenericParameters (snames);
+                       GenericTypeParameterBuilder[] gen_params = m.MethodBuilder.DefineGenericParameters (snames);
                        for (int i = 0; i < TypeParameters.Length; i++)
                                TypeParameters [i].Define (gen_params [i]);
 
@@ -1671,12 +1756,6 @@ namespace Mono.CSharp {
                        return true;
                }
 
-               internal static void Error_ParameterNameCollision (Location loc, string name, string collisionWith)
-               {
-                       Report.Error (412, loc, "The type parameter name `{0}' is the same as `{1}'",
-                               name, collisionWith);
-               }
-
                /// <summary>
                ///   We're called from MethodData.Define() after creating the MethodBuilder.
                /// </summary>
@@ -1761,7 +1840,7 @@ namespace Mono.CSharp {
                                // become equal.
                                //
                                while (b.IsArray) {
-                                       b = b.GetElementType ();
+                                       b = GetElementType (b);
                                        if (a.Equals (b))
                                                return false;
                                }
@@ -1829,8 +1908,8 @@ namespace Mono.CSharp {
                                if (a.GetArrayRank () != b.GetArrayRank ())
                                        return false;
                        
-                               a = a.GetElementType ();
-                               b = b.GetElementType ();
+                               a = GetElementType (a);
+                               b = GetElementType (b);
 
                                return MayBecomeEqualGenericTypes (a, b, class_inferred, method_inferred);
                        }
@@ -2060,7 +2139,7 @@ namespace Mono.CSharp {
                                        if (at.GetArrayRank () != pt.GetArrayRank ())
                                                return false;
 
-                                       return UnifyType (pt.GetElementType (), at.GetElementType (), inferred);
+                                       return UnifyType (TypeManager.GetElementType (pt), TypeManager.GetElementType (at), inferred);
                                }
 
                                if (!pt.IsGenericType)
@@ -2796,10 +2875,11 @@ namespace Mono.CSharp {
                        return LowerBoundInference (e.Type, t) * 2;
                }
 
-               static void RemoveDependentTypes (ArrayList types, Type returnType)
+               void RemoveDependentTypes (ArrayList types, Type returnType)
                {
-                       if (returnType.IsGenericParameter) {
-                               types [returnType.GenericParameterPosition] = null;
+                       int idx = IsUnfixed (returnType);
+                       if (idx >= 0) {
+                               types [idx] = null;
                                return;
                        }