valasemanticanalyzer.vala 83.8 KB
Newer Older
1
2
/* valasemanticanalyzer.vala
 *
3
 * Copyright (C) 2006-2007  Jürg Billeter, Raffaele Sandrini
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
 *
 * This library is free software; you can redistribute it and/or
 * modify it under the terms of the GNU Lesser General Public
 * License as published by the Free Software Foundation; either
 * version 2 of the License, or (at your option) any later version.

 * This library is distributed in the hope that it will be useful,
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
 * Lesser General Public License for more details.

 * You should have received a copy of the GNU Lesser General Public
 * License along with this library; if not, write to the Free Software
 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
 *
 * Author:
 * 	Jürg Billeter <j@bitron.ch>
21
 *	Raffaele Sandrini <rasa@gmx.ch>
22
23
24
25
 */

using GLib;

26
27
28
29
30
31
32
33
/**
 * Code visitor analyzing and checking code.
 */
public class Vala.SemanticAnalyzer : CodeVisitor {
	/**
	 * Specifies whether automatic memory management is active.
	 */
	public bool memory_management { get; set; }
34

35
36
37
38
	Symbol root_symbol;
	Symbol current_symbol;
	SourceFile current_source_file;
	TypeReference current_return_type;
39
	Class current_class;
40
	Struct current_struct;
41

42
	List<weak NamespaceReference> current_using_directives;
43

44
45
	TypeReference bool_type;
	TypeReference string_type;
46
	TypeReference int_type;
47
	TypeReference uint_type;
48
	TypeReference ulong_type;
49
	TypeReference unichar_type;
50
	TypeReference type_type;
51
	DataType pointer_type;
52
	DataType object_type;
53
	DataType initially_unowned_type;
54
55
	DataType glist_type;
	DataType gslist_type;
56
	DataType gerror_type;
57
	DataType iterable_type;
58
	DataType iterator_type;
59
60
	DataType list_type;
	DataType map_type;
61
62

	private int next_lambda_id = 0;
63

64
	public SemanticAnalyzer (bool manage_memory = true) {
65
66
		memory_management = manage_memory;
	}
67

68
69
70
71
72
73
	/**
	 * Analyze and check code in the specified context.
	 *
	 * @param context a code context
	 */
	public void analyze (CodeContext! context) {
74
		root_symbol = context.root;
75
76

		bool_type = new TypeReference ();
77
		bool_type.data_type = (DataType) root_symbol.scope.lookup ("bool");
78
79

		string_type = new TypeReference ();
80
		string_type.data_type = (DataType) root_symbol.scope.lookup ("string");
81

82
		pointer_type = (DataType) root_symbol.scope.lookup ("pointer");
83

84
		int_type = new TypeReference ();
85
		int_type.data_type = (DataType) root_symbol.scope.lookup ("int");
86

87
		uint_type = new TypeReference ();
88
		uint_type.data_type = (DataType) root_symbol.scope.lookup ("uint");
89

90
		ulong_type = new TypeReference ();
91
		ulong_type.data_type = (DataType) root_symbol.scope.lookup ("ulong");
92

93
		unichar_type = new TypeReference ();
94
		unichar_type.data_type = (DataType) root_symbol.scope.lookup ("unichar");
95

96
		// TODO: don't require GLib namespace in semantic analyzer
97
		var glib_ns = root_symbol.scope.lookup ("GLib");
98
		if (glib_ns != null) {
99
			object_type = (DataType) glib_ns.scope.lookup ("Object");
100
			initially_unowned_type = (DataType) glib_ns.scope.lookup ("InitiallyUnowned");
101

102
			type_type = new TypeReference ();
103
			type_type.data_type = (DataType) glib_ns.scope.lookup ("Type");
104

105
106
			glist_type = (DataType) glib_ns.scope.lookup ("List");
			gslist_type = (DataType) glib_ns.scope.lookup ("SList");
107

108
			gerror_type = (DataType) glib_ns.scope.lookup ("Error");
109
		}
110

111
112
113
		var gee_ns = root_symbol.scope.lookup ("Gee");
		if (gee_ns != null) {
			iterable_type = (DataType) gee_ns.scope.lookup ("Iterable");
114
			iterator_type = (DataType) gee_ns.scope.lookup ("Iterator");
115
116
			list_type = (DataType) gee_ns.scope.lookup ("List");
			map_type = (DataType) gee_ns.scope.lookup ("Map");
117
118
		}

119
120
121
		current_symbol = root_symbol;
		context.accept (this);
	}
122

123
	public override void visit_source_file (SourceFile! file) {
124
125
		current_source_file = file;
		current_using_directives = file.get_using_directives ();
126

127
		next_lambda_id = 0;
128

129
130
		file.accept_children (this);

131
132
		current_using_directives = null;
	}
133

134
	public override void visit_class (Class! cl) {
135
		current_symbol = cl;
136
		current_class = cl;
137

138
		if (cl.base_class != null) {
139
			current_source_file.add_symbol_dependency (cl.base_class, SourceFileDependencyType.HEADER_FULL);
140
		}
141

142
		foreach (TypeReference base_type_reference in cl.get_base_types ()) {
143
			current_source_file.add_symbol_dependency (base_type_reference.data_type, SourceFileDependencyType.HEADER_FULL);
144
		}
145

146
		cl.accept_children (this);
147

148
149
150
151
		/* gather all prerequisites */
		List<DataType> prerequisites = null;
		foreach (TypeReference base_type in cl.get_base_types ()) {
			if (base_type.data_type is Interface) {
152
				prerequisites.concat (get_all_prerequisites ((Interface) base_type.data_type));
153
154
155
156
157
			}
		}
		/* check whether all prerequisites are met */
		List<string> missing_prereqs = null;
		foreach (DataType prereq in prerequisites) {
158
			if (!class_is_a (cl, prereq)) {
159
				missing_prereqs.prepend (prereq.get_full_name ());
160
161
162
163
164
			}
		}
		/* report any missing prerequisites */
		if (missing_prereqs != null) {
			cl.error = true;
165

166
			string error_string = "%s: some prerequisites (".printf (cl.get_full_name ());
167
168
169
170
171
172
173
174
175
176
177
178
			bool first = true;
			foreach (string s in missing_prereqs) {
				if (first) {
					error_string = "%s`%s'".printf (error_string, s);
					first = false;
				} else {
					error_string = "%s, `%s'".printf (error_string, s);
				}
			}
			error_string += ") are not met";
			Report.error (cl.source_reference, error_string);
		}
179

180
		/* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
181
182
		foreach (TypeReference base_type in cl.get_base_types ()) {
			if (base_type.data_type is Interface) {
183
184
				Interface iface = (Interface) base_type.data_type;

185
186
187
				/* We do not need to do expensive equality checking here since this is done
				 * already. We only need to guarantee the symbols are present.
				 */
188

189
190
				/* check methods */
				foreach (Method m in iface.get_methods ()) {
191
					if (m.is_abstract) {
192
193
						var sym = cl.scope.lookup (m.name);
						if (sym == null || !(sym is Method) || ((Method) sym).base_interface_method != m) {
194
							cl.error = true;
195
							Report.error (cl.source_reference, "`%s' does not implement interface method `%s'".printf (cl.get_full_name (), m.get_full_name ()));
196
197
198
199
200
201
202
203
204
205
206
207
208
209
						}
					}
				}
			}
		}

		/* all abstract symbols defined in base classes have to be implemented in non-abstract classes
		 * VAPI classes don't have to specify overridden methods
		 */
		if (!cl.is_abstract && !cl.source_reference.file.pkg) {
			var base_class = cl.base_class;
			while (base_class != null && base_class.is_abstract) {
				foreach (Method m in base_class.get_methods ()) {
					if (m.is_abstract) {
210
211
						var sym = cl.scope.lookup (m.name);
						if (sym == null || !(sym is Method) || ((Method) sym).base_method != m) {
212
							cl.error = true;
213
							Report.error (cl.source_reference, "`%s' does not implement abstract method `%s'".printf (cl.get_full_name (), m.get_full_name ()));
214
						}
215
216
					}
				}
217
				base_class = base_class.base_class;
218
219
			}
		}
220

221
		current_symbol = current_symbol.parent_symbol;
222
		current_class = null;
223
	}
224

225
	private List<DataType> get_all_prerequisites (Interface! iface) {
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
		List<DataType> ret = null;

		foreach (TypeReference prereq in iface.get_prerequisites ()) {
			DataType type = prereq.data_type;
			/* skip on previous errors */
			if (type == null) {
				continue;
			}

			ret.prepend (type);
			if (type is Interface) {
				ret.concat (get_all_prerequisites ((Interface) type));

			}
		}

		ret.reverse ();
		return #ret;
	}

	private bool class_is_a (Class! cl, DataType! t) {
		if (cl == t) {
			return true;
		}

		foreach (TypeReference base_type in cl.get_base_types ()) {
			if (base_type.data_type is Class) {
				if (class_is_a ((Class) base_type.data_type, t)) {
					return true;
				}
			} else if (base_type.data_type == t) {
				return true;
			}
		}

		return false;
	}

	public override void visit_struct (Struct! st) {
265
		current_symbol = st;
266
		current_struct = st;
267

268
269
		st.accept_children (this);

270
		current_symbol = current_symbol.parent_symbol;
271
		current_struct = null;
272
	}
273

274
	public override void visit_interface (Interface! iface) {
275
		current_symbol = iface;
276

277
		foreach (TypeReference prerequisite_reference in iface.get_prerequisites ()) {
278
			current_source_file.add_symbol_dependency (prerequisite_reference.data_type, SourceFileDependencyType.HEADER_FULL);
279
280
		}

281
282
283
284
285
286
287
288
289
290
291
292
293
		/* check prerequisites */
		Class prereq_class;
		foreach (TypeReference prereq in iface.get_prerequisites ()) {
			DataType class_or_interface = prereq.data_type;
			/* skip on previous errors */
			if (class_or_interface == null) {
				iface.error = true;
				continue;
			}
			/* interfaces are not allowed to have multiple instantiable prerequisites */
			if (class_or_interface is Class) {
				if (prereq_class != null) {
					iface.error = true;
294
					Report.error (iface.source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (iface.get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
295
296
					return;
				}
297

298
				prereq_class = (Class) class_or_interface;
299
300
			}
		}
301

302
303
304
305
306
307
308
309
310
		if (prereq_class == null) {
			/* default to GObject */
			var obj_type = new TypeReference ();
			obj_type.data_type = object_type;
			iface.prepend_prerequisite (obj_type);
		}

		iface.accept_children (this);

311
312
		current_symbol = current_symbol.parent_symbol;
	}
313

314
315
316
317
	public override void visit_callback (Callback! cb) {
		cb.accept_children (this);
	}

318
	public override void visit_constant (Constant! c) {
319
320
		c.accept_children (this);

321
322
323
324
325
326
327
		if (!current_source_file.pkg) {
			if (c.initializer == null) {
				c.error = true;
				Report.error (c.source_reference, "A const field requires a initializer to be provided");
			}
		}
	}
328

329
	public override void visit_field (Field! f) {
330
331
		f.accept_children (this);

332
		if (f.access != MemberAccessibility.PRIVATE) {
333
			if (f.type_reference.data_type != null) {
334
				/* is null if it references a type parameter */
335
				current_source_file.add_symbol_dependency (f.type_reference.data_type, SourceFileDependencyType.HEADER_SHALLOW);
336
			}
337
		} else {
338
			if (f.type_reference.data_type != null) {
339
				/* is null if it references a type parameter */
340
				current_source_file.add_symbol_dependency (f.type_reference.data_type, SourceFileDependencyType.SOURCE);
341
342
			}
		}
343
	}
344

345
	public override void visit_method (Method! m) {
346
		current_symbol = m;
347
		current_return_type = m.return_type;
348
349
350
351
352
353

		var init_attr = m.get_attribute ("ModuleInit");
		if (init_attr != null) {
			m.source_reference.file.context.module_init_method = m;
		}

354
		if (m.return_type.data_type != null) {
355
			/* is null if it is void or a reference to a type parameter */
356
			current_source_file.add_symbol_dependency (m.return_type.data_type, SourceFileDependencyType.HEADER_SHALLOW);
357
		}
358
359
360
361
362
363

		m.accept_children (this);

		current_symbol = current_symbol.parent_symbol;
		current_return_type = null;

364
		if (current_symbol.parent_symbol is Method) {
365
			/* lambda expressions produce nested methods */
366
			var up_method = (Method) current_symbol.parent_symbol;
367
368
369
			current_return_type = up_method.return_type;
		}

370
		if (current_symbol is Class) {
371
			if (!(m is CreationMethod)) {
372
				find_base_interface_method (m, (Class) current_symbol);
373
				if (m.is_virtual || m.overrides) {
374
					find_base_class_method (m, (Class) current_symbol);
375
					if (m.base_method == null) {
376
						Report.error (m.source_reference, "%s: no suitable method found to override".printf (m.get_full_name ()));
377
378
379
					}
				}
			}
380
		} else if (current_symbol is Struct) {
381
			if (m.is_abstract || m.is_virtual || m.overrides) {
382
				Report.error (m.source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m.get_full_name ()));
383
384
385
				return;
			}
		}
386
	}
387

388
	private void find_base_class_method (Method! m, Class! cl) {
389
390
391
		var sym = cl.scope.lookup (m.name);
		if (sym is Method) {
			var base_method = (Method) sym;
392
393
394
			if (base_method.is_abstract || base_method.is_virtual) {
				if (!m.equals (base_method)) {
					m.error = true;
395
					Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.get_full_name (), base_method.get_full_name ()));
396
397
					return;
				}
398

399
400
401
402
403
				m.base_method = base_method;
				return;
			}
		}

404
405
406
407
408
409
		if (cl.base_class != null) {
			find_base_class_method (m, cl.base_class);
		}
	}

	private void find_base_interface_method (Method! m, Class! cl) {
410
		// FIXME report error if multiple possible base methods are found
411
412
		foreach (TypeReference type in cl.get_base_types ()) {
			if (type.data_type is Interface) {
413
414
415
				var sym = type.data_type.scope.lookup (m.name);
				if (sym is Method) {
					var base_method = (Method) sym;
416
417
418
					if (base_method.is_abstract) {
						if (!m.equals (base_method)) {
							m.error = true;
419
							Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.get_full_name (), base_method.get_full_name ()));
420
421
							return;
						}
422

423
424
425
						m.base_interface_method = base_method;
						return;
					}
426
427
428
429
430
				}
			}
		}
	}

431
432
	public override void visit_creation_method (CreationMethod! m) {
		m.return_type = new TypeReference ();
433
		m.return_type.data_type = (DataType) m.parent_symbol;
434
435
		m.return_type.transfers_ownership = true;

436
		if (current_symbol is Class) {
437
			// check for floating reference
438
			var cl = (Class) current_symbol;
439
440
441
442
443
444
445
446
447
448
			while (cl != null) {
				if (cl == initially_unowned_type) {
					m.return_type.floating_reference = true;
					break;
				}

				cl = cl.base_class;
			}
		}

449
		current_symbol = m;
450
451
452
453
		current_return_type = m.return_type;

		m.accept_children (this);

454
455
		current_symbol = current_symbol.parent_symbol;
		current_return_type = null;
456

457
		if (current_symbol.parent_symbol is Method) {
458
			/* lambda expressions produce nested methods */
459
			var up_method = (Method) current_symbol.parent_symbol;
460
461
			current_return_type = up_method.return_type;
		}
462

463
464
465
		if (m.is_abstract || m.is_virtual || m.overrides) {
			Report.error (m.source_reference, "The creation method `%s' cannot be marked as override, virtual, or abstract".printf (m.get_full_name ()));
			return;
466
		}
467

468
		if (m.body != null && current_class != null) {
469
470
			int n_params = 0;
			foreach (Statement stmt in m.body.get_statements ()) {
471
				if (!(stmt is ExpressionStatement) || ((ExpressionStatement) stmt).assigned_property () == null) {
472
					m.error = true;
473
					Report.error (stmt.source_reference, "class creation methods only allow property assignment statements");
474
					return;
475
				}
476
477
478
				if (((ExpressionStatement) stmt).assigned_property ().set_accessor.construction) {
					n_params++;
				}
479
480
481
			}
			m.n_construction_params = n_params;
		}
482
	}
483

484
	public override void visit_formal_parameter (FormalParameter! p) {
485
486
		p.accept_children (this);

487
		if (!p.ellipsis) {
488
			if (p.type_reference.data_type != null) {
489
				/* is null if it references a type parameter */
490
491
				current_source_file.add_symbol_dependency (p.type_reference.data_type, SourceFileDependencyType.HEADER_SHALLOW);
				current_source_file.add_symbol_dependency (p.type_reference.data_type, SourceFileDependencyType.SOURCE);
492
493
			}
		}
494

495
496
		/* special treatment for construct formal parameters used in creation methods */
		if (p.construct_parameter) {
497
			if (!(p.parent_symbol is CreationMethod)) {
498
499
500
501
				p.error = true;
				Report.error (p.source_reference, "construct parameters are only allowed in type creation methods");
				return;
			}
502

503
			var method_body = ((CreationMethod) p.parent_symbol).body;
504
505
			var left = new MemberAccess.simple (p.name);
			var right = new MemberAccess.simple (p.name);
506

507
			/* try to lookup the requested property */
508
509
			var prop_sym = symbol_lookup_inherited (current_class, p.name);
			if (!(prop_sym is Property)) {
510
				p.error = true;
511
				Report.error (p.source_reference, "class `%s' does not contain a property named `%s'".printf (current_class.get_full_name (), p.name));
512
513
514
				return;
			}
			left.symbol_reference = prop_sym;
515

516
			right.symbol_reference = p;
517

518
519
			method_body.add_statement (new ExpressionStatement (new Assignment (left, right)));
		}
520
	}
521

522
	private void find_base_class_property (Property! prop, Class! cl) {
523
524
525
		var sym = cl.scope.lookup (prop.name);
		if (sym is Property) {
			var base_property = (Property) sym;
526
527
528
			if (base_property.is_abstract || base_property.is_virtual) {
				if (!prop.equals (base_property)) {
					prop.error = true;
529
					Report.error (prop.source_reference, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop.get_full_name (), base_property.get_full_name ()));
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
					return;
				}

				prop.base_property = base_property;
				return;
			}
		}

		if (cl.base_class != null) {
			find_base_class_property (prop, cl.base_class);
		}
	}

	private void find_base_interface_property (Property! prop, Class! cl) {
		// FIXME report error if multiple possible base properties are found
		foreach (TypeReference type in cl.get_base_types ()) {
			if (type.data_type is Interface) {
547
548
549
				var sym = type.data_type.scope.lookup (prop.name);
				if (sym is Property) {
					var base_property = (Property) sym;
550
551
552
					if (base_property.is_abstract) {
						if (!prop.equals (base_property)) {
							prop.error = true;
553
							Report.error (prop.source_reference, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop.get_full_name (), base_property.get_full_name ()));
554
555
556
557
558
559
560
561
562
563
564
							return;
						}

						prop.base_interface_property = base_property;
						return;
					}
				}
			}
		}
	}

565
	public override void visit_property (Property! prop) {
566
567
		current_symbol = prop;

568
569
		prop.accept_children (this);

570
571
		current_symbol = current_symbol.parent_symbol;

572
		if (prop.type_reference.data_type != null) {
573
			/* is null if it references a type parameter */
574
575
			current_source_file.add_symbol_dependency (prop.type_reference.data_type, SourceFileDependencyType.HEADER_SHALLOW);
			current_source_file.add_symbol_dependency (prop.type_reference.data_type, SourceFileDependencyType.SOURCE);
576
		}
577

578
579
		if (prop.parent_symbol is Class) {
			var cl = (Class) prop.parent_symbol;
580
581
582
583
584
			find_base_interface_property (prop, cl);
			if (prop.is_virtual || prop.overrides) {
				find_base_class_property (prop, cl);
				if (prop.base_property == null) {
					prop.error = true;
585
					Report.error (prop.source_reference, "%s: no suitable property found to override".printf (prop.get_full_name ()));
586
587
588
				}
			}
		}
589
	}
590

591
	public override void visit_property_accessor (PropertyAccessor! acc) {
592
		acc.prop = (Property) current_symbol;
593

594
		if (acc.readable) {
595
			current_return_type = acc.prop.type_reference;
596
597
598
		} else {
			// void
			current_return_type = new TypeReference ();
599
600
		}

601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
		if (!acc.source_reference.file.pkg) {
			if (acc.body == null && !acc.prop.interface_only && !acc.prop.is_abstract) {
				/* no accessor body specified, insert default body */
			
				acc.body = new Block ();
				if (acc.readable) {
					acc.body.add_statement (new ReturnStatement (new MemberAccess.simple ("_%s".printf (acc.prop.name))));
				} else {
					acc.body.add_statement (new ExpressionStatement (new Assignment (new MemberAccess.simple ("_%s".printf (acc.prop.name)), new MemberAccess.simple ("value"))));
				}
			}

			if (acc.writable || acc.construction) {
				acc.value_parameter = new FormalParameter ("value", acc.prop.type_reference);
				acc.body.scope.add (acc.value_parameter.name, acc.value_parameter);
			}
		}

619
620
		acc.accept_children (this);

621
622
		current_return_type = null;
	}
623

624
625
	public override void visit_signal (Signal! sig) {
		sig.accept_children (this);
626
	}
627

628
	public override void visit_constructor (Constructor! c) {
629
630
631
632
633
634
		c.this_parameter = new FormalParameter ("this", new TypeReference ());
		c.this_parameter.type_reference.data_type = (DataType) current_symbol;
		c.scope.add (c.this_parameter.name, c.this_parameter);

		c.owner = current_symbol.scope;
		current_symbol = c;
635
636
637

		c.accept_children (this);

638
639
		current_symbol = current_symbol.parent_symbol;
	}
640

641
	public override void visit_destructor (Destructor! d) {
642
643
		d.owner = current_symbol.scope;
		current_symbol = d;
644

645
646
		d.accept_children (this);

647
648
		current_symbol = current_symbol.parent_symbol;
	}
649

650
651
652
653
	public override void visit_named_argument (NamedArgument! n) {
	}

	public override void visit_begin_block (Block! b) {
654
655
		b.owner = current_symbol.scope;
		current_symbol = b;
656
657
658
659
	}

	public override void visit_end_block (Block! b) {
		foreach (VariableDeclarator decl in b.get_local_variables ()) {
660
			decl.active = false;
661
		}
662

663
664
		current_symbol = current_symbol.parent_symbol;
	}
665

666
667
668
	public override void visit_variable_declarator (VariableDeclarator! decl) {
		if (decl.type_reference == null) {
			/* var type */
669

670
671
672
673
			if (decl.initializer == null) {
				decl.error = true;
				Report.error (decl.source_reference, "var declaration not allowed without initializer");
				return;
674
			}
675
676
677
678
679
			if (decl.initializer.static_type == null) {
				decl.error = true;
				Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
				return;
			}
680

681
			decl.type_reference = decl.initializer.static_type.copy ();
682
			decl.type_reference.takes_ownership = (decl.type_reference.data_type == null || decl.type_reference.data_type.is_reference_type ());
683
			decl.type_reference.transfers_ownership = false;
684
		}
685

686
687
688
		if (decl.initializer != null) {
			if (decl.initializer.static_type == null) {
				if (!(decl.initializer is MemberAccess)) {
689
					decl.error = true;
690
					Report.error (decl.source_reference, "expression type not allowed as initializer");
691
692
					return;
				}
693

694
				if (decl.initializer.symbol_reference is Method &&
695
				    decl.type_reference.data_type is Callback) {
696
					var m = (Method) decl.initializer.symbol_reference;
697
					var cb = (Callback) decl.type_reference.data_type;
698

699
700
					/* check whether method matches callback type */
					if (!cb.matches_method (m)) {
701
						decl.error = true;
702
						Report.error (decl.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
703
704
						return;
					}
705

706
707
708
709
710
					decl.initializer.static_type = decl.type_reference;
				} else {
					decl.error = true;
					Report.error (decl.source_reference, "expression type not allowed as initializer");
					return;
711
				}
712
			}
713

714
			if (memory_management) {
715
				if (decl.initializer.static_type.transfers_ownership) {
716
					/* rhs transfers ownership of the expression */
717
					if (!decl.type_reference.takes_ownership) {
718
719
720
721
						/* lhs doesn't own the value */
						decl.error = true;
						Report.error (decl.source_reference, "Invalid assignment from owned expression to unowned variable");
						return;
722
723
724
					}
				}
			}
725
		}
726

727
		if (decl.type_reference.data_type != null) {
728
			current_source_file.add_symbol_dependency (decl.type_reference.data_type, SourceFileDependencyType.SOURCE);
729
730
		}

731
		current_symbol.scope.add (decl.name, decl);
732

733
		var block = (Block) current_symbol;
734
		block.add_local_variable (decl);
735

736
		decl.active = true;
737
	}
738

739
740
741
742
743
744
745
746
747
748
749
750
	/**
	 * Visit operation called for initializer lists
	 *
	 * @param list an initializer list
	 */
	public override void visit_begin_initializer_list (InitializerList! list) {
		if (list.expected_type != null && list.expected_type.data_type is Array) {
			/* initializer is used as array initializer */
			Array edt = (Array)list.expected_type.data_type;
			var inits = list.get_initializers ();
			int rank = ((Array)list.expected_type.data_type).rank;
			var child_type = list.expected_type.copy ();
751

752
753
754
755
756
			if (rank > 1) {
				child_type.data_type = edt.element_type.get_array (rank - 1);
			} else {
				child_type.data_type = edt.element_type;
			}
757

758
759
760
761
762
			foreach (Expression e in inits) {
				e.expected_type = child_type.copy ();
			}
		}
	}
763

764
765
766
767
768
769
770
771
772
773
774
775
	/**
	 * Visit operation called for initializer lists
	 *
	 * @param list an initializer list
	 */
	public override void visit_end_initializer_list (InitializerList! list) {
		if (list.expected_type != null && list.expected_type.data_type is Array) {
			Array edt = (Array)list.expected_type.data_type;
			var inits = list.get_initializers ();
			int rank = edt.rank;
			var child_type = list.expected_type.copy ();
			bool error = false;
776

777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
			if (rank > 1) {
				child_type.data_type = edt.element_type.get_array (rank - 1);
				foreach (Expression e in inits) {
					if (e.static_type == null) {
						error = true;
						continue;
					}
					if (!(e is InitializerList)) {
						error = true;
						e.error = true;
						Report.error (e.source_reference, "Initializer list expected");
						continue;
					}
					if (!e.static_type.equals (child_type)) {
						error = true;
						e.error = true;
						Report.error (e.source_reference, "Expected initializer list of type `%s' but got `%s'".printf (child_type.data_type.name, e.static_type.data_type.name));
					}
				}
			} else {
				child_type.data_type = edt.element_type;
				foreach (Expression e in inits) {
					if (e.static_type == null) {
						error = true;
						continue;
					}
					if (!is_type_compatible (e.static_type, child_type)) {
						error = true;
						e.error = true;
						Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (child_type.data_type.name, e.static_type.data_type.name));
					}
				}
			}
810

811
812
813
814
815
816
			if (!error) {
				/* everything seems to be correct */
				list.static_type = list.expected_type;
			}
		}
	}
