]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
add dup_func parameter to generic classes, fix some memory management
authorJuerg Billeter <j@bitron.ch>
Wed, 25 Jul 2007 20:30:58 +0000 (20:30 +0000)
committerJürg Billeter <juergbi@src.gnome.org>
Wed, 25 Jul 2007 20:30:58 +0000 (20:30 +0000)
2007-07-25  Juerg 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

svn path=/trunk/; revision=387

ChangeLog
gobject/valacodegenerator.vala
gobject/valacodegeneratorassignment.vala
gobject/valacodegeneratorclass.vala
gobject/valacodegeneratormethod.vala
vala/valainvokable.vala
vala/valamemorymanager.vala
vala/valasymbolresolver.vala

index 86281af4b8c6080f1dd65c62c508feb1ff12116a..0ab318f614fadb4feecbeedfbbc72dbe88d4a1c6 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,12 @@
+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,
index b9eedb1e45e476ec1674879864d8b870ea133b35..8471f81f19bddc11687dea6ef900dc78afc270da 100644 (file)
@@ -879,6 +879,27 @@ public class Vala.CodeGenerator : CodeVisitor {
                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;
@@ -2008,26 +2029,9 @@ public class Vala.CodeGenerator : CodeVisitor {
                 * 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;
@@ -2038,13 +2042,22 @@ public class Vala.CodeGenerator : CodeVisitor {
                        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;
@@ -2066,7 +2079,15 @@ public class Vala.CodeGenerator : CodeVisitor {
                                }
                        }
 
-                       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;
                }
@@ -2129,9 +2150,11 @@ public class Vala.CodeGenerator : CodeVisitor {
                        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"));
                                        }
                                }
                        }
@@ -2141,9 +2164,6 @@ public class Vala.CodeGenerator : CodeVisitor {
                        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;
index 260773d98d44ec34b04345d55359232e70b294e4..3007cedb1127549fd3c15f0d138f8620fb8121d7 100644 (file)
@@ -192,9 +192,6 @@ public class Vala.CodeGenerator {
                        
                        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
index ac390b5e49441fb2b353f9394f5e9643682f902e..9c167a83de7d56eb0e28d115eee7344287939906 100644 (file)
@@ -221,15 +221,37 @@ public class Vala.CodeGenerator {
                        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\""));
index def0fea393bf1d92da1381c2dc3e54e37e7016b9..a536292698f3af897102c3f7a919b7a2294259c4 100644 (file)
@@ -129,8 +129,8 @@ public class Vala.CodeGenerator {
                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"));
                        }
                }
 
@@ -275,11 +275,20 @@ public class Vala.CodeGenerator {
                                                        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 {
index 240439ddbba8e3194cf1a9799d10b60c2fe9b897..d9838cbe2cda063eacf28bb5e20f0a08f6296d0f 100644 (file)
@@ -25,7 +25,7 @@ using GLib;
 /**
  * Represents a possibly invokable code object.
  */
-public interface Vala.Invokable /* : CodeNode */ {
+public interface Vala.Invokable : Symbol {
        /**
         * Returns whether this code object is invokable.
         *
index ab4f776a1f0a2adeadf2fbdfeb6fb5a87c9b9958..fa8a07e59cb80a7b8f5da9e577b2ad93be3469d7 100644 (file)
@@ -171,28 +171,9 @@ public class Vala.MemoryManager : CodeVisitor {
        }
 
        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) {
@@ -203,63 +184,51 @@ 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) {
-                                               // 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;
                                                }
                                        }
@@ -280,6 +249,64 @@ public class Vala.MemoryManager : CodeVisitor {
                }
        }
 
+       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);
index 379ebeb84db2c61d7396d93b94385af7abcfb2f9..c76898c182720883af7026cffbcc5a26c0ab9217 100644 (file)
@@ -268,6 +268,7 @@ public class Vala.SymbolResolver : CodeVisitor {
                                }
                                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;
                        }