Line data Source code
1 : /* valaobjectcreationexpression.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 object creation expression in the source code.
27 : */
28 41778 : public class Vala.ObjectCreationExpression : Expression, CallableExpression {
29 : /**
30 : * The object type to create.
31 : */
32 : public DataType type_reference {
33 228610 : get { return _data_type; }
34 18431 : private set {
35 267623 : _data_type = value;
36 18431 : _data_type.parent_node = this;
37 : }
38 : }
39 :
40 : /**
41 : * The construction method to call.
42 : */
43 : public Expression call {
44 1493 : get { return member_name; }
45 : }
46 :
47 : /**
48 : * The construction method to use or the data type to be created
49 : * with the default construction method.
50 : */
51 : public MemberAccess member_name {
52 253416 : get { return _member_name; }
53 19352 : private set {
54 38704 : _member_name = value;
55 19352 : _member_name.parent_node = this;
56 : }
57 : }
58 :
59 23846 : public bool is_yield_expression { get; set; }
60 :
61 270 : public bool is_chainup { get; set; }
62 :
63 162 : public bool struct_creation { get; set; }
64 :
65 38704 : private List<Expression> argument_list = new ArrayList<Expression> ();
66 :
67 38704 : private List<MemberInitializer> object_initializer = new ArrayList<MemberInitializer> ();
68 :
69 19352 : private DataType _data_type;
70 19352 : private MemberAccess _member_name;
71 :
72 : /**
73 : * Creates a new object creation expression.
74 : *
75 : * @param member_name object type to create
76 : * @param source_reference reference to source code
77 : * @return newly created object creation expression
78 : */
79 58056 : public ObjectCreationExpression (MemberAccess member_name, SourceReference? source_reference = null) {
80 19352 : this.source_reference = source_reference;
81 19352 : this.member_name = member_name;
82 : }
83 :
84 : /**
85 : * Appends the specified expression to the list of arguments.
86 : *
87 : * @param arg an argument
88 : */
89 41804 : public void add_argument (Expression arg) {
90 41804 : argument_list.add (arg);
91 41804 : arg.parent_node = this;
92 : }
93 :
94 : /**
95 : * Returns the argument list.
96 : *
97 : * @return argument list
98 : */
99 7094 : public unowned List<Expression> get_argument_list () {
100 7094 : return argument_list;
101 : }
102 :
103 : /**
104 : * Appends the specified member initializer to the object initializer.
105 : *
106 : * @param init a member initializer
107 : */
108 93 : public void add_member_initializer (MemberInitializer init) {
109 93 : object_initializer.add (init);
110 93 : init.parent_node = this;
111 : }
112 :
113 : /**
114 : * Returns the object initializer.
115 : *
116 : * @return member initializer list
117 : */
118 44145 : public unowned List<MemberInitializer> get_object_initializer () {
119 44145 : return object_initializer;
120 : }
121 :
122 73981 : public override void accept (CodeVisitor visitor) {
123 73981 : visitor.visit_object_creation_expression (this);
124 :
125 73981 : visitor.visit_expression (this);
126 : }
127 :
128 73980 : public override void accept_children (CodeVisitor visitor) {
129 73980 : if (type_reference != null) {
130 29771 : type_reference.accept (visitor);
131 : }
132 :
133 73980 : if (member_name != null) {
134 73980 : member_name.accept (visitor);
135 : }
136 :
137 410652 : foreach (Expression arg in argument_list) {
138 168336 : arg.accept (visitor);
139 : }
140 :
141 74894 : foreach (MemberInitializer init in object_initializer) {
142 457 : init.accept (visitor);
143 : }
144 : }
145 :
146 36 : public override void replace_expression (Expression old_node, Expression new_node) {
147 36 : int index = argument_list.index_of (old_node);
148 36 : if (index >= 0) {
149 36 : argument_list[index] = new_node;
150 36 : new_node.parent_node = this;
151 : }
152 : }
153 :
154 0 : public override bool is_pure () {
155 0 : return false;
156 : }
157 :
158 1417 : public override bool is_accessible (Symbol sym) {
159 1417 : if (member_name != null && !member_name.is_accessible (sym)) {
160 0 : return false;
161 : }
162 :
163 1417 : foreach (var arg in argument_list) {
164 0 : if (!arg.is_accessible (sym)) {
165 0 : return false;
166 : }
167 : }
168 :
169 1417 : foreach (var init in object_initializer) {
170 0 : if (!init.initializer.is_accessible (sym)) {
171 0 : return false;
172 : }
173 : }
174 :
175 1417 : return true;
176 : }
177 :
178 0 : public override void replace_type (DataType old_type, DataType new_type) {
179 0 : if (type_reference == old_type) {
180 0 : type_reference = new_type;
181 : }
182 : }
183 :
184 18471 : public override bool check (CodeContext context) {
185 18471 : if (checked) {
186 37 : return !error;
187 : }
188 :
189 18434 : checked = true;
190 :
191 18434 : if (!member_name.check (context)) {
192 1 : error = true;
193 1 : return false;
194 : }
195 :
196 : TypeSymbol type;
197 :
198 18433 : if (member_name.symbol_reference == null) {
199 0 : error = true;
200 0 : return false;
201 : }
202 :
203 18433 : var constructor_sym = member_name.symbol_reference;
204 18433 : var type_sym = member_name.symbol_reference;
205 :
206 24409 : var type_args = member_name.get_type_arguments ();
207 :
208 24410 : if (constructor_sym is Method) {
209 11956 : type_sym = constructor_sym.parent_symbol;
210 :
211 5978 : var constructor = (Method) constructor_sym;
212 5978 : if (!(constructor_sym is CreationMethod)) {
213 1 : error = true;
214 1 : Report.error (source_reference, "`%s' is not a creation method", constructor.get_full_name ());
215 1 : return false;
216 : }
217 :
218 5977 : symbol_reference = constructor;
219 :
220 : // inner expression can also be base access when chaining constructors
221 5977 : unowned MemberAccess? ma = member_name.inner as MemberAccess;
222 11953 : if (ma != null) {
223 11952 : type_args = ma.get_type_arguments ();
224 : }
225 : }
226 :
227 18432 : if (type_sym is Class) {
228 16774 : type = (TypeSymbol) type_sym;
229 16774 : if (((Class) type).is_error_base) {
230 2788 : type_reference = new ErrorType (null, null, source_reference);
231 : } else {
232 13986 : type_reference = new ObjectType ((Class) type, source_reference);
233 : }
234 1658 : } else if (type_sym is Struct) {
235 164 : type = (TypeSymbol) type_sym;
236 164 : type_reference = new StructValueType ((Struct) type, source_reference);
237 1494 : } else if (type_sym is ErrorCode) {
238 1493 : type = (TypeSymbol) type_sym;
239 1493 : type_reference = new ErrorType ((ErrorDomain) type_sym.parent_symbol, (ErrorCode) type_sym, source_reference);
240 1493 : symbol_reference = type_sym;
241 : } else {
242 1 : error = true;
243 1 : Report.error (source_reference, "`%s' is not a class, struct, or error code", type_sym.get_full_name ());
244 1 : return false;
245 : }
246 :
247 19335 : foreach (DataType type_arg in type_args) {
248 452 : type_reference.add_type_argument (type_arg);
249 : }
250 :
251 18431 : if (!type_reference.check (context)) {
252 2 : error = true;
253 2 : return false;
254 : }
255 :
256 18429 : context.analyzer.check_type (type_reference);
257 : // check whether there is the expected amount of type-arguments
258 18429 : if (!type_reference.check_type_arguments (context)) {
259 0 : error = true;
260 0 : return false;
261 : }
262 :
263 18429 : value_type = type_reference.copy ();
264 18429 : value_type.value_owned = true;
265 :
266 35198 : if (type is Class) {
267 16772 : var cl = (Class) type;
268 :
269 16772 : if (struct_creation) {
270 0 : error = true;
271 0 : Report.error (source_reference, "syntax error, use `new' to create new objects");
272 0 : return false;
273 : }
274 :
275 16772 : if (cl.is_abstract) {
276 1 : value_type = null;
277 1 : error = true;
278 1 : Report.error (source_reference, "Can't create instance of abstract class `%s'", cl.get_full_name ());
279 1 : return false;
280 : }
281 :
282 16771 : if (symbol_reference == null) {
283 10799 : symbol_reference = cl.default_construction_method;
284 :
285 10799 : if (symbol_reference == null) {
286 0 : error = true;
287 0 : Report.error (source_reference, "`%s' does not have a default constructor", cl.get_full_name ());
288 0 : return false;
289 : }
290 :
291 : // track usage for flow analyzer
292 10799 : symbol_reference.used = true;
293 10799 : symbol_reference.version.check (context, source_reference);
294 : }
295 :
296 16771 : if (symbol_reference != null
297 16771 : && (symbol_reference.access == SymbolAccessibility.PRIVATE || symbol_reference.access == SymbolAccessibility.PROTECTED)) {
298 66 : bool in_target_type = false;
299 782 : for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
300 260 : if (this_symbol == cl) {
301 : in_target_type = true;
302 : break;
303 : }
304 : }
305 :
306 66 : if (!in_target_type) {
307 2 : error = true;
308 2 : Report.error (source_reference, "Access to non-public constructor `%s' denied", symbol_reference.get_full_name ());
309 2 : return false;
310 : }
311 : }
312 :
313 50929 : while (cl != null) {
314 : // FIXME: use target values in the codegen
315 34198 : if (cl.has_attribute_argument ("CCode", "ref_sink_function")) {
316 38 : value_type.floating_reference = true;
317 38 : break;
318 : }
319 :
320 51589 : cl = cl.base_class;
321 : }
322 1821 : } else if (type is Struct) {
323 164 : var st = (Struct) type;
324 :
325 164 : if (!struct_creation && !context.deprecated) {
326 2 : Report.warning (source_reference, "deprecated syntax, don't use `new' to initialize structs");
327 : }
328 :
329 164 : if (symbol_reference == null) {
330 159 : symbol_reference = st.default_construction_method;
331 : }
332 :
333 164 : if (context.profile == Profile.GOBJECT && st.is_simple_type () && symbol_reference == null && object_initializer.size == 0) {
334 0 : error = true;
335 0 : Report.error (source_reference, "`%s' does not have a default constructor", st.get_full_name ());
336 0 : return false;
337 : }
338 : }
339 :
340 18426 : if (symbol_reference == null && argument_list.size != 0) {
341 0 : value_type = null;
342 0 : error = true;
343 0 : Report.error (source_reference, "No arguments allowed when constructing type `%s'", type.get_full_name ());
344 0 : return false;
345 : }
346 :
347 35303 : if (symbol_reference is Method) {
348 16877 : var m = (Method) symbol_reference;
349 :
350 16877 : if (is_yield_expression) {
351 9 : if (!m.coroutine) {
352 1 : error = true;
353 1 : Report.error (source_reference, "yield expression requires async method");
354 : }
355 9 : if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) {
356 1 : error = true;
357 1 : Report.error (source_reference, "yield expression not available outside async method");
358 : }
359 16868 : } else if (m is CreationMethod) {
360 16868 : if (m.coroutine) {
361 1 : error = true;
362 1 : Report.error (source_reference, "missing `yield' before async creation expression");
363 : }
364 : }
365 :
366 : // FIXME partial code duplication of MethodCall.check
367 :
368 16877 : Expression last_arg = null;
369 :
370 16877 : Iterator<Expression> arg_it = argument_list.iterator ();
371 87193 : foreach (Parameter param in m.get_parameters ()) {
372 38000 : if (!param.check (context)) {
373 0 : error = true;
374 : }
375 :
376 38000 : if (param.ellipsis) {
377 2836 : break;
378 : }
379 :
380 35164 : if (param.params_array) {
381 12 : var array_type = (ArrayType) param.variable_type;
382 42 : while (arg_it.next ()) {
383 18 : Expression arg = arg_it.get ();
384 :
385 : /* store expected type for callback parameters */
386 18 : arg.target_type = array_type.element_type;
387 18 : arg.target_type.value_owned = array_type.value_owned;
388 : }
389 6 : break;
390 : }
391 :
392 67445 : if (arg_it.next ()) {
393 32287 : Expression arg = arg_it.get ();
394 :
395 : /* store expected type for callback parameters */
396 32287 : arg.formal_target_type = param.variable_type;
397 32287 : arg.target_type = arg.formal_target_type.get_actual_type (value_type, null, this);
398 :
399 64574 : last_arg = arg;
400 : }
401 : }
402 :
403 : // printf arguments
404 16877 : if (m.printf_format) {
405 2788 : StringLiteral format_literal = null;
406 2788 : if (last_arg is NullLiteral) {
407 : // do not replace explicit null
408 2788 : } else if (last_arg != null) {
409 : // use last argument as format string
410 2788 : format_literal = StringLiteral.get_format_literal (last_arg);
411 2788 : if (format_literal == null && argument_list.size == m.get_parameters ().size - 1) {
412 : // insert "%s" to avoid issues with embedded %
413 0 : format_literal = new StringLiteral ("\"%s\"");
414 0 : format_literal.target_type = context.analyzer.string_type.copy ();
415 0 : argument_list.insert (argument_list.size - 1, format_literal);
416 :
417 : // recreate iterator and skip to right position
418 0 : arg_it = argument_list.iterator ();
419 0 : foreach (Parameter param in m.get_parameters ()) {
420 0 : if (param.ellipsis || param.params_array) {
421 0 : break;
422 : }
423 0 : arg_it.next ();
424 : }
425 : }
426 : }
427 22453 : if (format_literal != null) {
428 2788 : string format = format_literal.eval ();
429 2788 : if (!context.analyzer.check_print_format (format, arg_it, source_reference)) {
430 0 : return false;
431 : }
432 : }
433 : }
434 :
435 87183 : foreach (Expression arg in argument_list) {
436 35153 : arg.check (context);
437 : }
438 :
439 16877 : context.analyzer.check_arguments (this, new MethodType (m), m.get_parameters (), argument_list);
440 1549 : } else if (type_reference is ErrorType) {
441 1493 : if (member_name != null) {
442 1493 : member_name.check (context);
443 : }
444 :
445 4491 : foreach (Expression arg in argument_list) {
446 1499 : arg.check (context);
447 : }
448 :
449 1493 : foreach (MemberInitializer init in object_initializer) {
450 0 : init.check (context);
451 : }
452 :
453 2985 : if (argument_list.size == 0) {
454 1 : error = true;
455 1 : Report.error (source_reference, "Too few arguments, errors need at least 1 argument");
456 : } else {
457 1492 : Iterator<Expression> arg_it = argument_list.iterator ();
458 1492 : arg_it.next ();
459 1492 : var ex = arg_it.get ();
460 1492 : if (ex.value_type == null || !ex.value_type.compatible (context.analyzer.string_type)) {
461 1 : error = true;
462 1 : Report.error (source_reference, "Invalid type for argument 1");
463 : }
464 :
465 1492 : var format_literal = StringLiteral.get_format_literal (ex);
466 2981 : if (format_literal != null) {
467 1489 : var format = format_literal.eval ();
468 1489 : if (!context.analyzer.check_print_format (format, arg_it, source_reference)) {
469 0 : error = true;
470 0 : return false;
471 : }
472 : }
473 :
474 1492 : arg_it = argument_list.iterator ();
475 1492 : arg_it.next ();
476 1492 : if (!context.analyzer.check_variadic_arguments (arg_it, 1, source_reference)) {
477 0 : error = true;
478 0 : return false;
479 : }
480 : }
481 : }
482 :
483 : //Resolve possible generic-type in SizeofExpression used as parameter default-value
484 97472 : foreach (Expression arg in argument_list) {
485 39523 : unowned SizeofExpression sizeof_expr = arg as SizeofExpression;
486 39537 : if (sizeof_expr != null && sizeof_expr.type_reference is GenericType) {
487 14 : var sizeof_type = sizeof_expr.type_reference.get_actual_type (type_reference, type_reference.get_type_arguments (), this);
488 14 : replace_expression (arg, new SizeofExpression (sizeof_type, source_reference));
489 : }
490 : }
491 :
492 : // Unwrap chained member initializers
493 18522 : foreach (MemberInitializer init in get_object_initializer ()) {
494 93 : if (!(init.initializer is MemberInitializer)) {
495 90 : continue;
496 : }
497 :
498 3 : int index = object_initializer.index_of (init);
499 3 : object_initializer.remove_at (index);
500 3 : assert (index >= 0);
501 :
502 3 : unowned MemberInitializer? inner_mi = (MemberInitializer) init.initializer;
503 6 : while (inner_mi.initializer is MemberInitializer) {
504 3 : inner_mi = (MemberInitializer) inner_mi.initializer;
505 : }
506 :
507 3 : var local = new LocalVariable (null, get_temp_name (), inner_mi.initializer, inner_mi.initializer.source_reference);
508 3 : var decl = new DeclarationStatement (local, inner_mi.initializer.source_reference);
509 3 : decl.check (context);
510 3 : insert_statement (context.analyzer.insert_block, decl);
511 :
512 21 : do {
513 9 : var member_init = new MemberInitializer (inner_mi.name, new MemberAccess (null, local.name, inner_mi.source_reference), inner_mi.source_reference);
514 9 : object_initializer.insert (index++, member_init);
515 15 : inner_mi = inner_mi.parent_node as MemberInitializer;
516 9 : } while (inner_mi != null);
517 : }
518 18624 : foreach (MemberInitializer init in get_object_initializer ()) {
519 99 : init.parent_node = this;
520 99 : init.check (context);
521 : }
522 :
523 : // FIXME code duplication in MethodCall.check
524 18426 : if (tree_can_fail) {
525 30 : if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
526 : // simple statements, no side effects after method call
527 27 : } else if (!(context.analyzer.current_symbol is Block)) {
528 : // can't handle errors in field initializers
529 1 : Report.error (source_reference, "Field initializers must not throw errors");
530 : } else {
531 : // store parent_node as we need to replace the expression in the old parent node later on
532 13 : var old_parent_node = parent_node;
533 :
534 13 : var local = new LocalVariable (value_type.copy (), get_temp_name (), null, source_reference);
535 13 : var decl = new DeclarationStatement (local, source_reference);
536 :
537 13 : insert_statement (context.analyzer.insert_block, decl);
538 :
539 13 : var temp_access = SemanticAnalyzer.create_temp_access (local, target_type);
540 13 : temp_access.formal_target_type = formal_target_type;
541 13 : formal_target_type = null;
542 :
543 : // don't set initializer earlier as this changes parent_node and parent_statement
544 13 : local.initializer = this;
545 13 : decl.check (context);
546 :
547 : // move temp variable to insert block to ensure the
548 : // variable is in the same block as the declaration
549 : // otherwise there will be scoping issues in the generated code
550 13 : var block = (Block) context.analyzer.current_symbol;
551 13 : block.remove_local_variable (local);
552 13 : context.analyzer.insert_block.add_local_variable (local);
553 :
554 13 : old_parent_node.replace_expression (this, temp_access);
555 13 : temp_access.check (context);
556 : }
557 : }
558 :
559 18426 : return !error;
560 : }
561 :
562 63693 : public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
563 125726 : if (symbol_reference is Method) {
564 62033 : if (source_reference == null) {
565 45197 : source_reference = this.source_reference;
566 : }
567 62033 : var m = (Method) symbol_reference;
568 62033 : m.get_error_types (collection, source_reference);
569 : }
570 : }
571 :
572 7097 : public override void emit (CodeGenerator codegen) {
573 27373 : foreach (Expression arg in argument_list) {
574 10138 : arg.emit (codegen);
575 : }
576 :
577 7285 : foreach (MemberInitializer init in object_initializer) {
578 94 : init.emit (codegen);
579 : }
580 :
581 7097 : codegen.visit_object_creation_expression (this);
582 :
583 7097 : codegen.visit_expression (this);
584 : }
585 :
586 40842 : public override void get_defined_variables (Collection<Variable> collection) {
587 219978 : foreach (Expression arg in argument_list) {
588 89568 : arg.get_defined_variables (collection);
589 : }
590 : }
591 :
592 13653 : public override void get_used_variables (Collection<Variable> collection) {
593 73387 : foreach (Expression arg in argument_list) {
594 29867 : arg.get_used_variables (collection);
595 : }
596 :
597 13839 : foreach (MemberInitializer init in object_initializer) {
598 93 : init.get_used_variables (collection);
599 : }
600 : }
601 :
602 0 : public override string to_string () {
603 0 : var b = new StringBuilder ();
604 0 : if (is_yield_expression) {
605 0 : b.append ("yield ");
606 : }
607 0 : if (!struct_creation) {
608 0 : b.append ("new ");
609 : }
610 0 : if (member_name != null) {
611 0 : b.append (member_name.to_string ());
612 : }
613 0 : b.append_c ('(');
614 :
615 0 : bool first = true;
616 0 : foreach (var expr in argument_list) {
617 0 : if (!first) {
618 0 : b.append (", ");
619 : }
620 0 : b.append (expr.to_string ());
621 0 : first = false;
622 : }
623 0 : b.append_c (')');
624 :
625 0 : return b.str;
626 : }
627 : }
|