This commit adds generic variance support under the new
authorScott Thomas <lunchtimemama@gmail.com>
Wed, 4 Feb 2009 04:22:19 +0000 (04:22 -0000)
committerScott Thomas <lunchtimemama@gmail.com>
Wed, 4 Feb 2009 04:22:19 +0000 (04:22 -0000)
"future" langversion. Variance is allowed in interface
and delegate types. Covariant type parameters are denoted
with the "out" keyword like so:

interface IFoo<out T> {
    T Bar { get; }
}

And contravariant type parameters are dentoed with the
"in" keyword, like so:

delegate void Bar<in T> (T input);

Covariant type parameters can only be used as method
return types and type arguments for inherited
interfaces. Contravariant type parameters can only be
used as by-value method parameter types.

Only reference type are variant.

!!!IT SHOULD BE NOTED!!!
That the Mono VM does not yet fully support generic
type variance, so variant code compiled with this
feature will not run on Mono until variance support
is complete. Code compiled with this feature will run
on the .NET 2.0 virtual machine.

This patch is contributed under the MIT/X11 license.

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

52 files changed:
mcs/errors/ChangeLog
mcs/errors/errors.txt
mcs/errors/gcs1525.cs
mcs/errors/gcs1644-15.cs [new file with mode: 0644]
mcs/errors/gcs1644-16.cs [new file with mode: 0644]
mcs/errors/gcs8033-2.cs [new file with mode: 0644]
mcs/errors/gcs8033.cs [new file with mode: 0644]
mcs/errors/gcs8034-10.cs [new file with mode: 0644]
mcs/errors/gcs8034-2.cs [new file with mode: 0644]
mcs/errors/gcs8034-3.cs [new file with mode: 0644]
mcs/errors/gcs8034-4.cs [new file with mode: 0644]
mcs/errors/gcs8034-5.cs [new file with mode: 0644]
mcs/errors/gcs8034-6.cs [new file with mode: 0644]
mcs/errors/gcs8034-7.cs [new file with mode: 0644]
mcs/errors/gcs8034-8.cs [new file with mode: 0644]
mcs/errors/gcs8034-9.cs [new file with mode: 0644]
mcs/errors/gcs8034.cs [new file with mode: 0644]
mcs/errors/gcs8035-10.cs [new file with mode: 0644]
mcs/errors/gcs8035-2.cs [new file with mode: 0644]
mcs/errors/gcs8035-3.cs [new file with mode: 0644]
mcs/errors/gcs8035-4.cs [new file with mode: 0644]
mcs/errors/gcs8035-5.cs [new file with mode: 0644]
mcs/errors/gcs8035-6.cs [new file with mode: 0644]
mcs/errors/gcs8035-7.cs [new file with mode: 0644]
mcs/errors/gcs8035-8.cs [new file with mode: 0644]
mcs/errors/gcs8035-9.cs [new file with mode: 0644]
mcs/errors/gcs8035.cs [new file with mode: 0644]
mcs/errors/gcs8036-2.cs [new file with mode: 0644]
mcs/errors/gcs8036.cs [new file with mode: 0644]
mcs/errors/gcs8037-2.cs [new file with mode: 0644]
mcs/errors/gcs8037.cs [new file with mode: 0644]
mcs/errors/gcs8038-2.cs [new file with mode: 0644]
mcs/errors/gcs8038-3.cs [new file with mode: 0644]
mcs/errors/gcs8038.cs [new file with mode: 0644]
mcs/errors/gcs8039.cs [new file with mode: 0644]
mcs/mcs/ChangeLog
mcs/mcs/class.cs
mcs/mcs/convert.cs
mcs/mcs/cs-parser.jay
mcs/mcs/cs-tokenizer.cs
mcs/mcs/decl.cs
mcs/mcs/delegate.cs
mcs/mcs/driver.cs
mcs/mcs/generic-mcs.cs
mcs/mcs/generic.cs
mcs/mcs/parameter.cs
mcs/mcs/rootcontext.cs
mcs/mcs/typemanager.cs
mcs/tests/ChangeLog
mcs/tests/gtest-variance-1.cs [new file with mode: 0644]
mcs/tests/gtest-variance-2.cs [new file with mode: 0644]
mcs/tests/known-issues-gmcs

