[svn] r6199: nemerle/trunk/ncc: external/LibrariesLoader.n hierarchy/ExtensionMethod.n testsuite/negative/...

malekith svnadmin at nemerle.org
Wed Apr 26 18:09:11 CEST 2006


Log:
Allow extension methods to be defined on generic types.

Author: malekith
Date: Wed Apr 26 18:09:09 2006
New Revision: 6199

Modified:
   nemerle/trunk/ncc/external/LibrariesLoader.n
   nemerle/trunk/ncc/hierarchy/ExtensionMethod.n
   nemerle/trunk/ncc/testsuite/negative/extension-methods.n
   nemerle/trunk/ncc/testsuite/positive/extension-methods-lib.n
   nemerle/trunk/ncc/testsuite/positive/extension-methods.n
   nemerle/trunk/ncc/typing/TypedTree.n
   nemerle/trunk/ncc/typing/Typer2.n

Modified: nemerle/trunk/ncc/external/LibrariesLoader.n
==============================================================================
--- nemerle/trunk/ncc/external/LibrariesLoader.n	(original)
+++ nemerle/trunk/ncc/external/LibrariesLoader.n	Wed Apr 26 18:09:09 2006
@@ -1284,7 +1284,7 @@
             foreach (m is IMethod in GetMembers ())
               when (m.IsStatic && m.GetHandle ().IsDefined (t, false))
                 match (m.GetParameters ().Head.ty.Fix ()) {
-                  | Class (tc, []) =>
+                  | Class (tc, _) =>
                     tc.AddExtensionMethod (m);
                   | _ => Util.ice ()
                 }

Modified: nemerle/trunk/ncc/hierarchy/ExtensionMethod.n
==============================================================================
--- nemerle/trunk/ncc/hierarchy/ExtensionMethod.n	(original)
+++ nemerle/trunk/ncc/hierarchy/ExtensionMethod.n	Wed Apr 26 18:09:09 2006
@@ -26,13 +26,16 @@
  * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  */
 
+using Nemerle.Collections;
 using Nemerle.Compiler;
