[svn] r5982: nemerle/trunk/ncc: generation/Typer3.n testsuite/positive/closures.n typing/TypedTree.n

malekith svnadmin at nemerle.org
Tue Nov 29 22:00:11 CET 2005


Log:
Include closures used by local functions we call. Resolves #581.

Author: malekith
Date: Tue Nov 29 22:00:10 2005
New Revision: 5982

Modified:
   nemerle/trunk/ncc/generation/Typer3.n
   nemerle/trunk/ncc/testsuite/positive/closures.n
   nemerle/trunk/ncc/typing/TypedTree.n

Modified: nemerle/trunk/ncc/generation/Typer3.n
==============================================================================
--- nemerle/trunk/ncc/generation/Typer3.n	(original)
+++ nemerle/trunk/ncc/generation/Typer3.n	Tue Nov 29 22:00:10 2005
@@ -438,7 +438,7 @@
         PlainRef (decl)
       } else {
         Util.cassert (closure_fields != null);
-        Util.cassert (closure_fields.Contains (hd.id), $ "no clo for $(hd.name)");
+        Util.cassert (closure_fields.Contains (hd.id), $ "no clo for $(hd.name) from $(current_local_fun.name)");
         def field = closure_fields [hd.id];
         // Message.Debug ($"cloref: $(hd.name) from $(current_local_fun.name) $(field.GetMemType()) $field");
         TExpr.FieldMember (field.GetMemType (),
@@ -642,7 +642,8 @@
     #region Function prolog
     PrepareClosureParms () : void
     {
-      when (closure_parms != null) {
+      when (closure_parms != null &&
+            (parent == null || parent.closure_parms : object != closure_parms)) {
         def len = current_local_fun.used_closures.Length;
         List.Iter2 (current_local_fun.parms.FirstN (len),
                     current_local_fun.used_closures, fun (parm, header) {
@@ -826,25 +827,46 @@
 
 
     #region Local function generation
-    static ParentsWithClosures (h : Fun_header) : list [Fun_header]
+    ComputeUsedClosures (h : Fun_header) : void
     {
-      def loop (fh : Fun_header, acc) {
-        match (fh.closure_vars) {
-          | [] => acc
-          | vars => 
-            if (vars.Exists (fun (var) {
+      def we_use (var) {
                 // FIXME: doesn't work, because function have to be removed from external closures
                 //var.id != h.decl.id && // call to our function shouldn't be closurised
                 (h :: h.children_funs).Exists (fun (child) { 
                   var.UsedIn.Contains (child) 
                 })
-              })) 
-              fh :: acc
-            else
-              acc
         }
+      
+      when (h.used_closures == null) {
+        h.used_closures = [];
+
+        def needed = Hashtable ();
+        
+        foreach (fh in h.GetParents ())
+          foreach (var in fh.closure_vars) {
+            when (we_use (var)) {
+              needed [fh.id] = true;
+              match (var.ValKind) {
+                | Function (ch, _) =>
+                  ComputeUsedClosures (ch);
+                  foreach (clo in ch.used_closures)
+                    needed [clo.id] = true;
+                | _ => {}
+              }
+            }
+          }
+
+          h.used_closures = h.GetParents ().Filter (fun (fh) { needed.Contains (fh.id) })
       }
-      List.FoldLeft (h.GetParents (), [], loop);
+    }
+
+
+    static ClosureParmCount (fn : Fun_header) : int
+    {
+      Util.cassert (fn.used_closures != null || fn.decl == null, 
+                    $ "closures not computed for $(fn.name)");
+      if (fn.static_method == null) 0
+      else fn.used_closures.Length
     }
 
 
@@ -853,7 +875,7 @@
       def new_header = meth.fun_header;
       meth.fun_header = fn;
 
-      def clo_count = fn.used_closures.Length;
+      def clo_count = ClosureParmCount (fn);
       def new_parms = new_header.parms.ChopFirstN (clo_count);
 
       foreach (parm in new_header.parms.FirstN (clo_count)) {
@@ -899,10 +921,11 @@
     }
 
 
-    EmitStaticLocalFunction (fn : Fun_header, closures : list [Fun_header], children : Queue [Typer3]) : void
+    EmitStaticLocalFunction (fn : Fun_header, children : Queue [Typer3]) : void
     {
       def (new_tp, subst) = CopyFunTyparms ();
       fn.typarms = fn.typarms + new_tp;
+      def closures = fn.used_closures;
 
       // Message.Debug ($ "emit static $(fn.name) $(fn.typarms) subst=$subst");
 
@@ -948,8 +971,8 @@
       CurrentType.forced_typarms = fn.typarms;
       def meth = CurrentType.DefineAndReturn (decl) :> MethodBuilder;
 
-      PrepareForEmission (meth, fn, subst);
       fn.static_method = meth;
+      PrepareForEmission (meth, fn, subst);
       fn.typarms_to_pass =
         accumulated_typarms.Map (fun (x) { MType.TyVarRef (x) });
 
@@ -961,9 +984,10 @@
     }
 
 
-    EmitFunctionalValue (fn : Fun_header, closures : list [Fun_header], children : Queue [Typer3]) : TExpr
+    EmitFunctionalValue (fn : Fun_header, children : Queue [Typer3]) : TExpr
     {
       Stats.FirstClassFunctions++;
+      def closures = fn.used_closures;
 
       Util.cassert (fn.typarms.IsEmpty, $"should be handled in T2, $(fn.name)");
 
@@ -1060,7 +1084,9 @@
       mutable res = [];
       def q = Queue ();
 
+      
       foreach (fn in fns) {
+        ComputeUsedClosures (fn);
         //Message.Debug ($"hlf: $(fn.name) $(fn.usage) $closures");
         match (fn.usage) {
           | FunctionUsage.UsedJustOnce // handled in EmitLoop
@@ -1068,11 +1094,10 @@
             {}
 
           | FunctionUsage.Used =>
-            fn.used_closures = ParentsWithClosures (fn);
-            EmitStaticLocalFunction (fn, fn.used_closures, q);
+            EmitStaticLocalFunction (fn, q);
 
           | FunctionUsage.UsedAsFirstClass =>
-            def fval = EmitFunctionalValue (fn, ParentsWithClosures (fn), q);
+            def fval = EmitFunctionalValue (fn, q);
             assert (fn.decl != null);
             res ::= TExpr.DefValIn (fn.decl, fval, null);
         }
@@ -1128,14 +1153,13 @@
           | TExpr.DefFunctionsIn ([func], LocalFunRef (decl, typarms))
             when func.decl.Equals (decl) => // this is for sure lambda
 
-            def closures = ParentsWithClosures (func);
-            match (closures) {
+            ComputeUsedClosures (func);
+            match (func.used_closures) {
               | [] when func.parms.Length == 
                         Option.UnSome (parm.MType.FunReturnTypeAndParms ()) [0].Length =>
                 // Message.Debug ($"empty, parms count = $(func.parms.Length)");
                 def q = Queue ();
-                func.used_closures = closures;
-                EmitStaticLocalFunction (func, closures, q);
+                EmitStaticLocalFunction (func, q);
                 
                 while (!q.IsEmpty)
                   q.Take ().Run ();
@@ -1394,7 +1418,7 @@
           EmitCall (expr.Type, func, parms, is_tail)
 
         | TExpr.SelfTailCall (parms) =>
-          def clo_len = current_local_fun.used_closures.Length;
+          def clo_len = ClosureParmCount (current_local_fun);
           def (parms, ini) = TupleParms (current_local_fun, parms, clo_len);
           def assigns =
             List.Map2 (parms, current_local_fun.parms.ChopFirstN (clo_len), 

Modified: nemerle/trunk/ncc/testsuite/positive/closures.n
==============================================================================
--- nemerle/trunk/ncc/testsuite/positive/closures.n	(original)
+++ nemerle/trunk/ncc/testsuite/positive/closures.n	Tue Nov 29 22:00:10 2005
@@ -33,6 +33,21 @@
 
 System.Console.WriteLine (None ().WithDefault (foo ()))
   }
+
+  public static Bug581 () : void
+  {
+    def inf = 0;
+
+    def intersect () {
+      def ray_sphere () { inf }
+      def aux () { ray_sphere () + ray_sphere () }
+      //_ = aux;
+      aux ();
+      aux ()
+    }
+
+    _ = intersect ()
+  }
 }
 
 /*

Modified: nemerle/trunk/ncc/typing/TypedTree.n
==============================================================================
--- nemerle/trunk/ncc/typing/TypedTree.n	(original)
+++ nemerle/trunk/ncc/typing/TypedTree.n	Tue Nov 29 22:00:10 2005
@@ -223,7 +223,7 @@
     internal mutable uses_try_block : bool;
 
     // FIXME: move to hashtables in t3
-    internal mutable used_closures : list [Fun_header] = [];
+    internal mutable used_closures : list [Fun_header];
     internal mutable static_method : IMethod;
     internal mutable typarms_to_pass : list [MType]; 
     internal mutable closure_type : MType.Class;



More information about the svn mailing list