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
20 * Jürg Billeter <j@bitron.ch>
26 * Represents an object creation expression in the source code.
28 public class Vala
.ObjectCreationExpression
: Expression
{
30 * The object type to create.
32 public DataType type_reference
{
33 get { return _data_type
; }
36 _data_type
.parent_node
= this
;
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
;
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
;
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
;
79 * Returns a copy of the argument list.
81 * @return argument list
83 public List
<Expression
> get_argument_list () {
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
;
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 () {
142 public override bool is_accessible (Symbol sym
) {
143 if (member_name
!= null && !member_name
.is_accessible (sym
)) {
147 foreach (var arg
in argument_list
) {
148 if (!arg
.is_accessible (sym
)) {
153 foreach (var init
in object_initializer
) {
154 if (!init
.initializer
.is_accessible (sym
)) {
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
) {
175 if (member_name
!= null) {
176 if (!member_name
.check (context
)) {
182 TypeSymbol type
= null;
184 if (type_reference
== null) {
185 if (member_name
== null) {
187 Report
.error (source_reference
, "Incomplete object creation expression");
191 if (member_name
.symbol_reference
== null) {
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
)) {
207 Report
.error (source_reference
, "`%s' is not a creation method".printf (constructor
.get_full_name ()));
211 symbol_reference
= constructor
;
213 // inner expression can also be base access when chaining constructors
214 var ma
= member_name
.inner as MemberAccess
;
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
);
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
;
235 Report
.error (source_reference
, "`%s' is not a class, struct, or error code".printf (type_sym
.get_full_name ()));
239 foreach (DataType type_arg
in type_args
) {
240 type_reference
.add_type_argument (type_arg
);
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;
255 var cl
= (Class
) type
;
257 expected_num_type_args
= cl
.get_type_parameters ().size
;
259 if (struct_creation
) {
261 Report
.error (source_reference
, "syntax error, use `new' to create new objects");
265 if (cl
.is_abstract
) {
268 Report
.error (source_reference
, "Can't create instance of abstract class `%s'".printf (cl
.get_full_name ()));
272 if (symbol_reference
== null) {
273 symbol_reference
= cl
.default_construction_method
;
275 if (symbol_reference
== null) {
277 Report
.error (source_reference
, "`%s' does not have a default constructor".printf (cl
.get_full_name ()));
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;
296 if (!in_target_type
) {
298 Report
.error (source_reference
, "Access to non-public constructor `%s' denied".printf (symbol_reference
.get_full_name ()));
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;
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) {
327 Report
.error (source_reference
, "`%s' does not have a default constructor".printf (st
.get_full_name ()));
332 if (expected_num_type_args
> given_num_type_args
) {
334 Report
.error (source_reference
, "too few type arguments");
336 } else if (expected_num_type_args
< given_num_type_args
) {
338 Report
.error (source_reference
, "too many type arguments");
342 if (symbol_reference
== null && get_argument_list ().size
!= 0) {
345 Report
.error (source_reference
, "No arguments allowed when constructing type `%s'".printf (type
.get_full_name ()));
349 if (symbol_reference is Method
) {
350 var m
= (Method
) symbol_reference
;
352 if (is_yield_expression
) {
355 Report
.error (source_reference
, "yield expression requires async method");
357 if (context
.analyzer
.current_method
== null || !context
.analyzer
.current_method
.coroutine
) {
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
)) {
374 if (param
.ellipsis
) {
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
);
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
) {
413 if (format_literal
!= null) {
414 string format
= format_literal
.eval ();
415 if (!context
.analyzer
.check_print_format (format
, arg_it
, source_reference
)) {
421 foreach (Expression arg
in args
) {
425 context
.analyzer
.check_arguments (this
, new
MethodType (m
), m
.get_parameters (), args
);
427 foreach (DataType error_type
in m
.get_error_types ()) {
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
) {
449 foreach (MemberInitializer init
in object_initializer
) {
450 init
.check (context
);
453 if (get_argument_list ().size
== 0) {
455 Report
.error (source_reference
, "Too few arguments, errors need at least 1 argument");
457 Iterator
<Expression
> arg_it
= get_argument_list ().iterator ();
459 var ex
= arg_it
.get ();
460 if (ex
.value_type
== null || !ex
.value_type
.compatible (context
.analyzer
.string_type
)) {
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
)) {
474 arg_it
= get_argument_list ().iterator ();
476 if (!context
.analyzer
.check_variadic_arguments (arg_it
, 1, source_reference
)) {
483 foreach (MemberInitializer init
in get_object_initializer ()) {
484 context
.analyzer
.visit_member_initializer (init
, type_reference
);
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");
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
);
523 public override void emit (CodeGenerator codegen
) {
524 foreach (Expression arg
in argument_list
) {
528 foreach (MemberInitializer init
in object_initializer
) {
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
);