index b83694916bd4c18b30124c8db0640bb513a5d02f..f1b5cec7b76839fcfdc7eddfeea3ef5d43c8947e 100644 (file)
@@ -1,3 +1,46 @@
+2009-02-04  Scott Peterson  <lunchtimemama@gmail.com>
+
+       This patch is contributed under the MIT/X11 license.
+
+       * errors.txt: Added new mono-specific errors codes -33 to -39 pertaining
+       to generic variance.
+
+       * gcs8033.cs:
+       * gcs8033-2.cs:
+       * gcs8034.cs:
+       * gcs8034-2.cs:
+       * gcs8034-3.cs:
+       * gcs8034-4.cs:
+       * gcs8034-5.cs:
+       * gcs8034-6.cs:
+       * gcs8034-7.cs:
+       * gcs8034-8.cs:
+       * gcs8034-9.cs:
+       * gcs8034-10.cs:
+       * gcs8035.cs:
+       * gcs8035-2.cs:
+       * gcs8035-3.cs:
+       * gcs8035-4.cs:
+       * gcs8035-5.cs:
+       * gcs8035-6.cs:
+       * gcs8035-7.cs:
+       * gcs8035-8.cs:
+       * gcs8035-9.cs:
+       * gcs8035-10.cs:
+       * gcs8036.cs:
+       * gcs8036-2.cs:
+       * gcs8037.cs:
+       * gcs8037-2.cs:
+       * gcs8038.cs:
+       * gcs8038-2.cs:
+       * gcs8038-3.cs:
+       * gcs8039.cs: Added tests for new error codes.
+
+       * gcs1525.cs: Updated error message to jive with new grammar.
+
+       * gcs1644-15.cs:
+       * gcs1644-16.cs: Add tests for "unsupported feature" error in iso-2.
+
 2009-01-19  Zoltan Varga  <vargaz@gmail.com>
 
        * Makefile (check): Add a standard check target.
index f8abfa43c60b55631d97f427a07be5bcf5a4b18b..50a5199886921708ad6caffeacd0425d89b8d363 100644 (file)
@@ -91,6 +91,24 @@ numbers, as they look nicer on the debugging output.
 
 -31     Internal compiler error during the method emit phase.
 
+-32     Internal compiler error during parsing.
+
+-33     Contravariant type parameters cannot be the return type.
+
+-34     Contravariant type parameters cannot be used as type arguments.
+
+-35     Covariant type parameters cannot be used as type arguments except
+        for inherited interfaces.
+
+-36     Variant type parameters can only be used with interface and
+        delegate types.
+
+-37     Contravariant type parameters cannot be byref method parameters.
+
+-38     Covariant type parameters cannot be used as method parameters.
+
+-39     Contravariant type parameters cannot be used in interface inheritance.
+
 ----------
 
 Errors that we have allocated that will have corresponding errors in
index 409d20a5320e8962720ee3a44975914d52e934ae..1fba74b47c1a97ed50c0fcf43c08258f252de11e 100644 (file)
@@ -1,4 +1,4 @@
-// CS1525: Unexpected symbol `>', expecting `[', or `identifier'
+// CS1525: Unexpected symbol `>', expecting `[', `identifier', `in', or `out'
 // Line: 4
 
 public class C<>
