Commit 013bb64c authored by Rico Tzschichholz's avatar Rico Tzschichholz

codegen: Handle non-default AsyncResult parameter position

Unfortunately gdbus-codegen puts the AsyncResult parameter after possible
out-parameters therefore there is an "async_result_pos" attribute required
to handle this correctly.

Vala supposely follows the common practice to put the AsyncResult before
out-parameters by default.

Fixes GNOME/vala#709
parent 3763b4c6
......@@ -380,6 +380,11 @@ namespace Vala {
return get_ccode_attribute(m).vfunc_name;
}
public static double get_ccode_async_result_pos (Method m) {
assert (m.coroutine);
return m.get_attribute_double ("CCode", "async_result_pos", 0.1);
}
public static string get_ccode_finish_name (Method m) {
return get_ccode_attribute(m).finish_name;
}
......
......@@ -4835,7 +4835,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
// output arguments used separately
out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
// pass GAsyncResult stored in closure to finish function
out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
}
if (cl != null && !cl.is_compact) {
......
......@@ -129,7 +129,7 @@ public class Vala.CCodeMethodCallModule : CCodeAssignmentModule {
// output arguments used separately
out_arg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
// pass GAsyncResult stored in closure to finish function
out_arg_map.set (get_param_pos (0.1), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
out_arg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeMemberAccess.pointer (new CCodeIdentifier ("_data_"), "_res_"));
}
}
......
......@@ -586,7 +586,7 @@ public class Vala.GAsyncModule : GtkModule {
var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
generate_cparameters (m, cfile, cparam_map, finishfunc, null, null, null, 2);
......@@ -832,9 +832,9 @@ public class Vala.GAsyncModule : GtkModule {
carg_map.set (get_param_pos (-0.9), new CCodeIdentifier ("_user_data_"));
}
} else if (direction == 2) {
cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
if (carg_map != null) {
carg_map.set (get_param_pos (0.1), new CCodeIdentifier ("_res_"));
carg_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeIdentifier ("_res_"));
}
}
}
......
......@@ -936,7 +936,7 @@ public class Vala.GDBusClientModule : GDBusModule {
var cparam_map = new HashMap<int,CCodeParameter> (direct_hash, direct_equal);
cparam_map.set (get_param_pos (0.1), new CCodeParameter ("_res_", "GAsyncResult*"));
cparam_map.set (get_param_pos (get_ccode_async_result_pos (m)), new CCodeParameter ("_res_", "GAsyncResult*"));
generate_cparameters (m, cfile, cparam_map, function, null, null, null, 2);
......
......@@ -403,6 +403,7 @@ TESTS = \
asynchronous/bug793158.vala \
asynchronous/closures.vala \
asynchronous/generator.vala \
asynchronous/result-pos.vala \
asynchronous/yield.vala \
generics/bug640330.test \
generics/bug640330.vala \
......@@ -434,6 +435,7 @@ TESTS = \
gir/bug788775.test \
gir/bug792998.test \
gir/array-fixed-length.test \
gir/async-result-pos.test \
gir/class.test \
gir/delegate-alias-without-target.test \
gir/delegate-closure-destroy-index-conflict.test \
......
[CCode (async_result_pos = 2.1)]
async void foo (int in_i, out int out_i) {
out_i = in_i;
}
[CCode (async_result_pos = 2.1)]
async void bar (int in_i, out int out_i) throws Error {
out_i = in_i;
}
async void run () {
int i;
yield foo (323, out i);
assert (i == 323);
try {
yield bar (742, out i);
assert (i == 742);
} catch {
assert_not_reached ();
}
loop.quit ();
}
MainLoop loop;
void main () {
loop = new MainLoop ();
foo.begin (23, (o,r) => {
int i;
foo.end (r, out i);
assert (i == 23);
});
bar.begin (42, (o,r) => {
try {
int i;
bar.end (r, out i);
assert (i == 42);
} catch {
assert_not_reached ();
}
});
run.begin ();
loop.run ();
}
GIR
Input:
<class name="Foo" c:type="TestFoo" glib:type-name="TestFoo" glib:get-type="test_foo_get_type" glib:type-struct="FooClass" parent="GObject.Object">
<method name="method_async" c:identifier="test_foo_method_async">
<return-value transfer-ownership="none">
<type name="none"/>
</return-value>
<parameters>
<instance-parameter name="self" transfer-ownership="none">
<type name="Foo" c:type="TestFoo*"/>
</instance-parameter>
<parameter name="input" transfer-ownership="none">
<type name="utf8" c:type="const gchar*"/>
</parameter>
<parameter name="_callback_" transfer-ownership="none" allow-none="1" closure="2" scope="async">
<type name="Gio.AsyncReadyCallback" c:type="GAsyncReadyCallback"/>
</parameter>
<parameter name="_callback__target" transfer-ownership="none" allow-none="1">
<type name="gpointer" c:type="void*"/>
</parameter>
</parameters>
</method>
<method name="method_finish" c:identifier="test_foo_method_finish" throws="1">
<return-value transfer-ownership="full">
<type name="none"/>
</return-value>
<parameters>
<instance-parameter name="self" transfer-ownership="none">
<type name="Foo" c:type="TestFoo*"/>
</instance-parameter>
<parameter name="output" direction="out" transfer-ownership="full">
<type name="utf8" c:type="gchar**"/>
</parameter>
<parameter name="_res_" transfer-ownership="none">
<type name="Gio.AsyncResult" c:type="GAsyncResult*"/>
</parameter>
</parameters>
</method>
<constructor name="new" c:identifier="test_foo_new">
<return-value transfer-ownership="full">
<type name="Test.Foo" c:type="TestFoo*"/>
</return-value>
</constructor>
</class>
Output:
[CCode (cheader_filename = "test.h", type_id = "test_foo_get_type ()")]
public class Foo : GLib.Object {
[CCode (has_construct_function = false)]
public Foo ();
[CCode (async_result_pos = 2.1)]
public async void method_async (string input, out string output) throws GLib.Error;
}
......@@ -3854,6 +3854,7 @@ public class Vala.GirParser : CodeVisitor {
int i = 0, j=1;
int first_out = -1;
int last = -1;
foreach (ParameterInfo info in parameters) {
if (s is Delegate && info.closure_idx == i) {
......@@ -3885,6 +3886,16 @@ public class Vala.GirParser : CodeVisitor {
// hidden parameters at the end of the parameter list
info.vala_idx = (j - 1) + (i - last) * 0.1F;
}
if (first_out < 0 && info.param.direction == ParameterDirection.OUT) {
first_out = i;
}
if (s is Method && first_out >= 0 && info.param.variable_type != null) {
var type_name = info.param.variable_type.to_string ();
if (type_name == "GLib.AsyncResult" || type_name == "Gio.AsyncResult") {
var shift = ((Method) s).binding == MemberBinding.INSTANCE ? 1.1 : 0.1;
s.set_attribute_double ("CCode", "async_result_pos", i + shift);
}
}
i++;
}
......@@ -4124,6 +4135,8 @@ public class Vala.GirParser : CodeVisitor {
}
}
method.copy_attribute_double (finish_method, "CCode", "async_result_pos");
foreach (var param in finish_method.get_parameters ()) {
if (param.direction == ParameterDirection.OUT) {
var async_param = param.copy ();
......
......@@ -1061,6 +1061,7 @@ public class Vala.Method : Subroutine, Callable {
foreach (var param in get_type_parameters ()) {
end_method.add_type_parameter (param);
}
end_method.copy_attribute_double (this, "CCode", "async_result_pos");
}
return end_method;
}
......@@ -1125,7 +1126,7 @@ public class Vala.Method : Subroutine, Callable {
var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
var result_param = new Parameter ("_res_", result_type);
result_param.set_attribute_double ("CCode", "pos", 0.1);
result_param.set_attribute_double ("CCode", "pos", get_attribute_double ("CCode", "async_result_pos", 0.1));
params.add (result_param);
foreach (var param in parameters) {
......
......@@ -40,7 +40,7 @@ public class Vala.UsedAttr : CodeVisitor {
"array_length_type", "array_length", "array_length_cname", "array_length_cexpr", "array_null_terminated",
"vfunc_name", "finish_vfunc_name", "finish_name", "free_function_address_of", "pos", "delegate_target", "delegate_target_cname",
"array_length_pos", "delegate_target_pos", "destroy_notify_pos", "ctype", "has_new_function", "notify", "finish_instance",
"use_inplace", "feature_test_macro", "default_value_on_error", "",
"use_inplace", "feature_test_macro", "default_value_on_error", "async_result_pos", "",
"Immutable", "",
"SingleInstance", "",
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment