From: Rico Tzschichholz Date: Sun, 12 Apr 2020 09:02:29 +0000 (+0200) Subject: codegen: Correctly handle signals returning real non-nullable struct X-Git-Tag: 0.49.1~179 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=bcc40d5b971c3f5e3ebe928890b9aeba5ba32ba8;p=thirdparty%2Fvala.git codegen: Correctly handle signals returning real non-nullable struct Fixes https://gitlab.gnome.org/GNOME/vala/issues/466 --- diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala index 909131775..108622815 100644 --- a/codegen/valagsignalmodule.vala +++ b/codegen/valagsignalmodule.vala @@ -24,8 +24,8 @@ public class Vala.GSignalModule : GObjectModule { - string get_marshaller_function (List params, DataType return_type, string? prefix = null) { - var signature = get_marshaller_signature (params, return_type); + string get_marshaller_function (Signal sig, List params, DataType return_type, string? prefix = null) { + var signature = get_marshaller_signature (sig, params, return_type); string ret; if (prefix == null) { @@ -38,12 +38,13 @@ public class Vala.GSignalModule : GObjectModule { ret = "%s_%s_".printf (prefix, get_ccode_marshaller_type_name (return_type)); - if (params == null || params.size == 0) { + foreach (Parameter p in params) { + ret = "%s_%s".printf (ret, get_ccode_marshaller_type_name (p).replace (",", "_")); + } + if (sig.return_type.is_real_non_null_struct_type ()) { + ret = ret + "_POINTER"; + } else if (params.size == 0) { ret = ret + "_VOID"; - } else { - foreach (Parameter p in params) { - ret = "%s_%s".printf (ret, get_ccode_marshaller_type_name (p).replace (",", "_")); - } } return ret; @@ -93,23 +94,24 @@ public class Vala.GSignalModule : GObjectModule { } } - private string get_marshaller_signature (List params, DataType return_type) { + private string get_marshaller_signature (Signal sig, List params, DataType return_type) { string signature; signature = "%s:".printf (get_ccode_marshaller_type_name (return_type)); - if (params == null || params.size == 0) { - signature = signature + "VOID"; - } else { - bool first = true; - foreach (Parameter p in params) { - if (first) { - signature = signature + get_ccode_marshaller_type_name (p); - first = false; - } else { - signature = "%s,%s".printf (signature, get_ccode_marshaller_type_name (p)); - } + bool first = true; + foreach (Parameter p in params) { + if (first) { + signature = signature + get_ccode_marshaller_type_name (p); + first = false; + } else { + signature = "%s,%s".printf (signature, get_ccode_marshaller_type_name (p)); } } + if (sig.return_type.is_real_non_null_struct_type ()) { + signature = signature + (first ? "POINTER" : ",POINTER"); + } else if (params.size == 0) { + signature = signature + "VOID"; + } return signature; } @@ -164,24 +166,29 @@ public class Vala.GSignalModule : GObjectModule { sig.accept_children (this); // declare parameter type - foreach (Parameter p in sig.get_parameters ()) { + unowned List params = sig.get_parameters (); + foreach (Parameter p in params) { generate_parameter (p, cfile, new HashMap (), null); } - generate_marshaller (sig.get_parameters (), sig.return_type); + if (sig.return_type.is_real_non_null_struct_type ()) { + generate_marshaller (sig, params, new VoidType ()); + } else { + generate_marshaller (sig, params, sig.return_type); + } } - void generate_marshaller (List params, DataType return_type) { + void generate_marshaller (Signal sig, List params, DataType return_type) { string signature; int n_params, i; /* check whether a signal with the same signature already exists for this source file (or predefined) */ - signature = get_marshaller_signature (params, return_type); + signature = get_marshaller_signature (sig, params, return_type); if (predefined_marshal_set.contains (signature) || user_marshal_set.contains (signature)) { return; } - var signal_marshaller = new CCodeFunction (get_marshaller_function (params, return_type, null), "void"); + var signal_marshaller = new CCodeFunction (get_marshaller_function (sig, params, return_type, null), "void"); signal_marshaller.modifiers = CCodeModifiers.STATIC; signal_marshaller.add_parameter (new CCodeParameter ("closure", "GClosure *")); @@ -193,7 +200,7 @@ public class Vala.GSignalModule : GObjectModule { push_function (signal_marshaller); - var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (params, return_type, "GMarshalFunc")); + var callback_decl = new CCodeFunctionDeclarator (get_marshaller_function (sig, params, return_type, "GMarshalFunc")); callback_decl.add_parameter (new CCodeParameter ("data1", "gpointer")); n_params = 1; foreach (Parameter p in params) { @@ -218,10 +225,15 @@ public class Vala.GSignalModule : GObjectModule { } } } + if (sig.return_type.is_real_non_null_struct_type ()) { + callback_decl.add_parameter (new CCodeParameter ("arg_%d".printf (n_params), "gpointer")); + n_params++; + } + callback_decl.add_parameter (new CCodeParameter ("data2", "gpointer")); ccode.add_statement (new CCodeTypeDefinition (get_value_type_name_from_type_reference (return_type), callback_decl)); - ccode.add_declaration (get_marshaller_function (params, return_type, "GMarshalFunc"), new CCodeVariableDeclarator ("callback"), CCodeModifiers.REGISTER); + ccode.add_declaration (get_marshaller_function (sig, params, return_type, "GMarshalFunc"), new CCodeVariableDeclarator ("callback"), CCodeModifiers.REGISTER); ccode.add_declaration ("GCClosure *", new CCodeVariableDeclarator ("cc", new CCodeCastExpression (new CCodeIdentifier ("closure"), "GCClosure *")), CCodeModifiers.REGISTER); @@ -254,7 +266,7 @@ public class Vala.GSignalModule : GObjectModule { ccode.add_assignment (new CCodeIdentifier ("data2"), data); ccode.close (); - var c_assign_rhs = new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (params, return_type, "GMarshalFunc")); + var c_assign_rhs = new CCodeCastExpression (new CCodeConditionalExpression (new CCodeIdentifier ("marshal_data"), new CCodeIdentifier ("marshal_data"), new CCodeMemberAccess (new CCodeIdentifier ("cc"), "callback", true)), get_marshaller_function (sig, params, return_type, "GMarshalFunc")); ccode.add_assignment (new CCodeIdentifier ("callback"), c_assign_rhs); fc = new CCodeFunctionCall (new CCodeIdentifier ("callback")); @@ -298,6 +310,12 @@ public class Vala.GSignalModule : GObjectModule { } } } + if (sig.return_type.is_real_non_null_struct_type ()) { + var inner_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_get_pointer")); + inner_fc.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier ("param_values"), new CCodeIdentifier (i.to_string ()))); + fc.add_argument (inner_fc); + i++; + } fc.add_argument (new CCodeIdentifier ("data2")); if (return_type.type_symbol != null || return_type is ArrayType) { @@ -379,12 +397,17 @@ public class Vala.GSignalModule : GObjectModule { csignew.add_argument (new CCodeConstant ("NULL")); csignew.add_argument (new CCodeConstant ("NULL")); - string marshaller = get_marshaller_function (sig.get_parameters (), sig.return_type); + unowned List params = sig.get_parameters (); + string marshaller; + if (sig.return_type.is_real_non_null_struct_type ()) { + marshaller = get_marshaller_function (sig, params, new VoidType ()); + } else { + marshaller = get_marshaller_function (sig, params, sig.return_type); + } var marshal_arg = new CCodeIdentifier (marshaller); csignew.add_argument (marshal_arg); - var params = sig.get_parameters (); if (sig.return_type is PointerType || sig.return_type is GenericType) { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } else if (sig.return_type is ErrorType) { @@ -393,6 +416,8 @@ public class Vala.GSignalModule : GObjectModule { csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); } else if (sig.return_type.type_symbol == null) { csignew.add_argument (new CCodeConstant ("G_TYPE_NONE")); + } else if (sig.return_type.is_real_non_null_struct_type ()) { + csignew.add_argument (new CCodeConstant ("G_TYPE_NONE")); } else { csignew.add_argument (new CCodeConstant (get_ccode_type_id (sig.return_type.type_symbol))); } @@ -412,6 +437,9 @@ public class Vala.GSignalModule : GObjectModule { } } } + if (sig.return_type.is_real_non_null_struct_type ()) { + params_len++; + } csignew.add_argument (new CCodeConstant ("%d".printf (params_len))); foreach (Parameter param in params) { @@ -446,6 +474,9 @@ public class Vala.GSignalModule : GObjectModule { csignew.add_argument (new CCodeConstant (get_ccode_type_id (param.variable_type.type_symbol))); } } + if (sig.return_type.is_real_non_null_struct_type ()) { + csignew.add_argument (new CCodeConstant ("G_TYPE_POINTER")); + } marshal_arg.name = marshaller; diff --git a/tests/Makefile.am b/tests/Makefile.am index af7a89f37..8f942e8e3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -417,6 +417,7 @@ TESTS = \ objects/signals-fundamental-return.vala \ objects/signals-gobject-return.vala \ objects/signals-lambda-delegate.vala \ + objects/signals-struct-return.vala \ objects/singleton.vala \ objects/test-025.vala \ objects/test-026.vala \ diff --git a/tests/objects/signals-struct-return.vala b/tests/objects/signals-struct-return.vala new file mode 100644 index 000000000..4790d9d9d --- /dev/null +++ b/tests/objects/signals-struct-return.vala @@ -0,0 +1,46 @@ +struct Foo { + public string s; + public int i; +} + +class Bar : Object { + public signal Foo on_foo (); + public signal Foo on_foo_with_arg (string s); + public signal Foo? on_bar (); + public signal Foo? on_bar_with_arg (string s); +} + +void main () { + { + var bar = new Bar (); + bar.on_foo.connect (() => { + return { "foo", 23 }; + }); + bar.on_foo_with_arg.connect ((s) => { + assert (s == "foo"); + return { "foo", 42 }; + }); + var foo = bar.on_foo (); + assert (foo.s == "foo"); + assert (foo.i == 23); + var foo2 = bar.on_foo_with_arg ("foo"); + assert (foo2.s == "foo"); + assert (foo2.i == 42); + } + { + var bar = new Bar (); + bar.on_bar.connect (() => { + return { "bar", 42 }; + }); + bar.on_bar_with_arg.connect ((s) => { + assert (s == "bar"); + return { "bar", 23 }; + }); + var foo = bar.on_bar (); + assert (foo.s == "bar"); + assert (foo.i == 42); + var foo2 = bar.on_bar_with_arg ("bar"); + assert (foo2.s == "bar"); + assert (foo2.i == 23); + } +}