[svn] r6473: nemerle/trunk/ncc: hierarchy/ClassMembers.n
testsuite/negative/co-contravariant-native.n test...
nazgul
svnadmin at nemerle.org
Fri Jul 28 00:14:17 CEST 2006
Log:
Tighten checks of variant generic parameters. Add more tests
Author: nazgul
Date: Fri Jul 28 00:14:13 2006
New Revision: 6473
Modified:
nemerle/trunk/ncc/hierarchy/ClassMembers.n
nemerle/trunk/ncc/testsuite/negative/co-contravariant-native.n
nemerle/trunk/ncc/testsuite/positive/co-contra-variance-native.n
Modified: nemerle/trunk/ncc/hierarchy/ClassMembers.n
==============================================================================
--- nemerle/trunk/ncc/hierarchy/ClassMembers.n (original)
+++ nemerle/trunk/ncc/hierarchy/ClassMembers.n Fri Jul 28 00:14:13 2006
@@ -904,20 +904,56 @@
fun_header.body = fun_body;
- match (fun_header.ret_type)
+
+ // this method check the specification from CLI ECMA-335 II 9.7
+ def check_variance_valid (t, enforced_variance_sign)
{
- | MType.TyVarRef (tr) when tr.IsContravariant =>
- Message.Error ($"cannot use contravariant generic parameter as method's `$name' return type");
- | _ => ()
+ match (t) {
+ | MType.Class (_, []) => true // is always valid
+ | MType.TyVarRef (tr) =>
+ if (enforced_variance_sign > 0)
+ !tr.IsContravariant
+ else if (enforced_variance_sign < 0)
+ !tr.IsCovariant
+ else
+ !tr.IsCovariant && !tr.IsContravariant
+ | MType.Array (t, _) => check_variance_valid (t, 1) // array types behave covariantly
+ | MType.Class (tc, args) =>
+ List.ForAll2 (tc.Typarms, args, fun (parm, arg) {
+ def enforce_sign = if (parm.IsCovariant) 1
+ else if (parm.IsContravariant) -1
+ else 0;
+ check_variance_valid (arg, enforce_sign)
+ })
+
+ | MType.Fun (a,b) => check_variance_valid (a, 0) && check_variance_valid (b, 0)
+ | MType.Tuple (args) => args.ForAll (check_variance_valid (_, 0))
+ | MType.Ref (a) | MType.Out (a) => check_variance_valid (a, 0)
+ | _ => true // others should not appear here, just ignore
+ }
}
+ unless (check_variance_valid (fun_header.ret_type.Fix(), 1))
+ Message.Error ($"return type of method `$name' must behave covariantly");
+
foreach (parm in parms) {
match (parm.ty.Fix()) {
| MType.Void => Message.Error ($ "method `$name' has void argument");
- | MType.TyVarRef (tr) when tr.IsCovariant => Message.Error ($"cannot use covariant generic parameter as method's `$name' parameter `$(parm.name)' type");
- | _ => ()
+ | x =>
+ unless (check_variance_valid (x, -1))
+ Message.Error ($"type of `$name' method's parameter `$(parm.name)' must behave contravariantly");
+ }
}
+
+ foreach (tp in typarms) {
+ when (tp.IsCovariant || tp.IsContravariant)
+ Message.Error ("method's generic paramameter cannot declare variance");
+ foreach (ctr in tp.Constraints)
+ unless (check_variance_valid (ctr, -1))
+ // I'm not sure why this is forbidden, but PEVerify indeed complains :)
+ Message.Error ($"constraints of generic parameters of method `$name' must behave contravariantly");
}
+ /// end of variance checks
ty = MType.ConstructFunctionType (fun_header);
Modified: nemerle/trunk/ncc/testsuite/negative/co-contravariant-native.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/negative/co-contravariant-native.n (original)
+++ nemerle/trunk/ncc/testsuite/negative/co-contravariant-native.n Fri Jul 28 00:14:13 2006
@@ -1,9 +1,13 @@
+interface Moogie [T] { }
interface IBuggy [+P, -M] {
- Get (i : int) : M; // E: cannot use contravariant
- IsEmpty : M { get; }; // E: cannot use contravariant
+ Get (i : int) : M; // E: return type of method `Get' must behave covariantly
+ IsEmpty : Moogie [M] { get; }; // E: return type of method `get_IsEmpty' must behave covariantly
- Set (x : P) : void; // E: cannot use covariant
+ Set (x : P) : void; // E: type of `Set' method's parameter `x' must behave contravariantly
+
+ MeGene ['a] (x : int) : void where 'a : P; // E: constraints of generic parameters of method `MeGene' must behave contravariantly
}
+()
Modified: nemerle/trunk/ncc/testsuite/positive/co-contra-variance-native.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/positive/co-contra-variance-native.n (original)
+++ nemerle/trunk/ncc/testsuite/positive/co-contra-variance-native.n Fri Jul 28 00:14:13 2006
@@ -1,3 +1,79 @@
+interface ICovariantEnumerator [+T]
+{
+ MoveNext () : bool;
+ Current : T { get; }
+}
+
+interface ICovariantEnumerable [+T]
+{
+ GetEnumerator () : ICovariantEnumerator [T];
+}
+
+
+[Record]
+class Enumerator [T] : ICovariantEnumerator [T]
+{
+ enu : System.Collections.Generic.IEnumerator [T];
+
+ public MoveNext () : bool
+ {
+ enu.MoveNext ();
+ }
+
+ public Current : T {
+ get { enu.Current }
+ }
+}
+
+[Record]
+class Enumerable [T] : ICovariantEnumerable [T]
+{
+ enu : System.Collections.Generic.IEnumerable [T];
+
+ public GetEnumerator () : ICovariantEnumerator [T]
+ {
+ Enumerator (enu.GetEnumerator ())
+ }
+}
+
+module EnumerTest {
+ public processObjects (x : ICovariantEnumerator [object]) : void {
+ _ = x.MoveNext ();
+ assert (x.Current == "bb");
+ }
+
+ public processStrings (x : ICovariantEnumerator [string]) : void {
+ _ = x.MoveNext ();
+ assert (x.Current == "aa");
+ }
+
+ public processEObjects (x : ICovariantEnumerable [object]) : void
+ {
+ foreach (a in x)
+ assert (a.ToString () == "aa" || a.ToString () == "bb");
+ }
+
+ public processEStrings (x : ICovariantEnumerable [object]) : void
+ {
+ foreach (a in x)
+ assert (a == "aa" || a == "bb");
+ }
+
+ public Run () : void
+ {
+ def x = System.Collections.Generic.List ();
+ x.Add ("aa");
+ x.Add ("bb");
+ def y = Enumerator (x.GetEnumerator ());
+ processStrings (y);
+ processObjects (y);
+
+ def z = Enumerable (x);
+ processEStrings (z);
+ processEObjects (z);
+ }
+}
+
public delegate DFun [-I, +O] (x : I) : O;
@@ -11,6 +87,9 @@
Apply (x : I) : O;
}
+public interface IGenee [-I, +O] {
+ Bar ['a] (x : I) : O where 'a : I;
+}
public class ImmutableList [T] : IList[T]
{
@@ -81,4 +160,11 @@
Tester.DeObjectObject (z);
Tester.DeStringString (z);
Tester.DeStringObject (z);
+
+EnumerTest.Run ();
#endif
\ No newline at end of file
+
+/*
+BEGIN-OUTPUT
+END-OUTPUT
+*/
\ No newline at end of file
More information about the svn
mailing list