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



commit 380dfb1a3430b4d07add579dd3b6bbd485b677f4
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Fri Dec 6 15:17:59 2019 +0100

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

 codegen/valagobjectmodule.vala                     | 113 +++++++++++++++++++++
 tests/Makefile.am                                  |   2 +
 tests/generics/gobject-construction-class.vala     |  15 +++
 tests/generics/gobject-construction-interface.vala |  24 +++++
 vala/valaclass.vala                                |   7 +-
 5 files changed, 160 insertions(+), 1 deletion(-)
---
diff --git a/codegen/valagobjectmodule.vala b/codegen/valagobjectmodule.vala
index 674f18d8a..8a6c1fc3f 100644
--- a/codegen/valagobjectmodule.vala
+++ b/codegen/valagobjectmodule.vala
@@ -559,6 +559,119 @@ 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
+                       bool entered = false;
+                       foreach (DataType base_type in cl.get_base_types ()) {
+                               unowned ObjectTypeSymbol? base_sym = base_type.type_symbol as 
ObjectTypeSymbol;
+                               if (base_sym == null || !base_sym.has_type_parameters ()) {
+                                       continue;
+                               }
+
+                               var type_parameters = base_sym.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.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--"));
+
+                                               ccode.open_if (new CCodeBinaryExpression 
(CCodeBinaryOperator.EQUALITY, new CCodeIdentifier ("_properties->pspec->owner_type"), get_type_id_expression 
((base_sym is Class) ? base_type : new ClassType (cl))));
+
+                                               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++;
+                               }
+                       }
+                       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 21bfb431e..e7666114a 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -510,6 +510,8 @@ TESTS = \
        asynchronous/yield.vala \
        generics/arrays-not-supported.test \
        generics/constructor-chain-up.vala \
+       generics/gobject-construction-class.vala \
+       generics/gobject-construction-interface.vala \
        generics/inference-argument-may-fail.vala \
        generics/inference-static-function.vala \
        generics/parameter-sizeof-initializer.vala \
diff --git a/tests/generics/gobject-construction-class.vala b/tests/generics/gobject-construction-class.vala
new file mode 100644
index 000000000..364dc92c1
--- /dev/null
+++ b/tests/generics/gobject-construction-class.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/tests/generics/gobject-construction-interface.vala 
b/tests/generics/gobject-construction-interface.vala
new file mode 100644
index 000000000..28a59dbe6
--- /dev/null
+++ b/tests/generics/gobject-construction-interface.vala
@@ -0,0 +1,24 @@
+[GenericAccessors]
+interface IFoo<T> : Object {
+       public abstract T foo { get; set; }
+       public Type get_foo_type () {
+               return typeof (T);
+       }
+}
+
+abstract class Foo<T> : Object, IFoo<T> {
+       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");
+       assert (bar.get_foo_type () == typeof (string));
+}
diff --git a/vala/valaclass.vala b/vala/valaclass.vala
index e9312c415..36e0ddf5a 100644
--- a/vala/valaclass.vala
+++ b/vala/valaclass.vala
@@ -525,6 +525,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;
@@ -555,6 +557,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) {
@@ -576,7 +580,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]