diff --git a/mcs/errors/gcs1644-15.cs b/mcs/errors/gcs1644-15.cs
new file mode 100644 (file)
index 0000000..e878496
--- /dev/null
@@ -0,0 +1,6 @@
+// CS1644: Feature `generic variance' cannot be used because it is not part of the C# 2.0 language specification\r
+// Line: 5\r
+// Compiler options: -langversion:iso-2
+
+ public interface IFoo<out T> {
+ }
diff --git a/mcs/errors/gcs1644-16.cs b/mcs/errors/gcs1644-16.cs
new file mode 100644 (file)
index 0000000..6b8e398
--- /dev/null
@@ -0,0 +1,6 @@
+// CS1644: Feature `generic variance' cannot be used because it is not part of the C# 2.0 language specification\r
+// Line: 5\r
+// Compiler options: -langversion:iso-2
+
+ public interface IFoo<in T> {
+ }
diff --git a/mcs/errors/gcs8033-2.cs b/mcs/errors/gcs8033-2.cs
new file mode 100644 (file)
index 0000000..73329af
--- /dev/null
@@ -0,0 +1,5 @@
+// CS8033: Contravariant type parameters can only be used in input positions\r
+// Line: 5\r
+// Compiler options: -langversion:future
+
+delegate T D<in T> ();
diff --git a/mcs/errors/gcs8033.cs b/mcs/errors/gcs8033.cs
new file mode 100644 (file)
index 0000000..0b212ae
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8033: Contravariant type parameters can only be used in input positions\r
+// Line: 7\r
+// Compiler options: -langversion:future
+
+interface A<in T>
+{
+       T B();
+}
diff --git a/mcs/errors/gcs8034-10.cs b/mcs/errors/gcs8034-10.cs
new file mode 100644 (file)
index 0000000..c47f0b5
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate void B<in T> (A<A<T>> a);
diff --git a/mcs/errors/gcs8034-2.cs b/mcs/errors/gcs8034-2.cs
new file mode 100644 (file)
index 0000000..d689c71
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T>
+{
+       A<A<T>> A { get; }
+}
diff --git a/mcs/errors/gcs8034-3.cs b/mcs/errors/gcs8034-3.cs
new file mode 100644 (file)
index 0000000..94947f6
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T>
+{
+       A<T> C();
+}
diff --git a/mcs/errors/gcs8034-4.cs b/mcs/errors/gcs8034-4.cs
new file mode 100644 (file)
index 0000000..cc67972
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T>
+{
+       A<A<T>> C();
+}
diff --git a/mcs/errors/gcs8034-5.cs b/mcs/errors/gcs8034-5.cs
new file mode 100644 (file)
index 0000000..8e9169c
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T>
+{
+       void C(A<T> a);
+}
diff --git a/mcs/errors/gcs8034-6.cs b/mcs/errors/gcs8034-6.cs
new file mode 100644 (file)
index 0000000..23c2919
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T>
+{
+       void C(A<A<T>> a);
+}
diff --git a/mcs/errors/gcs8034-7.cs b/mcs/errors/gcs8034-7.cs
new file mode 100644 (file)
index 0000000..1bc900f
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate A<T> B<in T> ();
diff --git a/mcs/errors/gcs8034-8.cs b/mcs/errors/gcs8034-8.cs
new file mode 100644 (file)
index 0000000..c3134bf
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate A<A<T>> B<in T> ();
diff --git a/mcs/errors/gcs8034-9.cs b/mcs/errors/gcs8034-9.cs
new file mode 100644 (file)
index 0000000..451cf0a
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate void B<in T> (A<T> a);
diff --git a/mcs/errors/gcs8034.cs b/mcs/errors/gcs8034.cs
new file mode 100644 (file)
index 0000000..2b8c2cd
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8034: Contravariant type parameters can only be used as input arguments to a method\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T>
+{
+       A<T> A { get; }
+}
diff --git a/mcs/errors/gcs8035-10.cs b/mcs/errors/gcs8035-10.cs
new file mode 100644 (file)
index 0000000..ef1a547
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate void B<out T> (A<A<T>> a);
diff --git a/mcs/errors/gcs8035-2.cs b/mcs/errors/gcs8035-2.cs
new file mode 100644 (file)
index 0000000..959d0e4
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<out T>
+{
+       A<A<T>> A { get; }
+}
diff --git a/mcs/errors/gcs8035-3.cs b/mcs/errors/gcs8035-3.cs
new file mode 100644 (file)
index 0000000..e739065
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<out T>
+{
+       A<T> C();
+}
diff --git a/mcs/errors/gcs8035-4.cs b/mcs/errors/gcs8035-4.cs
new file mode 100644 (file)
index 0000000..7ccf793
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<out T>
+{
+       A<A<T>> C();
+}
diff --git a/mcs/errors/gcs8035-5.cs b/mcs/errors/gcs8035-5.cs
new file mode 100644 (file)
index 0000000..b1285c1
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<out T>
+{
+       void C(A<T> a);
+}
diff --git a/mcs/errors/gcs8035-6.cs b/mcs/errors/gcs8035-6.cs
new file mode 100644 (file)
index 0000000..0d32091
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<out T>
+{
+       void C(A<A<T>> a);
+}
diff --git a/mcs/errors/gcs8035-7.cs b/mcs/errors/gcs8035-7.cs
new file mode 100644 (file)
index 0000000..21ad965
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate A<T> B<out T> ();
diff --git a/mcs/errors/gcs8035-8.cs b/mcs/errors/gcs8035-8.cs
new file mode 100644 (file)
index 0000000..daa6527
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate A<A<T>> B<out T> ();
diff --git a/mcs/errors/gcs8035-9.cs b/mcs/errors/gcs8035-9.cs
new file mode 100644 (file)
index 0000000..d8475b5
--- /dev/null
@@ -0,0 +1,9 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+delegate void B<out T> (A<T> a);
diff --git a/mcs/errors/gcs8035.cs b/mcs/errors/gcs8035.cs
new file mode 100644 (file)
index 0000000..7f7b3fb
--- /dev/null
@@ -0,0 +1,12 @@
+// CS8035: Covariant type parameters can only be used as return types or in interface inheritance\r
+// Line: 11\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<out T>
+{
+       A<T> A { get; }
+}
diff --git a/mcs/errors/gcs8036-2.cs b/mcs/errors/gcs8036-2.cs
new file mode 100644 (file)
index 0000000..cf34ecd
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8036: Generic variance can only be used with interfaces and delegates\r
+// Line: 5\r
+// Compiler options: -langversion:future
+
+class A<in T>
+{
+}
diff --git a/mcs/errors/gcs8036.cs b/mcs/errors/gcs8036.cs
new file mode 100644 (file)
index 0000000..fc557d4
--- /dev/null
@@ -0,0 +1,7 @@
+// CS8036: Generic variance can only be used with interfaces and delegates\r
+// Line: 5\r
+// Compiler options: -langversion:future
+
+class A<out T>
+{
+}
diff --git a/mcs/errors/gcs8037-2.cs b/mcs/errors/gcs8037-2.cs
new file mode 100644 (file)
index 0000000..97e3e79
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8037: Contravariant type parameters cannot be used in output positions\r
+// Line: 7\r
+// Compiler options: -langversion:future
+
+interface A<in T>
+{
+       void B(ref T t);
+}
diff --git a/mcs/errors/gcs8037.cs b/mcs/errors/gcs8037.cs
new file mode 100644 (file)
index 0000000..3284ad2
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8037: Contravariant type parameters cannot be used in output positions\r
+// Line: 7\r
+// Compiler options: -langversion:future
+
+interface A<in T>
+{
+       void B(out T t);
+}
diff --git a/mcs/errors/gcs8038-2.cs b/mcs/errors/gcs8038-2.cs
new file mode 100644 (file)
index 0000000..22a5f63
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8038: Covariant type parameters cannot be used as method parameters\r
+// Line: 7\r
+// Compiler options: -langversion:future
+
+interface A<out T>
+{
+       void B(out T t);
+}
diff --git a/mcs/errors/gcs8038-3.cs b/mcs/errors/gcs8038-3.cs
new file mode 100644 (file)
index 0000000..596fad1
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8038: Covariant type parameters cannot be used as method parameters\r
+// Line: 7\r
+// Compiler options: -langversion:future
+
+interface A<out T>
+{
+       void B(ref T t);
+}
diff --git a/mcs/errors/gcs8038.cs b/mcs/errors/gcs8038.cs
new file mode 100644 (file)
index 0000000..511595d
--- /dev/null
@@ -0,0 +1,8 @@
+// CS8038: Covariant type parameters cannot be used as method parameters\r
+// Line: 7\r
+// Compiler options: -langversion:future
+
+interface A<out T>
+{
+       void B(T t);
+}
diff --git a/mcs/errors/gcs8039.cs b/mcs/errors/gcs8039.cs
new file mode 100644 (file)
index 0000000..11aedc8
--- /dev/null
@@ -0,0 +1,11 @@
+// CS8039: Contravariant type parameters cannot be used as arguments in interface inheritance\r
+// Line: 9\r
+// Compiler options: -langversion:future
+
+interface A<T>
+{
+}
+
+interface B<in T> : A<T>
+{
+}
index 6f2b8cfc6f02b331ba21acc18ba0700fe61619c1..4a94433715faf229241718796c2e04c4857e0f85 100644 (file)
@@ -1,3 +1,57 @@
+2009-02-04  Scott Peterson  <lunchtimemama@gmail.com>
+
+       This patch adds initial generic variance support to the compiler.
+       It is contributed under the MIT/X11 license.
+
+       * typemanager.cs: Modified ImplementsInterface to check variance.
+       Added VerifyVariantTypeParameters which checks the specified type to see
+       if it uses a variant type parameter as a type argument (which is not
+       allowed). Added IsVariantOf which determins if the first type is a
+       variant of the second. NOTE: This only supports reference types at
+       the moment to conform with the current level of VM support. When the
+       VM supports value types, this will follow step.
+
+       * generic.cs: Added the Variance enum. Added a Variance property to
+       TypeParameter and added variance support to definition phase. Added a
+       Variance property to TypeParameterName. Also check to make sure that
+       no variant types appear in generic method parameters.
+
+       * cs-tokenizer.cs: Modified parse_less_than to tokenize the variance
+       keywords if the langversion supports it.
+
+       * parameter.cs: Added Parameter.VerifyNoVariantTypeParameters to ensure
+       that variant types are only used in legal positions. Also added
+       ParametersCompiled.VerifyNoVariantTypeParameters to check all of its
+       parameters.
+
+       * decl.cs: Construct TypeParameter with the variance information.
+
+       * convert.cs: Checks variance in ImplicitReferenceConversionExists
+       and ImplicitConversionStandard.
+
+       * rootcontext.cs: Added new "Future" language version.
+
+       * class.cs: In TypeContainer.DoDefineMembers, ensure that contravariant
+       type parameters are not used as type arguments in interface inheritance.
+       In MemberBase.DoMemberDependentChecks, ensure that contravariant type
+       parameters are not used as method return types. In MemberBase.
+       ResolveMemberType, ensure that variant type parameters are not used
+       as type arguments. Also call VerifyNoVariantTypeParameters on every
+       set of parameters which are resolved.
+
+       * delegate.cs: Modified Delegate.Define to ensure that variant
+       parameters are not used as type arguments and that a contravariant
+       parameter is not used as the return type. Also call
+       VerifyNoVariantTypeParameters on the delegate parameters.
+
+       * cs-parser.jay: Modified grammar to support "in" and "out" keywords
+       to specify generic variance.
+
+       * driver.cs: Added support for LanguageVersion.Future in the form of
+       "-langversion:future".
+
+       * generic-mcs.cs: Stubbed out new members in generic.cs.
+
 2009-02-03  Marek Safar  <marek.safar@gmail.com>
 
        * class.cs, generic.cs: Emit type parameter constraints for nested
