Line data Source code
1 : /* valamethodcall.vala
2 : *
3 : * Copyright (C) 2006-2012 Jürg Billeter
4 : *
5 : * This library is free software; you can redistribute it and/or
6 : * modify it under the terms of the GNU Lesser General Public
7 : * License as published by the Free Software Foundation; either
8 : * version 2.1 of the License, or (at your option) any later version.
9 :
10 : * This library is distributed in the hope that it will be useful,
11 : * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 : * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 : * Lesser General Public License for more details.
14 :
15 : * You should have received a copy of the GNU Lesser General Public
16 : * License along with this library; if not, write to the Free Software
17 : * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 : *
19 : * Author:
20 : * Jürg Billeter <j@bitron.ch>
21 : */
22 :
23 : using GLib;
24 :
25 : /**
26 : * Represents an invocation expression in the source code.
27 : */
28 449498 : public class Vala.MethodCall : Expression, CallableExpression {
29 : /**
30 : * The method to call.
31 : */
32 : public Expression call {
33 5468889 : get { return _call; }
34 : }
35 :
36 222677 : public bool is_yield_expression { get; set; }
37 :
38 40135 : public bool is_assert { get; private set; }
39 :
40 : /**
41 : * Whether this chain up uses the constructv function with va_list.
42 : */
43 30212 : public bool is_constructv_chainup { get; private set; }
44 :
45 767803 : public bool is_chainup { get; set; }
46 :
47 223212 : private Expression _call;
48 :
49 446424 : private List<Expression> argument_list = new ArrayList<Expression> ();
50 :
51 : /**
52 : * Creates a new invocation expression.
53 : *
54 : * @param call method to call
55 : * @param source_reference reference to source code
56 : * @return newly created invocation expression
57 : */
58 669636 : public MethodCall (Expression call, SourceReference? source_reference = null) {
59 223212 : this.source_reference = source_reference;
60 1005798 : this._call = call;
61 223212 : this._call.parent_node = this;
62 : }
63 :
64 : /**
65 : * Appends the specified expression to the list of arguments.
66 : *
67 : * @param arg an argument
68 : */
69 337898 : public void add_argument (Expression arg) {
70 337898 : argument_list.add (arg);
71 337898 : arg.parent_node = this;
72 : }
73 :
74 : /**
75 : * Returns the argument list.
76 : *
77 : * @return argument list
78 : */
79 73414 : public unowned List<Expression> get_argument_list () {
80 73414 : return argument_list;
81 : }
82 :
83 869040 : public override void accept (CodeVisitor visitor) {
84 869040 : visitor.visit_method_call (this);
85 :
86 869040 : visitor.visit_expression (this);
87 : }
88 :
89 869039 : public override void accept_children (CodeVisitor visitor) {
90 869039 : call.accept (visitor);
91 :
92 3736699 : foreach (Expression expr in argument_list) {
93 1433830 : expr.accept (visitor);
94 : }
95 : }
96 :
97 10450 : public override void replace_expression (Expression old_node, Expression new_node) {
98 10450 : if (call == old_node) {
99 5 : _call = new_node;
100 : }
101 :
102 10450 : int index = argument_list.index_of (old_node);
103 10450 : if (index >= 0) {
104 10445 : argument_list[index] = new_node;
105 10445 : new_node.parent_node = this;
106 : }
107 : }
108 :
109 546 : public override bool is_constant () {
110 546 : unowned MethodType? method_type = call.value_type as MethodType;
111 :
112 546 : if (method_type != null) {
113 : // N_ and NC_ do not have any effect on the C code,
114 : // they are only interpreted by xgettext
115 : // this means that it is ok to use them in constant initializers
116 546 : if (method_type.method_symbol.get_full_name () == "GLib.N_") {
117 : // first argument is string
118 7 : return argument_list[0].is_constant ();
119 539 : } else if (method_type.method_symbol.get_full_name () == "GLib.NC_") {
120 : // first and second argument is string
121 2 : return argument_list[0].is_constant () && argument_list[1].is_constant ();
122 : }
123 : }
124 :
125 546 : return false;
126 : }
127 :
128 0 : public override bool is_pure () {
129 0 : return false;
130 : }
131 :
132 8 : public override bool is_accessible (Symbol sym) {
133 26 : foreach (var arg in argument_list) {
134 9 : if (!arg.is_accessible (sym)) {
135 0 : return false;
136 : }
137 : }
138 :
139 8 : return call.is_accessible (sym);
140 : }
141 :
142 752571 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
143 752571 : if (source_reference == null) {
144 695060 : source_reference = this.source_reference;
145 : }
146 752571 : unowned DataType? mtype = call.value_type;
147 752571 : if (mtype is MethodType) {
148 709996 : unowned Method m = ((MethodType) mtype).method_symbol;
149 709996 : if (!(m.coroutine && !is_yield_expression && ((MemberAccess) call).member_name != "end")) {
150 709662 : m.get_error_types (collection, source_reference);
151 : }
152 42575 : } else if (mtype is ObjectType && mtype.type_symbol is Class) {
153 : // constructor
154 3132 : unowned Class cl = (Class) ((ObjectType) mtype).type_symbol;
155 3132 : unowned Method m = cl.default_construction_method;
156 3132 : m.get_error_types (collection, source_reference);
157 39443 : } else if (mtype is DelegateType) {
158 38908 : unowned Delegate d = ((DelegateType) mtype).delegate_symbol;
159 38908 : d.get_error_types (collection, source_reference);
160 : }
161 :
162 3013353 : foreach (Expression expr in argument_list) {
163 1130391 : expr.get_error_types (collection, source_reference);
164 : }
165 : }
166 :
167 201891 : public override bool check (CodeContext context) {
168 201891 : if (checked) {
169 10314 : return !error;
170 : }
171 :
172 191577 : checked = true;
173 :
174 191577 : if ((call is MemberAccess) && ((MemberAccess) call).null_safe_access) {
175 7 : error = !base.check (context);
176 7 : return !error;
177 : }
178 :
179 191570 : if (!call.check (context)) {
180 : /* if method resolving didn't succeed, skip this check */
181 23 : error = true;
182 23 : return false;
183 : }
184 :
185 : // type of target object
186 191547 : DataType target_object_type = null;
187 :
188 191547 : List<DataType> method_type_args = null;
189 :
190 191547 : if (call.value_type is DelegateType) {
191 : // delegate invocation, resolve generic types relative to delegate
192 14311 : target_object_type = call.value_type;
193 177236 : } else if (call is MemberAccess) {
194 176601 : unowned MemberAccess ma = (MemberAccess) call;
195 176601 : if (ma.prototype_access) {
196 0 : error = true;
197 0 : Report.error (source_reference, "Access to instance member `%s' denied", call.symbol_reference.get_full_name ());
198 0 : return false;
199 : }
200 :
201 368104 : method_type_args = ma.get_type_arguments ();
202 :
203 176601 : if (ma.inner != null) {
204 122424 : target_object_type = ma.inner.value_type;
205 :
206 : // foo is relevant instance in foo.bar.connect (on_bar)
207 122424 : if (ma.inner.symbol_reference is Signal) {
208 103 : unowned MemberAccess? sig = ma.inner as MemberAccess;
209 90 : if (sig != null) {
210 180 : target_object_type = sig.inner.value_type;
211 : }
212 : }
213 :
214 : // foo is relevant instance in foo.bar.begin (bar_ready) and foo.bar.end (result)
215 122424 : unowned Method? m = ma.symbol_reference as Method;
216 122279 : if (m != null && m.coroutine) {
217 : // begin or end call of async method
218 107 : if (ma.member_name == "begin" || ma.member_name == "end") {
219 74 : unowned MemberAccess? method_access = ma.inner as MemberAccess;
220 74 : if (method_access != null && method_access.inner != null) {
221 68 : target_object_type = method_access.inner.value_type;
222 : } else {
223 : // static method
224 38 : target_object_type = null;
225 : }
226 : }
227 : }
228 : }
229 :
230 176601 : if (ma.symbol_reference != null && ma.symbol_reference.has_attribute ("Assert")) {
231 10123 : this.is_assert = true;
232 :
233 10123 : if (argument_list.size == 1) {
234 10123 : this.source_reference = argument_list[0].source_reference;
235 : }
236 : }
237 : }
238 :
239 191547 : var mtype = call.value_type;
240 191547 : var gobject_chainup = (context.profile == Profile.GOBJECT && call.symbol_reference == context.analyzer.object_type);
241 191547 : is_chainup = gobject_chainup;
242 :
243 191547 : if (!gobject_chainup) {
244 191194 : unowned Expression expr = call;
245 191194 : unowned MemberAccess? ma = expr as MemberAccess;
246 190881 : if (ma != null && ma.symbol_reference is CreationMethod) {
247 1425 : expr = ma.inner;
248 1425 : ma = expr as MemberAccess;
249 : }
250 380960 : if (ma != null && ma.member_name == "this") {
251 : // this[.with_foo] ()
252 1423 : is_chainup = true;
253 189771 : } else if (expr is BaseAccess) {
254 : // base[.with_foo] ()
255 313 : is_chainup = true;
256 : }
257 : }
258 :
259 191547 : unowned CreationMethod? base_cm = null;
260 :
261 191547 : if (is_chainup) {
262 2089 : unowned CreationMethod? cm = context.analyzer.find_current_method () as CreationMethod;
263 2089 : if (cm == null) {
264 0 : error = true;
265 0 : Report.error (source_reference, "invocation not supported in this context");
266 0 : return false;
267 2089 : } else if (cm.chain_up) {
268 0 : error = true;
269 0 : Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted");
270 0 : return false;
271 : }
272 2089 : cm.chain_up = true;
273 :
274 2089 : if (mtype is ObjectType) {
275 635 : unowned Class cl = (Class) ((ObjectType) mtype).type_symbol;
276 635 : base_cm = cl.default_construction_method;
277 635 : if (base_cm == null) {
278 0 : error = true;
279 0 : Report.error (source_reference, "chain up to `%s' not supported", cl.get_full_name ());
280 0 : return false;
281 635 : } else if (!base_cm.has_construct_function) {
282 0 : error = true;
283 0 : Report.error (source_reference, "chain up to `%s' not supported", base_cm.get_full_name ());
284 0 : return false;
285 : }
286 1454 : } else if (call.symbol_reference is CreationMethod && call.symbol_reference.parent_symbol is Class) {
287 1421 : base_cm = (CreationMethod) call.symbol_reference;
288 1421 : if (!base_cm.has_construct_function) {
289 0 : error = true;
290 0 : Report.error (source_reference, "chain up to `%s' not supported", base_cm.get_full_name ());
291 0 : return false;
292 : }
293 33 : } else if (gobject_chainup) {
294 29 : unowned Class? cl = cm.parent_symbol as Class;
295 29 : if (cl == null || !cl.is_subtype_of (context.analyzer.object_type)) {
296 0 : error = true;
297 0 : Report.error (source_reference, "chain up to `GLib.Object' not supported");
298 0 : return false;
299 : }
300 29 : call.value_type = new ObjectType (context.analyzer.object_type, source_reference);
301 58 : mtype = call.value_type;
302 : }
303 :
304 2056 : if (base_cm != null && source_reference.file != base_cm.source_reference.file && base_cm.access == SymbolAccessibility.PRIVATE) {
305 0 : error = true;
306 0 : Report.error (source_reference, "chain up to private `%s' not possible", base_cm.get_full_name ());
307 0 : return false;
308 : }
309 : }
310 :
311 : // check for struct construction
312 191547 : if (call is MemberAccess &&
313 190910 : ((call.symbol_reference is CreationMethod
314 1425 : && call.symbol_reference.parent_symbol is Struct)
315 190906 : || call.symbol_reference is Struct)) {
316 121 : unowned Struct? st = call.symbol_reference as Struct;
317 117 : if (st != null && st.default_construction_method == null && (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ())) {
318 0 : error = true;
319 0 : Report.error (source_reference, "invocation not supported in this context");
320 0 : return false;
321 : }
322 :
323 121 : var struct_creation_expression = new ObjectCreationExpression ((MemberAccess) call, source_reference);
324 121 : struct_creation_expression.struct_creation = true;
325 121 : struct_creation_expression.is_chainup = is_chainup;
326 281 : foreach (Expression arg in argument_list) {
327 80 : struct_creation_expression.add_argument (arg);
328 : }
329 121 : struct_creation_expression.target_type = target_type;
330 121 : context.analyzer.replaced_nodes.add (this);
331 121 : parent_node.replace_expression (this, struct_creation_expression);
332 121 : struct_creation_expression.check (context);
333 121 : return true;
334 191426 : } else if (!is_chainup && call is MemberAccess && call.symbol_reference is CreationMethod) {
335 0 : error = true;
336 0 : Report.error (source_reference, "use `new' operator to create new objects");
337 0 : return false;
338 : }
339 :
340 191426 : if (!is_chainup && mtype is ObjectType) {
341 : // prevent funny stuff like (new Object ()) ()
342 1 : error = true;
343 1 : Report.error (source_reference, "invocation not supported in this context");
344 1 : return false;
345 191425 : } else if (mtype != null && mtype.is_invokable ()) {
346 : // call ok, expression is invokable
347 0 : } else if (call.symbol_reference is Class) {
348 0 : error = true;
349 0 : Report.error (source_reference, "use `new' operator to create new objects");
350 0 : return false;
351 : } else {
352 0 : error = true;
353 0 : Report.error (source_reference, "invocation not supported in this context");
354 0 : return false;
355 : }
356 :
357 191425 : var ret_type = mtype.get_return_type ();
358 191425 : var params = mtype.get_parameters ();
359 :
360 191425 : if (mtype is MethodType) {
361 176351 : unowned MemberAccess ma = (MemberAccess) call;
362 176351 : unowned Method m = ((MethodType) mtype).method_symbol;
363 :
364 176351 : if (m.coroutine) {
365 124 : if (!is_yield_expression) {
366 : // begin or end call of async method
367 78 : if (ma.member_name != "end") {
368 : // begin (possibly implicit)
369 56 : if (ma.member_name != "begin") {
370 5 : Report.deprecated (ma.source_reference, "implicit .begin is deprecated");
371 : }
372 112 : params = m.get_async_begin_parameters ();
373 56 : ret_type = new VoidType ();
374 : } else {
375 : // end
376 44 : params = m.get_async_end_parameters ();
377 : }
378 46 : } else if (ma.member_name == "begin" || ma.member_name == "end") {
379 1 : error = true;
380 1 : Report.error (ma.source_reference, "use of `%s' not allowed in yield statement", ma.member_name);
381 : }
382 : }
383 :
384 176351 : int n_type_params = m.get_type_parameters ().size;
385 176351 : int n_type_args = ma.get_type_arguments ().size;
386 176351 : if (n_type_args > 0 && n_type_args < n_type_params) {
387 1 : error = true;
388 1 : Report.error (ma.source_reference, "too few type arguments for `%s'", m.to_string ());
389 1 : return false;
390 176350 : } else if (n_type_args > 0 && n_type_args > n_type_params) {
391 1 : error = true;
392 1 : Report.error (ma.source_reference, "too many type arguments for `%s'", m.to_string ());
393 1 : return false;
394 : }
395 : }
396 :
397 : // FIXME partial code duplication in ObjectCreationExpression.check
398 :
399 191423 : Expression last_arg = null;
400 :
401 191423 : Iterator<Expression> arg_it = argument_list.iterator ();
402 727421 : foreach (Parameter param in params) {
403 284551 : if (!param.check (context)) {
404 0 : error = true;
405 : }
406 :
407 284551 : if (param.ellipsis) {
408 16536 : break;
409 : }
410 :
411 268015 : if (param.params_array) {
412 32 : var array_type = (ArrayType) param.variable_type;
413 112 : while (arg_it.next ()) {
414 48 : Expression arg = arg_it.get ();
415 :
416 : /* store expected type for callback parameters */
417 48 : arg.target_type = array_type.element_type;
418 48 : arg.target_type.value_owned = array_type.value_owned;
419 : }
420 16 : break;
421 : }
422 :
423 524918 : if (arg_it.next ()) {
424 256919 : Expression arg = arg_it.get ();
425 :
426 : /* store expected type for callback parameters */
427 256919 : arg.formal_target_type = param.variable_type;
428 256919 : arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, method_type_args, this);
429 :
430 513838 : last_arg = arg;
431 : }
432 : }
433 :
434 : // concatenate stringified arguments for methods with attribute [Print]
435 191426 : if (mtype is MethodType && ((MethodType) mtype).method_symbol.has_attribute ("Print")) {
436 3 : var template = new Template (source_reference);
437 25 : foreach (Expression arg in argument_list) {
438 11 : arg.parent_node = null;
439 11 : template.add_expression (arg);
440 : }
441 3 : argument_list.clear ();
442 3 : add_argument (template);
443 : }
444 :
445 : // printf arguments
446 191423 : if (mtype is MethodType && ((MethodType) mtype).method_symbol.printf_format) {
447 3289 : StringLiteral format_literal = null;
448 3289 : if (last_arg is NullLiteral) {
449 : // do not replace explicit null
450 3288 : } else if (last_arg != null) {
451 : // use last argument as format string
452 777 : format_literal = StringLiteral.get_format_literal (last_arg);
453 777 : if (format_literal == null && argument_list.size == params.size - 1) {
454 : // insert "%s" to avoid issues with embedded %
455 14 : format_literal = new StringLiteral ("\"%s\"");
456 14 : format_literal.target_type = context.analyzer.string_type.copy ();
457 14 : argument_list.insert (argument_list.size - 1, format_literal);
458 :
459 : // recreate iterator and skip to right position
460 14 : arg_it = argument_list.iterator ();
461 84 : foreach (Parameter param in params) {
462 49 : if (param.ellipsis || param.params_array) {
463 14 : break;
464 : }
465 35 : arg_it.next ();
466 : }
467 : }
468 : } else {
469 : // use instance as format string for string.printf (...)
470 2511 : unowned MemberAccess? ma = call as MemberAccess;
471 2511 : if (ma != null) {
472 2511 : format_literal = StringLiteral.get_format_literal (ma.inner);
473 : }
474 : }
475 6489 : if (format_literal != null) {
476 3203 : string format = format_literal.eval ();
477 3203 : if (!context.analyzer.check_print_format (format, arg_it, source_reference)) {
478 2 : error = true;
479 2 : return false;
480 : }
481 : }
482 : }
483 :
484 191421 : bool force_lambda_method_closure = false;
485 752043 : foreach (Expression arg in argument_list) {
486 280317 : if (!arg.check (context)) {
487 12 : error = true;
488 12 : continue;
489 : }
490 :
491 280305 : if (arg is LambdaExpression && ((LambdaExpression) arg).method.closure) {
492 280305 : force_lambda_method_closure = true;
493 : }
494 : }
495 : // force all lambda arguments using the same closure scope
496 : // TODO https://gitlab.gnome.org/GNOME/vala/issues/59
497 191421 : if (!error && force_lambda_method_closure) {
498 22835 : foreach (Expression arg in argument_list) {
499 8562 : unowned LambdaExpression? lambda = arg as LambdaExpression;
500 12822 : if (lambda != null && lambda.method.binding != MemberBinding.STATIC) {
501 4260 : lambda.method.closure = true;
502 : }
503 : }
504 : }
505 :
506 191421 : if (ret_type is VoidType) {
507 : // void return type
508 71941 : if (!(parent_node is ExpressionStatement)
509 1 : && !(parent_node is ForStatement)
510 1 : && !(parent_node is YieldStatement)) {
511 : // A void method invocation can be in the initializer or
512 : // iterator of a for statement
513 1 : error = true;
514 1 : Report.error (source_reference, "invocation of void method not allowed as expression");
515 1 : return false;
516 : }
517 : }
518 :
519 191420 : formal_value_type = ret_type.copy ();
520 191420 : value_type = formal_value_type.get_actual_type (target_object_type, method_type_args, this);
521 :
522 191420 : if (is_yield_expression) {
523 48 : if (!(mtype is MethodType) || !((MethodType) mtype).method_symbol.coroutine) {
524 2 : error = true;
525 2 : Report.error (source_reference, "yield expression requires async method");
526 : }
527 48 : if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) {
528 2 : error = true;
529 2 : Report.error (source_reference, "yield expression not available outside async method");
530 : }
531 : }
532 :
533 191420 : if (mtype is MethodType) {
534 176346 : unowned Method m = ((MethodType) mtype).method_symbol;
535 176346 : if (m.returns_floating_reference) {
536 10 : value_type.floating_reference = true;
537 : }
538 176346 : if (m.returns_modified_pointer) {
539 5711 : unowned Expression inner = ((MemberAccess) call).inner;
540 5711 : inner.lvalue = true;
541 5711 : unowned Property? prop = inner.symbol_reference as Property;
542 2 : if (prop != null && (prop.set_accessor == null || !prop.set_accessor.writable)) {
543 1 : error = true;
544 1 : Report.error (inner.source_reference, "Property `%s' is read-only", prop.get_full_name ());
545 : }
546 : }
547 : // avoid passing possible null to ref_sink_function without checking
548 176346 : if (tree_can_fail && !value_type.nullable && value_type.floating_reference && ret_type is ObjectType) {
549 0 : value_type.nullable = true;
550 : }
551 :
552 176346 : unowned Signal? sig = m.parent_symbol as Signal;
553 103 : if (sig != null && m.name == "disconnect") {
554 13 : if (!argument_list.is_empty && argument_list[0] is LambdaExpression) {
555 1 : error = true;
556 1 : Report.error (source_reference, "Cannot disconnect lambda expression from signal");
557 1 : return false;
558 : }
559 : }
560 :
561 176345 : unowned DynamicSignal? dynamic_sig = m.parent_symbol as DynamicSignal;
562 6 : if (dynamic_sig != null && dynamic_sig.handler != null) {
563 6 : dynamic_sig.return_type = dynamic_sig.handler.value_type.get_return_type ().copy ();
564 6 : bool first = true;
565 18 : foreach (Parameter param in dynamic_sig.handler.value_type.get_parameters ()) {
566 6 : if (first) {
567 : // skip sender parameter
568 : first = false;
569 : } else {
570 4 : dynamic_sig.add_parameter (param.copy ());
571 : }
572 : }
573 6 : dynamic_sig.handler.target_type = new DelegateType (dynamic_sig.get_delegate (new ObjectType ((ObjectTypeSymbol) dynamic_sig.parent_symbol), this), source_reference);
574 : }
575 :
576 176345 : if (m != null && m.has_type_parameters ()) {
577 1594 : unowned MemberAccess ma = (MemberAccess) call;
578 1594 : if (ma.get_type_arguments ().size == 0) {
579 : // infer type arguments
580 296 : foreach (var type_param in m.get_type_parameters ()) {
581 100 : DataType type_arg = null;
582 :
583 : // infer type arguments from arguments
584 100 : arg_it = argument_list.iterator ();
585 370 : foreach (Parameter param in params) {
586 186 : if (param.ellipsis || param.params_array) {
587 0 : break;
588 : }
589 :
590 285 : if (arg_it.next ()) {
591 150 : Expression arg = arg_it.get ();
592 :
593 150 : if (param.initializer is SizeofExpression && arg is SizeofExpression
594 2 : && ((SizeofExpression) param.initializer).type_reference.type_symbol == type_param) {
595 2 : type_arg = ((SizeofExpression) arg).type_reference.copy ();
596 148 : } else if (param.initializer is TypeofExpression && arg is TypeofExpression
597 2 : && ((TypeofExpression) param.initializer).type_reference.type_symbol == type_param) {
598 2 : type_arg = ((TypeofExpression) arg).type_reference.copy ();
599 : } else {
600 146 : type_arg = param.variable_type.infer_type_argument (type_param, arg.value_type);
601 : }
602 :
603 150 : if (type_arg != null) {
604 51 : break;
605 : }
606 :
607 99 : arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, method_type_args, this);
608 : }
609 : }
610 :
611 : // infer type arguments from expected return type
612 100 : if (type_arg == null && target_type != null) {
613 49 : type_arg = m.return_type.infer_type_argument (type_param, target_type);
614 : }
615 :
616 100 : if (type_arg == null) {
617 0 : error = true;
618 0 : Report.error (ma.source_reference, "cannot infer generic type argument for type parameter `%s'", type_param.get_full_name ());
619 0 : return false;
620 : }
621 :
622 100 : ma.add_type_argument (type_arg);
623 : }
624 :
625 : // recalculate argument target types with new information
626 96 : arg_it = argument_list.iterator ();
627 464 : foreach (Parameter param in params) {
628 184 : if (param.ellipsis || param.params_array) {
629 0 : break;
630 : }
631 :
632 331 : if (arg_it.next ()) {
633 147 : Expression arg = arg_it.get ();
634 :
635 147 : arg.target_type = arg.formal_target_type.get_actual_type (target_object_type, method_type_args, this);
636 : }
637 : }
638 :
639 : // recalculate return value type with new information
640 96 : value_type = formal_value_type.get_actual_type (target_object_type, method_type_args, this);
641 : }
642 : }
643 : // replace method-type if needed for proper argument-check in semantic-analyser
644 176345 : if (m != null && m.coroutine) {
645 124 : unowned MemberAccess ma = (MemberAccess) call;
646 124 : if (ma.member_name == "end") {
647 22 : mtype = new MethodType (m.get_end_method (), source_reference);
648 : }
649 : }
650 : }
651 :
652 191419 : if (!context.analyzer.check_arguments (this, mtype, params, argument_list)) {
653 31 : error = true;
654 31 : return false;
655 : }
656 :
657 : //Resolve possible generic-type in certain Expressions used as parameter default-value
658 191388 : arg_it = argument_list.iterator ();
659 470433 : foreach (Parameter param in params) {
660 284514 : if (param.ellipsis || param.params_array) {
661 16547 : break;
662 : }
663 279045 : if (arg_it.next ()) {
664 267967 : Expression arg = arg_it.get ();
665 267967 : if (param.initializer != arg) {
666 256889 : continue;
667 : }
668 11078 : unowned SizeofExpression? sizeof_expr = arg as SizeofExpression;
669 12 : if (sizeof_expr != null && sizeof_expr.type_reference is GenericType) {
670 6 : var sizeof_type = sizeof_expr.type_reference.get_actual_type (target_object_type, method_type_args, this);
671 6 : replace_expression (arg, new SizeofExpression (sizeof_type, source_reference));
672 : }
673 11078 : unowned TypeofExpression? typeof_expr = arg as TypeofExpression;
674 11081 : if (typeof_expr != null && typeof_expr.type_reference is GenericType) {
675 3 : var typeof_type = typeof_expr.type_reference.get_actual_type (target_object_type, method_type_args, this);
676 3 : replace_expression (arg, new TypeofExpression (typeof_type, source_reference));
677 : }
678 : }
679 : }
680 :
681 : /* Check for constructv chain up */
682 191393 : if (base_cm != null && base_cm.is_variadic () && argument_list.size == base_cm.get_parameters ().size) {
683 5 : var this_last_arg = argument_list[argument_list.size - 1];
684 5 : if (this_last_arg.value_type is StructValueType && this_last_arg.value_type.type_symbol == context.analyzer.va_list_type.type_symbol) {
685 4 : is_constructv_chainup = true;
686 : }
687 : }
688 :
689 191388 : value_type.check (context);
690 :
691 : // FIXME code duplication in ObjectCreationExpression.check
692 191388 : if (tree_can_fail) {
693 3313 : if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
694 : // simple statements, no side effects after method call
695 5785 : } else if (!(context.analyzer.current_symbol is Block)) {
696 : // can't handle errors in field initializers
697 1 : error = true;
698 1 : Report.error (source_reference, "Field initializers must not throw errors");
699 : } else {
700 : // store parent_node as we need to replace the expression in the old parent node later on
701 2892 : var old_parent_node = parent_node;
702 :
703 2892 : var local = new LocalVariable (value_type.copy (), get_temp_name (), null, source_reference);
704 2892 : var decl = new DeclarationStatement (local, source_reference);
705 :
706 : // don't carry floating reference any further if the target-type is unknown
707 2892 : if (target_type == null) {
708 26 : local.variable_type.floating_reference = false;
709 : }
710 :
711 2892 : insert_statement (context.analyzer.insert_block, decl);
712 :
713 2892 : var temp_access = SemanticAnalyzer.create_temp_access (local, target_type);
714 2892 : temp_access.formal_target_type = formal_target_type;
715 2892 : formal_target_type = null;
716 :
717 : // don't set initializer earlier as this changes parent_node and parent_statement
718 2892 : local.initializer = this;
719 2892 : decl.check (context);
720 :
721 : // move temp variable to insert block to ensure the
722 : // variable is in the same block as the declaration
723 : // otherwise there will be scoping issues in the generated code
724 2892 : var block = (Block) context.analyzer.current_symbol;
725 2892 : block.remove_local_variable (local);
726 2892 : context.analyzer.insert_block.add_local_variable (local);
727 :
728 2892 : old_parent_node.replace_expression (this, temp_access);
729 2892 : temp_access.check (context);
730 : }
731 : }
732 :
733 191388 : return !error;
734 : }
735 :
736 30176 : public override void emit (CodeGenerator codegen) {
737 30176 : unowned MethodType? method_type = call.value_type as MethodType;
738 30176 : if (method_type != null && method_type.method_symbol.parent_symbol is Signal) {
739 101 : ((MemberAccess) call).inner.emit (codegen);
740 : } else {
741 30075 : call.emit (codegen);
742 : }
743 :
744 101494 : foreach (Expression expr in argument_list) {
745 35659 : expr.emit (codegen);
746 : }
747 :
748 30176 : codegen.visit_method_call (this);
749 :
750 30176 : codegen.visit_expression (this);
751 : }
752 :
753 417987 : public override void get_defined_variables (Collection<Variable> collection) {
754 417987 : call.get_defined_variables (collection);
755 :
756 1672893 : foreach (Expression arg in argument_list) {
757 627453 : arg.get_defined_variables (collection);
758 : }
759 : }
760 :
761 139630 : public override void get_used_variables (Collection<Variable> collection) {
762 139630 : call.get_used_variables (collection);
763 :
764 558520 : foreach (Expression arg in argument_list) {
765 209445 : arg.get_used_variables (collection);
766 : }
767 : }
768 :
769 11 : public StringLiteral? get_format_literal () {
770 11 : unowned MethodType? mtype = this.call.value_type as MethodType;
771 1 : if (mtype != null) {
772 1 : int format_arg = mtype.method_symbol.get_format_arg_index ();
773 1 : if (format_arg >= 0 && format_arg < argument_list.size) {
774 0 : return StringLiteral.get_format_literal (argument_list[format_arg]);
775 : }
776 : }
777 :
778 11 : return null;
779 : }
780 :
781 0 : public override string to_string () {
782 0 : var b = new StringBuilder ();
783 0 : if (is_yield_expression) {
784 0 : b.append ("yield ");
785 : }
786 0 : b.append (call.to_string ());
787 0 : b.append_c ('(');
788 :
789 0 : bool first = true;
790 0 : foreach (var expr in argument_list) {
791 0 : if (!first) {
792 0 : b.append (", ");
793 : }
794 0 : b.append (expr.to_string ());
795 0 : first = false;
796 : }
797 0 : b.append_c (')');
798 :
799 0 : return b.str;
800 : }
801 : }
|