Use strict non-null types with --enable-experimental-non-null
[vala-lang.git] / vala / valamethod.vala
blob731e9d6537415f2e60c2cd8eec5652453ebacee4
1 /* valamethod.vala
3 * Copyright (C) 2006-2009 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * Represents a type or namespace method.
30 public class Vala.Method : Member {
31 List<TypeParameter> type_parameters = new ArrayList<TypeParameter> ();
33 public const string DEFAULT_SENTINEL = "NULL";
35 /**
36 * The return type of this method.
38 public DataType return_type {
39 get { return _return_type; }
40 set {
41 _return_type = value;
42 _return_type.parent_node = this;
46 public Block body {
47 get { return _body; }
48 set {
49 _body = value;
50 if (_body != null) {
51 _body.owner = scope;
56 public BasicBlock entry_block { get; set; }
58 public BasicBlock exit_block { get; set; }
60 /**
61 * Specifies whether this method may only be called with an instance of
62 * the contained type.
64 public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
66 /**
67 * The name of the vfunc of this method as it is used in C code.
69 public string vfunc_name {
70 get {
71 if (_vfunc_name == null) {
72 _vfunc_name = this.name;
74 return _vfunc_name;
76 set {
77 _vfunc_name = value;
81 /**
82 * The sentinel to use for terminating variable length argument lists.
84 public string sentinel {
85 get {
86 if (_sentinel == null) {
87 return DEFAULT_SENTINEL;
90 return _sentinel;
93 set {
94 _sentinel = value;
98 /**
99 * Specifies whether this method is abstract. Abstract methods have no
100 * body, may only be specified within abstract classes, and must be
101 * overriden by derived non-abstract classes.
103 public bool is_abstract { get; set; }
106 * Specifies whether this method is virtual. Virtual methods may be
107 * overridden by derived classes.
109 public bool is_virtual { get; set; }
112 * Specifies whether this method overrides a virtual or abstract method
113 * of a base type.
115 public bool overrides { get; set; }
118 * Specifies whether this method should be inlined.
120 public bool is_inline { get; set; }
123 * Specifies whether the C method returns a new instance pointer which
124 * may be different from the previous instance pointer. Only valid for
125 * imported methods.
127 public bool returns_modified_pointer { get; set; }
130 * Specifies the virtual or abstract method this method overrides.
131 * Reference must be weak as virtual and abstract methods set
132 * base_method to themselves.
134 public Method base_method {
135 get {
136 find_base_methods ();
137 return _base_method;
142 * Specifies the abstract interface method this method implements.
144 public Method base_interface_method {
145 get {
146 find_base_methods ();
147 return _base_interface_method;
151 public bool entry_point { get; private set; }
154 * Specifies the generated `this' parameter for instance methods.
156 public FormalParameter this_parameter { get; set; }
159 * Specifies the generated `result' variable for postconditions.
161 public LocalVariable result_var { get; set; }
164 * Specifies the position of the instance parameter in the C function.
166 public double cinstance_parameter_position { get; set; }
169 * Specifies the position of the array length out parameter in the C
170 * function.
172 public double carray_length_parameter_position { get; set; }
175 * Specifies the position of the delegate target out parameter in the C
176 * function.
178 public double cdelegate_target_parameter_position { get; set; }
181 * Specifies whether the array length should be returned implicitly
182 * if the return type is an array.
184 public bool no_array_length { get; set; }
187 * Specifies whether the array is null terminated.
189 public bool array_null_terminated { get; set; }
192 * Specified a custom type for the array length parameter.
194 public string? array_length_type { get; set; default = null; }
197 * Specifies whether this method expects printf-style format arguments.
199 public bool printf_format { get; set; }
202 * Specifies whether this method expects scanf-style format arguments.
204 public bool scanf_format { get; set; }
207 * Specifies whether a new function without a GType parameter is
208 * available. This is only applicable to creation methods.
210 public bool has_new_function { get; set; default = true; }
213 * Specifies whether a construct function with a GType parameter is
214 * available. This is only applicable to creation methods.
216 public bool has_construct_function { get; set; default = true; }
218 public bool has_generic_type_parameter { get; set; }
220 public double generic_type_parameter_position { get; set; }
222 public weak Signal signal_reference { get; set; }
224 public bool closure { get; set; }
226 public bool coroutine { get; set; }
228 public bool is_async_callback { get; set; }
230 private List<FormalParameter> parameters = new ArrayList<FormalParameter> ();
231 private string cname;
232 private string _vfunc_name;
233 private string _sentinel;
234 private List<Expression> preconditions = new ArrayList<Expression> ();
235 private List<Expression> postconditions = new ArrayList<Expression> ();
236 private DataType _return_type;
237 private Block _body;
239 private weak Method _base_method;
240 private Method _base_interface_method;
241 private bool base_methods_valid;
243 Method? callback_method;
245 // only valid for closures
246 List<LocalVariable> captured_variables;
249 * Creates a new method.
251 * @param name method name
252 * @param return_type method return type
253 * @param source reference to source code
254 * @return newly created method
256 public Method (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
257 base (name, source_reference, comment);
258 this.return_type = return_type;
260 carray_length_parameter_position = -3;
261 cdelegate_target_parameter_position = -3;
265 * Appends parameter to this method.
267 * @param param a formal parameter
269 public void add_parameter (FormalParameter param) {
270 // default C parameter position
271 param.cparameter_position = parameters.size + 1;
272 param.carray_length_parameter_position = param.cparameter_position + 0.1;
273 param.cdelegate_target_parameter_position = param.cparameter_position + 0.1;
275 parameters.add (param);
276 if (!param.ellipsis) {
277 scope.add (param.name, param);
281 public List<FormalParameter> get_parameters () {
282 return new ReadOnlyList<FormalParameter> (parameters);
286 * Remove all parameters from this method.
288 public void clear_parameters () {
289 foreach (FormalParameter param in parameters) {
290 if (!param.ellipsis) {
291 scope.remove (param.name);
294 parameters.clear ();
297 public override void accept (CodeVisitor visitor) {
298 visitor.visit_method (this);
301 public override void accept_children (CodeVisitor visitor) {
302 foreach (TypeParameter p in get_type_parameters ()) {
303 p.accept (visitor);
306 if (return_type != null) {
307 return_type.accept (visitor);
310 foreach (FormalParameter param in parameters) {
311 param.accept (visitor);
314 foreach (DataType error_type in get_error_types ()) {
315 error_type.accept (visitor);
318 if (result_var != null) {
319 result_var.accept (visitor);
322 foreach (Expression precondition in preconditions) {
323 precondition.accept (visitor);
326 foreach (Expression postcondition in postconditions) {
327 postcondition.accept (visitor);
330 if (body != null) {
331 body.accept (visitor);
336 * Returns the interface name of this method as it is used in C code.
338 * @return the name to be used in C code
340 public string get_cname () {
341 if (cname == null) {
342 cname = get_default_cname ();
344 return cname;
347 public string get_finish_cname () {
348 assert (coroutine);
349 string result = get_cname ();
350 if (result.has_suffix ("_async")) {
351 result = result.substring (0, result.length - "_async".length);
353 result += "_finish";
354 return result;
358 * Returns the default interface name of this method as it is used in C
359 * code.
361 * @return the name to be used in C code by default
363 public virtual string get_default_cname () {
364 if (name == "main" && parent_symbol.name == null) {
365 // avoid conflict with generated main function
366 return "_main";
367 } else if (name.has_prefix ("_")) {
368 return "_%s%s".printf (parent_symbol.get_lower_case_cprefix (), name.offset (1));
369 } else {
370 return "%s%s".printf (parent_symbol.get_lower_case_cprefix (), name);
375 * Returns the implementation name of this data type as it is used in C
376 * code.
378 * @return the name to be used in C code
380 public virtual string get_real_cname () {
381 if (base_method != null || base_interface_method != null) {
382 return "%sreal_%s".printf (parent_symbol.get_lower_case_cprefix (), name);
383 } else {
384 return get_cname ();
388 public string get_finish_real_cname () {
389 assert (coroutine);
390 string result = get_real_cname ();
391 if (result.has_suffix ("_async")) {
392 result = result.substring (0, result.length - "_async".length);
394 result += "_finish";
395 return result;
398 public string get_finish_vfunc_name () {
399 assert (coroutine);
400 string result = vfunc_name;
401 if (result.has_suffix ("_async")) {
402 result = result.substring (0, result.length - "_async".length);
404 result += "_finish";
405 return result;
409 * Sets the name of this method as it is used in C code.
411 * @param cname the name to be used in C code
413 public void set_cname (string cname) {
414 this.cname = cname;
417 private void process_ccode_attribute (Attribute a) {
418 if (a.has_argument ("cname")) {
419 set_cname (a.get_string ("cname"));
421 if (a.has_argument ("cheader_filename")) {
422 var val = a.get_string ("cheader_filename");
423 foreach (string filename in val.split (",")) {
424 add_cheader_filename (filename);
427 if (a.has_argument ("vfunc_name")) {
428 this.vfunc_name = a.get_string ("vfunc_name");
430 if (a.has_argument ("sentinel")) {
431 this.sentinel = a.get_string ("sentinel");
433 if (a.has_argument ("instance_pos")) {
434 cinstance_parameter_position = a.get_double ("instance_pos");
436 if (a.has_argument ("array_length")) {
437 no_array_length = !a.get_bool ("array_length");
439 if (a.has_argument ("array_length_type")) {
440 array_length_type = a.get_string ("array_length_type");
442 if (a.has_argument ("array_null_terminated")) {
443 array_null_terminated = a.get_bool ("array_null_terminated");
445 if (a.has_argument ("array_length_pos")) {
446 carray_length_parameter_position = a.get_double ("array_length_pos");
448 if (a.has_argument ("delegate_target_pos")) {
449 cdelegate_target_parameter_position = a.get_double ("delegate_target_pos");
451 if (a.has_argument ("has_new_function")) {
452 has_new_function = a.get_bool ("has_new_function");
454 if (a.has_argument ("has_construct_function")) {
455 has_construct_function = a.get_bool ("has_construct_function");
457 if (a.has_argument ("generic_type_pos")) {
458 has_generic_type_parameter = true;
459 generic_type_parameter_position = a.get_double ("generic_type_pos");
464 * Process all associated attributes.
466 public void process_attributes () {
467 foreach (Attribute a in attributes) {
468 if (a.name == "CCode") {
469 process_ccode_attribute (a);
470 } else if (a.name == "ReturnsModifiedPointer") {
471 returns_modified_pointer = true;
472 } else if (a.name == "FloatingReference") {
473 return_type.floating_reference = true;
474 } else if (a.name == "PrintfFormat") {
475 printf_format = true;
476 } else if (a.name == "ScanfFormat") {
477 scanf_format = true;
483 * Checks whether the parameters and return type of this method are
484 * compatible with the specified method
486 * @param base_method a method
487 * @param invalid_match error string about which check failed
488 * @return true if the specified method is compatible to this method
490 public bool compatible (Method base_method, out string? invalid_match) {
491 if (binding != base_method.binding) {
492 invalid_match = "incompatible binding";
493 return false;
496 ObjectType object_type = null;
497 if (parent_symbol is ObjectTypeSymbol) {
498 object_type = new ObjectType ((ObjectTypeSymbol) parent_symbol);
499 foreach (TypeParameter type_parameter in object_type.type_symbol.get_type_parameters ()) {
500 var type_arg = new GenericType (type_parameter);
501 type_arg.value_owned = true;
502 object_type.add_type_argument (type_arg);
506 var actual_base_type = base_method.return_type.get_actual_type (object_type, null, this);
507 if (!return_type.equals (actual_base_type)) {
508 invalid_match = "incompatible return type";
509 return false;
512 Iterator<FormalParameter> method_params_it = parameters.iterator ();
513 int param_index = 1;
514 foreach (FormalParameter base_param in base_method.parameters) {
515 /* this method may not expect less arguments */
516 if (!method_params_it.next ()) {
517 invalid_match = "too few parameters";
518 return false;
521 actual_base_type = base_param.parameter_type.get_actual_type (object_type, null, this);
522 if (!actual_base_type.equals (method_params_it.get ().parameter_type)) {
523 invalid_match = "incompatible type of parameter %d".printf (param_index);
524 return false;
526 param_index++;
529 /* this method may not expect more arguments */
530 if (method_params_it.next ()) {
531 invalid_match = "too many parameters";
532 return false;
535 /* this method may throw less but not more errors than the base method */
536 foreach (DataType method_error_type in get_error_types ()) {
537 bool match = false;
538 foreach (DataType base_method_error_type in base_method.get_error_types ()) {
539 if (method_error_type.compatible (base_method_error_type)) {
540 match = true;
541 break;
545 if (!match) {
546 invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
547 return false;
550 if (base_method.coroutine != this.coroutine) {
551 invalid_match = "async mismatch";
552 return false;
555 return true;
559 * Appends the specified parameter to the list of type parameters.
561 * @param p a type parameter
563 public void add_type_parameter (TypeParameter p) {
564 type_parameters.add (p);
565 scope.add (p.name, p);
569 * Returns a copy of the type parameter list.
571 * @return list of type parameters
573 public List<TypeParameter> get_type_parameters () {
574 return new ReadOnlyList<TypeParameter> (type_parameters);
577 public int get_type_parameter_index (string name) {
578 int i = 0;
579 foreach (TypeParameter parameter in type_parameters) {
580 if (parameter.name == name) {
581 return i;
583 i++;
585 return -1;
589 * Adds a precondition to this method.
591 * @param precondition a boolean precondition expression
593 public void add_precondition (Expression precondition) {
594 preconditions.add (precondition);
595 precondition.parent_node = this;
599 * Returns a copy of the list of preconditions of this method.
601 * @return list of preconditions
603 public List<Expression> get_preconditions () {
604 return new ReadOnlyList<Expression> (preconditions);
608 * Adds a postcondition to this method.
610 * @param postcondition a boolean postcondition expression
612 public void add_postcondition (Expression postcondition) {
613 postconditions.add (postcondition);
614 postcondition.parent_node = this;
618 * Returns a copy of the list of postconditions of this method.
620 * @return list of postconditions
622 public List<Expression> get_postconditions () {
623 return new ReadOnlyList<Expression> (postconditions);
626 public override void replace_type (DataType old_type, DataType new_type) {
627 if (return_type == old_type) {
628 return_type = new_type;
629 return;
631 var error_types = get_error_types ();
632 for (int i = 0; i < error_types.size; i++) {
633 if (error_types[i] == old_type) {
634 error_types[i] = new_type;
635 return;
640 private void find_base_methods () {
641 if (base_methods_valid) {
642 return;
645 if (parent_symbol is Class) {
646 if (!(this is CreationMethod)) {
647 find_base_interface_method ((Class) parent_symbol);
648 if (is_virtual || is_abstract || overrides) {
649 find_base_class_method ((Class) parent_symbol);
652 } else if (parent_symbol is Interface) {
653 if (is_virtual || is_abstract) {
654 _base_interface_method = this;
658 base_methods_valid = true;
661 private void find_base_class_method (Class cl) {
662 var sym = cl.scope.lookup (name);
663 if (sym is Method) {
664 var base_method = (Method) sym;
665 if (base_method.is_abstract || base_method.is_virtual) {
666 string invalid_match;
667 if (!compatible (base_method, out invalid_match)) {
668 error = true;
669 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), invalid_match));
670 return;
673 _base_method = base_method;
674 return;
676 } else if (sym is Signal) {
677 var sig = (Signal) sym;
678 if (sig.is_virtual) {
679 var base_method = sig.default_handler;
680 string invalid_match;
681 if (!compatible (base_method, out invalid_match)) {
682 error = true;
683 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), invalid_match));
684 return;
687 _base_method = base_method;
688 return;
692 if (cl.base_class != null) {
693 find_base_class_method (cl.base_class);
697 private void find_base_interface_method (Class cl) {
698 // FIXME report error if multiple possible base methods are found
699 foreach (DataType type in cl.get_base_types ()) {
700 if (type.data_type is Interface) {
701 var sym = type.data_type.scope.lookup (name);
702 if (sym is Method) {
703 var base_method = (Method) sym;
704 if (base_method.is_abstract || base_method.is_virtual) {
705 string invalid_match;
706 if (!compatible (base_method, out invalid_match)) {
707 error = true;
708 Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.".printf (get_full_name (), base_method.get_full_name (), invalid_match));
709 return;
712 _base_interface_method = base_method;
713 return;
720 public override bool check (SemanticAnalyzer analyzer) {
721 if (checked) {
722 return !error;
725 checked = true;
727 process_attributes ();
729 if (is_abstract) {
730 if (parent_symbol is Class) {
731 var cl = (Class) parent_symbol;
732 if (!cl.is_abstract) {
733 error = true;
734 Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
735 return false;
737 } else if (!(parent_symbol is Interface)) {
738 error = true;
739 Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
740 return false;
742 } else if (is_virtual) {
743 if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
744 error = true;
745 Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
746 return false;
749 if (parent_symbol is Class) {
750 var cl = (Class) parent_symbol;
751 if (cl.is_compact) {
752 Report.error (source_reference, "Virtual methods may not be declared in compact classes");
753 return false;
756 } else if (overrides) {
757 if (!(parent_symbol is Class)) {
758 error = true;
759 Report.error (source_reference, "Methods may not be overridden outside of classes");
760 return false;
764 if (is_abstract && body != null) {
765 Report.error (source_reference, "Abstract methods cannot have bodies");
766 } else if ((is_abstract || is_virtual) && external && !external_package && !parent_symbol.external) {
767 Report.error (source_reference, "Extern methods cannot be abstract or virtual");
768 } else if (external && body != null) {
769 Report.error (source_reference, "Extern methods cannot have bodies");
770 } else if (!is_abstract && !external && !external_package && body == null) {
771 Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
774 if (coroutine && !external_package && !analyzer.context.has_package ("gio-2.0")) {
775 error = true;
776 Report.error (source_reference, "gio-2.0 package required for async methods");
777 return false;
780 var old_source_file = analyzer.current_source_file;
781 var old_symbol = analyzer.current_symbol;
783 if (source_reference != null) {
784 analyzer.current_source_file = source_reference.file;
786 analyzer.current_symbol = this;
788 return_type.check (analyzer);
790 var init_attr = get_attribute ("ModuleInit");
791 if (init_attr != null) {
792 source_reference.file.context.module_init_method = this;
795 if (return_type != null) {
796 return_type.check (analyzer);
799 foreach (FormalParameter param in parameters) {
800 param.check (analyzer);
803 foreach (DataType error_type in get_error_types ()) {
804 error_type.check (analyzer);
807 if (result_var != null) {
808 result_var.check (analyzer);
811 foreach (Expression precondition in preconditions) {
812 precondition.check (analyzer);
815 foreach (Expression postcondition in postconditions) {
816 postcondition.check (analyzer);
819 if (body != null) {
820 body.check (analyzer);
823 analyzer.current_source_file = old_source_file;
824 analyzer.current_symbol = old_symbol;
826 if (analyzer.current_struct != null) {
827 if (is_abstract || is_virtual || overrides) {
828 Report.error (source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
829 return false;
831 } else if (overrides && base_method == null) {
832 Report.error (source_reference, "%s: no suitable method found to override".printf (get_full_name ()));
835 if (!external_package && !overrides && !hides && get_hidden_member () != null) {
836 Report.warning (source_reference, "%s hides inherited method `%s'. Use the `new' keyword if hiding was intentional".printf (get_full_name (), get_hidden_member ().get_full_name ()));
839 // check whether return type is at least as accessible as the method
840 if (!analyzer.is_type_accessible (this, return_type)) {
841 error = true;
842 Report.error (source_reference, "return type `%s` is less accessible than method `%s`".printf (return_type.to_string (), get_full_name ()));
843 return false;
846 foreach (Expression precondition in get_preconditions ()) {
847 if (precondition.error) {
848 // if there was an error in the precondition, skip this check
849 error = true;
850 return false;
853 if (!precondition.value_type.compatible (analyzer.bool_type)) {
854 error = true;
855 Report.error (precondition.source_reference, "Precondition must be boolean");
856 return false;
860 foreach (Expression postcondition in get_postconditions ()) {
861 if (postcondition.error) {
862 // if there was an error in the postcondition, skip this check
863 error = true;
864 return false;
867 if (!postcondition.value_type.compatible (analyzer.bool_type)) {
868 error = true;
869 Report.error (postcondition.source_reference, "Postcondition must be boolean");
870 return false;
874 // check that all errors that can be thrown in the method body are declared
875 if (body != null) {
876 foreach (DataType body_error_type in body.get_error_types ()) {
877 bool can_propagate_error = false;
878 foreach (DataType method_error_type in get_error_types ()) {
879 if (body_error_type.compatible (method_error_type)) {
880 can_propagate_error = true;
883 if (!can_propagate_error && !((ErrorType) body_error_type).dynamic_error) {
884 Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
889 if (is_possible_entry_point (analyzer)) {
890 if (analyzer.context.entry_point != null) {
891 error = true;
892 Report.error (source_reference, "program already has an entry point `%s'".printf (analyzer.context.entry_point.get_full_name ()));
893 return false;
895 entry_point = true;
896 analyzer.context.entry_point = this;
898 if (tree_can_fail) {
899 Report.error (source_reference, "\"main\" method cannot throw errors");
903 return !error;
906 bool is_possible_entry_point (SemanticAnalyzer analyzer) {
907 if (external_package) {
908 return false;
911 if (analyzer.context.entry_point_name == null) {
912 if (name == null || name != "main") {
913 // method must be called "main"
914 return false;
916 } else {
917 // custom entry point name
918 if (get_full_name () != analyzer.context.entry_point_name) {
919 return false;
923 if (binding == MemberBinding.INSTANCE) {
924 // method must be static
925 return false;
928 if (return_type is VoidType) {
929 } else if (return_type.data_type == analyzer.int_type.data_type) {
930 } else {
931 // return type must be void or int
932 return false;
935 var params = get_parameters ();
936 if (params.size == 0) {
937 // method may have no parameters
938 return true;
941 if (params.size > 1) {
942 // method must not have more than one parameter
943 return false;
946 Iterator<FormalParameter> params_it = params.iterator ();
947 params_it.next ();
948 var param = params_it.get ();
950 if (param.direction == ParameterDirection.OUT) {
951 // parameter must not be an out parameter
952 return false;
955 if (!(param.parameter_type is ArrayType)) {
956 // parameter must be an array
957 return false;
960 var array_type = (ArrayType) param.parameter_type;
961 if (array_type.element_type.data_type != analyzer.string_type.data_type) {
962 // parameter must be an array of strings
963 return false;
966 return true;
969 public int get_required_arguments () {
970 int n = 0;
971 foreach (var param in parameters) {
972 if (param.default_expression != null || param.ellipsis) {
973 // optional argument
974 break;
976 n++;
978 return n;
981 public Method get_callback_method () {
982 assert (this.coroutine);
984 if (callback_method == null) {
985 var bool_type = new BooleanType ((Struct) CodeContext.get ().root.scope.lookup ("bool"));
986 bool_type.value_owned = true;
987 callback_method = new Method ("callback", bool_type, source_reference);
988 callback_method.access = SymbolAccessibility.PUBLIC;
989 callback_method.external = true;
990 callback_method.binding = MemberBinding.INSTANCE;
991 callback_method.owner = scope;
992 callback_method.is_async_callback = true;
993 callback_method.set_cname (get_real_cname () + "_co");
995 return callback_method;
998 public List<FormalParameter> get_async_begin_parameters () {
999 assert (this.coroutine);
1001 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1003 var params = new ArrayList<FormalParameter> ();
1004 foreach (var param in parameters) {
1005 if (param.direction == ParameterDirection.IN) {
1006 params.add (param);
1010 var callback_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("AsyncReadyCallback"));
1011 callback_type.nullable = true;
1013 var callback_param = new FormalParameter ("_callback_", callback_type);
1014 callback_param.default_expression = new NullLiteral (source_reference);
1015 callback_param.cparameter_position = -1;
1016 callback_param.cdelegate_target_parameter_position = -0.9;
1018 params.add (callback_param);
1020 return params;
1023 public List<FormalParameter> get_async_end_parameters () {
1024 assert (this.coroutine);
1026 var params = new ArrayList<FormalParameter> ();
1028 var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1029 var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
1031 var result_param = new FormalParameter ("_res_", result_type);
1032 result_param.cparameter_position = 0.1;
1033 params.add (result_param);
1035 foreach (var param in parameters) {
1036 if (param.direction == ParameterDirection.OUT) {
1037 params.add (param);
1041 return params;
1044 public void add_captured_variable (LocalVariable local) {
1045 assert (this.closure);
1047 if (captured_variables == null) {
1048 captured_variables = new ArrayList<LocalVariable> ();
1050 captured_variables.add (local);
1053 public void get_captured_variables (Collection<LocalVariable> variables) {
1054 if (captured_variables != null) {
1055 foreach (var local in captured_variables) {
1056 variables.add (local);
1062 // vim:sw=8 noet