2009-02-16 Marek Safar <marek.safar@gmail.com>
[mono.git] / mcs / mcs / generic.cs
index 77844a666b0be5e9bc1b34dbdc3e60ab72ce552e..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);