[vala/wip/issue/871: 3/3] codegen: Set generic-type properties in Object.constructor()



commit cac2096f6c3a98c9563300af64be0cce9fa8bc99
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Thu Oct 31 15:10:46 2019 +0100

    codegen: Set generic-type properties in Object.constructor()
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/871

 codegen/valagobjectmodule.vala           | 111 +++++++++++++++++++++++++++++++
 tests/Makefile.am                        |   1 +
 tests/generics/gobject-construction.vala |  15 +++++
 vala/valaclass.vala                      |   7 +-
 4 files changed, 133 insertions(+), 1 deletion(-)
---
diff --git a/codegen/valagobjectmodule.vala b/codegen/valagobjectmodule.vala
index 65726fe68..0f2b5ee35 100644
--- a/codegen/valagobjectmodule.vala
+++ b/codegen/valagobjectmodule.vala
@@ -522,6 +522,117 @@ public class Vala.GObjectModule : GTypeModule {
                        ccast.add_argument (new CCodeIdentifier ("%s_parent_class".printf 
(get_ccode_lower_case_name (cl, null))));
                        ccode.add_assignment (new CCodeIdentifier ("parent_class"), ccast);
 
+
+                       // Set values of generic type properties with available information
+                       ccode.add_declaration ("guint", new CCodeVariableDeclarator ("_n_properties"));
+                       ccode.add_declaration ("GObjectConstructParam *", new CCodeVariableDeclarator 
("_properties"));
+
+                       ccode.add_assignment (new CCodeIdentifier ("_n_properties"), new CCodeIdentifier 
("n_construct_properties"));
+                       ccode.add_assignment (new CCodeIdentifier ("_properties"), new CCodeIdentifier 
("construct_properties"));
+                       ccode.open_if (new CCodeIdentifier ("_n_properties"));
+                       ccode.open_while (new CCodeIdentifier ("_n_properties--"));
+
+                       bool entered = false;
+                       foreach (DataType base_type in cl.get_base_types ()) {
+                               if (base_type.type_symbol is Class) {
+                                       var type_parameters = ((Class) 
base_type.type_symbol).get_type_parameters ();
+                                       int type_param_index = 0;
+
+                                       foreach (var type_arg in base_type.get_type_arguments ()) {
+                                               if (type_arg is GenericType) {
+                                                       type_param_index++;
+                                                       continue;
+                                               }
+
+                                               var type_param_name = type_parameters.get 
(type_param_index).name.down ().replace ("_", "-");
+
+                                               var cmp = new CCodeFunctionCall (new CCodeIdentifier 
("strcmp"));
+                                               cmp.add_argument (new CCodeIdentifier ("_property_name"));
+                                               cmp.add_argument (new CCodeIdentifier ("\"%s-type\"".printf 
(type_param_name)));
+                                               var cond = new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, cmp, new CCodeConstant ("0"));
+
+                                               if (!entered) {
+                                                       ccode.open_if (new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("_properties->pspec->owner_type"), get_type_id_expression 
(base_type)));
+
+                                                       ccode.add_declaration ("const gchar *", new 
CCodeVariableDeclarator ("_property_name"));
+                                                       ccode.add_assignment (new CCodeIdentifier 
("_property_name"), new CCodeIdentifier ("_properties->pspec->name"));
+
+                                                       ccode.open_if (cond);
+                                                       entered = true;
+                                               } else {
+                                                       ccode.else_if (cond);
+                                               }
+
+                                               var ccall = new CCodeFunctionCall (new CCodeIdentifier 
("g_value_set_gtype"));
+                                               ccall.add_argument (new CCodeIdentifier 
("_properties->value"));
+                                               ccall.add_argument (get_type_id_expression (type_arg));
+                                               ccode.add_statement (new CCodeExpressionStatement (ccall));
+
+                                               if (requires_copy (type_arg)) {
+                                                       var dup_func = get_dup_func_expression (type_arg, 
type_arg.source_reference);
+                                                       if (dup_func == null) {
+                                                               assert_not_reached ();
+                                                       }
+
+                                                       cmp = new CCodeFunctionCall (new CCodeIdentifier 
("strcmp"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("_property_name"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("\"%s-dup-func\"".printf (type_param_name)));
+                                                       cond = new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, cmp, new CCodeConstant ("0"));
+                                                       ccode.else_if (cond);
+
+                                                       ccall = new CCodeFunctionCall (new CCodeIdentifier 
("g_value_set_pointer"));
+                                                       ccall.add_argument (new CCodeIdentifier 
("_properties->value"));
+                                                       ccall.add_argument (dup_func);
+                                                       ccode.add_statement (new CCodeExpressionStatement 
(ccall));
+
+                                                       cmp = new CCodeFunctionCall (new CCodeIdentifier 
("strcmp"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("_property_name"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("\"%s-destroy-func\"".printf (type_param_name)));
+                                                       cond = new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, cmp, new CCodeConstant ("0"));
+                                                       ccode.else_if (cond);
+
+                                                       ccall = new CCodeFunctionCall (new CCodeIdentifier 
("g_value_set_pointer"));
+                                                       ccall.add_argument (new CCodeIdentifier 
("_properties->value"));
+                                                       ccall.add_argument (get_destroy_func_expression 
(type_arg));
+                                                       ccode.add_statement (new CCodeExpressionStatement 
(ccall));
+                                               } else {
+                                                       cmp = new CCodeFunctionCall (new CCodeIdentifier 
("strcmp"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("_property_name"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("\"%s-dup-func\"".printf (type_param_name)));
+                                                       cond = new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, cmp, new CCodeConstant ("0"));
+                                                       ccode.else_if (cond);
+
+                                                       ccall = new CCodeFunctionCall (new CCodeIdentifier 
("g_value_set_pointer"));
+                                                       ccall.add_argument (new CCodeIdentifier 
("_properties->value"));
+                                                       ccall.add_argument (new CCodeConstant ("NULL"));
+                                                       ccode.add_statement (new CCodeExpressionStatement 
(ccall));
+
+                                                       cmp = new CCodeFunctionCall (new CCodeIdentifier 
("strcmp"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("_property_name"));
+                                                       cmp.add_argument (new CCodeIdentifier 
("\"%s-destroy-func\"".printf (type_param_name)));
+                                                       cond = new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, cmp, new CCodeConstant ("0"));
+                                                       ccode.else_if (cond);
+
+                                                       ccall = new CCodeFunctionCall (new CCodeIdentifier 
("g_value_set_pointer"));
+                                                       ccall.add_argument (new CCodeIdentifier 
("_properties->value"));
+                                                       ccall.add_argument (new CCodeConstant ("NULL"));
+                                                       ccode.add_statement (new CCodeExpressionStatement 
(ccall));
+                                               }
+
+                                               type_param_index++;
+                                       }
+                                       break;
+                               }
+                       }
+                       if (entered) {
+                               ccode.close ();
+                               ccode.close ();
+                       }
+                       ccode.add_statement (new CCodeExpressionStatement (new CCodeIdentifier 
("_properties++")));
+                       ccode.close ();
+                       ccode.close ();
+
+
                        var ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier 
("parent_class"), "constructor"));
                        ccall.add_argument (new CCodeIdentifier ("type"));
                        ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 292eea0c7..61c49bbd6 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -500,6 +500,7 @@ TESTS = \
        asynchronous/yield.vala \
        generics/arrays-not-supported.test \
        generics/constructor-chain-up.vala \
