]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
fix memory management in foreach statements
authorJuerg Billeter <j@bitron.ch>
Fri, 27 Jul 2007 11:38:55 +0000 (11:38 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Fri, 27 Jul 2007 11:38:55 +0000 (11:38 +0000)
2007-07-27  Juerg Billeter  <j@bitron.ch>

* vala/parser.y, vala/valaforeachstatement.vala,
  vala/valamemorymanager.vala, vala/valasemanticanalyzer.vala,
  gobject/valacodegenerator.vala,
  gobject/valacodegeneratorassignment.vala: fix memory management in
  foreach statements

svn path=/trunk/; revision=402

ChangeLog
gobject/valacodegenerator.vala
gobject/valacodegeneratorassignment.vala
vala/parser.y
vala/valaforeachstatement.vala
vala/valamemorymanager.vala
vala/valasemanticanalyzer.vala

index 42c4fa646067603c86d09ea0a618bf57d5a4aaab..4f55df916f12c7a4c5effe1fe70746ea4b54dcb7 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,11 @@
+2007-07-27  Jürg Billeter  <j@bitron.ch>
+
+       * vala/parser.y, vala/valaforeachstatement.vala,
+         vala/valamemorymanager.vala, vala/valasemanticanalyzer.vala,
+         gobject/valacodegenerator.vala,
+         gobject/valacodegeneratorassignment.vala: fix memory management in
+         foreach statements
+
 2007-07-27  Jürg Billeter  <j@bitron.ch>
 
        * gobject/valacodegenerator.vala: use cast for field initializers when
index eb546130ec4faede4ea145d25050f2838093edf4..89c7749dee05d3bc44220eab0f7624de8e3defd2 100644 (file)
@@ -1321,16 +1321,26 @@ public class Vala.CodeGenerator : CodeVisitor {
                create_temp_decl (stmt, stmt.condition.temp_vars);
        }
 
+       public override void visit_begin_foreach_statement (ForeachStatement! stmt) {
+               stmt.variable_declarator.active = true;
+               stmt.collection_variable_declarator.active = true;
+               if (stmt.iterator_variable_declarator != null) {
+                       stmt.iterator_variable_declarator.active = true;
+               }
+       }
+
        public override void visit_end_foreach_statement (ForeachStatement! stmt) {
                var cblock = new CCodeBlock ();
                CCodeForStatement cfor;
-               VariableDeclarator collection_backup = get_temp_variable_declarator (stmt.collection.static_type);
-               
-               stmt.collection.temp_vars.prepend (collection_backup);
+
                var cfrag = new CCodeFragment ();
                append_temp_decl (cfrag, stmt.collection.temp_vars);
                cblock.add_statement (cfrag);
-               cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier (collection_backup.name), (CCodeExpression) stmt.collection.ccodenode)));
+               
+               var collection_backup = stmt.collection_variable_declarator;
+               var ccoldecl = new CCodeDeclaration (collection_backup.type_reference.get_cname ());
+               ccoldecl.add_declarator (new CCodeVariableDeclarator.with_initializer (collection_backup.name, (CCodeExpression) stmt.collection.ccodenode));
+               cblock.add_statement (ccoldecl);
                
                stmt.ccodenode = cblock;
                
@@ -1348,9 +1358,23 @@ public class Vala.CodeGenerator : CodeVisitor {
                                cblock.add_statement (citdecl);
                                
                                var cbody = new CCodeBlock ();
-                               
+
+                               CCodeExpression element_expr = new CCodeIdentifier ("*%s".printf (it_name));
+
+                               if (stmt.type_reference.takes_ownership) {
+                                       var ma = new MemberAccess.simple (stmt.variable_name);
+                                       ma.static_type = stmt.type_reference;
+                                       ma.ccodenode = element_expr;
+                                       element_expr = get_ref_expression (ma);
+
+                                       var cfrag = new CCodeFragment ();
+                                       append_temp_decl (cfrag, temp_vars);
+                                       cbody.add_statement (cfrag);
+                                       temp_vars = null;
+                               }
+
                                var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
-                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeIdentifier ("*%s".printf (it_name))));
+                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
                                cbody.add_statement (cdecl);
                                
                                cbody.add_statement (stmt.body.ccodenode);
