]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
Fix nested closures
authorJürg Billeter <j@bitron.ch>
Fri, 18 Sep 2009 13:17:35 +0000 (15:17 +0200)
committerJürg Billeter <j@bitron.ch>
Fri, 18 Sep 2009 13:17:35 +0000 (15:17 +0200)
Fixes bug 595538.

codegen/valaccodebasemodule.vala
codegen/valaccodedelegatemodule.vala
codegen/valaccodemethodmodule.vala
vala/valamemberaccess.vala

index 1b686c468eb686910ab694b9d1fd6fb9e850d702..d3caef857a1fd11557a41bd1cfd4781ad7bc8f1f 100644 (file)
@@ -91,6 +91,29 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                }
        }
 
+       public Block? current_closure_block {
+               get {
+                       return next_closure_block (current_symbol);
+               }
+       }
+
+       public unowned Block? next_closure_block (Symbol sym) {
+               unowned Block block = null;
+               while (true) {
+                       block = sym as Block;
+                       if (!(sym is Block || sym is Method)) {
+                               // no closure block
+                               break;
+                       }
+                       if (block != null && block.captured) {
+                               // closure block found
+                               break;
+                       }
+                       sym = sym.parent_symbol;
+               }
+               return block;
+       }
+
        public CCodeDeclarationSpace header_declarations;
        public CCodeDeclarationSpace internal_header_declarations;
        public CCodeDeclarationSpace source_declarations;
@@ -1610,10 +1633,7 @@ internal class Vala.CCodeBaseModule : CCodeModule {
                var cblock = new CCodeBlock ();
 
                if (b.captured) {
-                       var parent_block = b.parent_symbol as Block;
-                       while (parent_block != null && !parent_block.captured) {
-                               parent_block = parent_block.parent_symbol as Block;
-                       }
+                       var parent_block = next_closure_block (b.parent_symbol);
 
                        int block_id = get_block_id (b);
                        string struct_name = "Block%dData".printf (block_id);
index 85d9ea9ee8ac16ab8deefdabeeecd659f898066d..8611b0a843d345e3253be8200da6185125d3834a 100644 (file)
@@ -143,10 +143,7 @@ internal class Vala.CCodeDelegateModule : CCodeArrayModule {
                        }
                        return invocation_expr.delegate_target;
                } else if (delegate_expr is LambdaExpression) {
-                       var closure_block = current_symbol as Block;
-                       while (closure_block != null && !closure_block.captured) {
-                               closure_block = closure_block.parent_symbol as Block;
-                       }
+                       var closure_block = current_closure_block;
                        if (closure_block != null) {
                                int block_id = get_block_id (closure_block);
                                var delegate_target = get_variable_cexpression ("_data%d_".printf (block_id));
index 363c6c43544e4da20d53cb1fee4121da69ab103b..bb28ecfb92824ad9287a3ab6d672a7d6d764ea56 100644 (file)
@@ -416,16 +416,10 @@ internal class Vala.CCodeMethodModule : CCodeStructModule {
                                if (m.closure) {
                                        // add variables for parent closure blocks
                                        // as closures only have one parameter for the innermost closure block
-                                       var closure_block = m.parent_symbol as Block;
-                                       while (closure_block != null && !closure_block.captured) {
-                                               closure_block = closure_block.parent_symbol as Block;
-                                       }
+                                       var closure_block = current_closure_block;
                                        int block_id = get_block_id (closure_block);
                                        while (true) {
-                                               var parent_closure_block = closure_block.parent_symbol as Block;
-                                               while (parent_closure_block != null && !parent_closure_block.captured) {
-                                                       parent_closure_block = parent_closure_block.parent_symbol as Block;
-                                               }
+                                               var parent_closure_block = next_closure_block (closure_block.parent_symbol);
                                                if (parent_closure_block == null) {
                                                        break;
                                                }
@@ -776,10 +770,7 @@ internal class Vala.CCodeMethodModule : CCodeStructModule {
 
        public override void generate_cparameters (Method m, CCodeDeclarationSpace decl_space, Map<int,CCodeFormalParameter> cparam_map, CCodeFunction func, CCodeFunctionDeclarator? vdeclarator = null, Map<int,CCodeExpression>? carg_map = null, CCodeFunctionCall? vcall = null, int direction = 3) {
                if (m.closure) {
-                       var closure_block = m.parent_symbol as Block;
-                       while (closure_block != null && !closure_block.captured) {
-                               closure_block = closure_block.parent_symbol as Block;
-                       }
+                       var closure_block = current_closure_block;
                        int block_id = get_block_id (closure_block);
                        var instance_param = new CCodeFormalParameter ("_data%d_".printf (block_id), "Block%dData*".printf (block_id));
                        cparam_map.set (get_param_pos (m.cinstance_parameter_position), instance_param);
index 70f3a260c327a28b0de96c00db89eafeec97076e..80e0b0032bdd31d377343c6c0e3e57d48f01472c 100644 (file)
@@ -423,18 +423,40 @@ public class Vala.MemberAccess : Expression {
                        var local = (LocalVariable) member;
                        var block = (Block) local.parent_symbol;
                        if (analyzer.find_parent_method (block) != analyzer.current_method) {
+                               // mark all methods between current method and the captured
+                               // block as closures (to support nested closures)
+                               Symbol sym = analyzer.current_method;
+                               while (sym != block) {
+                                       var method = sym as Method;
+                                       if (method != null) {
+                                               method.closure = true;
+                                               // consider captured variables as used
+                                               // as we require captured variables to be initialized
+                                               method.add_captured_variable (local);
+                                       }
+                                       sym = sym.parent_symbol;
+                               }
+
                                local.captured = true;
                                block.captured = true;
-                               analyzer.current_method.closure = true;
-                               analyzer.current_method.add_captured_variable (local);
                        }
                } else if (member is FormalParameter) {
                        var param = (FormalParameter) member;
                        var m = param.parent_symbol as Method;
                        if (m != null && m != analyzer.current_method && param != m.this_parameter) {
+                               // mark all methods between current method and the captured
+                               // parameter as closures (to support nested closures)
+                               Symbol sym = analyzer.current_method;
+                               while (sym != m) {
+                                       var method = sym as Method;
+                                       if (method != null) {
+                                               method.closure = true;
+                                       }
+                                       sym = sym.parent_symbol;
+                               }
+
                                param.captured = true;
                                m.body.captured = true;
-                               analyzer.current_method.closure = true;
                        }
                } else if (member is Field) {
                        var f = (Field) member;