+2007-07-25 Jürg Billeter <j@bitron.ch>
+
+ * vala/valainvokable.vala, vala/valamemorymanager.vala,
+ vala/valasymbolresolver.vala, gobject/valacodegenerator.vala,
+ gobject/valacodegeneratorassignment.vala,
+ gobject/valacodegeneratorclass.vala,
+ gobject/valacodegeneratormethod.vala: add dup_func parameter to
+ generic classes, fix some memory management issues with generic types
+
2007-07-25 Jürg Billeter <j@bitron.ch>
* gobject/valacodegenerator.vala, gobject/valacodegeneratorclass.vala,
return decl;
}
+ private CCodeExpression get_dup_func_expression (TypeReference! type) {
+ if (type.data_type != null) {
+ string dup_function;
+ if (type.data_type.is_reference_counting ()) {
+ dup_function = type.data_type.get_ref_function ();
+ } else {
+ if (type.data_type != string_type.data_type) {
+ // duplicating non-reference counted structs may cause side-effects (and performance issues)
+ Report.warning (type.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (type.data_type.name));
+ }
+ dup_function = type.data_type.get_dup_function ();
+ }
+ return new CCodeIdentifier (dup_function);
+ } else if (type.type_parameter != null && current_type_symbol is Class) {
+ string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
+ return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ } else {
+ return new CCodeConstant ("NULL");
+ }
+ }
+
private CCodeExpression get_destroy_func_expression (TypeReference! type) {
if (type.data_type != null) {
string unref_function;
* if static type of expr is non-null
*/
- if (expr.static_type.data_type == null &&
- expr.static_type.type_parameter != null) {
- Report.warning (expr.source_reference, "Missing generics support for memory management");
- return (CCodeExpression) expr.ccodenode;
- }
-
- string ref_function;
- if (expr.static_type.data_type.is_reference_counting ()) {
- ref_function = expr.static_type.data_type.get_ref_function ();
- } else {
- if (expr.static_type.data_type != string_type.data_type) {
- // duplicating non-reference counted structs may cause side-effects (and performance issues)
- Report.warning (expr.source_reference, "duplicating %s instance, use weak variable or explicitly invoke copy method".printf (expr.static_type.data_type.name));
- }
- ref_function = expr.static_type.data_type.get_dup_function ();
- }
-
- var ccall = new CCodeFunctionCall (new CCodeIdentifier (ref_function));
+ var ccall = new CCodeFunctionCall (get_dup_func_expression (expr.static_type));
- if (expr.static_type.non_null) {
+ if (expr.static_type.non_null && expr.static_type.type_parameter == null) {
ccall.add_argument ((CCodeExpression) expr.ccodenode);
return ccall;
var ctemp = new CCodeIdentifier (decl.name);
var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, new CCodeConstant ("NULL"));
+ if (expr.static_type.data_type == null) {
+ if (!(current_type_symbol is Class)) {
+ return (CCodeExpression) expr.ccodenode;
+ }
+
+ // dup functions are optional for type parameters
+ var cdupisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, get_dup_func_expression (expr.static_type), new CCodeConstant ("NULL"));
+ cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cisnull, cdupisnull);
+ }
ccall.add_argument (ctemp);
var ccomma = new CCodeCommaExpression ();
ccomma.append_expression (new CCodeAssignment (ctemp, (CCodeExpression) expr.ccodenode));
- if (ref_function == "g_list_copy") {
+ if (expr.static_type.data_type == list_type) {
bool is_ref = false;
bool is_class = false;
bool is_interface = false;
}
}
- ccomma.append_expression (new CCodeConditionalExpression (cisnull, new CCodeConstant ("NULL"), ccall));
+ CCodeExpression cifnull;
+ if (expr.static_type.data_type != null) {
+ cifnull = new CCodeConstant ("NULL");
+ } else {
+ // the value might be non-null even when the dup function is null,
+ // so we may not just use NULL for type parameters
+ cifnull = ctemp;
+ }
+ ccomma.append_expression (new CCodeConditionalExpression (cisnull, cifnull, ccall));
return ccomma;
}
if (expr.type_reference.data_type is Class) {
foreach (TypeReference type_arg in expr.type_reference.get_type_arguments ()) {
if (type_arg.takes_ownership) {
+ ccall.add_argument (get_dup_func_expression (type_arg));
ccall.add_argument (get_destroy_func_expression (type_arg));
} else {
ccall.add_argument (new CCodeConstant ("NULL"));
+ ccall.add_argument (new CCodeConstant ("NULL"));
}
}
}
int i = 1;
weak List<weak FormalParameter> params_it = params;
foreach (Expression arg in expr.get_argument_list ()) {
- /* explicitly use strong reference as ccall gets
- * unrefed at end of inner block
- */
CCodeExpression cexpr = (CCodeExpression) arg.ccodenode;
if (params_it != null) {
var param = (FormalParameter) params_it.data;
a.ccodenode = ccall;
} else {
- /* explicitly use strong reference as ccast gets
- * unrefed at end of inner block
- */
CCodeExpression rhs = (CCodeExpression) a.right.ccodenode;
if (a.left.static_type.data_type != null
init_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeMemberAccess.pointer (ccast, m.name), new CCodeIdentifier (m.get_real_cname ()))));
}
- /* create destroy_func properties for generic types */
+ /* create dup_func and destroy_func properties for generic types */
foreach (TypeParameter type_param in cl.get_type_parameters ()) {
- string func_name = "%s_destroy_func".printf (type_param.name.down ());
- var func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
- string enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
- var cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
+ string func_name, enum_value;
+ CCodeConstant func_name_constant;
+ CCodeFunctionCall cinst, cspec;
+
+ func_name = "%s_dup_func".printf (type_param.name.down ());
+ func_name_constant = new CCodeConstant ("\"%s-dup-func\"".printf (type_param.name.down ()));
+ enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
+ cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
+ cinst.add_argument (ccall);
+ cinst.add_argument (new CCodeConstant (enum_value));
+ cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
+ cspec.add_argument (func_name_constant);
+ cspec.add_argument (new CCodeConstant ("\"dup func\""));
+ cspec.add_argument (new CCodeConstant ("\"dup func\""));
+ cspec.add_argument (new CCodeConstant ("G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | G_PARAM_WRITABLE"));
+ cinst.add_argument (cspec);
+ init_block.add_statement (new CCodeExpressionStatement (cinst));
+ prop_enum.add_value (enum_value, null);
+
+ instance_priv_struct.add_field ("GBoxedCopyFunc", func_name);
+
+
+ func_name = "%s_destroy_func".printf (type_param.name.down ());
+ func_name_constant = new CCodeConstant ("\"%s-destroy-func\"".printf (type_param.name.down ()));
+ enum_value = "%s_%s".printf (cl.get_lower_case_cname (null), func_name).up ();
+ cinst = new CCodeFunctionCall (new CCodeIdentifier ("g_object_class_install_property"));
cinst.add_argument (ccall);
cinst.add_argument (new CCodeConstant (enum_value));
- var cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
+ cspec = new CCodeFunctionCall (new CCodeIdentifier ("g_param_spec_pointer"));
cspec.add_argument (func_name_constant);
cspec.add_argument (new CCodeConstant ("\"destroy func\""));
cspec.add_argument (new CCodeConstant ("\"destroy func\""));
if (m is CreationMethod && current_type_symbol is Class) {
// memory management for generic types
foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
- var cparam = new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify");
- function.add_parameter (cparam);
+ function.add_parameter (new CCodeFormalParameter ("%s_dup_func".printf (type_param.name.down ()), "GBoxedCopyFunc"));
+ function.add_parameter (new CCodeFormalParameter ("%s_destroy_func".printf (type_param.name.down ()), "GDestroyNotify"));
}
}
cinit.append (cdecl);
}
- /* destroy func properties for generic types */
+ /* dup and destroy func properties for generic types */
foreach (TypeParameter type_param in current_class.get_type_parameters ()) {
- string func_name = "%s_destroy_func".printf (type_param.name.down ());
- var cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
- var cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
+ string func_name;
+ CCodeMemberAccess cmember;
+ CCodeAssignment cassign;
+
+ func_name = "%s_dup_func".printf (type_param.name.down ());
+ cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
+ function.block.add_statement (new CCodeExpressionStatement (cassign));
+
+ func_name = "%s_destroy_func".printf (type_param.name.down ());
+ cmember = new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+ cassign = new CCodeAssignment (cmember, new CCodeIdentifier (func_name));
function.block.add_statement (new CCodeExpressionStatement (cassign));
}
} else {
/**
* Represents a possibly invokable code object.
*/
-public interface Vala.Invokable /* : CodeNode */ {
+public interface Vala.Invokable : Symbol {
/**
* Returns whether this code object is invokable.
*
}
public override void visit_end_invocation_expression (InvocationExpression! expr) {
- List<weak FormalParameter> params;
-
- var msym = expr.call.symbol_reference;
- if (msym is VariableDeclarator) {
- var decl = (VariableDeclarator) msym;
- var cb = (Callback) decl.type_reference.data_type;
- params = cb.get_parameters ();
- } else if (msym is FormalParameter) {
- var param = (FormalParameter) msym;
- var cb = (Callback) param.type_reference.data_type;
- params = cb.get_parameters ();
- } else if (msym is Field) {
- var f = (Field) msym;
- var cb = (Callback) f.type_reference.data_type;
- params = cb.get_parameters ();
- } else if (msym is Method) {
- var m = (Method) msym;
- params = m.get_parameters ();
- } else if (msym is Signal) {
- var sig = (Signal) msym;
- params = sig.get_parameters ();
- }
+ var msym = (Invokable) expr.call.symbol_reference;
+ List<weak FormalParameter> params = msym.get_parameters ();
+
weak List<weak FormalParameter> params_it = params;
foreach (Expression arg in expr.get_argument_list ()) {
if (params_it != null) {
|| param.type_reference.type_parameter != null)) {
bool is_ref = param.type_reference.takes_ownership;
if (is_ref && param.type_reference.type_parameter != null) {
- // TODO move this to semantic analyzer
if (expr.call is MemberAccess) {
var ma = (MemberAccess) expr.call;
- TypeReference instance_type = ma.inner.static_type;
- // trace type arguments back to the datatype where the method has been declared
- while (instance_type.data_type != msym.parent_symbol) {
- List<weak TypeReference> base_types = null;
- if (instance_type.data_type is Class) {
- var cl = (Class) instance_type.data_type;
- base_types = cl.get_base_types ();
- } else if (instance_type.data_type is Interface) {
- var iface = (Interface) instance_type.data_type;
- base_types = iface.get_prerequisites ();
- } else {
- Report.error (expr.source_reference, "internal error: unsupported generic type");
- expr.error = true;
- return;
- }
- foreach (TypeReference base_type in base_types) {
- if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, msym.name) != null) {
- // construct a new type reference for the base type with correctly linked type arguments
- var instance_base_type = new TypeReference ();
- instance_base_type.data_type = base_type.data_type;
- foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
- if (type_arg.type_parameter != null) {
- // link to type argument of derived type
- int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
- if (param_index == -1) {
- Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
- expr.error = true;
- return;
- }
- type_arg = instance_type.get_type_arguments ().nth_data (param_index);
- }
- instance_base_type.add_type_argument (type_arg);
- }
- instance_type = instance_base_type;
- }
- }
- }
- if (instance_type.data_type != msym.parent_symbol) {
- Report.error (expr.source_reference, "internal error: generic type parameter tracing not supported yet");
- expr.error = true;
- return;
- }
- int param_index = instance_type.data_type.get_type_parameter_index (param.type_reference.type_parameter.name);
- if (param_index == -1) {
- Report.error (expr.source_reference, "internal error: unknown type parameter %s".printf (param.type_reference.type_parameter.name));
- expr.error = true;
- return;
- }
- var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
- if (param_type == null) {
- Report.error (expr.source_reference, "internal error: no actual argument found for type parameter %s".printf (param.type_reference.type_parameter.name));
- expr.error = true;
- return;
+ var param_type = get_actual_type (ma.inner.static_type, msym, param.type_reference.type_parameter, expr);
+ if (param_type != null) {
+ is_ref = param_type.takes_ownership;
}
+ }
+ }
+
+ if (is_ref) {
+ visit_possibly_missing_copy_expression (arg);
+ } else {
+ visit_possibly_leaked_expression (arg);
+ }
+ } else {
+ visit_possibly_leaked_expression (arg);
+ }
+
+ params_it = params_it.next;
+ } else {
+ visit_possibly_leaked_expression (arg);
+ }
+ }
+ }
+
+ public override void visit_end_object_creation_expression (ObjectCreationExpression! expr) {
+ if (!(expr.symbol_reference is Invokable)) {
+ return;
+ }
+
+ var msym = (Invokable) expr.symbol_reference;
+ List<weak FormalParameter> params = msym.get_parameters ();
+
+ weak List<weak FormalParameter> params_it = params;
+ foreach (Expression arg in expr.get_argument_list ()) {
+ if (params_it != null) {
+ var param = (FormalParameter) params_it.data;
+ if (!param.ellipsis
+ && ((param.type_reference.data_type != null
+ && param.type_reference.data_type.is_reference_type ())
+ || 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 = get_actual_type (expr.type_reference, msym, param.type_reference.type_parameter, expr);
+ if (param_type != null) {
is_ref = param_type.takes_ownership;
}
}
}
}
+ private TypeReference get_actual_type (TypeReference instance_type, Symbol generic_member, TypeParameter type_parameter, CodeNode node_reference) {
+ // trace type arguments back to the datatype where the method has been declared
+ // TODO move this to semantic analyzer
+ while (instance_type.data_type != generic_member.parent_symbol) {
+ List<weak TypeReference> base_types = null;
+ if (instance_type.data_type is Class) {
+ var cl = (Class) instance_type.data_type;
+ base_types = cl.get_base_types ();
+ } else if (instance_type.data_type is Interface) {
+ var iface = (Interface) instance_type.data_type;
+ base_types = iface.get_prerequisites ();
+ } else {
+ Report.error (node_reference.source_reference, "internal error: unsupported generic type");
+ node_reference.error = true;
+ return null;
+ }
+ foreach (TypeReference base_type in base_types) {
+ if (SemanticAnalyzer.symbol_lookup_inherited (base_type.data_type, generic_member.name) != null) {
+ // construct a new type reference for the base type with correctly linked type arguments
+ var instance_base_type = new TypeReference ();
+ instance_base_type.data_type = base_type.data_type;
+ foreach (TypeReference type_arg in base_type.get_type_arguments ()) {
+ if (type_arg.type_parameter != null) {
+ // link to type argument of derived type
+ int param_index = instance_type.data_type.get_type_parameter_index (type_arg.type_parameter.name);
+ if (param_index == -1) {
+ Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_arg.type_parameter.name));
+ node_reference.error = true;
+ return null;
+ }
+ type_arg = instance_type.get_type_arguments ().nth_data (param_index);
+ }
+ instance_base_type.add_type_argument (type_arg);
+ }
+ instance_type = instance_base_type;
+ }
+ }
+ }
+ if (instance_type.data_type != generic_member.parent_symbol) {
+ Report.error (node_reference.source_reference, "internal error: generic type parameter tracing not supported yet");
+ node_reference.error = true;
+ return null;
+ }
+ int param_index = instance_type.data_type.get_type_parameter_index (type_parameter.name);
+ if (param_index == -1) {
+ Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (type_parameter.name));
+ node_reference.error = true;
+ return null;
+ }
+ var param_type = (TypeReference) instance_type.get_type_arguments ().nth_data (param_index);
+ if (param_type == null) {
+ Report.error (node_reference.source_reference, "internal error: no actual argument found for type parameter %s".printf (type_parameter.name));
+ node_reference.error = true;
+ return null;
+ }
+ return param_type;
+ }
+
public override void visit_binary_expression (BinaryExpression! expr) {
visit_possibly_leaked_expression (expr.left);
visit_possibly_leaked_expression (expr.right);
}
type.data_type = element_type.data_type.get_array (type.array_rank);
} else {
+ element_type.takes_ownership = type.takes_ownership;
type.data_type = element_type.type_parameter.get_array (type.array_rank);
type.type_parameter = null;
}