[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