+using Nemerle.Compiler.SolverMacros;
 using Nemerle.Compiler.Typedtree;
 
 namespace Nemerle.Compiler
 {
   class ExtensionMethod : BuiltinMethod
   {
+    
     internal this (parent : TypeInfo,
                    impl : IMethod)
     {
@@ -41,9 +44,42 @@
       def h = impl.GetHeader ();
       assert (h != null);
       assert (h.parms != null);
-      assert (h.typarms is []);
-      assert (h.tenv == null || h.tenv.IsEmpty);
-      header = Fun_header (h.loc, h.name, h.ret_type, h.parms.Tail, [], h.tenv);
+      when (impl.DeclaringType.TyparmsCount != 0)
+        Message.Error ("cannot define extension methods in generic types");
+      match (h.parms) {
+        | first_parm :: rest_of_parms =>
+          match (first_parm.ty.Fix ()) {
+            | MType.Class (tc, tcparms) =>
+              assert (parent.Equals (tc));
+              if (tcparms.Length > h.typarms.Length ||
+                  List.Exists2 (tcparms, h.typarms.FirstN (tcparms.Length),
+                                fun (x, y) { ! x.Equals (MType.TyVarRef (y)) })) {
+                 Message.Error ("type parameters of first parameter of extension "
+                                "methods should be prefix of type parameters of the "
+                                "method itself");
+                 Message.HintOnce ("for example: public static foo[A,B,C,D] "
+                                   "(this a : Qux[A,B], b : list [C * D]) : int");
+              } else {
+                def our_typarms = h.typarms.ChopFirstN (tcparms.Length);
+                def tosubst = h.typarms.FirstN (tcparms.Length);
+                def forward_sub = Subst ();
+                List.Iter2 (tosubst, parent.Typarms, fun (meth, typ) {
+                  forward_sub.Add (meth, MType.TyVarRef (typ));
+                });
+                def parms = rest_of_parms.Map (fun (tp) {
+                  def tp = tp.Clone ();
+                  tp.ty = forward_sub.Apply (tp.ty.Fix ());
+                  tp
+                });
+                // tenv is not important I guess
+                header = Fun_header (h.loc, h.name, 
+                                     forward_sub.Apply (h.ret_type.Fix ()),
+                                     parms, our_typarms, h.tenv);
+              }
+            | _ => Util.ice ()
+          }
+        | [] => Util.ice ()
+      }
     }
     
     public override Attributes : NemerleAttributes {
@@ -56,6 +92,5 @@
     { 
       get { false } 
     }
-    
   }
 }

Modified: nemerle/trunk/ncc/testsuite/negative/extension-methods.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/negative/extension-methods.n	(original)
+++ nemerle/trunk/ncc/testsuite/negative/extension-methods.n	Wed Apr 26 18:09:09 2006
@@ -15,3 +15,10 @@
   public foo (p : int, this a : A) : void // E: 'this' modifier \(for extension method\) can only be used on the first parameter
     Write ($"foo($(a.v),$p)\n")
 
+class D[X]
+  public static foo (this a : A, p : int) : void // E: cannot define extension methods in generic types
+    ()
+
+class D2
+  public static foo[A,B] (this a : D[B]) : void // E: type parameters.*extension method
+    ()

Modified: nemerle/trunk/ncc/testsuite/positive/extension-methods-lib.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/positive/extension-methods-lib.n	(original)
+++ nemerle/trunk/ncc/testsuite/positive/extension-methods-lib.n	Wed Apr 26 18:09:09 2006
@@ -17,6 +17,13 @@
   public static foo (this a : A, p : int) : void
     Write ($"foo($(a.v),$p)\n")
 
+  public static bar[A,B] (this a : G[A,B]) : void
+    a.Describe ()
+
+  public static bar[A,B,C] (this a : G[A,B], _c : C) : void
+    a.Describe ()
+    System.Console.WriteLine ($"$(typeof(C))")
+
   public static Run () : void
     def a = A (42)
     a.foo ()
@@ -26,3 +33,12 @@
     def c = C(77, "aa")
     c.foo (3)
     B.foo (c, 4)
+
+    def g = G.[int,string]()
+    g.Describe ()
+    g.bar ()
+    g.bar (7.0)
+
+public class G[X, Y]
+  public Describe () : void
+    System.Console.WriteLine ($"$(typeof(X)) $(typeof(Y))")

Modified: nemerle/trunk/ncc/testsuite/positive/extension-methods.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/positive/extension-methods.n	(original)
+++ nemerle/trunk/ncc/testsuite/positive/extension-methods.n	Wed Apr 26 18:09:09 2006
@@ -8,6 +8,11 @@
 a.foo (1)
 B.foo (a, 2)
 
+def g = G.[int,string]()
+g.Describe ()
+g.bar ()
+g.bar (7.0)
+
 /*
 BEGIN-OUTPUT
 foo()
@@ -15,8 +20,16 @@
 foo(42,2)
 foo(77,3)
 foo(77,4)
+System.Int32 System.String
+System.Int32 System.String
+System.Int32 System.String
+System.Double
 foo()
 foo(42,1)
 foo(42,2)
+System.Int32 System.String
+System.Int32 System.String
+System.Int32 System.String
+System.Double
 END-OUTPUT
 */

Modified: nemerle/trunk/ncc/typing/TypedTree.n
==============================================================================
--- nemerle/trunk/ncc/typing/TypedTree.n	(original)
+++ nemerle/trunk/ncc/typing/TypedTree.n	Wed Apr 26 18:09:09 2006
@@ -79,6 +79,11 @@
       this.kind = kind;
     }
 
+    public Clone () : Fun_parm
+    {
+      MemberwiseClone () :> Fun_parm
+    }
+
     public SystemType : System.Type
     {
       get {

Modified: nemerle/trunk/ncc/typing/Typer2.n
==============================================================================
--- nemerle/trunk/ncc/typing/Typer2.n	(original)
+++ nemerle/trunk/ncc/typing/Typer2.n	Wed Apr 26 18:09:09 2006
@@ -978,13 +978,18 @@
                 ivtc.ty = expr.ty;
                 ivtc
 
-              | TExpr.MethodRef (obj, IMethod where (BuiltinKind = ExtensionMethod (impl)), type_parms, _) as func =>
+              | TExpr.MethodRef (obj, IMethod where (BuiltinKind = ExtensionMethod (impl)) as im, type_parms, _) as func =>
                 //Message.Debug ($"expand to $impl");
                 def from = impl.DeclaringType.GetMemType ();
                 def fnt = {
                   def (parms, ret) = func.MType.FunReturnTypeAndParms ().Value;
                   MType.ConstructFunctionType (obj.Type :: parms, ret)
                 }
+                def type_parms =
+                  (match (obj.Type.Fix ().GetInstantiatedSuperType (im.DeclaringType)) {
+                    | MType.Class (_, parms) => parms
+                    | _ => Util.ice ()
+                  }) + type_parms;
                 def fn = TExpr.StaticRef (fnt, from, impl, type_parms);
                 Walk (Context.IsCalledValue,
                       TExpr.Call (expr.Type, fn, Parm (obj) :: parms, false))



More information about the svn mailing list