[vala/staging] vala: Add support to infer return type of dynamic signals



commit 3e38dc450eb5a1ebf1dd5d1b88ae69f660097429
Author: Lorenz Wildberg <lorenz wild-fisch de>
Date:   Wed Dec 8 18:41:39 2021 +0000

    vala: Add support to infer return type of dynamic signals

 codegen/valaccodemethodcallmodule.vala             |  6 +-
 tests/Makefile.am                                  |  1 +
 tests/objects/signals-dynamic-emit.c-expected      | 76 ++++++++++++++++++++++
 tests/objects/signals-dynamic-emit.vala            | 15 +++++
 .../signals-dynamic-invalid-return-type.test       | 12 ++++
 tests/objects/signals-emit.c-expected              | 76 ++++++++++++++++++++++
 tests/objects/signals-emit.vala                    | 15 +++++
 vala/valamemberaccess.vala                         |  8 ++-
 8 files changed, 207 insertions(+), 2 deletions(-)
---
diff --git a/codegen/valaccodemethodcallmodule.vala b/codegen/valaccodemethodcallmodule.vala
index d7827741b..6332271ad 100644
--- a/codegen/valaccodemethodcallmodule.vala
+++ b/codegen/valaccodemethodcallmodule.vala
@@ -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) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 2103afa6e..0b9f71524 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -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 \
diff --git a/tests/objects/signals-dynamic-emit.c-expected b/tests/objects/signals-dynamic-emit.c-expected
index 5b04c9bbb..7c71e3b42 100644
--- a/tests/objects/signals-dynamic-emit.c-expected
+++ b/tests/objects/signals-dynamic-emit.c-expected
@@ -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);
 }
 
diff --git a/tests/objects/signals-dynamic-emit.vala b/tests/objects/signals-dynamic-emit.vala
index 55d6fac98..8605bc5d3 100644
--- a/tests/objects/signals-dynamic-emit.vala
+++ b/tests/objects/signals-dynamic-emit.vala
@@ -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
index 000000000..4c7c1ceef
--- /dev/null
+++ b/tests/objects/signals-dynamic-invalid-return-type.test
@@ -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 ();
+}
diff --git a/tests/objects/signals-emit.c-expected b/tests/objects/signals-emit.c-expected
index e249f6fe7..3836abc87 100644
--- a/tests/objects/signals-emit.c-expected
+++ b/tests/objects/signals-emit.c-expected
@@ -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);
 }
 
diff --git a/tests/objects/signals-emit.vala b/tests/objects/signals-emit.vala
index 5b49cae8c..5ac682f58 100644
--- a/tests/objects/signals-emit.vala
+++ b/tests/objects/signals-emit.vala
@@ -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);
+
 }
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index f083da911..7ee417a29 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -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);


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