817

818
819
	public override void visit_expression_statement (ExpressionStatement! stmt) {
		if (stmt.expression.static_type != null &&
820
		    stmt.expression.static_type.transfers_ownership) {
821
			Report.warning (stmt.source_reference, "Short-living reference");
822
		}
823
824

		stmt.tree_can_fail = stmt.expression.tree_can_fail;
825
	}
826

827
	public override void visit_if_statement (IfStatement! stmt) {
828
829
830
831
832
		if (stmt.condition.error) {
			/* if there was an error in the condition, skip this check */
			stmt.error = true;
			return;
		}
833

834
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
835
836
837
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
838
		}
839
	}
840

841
	public override void visit_while_statement (WhileStatement! stmt) {
842
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
843
844
845
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
846
		}
847
	}
848

849
	public override void visit_for_statement (ForStatement! stmt) {
850
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
851
852
853
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
854
		}
855
	}
856

857
	public override void visit_begin_foreach_statement (ForeachStatement! stmt) {
858
		if (stmt.type_reference.data_type != null) {
859
			current_source_file.add_symbol_dependency (stmt.type_reference.data_type, SourceFileDependencyType.SOURCE);
860
		}
861

862
		stmt.variable_declarator = new VariableDeclarator (stmt.variable_name);
863
		stmt.variable_declarator.type_reference = stmt.type_reference;
864

865
		stmt.body.scope.add (stmt.variable_name, stmt.variable_declarator);
866
867
868

		stmt.body.add_local_variable (stmt.variable_declarator);
		stmt.variable_declarator.active = true;
869
	}
870

871
	public override void visit_end_foreach_statement (ForeachStatement! stmt) {
872
873
874
875
876
877
878
879
		stmt.collection_variable_declarator = new VariableDeclarator ("%s_collection".printf (stmt.variable_name));
		stmt.collection_variable_declarator.type_reference = stmt.collection.static_type.copy ();
		stmt.collection_variable_declarator.type_reference.transfers_ownership = false;
		stmt.collection_variable_declarator.type_reference.takes_ownership = stmt.collection.static_type.transfers_ownership;

		stmt.add_local_variable (stmt.collection_variable_declarator);
		stmt.collection_variable_declarator.active = true;

880
		var collection_type = stmt.collection.static_type.data_type;