diff options
author | Rico Tzschichholz <ricotz@ubuntu.com> | 2021-11-26 15:34:40 +0100 |
---|---|---|
committer | Rico Tzschichholz <ricotz@ubuntu.com> | 2021-11-28 23:11:34 +0100 |
commit | 4bfc82291b574b543f8143bcb047e05e96fd53d1 (patch) | |
tree | 622f19f58122f172e5f86e01dbecab6af7926ef0 | |
parent | db09aeab8cc4814b9d5797b7d917c96665128386 (diff) | |
download | vala-4bfc82291b574b543f8143bcb047e05e96fd53d1.tar.gz |
vala: Fix signals with generic return
In addition to 36999b5ffd63cc56a8648791b02bf07e7da88077
-rw-r--r-- | codegen/valagsignalmodule.vala | 4 | ||||
-rw-r--r-- | tests/Makefile.am | 1 | ||||
-rw-r--r-- | tests/objects/signals-generic-return.c-expected | 421 | ||||
-rw-r--r-- | tests/objects/signals-generic-return.vala | 39 | ||||
-rw-r--r-- | vala/valasignal.vala | 7 |
5 files changed, 468 insertions, 4 deletions
diff --git a/codegen/valagsignalmodule.vala b/codegen/valagsignalmodule.vala index 126e78a44..17b681365 100644 --- a/codegen/valagsignalmodule.vala +++ b/codegen/valagsignalmodule.vala @@ -242,7 +242,7 @@ public class Vala.GSignalModule : GObjectModule { CCodeFunctionCall fc; - if (return_type.type_symbol != null || return_type is ArrayType) { + if (return_type.type_symbol != null || return_type is ArrayType || return_type is GenericType) { ccode.add_declaration (get_value_type_name_from_type_reference (return_type), new CCodeVariableDeclarator ("v_return")); fc = new CCodeFunctionCall (new CCodeIdentifier ("g_return_if_fail")); @@ -318,7 +318,7 @@ public class Vala.GSignalModule : GObjectModule { } fc.add_argument (new CCodeIdentifier ("data2")); - if (return_type.type_symbol != null || return_type is ArrayType) { + if (return_type.type_symbol != null || return_type is ArrayType || return_type is GenericType) { ccode.add_assignment (new CCodeIdentifier ("v_return"), fc); CCodeFunctionCall set_fc; diff --git a/tests/Makefile.am b/tests/Makefile.am index 3468f0bbf..f0841cf80 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -543,6 +543,7 @@ TESTS = \ objects/signals-dynamic-lambda-handler.test \ objects/signals-error-marshal.vala \ objects/signals-fundamental-return.vala \ + objects/signals-generic-return.vala \ objects/signals-gobject-return.vala \ objects/signals-lambda-delegate.vala \ objects/signals-prototype-access.vala \ diff --git a/tests/objects/signals-generic-return.c-expected b/tests/objects/signals-generic-return.c-expected new file mode 100644 index 000000000..c2170c71a --- /dev/null +++ b/tests/objects/signals-generic-return.c-expected @@ -0,0 +1,421 @@ +/* objects_signals_generic_return.c generated by valac, the Vala compiler + * generated from objects_signals_generic_return.vala, do not modify */ + +#include <glib-object.h> +#include <glib.h> +#include <stdlib.h> +#include <string.h> + +#if !defined(VALA_EXTERN) +#if defined(_MSC_VER) +#define VALA_EXTERN __declspec(dllexport) extern +#elif __GNUC__ >= 4 +#define VALA_EXTERN __attribute__((visibility("default"))) extern +#else +#define VALA_EXTERN extern +#endif +#endif + +#define TYPE_FOO (foo_get_type ()) +#define FOO(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TYPE_FOO, Foo)) +#define FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TYPE_FOO, FooClass)) +#define IS_FOO(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TYPE_FOO)) +#define IS_FOO_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TYPE_FOO)) +#define FOO_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TYPE_FOO, FooClass)) + +typedef struct _Foo Foo; +typedef struct _FooClass FooClass; +typedef struct _FooPrivate FooPrivate; +enum { + FOO_0_PROPERTY, + FOO_G_TYPE, + FOO_G_DUP_FUNC, + FOO_G_DESTROY_FUNC, + FOO_T_TYPE, + FOO_T_DUP_FUNC, + FOO_T_DESTROY_FUNC, + FOO_NUM_PROPERTIES +}; +static GParamSpec* foo_properties[FOO_NUM_PROPERTIES]; +enum { + FOO_ON_FOO_SIGNAL, + FOO_ON_BAR_SIGNAL, + FOO_NUM_SIGNALS +}; +static guint foo_signals[FOO_NUM_SIGNALS] = {0}; +#define _g_free0(var) (var = (g_free (var), NULL)) +#define _g_object_unref0(var) ((var == NULL) ? NULL : (var = (g_object_unref (var), NULL))) +#define _vala_assert(expr, msg) if G_LIKELY (expr) ; else g_assertion_message_expr (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg); +#define _vala_return_if_fail(expr, msg) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return; } +#define _vala_return_val_if_fail(expr, msg, val) if G_LIKELY (expr) ; else { g_return_if_fail_warning (G_LOG_DOMAIN, G_STRFUNC, msg); return val; } +#define _vala_warn_if_fail(expr, msg) if G_LIKELY (expr) ; else g_warn_message (G_LOG_DOMAIN, __FILE__, __LINE__, G_STRFUNC, msg); + +struct _Foo { + GObject parent_instance; + FooPrivate * priv; +}; + +struct _FooClass { + GObjectClass parent_class; +}; + +struct _FooPrivate { + GType g_type; + GBoxedCopyFunc g_dup_func; + GDestroyNotify g_destroy_func; + GType t_type; + GBoxedCopyFunc t_dup_func; + GDestroyNotify t_destroy_func; +}; + +static gint Foo_private_offset; +static gpointer foo_parent_class = NULL; + +VALA_EXTERN GType foo_get_type (void) G_GNUC_CONST ; +G_DEFINE_AUTOPTR_CLEANUP_FUNC (Foo, g_object_unref) +VALA_EXTERN Foo* foo_new (GType g_type, + GBoxedCopyFunc g_dup_func, + GDestroyNotify g_destroy_func, + GType t_type, + GBoxedCopyFunc t_dup_func, + GDestroyNotify t_destroy_func); +VALA_EXTERN Foo* foo_construct (GType object_type, + GType g_type, + GBoxedCopyFunc g_dup_func, + GDestroyNotify g_destroy_func, + GType t_type, + GBoxedCopyFunc t_dup_func, + GDestroyNotify t_destroy_func); +static void g_cclosure_user_marshal_POINTER__VOID (GClosure * closure, + GValue * return_value, + guint n_param_values, + const GValue * param_values, + gpointer invocation_hint, + gpointer marshal_data); +static GType foo_get_type_once (void); +static void _vala_foo_get_property (GObject * object, + guint property_id, + GValue * value, + GParamSpec * pspec); +static void _vala_foo_set_property (GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec); +VALA_EXTERN gint cb_foo (void); +VALA_EXTERN gchar* cb_bar (void); +static void _vala_main (void); +static gint ___lambda4_ (void); +static gpointer ____lambda4__foo_on_foo (Foo* _sender, + gpointer self); +static gchar* ___lambda5_ (void); +static gpointer ____lambda5__foo_on_bar (Foo* _sender, + gpointer self); +static gpointer _cb_foo_foo_on_foo (Foo* _sender, + gpointer self); +static gpointer _cb_bar_foo_on_bar (Foo* _sender, + gpointer self); + +static inline gpointer +foo_get_instance_private (Foo* self) +{ + return G_STRUCT_MEMBER_P (self, Foo_private_offset); +} + +Foo* +foo_construct (GType object_type, + GType g_type, + GBoxedCopyFunc g_dup_func, + GDestroyNotify g_destroy_func, + GType t_type, + GBoxedCopyFunc t_dup_func, + GDestroyNotify t_destroy_func) +{ + Foo * self = NULL; + self = (Foo*) g_object_new (object_type, NULL); + self->priv->g_type = g_type; + self->priv->g_dup_func = g_dup_func; + self->priv->g_destroy_func = g_destroy_func; + self->priv->t_type = t_type; + self->priv->t_dup_func = t_dup_func; + self->priv->t_destroy_func = t_destroy_func; + return self; +} + +Foo* +foo_new (GType g_type, + GBoxedCopyFunc g_dup_func, + GDestroyNotify g_destroy_func, + GType t_type, + GBoxedCopyFunc t_dup_func, + GDestroyNotify t_destroy_func) +{ + return foo_construct (TYPE_FOO, g_type, g_dup_func, g_destroy_func, t_type, t_dup_func, t_destroy_func); +} + +static void +g_cclosure_user_marshal_POINTER__VOID (GClosure * closure, + GValue * return_value, + guint n_param_values, + const GValue * param_values, + gpointer invocation_hint, + gpointer marshal_data) +{ + typedef gpointer (*GMarshalFunc_POINTER__VOID) (gpointer data1, gpointer data2); + register GMarshalFunc_POINTER__VOID callback; + register GCClosure * cc; + register gpointer data1; + register gpointer data2; + gpointer v_return; + cc = (GCClosure *) closure; + g_return_if_fail (return_value != NULL); + g_return_if_fail (n_param_values == 1); + if (G_CCLOSURE_SWAP_DATA (closure)) { + data1 = closure->data; + data2 = param_values->data[0].v_pointer; + } else { + data1 = param_values->data[0].v_pointer; + data2 = closure->data; + } + callback = (GMarshalFunc_POINTER__VOID) (marshal_data ? marshal_data : cc->callback); + v_return = callback (data1, data2); + g_value_set_pointer (return_value, v_return); +} + +static void +foo_class_init (FooClass * klass, + gpointer klass_data) +{ + foo_parent_class = g_type_class_peek_parent (klass); + g_type_class_adjust_private_offset (klass, &Foo_private_offset); + G_OBJECT_CLASS (klass)->get_property = _vala_foo_get_property; + G_OBJECT_CLASS (klass)->set_property = _vala_foo_set_property; + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_G_TYPE, g_param_spec_gtype ("g-type", "type", "type", G_TYPE_NONE, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_G_DUP_FUNC, g_param_spec_pointer ("g-dup-func", "dup func", "dup func", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_G_DESTROY_FUNC, g_param_spec_pointer ("g-destroy-func", "destroy func", "destroy func", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_T_TYPE, g_param_spec_gtype ("t-type", "type", "type", G_TYPE_NONE, G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_T_DUP_FUNC, g_param_spec_pointer ("t-dup-func", "dup func", "dup func", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + g_object_class_install_property (G_OBJECT_CLASS (klass), FOO_T_DESTROY_FUNC, g_param_spec_pointer ("t-destroy-func", "destroy func", "destroy func", G_PARAM_STATIC_STRINGS | G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY)); + foo_signals[FOO_ON_FOO_SIGNAL] = g_signal_new ("on-foo", TYPE_FOO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_POINTER__VOID, G_TYPE_POINTER, 0); + foo_signals[FOO_ON_BAR_SIGNAL] = g_signal_new ("on-bar", TYPE_FOO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_POINTER__VOID, G_TYPE_POINTER, 0); +} + +static void +foo_instance_init (Foo * self, + gpointer klass) +{ + self->priv = foo_get_instance_private (self); +} + +static GType +foo_get_type_once (void) +{ + static const GTypeInfo g_define_type_info = { sizeof (FooClass), (GBaseInitFunc) NULL, (GBaseFinalizeFunc) NULL, (GClassInitFunc) foo_class_init, (GClassFinalizeFunc) NULL, NULL, sizeof (Foo), 0, (GInstanceInitFunc) foo_instance_init, NULL }; + GType foo_type_id; + foo_type_id = g_type_register_static (G_TYPE_OBJECT, "Foo", &g_define_type_info, 0); + Foo_private_offset = g_type_add_instance_private (foo_type_id, sizeof (FooPrivate)); + return foo_type_id; +} + +GType +foo_get_type (void) +{ + static volatile gsize foo_type_id__volatile = 0; + if (g_once_init_enter (&foo_type_id__volatile)) { + GType foo_type_id; + foo_type_id = foo_get_type_once (); + g_once_init_leave (&foo_type_id__volatile, foo_type_id); + } + return foo_type_id__volatile; +} + +static void +_vala_foo_get_property (GObject * object, + guint property_id, + GValue * value, + GParamSpec * pspec) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_FOO, Foo); + switch (property_id) { + case FOO_G_TYPE: + g_value_set_gtype (value, self->priv->g_type); + break; + case FOO_G_DUP_FUNC: + g_value_set_pointer (value, self->priv->g_dup_func); + break; + case FOO_G_DESTROY_FUNC: + g_value_set_pointer (value, self->priv->g_destroy_func); + break; + case FOO_T_TYPE: + g_value_set_gtype (value, self->priv->t_type); + break; + case FOO_T_DUP_FUNC: + g_value_set_pointer (value, self->priv->t_dup_func); + break; + case FOO_T_DESTROY_FUNC: + g_value_set_pointer (value, self->priv->t_destroy_func); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +_vala_foo_set_property (GObject * object, + guint property_id, + const GValue * value, + GParamSpec * pspec) +{ + Foo * self; + self = G_TYPE_CHECK_INSTANCE_CAST (object, TYPE_FOO, Foo); + switch (property_id) { + case FOO_G_TYPE: + self->priv->g_type = g_value_get_gtype (value); + break; + case FOO_G_DUP_FUNC: + self->priv->g_dup_func = g_value_get_pointer (value); + break; + case FOO_G_DESTROY_FUNC: + self->priv->g_destroy_func = g_value_get_pointer (value); + break; + case FOO_T_TYPE: + self->priv->t_type = g_value_get_gtype (value); + break; + case FOO_T_DUP_FUNC: + self->priv->t_dup_func = g_value_get_pointer (value); + break; + case FOO_T_DESTROY_FUNC: + self->priv->t_destroy_func = g_value_get_pointer (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +gint +cb_foo (void) +{ + gint result = 0; + result = 23; + return result; +} + +gchar* +cb_bar (void) +{ + gchar* _tmp0_; + gchar* result = NULL; + _tmp0_ = g_strdup ("foo"); + result = _tmp0_; + return result; +} + +static gint +___lambda4_ (void) +{ + gint result = 0; + result = 42; + return result; +} + +static gpointer +____lambda4__foo_on_foo (Foo* _sender, + gpointer self) +{ + gpointer result; + result = (gpointer) ((gintptr) ___lambda4_ ()); + return result; +} + +static gchar* +___lambda5_ (void) +{ + gchar* _tmp0_; + gchar* result = NULL; + _tmp0_ = g_strdup ("bar"); + result = _tmp0_; + return result; +} + +static gpointer +____lambda5__foo_on_bar (Foo* _sender, + gpointer self) +{ + gpointer result; + result = ___lambda5_ (); + return result; +} + +static gpointer +_cb_foo_foo_on_foo (Foo* _sender, + gpointer self) +{ + gpointer result; + result = (gpointer) ((gintptr) cb_foo ()); + return result; +} + +static gpointer +_cb_bar_foo_on_bar (Foo* _sender, + gpointer self) +{ + gpointer result; + result = cb_bar (); + return result; +} + +static void +_vala_main (void) +{ + { + Foo* foo = NULL; + Foo* _tmp0_; + gint bar = 0; + gpointer _tmp1_ = NULL; + gchar* bar2 = NULL; + gpointer _tmp2_ = NULL; + _tmp0_ = foo_new (G_TYPE_INT, NULL, NULL, G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free); + foo = _tmp0_; + g_signal_connect (foo, "on-foo", (GCallback) ____lambda4__foo_on_foo, NULL); + g_signal_connect (foo, "on-bar", (GCallback) ____lambda5__foo_on_bar, NULL); + g_signal_emit (foo, foo_signals[FOO_ON_FOO_SIGNAL], 0, &_tmp1_); + bar = (gint) ((gintptr) _tmp1_); + _vala_assert (bar == 42, "bar == 42"); + g_signal_emit (foo, foo_signals[FOO_ON_BAR_SIGNAL], 0, &_tmp2_); + bar2 = (gchar*) _tmp2_; + _vala_assert (g_strcmp0 (bar2, "bar") == 0, "bar2 == \"bar\""); + _g_free0 (bar2); + _g_object_unref0 (foo); + } + { + Foo* foo = NULL; + Foo* _tmp3_; + gint bar = 0; + gpointer _tmp4_ = NULL; + gchar* bar2 = NULL; + gpointer _tmp5_ = NULL; + _tmp3_ = foo_new (G_TYPE_INT, NULL, NULL, G_TYPE_STRING, (GBoxedCopyFunc) g_strdup, (GDestroyNotify) g_free); + foo = _tmp3_; + g_signal_connect (foo, "on-foo", (GCallback) _cb_foo_foo_on_foo, NULL); + g_signal_connect (foo, "on-bar", (GCallback) _cb_bar_foo_on_bar, NULL); + g_signal_emit (foo, foo_signals[FOO_ON_FOO_SIGNAL], 0, &_tmp4_); + bar = (gint) ((gintptr) _tmp4_); + _vala_assert (bar == 23, "bar == 23"); + g_signal_emit (foo, foo_signals[FOO_ON_BAR_SIGNAL], 0, &_tmp5_); + bar2 = (gchar*) _tmp5_; + _vala_assert (g_strcmp0 (bar2, "foo") == 0, "bar2 == \"foo\""); + _g_free0 (bar2); + _g_object_unref0 (foo); + } +} + +int +main (int argc, + char ** argv) +{ + _vala_main (); + return 0; +} + diff --git a/tests/objects/signals-generic-return.vala b/tests/objects/signals-generic-return.vala new file mode 100644 index 000000000..410cdc789 --- /dev/null +++ b/tests/objects/signals-generic-return.vala @@ -0,0 +1,39 @@ +class Foo<G,T> : Object { + public signal G on_foo (); + public signal T on_bar (); +} + +int cb_foo () { + return 23; +} + +string cb_bar () { + return "foo"; +} + +void main () { + { + var foo = new Foo<int,string> (); + foo.on_foo.connect (() => { + return 42; + }); + foo.on_bar.connect (() => { + return "bar"; + }); + + var bar = foo.on_foo (); + assert (bar == 42); + var bar2 = foo.on_bar (); + assert (bar2 == "bar"); + } + { + var foo = new Foo<int,string> (); + foo.on_foo.connect (cb_foo); + foo.on_bar.connect (cb_bar); + + var bar = foo.on_foo (); + assert (bar == 23); + var bar2 = foo.on_bar (); + assert (bar2 == "foo"); + } +} diff --git a/vala/valasignal.vala b/vala/valasignal.vala index 8e805d682..ffd5a760a 100644 --- a/vala/valasignal.vala +++ b/vala/valasignal.vala @@ -115,7 +115,7 @@ public class Vala.Signal : Symbol, Callable { generated_delegate.sender_type = sender_param_type; - bool is_generic = false; + bool is_generic = actual_return_type.is_generic (); foreach (Parameter param in parameters) { var actual_param = param.copy (); @@ -133,8 +133,11 @@ public class Vala.Signal : Symbol, Callable { generated_delegate.add_type_parameter (new TypeParameter (type_param.name, type_param.source_reference)); } - // parameter types must refer to the delegate type parameters + // return type and parameter types must refer to the delegate type parameters // instead of to the class type parameters + foreach (var type_param in generated_delegate.get_type_parameters ()) { + actual_return_type.replace_type_parameter (cl.get_type_parameters ().get (cl.get_type_parameter_index (type_param.name)), type_param); + } foreach (var param in generated_delegate.get_parameters ()) { foreach (var type_param in generated_delegate.get_type_parameters ()) { param.variable_type.replace_type_parameter (cl.get_type_parameters ().get (cl.get_type_parameter_index (type_param.name)), type_param); |