]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
vala: Add support to infer return type of dynamic signals
authorLorenz Wildberg <lorenz@wild-fisch.de>
Wed, 8 Dec 2021 18:41:39 +0000 (18:41 +0000)
committerRico Tzschichholz <ricotz@ubuntu.com>
Tue, 25 Jan 2022 12:41:43 +0000 (13:41 +0100)
codegen/valaccodemethodcallmodule.vala
tests/Makefile.am
tests/objects/signals-dynamic-emit.c-expected
tests/objects/signals-dynamic-emit.vala
tests/objects/signals-dynamic-invalid-return-type.test [new file with mode: 0644]
tests/objects/signals-emit.c-expected
tests/objects/signals-emit.vala
vala/valamemberaccess.vala

index d7827741b99fe23d4744513e29774d8632f06e4b..6332271ad744c334f28ef276ae2773485a6e7839 100644 (file)
@@ -546,7 +546,11 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
                                }
                        }
 
-                       arg_pos = get_param_pos (param != null && !ellipsis ? get_ccode_pos (param) : i, ellipsis);
+                       if (itype is SignalType && ((SignalType) itype).signal_symbol is DynamicSignal) {
+                               arg_pos = get_param_pos (i, false);
+                       } else {
+                               arg_pos = get_param_pos (param != null && !ellipsis ? get_ccode_pos (param) : i, ellipsis);
+                       }
                        carg_map.set (arg_pos, cexpr);
 
                        if (m is ArrayResizeMethod && context.profile == Profile.POSIX) {
index 2103afa6e6025bcedeeda9ddf9e10a7cc7203aee..0b9f71524c137982924d54bffe6908f41f6fb364 100644 (file)
@@ -563,6 +563,7 @@ TESTS = \
        objects/signals-dynamic-emit.vala \
        objects/signals-dynamic-invalid-disconnect.test \
        objects/signals-dymanic-invalid-handler.test \
+       objects/signals-dynamic-invalid-return-type.test \
        objects/signals-dynamic-lambda-handler.test \
        objects/signals-emit.vala \
        objects/signals-error-marshal.vala \
index 5b04c9bbbef4064b31d14538471bb3b0d056f052..7c71e3b42f047be13e152156d988fe180b364988 100644 (file)
@@ -33,6 +33,7 @@ enum  {
 static GParamSpec* foo_properties[FOO_NUM_PROPERTIES];
 enum  {
        FOO_SIG_SIGNAL,
+       FOO_SIG2_SIGNAL,
        FOO_NUM_SIGNALS
 };
 static guint foo_signals[FOO_NUM_SIGNALS] = {0};
@@ -65,15 +66,28 @@ static void g_cclosure_user_marshal_VOID__STRING_INT (GClosure * closure,
                                                const GValue * param_values,
                                                gpointer invocation_hint,
                                                gpointer marshal_data);
+static void g_cclosure_user_marshal_BOOLEAN__STRING_INT (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);
 VALA_EXTERN void sig_cb (GObject* o,
              const gchar* s,
              gint i);
+VALA_EXTERN gboolean sig2_cb (GObject* o,
+                  const gchar* s,
+                  gint i);
 static void _vala_main (void);
 static void _sig_cb_dynamic_sig0_ (GObject* _sender,
                             const gchar* s,
                             gint i,
                             gpointer self);
+static gboolean _sig2_cb_dynamic_sig21_ (GObject* _sender,
+                                  const gchar* s,
+                                  gint i,
+                                  gpointer self);
 
 Foo*
 foo_construct (GType object_type)
@@ -115,12 +129,42 @@ g_cclosure_user_marshal_VOID__STRING_INT (GClosure * closure,
        callback (data1, g_value_get_string (param_values + 1), g_value_get_int (param_values + 2), data2);
 }
 
+static void
+g_cclosure_user_marshal_BOOLEAN__STRING_INT (GClosure * closure,
+                                             GValue * return_value,
+                                             guint n_param_values,
+                                             const GValue * param_values,
+                                             gpointer invocation_hint,
+                                             gpointer marshal_data)
+{
+       typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_INT) (gpointer data1, const char* arg_1, gint arg_2, gpointer data2);
+       register GMarshalFunc_BOOLEAN__STRING_INT callback;
+       register GCClosure * cc;
+       register gpointer data1;
+       register gpointer data2;
+       gboolean v_return;
+       cc = (GCClosure *) closure;
+       g_return_if_fail (return_value != NULL);
+       g_return_if_fail (n_param_values == 3);
+       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_BOOLEAN__STRING_INT) (marshal_data ? marshal_data : cc->callback);
+       v_return = callback (data1, g_value_get_string (param_values + 1), g_value_get_int (param_values + 2), data2);
+       g_value_set_boolean (return_value, v_return);
+}
+
 static void
 foo_class_init (FooClass * klass,
                 gpointer klass_data)
 {
        foo_parent_class = g_type_class_peek_parent (klass);
        foo_signals[FOO_SIG_SIGNAL] = g_signal_new ("sig", TYPE_FOO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__STRING_INT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+       foo_signals[FOO_SIG2_SIGNAL] = g_signal_new ("sig2", TYPE_FOO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_BOOLEAN__STRING_INT, G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_INT);
 }
 
 static void
@@ -162,6 +206,21 @@ sig_cb (GObject* o,
        _vala_assert (i == 42, "i == 42");
 }
 
+gboolean
+sig2_cb (GObject* o,
+         const gchar* s,
+         gint i)
+{
+       gboolean result;
+       g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (o, G_TYPE_OBJECT), FALSE);
+       g_return_val_if_fail (s != NULL, FALSE);
+       success = TRUE;
+       _vala_assert (g_strcmp0 (s, "foo") == 0, "s == \"foo\"");
+       _vala_assert (i == 42, "i == 42");
+       result = TRUE;
+       return result;
+}
+
 static void
 _sig_cb_dynamic_sig0_ (GObject* _sender,
                        const gchar* s,
@@ -171,17 +230,34 @@ _sig_cb_dynamic_sig0_ (GObject* _sender,
        sig_cb (_sender, s, i);
 }
 
+static gboolean
+_sig2_cb_dynamic_sig21_ (GObject* _sender,
+                         const gchar* s,
+                         gint i,
+                         gpointer self)
+{
+       gboolean result;
+       result = sig2_cb (_sender, s, i);
+       return result;
+}
+
 static void
 _vala_main (void)
 {
        GObject* dfoo = NULL;
        Foo* _tmp0_;
+       gboolean _tmp1_ = FALSE;
        _tmp0_ = foo_new ();
        dfoo = G_TYPE_CHECK_INSTANCE_CAST (_tmp0_, G_TYPE_OBJECT, GObject);
        g_signal_connect (dfoo, "sig", (GCallback) _sig_cb_dynamic_sig0_, NULL);
        success = FALSE;
        g_signal_emit_by_name (dfoo, "sig", "foo", 42);
        _vala_assert (success, "success");
+       g_signal_connect (dfoo, "sig2", (GCallback) _sig2_cb_dynamic_sig21_, NULL);
+       success = FALSE;
+       g_signal_emit_by_name (dfoo, "sig2", "foo", 42, &_tmp1_);
+       _vala_assert (_tmp1_, "dfoo.sig2.emit (\"foo\", 42)");
+       _vala_assert (success, "success");
        _g_object_unref0 (dfoo);
 }
 
index 55d6fac98f9fce70f619c2e91ded1308a1c1802f..8605bc5d33338c91733973c595a95adf411ebabb 100644 (file)
@@ -1,5 +1,7 @@
 class Foo : Object {
        public signal void sig (string s, int i);
+
+       public signal bool sig2 (string s, int i);
 }
 
 void sig_cb (Object o, string s, int i) {
@@ -8,6 +10,13 @@ void sig_cb (Object o, string s, int i) {
        assert (i == 42);
 }
 
+bool sig2_cb (Object o, string s, int i) {
+       success = true;
+       assert (s == "foo");
+       assert (i == 42);
+       return true;
+}
+
 bool success = false;
 
 void main () {
@@ -17,4 +26,10 @@ void main () {
        success = false;
        dfoo.sig.emit ("foo", 42);
        assert (success);
+
+       dfoo.sig2.connect (sig2_cb);
+
+       success = false;
+       assert (dfoo.sig2.emit ("foo", 42));
+       assert (success);
 }
diff --git a/tests/objects/signals-dynamic-invalid-return-type.test b/tests/objects/signals-dynamic-invalid-return-type.test
new file mode 100644 (file)
index 0000000..4c7c1ce
--- /dev/null
@@ -0,0 +1,12 @@
+Invalid Code
+
+class Foo : Object {
+       public signal void sig ();
+}
+
+void main () {
+       var real = new Foo ();
+       dynamic Object foo = real;
+
+       var bar = foo.sig.emit ();
+}
index e249f6fe73c985dd07554f03e695b16a0b321e64..3836abc87ac13c0cc3da3dc62e20051752fae7dd 100644 (file)
@@ -33,6 +33,7 @@ enum  {
 static GParamSpec* foo_properties[FOO_NUM_PROPERTIES];
 enum  {
        FOO_SIG_SIGNAL,
+       FOO_SIG2_SIGNAL,
        FOO_NUM_SIGNALS
 };
 static guint foo_signals[FOO_NUM_SIGNALS] = {0};
@@ -66,15 +67,28 @@ static void g_cclosure_user_marshal_VOID__STRING_INT (GClosure * closure,
                                                const GValue * param_values,
                                                gpointer invocation_hint,
                                                gpointer marshal_data);
+static void g_cclosure_user_marshal_BOOLEAN__STRING_INT (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);
 VALA_EXTERN void sig_cb (GObject* o,
              const gchar* s,
              gint i);
+VALA_EXTERN gboolean sig2_cb (GObject* o,
+                  const gchar* s,
+                  gint i);
 static void _vala_main (void);
 static void _sig_cb_foo_sig (Foo* _sender,
                       const gchar* s,
                       gint i,
                       gpointer self);
+static gboolean _sig2_cb_foo_sig2 (Foo* _sender,
+                            const gchar* s,
+                            gint i,
+                            gpointer self);
 
 void
 foo_fire (Foo* self)
@@ -123,12 +137,42 @@ g_cclosure_user_marshal_VOID__STRING_INT (GClosure * closure,
        callback (data1, g_value_get_string (param_values + 1), g_value_get_int (param_values + 2), data2);
 }
 
+static void
+g_cclosure_user_marshal_BOOLEAN__STRING_INT (GClosure * closure,
+                                             GValue * return_value,
+                                             guint n_param_values,
+                                             const GValue * param_values,
+                                             gpointer invocation_hint,
+                                             gpointer marshal_data)
+{
+       typedef gboolean (*GMarshalFunc_BOOLEAN__STRING_INT) (gpointer data1, const char* arg_1, gint arg_2, gpointer data2);
+       register GMarshalFunc_BOOLEAN__STRING_INT callback;
+       register GCClosure * cc;
+       register gpointer data1;
+       register gpointer data2;
+       gboolean v_return;
+       cc = (GCClosure *) closure;
+       g_return_if_fail (return_value != NULL);
+       g_return_if_fail (n_param_values == 3);
+       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_BOOLEAN__STRING_INT) (marshal_data ? marshal_data : cc->callback);
+       v_return = callback (data1, g_value_get_string (param_values + 1), g_value_get_int (param_values + 2), data2);
+       g_value_set_boolean (return_value, v_return);
+}
+
 static void
 foo_class_init (FooClass * klass,
                 gpointer klass_data)
 {
        foo_parent_class = g_type_class_peek_parent (klass);
        foo_signals[FOO_SIG_SIGNAL] = g_signal_new ("sig", TYPE_FOO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_VOID__STRING_INT, G_TYPE_NONE, 2, G_TYPE_STRING, G_TYPE_INT);
+       foo_signals[FOO_SIG2_SIGNAL] = g_signal_new ("sig2", TYPE_FOO, G_SIGNAL_RUN_LAST, 0, NULL, NULL, g_cclosure_user_marshal_BOOLEAN__STRING_INT, G_TYPE_BOOLEAN, 2, G_TYPE_STRING, G_TYPE_INT);
 }
 
 static void
@@ -170,6 +214,21 @@ sig_cb (GObject* o,
        _vala_assert (i == 42, "i == 42");
 }
 
+gboolean
+sig2_cb (GObject* o,
+         const gchar* s,
+         gint i)
+{
+       gboolean result;
+       g_return_val_if_fail (G_TYPE_CHECK_INSTANCE_TYPE (o, G_TYPE_OBJECT), FALSE);
+       g_return_val_if_fail (s != NULL, FALSE);
+       success = TRUE;
+       _vala_assert (g_strcmp0 (s, "foo") == 0, "s == \"foo\"");
+       _vala_assert (i == 42, "i == 42");
+       result = TRUE;
+       return result;
+}
+
 static void
 _sig_cb_foo_sig (Foo* _sender,
                  const gchar* s,
@@ -179,11 +238,23 @@ _sig_cb_foo_sig (Foo* _sender,
        sig_cb (_sender, s, i);
 }
 
+static gboolean
+_sig2_cb_foo_sig2 (Foo* _sender,
+                   const gchar* s,
+                   gint i,
+                   gpointer self)
+{
+       gboolean result;
+       result = sig2_cb (_sender, s, i);
+       return result;
+}
+
 static void
 _vala_main (void)
 {
        Foo* foo = NULL;
        Foo* _tmp0_;
+       gboolean _tmp1_ = FALSE;
        _tmp0_ = foo_new ();
        foo = _tmp0_;
        g_signal_connect (foo, "sig", (GCallback) _sig_cb_foo_sig, NULL);
@@ -193,6 +264,11 @@ _vala_main (void)
        success = FALSE;
        foo_fire (foo);
        _vala_assert (success, "success");
+       success = FALSE;
+       g_signal_connect (foo, "sig2", (GCallback) _sig2_cb_foo_sig2, NULL);
+       g_signal_emit (foo, foo_signals[FOO_SIG2_SIGNAL], 0, "foo", 42, &_tmp1_);
+       _vala_assert (_tmp1_, "foo.sig2.emit (\"foo\", 42)");
+       _vala_assert (success, "success");
        _g_object_unref0 (foo);
 }
 
index 5b49cae8c6d36148f5eb32de9e58017140317162..5ac682f58fda090f7a22c3906cfdf40f26fa6e65 100644 (file)
@@ -1,6 +1,8 @@
 class Foo : Object {
        public signal void sig (string s, int i);
 
+       public signal bool sig2 (string s, int i);
+
        public void fire () {
                sig.emit ("foo", 42);
        }
@@ -12,6 +14,13 @@ void sig_cb (Object o, string s, int i) {
        assert (i == 42);
 }
 
+bool sig2_cb (Object o, string s, int i) {
+       success = true;
+       assert (s == "foo");
+       assert (i == 42);
+       return true;
+}
+
 bool success = false;
 
 void main () {
@@ -25,4 +34,10 @@ void main () {
        success = false;
        foo.fire ();
        assert (success);
+
+       success = false;
+       foo.sig2.connect (sig2_cb);
+       assert (foo.sig2.emit ("foo", 42));
+       assert (success);
+
 }
index f083da911743057c49a8acef8ea0689432fd6ff0..7ee417a29d3c18c322850e15b7174301ebd6fe87 100644 (file)
@@ -518,7 +518,13 @@ public class Vala.MemberAccess : Expression {
                                                symbol_reference = s;
                                        } else if (ma.member_name == "emit") {
                                                // dynamic signal
-                                               var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
+                                               unowned MethodCall mcall = (MethodCall) ma.parent_node;
+                                               var return_type = mcall.target_type ?? new VoidType ();
+                                               if (return_type is VarType) {
+                                                       error = true;
+                                                       Report.error (mcall.source_reference, "Cannot infer return type for dynamic signal `%s' from given context", member_name);
+                                               }
+                                               var s = new DynamicSignal (inner.value_type, member_name, return_type, source_reference);
                                                s.access = SymbolAccessibility.PUBLIC;
                                                s.add_parameter (new Parameter.with_ellipsis ());
                                                dynamic_object_type.type_symbol.scope.add (null, s);