[vala/wip/issue/160: 10/10] vala: Support variadic delegates including params array




commit 539b1e296a7d17d046774664f8088804b0b31b59
Author: Rico Tzschichholz <ricotz ubuntu com>
Date:   Tue Mar 2 17:55:25 2021 +0100

    vala: Support variadic delegates including params array
    
    There can't be a generated wrapper to mitigate possible differences,
    therefore the signatures must perfectly match and an explicit cast is
    required.
    
    Fixes https://gitlab.gnome.org/GNOME/vala/issues/160

 codegen/valaccodedelegatemodule.vala          |  6 ++-
 tests/Makefile.am                             |  3 ++
 tests/delegates/params-array-with-throws.vala | 35 +++++++++++++
 tests/delegates/params-array.vala             | 72 ++++++++++++++++++++++++++
 tests/delegates/variadic.vala                 | 74 +++++++++++++++++++++++++++
 vala/valadelegate.vala                        | 11 +++-
 vala/valadelegatetype.vala                    |  9 +++-
 7 files changed, 207 insertions(+), 3 deletions(-)
---
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index dd3e0fcf6..4da3d4374 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -162,7 +162,11 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
                                method = method.base_interface_method;
                        }
 
-                       return new CCodeIdentifier (generate_delegate_wrapper (method, dt, node));
+                       if (method.is_variadic ()) {
+                               Report.warning (node.source_reference, "internal: Varidic method requires a 
direct cast to delegate");
+                       } else {
+                               return new CCodeIdentifier (generate_delegate_wrapper (method, dt, node));
+                       }
                }
 
                return base.get_implicit_cast_expression (source_cexpr, expression_type, target_type, node);
diff --git a/tests/Makefile.am b/tests/Makefile.am
index a74714d9e..99cfa709b 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -394,8 +394,11 @@ TESTS = \
        delegates/lambda-mixed-instance-static.vala \
        delegates/lambda-shared-closure.vala \
        delegates/member-target-destroy.vala \
+       delegates/params-array.vala \
+       delegates/params-array-with-throws.vala \
        delegates/reference_transfer.vala \
        delegates/return-array-null-terminated.vala \
+       delegates/variadic.vala \
        delegates/wrapper.vala \
        delegates/bug519949.test \
        delegates/bug539166.vala \