+       generics/gobject-construction.vala \
        generics/inference-static-function.vala \
        generics/parameter-sizeof-initializer.vala \
        generics/bug640330.test \
diff --git a/tests/generics/gobject-construction.vala b/tests/generics/gobject-construction.vala
new file mode 100644
index 000000000..364dc92c1
--- /dev/null
+++ b/tests/generics/gobject-construction.vala
@@ -0,0 +1,15 @@
+abstract class Foo<T> : Object {
+       public T foo { get; set; }
+}
+
+class Bar : Foo<string> {
+}
+
+void main () {
+       Bar bar;
+       {
+               string foo = "foo";
+               bar = (Bar) Object.new (typeof (Bar), "foo", foo);
+       }
+       assert (bar.foo == "foo");
+}
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index 6cad8e00a..bc3cc0482 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -512,6 +512,8 @@ public class Vala.Class : ObjectTypeSymbol {
                }
                context.analyzer.current_symbol = this;
 
+               bool has_type_arguments = false;
+
                foreach (DataType base_type_reference in get_base_types ()) {
                        if (!base_type_reference.check (context)) {
                                error = true;
@@ -542,6 +544,8 @@ public class Vala.Class : ObjectTypeSymbol {
                                Report.error (base_type_reference.source_reference, "too many type 
arguments");
                                return false;
                        }
+
+                       has_type_arguments = (n_type_args > 0);
                }
 
                foreach (DataType type in base_types) {
@@ -563,7 +567,8 @@ public class Vala.Class : ObjectTypeSymbol {
                }
 
                /* singleton classes require an instance construtor */
-               if (is_singleton && constructor == null) {
+               if (constructor == null
+                   && (is_singleton || (is_subtype_of (context.analyzer.object_type) && 
has_type_arguments))) {
                        var c = new Constructor (source_reference);
                        c.body = new Block (source_reference);
                        add_constructor (c);


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