index 49f8df63cfc62e80b38f300e81b6b7905945ee8f..18405aecd4b70d7fcfb4d9ea6ff3e9835b0bf573 100644 (file)
@@ -1291,8 +1291,18 @@ namespace Mono.CSharp {
                                                        oa, iface.GetSignatureForError (), Location);
 
                                        GenericTypeExpr ct = iface as GenericTypeExpr;
-                                       if ((ct != null) && !ct.CheckConstraints (this))
-                                               return false;
+                                       if (ct != null) {
+                                               if (!ct.CheckConstraints (this))
+                                                       return false;
+#if GMCS_SOURCE
+                                               foreach (Type t in ct.TypeArguments.Arguments) {
+                                                       if (t.IsGenericParameter && (t.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) {
+                                                               Report.Error (-39, ct.Location, "Contravariant type parameters cannot be used " +
+                                                                             "as arguments in interface inheritance");
+                                                       }
+                                               }
+#endif
+                                       }
                                }
                        }
 
@@ -5304,6 +5314,11 @@ namespace Mono.CSharp {
                                                      "accessible than field `" + GetSignatureForError () + "'");
                                }
                        }
+#if GMCS_SOURCE
+                       if (MemberType.IsGenericParameter && (MemberType.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) {
+                               Report.Error (-33, Location, "Contravariant type parameters can only be used in input positions");
+                       }
+#endif
                }
 
                protected bool IsTypePermitted ()
