[vala] Fix nested closures



commit c0aac5d3405fc30133b67546126cabae10ff7ab1
Author: Jürg Billeter <j bitron ch>
Date:   Fri Sep 18 15:17:35 2009 +0200

    Fix nested closures
    
    Fixes bug 595538.

 codegen/valaccodebasemodule.vala     |   28 ++++++++++++++++++++++++----
 codegen/valaccodedelegatemodule.vala |    5 +----
 codegen/valaccodemethodmodule.vala   |   15 +++------------
 vala/valamemberaccess.vala           |   28 +++++++++++++++++++++++++---
 4 files changed, 53 insertions(+), 23 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index 1b686c4..d3caef8 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -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);
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index 85d9ea9..8611b0a 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -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));
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 363c6c4..bb28ecf 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -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);
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index 70f3a26..80e0b00 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -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;



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]