@@ -1372,9 +1396,23 @@ public class Vala.CodeGenerator : CodeVisitor {
                                cblock.add_statement (citdecl);
                                
                                var cbody = new CCodeBlock ();
-                               
+
+                               CCodeExpression element_expr = new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name));
+
+                               if (stmt.type_reference.takes_ownership) {
+                                       var ma = new MemberAccess.simple (stmt.variable_name);
+                                       ma.static_type = stmt.type_reference;
+                                       ma.ccodenode = element_expr;
+                                       element_expr = get_ref_expression (ma);
+
+                                       var cfrag = new CCodeFragment ();
+                                       append_temp_decl (cfrag, temp_vars);
+                                       cbody.add_statement (cfrag);
+                                       temp_vars = null;
+                               }
+
                                var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
-                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name))));
+                               cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
                                cbody.add_statement (cdecl);
 
                                cbody.add_statement (stmt.body.ccodenode);
@@ -1419,6 +1457,18 @@ public class Vala.CodeGenerator : CodeVisitor {
 
                        element_expr = convert_from_generic_pointer (element_expr, stmt.type_reference);
 
+                       if (stmt.type_reference.takes_ownership) {
+                               var ma = new MemberAccess.simple (stmt.variable_name);
+                               ma.static_type = stmt.type_reference;
+                               ma.ccodenode = element_expr;
+                               element_expr = get_ref_expression (ma);
+
+                               var cfrag = new CCodeFragment ();
+                               append_temp_decl (cfrag, temp_vars);
+                               cbody.add_statement (cfrag);
+                               temp_vars = null;
+                       }
+
                        var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
                        cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
                        cbody.add_statement (cdecl);
@@ -1453,29 +1503,42 @@ public class Vala.CodeGenerator : CodeVisitor {
 
                        element_expr = convert_from_generic_pointer (element_expr, stmt.type_reference);
 
+                       List<weak TypeReference> type_arg_list = it_method.return_type.get_type_arguments ();
+                       var it_type = SemanticAnalyzer.get_actual_type (stmt.collection.static_type, it_method, (TypeReference) type_arg_list.data, stmt);
+
+                       if (stmt.type_reference.takes_ownership && !it_type.takes_ownership) {
+                               var ma = new MemberAccess.simple (stmt.variable_name);
+                               ma.static_type = stmt.type_reference;
+                               ma.ccodenode = element_expr;
+                               element_expr = get_ref_expression (ma);
+
+                               var cfrag = new CCodeFragment ();
+                               append_temp_decl (cfrag, temp_vars);
+                               cbody.add_statement (cfrag);
+                               temp_vars = null;
+                       }
+
                        var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
                        cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
                        cbody.add_statement (cdecl);
                        
                        cbody.add_statement (stmt.body.ccodenode);
 
-                       cbody.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (stmt.variable_name), stmt.type_reference, null)));
-                       
                        var next_method = (Method) iterator_type.scope.lookup ("next");
                        var next_ccall = new CCodeFunctionCall (new CCodeIdentifier (next_method.get_cname ()));
                        next_ccall.add_argument (new CCodeIdentifier (it_name));
 
                        cblock.add_statement (new CCodeWhileStatement (next_ccall, cbody));
-
-                       var it_unref_ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
-                       it_unref_ccall.add_argument (new CCodeIdentifier (it_name));
-                       cblock.add_statement (new CCodeExpressionStatement (it_unref_ccall));
                }
-               
-               if (memory_management && stmt.collection.static_type.transfers_ownership) {
-                       var ma = new MemberAccess.simple (collection_backup.name);
-                       ma.symbol_reference = collection_backup;
-                       cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (collection_backup.name), stmt.collection.static_type, ma)));
+
+               if (memory_management) {
+                       foreach (VariableDeclarator decl in stmt.get_local_variables ()) {
+                               if (decl.type_reference.takes_ownership) {
+                                       var ma = new MemberAccess.simple (decl.name);
+                                       ma.symbol_reference = decl;
+                                       cblock.add_statement (new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (decl.name)), decl.type_reference, ma)));
+                               }
+                       }
                }
        }
 
@@ -1987,7 +2050,7 @@ public class Vala.CodeGenerator : CodeVisitor {
                        var get_param = (FormalParameter) get_params.data;
 
                        if (get_param.type_reference.type_parameter != null) {
-                               var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, get_method, get_param.type_reference.type_parameter, expr);
+                               var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, get_method, get_param.type_reference, expr);
                                cindex = convert_to_generic_pointer (cindex, index_type);
                        }
 
index 062dd071559c9877c58117e44418dc71ed97bcbe..591e39b4eb1f62655721bd4c11e7ea3ee2337ccc 100644 (file)
@@ -219,7 +219,7 @@ public class Vala.CodeGenerator {
                                var set_param = (FormalParameter) set_params.data;
 
                                if (set_param.type_reference.type_parameter != null) {
-                                       var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, set_method, set_param.type_reference.type_parameter, a);
+                                       var index_type = SemanticAnalyzer.get_actual_type (expr.container.static_type, set_method, set_param.type_reference, a);
                                        cindex = convert_to_generic_pointer (cindex, index_type);
                                }
 