diff --git a/tests/delegates/params-array-with-throws.vala b/tests/delegates/params-array-with-throws.vala
new file mode 100644
index 000000000..aad013416
--- /dev/null
+++ b/tests/delegates/params-array-with-throws.vala
@@ -0,0 +1,35 @@
+errordomain FooError {
+       BAD,
+       WORSE
+}
+
+[CCode (has_target = false)]
+delegate void FooFunc (params string[] array) throws FooError;
+
+void foo (params string[] array) throws FooError {
+       assert (array.length == 3);
+       assert (array[0] == "foo");
+       assert (array[1] == "bar");
+       assert (array[2] == "manam");
+}
+
+void bar (params string[] array) throws FooError {
+       throw new FooError.BAD ("bad");
+}
+
+void main () {
+       {
+               FooFunc func = foo;
+               func ("foo", "bar", "manam");
+       }
+       {
+               FooFunc func = bar;
+               try {
+                       func ("foo", "bar", "manam");
+                       assert_not_reached ();
+               } catch (FooError.BAD e) {
+               } catch {
+                       assert_not_reached ();
+               }
+       }
+}
diff --git a/tests/delegates/params-array.vala b/tests/delegates/params-array.vala
new file mode 100644
index 000000000..d71b14547
--- /dev/null
+++ b/tests/delegates/params-array.vala
@@ -0,0 +1,72 @@
+[CCode (has_target = false)]
+delegate void FooFunc (params string[] strv);
+
+void foo (params string[] strv) {
+       assert (strv.length == 3);
+       assert (strv[0] == "foo");
+       assert (strv[1] == "bar");
+       assert (strv[2] == "manam");
+}
+
+[CCode (has_target = false)]
+delegate void BarFunc (params int[] intv);
+
+void bar (params int[] intv) {
+       assert (intv.length == 3);
+       assert (intv[0] == 23);
+       assert (intv[1] == 42);
+       assert (intv[2] == 4711);
+}
+
+[CCode (has_target = false)]
+delegate void ManamFunc (params Value?[] valuev);
+
+void manam (params Value?[] valuev) {
+       assert (valuev.length == 3);
+       assert (valuev[0] == "foo");
+       assert (valuev[1] == 4711);
+       assert (valuev[2] == 3.1415);
+}
+
+[CCode (has_target = false)]
+delegate void ManamOwnedFunc (params owned Value?[] valuev);
+
+void manam_owned (params owned Value?[] valuev) {
+       assert (valuev.length == 3);
+       assert (valuev[0] == "foo");
+       assert (valuev[1] == 4711);
+       assert (valuev[2] == 3.1415);
+}
+
+[CCode (has_target = false)]
+delegate void MinimFunc (params Variant[] variantv);
+
+void minim (params Variant[] variantv) {
+       assert (variantv.length == 3);
+       assert ((string) variantv[0] == "foo");
+       assert ((int) variantv[1] == 4711);
+       assert ((double) variantv[2] == 3.1415);
+}
+
+void main () {
+       {
+               FooFunc func = foo;
+               func ("foo", "bar", "manam");
+       }
+       {
+               BarFunc func = bar;
+               func (23, 42, 4711);
+       }
+       {
+               ManamFunc func = manam;
+               func ("foo", 4711, 3.1415);
+       }
+       {
+               ManamOwnedFunc func = manam_owned;
+               func ("foo", 4711, 3.1415);
+       }
+       {
+               MinimFunc func = minim;
+               func ("foo", 4711, 3.1415);
+       }
+}
diff --git a/tests/delegates/variadic.vala b/tests/delegates/variadic.vala
new file mode 100644
index 000000000..b96fb62b0
--- /dev/null
+++ b/tests/delegates/variadic.vala
@@ -0,0 +1,74 @@
+[CCode (has_target = false)]
+delegate void FooFunc (string first, ...);
+
+[CCode (has_target = false)]
+delegate void BarFunc (string first, ...);
+
+errordomain BazError {
+       BAD,
+       WORSE
+}
+
+[CCode (has_target = false)]
+delegate void BazFunc (string first, ...) throws BazError;
+
+void foo (string first, ...) {
+       assert (first == "foo");
+       va_list args = va_list ();
+       int i = args.arg<int> ();
+       assert (i == 42);
+       string s = args.arg<string> ();
+       assert (s == "bar");
+}
+
+void baz (string first, ...) throws BazError {
+       assert (first == "baz");
+       va_list args = va_list ();
+       int i = args.arg<int> ();
+       assert (i == 23);
+       string s = args.arg<string> ();
+       assert (s == "bar");
+}
+
+void baz_fail (string first, ...) throws BazError {
+       throw new BazError.BAD ("bad");
+}
+
+void mamam (FooFunc func) {
+       func ("foo", 42, "bar");
+}
+
+void main () {
+       {
+               FooFunc func = foo;
+               func ("foo", 42, "bar");
+       }
+       {
+               FooFunc func = foo;
+               BarFunc f = func;
+       }
+       {
+               FooFunc func = (FooFunc) foo;
+               BarFunc f = (BarFunc) func;
+       }
+       {
+               BazFunc func = baz;
+               func ("baz", 23, "bar");
+       }
+       {
+               BazFunc func = baz_fail;
+               try {
+                       func ("baz", 23, "bar");
+                       assert_not_reached ();
+               } catch (BazError.BAD e) {
+               } catch {
+                       assert_not_reached ();
+               }
+       }
+       {
+               mamam (foo);
+       }
+       {
+               mamam ((FooFunc) foo);
+       }
+}
diff --git a/vala/valadelegate.vala b/vala/valadelegate.vala
index 83a3415dc..9b590ca47 100644
--- a/vala/valadelegate.vala
+++ b/vala/valadelegate.vala
@@ -165,6 +165,7 @@ public class Vala.Delegate : TypeSymbol, Callable {
 
                bool first = true;
                foreach (Parameter param in parameters) {
+                       Parameter? method_param = null;
                        DataType method_param_type;
                        /* use first callback parameter as instance parameter if
                         * an instance method is being compared to a static
@@ -178,7 +179,15 @@ public class Vala.Delegate : TypeSymbol, Callable {
                                if (!method_params_it.next ()) {
                                        break;
                                }
-                               method_param_type = method_params_it.get ().variable_type;
+                               method_param = method_params_it.get ();
+                               method_param_type = method_param.variable_type;
+                       }
+
+                       if (method_param != null && (param.ellipsis || param.params_array)) {
+                               if (param.ellipsis != method_param.ellipsis || param.params_array != 
method_param.params_array) {
+                                       return false;
+                               }
+                               break;
                        }
 
                        // method is allowed to accept arguments of looser types (weaker precondition)
diff --git a/vala/valadelegatetype.vala b/vala/valadelegatetype.vala
index 4029f00af..d7b9fc126 100644
--- a/vala/valadelegatetype.vala
+++ b/vala/valadelegatetype.vala
@@ -160,8 +160,15 @@ public class Vala.DelegateType : CallableType {
                                return false;
                        }
 
-                       // target-delegate is allowed to accept arguments of looser types (weaker 
precondition)
                        var p = params_it.get ();
+                       if (p != null && (param.ellipsis || param.params_array)) {
+                               if (param.ellipsis != p.ellipsis || param.params_array != p.params_array) {
+                                       return false;
+                               }
+                               break;
+                       }
+
+                       // target-delegate is allowed to accept arguments of looser types (weaker 
precondition)
                        if (!param.variable_type.get_actual_type (this, null, this).stricter 
(p.variable_type)) {
                                return false;
                        }


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