glib-2.0: Fix g_variant_new_tuple binding
[vala-lang.git] / vala / valaobjectcreationexpression.vala
blobd7cc00822e3a388f4ea3ce5da441416d0e745508
1 /* valaobjectcreationexpression.vala
3 * Copyright (C) 2006-2010 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. May be null to indicate that
42 * the default construction method should be used.
44 public Method constructor { get; set; }
46 /**
47 * The construction method to use or the data type to be created
48 * with the default construction method.
50 public MemberAccess member_name { get; set; }
52 public bool struct_creation { get; set; }
54 private List<Expression> argument_list = new ArrayList<Expression> ();
56 private List<MemberInitializer> object_initializer = new ArrayList<MemberInitializer> ();
58 private DataType _data_type;
60 /**
61 * Creates a new object creation expression.
63 * @param member_name object type to create
64 * @param source_reference reference to source code
65 * @return newly created object creation expression
67 public ObjectCreationExpression (MemberAccess member_name, SourceReference source_reference) {
68 this.source_reference = source_reference;
69 this.member_name = member_name;
72 /**
73 * Appends the specified expression to the list of arguments.
75 * @param arg an argument
77 public void add_argument (Expression arg) {
78 argument_list.add (arg);
79 arg.parent_node = this;
82 /**
83 * Returns a copy of the argument list.
85 * @return argument list
87 public List<Expression> get_argument_list () {
88 return argument_list;
91 /**
92 * Appends the specified member initializer to the object initializer.
94 * @param init a member initializer
96 public void add_member_initializer (MemberInitializer init) {
97 object_initializer.add (init);
98 init.parent_node = this;
102 * Returns the object initializer.
104 * @return member initializer list
106 public List<MemberInitializer> get_object_initializer () {
107 return object_initializer;
110 public override void accept (CodeVisitor visitor) {
111 visitor.visit_object_creation_expression (this);
113 visitor.visit_expression (this);
116 public override void accept_children (CodeVisitor visitor) {
117 if (type_reference != null) {
118 type_reference.accept (visitor);
121 if (member_name != null) {
122 member_name.accept (visitor);
125 foreach (Expression arg in argument_list) {
126 arg.accept (visitor);
129 foreach (MemberInitializer init in object_initializer) {
130 init.accept (visitor);
134 public override void replace_expression (Expression old_node, Expression new_node) {
135 int index = argument_list.index_of (old_node);
136 if (index >= 0 && new_node.parent_node == null) {
137 argument_list[index] = new_node;
138 new_node.parent_node = this;
142 public override bool is_pure () {
143 return false;
146 public override void replace_type (DataType old_type, DataType new_type) {
147 if (type_reference == old_type) {
148 type_reference = new_type;
152 public override bool check (SemanticAnalyzer analyzer) {
153 if (checked) {
154 return !error;
157 checked = true;
159 if (member_name != null) {
160 member_name.check (analyzer);
163 TypeSymbol type = null;
165 if (type_reference == null) {
166 if (member_name == null) {
167 error = true;
168 Report.error (source_reference, "Incomplete object creation expression");
169 return false;
172 if (member_name.symbol_reference == null) {
173 error = true;
174 return false;
177 var constructor_sym = member_name.symbol_reference;
178 var type_sym = member_name.symbol_reference;
180 var type_args = member_name.get_type_arguments ();
182 if (constructor_sym is Method) {
183 type_sym = constructor_sym.parent_symbol;
185 var constructor = (Method) constructor_sym;
186 if (!(constructor_sym is CreationMethod)) {
187 error = true;
188 Report.error (source_reference, "`%s' is not a creation method".printf (constructor.get_full_name ()));
189 return false;
192 symbol_reference = constructor;
194 // inner expression can also be base access when chaining constructors
195 var ma = member_name.inner as MemberAccess;
196 if (ma != null) {
197 type_args = ma.get_type_arguments ();
201 if (type_sym is Class) {
202 type = (TypeSymbol) type_sym;
203 if (((Class) type).is_error_base) {
204 type_reference = new ErrorType (null, null, source_reference);
205 } else {
206 type_reference = new ObjectType ((Class) type);
208 } else if (type_sym is Struct) {
209 type = (TypeSymbol) type_sym;
210 type_reference = new StructValueType ((Struct) type);
211 } else if (type_sym is ErrorCode) {
212 type_reference = new ErrorType ((ErrorDomain) type_sym.parent_symbol, (ErrorCode) type_sym, source_reference);
213 symbol_reference = type_sym;
214 } else {
215 error = true;
216 Report.error (source_reference, "`%s' is not a class, struct, or error code".printf (type_sym.get_full_name ()));
217 return false;
220 foreach (DataType type_arg in type_args) {
221 type_reference.add_type_argument (type_arg);
223 } else {
224 type = type_reference.data_type;
227 value_type = type_reference.copy ();
228 value_type.value_owned = true;
230 bool may_throw = false;
232 int given_num_type_args = type_reference.get_type_arguments ().size;
233 int expected_num_type_args = 0;
235 if (type is Class) {
236 var cl = (Class) type;
238 expected_num_type_args = cl.get_type_parameters ().size;
240 if (struct_creation) {
241 error = true;
242 Report.error (source_reference, "syntax error, use `new' to create new objects");
243 return false;
246 if (cl.is_abstract) {
247 value_type = null;
248 error = true;
249 Report.error (source_reference, "Can't create instance of abstract class `%s'".printf (cl.get_full_name ()));
250 return false;
253 if (symbol_reference == null) {
254 symbol_reference = cl.default_construction_method;
256 if (symbol_reference == null) {
257 error = true;
258 Report.error (source_reference, "`%s' does not have a default constructor".printf (cl.get_full_name ()));
259 return false;
262 // track usage for flow analyzer
263 symbol_reference.used = true;
264 symbol_reference.check_deprecated (source_reference);
267 if (symbol_reference != null && symbol_reference.access == SymbolAccessibility.PRIVATE) {
268 bool in_target_type = false;
269 for (Symbol this_symbol = analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
270 if (this_symbol == cl) {
271 in_target_type = true;
272 break;
276 if (!in_target_type) {
277 error = true;
278 Report.error (source_reference, "Access to private member `%s' denied".printf (symbol_reference.get_full_name ()));
279 return false;
283 while (cl != null) {
284 if (cl.get_ref_sink_function () != null) {
285 value_type.floating_reference = true;
286 break;
289 cl = cl.base_class;
291 } else if (type is Struct) {
292 var st = (Struct) type;
294 expected_num_type_args = st.get_type_parameters ().size;
296 if (!struct_creation && !analyzer.context.deprecated) {
297 Report.warning (source_reference, "deprecated syntax, don't use `new' to initialize structs");
300 if (symbol_reference == null) {
301 symbol_reference = st.default_construction_method;
305 if (expected_num_type_args > given_num_type_args) {
306 error = true;
307 Report.error (source_reference, "too few type arguments");
308 return false;
309 } else if (expected_num_type_args < given_num_type_args) {
310 error = true;
311 Report.error (source_reference, "too many type arguments");
312 return false;
315 if (symbol_reference == null && get_argument_list ().size != 0) {
316 value_type = null;
317 error = true;
318 Report.error (source_reference, "No arguments allowed when constructing type `%s'".printf (type.get_full_name ()));
319 return false;
322 if (symbol_reference is Method) {
323 var m = (Method) symbol_reference;
325 var args = get_argument_list ();
326 Iterator<Expression> arg_it = args.iterator ();
327 foreach (FormalParameter param in m.get_parameters ()) {
328 if (param.ellipsis) {
329 break;
332 if (arg_it.next ()) {
333 Expression arg = arg_it.get ();
335 /* store expected type for callback parameters */
336 arg.formal_target_type = param.variable_type;
337 arg.target_type = arg.formal_target_type.get_actual_type (value_type, null, this);
341 foreach (Expression arg in args) {
342 arg.check (analyzer);
345 analyzer.check_arguments (this, new MethodType (m), m.get_parameters (), args);
347 foreach (DataType error_type in m.get_error_types ()) {
348 may_throw = true;
350 // ensure we can trace back which expression may throw errors of this type
351 var call_error_type = error_type.copy ();
352 call_error_type.source_reference = source_reference;
354 add_error_type (call_error_type);
356 } else if (type_reference is ErrorType) {
357 if (type_reference != null) {
358 type_reference.check (analyzer);
361 if (member_name != null) {
362 member_name.check (analyzer);
365 foreach (Expression arg in argument_list) {
366 arg.check (analyzer);
369 foreach (MemberInitializer init in object_initializer) {
370 init.check (analyzer);
373 if (get_argument_list ().size == 0) {
374 error = true;
375 Report.error (source_reference, "Too few arguments, errors need at least 1 argument");
376 } else {
377 Iterator<Expression> arg_it = get_argument_list ().iterator ();
378 arg_it.next ();
379 var ex = arg_it.get ();
380 if (ex.value_type == null || !ex.value_type.compatible (analyzer.string_type)) {
381 error = true;
382 Report.error (source_reference, "Invalid type for argument 1");
387 foreach (MemberInitializer init in get_object_initializer ()) {
388 analyzer.visit_member_initializer (init, type_reference);
391 if (may_throw) {
392 if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
393 // simple statements, no side effects after method call
394 } else if (!(analyzer.current_symbol is Block)) {
395 if (analyzer.context.profile != Profile.DOVA) {
396 // can't handle errors in field initializers
397 Report.error (source_reference, "Field initializers must not throw errors");
399 } else {
400 // store parent_node as we need to replace the expression in the old parent node later on
401 var old_parent_node = parent_node;
403 var local = new LocalVariable (value_type, get_temp_name (), null, source_reference);
404 // use floating variable to avoid unnecessary (and sometimes impossible) copies
405 local.floating = true;
406 var decl = new DeclarationStatement (local, source_reference);
408 insert_statement (analyzer.insert_block, decl);
410 Expression temp_access = new MemberAccess.simple (local.name, source_reference);
411 temp_access.target_type = target_type;
413 // don't set initializer earlier as this changes parent_node and parent_statement
414 local.initializer = this;
415 decl.check (analyzer);
416 temp_access.check (analyzer);
418 // move temp variable to insert block to ensure the
419 // variable is in the same block as the declaration
420 // otherwise there will be scoping issues in the generated code
421 var block = (Block) analyzer.current_symbol;
422 block.remove_local_variable (local);
423 analyzer.insert_block.add_local_variable (local);
425 old_parent_node.replace_expression (this, temp_access);
429 return !error;
432 public override void emit (CodeGenerator codegen) {
433 foreach (Expression arg in argument_list) {
434 arg.emit (codegen);
437 foreach (MemberInitializer init in object_initializer) {
438 init.emit (codegen);
441 codegen.visit_object_creation_expression (this);
443 codegen.visit_expression (this);
446 public override void get_defined_variables (Collection<LocalVariable> collection) {
447 foreach (Expression arg in argument_list) {
448 arg.get_defined_variables (collection);
452 public override void get_used_variables (Collection<LocalVariable> collection) {
453 foreach (Expression arg in argument_list) {
454 arg.get_used_variables (collection);