summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorRico Tzschichholz <ricotz@ubuntu.com>2021-03-02 17:55:25 +0100
committerRico Tzschichholz <ricotz@ubuntu.com>2021-03-06 21:49:38 +0000
commit539b1e296a7d17d046774664f8088804b0b31b59 (patch)
tree25d05b503d35ae2af883716b350079b484a3ebd6
parent99ba32dab8d0b05c47801bc95572f40e07e4afc3 (diff)
downloadvala-wip/issue/160.tar.gz
vala: Support variadic delegates including params arraywip/issue/160
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
-rw-r--r--codegen/valaccodedelegatemodule.vala6
-rw-r--r--tests/Makefile.am3
-rw-r--r--tests/delegates/params-array-with-throws.vala35
-rw-r--r--tests/delegates/params-array.vala72
-rw-r--r--tests/delegates/variadic.vala74
-rw-r--r--vala/valadelegate.vala11
-rw-r--r--vala/valadelegatetype.vala9
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;
}