From: Rico Tzschichholz Date: Tue, 2 Mar 2021 16:55:25 +0000 (+0100) Subject: Add support for variadic delegates X-Git-Tag: 0.53.1~72 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=463c6328a20325234134e041d24c10c85360ad60;p=thirdparty%2Fvala.git Add support for variadic delegates 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 --- diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala index dc54d636c..64ad460c3 100644 --- a/codegen/valaccodedelegatemodule.vala +++ b/codegen/valaccodedelegatemodule.vala @@ -168,7 +168,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: Variadic 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 998ca62da..fae0ebe81 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -403,8 +403,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 (); + assert (i == 42); + string s = args.arg (); + assert (s == "bar"); +} + +void baz (string first, ...) throws BazError { + assert (first == "baz"); + va_list args = va_list (); + int i = args.arg (); + assert (i == 23); + string s = args.arg (); + 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 9821a9e70..e23eb15a1 100644 --- a/vala/valadelegatetype.vala +++ b/vala/valadelegatetype.vala @@ -146,8 +146,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; }