3 * Copyright (C) 2006-2010 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
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
28 * Represents a type or namespace method.
30 public class Vala
.Method
: Subroutine
{
31 List
<TypeParameter
> type_parameters
;
33 public const string DEFAULT_SENTINEL
= "NULL";
36 * The return type of this method.
38 public DataType return_type
{
39 get { return _return_type
; }
42 _return_type
.parent_node
= this
;
46 public override bool has_result
{
47 get { return !(return_type is VoidType
); }
51 * Specifies whether this method may only be called with an instance of
54 public MemberBinding binding
{ get; set; default = MemberBinding
.INSTANCE
; }
57 * The name of the vfunc of this method as it is used in C code.
59 public string vfunc_name
{
61 if (_vfunc_name
== null) {
62 _vfunc_name
= this
.name
;
72 * The sentinel to use for terminating variable length argument lists.
74 public string sentinel
{
76 if (_sentinel
== null) {
77 return DEFAULT_SENTINEL
;
89 * Specifies whether this method is abstract. Abstract methods have no
90 * body, may only be specified within abstract classes, and must be
91 * overriden by derived non-abstract classes.
93 public bool is_abstract
{ get; set; }
96 * Specifies whether this method is virtual. Virtual methods may be
97 * overridden by derived classes.
99 public bool is_virtual
{ get; set; }
102 * Specifies whether this method overrides a virtual or abstract method
105 public bool overrides
{ get; set; }
108 * Specifies whether this method should be inlined.
110 public bool is_inline
{ get; set; }
112 public bool returns_floating_reference
{ get; set; }
115 * Specifies whether the C method returns a new instance pointer which
116 * may be different from the previous instance pointer. Only valid for
119 public bool returns_modified_pointer
{ get; set; }
122 * Specifies the virtual or abstract method this method overrides.
123 * Reference must be weak as virtual and abstract methods set
124 * base_method to themselves.
126 public Method base_method
{
128 find_base_methods ();
134 * Specifies the abstract interface method this method implements.
136 public Method base_interface_method
{
138 find_base_methods ();
139 return _base_interface_method
;
143 public bool entry_point
{ get; private set; }
146 * Specifies the generated `this` parameter for instance methods.
148 public Parameter this_parameter
{ get; set; }
151 * Specifies the position of the instance parameter in the C function.
153 public double cinstance_parameter_position
{ get; set; }
156 * Specifies the position of the array length out parameter in the C
159 public double carray_length_parameter_position
{ get; set; }
162 * Specifies the position of the delegate target out parameter in the C
165 public double cdelegate_target_parameter_position
{ get; set; }
168 * Specifies whether the array length should be returned implicitly
169 * if the return type is an array.
171 public bool no_array_length
{ get; set; }
174 * Specifies whether the array is null terminated.
176 public bool array_null_terminated
{ get; set; }
179 * Specified a custom type for the array length parameter.
181 public string? array_length_type
{ get; set; default = null; }
184 * Specifies whether this method expects printf-style format arguments.
186 public bool printf_format
{ get; set; }
189 * Specifies whether this method expects scanf-style format arguments.
191 public bool scanf_format
{ get; set; }
194 * Specifies whether a new function without a GType parameter is
195 * available. This is only applicable to creation methods.
197 public bool has_new_function
{ get; set; default = true; }
200 * Specifies whether a construct function with a GType parameter is
201 * available. This is only applicable to creation methods.
203 public bool has_construct_function
{ get; set; default = true; }
205 public bool has_generic_type_parameter
{ get; set; }
207 public double generic_type_parameter_position
{ get; set; }
209 public bool simple_generics
{ get; set; }
211 public weak Signal signal_reference
{ get; set; }
213 public bool closure
{ get; set; }
215 public bool coroutine
{ get; set; }
217 public bool is_async_callback
{ get; set; }
219 public int yield_count
{ get; set; }
221 private List
<Parameter
> parameters
= new ArrayList
<Parameter
> ();
222 private string cname
;
223 private string finish_name
;
224 private string _vfunc_name
;
225 private string _sentinel
;
226 private List
<Expression
> preconditions
;
227 private List
<Expression
> postconditions
;
228 private DataType _return_type
;
230 private weak Method _base_method
;
231 private Method _base_interface_method
;
232 private bool base_methods_valid
;
234 Method? callback_method
;
236 // only valid for closures
237 List
<LocalVariable
> captured_variables
;
239 static List
<Expression
> _empty_expression_list
;
240 static List
<TypeParameter
> _empty_type_parameter_list
;
243 * Creates a new method.
245 * @param name method name
246 * @param return_type method return type
247 * @param source reference to source code
248 * @return newly created method
250 public Method (string? name
, DataType return_type
, SourceReference? source_reference
= null, Comment? comment
= null) {
251 base (name
, source_reference
, comment
);
252 this
.return_type
= return_type
;
254 carray_length_parameter_position
= -3;
255 cdelegate_target_parameter_position
= -3;
259 * Appends parameter to this method.
261 * @param param a formal parameter
263 public void add_parameter (Parameter param
) {
264 // default C parameter position
265 param
.cparameter_position
= parameters
.size
+ 1;
266 param
.carray_length_parameter_position
= param
.cparameter_position
+ 0.1;
267 param
.cdelegate_target_parameter_position
= param
.cparameter_position
+ 0.1;
268 param
.cdestroy_notify_parameter_position
= param
.cparameter_position
+ 0.1;
270 parameters
.add (param
);
271 if (!param
.ellipsis
) {
272 scope
.add (param
.name
, param
);
276 public List
<Parameter
> get_parameters () {
281 * Remove all parameters from this method.
283 public void clear_parameters () {
284 foreach (Parameter param
in parameters
) {
285 if (!param
.ellipsis
) {
286 scope
.remove (param
.name
);
292 public override void accept (CodeVisitor visitor
) {
293 visitor
.visit_method (this
);
296 public override void accept_children (CodeVisitor visitor
) {
297 foreach (TypeParameter p
in get_type_parameters ()) {
301 if (return_type
!= null) {
302 return_type
.accept (visitor
);
305 foreach (Parameter param
in parameters
) {
306 param
.accept (visitor
);
309 foreach (DataType error_type
in get_error_types ()) {
310 error_type
.accept (visitor
);
313 if (result_var
!= null) {
314 result_var
.accept (visitor
);
317 if (preconditions
!= null) {
318 foreach (Expression precondition
in preconditions
) {
319 precondition
.accept (visitor
);
323 if (postconditions
!= null) {
324 foreach (Expression postcondition
in postconditions
) {
325 postcondition
.accept (visitor
);
330 body
.accept (visitor
);
335 * Returns the interface name of this method as it is used in C code.
337 * @return the name to be used in C code
339 public string get_cname () {
341 cname
= get_default_cname ();
346 public string get_finish_cname () {
348 if (finish_name
== null) {
349 finish_name
= get_default_finish_cname ();
354 public void set_finish_cname (string name
) {
359 * Returns the default interface name of this method as it is used in C
362 * @return the name to be used in C code by default
364 public virtual string get_default_cname () {
365 if (name
== "main" && parent_symbol
.name
== null) {
366 // avoid conflict with generated main function
368 } else if (name
.has_prefix ("_")) {
369 return "_%s%s".printf (parent_symbol
.get_lower_case_cprefix (), name
.substring (1));
371 return "%s%s".printf (parent_symbol
.get_lower_case_cprefix (), name
);
376 * Returns the implementation name of this data type as it is used in C
379 * @return the name to be used in C code
381 public virtual string get_real_cname () {
382 if (base_method
!= null || base_interface_method
!= null) {
383 return "%sreal_%s".printf (parent_symbol
.get_lower_case_cprefix (), name
);
389 protected string get_finish_name_for_basename (string basename
) {
390 string result
= basename
;
391 if (result
.has_suffix ("_async")) {
392 result
= result
.substring (0, result
.length
- "_async".length
);
398 public string get_finish_real_cname () {
400 return get_finish_name_for_basename (get_real_cname ());
403 public string get_finish_vfunc_name () {
405 return get_finish_name_for_basename (vfunc_name
);
408 public string get_default_finish_cname () {
409 return get_finish_name_for_basename (get_cname ());
413 * Sets the name of this method as it is used in C code.
415 * @param cname the name to be used in C code
417 public void set_cname (string cname
) {
421 private void process_ccode_attribute (Attribute a
) {
422 if (a
.has_argument ("cname")) {
423 set_cname (a
.get_string ("cname"));
425 if (a
.has_argument ("cheader_filename")) {
426 var val
= a
.get_string ("cheader_filename");
427 foreach (string filename
in val
.split (",")) {
428 add_cheader_filename (filename
);
431 if (a
.has_argument ("vfunc_name")) {
432 this
.vfunc_name
= a
.get_string ("vfunc_name");
434 if (a
.has_argument ("finish_name")) {
435 this
.finish_name
= a
.get_string ("finish_name");
437 if (a
.has_argument ("sentinel")) {
438 this
.sentinel
= a
.get_string ("sentinel");
440 if (a
.has_argument ("instance_pos")) {
441 cinstance_parameter_position
= a
.get_double ("instance_pos");
443 if (a
.has_argument ("array_length")) {
444 no_array_length
= !a
.get_bool ("array_length");
446 if (a
.has_argument ("array_length_type")) {
447 array_length_type
= a
.get_string ("array_length_type");
449 if (a
.has_argument ("array_null_terminated")) {
450 array_null_terminated
= a
.get_bool ("array_null_terminated");
452 if (a
.has_argument ("array_length_pos")) {
453 carray_length_parameter_position
= a
.get_double ("array_length_pos");
455 if (a
.has_argument ("delegate_target_pos")) {
456 cdelegate_target_parameter_position
= a
.get_double ("delegate_target_pos");
458 if (a
.has_argument ("has_new_function")) {
459 has_new_function
= a
.get_bool ("has_new_function");
461 if (a
.has_argument ("has_construct_function")) {
462 has_construct_function
= a
.get_bool ("has_construct_function");
464 if (a
.has_argument ("generic_type_pos")) {
465 has_generic_type_parameter
= true;
466 generic_type_parameter_position
= a
.get_double ("generic_type_pos");
468 if (a
.has_argument ("simple_generics")) {
469 simple_generics
= a
.get_bool ("simple_generics");
471 if (a
.has_argument ("returns_floating_reference")) {
472 returns_floating_reference
= a
.get_bool ("returns_floating_reference");
477 * Process all associated attributes.
479 public void process_attributes () {
480 foreach (Attribute a
in attributes
) {
481 if (a
.name
== "CCode") {
482 process_ccode_attribute (a
);
483 } else if (a
.name
== "ReturnsModifiedPointer") {
484 returns_modified_pointer
= true;
485 } else if (a
.name
== "FloatingReference") {
486 return_type
.floating_reference
= true;
487 } else if (a
.name
== "PrintfFormat") {
488 printf_format
= true;
489 } else if (a
.name
== "ScanfFormat") {
491 } else if (a
.name
== "NoArrayLength") {
492 Report
.warning (source_reference
, "NoArrayLength attribute is deprecated, use [CCode (array_length = false)] instead.");
493 no_array_length
= true;
494 } else if (a
.name
== "Deprecated") {
495 process_deprecated_attribute (a
);
496 } else if (a
.name
== "NoThrow") {
497 get_error_types ().clear ();
503 * Checks whether the parameters and return type of this method are
504 * compatible with the specified method
506 * @param base_method a method
507 * @param invalid_match error string about which check failed
508 * @return true if the specified method is compatible to this method
510 public bool compatible (Method base_method
, out string? invalid_match
) {
511 if (binding
!= base_method
.binding
) {
512 invalid_match
= "incompatible binding";
516 ObjectType object_type
= null;
517 if (parent_symbol is ObjectTypeSymbol
) {
518 object_type
= new
ObjectType ((ObjectTypeSymbol
) parent_symbol
);
519 foreach (TypeParameter type_parameter
in object_type
.type_symbol
.get_type_parameters ()) {
520 var type_arg
= new
GenericType (type_parameter
);
521 type_arg
.value_owned
= true;
522 object_type
.add_type_argument (type_arg
);
526 var actual_base_type
= base_method
.return_type
.get_actual_type (object_type
, null, this
);
527 if (!return_type
.equals (actual_base_type
)) {
528 invalid_match
= "incompatible return type";
532 Iterator
<Parameter
> method_params_it
= parameters
.iterator ();
534 foreach (Parameter base_param
in base_method
.parameters
) {
535 /* this method may not expect less arguments */
536 if (!method_params_it
.next ()) {
537 invalid_match
= "too few parameters";
541 var param
= method_params_it
.get ();
542 if (base_param
.ellipsis
!= param
.ellipsis
) {
543 invalid_match
= "ellipsis parameter mismatch";
546 if (!base_param
.ellipsis
) {
547 actual_base_type
= base_param
.variable_type
.get_actual_type (object_type
, null, this
);
548 if (!actual_base_type
.equals (param
.variable_type
)) {
549 invalid_match
= "incompatible type of parameter %d".printf (param_index
);
556 /* this method may not expect more arguments */
557 if (method_params_it
.next ()) {
558 invalid_match
= "too many parameters";
562 /* this method may throw less but not more errors than the base method */
563 foreach (DataType method_error_type
in get_error_types ()) {
565 foreach (DataType base_method_error_type
in base_method
.get_error_types ()) {
566 if (method_error_type
.compatible (base_method_error_type
)) {
573 invalid_match
= "incompatible error type `%s'".printf (method_error_type
.to_string ());
577 if (base_method
.coroutine
!= this
.coroutine
) {
578 invalid_match
= "async mismatch";
586 * Appends the specified parameter to the list of type parameters.
588 * @param p a type parameter
590 public void add_type_parameter (TypeParameter p
) {
591 if (type_parameters
== null) {
592 type_parameters
= new ArrayList
<TypeParameter
> ();
594 type_parameters
.add (p
);
595 scope
.add (p
.name
, p
);
599 * Returns a copy of the type parameter list.
601 * @return list of type parameters
603 public List
<TypeParameter
> get_type_parameters () {
604 if (type_parameters
!= null) {
605 return type_parameters
;
607 if (_empty_type_parameter_list
== null) {
608 _empty_type_parameter_list
= new ArrayList
<TypeParameter
> ();
610 return _empty_type_parameter_list
;
613 public int get_type_parameter_index (string name
) {
614 if (type_parameters
== null) {
619 foreach (TypeParameter parameter
in type_parameters
) {
620 if (parameter
.name
== name
) {
629 * Adds a precondition to this method.
631 * @param precondition a boolean precondition expression
633 public void add_precondition (Expression precondition
) {
634 if (preconditions
== null) {
635 preconditions
= new ArrayList
<Expression
> ();
637 preconditions
.add (precondition
);
638 precondition
.parent_node
= this
;
642 * Returns a copy of the list of preconditions of this method.
644 * @return list of preconditions
646 public List
<Expression
> get_preconditions () {
647 if (preconditions
!= null) {
648 return preconditions
;
650 if (_empty_expression_list
== null) {
651 _empty_expression_list
= new ArrayList
<Expression
> ();
653 return _empty_expression_list
;
657 * Adds a postcondition to this method.
659 * @param postcondition a boolean postcondition expression
661 public void add_postcondition (Expression postcondition
) {
662 if (postconditions
== null) {
663 postconditions
= new ArrayList
<Expression
> ();
665 postconditions
.add (postcondition
);
666 postcondition
.parent_node
= this
;
670 * Returns a copy of the list of postconditions of this method.
672 * @return list of postconditions
674 public List
<Expression
> get_postconditions () {
675 if (postconditions
!= null) {
676 return postconditions
;
678 if (_empty_expression_list
== null) {
679 _empty_expression_list
= new ArrayList
<Expression
> ();
681 return _empty_expression_list
;
684 public override void replace_type (DataType old_type
, DataType new_type
) {
685 if (return_type
== old_type
) {
686 return_type
= new_type
;
689 var error_types
= get_error_types ();
690 for (int i
= 0; i
< error_types
.size
; i
++) {
691 if (error_types
[i
] == old_type
) {
692 error_types
[i
] = new_type
;
698 private void find_base_methods () {
699 if (base_methods_valid
) {
703 if (parent_symbol is Class
) {
704 if (!(this is CreationMethod
)) {
705 find_base_interface_method ((Class
) parent_symbol
);
706 if (is_virtual
|| is_abstract
|| overrides
) {
707 find_base_class_method ((Class
) parent_symbol
);
710 } else if (parent_symbol is Interface
) {
711 if (is_virtual
|| is_abstract
) {
712 _base_interface_method
= this
;
716 base_methods_valid
= true;
719 private void find_base_class_method (Class cl
) {
720 var sym
= cl
.scope
.lookup (name
);
722 var base_method
= (Method
) sym
;
723 if (base_method
.is_abstract
|| base_method
.is_virtual
) {
724 string invalid_match
;
725 if (!compatible (base_method
, out invalid_match
)) {
727 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
));
731 _base_method
= base_method
;
734 } else if (sym is Signal
) {
735 var sig
= (Signal
) sym
;
736 if (sig
.is_virtual
) {
737 var base_method
= sig
.default_handler
;
738 string invalid_match
;
739 if (!compatible (base_method
, out invalid_match
)) {
741 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
));
745 _base_method
= base_method
;
750 if (cl
.base_class
!= null) {
751 find_base_class_method (cl
.base_class
);
755 private void find_base_interface_method (Class cl
) {
756 // FIXME report error if multiple possible base methods are found
757 foreach (DataType type
in cl
.get_base_types ()) {
758 if (type
.data_type is Interface
) {
759 var sym
= type
.data_type
.scope
.lookup (name
);
761 var base_method
= (Method
) sym
;
762 if (base_method
.is_abstract
|| base_method
.is_virtual
) {
763 string invalid_match
;
764 if (!compatible (base_method
, out invalid_match
)) {
766 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
));
770 _base_interface_method
= base_method
;
778 public override bool check (CodeContext context
) {
785 process_attributes ();
788 if (parent_symbol is Class
) {
789 var cl
= (Class
) parent_symbol
;
790 if (!cl
.is_abstract
) {
792 Report
.error (source_reference
, "Abstract methods may not be declared in non-abstract classes");
795 } else if (!(parent_symbol is Interface
)) {
797 Report
.error (source_reference
, "Abstract methods may not be declared outside of classes and interfaces");
800 } else if (is_virtual
) {
801 if (!(parent_symbol is Class
) && !(parent_symbol is Interface
)) {
803 Report
.error (source_reference
, "Virtual methods may not be declared outside of classes and interfaces");
807 if (parent_symbol is Class
) {
808 var cl
= (Class
) parent_symbol
;
810 Report
.error (source_reference
, "Virtual methods may not be declared in compact classes");
814 } else if (overrides
) {
815 if (!(parent_symbol is Class
)) {
817 Report
.error (source_reference
, "Methods may not be overridden outside of classes");
820 } else if (access
== SymbolAccessibility
.PROTECTED
) {
821 if (!(parent_symbol is Class
) && !(parent_symbol is Interface
)) {
823 Report
.error (source_reference
, "Protected methods may not be declared outside of classes and interfaces");
828 if (is_abstract
&& body
!= null) {
829 Report
.error (source_reference
, "Abstract methods cannot have bodies");
830 } else if ((is_abstract
|| is_virtual
) && external
&& !external_package
&& !parent_symbol
.external
) {
831 Report
.error (source_reference
, "Extern methods cannot be abstract or virtual");
832 } else if (external
&& body
!= null) {
833 Report
.error (source_reference
, "Extern methods cannot have bodies");
834 } else if (!is_abstract
&& !external
&& source_type
== SourceFileType
.SOURCE
&& body
== null) {
835 Report
.error (source_reference
, "Non-abstract, non-extern methods must have bodies");
838 if (coroutine
&& !external_package
&& !context
.has_package ("gio-2.0")) {
840 Report
.error (source_reference
, "gio-2.0 package required for async methods");
844 var old_source_file
= context
.analyzer
.current_source_file
;
845 var old_symbol
= context
.analyzer
.current_symbol
;
847 if (source_reference
!= null) {
848 context
.analyzer
.current_source_file
= source_reference
.file
;
850 context
.analyzer
.current_symbol
= this
;
852 return_type
.check (context
);
854 var init_attr
= get_attribute ("ModuleInit");
855 if (init_attr
!= null) {
856 source_reference
.file
.context
.module_init_method
= this
;
859 if (return_type
!= null) {
860 return_type
.check (context
);
863 if (parameters
.size
== 1 && parameters
[0].ellipsis
&& body
!= null) {
864 // accept just `...' for external methods for convenience
866 Report
.error (parameters
[0].source_reference
, "Named parameter required before `...'");
869 foreach (Parameter param
in parameters
) {
870 param
.check (context
);
871 if (coroutine
&& param
.direction
== ParameterDirection
.REF
) {
873 Report
.error (param
.source_reference
, "Reference parameters are not supported for async methods");
877 foreach (DataType error_type
in get_error_types ()) {
878 error_type
.check (context
);
880 // check whether error type is at least as accessible as the method
881 if (!context
.analyzer
.is_type_accessible (this
, error_type
)) {
883 Report
.error (source_reference
, "error type `%s` is less accessible than method `%s`".printf (error_type
.to_string (), get_full_name ()));
888 if (result_var
!= null) {
889 result_var
.check (context
);
892 if (preconditions
!= null) {
893 foreach (Expression precondition
in preconditions
) {
894 precondition
.check (context
);
898 if (postconditions
!= null) {
899 foreach (Expression postcondition
in postconditions
) {
900 postcondition
.check (context
);
905 body
.check (context
);
908 context
.analyzer
.current_source_file
= old_source_file
;
909 context
.analyzer
.current_symbol
= old_symbol
;
911 if (context
.analyzer
.current_struct
!= null) {
912 if (is_abstract
|| is_virtual
|| overrides
) {
914 Report
.error (source_reference
, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
917 } else if (overrides
&& base_method
== null) {
918 Report
.error (source_reference
, "%s: no suitable method found to override".printf (get_full_name ()));
919 } else if ((is_abstract
|| is_virtual
|| overrides
) && access
== SymbolAccessibility
.PRIVATE
) {
921 Report
.error (source_reference
, "Private member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
925 if (!external_package
&& !overrides
&& !hides
&& get_hidden_member () != null) {
926 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 ()));
929 // check whether return type is at least as accessible as the method
930 if (!context
.analyzer
.is_type_accessible (this
, return_type
)) {
932 Report
.error (source_reference
, "return type `%s` is less accessible than method `%s`".printf (return_type
.to_string (), get_full_name ()));
936 foreach (Expression precondition
in get_preconditions ()) {
937 if (precondition
.error
) {
938 // if there was an error in the precondition, skip this check
943 if (!precondition
.value_type
.compatible (context
.analyzer
.bool_type
)) {
945 Report
.error (precondition
.source_reference
, "Precondition must be boolean");
950 foreach (Expression postcondition
in get_postconditions ()) {
951 if (postcondition
.error
) {
952 // if there was an error in the postcondition, skip this check
957 if (!postcondition
.value_type
.compatible (context
.analyzer
.bool_type
)) {
959 Report
.error (postcondition
.source_reference
, "Postcondition must be boolean");
964 // check that all errors that can be thrown in the method body are declared
966 foreach (DataType body_error_type
in body
.get_error_types ()) {
967 bool can_propagate_error
= false;
968 foreach (DataType method_error_type
in get_error_types ()) {
969 if (body_error_type
.compatible (method_error_type
)) {
970 can_propagate_error
= true;
973 bool is_dynamic_error
= body_error_type is ErrorType
&& ((ErrorType
) body_error_type
).dynamic_error
;
974 if (!can_propagate_error
&& !is_dynamic_error
) {
975 Report
.warning (body_error_type
.source_reference
, "unhandled error `%s'".printf (body_error_type
.to_string()));
980 if (is_possible_entry_point (context
)) {
981 if (context
.entry_point
!= null) {
983 Report
.error (source_reference
, "program already has an entry point `%s'".printf (context
.entry_point
.get_full_name ()));
987 context
.entry_point
= this
;
989 if (tree_can_fail
&& context
.profile
!= Profile
.DOVA
) {
990 Report
.error (source_reference
, "\"main\" method cannot throw errors");
997 bool is_possible_entry_point (CodeContext context
) {
998 if (external_package
) {
1002 if (context
.entry_point_name
== null) {
1003 if (name
== null || name
!= "main") {
1004 // method must be called "main"
1008 // custom entry point name
1009 if (get_full_name () != context
.entry_point_name
) {
1014 if (binding
== MemberBinding
.INSTANCE
) {
1015 // method must be static
1019 if (return_type is VoidType
) {
1020 } else if (return_type
.data_type
== context
.analyzer
.int_type
.data_type
) {
1022 // return type must be void or int
1026 var params
= get_parameters ();
1027 if (params
.size
== 0) {
1028 // method may have no parameters
1032 if (params
.size
> 1) {
1033 // method must not have more than one parameter
1037 Iterator
<Parameter
> params_it
= params
.iterator ();
1039 var param
= params_it
.get ();
1041 if (param
.direction
== ParameterDirection
.OUT
) {
1042 // parameter must not be an out parameter
1046 if (!(param
.variable_type is ArrayType
)) {
1047 // parameter must be an array
1051 var array_type
= (ArrayType
) param
.variable_type
;
1052 if (array_type
.element_type
.data_type
!= context
.analyzer
.string_type
.data_type
) {
1053 // parameter must be an array of strings
1060 public int get_required_arguments () {
1062 foreach (var param
in parameters
) {
1063 if (param
.initializer
!= null || param
.ellipsis
) {
1064 // optional argument
1072 public Method
get_callback_method () {
1073 assert (this
.coroutine
);
1075 if (callback_method
== null) {
1076 var bool_type
= new
BooleanType ((Struct
) CodeContext
.get ().root
.scope
.lookup ("bool"));
1077 bool_type
.value_owned
= true;
1078 callback_method
= new
Method ("callback", bool_type
, source_reference
);
1079 callback_method
.access
= SymbolAccessibility
.PUBLIC
;
1080 callback_method
.external
= true;
1081 callback_method
.binding
= MemberBinding
.INSTANCE
;
1082 callback_method
.owner
= scope
;
1083 callback_method
.is_async_callback
= true;
1084 callback_method
.set_cname (get_real_cname () + "_co");
1086 return callback_method
;
1089 public List
<Parameter
> get_async_begin_parameters () {
1090 assert (this
.coroutine
);
1092 var glib_ns
= CodeContext
.get ().root
.scope
.lookup ("GLib");
1094 var params
= new ArrayList
<Parameter
> ();
1095 foreach (var param
in parameters
) {
1096 if (param
.direction
== ParameterDirection
.IN
) {
1101 var callback_type
= new
DelegateType ((Delegate
) glib_ns
.scope
.lookup ("AsyncReadyCallback"));
1102 callback_type
.nullable
= true;
1103 callback_type
.is_called_once
= true;
1105 var callback_param
= new
Parameter ("_callback_", callback_type
);
1106 callback_param
.initializer
= new
NullLiteral (source_reference
);
1107 callback_param
.initializer
.target_type
= callback_type
.copy ();
1108 callback_param
.cparameter_position
= -1;
1109 callback_param
.cdelegate_target_parameter_position
= -0.9;
1111 params
.add (callback_param
);
1116 public List
<Parameter
> get_async_end_parameters () {
1117 assert (this
.coroutine
);
1119 var params
= new ArrayList
<Parameter
> ();
1121 var glib_ns
= CodeContext
.get ().root
.scope
.lookup ("GLib");
1122 var result_type
= new
ObjectType ((ObjectTypeSymbol
) glib_ns
.scope
.lookup ("AsyncResult"));
1124 var result_param
= new
Parameter ("_res_", result_type
);
1125 result_param
.cparameter_position
= 0.1;
1126 params
.add (result_param
);
1128 foreach (var param
in parameters
) {
1129 if (param
.direction
== ParameterDirection
.OUT
) {
1137 public void add_captured_variable (LocalVariable local
) {
1138 assert (this
.closure
);
1140 if (captured_variables
== null) {
1141 captured_variables
= new ArrayList
<LocalVariable
> ();
1143 captured_variables
.add (local
);
1146 public void get_captured_variables (Collection
<LocalVariable
> variables
) {
1147 if (captured_variables
!= null) {
1148 foreach (var local
in captured_variables
) {
1149 variables
.add (local
);
1154 public override void get_defined_variables (Collection
<LocalVariable
> collection
) {
1155 // capturing variables is only supported if they are initialized
1156 // therefore assume that captured variables are initialized
1158 get_captured_variables (collection
);