Commit db016167 authored by Jürg Billeter's avatar Jürg Billeter Committed by Jürg Billeter

fix memory management in foreach statements

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
parent f2e56f94
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
......
......@@ -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);
}
......
......@@ -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);
}
......
......@@ -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);
......
......@@ -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);
}
......
......@@ -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;
}
......
......@@ -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;
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment