From: Rico Tzschichholz Date: Tue, 5 Jun 2018 09:05:09 +0000 (+0200) Subject: Handle synchronous out-parameters in async methods X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=refs%2Fheads%2Fwip%2Fasync-out;p=thirdparty%2Fvala.git Handle synchronous out-parameters in async methods Although setting them is not supported yet. Fixes https://gitlab.gnome.org/GNOME/vala/issues/636 --- diff --git a/codegen/valaccodeassignmentmodule.vala b/codegen/valaccodeassignmentmodule.vala index c8f24383e..4f9552443 100644 --- a/codegen/valaccodeassignmentmodule.vala +++ b/codegen/valaccodeassignmentmodule.vala @@ -183,6 +183,11 @@ public class Vala.CCodeAssignmentModule : CCodeMemberAccessModule { bool capturing_parameter_in_coroutine = capturing_parameter && is_in_coroutine (); + if (capturing_parameter_in_coroutine && param.sync_arg) { + Report.error (source_reference, "Assigning synchronous out-parameters of async methods is not supported yet."); + return; + } + var param_type = param.variable_type.copy (); if (param.captured || is_in_coroutine ()) { if (!param_type.value_owned && !no_implicit_copy (param_type)) { diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index 9147a5fa0..e93d3e795 100644 --- a/codegen/valaccodebasemodule.vala +++ b/codegen/valaccodebasemodule.vala @@ -4767,7 +4767,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator { param = params_it.get (); ellipsis = param.ellipsis; if (!ellipsis) { - if (param.direction == ParameterDirection.OUT) { + if (param.direction == ParameterDirection.OUT && !param.sync_arg) { carg_map = out_arg_map; } diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala index 66e3ad1a7..3a02aa386 100644 --- a/codegen/valaccodemethodmodule.vala +++ b/codegen/valaccodemethodmodule.vala @@ -1015,12 +1015,12 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule { CCodeParameter? prev_cparam = null; foreach (Parameter param in m.get_parameters ()) { - if (param.direction != ParameterDirection.OUT) { + if (param.direction != ParameterDirection.OUT || param.sync_arg) { if ((direction & 1) == 0) { // no in parameters continue; } - } else { + } else if (!param.sync_arg) { if ((direction & 2) == 0) { // no out parameters continue; diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala index 715c35f56..306438113 100644 --- a/codegen/valagasyncmodule.vala +++ b/codegen/valagasyncmodule.vala @@ -51,6 +51,10 @@ public class Vala.GAsyncModule : GtkModule { } foreach (Parameter param in m.get_parameters ()) { + if (param.direction == ParameterDirection.OUT && param.sync_arg) { + continue; + } + bool is_unowned_delegate = param.variable_type is DelegateType && !param.variable_type.value_owned; var param_type = param.variable_type.copy (); @@ -645,7 +649,7 @@ public class Vala.GAsyncModule : GtkModule { emit_context.push_symbol (m); foreach (Parameter param in m.get_parameters ()) { - if (param.direction != ParameterDirection.IN) { + if (param.direction != ParameterDirection.IN && !param.sync_arg) { return_out_parameter (param); if (!(param.variable_type is ValueType) || param.variable_type.nullable) { ccode.add_assignment (new CCodeMemberAccess.pointer (data_var, get_variable_cname (param.name)), new CCodeConstant ("NULL")); diff --git a/tests/Makefile.am b/tests/Makefile.am index c05a68d51..a4179f055 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -363,6 +363,7 @@ TESTS = \ asynchronous/bug793158.vala \ asynchronous/closures.vala \ asynchronous/generator.vala \ + asynchronous/sync-args.vala \ asynchronous/yield.vala \ generics/bug694765-1.vala \ generics/bug694765-2.vala \ diff --git a/tests/asynchronous/sync-args.vala b/tests/asynchronous/sync-args.vala new file mode 100644 index 000000000..8f4f49c62 --- /dev/null +++ b/tests/asynchronous/sync-args.vala @@ -0,0 +1,44 @@ +public interface IFoo : Object { + public abstract async string ifunc (int i, out int out_j, string s) throws Error; +} + +public class Foo : Object, IFoo { + public async string ifunc (int i, out int out_j, string s) throws Error { + assert (i == 23); + assert (s == "ifoo"); + return "result_ifoo"; + } + + public virtual async string vfunc (int i, out int out_j, string s) throws Error { + assert (i == 42); + assert (s == "vfoo"); + return "result_vfoo"; + } + + public async string func (int i, string s, [SyncArg] out int out_j) throws Error { + assert (i == 4711); + assert (s == "foo"); + return "result_foo"; + } +} + +async void run () { + var foo = new Foo (); + int i; + foo.ifunc.begin (23, out i, "ifoo", (o, r) => { + var result = ((Foo) o).ifunc.end (r); + assert (result == "result_ifoo"); + }); + foo.vfunc.begin (42, out i, "vfoo", (o, r) => { + var result = ((Foo) o).ifunc.end (r); + assert (result == "result_vfoo"); + }); + foo.func.begin (4711, "foo", out i, (o, r) => { + var result = ((Foo) o).ifunc.end (r); + assert (result == "result_foo"); + }); +} + +void main () { + run.begin (); +} diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala index 95ad5c9d2..a6eb05900 100644 --- a/vala/valagirparser.vala +++ b/vala/valagirparser.vala @@ -4049,6 +4049,23 @@ public class Vala.GirParser : CodeVisitor { Method method = m; + if (m.coroutine) { + var parameters = m.get_parameters (); + bool requires_explicit_attribute = true; + for (int i = parameters.size - 1; i >= 0; i--) { + var param = parameters[i]; + if (param.direction == ParameterDirection.IN) { + requires_explicit_attribute = false; + } else { + param.sync_arg = true; + if (requires_explicit_attribute) { + param.set_attribute ("SyncArg", true); + requires_explicit_attribute = false; + } + } + } + } + if (finish_method_node != null && finish_method_node.symbol is Method) { finish_method_node.process (this); var finish_method = (Method) finish_method_node.symbol; diff --git a/vala/valamethod.vala b/vala/valamethod.vala index e6d9fb590..d71e3dcb7 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -728,6 +728,19 @@ public class Vala.Method : Subroutine, Callable { Report.error (parameters[0].source_reference, "Named parameter required before `...'"); } + // implicitly mark synchronous out-parameter as such + if (coroutine) { + bool requires_attribute = false; + for (int i = parameters.size - 1; i >= 0; i--) { + var param = parameters[i]; + if (param.direction == ParameterDirection.IN) { + requires_attribute = true; + } else if (requires_attribute) { + param.sync_arg = true; + } + } + } + var optional_param = false; foreach (Parameter param in parameters) { param.check (context); @@ -1042,7 +1055,7 @@ public class Vala.Method : Subroutine, Callable { foreach (var param in parameters) { if (param.ellipsis) { ellipsis = param; - } else if (param.direction == ParameterDirection.IN) { + } else if (param.direction == ParameterDirection.IN || param.sync_arg) { params.add (param); } } @@ -1080,7 +1093,7 @@ public class Vala.Method : Subroutine, Callable { params.add (result_param); foreach (var param in parameters) { - if (param.direction == ParameterDirection.OUT) { + if (param.direction == ParameterDirection.OUT && !param.sync_arg) { params.add (param); } } diff --git a/vala/valaparameter.vala b/vala/valaparameter.vala index bfc340bc5..76f234f45 100644 --- a/vala/valaparameter.vala +++ b/vala/valaparameter.vala @@ -50,11 +50,28 @@ public class Vala.Parameter : Variable { } } + public bool sync_arg { + get { + return _sync_arg || get_attribute ("SyncArg") != null || (base_parameter != null && base_parameter.sync_arg); + } + set { + if (!value) { + set_attribute ("SyncArg", false); + _sync_arg = false; + } else if (direction != ParameterDirection.IN) { + _sync_arg = true; + } + } + } + /** * The base parameter of this parameter relative to the base method. */ public Parameter base_parameter { get; set; } + + bool _sync_arg = false; + /** * Creates a new formal parameter. * diff --git a/vala/valausedattr.vala b/vala/valausedattr.vala index 999cfc867..276498914 100644 --- a/vala/valausedattr.vala +++ b/vala/valausedattr.vala @@ -74,6 +74,7 @@ public class Vala.UsedAttr : CodeVisitor { "PrintfFormat", "", "ScanfFormat", "", "FormatArg", "", + "SyncArg", "", "GtkChild", "name", "internal", "", "GtkTemplate", "ui", "",