index 8826842fce753a8ffb7a316f420ca23bbca278d9..4e573ec1faddb3a909a47bcee0d3456e96ec22f0 100644 (file)
@@ -1817,6 +1817,9 @@ foreach_statement
        : FOREACH OPEN_PARENS type identifier IN expression CLOSE_PARENS embedded_statement
          {
                ValaSourceReference *src = src(@3);
+               if (!vala_type_reference_get_is_weak ($3)) {
+                       vala_type_reference_set_takes_ownership ($3, TRUE);
+               }
                $$ = VALA_STATEMENT (vala_foreach_statement_new ($3, $4, $6, $8, src));
                g_object_unref ($3);
                g_free ($4);
index 9ec45970a0dbc195353962c9847d314de8d37dab..1fecf9f9b7a0115b05dcd6634397e478d336781f 100644 (file)
@@ -26,7 +26,7 @@ using GLib;
  * Represents a foreach statement in the source code. Foreach statements iterate
  * over the elements of a collection.
  */
-public class Vala.ForeachStatement : CodeNode, Statement {
+public class Vala.ForeachStatement : Block {
        /**
         * Specifies the element type.
         */
@@ -68,6 +68,16 @@ public class Vala.ForeachStatement : CodeNode, Statement {
         */
        public VariableDeclarator variable_declarator { get; set; }
 
+       /**
+        * Specifies the declarator for the generated collection variable.
+        */
+       public VariableDeclarator collection_variable_declarator { get; set; }
+
+       /**
+        * Specifies the declarator for the generated iterator variable.
+        */
+       public VariableDeclarator iterator_variable_declarator { get; set; }
+
        private Expression! _collection;
        private Block _body;
 
@@ -86,6 +96,8 @@ public class Vala.ForeachStatement : CodeNode, Statement {
        public override void accept (CodeVisitor! visitor) {
                visitor.visit_begin_foreach_statement (this);
 
+               visitor.visit_begin_block (this);
+
                type_reference.accept (visitor);
 
                collection.accept (visitor);
@@ -93,6 +105,8 @@ public class Vala.ForeachStatement : CodeNode, Statement {
 
                body.accept (visitor);
 
+               visitor.visit_end_block (this);
+
                visitor.visit_end_foreach_statement (this);
        }
 
index f1fd96e30055ceb40bb58a5582fc43af74253099..43149c86fc4fd606cfbd07e38bac11b56021bc5f 100644 (file)
@@ -186,7 +186,7 @@ public class Vala.MemoryManager : CodeVisitor {
                                        if (is_ref && param.type_reference.type_parameter != null) {
                                                if (expr.call is MemberAccess) {
                                                        var ma = (MemberAccess) expr.call;
-                                                       var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, msym, param.type_reference.type_parameter, expr);
+                                                       var param_type = SemanticAnalyzer.get_actual_type (ma.inner.static_type, msym, param.type_reference, expr);
                                                        if (param_type != null) {
                                                                is_ref = param_type.takes_ownership;
                                                        }
@@ -227,7 +227,7 @@ public class Vala.MemoryManager : CodeVisitor {
                                    || param.type_reference.type_parameter != null)) {
                                        bool is_ref = param.type_reference.takes_ownership;
                                        if (is_ref && param.type_reference.type_parameter != null) {
-                                               var param_type = SemanticAnalyzer.get_actual_type (expr.type_reference, msym, param.type_reference.type_parameter, expr);
+                                               var param_type = SemanticAnalyzer.get_actual_type (expr.type_reference, msym, param.type_reference, expr);
                                                if (param_type != null) {
                                                        is_ref = param_type.takes_ownership;
                                                }
index 2ed03e90eb0b5e237451846f71ac956c97f16be0..0b0ea404fb0ae297c3821f28b4cddecfb1620f3c 100644 (file)
@@ -55,6 +55,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        DataType gslist_type;
        DataType gerror_type;
        DataType iterable_type;
+       DataType iterator_type;
        DataType list_type;
        DataType map_type;
 
@@ -110,6 +111,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                var gee_ns = root_symbol.scope.lookup ("Gee");
                if (gee_ns != null) {
                        iterable_type = (DataType) gee_ns.scope.lookup ("Iterable");
+                       iterator_type = (DataType) gee_ns.scope.lookup ("Iterator");
                        list_type = (DataType) gee_ns.scope.lookup ("List");
                        map_type = (DataType) gee_ns.scope.lookup ("Map");
                }
@@ -861,11 +863,31 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                stmt.variable_declarator.type_reference = stmt.type_reference;
 
                stmt.body.scope.add (stmt.variable_name, stmt.variable_declarator);
+
+               stmt.body.add_local_variable (stmt.variable_declarator);
+               stmt.variable_declarator.active = true;
        }
 
        public override void visit_end_foreach_statement (ForeachStatement! stmt) {
+               stmt.collection_variable_declarator = new VariableDeclarator ("%s_collection".printf (stmt.variable_name));
+               stmt.collection_variable_declarator.type_reference = stmt.collection.static_type.copy ();
+               stmt.collection_variable_declarator.type_reference.transfers_ownership = false;
+               stmt.collection_variable_declarator.type_reference.takes_ownership = stmt.collection.static_type.transfers_ownership;
+
+               stmt.add_local_variable (stmt.collection_variable_declarator);
+               stmt.collection_variable_declarator.active = true;
+
                var collection_type = stmt.collection.static_type.data_type;
-               if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type || collection_type == iterable_type || collection_type.is_subtype_of (iterable_type))) {
+               if (iterable_type != null && (collection_type == iterable_type || collection_type.is_subtype_of (iterable_type))) {
+                       stmt.iterator_variable_declarator = new VariableDeclarator ("%s_it".printf (stmt.variable_name));
+                       stmt.iterator_variable_declarator.type_reference = new TypeReference ();
+                       stmt.iterator_variable_declarator.type_reference.data_type = iterator_type;
+                       stmt.iterator_variable_declarator.type_reference.takes_ownership = true;
+                       stmt.iterator_variable_declarator.type_reference.add_type_argument (stmt.type_reference);
+
+                       stmt.add_local_variable (stmt.iterator_variable_declarator);
+                       stmt.iterator_variable_declarator.active = true;
+               } else if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type)) {
                        stmt.error = true;
                        Report.error (stmt.source_reference, "Collection not iterable");
                        return;
@@ -1438,7 +1460,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                        expr.error = true;
                                        return;
                                } else {
-                                       ret_type = get_actual_type (ma.inner.static_type, msym, ret_type.type_parameter, expr);
+                                       ret_type = get_actual_type (ma.inner.static_type, msym, ret_type, expr);
                                        if (ret_type == null) {
                                                return;
                                        }
@@ -1456,7 +1478,8 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                check_arguments (expr, msym, params, expr.get_argument_list ());
        }
 
-       public static TypeReference get_actual_type (TypeReference instance_type, Symbol generic_member, TypeParameter type_parameter, CodeNode node_reference) {
+       public static TypeReference get_actual_type (TypeReference derived_instance_type, Symbol generic_member, TypeReference generic_type, CodeNode node_reference) {
+               TypeReference instance_type = derived_instance_type;
                // trace type arguments back to the datatype where the method has been declared
                while (instance_type.data_type != generic_member.parent_symbol) {
                        List<weak TypeReference> base_types = null;
@@ -1498,18 +1521,21 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        node_reference.error = true;
                        return null;
                }
-               int param_index = instance_type.data_type.get_type_parameter_index (type_parameter.name);
+               int param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name);
                if (param_index == -1) {
-                       Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_parameter.name));
+                       Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
                        node_reference.error = true;
                        return null;
                }
                var actual_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
                if (actual_type == null) {
-                       Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (type_parameter.name));
+                       Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (generic_type.type_parameter.name));
                        node_reference.error = true;
                        return null;
                }
+               actual_type = actual_type.copy ();
+               actual_type.transfers_ownership = actual_type.takes_ownership && generic_type.transfers_ownership;
+               actual_type.takes_ownership = actual_type.takes_ownership && generic_type.takes_ownership;
                return actual_type;
        }
 
@@ -1567,7 +1593,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
 
                        var index_type = get_param.type_reference;
                        if (index_type.type_parameter != null) {
-                               index_type = get_actual_type (expr.container.static_type, get_method, get_param.type_reference.type_parameter, expr);
+                               index_type = get_actual_type (expr.container.static_type, get_method, get_param.type_reference, expr);
                        }
 
                        if (!is_type_compatible (index.static_type, index_type)) {
@@ -1576,7 +1602,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                                return;
                        }
 
-                       expr.static_type = get_actual_type (expr.container.static_type, get_method, get_method.return_type.type_parameter, expr).copy ();
+                       expr.static_type = get_actual_type (expr.container.static_type, get_method, get_method.return_type, expr).copy ();
                        expr.static_type.takes_ownership = false;
                } else {
                        expr.error = true;