@@ -5336,6 +5351,10 @@ namespace Mono.CSharp {
                        if (te == null)
                                return false;
 
+                       if (!TypeManager.VerifyNoVariantTypeParameters (te.Type, te.Location)) {
+                               return false;
+                       }
+                       
                        //
                        // Replace original type name, error reporting can use fully resolved name
                        //
@@ -5965,7 +5984,7 @@ namespace Mono.CSharp {
                protected ToplevelBlock block;
                protected ListDictionary declarative_security;
 
-               // The accessor are created event if they are not wanted.
+               // The accessor are created even if they are not wanted.
                // But we need them because their names are reserved.
                // Field says whether accessor will be emited or not
                public readonly bool IsDummy;
@@ -6273,6 +6292,7 @@ namespace Mono.CSharp {
                        public override MethodBuilder Define (DeclSpace parent)
                        {
                                parameters.Resolve (ResolveContext);
+                               
                                base.Define (parent);
 
                                if (IsDummy)
index 020970c0516eff5f0228f28dbdd61a1c6758dfe2..608e25a206847cbf44b243a3869b76ac3f3ceb53 100644 (file)
@@ -369,10 +369,12 @@ namespace Mono.CSharp {
                                (expr_type == TypeManager.delegate_type || TypeManager.IsDelegateType (expr_type)))
                                return true;
 
-                       // from a generic type definition to a generic instance.
                        if (TypeManager.IsEqual (expr_type, target_type))
                                return true;
 
+                       if (TypeManager.IsVariantOf (expr_type, target_type))
+                           return true;
+
                        return false;
                }
 
@@ -1214,6 +1216,10 @@ namespace Mono.CSharp {
                                return null;
                        }
 
+                       if (TypeManager.IsVariantOf (expr_type, target_type)) {
+                               return expr;
+                       }
+
                        if (TypeManager.IsNullableType (target_type))
                                return ImplicitNulableConversion (ec, expr, target_type);
 
index bcd77aba95d2ec8eb2fc8601fd09b98b902c064c..5d85ce26ec7e449750750775db59457903a8807b 100644 (file)
@@ -2755,10 +2755,10 @@ type_parameters
        ;
 
 type_parameter
-       : opt_attributes IDENTIFIER
+       : opt_attributes opt_type_parameter_variance IDENTIFIER
          {
-               LocatedToken lt = (LocatedToken)$2;
-               $$ = new TypeParameterName (lt.Value, (Attributes)$1, lt.Location);
+               LocatedToken lt = (LocatedToken)$3;
+               $$ = new TypeParameterName (lt.Value, (Attributes)$1, (Variance)$2, lt.Location);
          }
        | error
          {
@@ -4188,6 +4188,30 @@ type_parameter_constraint
          }
        ;
 
+opt_type_parameter_variance
+       : /* empty */
+         {
+               $$ = Variance.None;
+         }
+       | type_parameter_variance
+         {
+               if (RootContext.Version < LanguageVersion.Future)
+                       Report.FeatureIsNotAvailable (lexer.Location, "generic variance");
+               $$ = $1;
+         }
+       ;
+
+type_parameter_variance
+       : OUT
+         {
+               $$ = Variance.Covariant;
+         }
+       | IN
+         {
+               $$ = Variance.Contravariant;
+         }
+       ;
+
 //
 // Statements (8.2)
 //
index addf9aa98c78fe893ad595b5dc5d1aed0a44479e..289741a3eabfb09b0c493f0d3c7b8cabd9f48104 100644 (file)
@@ -787,6 +787,8 @@ namespace Mono.CSharp
                                        the_token = token ();
                                } while (the_token != Token.CLOSE_BRACKET);
                                the_token = token ();
+                       } else if (the_token == Token.IN || the_token == Token.OUT) {
+                               the_token = token ();
                        }
                        switch (the_token) {
                        case Token.IDENTIFIER:
@@ -807,7 +809,6 @@ namespace Mono.CSharp
                        case Token.CHAR:
                        case Token.VOID:
                                break;
-
                        case Token.OP_GENERICS_GT:
                                return true;
 
index 399a59dd39b4375e9eb34ec1063dbce95fed0cf1..8d67c324cd37b3f2ae763861e4d41480d315c749 100644 (file)
@@ -1336,7 +1336,7 @@ namespace Mono.CSharp {
                                }
 
                                type_params [i] = new TypeParameter (
-                                       Parent, this, name.Name, constraints, name.OptAttributes,
+                                       Parent, this, name.Name, constraints, name.OptAttributes, name.Variance,
                                        Location);
 
                                AddToContainer (type_params [i], name.Name);
index 51ba1e021655f06cb619d79ffd7e8975cd8c01b7..941ab9b890aba90f35734c7e00c4be4e662fa586 100644 (file)
@@ -230,6 +230,17 @@ namespace Mono.CSharp {
                                return false;
                        }
 
+                       if (!TypeManager.VerifyNoVariantTypeParameters (ret_type, ReturnType.Location)) {
+                               return false;
+                       }
+
+#if GMCS_SOURCE
+                       if (ret_type.IsGenericParameter && (ret_type.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) {
+                               Report.Error (-33, Location, "Contravariant type parameters can only be used in input positions");
+                               return false;
+                       }
+#endif
+
                        //
                        // We don't have to check any others because they are all
                        // guaranteed to be accessible - they are standard types.
index d0e47c78393aba383d46ba91c804fb2d14327caa..aa503f6d6c65b0f516b8b67f6eff632e5c399b82 100644 (file)
@@ -239,7 +239,7 @@ namespace Mono.CSharp
                                "   -help                Lists all compiler options (short: -?)\n" + 
                                "   -keycontainer:NAME   The key pair container used to sign the output assembly\n" +
                                "   -keyfile:FILE        The key file used to strongname the ouput assembly\n" +
-                               "   -langversion:TEXT    Specifies language version modes: ISO-1, ISO-2, or Default\n" + 
+                               "   -langversion:TEXT    Specifies language version: ISO-1, ISO-2, Default, or future\n" + 
                                "   -lib:PATH1[,PATHn]   Specifies the location of referenced assemblies\n" +
                                "   -main:CLASS          Specifies the class with the Main method (short: -m)\n" +
                                "   -noconfig            Disables implicitly referenced assemblies\n" +
@@ -1497,6 +1497,9 @@ namespace Mono.CSharp
                                case "iso-2":
                                        RootContext.Version = LanguageVersion.ISO_2;
                                        return true;
+                               case "future":
+                                       RootContext.Version = LanguageVersion.Future;
+                                       return true;
 #endif
                                }
                                Report.Error (1617, "Invalid option `{0}' for /langversion. It must be either `ISO-1', `ISO-2' or `Default'", value);
index 70a10b07d80475b072bdc4833e70a6ebc88a9912..fef6843124c060b18dc4291513c938015afab669 100644 (file)
@@ -13,6 +13,13 @@ using System.Collections;
 
 namespace Mono.CSharp
 {
+       public enum Variance
+       {
+               None,
+               Covariant,
+               Contravariant
+       }
+
        public enum SpecialConstraint
        {
                Constructor,
@@ -68,7 +75,7 @@ namespace Mono.CSharp
        public class TypeParameter : MemberCore, IMemberContainer
        {
                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)
                {
                        throw new NotImplementedException ();
@@ -152,6 +159,10 @@ namespace Mono.CSharp
                        get { throw new NotImplementedException (); }
                }
 
+               public Variance Variance {
+                       get { throw new NotImplementedException (); }
+               }
+
                MemberCache IMemberContainer.BaseCache {
                        get { throw new NotImplementedException (); }
                }
@@ -199,11 +210,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 {
@@ -211,6 +229,12 @@ namespace Mono.CSharp
                                return attributes;
                        }
                }
+
+               public Variance Variance {
+                       get {
+                               return variance;
+                       }
+               }
        }
 
        public class GenericTypeExpr : TypeExpr
index 6730d2f1f4cbd0186c3e26c85a6be3b9e41ff8db..9014a1fc4fd55a6931e1716d55bda0be0451c514 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 Variacne {
+                       get { return variance; }
+               }
+
                public Type Type {
                        get { return type; }
                }
@@ -752,15 +768,22 @@ namespace Mono.CSharp {
 
                public void SetConstraints (GenericTypeParameterBuilder type)
                {
-                       if (gc == null)
-                               return;
+                       GenericParameterAttributes attr = GenericParameterAttributes.None;
+                       if (variance == Variance.Contravariant)
+                               attr |= GenericParameterAttributes.Contravariant;
+                       else if (variance == Variance.Covariant)
+                               attr |= GenericParameterAttributes.Covariant;
 
-                       if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
-                               type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
+                       if (gc != null) {
+                               if (gc.HasClassConstraint || gc.HasValueTypeConstraint)
+                                       type.SetBaseTypeConstraint (gc.EffectiveBaseClass);
 
-                       type.SetInterfaceConstraints (gc.InterfaceConstraints);
-                       type.SetGenericParameterAttributes (gc.Attributes);
-                       TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+                               attr |= gc.Attributes;
+                               type.SetInterfaceConstraints (gc.InterfaceConstraints);
+                               TypeManager.RegisterBuilder (type, gc.InterfaceConstraints);
+                       }
+                       
+                       type.SetGenericParameterAttributes (attr);
                }
 
                /// <summary>
@@ -1171,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 {
@@ -1183,6 +1213,12 @@ namespace Mono.CSharp {
                                return attributes;
                        }
                }
+
+               public Variance Variance {
+                       get {
+                               return variance;
+                       }
+               }
        }
 
        /// <summary>
index a0ec4b7dbbb29b7dab6cfa0c4924c8cc2cc2360f..0a9e2b920517a54aa04d3c593b7fa4c50c26daab 100644 (file)
@@ -376,10 +376,24 @@ namespace Mono.CSharp {
                        }
 
 #if GMCS_SOURCE
-                       TypeParameterExpr tparam = texpr as TypeParameterExpr;
-                       if (tparam != null) {
+                       if (parameter_type.IsGenericParameter) {
+                               AbstractPropertyEventMethod accessor = ec as AbstractPropertyEventMethod;
+                               if (accessor == null || !accessor.IsDummy) {
+                                       if ((parameter_type.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0) {
+                                               Report.Error (-38, Location, "Covariant type parameters cannot be used as method parameters");
+                                               return null;
+                                       } else if ((ModFlags & Modifier.ISBYREF) != 0 &&
+                                                  (parameter_type.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) {
+                                               Report.Error (-37, Location, "Contravariant type parameters cannot be used in output positions");
+                                               return null;
+                                       }
+                               }
                                return parameter_type;
                        }
+
+                       if (!TypeManager.VerifyNoVariantTypeParameters (parameter_type, Location)) {
+                               return null;
+                       }
 #endif
 
                        if ((parameter_type.Attributes & Class.StaticClassAttribute) == Class.StaticClassAttribute) {
@@ -1006,7 +1020,7 @@ namespace Mono.CSharp {
                {
                        if (types != null)
                                return true;
-
+                       
                        types = new Type [Count];
                        
                        bool ok = true;
index c67ba26bd8cef96b493befc9fa0e93e8a35d1fd0..f12d05e6c5b6e9d8952572c8bb789081a2a9233c 100644 (file)
@@ -25,6 +25,7 @@ namespace Mono.CSharp {
                Default_MCS     = 2,
                ISO_2           = 3,
                LINQ            = 4,
+               Future          = 5,
 
 #if GMCS_SOURCE
                Default         = LINQ
index d2f3ff2b935fc18e5d07baf11b852f8d9eabb23e..2aa18f193c1116433fa8669568c369dcf6b7b1c4 100644 (file)
@@ -2135,7 +2135,7 @@ namespace Mono.CSharp {
 
                        if (interfaces != null){
                                foreach (Type i in interfaces){
-                                       if (i == iface)
+                                       if (i == iface || IsVariantOf (i, iface))
                                                return true;
                                }
                        }
@@ -2146,6 +2146,64 @@ namespace Mono.CSharp {
                return false;
        }
 
+       public static bool VerifyNoVariantTypeParameters (Type type, Location loc)
+       {
+#if GMCS_SOURCE
+               if (type != null && type.IsGenericType) {
+                       foreach (Type t in type.GetGenericArguments ()) {
+                               if (t.IsGenericParameter) {
+                                       if ((t.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0) {
+                                               Report.Error (-34, loc, "Contravariant type parameters can only be used " +
+                                                             "as input arguments to a method");
+                                               return false;
+                                       }
+                                       if ((t.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0) {
+                                               Report.Error (-35, loc, "Covariant type parameters can only be used as return types " +
+                                                             "or in interface inheritance");
+                                               return false;
+                                       }
+                               } else if (!VerifyNoVariantTypeParameters (t, loc)) {
+                                       return false;
+                               }
+                       }
+               }
+#endif
+               return true;
+       }
+
+       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 (IsValueType (t1[i]) || IsValueType (t2[i])) {
+                                                       return false;
+                                               }
+                                               if ((t.GenericParameterAttributes & GenericParameterAttributes.Covariant) != 0 && !t2[i].IsAssignableFrom (t1[i])) {
+                                                       return false;
+                                               }
+                                               if ((t.GenericParameterAttributes & GenericParameterAttributes.Contravariant) != 0 && !t1[i].IsAssignableFrom (t2[i])) {
+                                                       return false;
+                                               }
+                                       } else if (t1[i] != t2[i]) {
+                                               return false;
+                                       }
+                                       i++;
+                               }
+                               return true;
+                       }
+               }
+#endif
+               return false;
+       }
+
        static NumberFormatInfo nf_provider = CultureInfo.CurrentCulture.NumberFormat;
 
        // This is a custom version of Convert.ChangeType() which works
index a974ef507cc4d88bb7c01667881f679f7c5c28e9..d775a4ff27f629a91b0a7742cc06d7044acd8f22 100644 (file)
@@ -1,3 +1,14 @@
+2009-02-04  Scott Peterson  <lunchtimemama@gmail.com>
+
+       This patch is contributed under the MIT/X11 license.
+
+       * gtest-variance-1.cs: Added test for generic covariance.
+
+       * gtest-variance-2.cs: Added test for generic contravariance.
+
+       * known-issues-gmcs: Added the two above tests to the ignore list
+       since runtime support is not yet in place.
+
 2009-01-22  Jb Evain  <jbevain@novell.com>
 
        * gtest-anontype-05.cs: update according to lastest changes in gmcs
diff --git a/mcs/tests/gtest-variance-1.cs b/mcs/tests/gtest-variance-1.cs
new file mode 100644 (file)
index 0000000..04fac52
--- /dev/null
@@ -0,0 +1,34 @@
+// Compiler options: -langversion:future
+
+interface IFoo<out T>
+{
+       T Bar { get; }
+}
+
+class Foo : IFoo<string>
+{
+       readonly string bar;
+       public Foo (string bar)
+       {
+               this.bar = bar;
+       }
+       public string Bar { get { return bar; } }
+}
+
+public class Test
+{
+       static int Main ()
+       {
+               string bar = "Who is John Galt?";
+               IFoo<string> foo = new Foo(bar);
+               IFoo<object> foo2 = foo;
+               if (!foo2.Bar.Equals (bar))
+                       return 1;
+
+               foo2 = new Foo(bar);
+               if (foo2.Bar != bar)
+                       return 2;
+
+               return 0;
+       }
+}
diff --git a/mcs/tests/gtest-variance-2.cs b/mcs/tests/gtest-variance-2.cs
new file mode 100644 (file)
index 0000000..531a8b8
--- /dev/null
@@ -0,0 +1,33 @@
+// Compiler options: -langversion:future
+
+interface IFoo<in T>
+{
+       string Bar (T t);
+}
+
+class Foo : IFoo<object>
+{
+       public string Bar (object t)
+       {
+               return t.GetType ().FullName;
+       }
+}
+
+public class Test
+{
+       static int Main ()
+       {
+               IFoo<object> foo = new Foo ();
+               IFoo<string> foo2 = foo;
+
+               if (foo2.Bar ("blah") != typeof (string).FullName)
+                       return 1;
+
+               foo2 = new Foo();
+               if (foo2.Bar ("blah") != typeof (string).FullName)
+                       return 2;
+               
+
+               return 0;
+       }
+}
index 23fdac9b87a05605642530b0298e291bc3ce3db4..282d815e2db3c8ee6761b48b4eca4dd7bf63a180 100644 (file)
@@ -12,3 +12,5 @@ gtest-437.cs
 
 gtest-etree-07.cs
 
+gtest-variance-1.cs IGNORE     # Runtime support for variance is not yet in place
+gtest-variance-2.cs IGNORE