Line data Source code
1 : /* valamethod.vala
2 : *
3 : * Copyright (C) 2006-2010 Jürg Billeter
4 : * Copyright (C) 2006-2008 Raffaele Sandrini
5 : *
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.
10 :
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.
15 :
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
19 : *
20 : * Author:
21 : * Jürg Billeter <j@bitron.ch>
22 : * Raffaele Sandrini <raffaele@sandrini.ch>
23 : */
24 :
25 : using GLib;
26 :
27 : /**
28 : * Represents a type or namespace method.
29 : */
30 13368761 : public class Vala.Method : Subroutine, Callable, GenericSymbol {
31 6682072 : List<TypeParameter> type_parameters;
32 :
33 : /**
34 : * The return type of this method.
35 : */
36 : public DataType return_type {
37 60037200 : get { return _return_type; }
38 10543656 : set {
39 21424392 : _return_type = value;
40 10543656 : _return_type.parent_node = this;
41 : }
42 : }
43 :
44 : public override bool has_result {
45 11743 : get { return !(return_type is VoidType); }
46 : }
47 :
48 : /**
49 : * Specifies whether this method may only be called with an instance of
50 : * the contained type.
51 : */
52 22835275 : public MemberBinding binding { get; set; default = MemberBinding.INSTANCE; }
53 :
54 : /**
55 : * Specifies whether this method is abstract. Abstract methods have no
56 : * body, may only be specified within abstract classes, and must be
57 : * overridden by derived non-abstract classes.
58 : */
59 9738933 : public bool is_abstract { get; set; }
60 :
61 : /**
62 : * Specifies whether this method is virtual. Virtual methods may be
63 : * overridden by derived classes.
64 : */
65 5760327 : public bool is_virtual { get; set; }
66 :
67 : /**
68 : * Specifies whether this method overrides a virtual or abstract method
69 : * of a base type.
70 : */
71 664711 : public bool overrides { get; set; }
72 :
73 : /**
74 : * Specifies whether this method should be inlined.
75 : */
76 10513 : public bool is_inline { get; set; }
77 :
78 : public bool returns_floating_reference {
79 5868943 : get {
80 5868943 : return get_attribute_bool ("CCode", "returns_floating_reference");
81 : }
82 0 : set {
83 0 : set_attribute_bool ("CCode", "returns_floating_reference", value);
84 : }
85 : }
86 :
87 : /*
88 : * Specifies whether the C method returns a new instance pointer which
89 : * may be different from the previous instance pointer. Only valid for
90 : * imported methods.
91 : */
92 : public bool returns_modified_pointer {
93 196631 : get {
94 196631 : return has_attribute ("ReturnsModifiedPointer");
95 : }
96 18 : set {
97 18 : set_attribute ("ReturnsModifiedPointer", value);
98 : }
99 : }
100 :
101 : /**
102 : * Specifies the virtual or abstract method this method overrides.
103 : * Reference must be weak as virtual and abstract methods set
104 : * base_method to themselves.
105 : */
106 : public Method base_method {
107 13640984 : get {
108 13640984 : find_base_methods ();
109 13640984 : return _base_method;
110 : }
111 : }
112 :
113 : /**
114 : * Specifies the abstract interface method this method implements.
115 : */
116 : public Method base_interface_method {
117 13730759 : get {
118 13730759 : find_base_methods ();
119 13730759 : return _base_interface_method;
120 : }
121 : }
122 :
123 : /**
124 : * Specifies the explicit interface containing the method this method implements.
125 : */
126 : public DataType base_interface_type {
127 28649644 : get { return _base_interface_type; }
128 24 : set {
129 48 : _base_interface_type = value;
130 24 : _base_interface_type.parent_node = this;
131 : }
132 : }
133 :
134 107607 : public bool entry_point { get; private set; }
135 :
136 5 : public bool is_main_block { get; private set; }
137 :
138 : /**
139 : * Specifies the generated `this` parameter for instance methods.
140 : */
141 33155727 : public Parameter? this_parameter { get; set; }
142 :
143 : /**
144 : * Specifies whether this method expects printf-style format arguments.
145 : */
146 : public bool printf_format {
147 236806 : get {
148 236806 : return has_attribute ("PrintfFormat");
149 : }
150 0 : set {
151 0 : set_attribute ("PrintfFormat", value);
152 : }
153 : }
154 :
155 : /**
156 : * Specifies whether this method expects scanf-style format arguments.
157 : */
158 : public bool scanf_format {
159 41780 : get {
160 41780 : return has_attribute ("ScanfFormat");
161 : }
162 0 : set {
163 0 : set_attribute ("ScanfFormat", value);
164 : }
165 : }
166 :
167 : /**
168 : * Specifies whether a construct function with a GType parameter is
169 : * available. This is only applicable to creation methods.
170 : */
171 : public bool has_construct_function {
172 2632 : get {
173 2632 : return get_attribute_bool ("CCode", "has_construct_function", true);
174 : }
175 599 : set {
176 599 : set_attribute_bool ("CCode", "has_construct_function", value);
177 : }
178 : }
179 :
180 6682165 : public LocalVariable? params_array_var { get; protected set; }
181 :
182 131782 : public weak Signal signal_reference { get; set; }
183 :
184 65819 : public bool closure { get; set; }
185 :
186 2722399 : public bool coroutine { get; set; }
187 :
188 288265 : public bool is_async_callback { get; set; }
189 :
190 13364147 : private List<Parameter> parameters = new ArrayList<Parameter> ();
191 6682072 : private List<Parameter>? async_begin_parameters;
192 6682072 : private List<Parameter>? async_end_parameters;
193 6682072 : private List<Expression> preconditions;
194 6682072 : private List<Expression> postconditions;
195 6682072 : private DataType _return_type;
196 :
197 6682072 : protected List<DataType> error_types;
198 :
199 : private weak Method _base_method;
200 : private weak Method _base_interface_method;
201 6682072 : private DataType _base_interface_type;
202 : private bool base_methods_valid;
203 :
204 6682072 : Method? callback_method;
205 6682072 : Method? end_method;
206 :
207 : // only valid for closures
208 6682072 : List<LocalVariable> captured_variables;
209 :
210 : static List<Expression> _empty_expression_list;
211 : static List<TypeParameter> _empty_type_parameter_list;
212 :
213 : /**
214 : * Creates a new method.
215 : *
216 : * @param name method name
217 : * @param return_type method return type
218 : * @param source_reference reference to source code
219 : * @return newly created method
220 : */
221 19479641 : public Method (string? name, DataType return_type, SourceReference? source_reference = null, Comment? comment = null) {
222 6682070 : base (name, source_reference, comment);
223 6682070 : this.return_type = return_type;
224 : }
225 :
226 : /**
227 : * Creates a new main block method.
228 : *
229 : * @param source_reference reference to source code
230 : * @return newly created method
231 : */
232 5 : public Method.main_block (SourceReference? source_reference = null) {
233 5 : base ("main", source_reference, null);
234 5 : return_type = new VoidType ();
235 5 : is_main_block = true;
236 : }
237 :
238 : /**
239 : * Appends parameter to this method.
240 : *
241 : * @param param a formal parameter
242 : */
243 8594782 : public void add_parameter (Parameter param) {
244 : // default C parameter position
245 8594782 : parameters.add (param);
246 8594782 : scope.add (param.name, param);
247 : }
248 :
249 2088720 : public unowned List<Parameter> get_parameters () {
250 2088720 : return parameters;
251 : }
252 :
253 : /**
254 : * Remove all parameters from this method.
255 : */
256 1 : public void clear_parameters () {
257 3 : foreach (Parameter param in parameters) {
258 1 : if (!param.ellipsis) {
259 0 : scope.remove (param.name);
260 : }
261 : }
262 1 : parameters.clear ();
263 : }
264 :
265 5670094 : public bool is_variadic () {
266 19557530 : foreach (Parameter param in parameters) {
267 7052802 : if (param.ellipsis || param.params_array) {
268 109084 : return true;
269 : }
270 : }
271 5670094 : return false;
272 : }
273 :
274 13288223 : public override void accept (CodeVisitor visitor) {
275 13288223 : visitor.visit_method (this);
276 : }
277 :
278 9495657 : public override void accept_children (CodeVisitor visitor) {
279 9652451 : foreach (TypeParameter p in get_type_parameters ()) {
280 78397 : p.accept (visitor);
281 : }
282 :
283 9495657 : if (base_interface_type != null) {
284 28 : base_interface_type.accept (visitor);
285 : }
286 :
287 9495657 : if (return_type != null) {
288 9495657 : return_type.accept (visitor);
289 : }
290 :
291 33166219 : foreach (Parameter param in parameters) {
292 11835281 : param.accept (visitor);
293 : }
294 :
295 9495657 : if (error_types != null) {
296 3858097 : foreach (DataType error_type in error_types) {
297 1298649 : error_type.accept (visitor);
298 : }
299 : }
300 :
301 9495657 : if (result_var != null) {
302 42 : result_var.accept (visitor);
303 : }
304 :
305 9495657 : if (preconditions != null) {
306 102 : foreach (Expression precondition in preconditions) {
307 34 : precondition.accept (visitor);
308 : }
309 : }
310 :
311 9495657 : if (postconditions != null) {
312 183 : foreach (Expression postcondition in postconditions) {
313 61 : postcondition.accept (visitor);
314 : }
315 : }
316 :
317 9495657 : if (body != null) {
318 298674 : body.accept (visitor);
319 : }
320 : }
321 :
322 : /**
323 : * Checks whether the parameters and return type of this method are
324 : * compatible with the specified method
325 : *
326 : * @param base_method a method
327 : * @param invalid_match error string about which check failed
328 : * @return true if the specified method is compatible to this method
329 : */
330 344629 : public bool compatible (Method base_method, out string? invalid_match) {
331 344629 : return compatible_internal (base_method, out invalid_match, this);
332 : }
333 :
334 : /**
335 : * Checks whether the parameters and return type of this method are
336 : * compatible with the specified method
337 : *
338 : * @param base_method a method
339 : * @return true if the specified method is compatible to this method
340 : */
341 3 : public bool compatible_no_error (Method base_method) {
342 3 : return compatible_internal (base_method, null, null);
343 : }
344 :
345 344632 : bool compatible_internal (Method base_method, out string? invalid_match, CodeNode? node_reference) {
346 : // method is always compatible to itself
347 344632 : if (this == base_method) {
348 314459 : invalid_match = null;
349 314459 : return true;
350 : }
351 :
352 30173 : if (binding != base_method.binding) {
353 0 : invalid_match = "incompatible binding";
354 0 : return false;
355 : }
356 :
357 30173 : ObjectType object_type = null;
358 30173 : if (parent_symbol is ObjectTypeSymbol) {
359 30173 : object_type = new ObjectType ((ObjectTypeSymbol) parent_symbol);
360 30907 : foreach (TypeParameter type_parameter in object_type.object_type_symbol.get_type_parameters ()) {
361 367 : var type_arg = new GenericType (type_parameter);
362 367 : type_arg.value_owned = true;
363 367 : object_type.add_type_argument (type_arg);
364 : }
365 : }
366 :
367 30173 : if (this.get_type_parameters ().size < base_method.get_type_parameters ().size) {
368 0 : invalid_match = "too few type parameters";
369 0 : return false;
370 30173 : } else if (this.get_type_parameters ().size > base_method.get_type_parameters ().size) {
371 0 : invalid_match = "too many type parameters";
372 0 : return false;
373 : }
374 :
375 30173 : List<DataType> method_type_args = null;
376 30173 : if (this.has_type_parameters ()) {
377 3 : method_type_args = new ArrayList<DataType> ();
378 11 : foreach (TypeParameter type_parameter in this.get_type_parameters ()) {
379 4 : var type_arg = new GenericType (type_parameter);
380 4 : type_arg.value_owned = true;
381 4 : method_type_args.add (type_arg);
382 : }
383 : }
384 :
385 30173 : var return_type = this.return_type.copy ();
386 30173 : if (has_attribute_argument ("CCode", "returns_floating_reference")) {
387 2 : return_type.floating_reference = returns_floating_reference;
388 : } else {
389 30171 : return_type.floating_reference = base_method.returns_floating_reference;
390 : }
391 :
392 30173 : var actual_base_type = base_method.return_type.get_actual_type (object_type, method_type_args, node_reference);
393 30173 : if (!return_type.equals (actual_base_type)) {
394 7 : invalid_match = "Base method expected return type `%s', but `%s' was provided".printf (actual_base_type.to_prototype_string (), return_type.to_prototype_string ());
395 7 : return false;
396 : }
397 :
398 30166 : Iterator<Parameter> method_params_it = parameters.iterator ();
399 30166 : int param_index = 1;
400 82902 : foreach (Parameter base_param in base_method.parameters) {
401 : /* this method may not expect less arguments */
402 26370 : if (!method_params_it.next ()) {
403 0 : invalid_match = "too few parameters";
404 0 : return false;
405 : }
406 :
407 26370 : var param = method_params_it.get ();
408 26370 : if (base_param.ellipsis != param.ellipsis) {
409 0 : invalid_match = "ellipsis parameter mismatch";
410 0 : return false;
411 : }
412 26370 : if (base_param.params_array != param.params_array) {
413 0 : invalid_match = "params array parameter mismatch";
414 0 : return false;
415 : }
416 26370 : if (!base_param.ellipsis) {
417 26370 : if (base_param.direction != param.direction) {
418 0 : invalid_match = "incompatible direction of parameter %d".printf (param_index);
419 0 : return false;
420 : }
421 :
422 26370 : actual_base_type = base_param.variable_type.get_actual_type (object_type, method_type_args, node_reference);
423 26370 : if (!actual_base_type.equals (param.variable_type)) {
424 2 : invalid_match = "incompatible type of parameter %d".printf (param_index);
425 2 : return false;
426 : }
427 : }
428 26368 : param_index++;
429 : }
430 :
431 : /* this method may not expect more arguments */
432 30164 : if (method_params_it.next ()) {
433 0 : invalid_match = "too many parameters";
434 0 : return false;
435 : }
436 :
437 : /* this method may throw less but not more errors than the base method */
438 30164 : var base_method_errors = new ArrayList<DataType> ();
439 30164 : base_method.get_error_types (base_method_errors);
440 30164 : if (error_types != null) {
441 12615 : foreach (DataType method_error_type in error_types) {
442 4205 : bool match = false;
443 4205 : foreach (DataType base_method_error_type in base_method_errors) {
444 4205 : if (method_error_type.compatible (base_method_error_type)) {
445 4205 : match = true;
446 4205 : break;
447 : }
448 : }
449 :
450 4205 : if (!match) {
451 0 : invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
452 0 : return false;
453 : }
454 : }
455 : }
456 30164 : if (base_method.coroutine != this.coroutine) {
457 0 : invalid_match = "async mismatch";
458 0 : return false;
459 : }
460 :
461 30164 : invalid_match = null;
462 30164 : return true;
463 : }
464 :
465 : /**
466 : * Appends the specified parameter to the list of type parameters.
467 : *
468 : * @param p a type parameter
469 : */
470 50648 : public void add_type_parameter (TypeParameter p) {
471 50648 : if (type_parameters == null) {
472 47582 : type_parameters = new ArrayList<TypeParameter> ();
473 : }
474 50648 : type_parameters.add (p);
475 50648 : scope.add (p.name, p);
476 : }
477 :
478 : /**
479 : * Returns the type parameter list.
480 : *
481 : * @return list of type parameters
482 : */
483 15485013 : public unowned List<TypeParameter> get_type_parameters () {
484 15485013 : if (type_parameters != null) {
485 15485013 : return type_parameters;
486 : }
487 15363882 : if (_empty_type_parameter_list == null) {
488 1430 : _empty_type_parameter_list = new ArrayList<TypeParameter> ();
489 : }
490 15363882 : return _empty_type_parameter_list;
491 : }
492 :
493 3129 : public int get_type_parameter_index (string name) {
494 3129 : if (type_parameters == null) {
495 0 : return -1;
496 : }
497 :
498 3129 : int i = 0;
499 3155 : foreach (TypeParameter parameter in type_parameters) {
500 3142 : if (parameter.name == name) {
501 3129 : return i;
502 : }
503 13 : i++;
504 : }
505 3129 : return -1;
506 : }
507 :
508 245825 : public bool has_type_parameters () {
509 245825 : return (type_parameters != null && type_parameters.size > 0);
510 : }
511 :
512 : /**
513 : * Adds a precondition to this method.
514 : *
515 : * @param precondition a boolean precondition expression
516 : */
517 14 : public void add_precondition (Expression precondition) {
518 14 : if (preconditions == null) {
519 14 : preconditions = new ArrayList<Expression> ();
520 : }
521 14 : preconditions.add (precondition);
522 14 : precondition.parent_node = this;
523 : }
524 :
525 : /**
526 : * Returns the list of preconditions of this method.
527 : *
528 : * @return list of preconditions
529 : */
530 7130946 : public unowned List<Expression> get_preconditions () {
531 7130946 : if (preconditions != null) {
532 7130946 : return preconditions;
533 : }
534 7130907 : if (_empty_expression_list == null) {
535 0 : _empty_expression_list = new ArrayList<Expression> ();
536 : }
537 7130907 : return _empty_expression_list;
538 : }
539 :
540 : /**
541 : * Adds a postcondition to this method.
542 : *
543 : * @param postcondition a boolean postcondition expression
544 : */
545 23 : public void add_postcondition (Expression postcondition) {
546 23 : if (postconditions == null) {
547 23 : postconditions = new ArrayList<Expression> ();
548 : }
549 23 : postconditions.add (postcondition);
550 23 : postcondition.parent_node = this;
551 : }
552 :
553 : /**
554 : * Returns the list of postconditions of this method.
555 : *
556 : * @return list of postconditions
557 : */
558 11462189 : public unowned List<Expression> get_postconditions () {
559 11462189 : if (postconditions != null) {
560 11462189 : return postconditions;
561 : }
562 11462120 : if (_empty_expression_list == null) {
563 1537 : _empty_expression_list = new ArrayList<Expression> ();
564 : }
565 11462120 : return _empty_expression_list;
566 : }
567 :
568 : /**
569 : * Adds an error type to the exceptions that can be
570 : * thrown by this method.
571 : */
572 900436 : public void add_error_type (DataType error_type) {
573 900436 : if (error_types == null) {
574 876018 : error_types = new ArrayList<DataType> ();
575 : }
576 900436 : error_types.add (error_type);
577 900436 : error_type.parent_node = this;
578 : }
579 :
580 877503 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
581 877503 : if (error_types != null) {
582 73718 : foreach (var error_type in error_types) {
583 41003 : if (source_reference != null) {
584 16307 : var type = error_type.copy ();
585 16307 : type.source_reference = source_reference;
586 16307 : collection.add (type);
587 : } else {
588 8389 : collection.add (error_type);
589 : }
590 : }
591 : }
592 : }
593 :
594 0 : public override void replace_expression (Expression old_node, Expression new_node) {
595 0 : if (preconditions != null) {
596 0 : var index = preconditions.index_of (old_node);
597 0 : if (index >= 0) {
598 0 : preconditions[index] = new_node;
599 0 : new_node.parent_node = this;
600 : }
601 : }
602 0 : if (postconditions != null) {
603 0 : var index = postconditions.index_of (old_node);
604 0 : if (index >= 0) {
605 0 : postconditions[index] = new_node;
606 0 : new_node.parent_node = this;
607 : }
608 : }
609 : }
610 :
611 4697552 : public override void replace_type (DataType old_type, DataType new_type) {
612 4697552 : if (base_interface_type == old_type) {
613 12 : base_interface_type = new_type;
614 12 : return;
615 : }
616 4697540 : if (return_type == old_type) {
617 3861306 : return_type = new_type;
618 3861306 : return;
619 : }
620 836234 : if (error_types != null) {
621 858922 : for (int i = 0; i < error_types.size; i++) {
622 858922 : if (error_types[i] == old_type) {
623 836234 : error_types[i] = new_type;
624 836234 : return;
625 : }
626 : }
627 : }
628 : }
629 :
630 27371743 : private void find_base_methods () {
631 27371743 : if (base_methods_valid) {
632 : return;
633 : }
634 :
635 6000406 : if (parent_symbol is Class) {
636 3896240 : if (!(this is CreationMethod)) {
637 3398115 : find_base_interface_method ((Class) parent_symbol);
638 3398115 : if (is_virtual || is_abstract || overrides) {
639 327828 : find_base_class_method ((Class) parent_symbol);
640 : }
641 : }
642 2104166 : } else if (parent_symbol is Interface) {
643 554004 : if (is_virtual || is_abstract) {
644 380411 : _base_interface_method = this;
645 : }
646 : }
647 :
648 6000406 : base_methods_valid = true;
649 : }
650 :
651 382493 : private void find_base_class_method (Class cl) {
652 355119 : var sym = cl.scope.lookup (name);
653 355119 : if (sym is Signal) {
654 79187 : unowned Signal sig = (Signal) sym;
655 158374 : sym = sig.default_handler;
656 : }
657 355119 : if (sym is Method) {
658 342511 : unowned Method base_method = (Method) sym;
659 342511 : if (base_method.is_abstract || base_method.is_virtual) {
660 : string invalid_match;
661 327745 : if (!compatible (base_method, out invalid_match)) {
662 3 : error = true;
663 3 : var base_method_type = new MethodType (base_method);
664 3 : Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.", get_full_name (), base_method_type.to_prototype_string (), invalid_match);
665 3 : return;
666 : }
667 :
668 327742 : _base_method = base_method;
669 327742 : copy_attribute_double (base_method, "CCode", "instance_pos");
670 327742 : copy_attribute_bool (base_method, "CCode", "returns_floating_reference");
671 327742 : return;
672 : }
673 : }
674 :
675 27374 : if (cl.base_class != null) {
676 27291 : find_base_class_method (cl.base_class);
677 : }
678 : }
679 :
680 6779348 : private void find_base_interface_method (Class cl) {
681 3398115 : Method? base_match = null;
682 :
683 3398115 : string? invalid_error = null;
684 3398115 : Method? invalid_base_match = null;
685 :
686 8866187 : foreach (DataType type in cl.get_base_types ()) {
687 3821874 : if (type.type_symbol is Interface) {
688 1087841 : if (base_interface_type != null && base_interface_type.type_symbol != type.type_symbol) {
689 4 : continue;
690 : }
691 :
692 1087837 : var sym = type.type_symbol.scope.lookup (name);
693 1087837 : if (sym is Signal) {
694 1 : unowned Signal sig = (Signal) sym;
695 2 : sym = sig.default_handler;
696 : }
697 1087837 : if (sym is Method) {
698 31241 : unowned Method base_method = (Method) sym;
699 31246 : if (base_method.is_abstract || base_method.is_virtual) {
700 16886 : if (base_interface_type == null) {
701 : // check for existing explicit implementation
702 16875 : var has_explicit_implementation = false;
703 311119 : foreach (var m in cl.get_methods ()) {
704 147124 : if (m.base_interface_type != null && base_method == m.base_interface_method) {
705 2 : has_explicit_implementation = true;
706 2 : break;
707 : }
708 : }
709 2 : if (has_explicit_implementation) {
710 2 : continue;
711 : }
712 : }
713 :
714 16884 : string invalid_match = null;
715 16884 : if (!compatible (base_method, out invalid_match)) {
716 10 : invalid_error = invalid_match;
717 5 : invalid_base_match = base_method;
718 : } else {
719 16879 : base_match = base_method;
720 16879 : break;
721 : }
722 : }
723 : }
724 : }
725 : }
726 :
727 3398115 : if (base_match != null) {
728 16879 : _base_interface_method = base_match;
729 16879 : copy_attribute_double (base_match, "CCode", "instance_pos");
730 16879 : copy_attribute_bool (base_match, "CCode", "returns_floating_reference");
731 16879 : return;
732 3381236 : } else if (!hides && invalid_base_match != null) {
733 3 : error = true;
734 3 : var base_method_type = new MethodType (invalid_base_match);
735 3 : Report.error (source_reference, "overriding method `%s' is incompatible with base method `%s': %s.", get_full_name (), base_method_type.to_prototype_string (), invalid_error);
736 3 : return;
737 : }
738 :
739 3381233 : if (base_interface_type != null) {
740 1 : Report.error (source_reference, "`%s': no suitable interface method found to implement", get_full_name ());
741 : }
742 : }
743 :
744 23005658 : public override bool check (CodeContext context) {
745 5840406 : if (checked) {
746 177972 : return !error;
747 : }
748 :
749 5662434 : checked = true;
750 :
751 5662434 : if (this_parameter != null) {
752 4216594 : this_parameter.check (context);
753 : }
754 :
755 5662434 : if (has_attribute ("DestroysInstance")) {
756 26981 : this_parameter.variable_type.value_owned = true;
757 : }
758 5662434 : if (has_attribute ("NoThrow")) {
759 0 : error_types = null;
760 : }
761 :
762 5662434 : if (parent_symbol is Class && (is_abstract || is_virtual)) {
763 314459 : unowned Class cl = (Class) parent_symbol;
764 314459 : if (cl.is_compact && cl.base_class != null) {
765 1 : error = true;
766 1 : Report.error (source_reference, "Abstract and virtual methods may not be declared in derived compact classes");
767 1 : return false;
768 : }
769 314458 : if (cl.is_opaque) {
770 1 : error = true;
771 1 : Report.error (source_reference, "Abstract and virtual methods may not be declared in opaque compact classes");
772 1 : return false;
773 : }
774 : }
775 :
776 5662432 : if (is_variadic () && (is_abstract || is_virtual)) {
777 2 : error = true;
778 2 : Report.error (source_reference, "Abstract and virtual methods may not be variadic. Use a `va_list' parameter instead of `...' or params-array.");
779 2 : return false;
780 : }
781 :
782 5662430 : if (has_attribute ("NoWrapper") && !(is_abstract || is_virtual)) {
783 1 : error = true;
784 1 : Report.error (source_reference, "[NoWrapper] methods must be declared abstract or virtual");
785 1 : return false;
786 : }
787 :
788 5662429 : if (is_abstract) {
789 300601 : if (parent_symbol is Class) {
790 9037 : unowned Class cl = (Class) parent_symbol;
791 9037 : if (!cl.is_abstract) {
792 1 : error = true;
793 1 : Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
794 1 : return false;
795 : }
796 291564 : } else if (!(parent_symbol is Interface)) {
797 1 : error = true;
798 1 : Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
799 1 : return false;
800 : }
801 5361828 : } else if (is_virtual) {
802 394255 : if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
803 1 : error = true;
804 1 : Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
805 1 : return false;
806 : }
807 4967573 : } else if (overrides) {
808 13291 : if (!(parent_symbol is Class)) {
809 1 : error = true;
810 1 : Report.error (source_reference, "Methods may not be overridden outside of classes");
811 1 : return false;
812 : }
813 4954282 : } else if (access == SymbolAccessibility.PROTECTED) {
814 245 : if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
815 1 : error = true;
816 1 : Report.error (source_reference, "Protected methods may not be declared outside of classes and interfaces");
817 1 : return false;
818 : }
819 : }
820 :
821 5662424 : if (is_abstract && body != null) {
822 1 : error = true;
823 1 : Report.error (source_reference, "Abstract methods cannot have bodies");
824 5662423 : } else if ((is_abstract || is_virtual) && is_extern) {
825 2 : error = true;
826 2 : Report.error (source_reference, "Extern methods cannot be abstract or virtual");
827 5662421 : } else if (is_extern && body != null) {
828 1 : error = true;
829 1 : Report.error (source_reference, "Extern methods cannot have bodies");
830 5662420 : } else if (!is_abstract && !external && source_type == SourceFileType.SOURCE && body == null) {
831 2 : error = true;
832 2 : Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
833 : }
834 :
835 : // auto-convert main block to async if a yield expression is used
836 5662424 : if (is_main_block && body != null) {
837 41 : body.accept (new TraverseVisitor (node => {
838 36 : if (!(node is Statement || node is Expression || node is Variable || node is CatchClause)) {
839 6 : return TraverseStatus.STOP;
840 : }
841 33 : if (node is YieldStatement
842 32 : || (node is MethodCall && ((MethodCall) node).is_yield_expression)
843 31 : || (node is ObjectCreationExpression && ((ObjectCreationExpression) node).is_yield_expression)) {
844 3 : coroutine = true;
845 3 : return TraverseStatus.STOP;
846 : }
847 36 : return TraverseStatus.CONTINUE;
848 : }));
849 : }
850 :
851 5662424 : if (coroutine && !external_package && !context.has_package ("gio-2.0")) {
852 0 : error = true;
853 0 : Report.error (source_reference, "gio-2.0 package required for async methods");
854 0 : return false;
855 : }
856 :
857 5662424 : var old_source_file = context.analyzer.current_source_file;
858 5662424 : var old_symbol = context.analyzer.current_symbol;
859 :
860 5662424 : if (source_reference != null) {
861 5662310 : context.analyzer.current_source_file = source_reference.file;
862 : }
863 5662424 : context.analyzer.current_symbol = this;
864 :
865 5662424 : return_type.floating_reference = returns_floating_reference;
866 5662424 : return_type.check (context);
867 5662424 : if (!external_package) {
868 5801 : context.analyzer.check_type (return_type);
869 5801 : return_type.check_type_arguments (context, !(return_type is DelegateType));
870 : }
871 :
872 5662424 : if (return_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
873 1 : error = true;
874 1 : Report.error (source_reference, "`%s' not supported as return type", return_type.type_symbol.get_full_name ());
875 1 : return false;
876 : }
877 :
878 5662423 : if (has_attribute ("ModuleInit")) {
879 1 : source_reference.file.context.module_init_method = this;
880 : }
881 :
882 5662423 : if (parameters.size == 1 && parameters[0].ellipsis && body != null && binding != MemberBinding.INSTANCE) {
883 : // accept just `...' for external methods and instance methods
884 1 : error = true;
885 1 : Report.error (parameters[0].source_reference, "Named parameter required before `...'");
886 : }
887 :
888 5662423 : if (has_attribute ("Print") && (parameters.size != 1 || parameters[0].variable_type.type_symbol != context.analyzer.string_type.type_symbol)) {
889 1 : error = true;
890 1 : Report.error (source_reference, "[Print] methods must have exactly one parameter of type `string'");
891 : }
892 :
893 : // Collect generic type references
894 : // TODO Can this be done in the SymbolResolver?
895 5662423 : List<GenericType> referenced_generics = new ArrayList<GenericType> ();
896 20223033 : var traverse = new TraverseVisitor (node => {
897 14560610 : if (node is GenericType) {
898 650408 : referenced_generics.add ((GenericType) node);
899 650408 : return TraverseStatus.STOP;
900 : }
901 14560610 : return TraverseStatus.CONTINUE;
902 : });
903 :
904 5756417 : foreach (TypeParameter p in get_type_parameters ()) {
905 46997 : if (!p.check (context)) {
906 0 : error = true;
907 : }
908 : }
909 :
910 5662423 : return_type.accept (traverse);
911 :
912 5662423 : var optional_param = false;
913 5662423 : var params_array_param = false;
914 5662423 : var ellipsis_param = false;
915 19142310 : foreach (Parameter param in parameters) {
916 7048115 : if (!param.check (context)) {
917 10 : error = true;
918 10 : continue;
919 : }
920 7048105 : if (coroutine && param.direction == ParameterDirection.REF) {
921 1 : error = true;
922 1 : Report.error (param.source_reference, "Reference parameters are not supported for async methods");
923 : }
924 7048105 : if (!external_package && coroutine && (param.ellipsis || param.params_array || param.variable_type.type_symbol == context.analyzer.va_list_type.type_symbol)) {
925 3 : error = true;
926 3 : Report.error (param.source_reference, "Variadic parameters are not supported for async methods");
927 3 : return false;
928 : }
929 :
930 7048102 : param.accept_children (traverse);
931 :
932 : // TODO: begin and end parameters must be checked separately for coroutines
933 7048102 : if (coroutine) {
934 616326 : continue;
935 : }
936 6431776 : if (optional_param && param.initializer == null && !param.ellipsis) {
937 0 : Report.warning (param.source_reference, "parameter without default follows parameter with default");
938 6431776 : } else if (param.initializer != null) {
939 643594 : optional_param = true;
940 : }
941 :
942 : // Disallow parameter after params array or ellipsis
943 6431776 : if (params_array_param) {
944 2 : Report.error (param.source_reference, "parameter follows params-array parameter");
945 6431774 : } else if (param.params_array) {
946 2890 : params_array_param = true;
947 : }
948 6431776 : if (ellipsis_param) {
949 1 : Report.error (param.source_reference, "parameter follows ellipsis parameter");
950 6431775 : } else if (param.ellipsis) {
951 104312 : ellipsis_param = true;
952 : }
953 :
954 : // Add local variable to provide access to params arrays which will be constructed out of the given va-args
955 6431795 : if (param.params_array && body != null) {
956 20 : if (params_array_var != null) {
957 1 : error = true;
958 1 : Report.error (param.source_reference, "Only one params-array parameter is allowed");
959 1 : continue;
960 : }
961 19 : if (!context.experimental) {
962 19 : Report.warning (param.source_reference, "Support of params-arrays is experimental");
963 : }
964 19 : var type = (ArrayType) param.variable_type.copy ();
965 19 : type.element_type.value_owned = type.value_owned;
966 19 : type.value_owned = true;
967 19 : if (type.element_type.is_real_struct_type () && !type.element_type.nullable) {
968 1 : error = true;
969 1 : Report.error (param.source_reference, "Only nullable struct elements are supported in params-array");
970 : }
971 19 : if (type.length != null) {
972 1 : error = true;
973 1 : Report.error (param.source_reference, "Passing length to params-array is not supported yet");
974 : }
975 19 : params_array_var = new LocalVariable (type, param.name, null, param.source_reference);
976 19 : body.insert_statement (0, new DeclarationStatement (params_array_var, param.source_reference));
977 : }
978 : }
979 :
980 : // Check if referenced type-parameters are present
981 : // TODO Can this be done in the SymbolResolver?
982 5746072 : if (binding == MemberBinding.STATIC && parent_symbol is Class && !((Class) parent_symbol).is_compact) {
983 83652 : Iterator<GenericType> ref_generics_it = referenced_generics.iterator ();
984 83660 : while (ref_generics_it.next ()) {
985 4 : var ref_generics = ref_generics_it.get ();
986 4 : foreach (var type_param in get_type_parameters ()) {
987 0 : if (ref_generics.type_parameter.name == type_param.name) {
988 0 : ref_generics_it.remove ();
989 : }
990 : }
991 : }
992 83660 : foreach (var type in referenced_generics) {
993 4 : error = true;
994 4 : Report.error (type.source_reference, "The type name `%s' could not be found", type.type_parameter.name);
995 : }
996 : }
997 :
998 5662420 : if (coroutine) {
999 : // TODO: async methods with out-parameters before in-parameters are not supported
1000 189758 : bool requires_pointer = false;
1001 1422406 : for (int i = parameters.size - 1; i >= 0; i--) {
1002 616324 : var param = parameters[i];
1003 616324 : if (param.direction == ParameterDirection.IN) {
1004 : requires_pointer = true;
1005 41899 : } else if (requires_pointer) {
1006 1 : error = true;
1007 1 : Report.error (param.source_reference, "Synchronous out-parameters are not supported in async methods");
1008 : }
1009 : }
1010 : }
1011 :
1012 5662420 : if (error_types != null) {
1013 2306143 : foreach (DataType error_type in error_types) {
1014 776246 : if (!(error_type is ErrorType)) {
1015 1 : error = true;
1016 1 : Report.error (error_type.source_reference, "`%s' is not an error type", error_type.to_string ());
1017 : }
1018 776246 : error_type.check (context);
1019 :
1020 : // check whether error type is at least as accessible as the method
1021 776246 : if (!error_type.is_accessible (this)) {
1022 1 : error = true;
1023 1 : Report.error (source_reference, "error type `%s' is less accessible than method `%s'", error_type.to_string (), get_full_name ());
1024 1 : return false;
1025 : }
1026 : }
1027 : }
1028 :
1029 5662419 : if (result_var != null) {
1030 14 : result_var.check (context);
1031 : }
1032 :
1033 5662419 : if (preconditions != null) {
1034 36 : foreach (Expression precondition in preconditions) {
1035 12 : precondition.check (context);
1036 : }
1037 : }
1038 :
1039 5662419 : if (postconditions != null) {
1040 63 : foreach (Expression postcondition in postconditions) {
1041 21 : postcondition.check (context);
1042 : }
1043 : }
1044 :
1045 5662419 : if (body != null) {
1046 124544 : body.check (context);
1047 : }
1048 :
1049 5662419 : if (overrides && base_method == null && base_interface_method != null && base_interface_method.is_abstract) {
1050 1 : Report.warning (source_reference, "`override' not required to implement `abstract' interface method `%s'", base_interface_method.get_full_name ());
1051 1 : overrides = false;
1052 5662418 : } else if (!error && overrides && base_method == null && base_interface_method == null) {
1053 0 : error = true;
1054 0 : Report.error (source_reference, "`%s': no suitable method found to override", get_full_name ());
1055 5662418 : } else if ((is_abstract || is_virtual || overrides) && access == SymbolAccessibility.PRIVATE) {
1056 3 : error = true;
1057 3 : Report.error (source_reference, "Private member `%s' cannot be marked as override, virtual, or abstract", get_full_name ());
1058 3 : return false;
1059 : }
1060 :
1061 5662416 : if (base_interface_type != null && base_interface_method != null && parent_symbol is Class) {
1062 10 : unowned Class cl = (Class) parent_symbol;
1063 64 : foreach (var m in cl.get_methods ()) {
1064 28 : if (m != this && m.base_interface_method == base_interface_method) {
1065 1 : m.checked = true;
1066 1 : m.error = true;
1067 1 : error = true;
1068 1 : Report.error (source_reference, "`%s' already contains an implementation for `%s'", cl.get_full_name (), base_interface_method.get_full_name ());
1069 1 : Report.notice (m.source_reference, "previous implementation of `%s' was here", base_interface_method.get_full_name ());
1070 1 : return false;
1071 : }
1072 : }
1073 : }
1074 :
1075 5662415 : context.analyzer.current_source_file = old_source_file;
1076 5662415 : context.analyzer.current_symbol = old_symbol;
1077 :
1078 5662415 : if (!external_package && !overrides && !hides && get_hidden_member () != null) {
1079 7 : Report.warning (source_reference, "%s hides inherited method `%s'. Use the `new' keyword if hiding was intentional", get_full_name (), get_hidden_member ().get_full_name ());
1080 : }
1081 :
1082 : // check whether return type is at least as accessible as the method
1083 5662415 : if (!return_type.is_accessible (this)) {
1084 1 : error = true;
1085 1 : Report.error (source_reference, "return type `%s' is less accessible than method `%s'", return_type.to_string (), get_full_name ());
1086 1 : return false;
1087 : }
1088 :
1089 5662436 : foreach (Expression precondition in get_preconditions ()) {
1090 12 : if (precondition.error) {
1091 : // if there was an error in the precondition, skip this check
1092 0 : error = true;
1093 0 : return false;
1094 : }
1095 :
1096 12 : if (!precondition.value_type.compatible (context.analyzer.bool_type)) {
1097 1 : error = true;
1098 1 : Report.error (precondition.source_reference, "Precondition must be boolean");
1099 1 : return false;
1100 : }
1101 : }
1102 :
1103 5662453 : foreach (Expression postcondition in get_postconditions ()) {
1104 21 : if (postcondition.error) {
1105 : // if there was an error in the postcondition, skip this check
1106 0 : error = true;
1107 0 : return false;
1108 : }
1109 :
1110 21 : if (!postcondition.value_type.compatible (context.analyzer.bool_type)) {
1111 1 : error = true;
1112 1 : Report.error (postcondition.source_reference, "Postcondition must be boolean");
1113 1 : return false;
1114 : }
1115 : }
1116 :
1117 : // check that all errors that can be thrown in the method body are declared
1118 5786714 : if (body != null && !body.error) {
1119 124302 : var body_errors = new ArrayList<DataType> ();
1120 124302 : body.get_error_types (body_errors);
1121 125126 : foreach (DataType body_error_type in body_errors) {
1122 412 : bool can_propagate_error = false;
1123 412 : if (error_types != null) {
1124 650 : foreach (DataType method_error_type in error_types) {
1125 217 : if (body_error_type.compatible (method_error_type)) {
1126 217 : can_propagate_error = true;
1127 : }
1128 : }
1129 : }
1130 412 : bool is_dynamic_error = body_error_type is ErrorType && ((ErrorType) body_error_type).dynamic_error;
1131 412 : if (!can_propagate_error && !is_dynamic_error) {
1132 196 : Report.warning (body_error_type.source_reference, "unhandled error `%s'", body_error_type.to_string());
1133 : }
1134 : }
1135 : }
1136 :
1137 : // check that DBus methods at least throw "GLib.Error" or "GLib.DBusError, GLib.IOError"
1138 9324772 : if (!(this is CreationMethod) && binding == MemberBinding.INSTANCE
1139 4216282 : && !overrides && access == SymbolAccessibility.PUBLIC
1140 4188845 : && parent_symbol is ObjectTypeSymbol && parent_symbol.has_attribute ("DBus")) {
1141 96 : Attribute? dbus_attr = get_attribute ("DBus");
1142 190 : if (dbus_attr == null || dbus_attr.get_bool ("visible", true)) {
1143 94 : bool throws_gerror = false;
1144 94 : bool throws_gioerror = false;
1145 94 : bool throws_gdbuserror = false;
1146 94 : var error_types = new ArrayList<DataType> ();
1147 94 : get_error_types (error_types);
1148 228 : foreach (DataType error_type in error_types) {
1149 86 : if (!(error_type is ErrorType)) {
1150 0 : continue;
1151 : }
1152 86 : unowned ErrorDomain? error_domain = ((ErrorType) error_type).error_domain;
1153 86 : if (error_domain == null) {
1154 19 : throws_gerror = true;
1155 19 : break;
1156 : }
1157 67 : string? full_error_domain = error_domain.get_full_name ();
1158 67 : if (full_error_domain == "GLib.IOError") {
1159 : throws_gioerror = true;
1160 22 : } else if (full_error_domain == "GLib.DBusError") {
1161 20 : throws_gdbuserror = true;
1162 : }
1163 : }
1164 94 : if (!throws_gerror && !(throws_gioerror && throws_gdbuserror)) {
1165 58 : Report.warning (source_reference, "DBus methods are recommended to throw at least `GLib.Error' or `GLib.DBusError, GLib.IOError'");
1166 : }
1167 : }
1168 : }
1169 :
1170 5662412 : if (is_possible_entry_point (context)) {
1171 1342 : if (context.entry_point != null) {
1172 1 : error = true;
1173 1 : Report.error (source_reference, "program already has an entry point `%s'", context.entry_point.get_full_name ());
1174 1 : return false;
1175 : }
1176 1341 : entry_point = true;
1177 1341 : context.entry_point = this;
1178 :
1179 1341 : if (tree_can_fail) {
1180 1 : error = true;
1181 1 : Report.error (source_reference, "\"main\" method cannot throw errors");
1182 : }
1183 :
1184 1341 : if (is_inline) {
1185 1 : error = true;
1186 1 : Report.error (source_reference, "\"main\" method cannot be inline");
1187 : }
1188 : }
1189 :
1190 5662411 : if (has_attribute ("GtkCallback")) {
1191 5 : used = true;
1192 : }
1193 :
1194 5662411 : return !error;
1195 : }
1196 :
1197 5662412 : bool is_possible_entry_point (CodeContext context) {
1198 5662412 : if (external_package) {
1199 5661070 : return false;
1200 : }
1201 :
1202 5789 : if (context.entry_point_name == null) {
1203 5789 : if (name == null || name != "main") {
1204 : // method must be called "main"
1205 4447 : return false;
1206 : }
1207 : } else {
1208 : // custom entry point name
1209 0 : if (get_full_name () != context.entry_point_name) {
1210 5661070 : return false;
1211 : }
1212 : }
1213 :
1214 1342 : if (binding == MemberBinding.INSTANCE) {
1215 : // method must be static
1216 5661070 : return false;
1217 : }
1218 :
1219 1342 : if (return_type is VoidType) {
1220 20 : } else if (return_type.type_symbol == context.analyzer.int_type.type_symbol) {
1221 : } else {
1222 : // return type must be void or int
1223 5661070 : return false;
1224 : }
1225 :
1226 1342 : var params = get_parameters ();
1227 1342 : if (params.size == 0) {
1228 : // method may have no parameters
1229 1248 : return true;
1230 : }
1231 :
1232 94 : if (params.size > 1) {
1233 : // method must not have more than one parameter
1234 0 : return false;
1235 : }
1236 :
1237 94 : Iterator<Parameter> params_it = params.iterator ();
1238 94 : params_it.next ();
1239 94 : var param = params_it.get ();
1240 :
1241 94 : if (param.direction == ParameterDirection.OUT) {
1242 : // parameter must not be an out parameter
1243 0 : return false;
1244 : }
1245 :
1246 94 : if (!(param.variable_type is ArrayType)) {
1247 : // parameter must be an array
1248 0 : return false;
1249 : }
1250 :
1251 94 : unowned ArrayType array_type = (ArrayType) param.variable_type;
1252 94 : if (array_type.element_type.type_symbol != context.analyzer.string_type.type_symbol) {
1253 : // parameter must be an array of strings
1254 0 : return false;
1255 : }
1256 :
1257 94 : return true;
1258 : }
1259 :
1260 557 : public int get_required_arguments () {
1261 557 : int n = 0;
1262 559 : foreach (var param in parameters) {
1263 325 : if (param.initializer != null || param.ellipsis) {
1264 : // optional argument
1265 324 : break;
1266 : }
1267 1 : n++;
1268 : }
1269 : return n;
1270 : }
1271 :
1272 22 : public unowned Method get_end_method () {
1273 22 : assert (this.coroutine);
1274 :
1275 22 : if (end_method == null) {
1276 21 : end_method = new Method ("end", return_type, source_reference);
1277 21 : end_method.access = SymbolAccessibility.PUBLIC;
1278 21 : end_method.external = true;
1279 21 : end_method.owner = scope;
1280 69 : foreach (var param in get_async_end_parameters ()) {
1281 24 : end_method.add_parameter (param.copy ());
1282 : }
1283 27 : foreach (var param in get_type_parameters ()) {
1284 3 : end_method.add_type_parameter (param);
1285 : }
1286 21 : end_method.copy_attribute_double (this, "CCode", "async_result_pos");
1287 : }
1288 22 : return end_method;
1289 : }
1290 :
1291 61 : public unowned Method get_callback_method () {
1292 61 : assert (this.coroutine);
1293 :
1294 84 : if (callback_method == null) {
1295 23 : var bool_type = CodeContext.get ().analyzer.bool_type.copy ();
1296 23 : bool_type.value_owned = true;
1297 23 : callback_method = new Method ("callback", bool_type, source_reference);
1298 23 : callback_method.access = SymbolAccessibility.PUBLIC;
1299 23 : callback_method.external = true;
1300 23 : callback_method.binding = MemberBinding.INSTANCE;
1301 23 : callback_method.owner = scope;
1302 23 : callback_method.is_async_callback = true;
1303 : }
1304 61 : return callback_method;
1305 : }
1306 :
1307 209 : public unowned List<Parameter> get_async_begin_parameters () {
1308 209 : assert (this.coroutine);
1309 :
1310 209 : if (async_begin_parameters != null) {
1311 209 : return async_begin_parameters;
1312 : }
1313 :
1314 93 : async_begin_parameters = new ArrayList<Parameter> ();
1315 :
1316 93 : var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1317 :
1318 93 : Parameter ellipsis = null;
1319 265 : foreach (var param in parameters) {
1320 86 : if (param.ellipsis) {
1321 0 : ellipsis = param;
1322 86 : } else if (param.direction == ParameterDirection.IN) {
1323 71 : async_begin_parameters.add (param);
1324 : }
1325 : }
1326 :
1327 93 : var callback_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("AsyncReadyCallback"), source_reference);
1328 93 : callback_type.nullable = true;
1329 93 : callback_type.value_owned = true;
1330 93 : callback_type.is_called_once = true;
1331 :
1332 93 : var callback_param = new Parameter ("_callback_", callback_type, source_reference);
1333 93 : callback_param.initializer = new NullLiteral (source_reference);
1334 93 : callback_param.initializer.target_type = callback_type.copy ();
1335 93 : callback_param.set_attribute_double ("CCode", "pos", -1);
1336 93 : callback_param.set_attribute_double ("CCode", "delegate_target_pos", -0.9);
1337 93 : scope.add (null, callback_param);
1338 93 : async_begin_parameters.add (callback_param);
1339 :
1340 93 : if (ellipsis != null) {
1341 0 : async_begin_parameters.add (ellipsis);
1342 : }
1343 :
1344 93 : return async_begin_parameters;
1345 : }
1346 :
1347 100 : public unowned List<Parameter> get_async_end_parameters () {
1348 100 : assert (this.coroutine);
1349 :
1350 100 : if (async_end_parameters != null) {
1351 100 : return async_end_parameters;
1352 : }
1353 :
1354 41 : async_end_parameters = new ArrayList<Parameter> ();
1355 :
1356 41 : var glib_ns = CodeContext.get ().root.scope.lookup ("GLib");
1357 41 : var result_type = new ObjectType ((ObjectTypeSymbol) glib_ns.scope.lookup ("AsyncResult"));
1358 :
1359 41 : var result_param = new Parameter ("_res_", result_type, source_reference);
1360 41 : result_param.set_attribute_double ("CCode", "pos", get_attribute_double ("CCode", "async_result_pos", 0.1));
1361 41 : scope.add (null, result_param);
1362 41 : async_end_parameters.add (result_param);
1363 :
1364 131 : foreach (var param in parameters) {
1365 45 : if (param.direction == ParameterDirection.OUT) {
1366 15 : async_end_parameters.add (param);
1367 : }
1368 : }
1369 :
1370 41 : return async_end_parameters;
1371 : }
1372 :
1373 91 : public void add_captured_variable (LocalVariable local) {
1374 91 : assert (this.closure);
1375 :
1376 91 : if (captured_variables == null) {
1377 72 : captured_variables = new ArrayList<LocalVariable> ();
1378 : }
1379 91 : captured_variables.add (local);
1380 : }
1381 :
1382 15776 : public void get_captured_variables (Collection<LocalVariable> variables) {
1383 15776 : if (captured_variables != null) {
1384 980 : foreach (var local in captured_variables) {
1385 352 : variables.add (local);
1386 : }
1387 : }
1388 : }
1389 :
1390 263520 : public override void get_defined_variables (Collection<Variable> collection) {
1391 263520 : if (result_var != null) {
1392 42 : collection.add (result_var);
1393 : }
1394 263520 : if (params_array_var != null) {
1395 66 : collection.add (params_array_var);
1396 : }
1397 :
1398 : // capturing variables is only supported if they are initialized
1399 : // therefore assume that captured variables are initialized
1400 263520 : if (closure) {
1401 11832 : get_captured_variables ((Collection<LocalVariable>) collection);
1402 : }
1403 : }
1404 :
1405 33148 : public int get_format_arg_index () {
1406 60044 : for (int i = 0; i < parameters.size; i++) {
1407 26955 : if (parameters[i].format_arg) {
1408 59 : return i;
1409 : }
1410 : }
1411 33148 : return -1;
1412 : }
1413 :
1414 50017 : public bool has_error_type_parameter () {
1415 50017 : if (tree_can_fail) {
1416 : return true;
1417 : }
1418 48821 : if (base_method != null && base_method != this && base_method.has_error_type_parameter ()) {
1419 : return true;
1420 : }
1421 48812 : if (base_interface_method != null && base_interface_method != this && base_interface_method.has_error_type_parameter ()) {
1422 : return true;
1423 : }
1424 : return false;
1425 : }
1426 : }
1427 :
1428 : // vim:sw=8 noet
|