Sync NEWS from 0.40
[vala-gnome.git] / vala / valaobjectcreationexpression.vala
blobfa419fd22637712caaa01f9617a244e66e242fdb
1 /* valaobjectcreationexpression.vala
3 * Copyright (C) 2006-2012 Jürg Billeter
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.
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.
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
23 using GLib;
25 /**
26 * Represents an object creation expression in the source code.
28 public class Vala.ObjectCreationExpression : Expression {
29 /**
30 * The object type to create.
32 public DataType type_reference {
33 get { return _data_type; }
34 set {
35 _data_type = value;
36 _data_type.parent_node = this;
40 /**
41 * The construction method to use or the data type to be created
42 * with the default construction method.
44 public MemberAccess member_name { get; set; }
46 public bool is_yield_expression { get; set; }
48 public bool struct_creation { get; set; }
50 private List<Expression> argument_list = new ArrayList<Expression> ();
52 private List<MemberInitializer> object_initializer = new ArrayList<MemberInitializer> ();
54 private DataType _data_type;
56 /**
57 * Creates a new object creation expression.
59 * @param member_name object type to create
60 * @param source_reference reference to source code
61 * @return newly created object creation expression
63 public ObjectCreationExpression (MemberAccess member_name, SourceReference source_reference) {
64 this.source_reference = source_reference;
65 this.member_name = member_name;
68 /**
69 * Appends the specified expression to the list of arguments.
71 * @param arg an argument
73 public void add_argument (Expression arg) {
74 argument_list.add (arg);
75 arg.parent_node = this;
78 /**
79 * Returns a copy of the argument list.
81 * @return argument list
83 public List<Expression> get_argument_list () {
84 return argument_list;
87 /**
88 * Appends the specified member initializer to the object initializer.
90 * @param init a member initializer
92 public void add_member_initializer (MemberInitializer init) {
93 object_initializer.add (init);
94 init.parent_node = this;
97 /**
98 * Returns the object initializer.
100 * @return member initializer list
102 public List<MemberInitializer> get_object_initializer () {
103 return object_initializer;
106 public override void accept (CodeVisitor visitor) {
107 visitor.visit_object_creation_expression (this);
109 visitor.visit_expression (this);
112 public override void accept_children (CodeVisitor visitor) {
113 if (type_reference != null) {
114 type_reference.accept (visitor);
117 if (member_name != null) {
118 member_name.accept (visitor);
121 foreach (Expression arg in argument_list) {
122 arg.accept (visitor);
125 foreach (MemberInitializer init in object_initializer) {
126 init.accept (visitor);
130 public override void replace_expression (Expression old_node, Expression new_node) {
131 int index = argument_list.index_of (old_node);
132 if (index >= 0 && new_node.parent_node == null) {
133 argument_list[index] = new_node;
134 new_node.parent_node = this;
138 public override bool is_pure () {
139 return false;
142 public override bool is_accessible (Symbol sym) {
143 if (member_name != null && !member_name.is_accessible (sym)) {
144 return false;
147 foreach (var arg in argument_list) {
148 if (!arg.is_accessible (sym)) {
149 return false;
153 foreach (var init in object_initializer) {
154 if (!init.initializer.is_accessible (sym)) {
155 return false;
159 return true;
162 public override void replace_type (DataType old_type, DataType new_type) {
163 if (type_reference == old_type) {
164 type_reference = new_type;
168 public override bool check (CodeContext context) {
169 if (checked) {
170 return !error;
173 checked = true;
175 if (member_name != null) {
176 if (!member_name.check (context)) {
177 error = true;
178 return false;
182 TypeSymbol type = null;
184 if (type_reference == null) {
185 if (member_name == null) {
186 error = true;
187 Report.error (source_reference, "Incomplete object creation expression");
188 return false;
191 if (member_name.symbol_reference == null) {
192 error = true;
193 return false;
196 var constructor_sym = member_name.symbol_reference;
197 var type_sym = member_name.symbol_reference;
199 var type_args = member_name.get_type_arguments ();
201 if (constructor_sym is Method) {
202 type_sym = constructor_sym.parent_symbol;
204 var constructor = (Method) constructor_sym;
205 if (!(constructor_sym is CreationMethod)) {
206 error = true;
207 Report.error (source_reference, "`%s' is not a creation method".printf (constructor.get_full_name ()));
208 return false;
211 symbol_reference = constructor;
213 // inner expression can also be base access when chaining constructors
214 var ma = member_name.inner as MemberAccess;
215 if (ma != null) {
216 type_args = ma.get_type_arguments ();
220 if (type_sym is Class) {
221 type = (TypeSymbol) type_sym;
222 if (((Class) type).is_error_base) {
223 type_reference = new ErrorType (null, null, source_reference);
224 } else {
225 type_reference = new ObjectType ((Class) type);
227 } else if (type_sym is Struct) {
228 type = (TypeSymbol) type_sym;
229 type_reference = new StructValueType ((Struct) type);
230 } else if (type_sym is ErrorCode) {
231 type_reference = new ErrorType ((ErrorDomain) type_sym.parent_symbol, (ErrorCode) type_sym, source_reference);
232 symbol_reference = type_sym;
233 } else {
234 error = true;
235 Report.error (source_reference, "`%s' is not a class, struct, or error code".printf (type_sym.get_full_name ()));
236 return false;
239 foreach (DataType type_arg in type_args) {
240 type_reference.add_type_argument (type_arg);
242 } else {
243 type = type_reference.data_type;
246 value_type = type_reference.copy ();
247 value_type.value_owned = true;
249 bool may_throw = false;
251 int given_num_type_args = type_reference.get_type_arguments ().size;
252 int expected_num_type_args = 0;
254 if (type is Class) {
255 var cl = (Class) type;
257 expected_num_type_args = cl.get_type_parameters ().size;
259 if (struct_creation) {
260 error = true;
261 Report.error (source_reference, "syntax error, use `new' to create new objects");
262 return false;
265 if (cl.is_abstract) {
266 value_type = null;
267 error = true;
268 Report.error (source_reference, "Can't create instance of abstract class `%s'".printf (cl.get_full_name ()));
269 return false;
272 if (symbol_reference == null) {
273 symbol_reference = cl.default_construction_method;
275 if (symbol_reference == null) {
276 error = true;
277 Report.error (source_reference, "`%s' does not have a default constructor".printf (cl.get_full_name ()));
278 return false;
281 // track usage for flow analyzer
282 symbol_reference.used = true;
283 symbol_reference.version.check (source_reference);
286 if (symbol_reference != null
287 && (symbol_reference.access == SymbolAccessibility.PRIVATE || symbol_reference.access == SymbolAccessibility.PROTECTED)) {
288 bool in_target_type = false;
289 for (Symbol this_symbol = context.analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
290 if (this_symbol == cl) {
291 in_target_type = true;
292 break;
296 if (!in_target_type) {
297 error = true;
298 Report.error (source_reference, "Access to non-public constructor `%s' denied".printf (symbol_reference.get_full_name ()));
299 return false;
303 while (cl != null) {
304 // FIXME: use target values in the codegen
305 if (cl.get_attribute_string ("CCode", "ref_sink_function") != null) {
306 value_type.floating_reference = true;
307 break;
310 cl = cl.base_class;
312 } else if (type is Struct) {
313 var st = (Struct) type;
315 expected_num_type_args = st.get_type_parameters ().size;
317 if (!struct_creation && !context.deprecated) {
318 Report.warning (source_reference, "deprecated syntax, don't use `new' to initialize structs");
321 if (symbol_reference == null) {
322 symbol_reference = st.default_construction_method;
325 if (context.profile == Profile.GOBJECT && st.is_simple_type () && symbol_reference == null && object_initializer.size == 0) {
326 error = true;
327 Report.error (source_reference, "`%s' does not have a default constructor".printf (st.get_full_name ()));
328 return false;
332 if (expected_num_type_args > given_num_type_args) {
333 error = true;
334 Report.error (source_reference, "too few type arguments");
335 return false;
336 } else if (expected_num_type_args < given_num_type_args) {
337 error = true;
338 Report.error (source_reference, "too many type arguments");
339 return false;
342 if (symbol_reference == null && get_argument_list ().size != 0) {
343 value_type = null;
344 error = true;
345 Report.error (source_reference, "No arguments allowed when constructing type `%s'".printf (type.get_full_name ()));
346 return false;
349 if (symbol_reference is Method) {
350 var m = (Method) symbol_reference;
352 if (is_yield_expression) {
353 if (!m.coroutine) {
354 error = true;
355 Report.error (source_reference, "yield expression requires async method");
357 if (context.analyzer.current_method == null || !context.analyzer.current_method.coroutine) {
358 error = true;
359 Report.error (source_reference, "yield expression not available outside async method");
363 // FIXME partial code duplication of MethodCall.check
365 Expression last_arg = null;
367 var args = get_argument_list ();
368 Iterator<Expression> arg_it = args.iterator ();
369 foreach (Parameter param in m.get_parameters ()) {
370 if (!param.check (context)) {
371 error = true;
374 if (param.ellipsis) {
375 break;
378 if (arg_it.next ()) {
379 Expression arg = arg_it.get ();
381 /* store expected type for callback parameters */
382 arg.formal_target_type = param.variable_type;
383 arg.target_type = arg.formal_target_type.get_actual_type (value_type, null, this);
385 last_arg = arg;
389 // printf arguments
390 if (m.printf_format) {
391 StringLiteral format_literal = null;
392 if (last_arg is NullLiteral) {
393 // do not replace explicit null
394 } else if (last_arg != null) {
395 // use last argument as format string
396 format_literal = StringLiteral.get_format_literal (last_arg);
397 if (format_literal == null && args.size == m.get_parameters ().size - 1) {
398 // insert "%s" to avoid issues with embedded %
399 format_literal = new StringLiteral ("\"%s\"");
400 format_literal.target_type = context.analyzer.string_type.copy ();
401 argument_list.insert (args.size - 1, format_literal);
403 // recreate iterator and skip to right position
404 arg_it = argument_list.iterator ();
405 foreach (Parameter param in m.get_parameters ()) {
406 if (param.ellipsis) {
407 break;
409 arg_it.next ();
413 if (format_literal != null) {
414 string format = format_literal.eval ();
415 if (!context.analyzer.check_print_format (format, arg_it, source_reference)) {
416 return false;
421 foreach (Expression arg in args) {
422 arg.check (context);
425 context.analyzer.check_arguments (this, new MethodType (m), m.get_parameters (), args);
427 foreach (DataType error_type in m.get_error_types ()) {
428 may_throw = true;
430 // ensure we can trace back which expression may throw errors of this type
431 var call_error_type = error_type.copy ();
432 call_error_type.source_reference = source_reference;
434 add_error_type (call_error_type);
436 } else if (type_reference is ErrorType) {
437 if (type_reference != null) {
438 type_reference.check (context);
441 if (member_name != null) {
442 member_name.check (context);
445 foreach (Expression arg in argument_list) {
446 arg.check (context);
449 foreach (MemberInitializer init in object_initializer) {
450 init.check (context);
453 if (get_argument_list ().size == 0) {
454 error = true;
455 Report.error (source_reference, "Too few arguments, errors need at least 1 argument");
456 } else {
457 Iterator<Expression> arg_it = get_argument_list ().iterator ();
458 arg_it.next ();
459 var ex = arg_it.get ();
460 if (ex.value_type == null || !ex.value_type.compatible (context.analyzer.string_type)) {
461 error = true;
462 Report.error (source_reference, "Invalid type for argument 1");
465 var format_literal = StringLiteral.get_format_literal (ex);
466 if (format_literal != null) {
467 var format = format_literal.eval ();
468 if (!context.analyzer.check_print_format (format, arg_it, source_reference)) {
469 error = true;
470 return false;
474 arg_it = get_argument_list ().iterator ();
475 arg_it.next ();
476 if (!context.analyzer.check_variadic_arguments (arg_it, 1, source_reference)) {
477 error = true;
478 return false;
483 foreach (MemberInitializer init in get_object_initializer ()) {
484 context.analyzer.visit_member_initializer (init, type_reference);
487 if (may_throw) {
488 if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
489 // simple statements, no side effects after method call
490 } else if (!(context.analyzer.current_symbol is Block)) {
491 // can't handle errors in field initializers
492 Report.error (source_reference, "Field initializers must not throw errors");
493 } else {
494 // store parent_node as we need to replace the expression in the old parent node later on
495 var old_parent_node = parent_node;
497 var local = new LocalVariable (value_type.copy (), get_temp_name (), null, source_reference);
498 var decl = new DeclarationStatement (local, source_reference);
500 insert_statement (context.analyzer.insert_block, decl);
502 var temp_access = SemanticAnalyzer.create_temp_access (local, target_type);
503 // don't set initializer earlier as this changes parent_node and parent_statement
504 local.initializer = this;
505 decl.check (context);
508 // move temp variable to insert block to ensure the
509 // variable is in the same block as the declaration
510 // otherwise there will be scoping issues in the generated code
511 var block = (Block) context.analyzer.current_symbol;
512 block.remove_local_variable (local);
513 context.analyzer.insert_block.add_local_variable (local);
515 old_parent_node.replace_expression (this, temp_access);
516 temp_access.check (context);
520 return !error;
523 public override void emit (CodeGenerator codegen) {
524 foreach (Expression arg in argument_list) {
525 arg.emit (codegen);
528 foreach (MemberInitializer init in object_initializer) {
529 init.emit (codegen);
532 codegen.visit_object_creation_expression (this);
534 codegen.visit_expression (this);
537 public override void get_defined_variables (Collection<Variable> collection) {
538 foreach (Expression arg in argument_list) {
539 arg.get_defined_variables (collection);
543 public override void get_used_variables (Collection<Variable> collection) {
544 foreach (Expression arg in argument_list) {
545 arg.get_used_variables (collection);
548 foreach (MemberInitializer init in object_initializer) {
549 init.get_used_variables (collection);