[Mono-dev] Generic Variance

Marek Safar marek.safar at seznam.cz
Mon Feb 2 06:59:19 EST 2009


Hi Scott,
> This patch adds generic variance support to the C# compiler. This 
> patch does not fully support the spec in that it provides variance 
> only for reference types. This limitation is designed to reflect the 
> current (proposed) level of variance support in the VM. New error 
> codes are defined and tests for each code are provided, as well as 
> tests for variance. This patch is contributed under the MIT/X11 
> license. It is attached.
>
> NOTE: This email is a re-send. The original also had the patch inline, 
> but it was too long for the system. Blarg.
>
I think there is more work needed to update all 
conversion/overload/operator/interence rules but it probably has to wait 
until some specification is released.

The naming convention for your tests should be gtest-variance-01.cs, etc.


Comments:

+    public static bool HasVariantTypeParameter (Type type, Location loc)
+    {

HasXXX method should not issue any compiler errors, change the method 
name or behaviour.

+    public static bool IsVariantOf (Type type1, Type type2)
+    {
+#if GMCS_SOURCE
+        if (type1.IsGenericType && type2.IsGenericType) {
+            Type generic_target_type = type2.GetGenericTypeDefinition ();
+            if (type1.GetGenericTypeDefinition () == generic_target_type) {
+                Type [] t1 = type1.GetGenericArguments ();
+                Type [] t2 = type2.GetGenericArguments ();
+                int i = 0;
+                foreach (Type t in 
generic_target_type.GetGenericArguments ()) {
+                    if ((t.GenericParameterAttributes & 
GenericParameterAttributes.VarianceMask) != 0) {
+                        // FIXME this is not right
+                        if (t1[i].IsValueType || t2[i].IsValueType) {
+                            return false;
+                        }

Use TypeManager.IsValueType if you really want to check any ValueType type.

+            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");
+            }

This check should be done in the parser.

+            GenericParameterAttributes attr = 
GenericParameterAttributes.None;
+            if (variance == Variance.Contravariant)
+                attr |= GenericParameterAttributes.Contravariant;
+            if (variance == Variance.Covariant)
+                attr |= GenericParameterAttributes.Covariant;

You are missing else for second 'if' or could they be both covariant and 
contra-variant ?

+            } else if (RootContext.Version >= LanguageVersion.Future &&
+                       (the_token == Token.IN || the_token == Token.OUT)) {
+                the_token = token ();

LanguageVersion check is not needed here. Look what we do elsewhere.

+                // FIXME this sucks, but it's the easiest way to handle 
the fact that
+                // the dummy setter parameter will violate generic 
covariance.
+                if (IsDummy)
+                    Report.DisableReporting ();
                 parameters.Resolve (ResolveContext);
+                if (IsDummy)
+                    Report.EnableReporting ();

This should really be fixed.

+opt_type_parameter_variance
+    : /* empty */ {
+        $$ = Variance.None;
+      }
+    | type_parameter_variance {
+        $$ = $1;
+      }
+    ;

We use different formating for .jay file.

+        // TODO is there a better way to handle this?
+        if (lexer.parsing_generic_declaration &&
+            RootContext.Version < LanguageVersion.Future &&
+            (name == "in" || name == "out"))
+            continue;

This should not be needed at all.


Thanks
Marek


More information about the Mono-devel-list mailing list