valasemanticanalyzer.vala 88 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
 */

using GLib;
25
using Gee;
26

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

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

43
	Collection<NamespaceReference> current_using_directives;
44

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

	private int next_lambda_id = 0;
64

65
66
	private Collection<BindingProvider> binding_providers = new ArrayList<BindingProvider> ();

67
	public SemanticAnalyzer (bool manage_memory = true) {
68
69
		memory_management = manage_memory;
	}
70

71
72
73
74
	public void add_binding_provider (BindingProvider! binding_provider) {
		binding_providers.add (binding_provider);
	}

75
76
77
78
79
80
	/**
	 * Analyze and check code in the specified context.
	 *
	 * @param context a code context
	 */
	public void analyze (CodeContext! context) {
81
		root_symbol = context.root;
82
83

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

		string_type = new TypeReference ();
87
		string_type.data_type = (DataType) root_symbol.scope.lookup ("string");
88

89
		pointer_type = (DataType) root_symbol.scope.lookup ("pointer");
90

91
		int_type = new TypeReference ();
92
		int_type.data_type = (DataType) root_symbol.scope.lookup ("int");
93

94
		uint_type = new TypeReference ();
95
		uint_type.data_type = (DataType) root_symbol.scope.lookup ("uint");
96

97
		ulong_type = new TypeReference ();
98
		ulong_type.data_type = (DataType) root_symbol.scope.lookup ("ulong");
99

100
		unichar_type = new TypeReference ();
101
		unichar_type.data_type = (DataType) root_symbol.scope.lookup ("unichar");
102

103
		// TODO: don't require GLib namespace in semantic analyzer
104
		var glib_ns = root_symbol.scope.lookup ("GLib");
105
		if (glib_ns != null) {
106
			object_type = (DataType) glib_ns.scope.lookup ("Object");
107
			initially_unowned_type = (DataType) glib_ns.scope.lookup ("InitiallyUnowned");
108

109
			type_type = new TypeReference ();
110
			type_type.data_type = (DataType) glib_ns.scope.lookup ("Type");
111

112
113
			glist_type = (DataType) glib_ns.scope.lookup ("List");
			gslist_type = (DataType) glib_ns.scope.lookup ("SList");
114

115
			gerror_type = (DataType) glib_ns.scope.lookup ("Error");
116
		}
117

118
119
120
		var gee_ns = root_symbol.scope.lookup ("Gee");
		if (gee_ns != null) {
			iterable_type = (DataType) gee_ns.scope.lookup ("Iterable");
121
			iterator_type = (DataType) gee_ns.scope.lookup ("Iterator");
122
123
			list_type = (DataType) gee_ns.scope.lookup ("List");
			map_type = (DataType) gee_ns.scope.lookup ("Map");
124
125
		}

126
127
128
		current_symbol = root_symbol;
		context.accept (this);
	}
129

130
	public override void visit_source_file (SourceFile! file) {
131
132
		current_source_file = file;
		current_using_directives = file.get_using_directives ();
133

134
		next_lambda_id = 0;
135

136
137
		file.accept_children (this);

138
139
		current_using_directives = null;
	}
140

141
	public override void visit_class (Class! cl) {
142
		current_symbol = cl;
143
		current_class = cl;
144

145
		if (cl.base_class != null) {
146
			current_source_file.add_symbol_dependency (cl.base_class, SourceFileDependencyType.HEADER_FULL);
147
		}
148

149
		foreach (TypeReference base_type_reference in cl.get_base_types ()) {
150
			current_source_file.add_symbol_dependency (base_type_reference.data_type, SourceFileDependencyType.HEADER_FULL);
151
		}
152

153
		cl.accept_children (this);
154

155
		/* gather all prerequisites */
156
		Gee.List<DataType> prerequisites = new ArrayList<DataType> ();
157
158
		foreach (TypeReference base_type in cl.get_base_types ()) {
			if (base_type.data_type is Interface) {
159
				get_all_prerequisites ((Interface) base_type.data_type, prerequisites);
160
161
162
			}
		}
		/* check whether all prerequisites are met */
163
		Gee.List<string> missing_prereqs = new ArrayList<string> ();
164
		foreach (DataType prereq in prerequisites) {
165
			if (!class_is_a (cl, prereq)) {
166
				missing_prereqs.insert (0, prereq.get_full_name ());
167
168
169
			}
		}
		/* report any missing prerequisites */
170
		if (missing_prereqs.size > 0) {
171
			cl.error = true;
172

173
			string error_string = "%s: some prerequisites (".printf (cl.get_full_name ());
174
175
176
177
178
179
180
181
182
183
184
185
			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);
		}
186

187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
		/* VAPI classes don't have to specify overridden methods */
		if (!cl.source_reference.file.pkg) {
			/* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
			foreach (TypeReference base_type in cl.get_base_types ()) {
				if (base_type.data_type is Interface) {
					Interface iface = (Interface) base_type.data_type;

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

					/* check methods */
					foreach (Method m in iface.get_methods ()) {
						if (m.is_abstract) {
							var sym = cl.scope.lookup (m.name);
							if (sym == null || !(sym is Method) || ((Method) sym).base_interface_method != m) {
								cl.error = true;
								Report.error (cl.source_reference, "`%s' does not implement interface method `%s'".printf (cl.get_full_name (), m.get_full_name ()));
							}
206
207
208
209
210
						}
					}
				}
			}

211
212
213
214
215
216
217
218
219
220
221
			/* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
			if (!cl.is_abstract) {
				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) {
							var sym = cl.scope.lookup (m.name);
							if (sym == null || !(sym is Method) || ((Method) sym).base_method != m) {
								cl.error = true;
								Report.error (cl.source_reference, "`%s' does not implement abstract method `%s'".printf (cl.get_full_name (), m.get_full_name ()));
							}
222
						}
223
					}
224
					base_class = base_class.base_class;
225
226
227
				}
			}
		}
228

229
		current_symbol = current_symbol.parent_symbol;
230
		current_class = null;
231
	}
232

233
	private void get_all_prerequisites (Interface! iface, Collection<DataType> list) {
234
235
236
237
238
239
240
		foreach (TypeReference prereq in iface.get_prerequisites ()) {
			DataType type = prereq.data_type;
			/* skip on previous errors */
			if (type == null) {
				continue;
			}

241
			list.add (type);
242
			if (type is Interface) {
243
				get_all_prerequisites ((Interface) type, list);
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267

			}
		}
	}

	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) {
268
		current_symbol = st;
269
		current_struct = st;
270

271
272
		st.accept_children (this);

273
		current_symbol = current_symbol.parent_symbol;
274
		current_struct = null;
275
	}
276

277
	public override void visit_interface (Interface! iface) {
278
		current_symbol = iface;
279

280
		foreach (TypeReference prerequisite_reference in iface.get_prerequisites ()) {
281
			current_source_file.add_symbol_dependency (prerequisite_reference.data_type, SourceFileDependencyType.HEADER_FULL);
282
283
		}

284
285
286
287
288
289
290
291
292
293
294
295
296
		/* 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;
297
					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 ()));
298
299
					return;
				}
300

301
				prereq_class = (Class) class_or_interface;
302
303
			}
		}
304

305
306
		iface.accept_children (this);

307
308
		current_symbol = current_symbol.parent_symbol;
	}
309

310
311
312
313
	public override void visit_callback (Callback! cb) {
		cb.accept_children (this);
	}

314
	public override void visit_constant (Constant! c) {
315
316
		c.accept_children (this);

317
318
319
320
321
322
323
		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");
			}
		}
	}
324

325
	public override void visit_field (Field! f) {
326
327
		f.accept_children (this);

328
		if (!f.is_internal_symbol ()) {
329
			if (f.type_reference.data_type != null) {
330
				/* is null if it references a type parameter */
331
				current_source_file.add_symbol_dependency (f.type_reference.data_type, SourceFileDependencyType.HEADER_SHALLOW);
332
			}
333
		} else {
334
335
336
337
338
339
			if (f.parent_symbol is Namespace) {
				f.error = true;
				Report.error (f.source_reference, "Namespaces may not have private members");
				return;
			}

340
			if (f.type_reference.data_type != null) {
341
				/* is null if it references a type parameter */
342
				current_source_file.add_symbol_dependency (f.type_reference.data_type, SourceFileDependencyType.SOURCE);
343
344
			}
		}
345
	}
346

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

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

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

		m.accept_children (this);

		current_symbol = current_symbol.parent_symbol;
		current_return_type = null;

369
		if (current_symbol.parent_symbol is Method) {
370
			/* lambda expressions produce nested methods */
371
			var up_method = (Method) current_symbol.parent_symbol;
372
373
374
			current_return_type = up_method.return_type;
		}

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

393
	private void find_base_class_method (Method! m, Class! cl) {
394
395
396
		var sym = cl.scope.lookup (m.name);
		if (sym is Method) {
			var base_method = (Method) sym;
397
			if (base_method.is_abstract || base_method.is_virtual) {
398
				if (!cl.source_reference.file.pkg && !m.equals (base_method)) {
399
					m.error = true;
400
					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 ()));
401
402
					return;
				}
403

404
405
406
407
408
				m.base_method = base_method;
				return;
			}
		}

409
410
411
412
413
414
		if (cl.base_class != null) {
			find_base_class_method (m, cl.base_class);
		}
	}

	private void find_base_interface_method (Method! m, Class! cl) {
415
		// FIXME report error if multiple possible base methods are found
416
417
		foreach (TypeReference type in cl.get_base_types ()) {
			if (type.data_type is Interface) {
418
419
420
				var sym = type.data_type.scope.lookup (m.name);
				if (sym is Method) {
					var base_method = (Method) sym;
421
					if (base_method.is_abstract) {
422
						if (!cl.source_reference.file.pkg && !m.equals (base_method)) {
423
							m.error = true;
424
							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 ()));
425
426
							return;
						}
427

428
429
430
						m.base_interface_method = base_method;
						return;
					}
431
432
433
434
435
				}
			}
		}
	}

436
437
	public override void visit_creation_method (CreationMethod! m) {
		m.return_type = new TypeReference ();
438
		m.return_type.data_type = (DataType) m.parent_symbol;
439
440
		m.return_type.transfers_ownership = true;

441
		if (current_symbol is Class) {
442
			// check for floating reference
443
			var cl = (Class) current_symbol;
444
445
446
447
448
449
450
451
452
453
			while (cl != null) {
				if (cl == initially_unowned_type) {
					m.return_type.floating_reference = true;
					break;
				}

				cl = cl.base_class;
			}
		}

454
		current_symbol = m;
455
456
457
458
		current_return_type = m.return_type;

		m.accept_children (this);

459
460
		current_symbol = current_symbol.parent_symbol;
		current_return_type = null;
461

462
		if (current_symbol.parent_symbol is Method) {
463
			/* lambda expressions produce nested methods */
464
			var up_method = (Method) current_symbol.parent_symbol;
465
466
			current_return_type = up_method.return_type;
		}
467

468
469
470
		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;
471
		}
472
	}
473

474
	public override void visit_formal_parameter (FormalParameter! p) {
475
476
		p.accept_children (this);

477
		if (!p.ellipsis) {
478
			if (p.type_reference.data_type != null) {
479
				/* is null if it references a type parameter */
480
481
482
				if (!p.is_internal_symbol ()) {
					current_source_file.add_symbol_dependency (p.type_reference.data_type, SourceFileDependencyType.HEADER_SHALLOW);
				}
483
				current_source_file.add_symbol_dependency (p.type_reference.data_type, SourceFileDependencyType.SOURCE);
484
485
			}
		}
486

487
488
		/* special treatment for construct formal parameters used in creation methods */
		if (p.construct_parameter) {
489
			if (!(p.parent_symbol is CreationMethod)) {
490
491
492
493
				p.error = true;
				Report.error (p.source_reference, "construct parameters are only allowed in type creation methods");
				return;
			}
494

495
			var method_body = ((CreationMethod) p.parent_symbol).body;
496
			var left = new MemberAccess (new MemberAccess.simple ("this"), p.name);
497
			var right = new MemberAccess.simple (p.name);
498

499
			method_body.add_statement (new ExpressionStatement (new Assignment (left, right), p.source_reference));
500
		}
501
	}
502

503
	private void find_base_class_property (Property! prop, Class! cl) {
504
505
506
		var sym = cl.scope.lookup (prop.name);
		if (sym is Property) {
			var base_property = (Property) sym;
507
508
509
			if (base_property.is_abstract || base_property.is_virtual) {
				if (!prop.equals (base_property)) {
					prop.error = true;
510
					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 ()));
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
					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) {
528
529
530
				var sym = type.data_type.scope.lookup (prop.name);
				if (sym is Property) {
					var base_property = (Property) sym;
531
532
533
					if (base_property.is_abstract) {
						if (!prop.equals (base_property)) {
							prop.error = true;
534
							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 ()));
535
536
537
538
539
540
541
542
543
544
545
							return;
						}

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

546
	public override void visit_property (Property! prop) {
547
548
		current_symbol = prop;

549
550
		prop.accept_children (this);

551
552
		current_symbol = current_symbol.parent_symbol;

553
		if (prop.type_reference.data_type != null) {
554
			/* is null if it references a type parameter */
555
556
557
			if (!prop.is_internal_symbol ()) {
				current_source_file.add_symbol_dependency (prop.type_reference.data_type, SourceFileDependencyType.HEADER_SHALLOW);
			}
558
			current_source_file.add_symbol_dependency (prop.type_reference.data_type, SourceFileDependencyType.SOURCE);
559
		}
560

561
562
		if (prop.parent_symbol is Class) {
			var cl = (Class) prop.parent_symbol;
563
564
565
566
567
			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;
568
					Report.error (prop.source_reference, "%s: no suitable property found to override".printf (prop.get_full_name ()));
569
570
571
				}
			}
		}
572
	}
573

574
	public override void visit_property_accessor (PropertyAccessor! acc) {
575
		acc.prop = (Property) current_symbol;
576

577
		if (acc.readable) {
578
			current_return_type = acc.prop.type_reference;
579
580
581
		} else {
			// void
			current_return_type = new TypeReference ();
582
583
		}

584
585
586
587
588
589
		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) {
590
					acc.body.add_statement (new ReturnStatement (new MemberAccess.simple ("_%s".printf (acc.prop.name)), acc.source_reference));
591
				} else {
592
					acc.body.add_statement (new ExpressionStatement (new Assignment (new MemberAccess.simple ("_%s".printf (acc.prop.name)), new MemberAccess.simple ("value")), acc.source_reference));
593
594
595
				}
			}

596
			if (acc.body != null && (acc.writable || acc.construction)) {
597
				acc.value_parameter = new FormalParameter ("value", acc.prop.type_reference, acc.source_reference);
598
599
600
601
				acc.body.scope.add (acc.value_parameter.name, acc.value_parameter);
			}
		}

602
603
		acc.accept_children (this);

604
605
		current_return_type = null;
	}
606

607
608
	public override void visit_signal (Signal! sig) {
		sig.accept_children (this);
609
	}
610

611
	public override void visit_constructor (Constructor! c) {
612
613
614
615
616
617
		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;
618
619
620

		c.accept_children (this);

621
622
		current_symbol = current_symbol.parent_symbol;
	}
623

624
	public override void visit_destructor (Destructor! d) {
625
626
		d.owner = current_symbol.scope;
		current_symbol = d;
627

628
629
		d.accept_children (this);

630
631
		current_symbol = current_symbol.parent_symbol;
	}
632

633
634
635
636
	public override void visit_named_argument (NamedArgument! n) {
	}

	public override void visit_begin_block (Block! b) {
637
638
		b.owner = current_symbol.scope;
		current_symbol = b;
639
640
641
642
	}

	public override void visit_end_block (Block! b) {
		foreach (VariableDeclarator decl in b.get_local_variables ()) {
643
			decl.active = false;
644
		}
645

646
647
		current_symbol = current_symbol.parent_symbol;
	}
648

649
	public override void visit_variable_declarator (VariableDeclarator! decl) {
650
651
652
653
654
655
		if (decl.initializer != null) {
			decl.initializer.expected_type = decl.type_reference;
		}

		decl.accept_children (this);

656
657
		if (decl.type_reference == null) {
			/* var type */
658

659
660
661
662
			if (decl.initializer == null) {
				decl.error = true;
				Report.error (decl.source_reference, "var declaration not allowed without initializer");
				return;
663
			}
664
665
666
667
668
			if (decl.initializer.static_type == null) {
				decl.error = true;
				Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
				return;
			}
669

670
			decl.type_reference = decl.initializer.static_type.copy ();
671
			decl.type_reference.takes_ownership = (decl.type_reference.data_type == null || decl.type_reference.data_type.is_reference_type ());
672
			decl.type_reference.transfers_ownership = false;
673
		}
674

675
676
677
		if (decl.initializer != null) {
			if (decl.initializer.static_type == null) {
				if (!(decl.initializer is MemberAccess)) {
678
					decl.error = true;
679
					Report.error (decl.source_reference, "expression type not allowed as initializer");
680
681
					return;
				}
682

683
				if (decl.initializer.symbol_reference is Method &&
684
				    decl.type_reference.data_type is Callback) {
685
					var m = (Method) decl.initializer.symbol_reference;
686
					var cb = (Callback) decl.type_reference.data_type;
687

688
689
					/* check whether method matches callback type */
					if (!cb.matches_method (m)) {
690
						decl.error = true;
691
						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 ()));
692
693
						return;
					}
694

695
696
697
698
699
					decl.initializer.static_type = decl.type_reference;
				} else {
					decl.error = true;
					Report.error (decl.source_reference, "expression type not allowed as initializer");
					return;
700
				}
701
			}
702

703
			if (memory_management) {
704
				if (decl.initializer.static_type.transfers_ownership) {
705
					/* rhs transfers ownership of the expression */
706
					if (!decl.type_reference.takes_ownership) {
707
708
709
710
						/* lhs doesn't own the value */
						decl.error = true;
						Report.error (decl.source_reference, "Invalid assignment from owned expression to unowned variable");
						return;
711
712
713
					}
				}
			}
714
		}
715

716
		if (decl.type_reference.data_type != null) {
717
			current_source_file.add_symbol_dependency (decl.type_reference.data_type, SourceFileDependencyType.SOURCE);
718
719
		}

720
		current_symbol.scope.add (decl.name, decl);
721

722
		var block = (Block) current_symbol;
723
		block.add_local_variable (decl);
724

725
		decl.active = true;
726
	}
727

728
729
730
731
732
	/**
	 * Visit operation called for initializer lists
	 *
	 * @param list an initializer list
	 */
733
	public override void visit_initializer_list (InitializerList! list) {
734
735
736
737
738
739
		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 ();
740

741
742
743
744
745
			if (rank > 1) {
				child_type.data_type = edt.element_type.get_array (rank - 1);
			} else {
				child_type.data_type = edt.element_type;
			}
746

747
748
749
750
			foreach (Expression e in inits) {
				e.expected_type = child_type.copy ();
			}
		}
751

752
753
		list.accept_children (this);

754
755
756
757
758
759
		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;
760

761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
			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));
					}
				}
			}
794

795
796
797
798
799
800
			if (!error) {
				/* everything seems to be correct */
				list.static_type = list.expected_type;
			}
		}
	}
801

802
803
	public override void visit_expression_statement (ExpressionStatement! stmt) {
		if (stmt.expression.static_type != null &&
804
		    stmt.expression.static_type.transfers_ownership) {
805
			Report.warning (stmt.source_reference, "Short-living reference");
806
		}
807
808

		stmt.tree_can_fail = stmt.expression.tree_can_fail;
809
	}
810

811
	public override void visit_if_statement (IfStatement! stmt) {
812
813
814
815
816
		if (stmt.condition.error) {
			/* if there was an error in the condition, skip this check */
			stmt.error = true;
			return;
		}
817

818
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
819
820
821
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
822
		}
823
	}
824

825
	public override void visit_while_statement (WhileStatement! stmt) {
826
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
827
828
829
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
830
		}
831
	}
832

833
	public override void visit_for_statement (ForStatement! stmt) {
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_begin_foreach_statement (ForeachStatement! stmt) {
842
		if (stmt.type_reference.data_type != null) {
843
			current_source_file.add_symbol_dependency (stmt.type_reference.data_type, SourceFileDependencyType.SOURCE);
844
		}
845

846
		stmt.variable_declarator = new VariableDeclarator (stmt.variable_name);
847
		stmt.variable_declarator.type_reference = stmt.type_reference;
848

849
		stmt.body.scope.add (stmt.variable_name, stmt.variable_declarator);
850
851
852

		stmt.body.add_local_variable (stmt.variable_declarator);
		stmt.variable_declarator.active = true;
853
	}
854

855
	public override void visit_end_foreach_statement (ForeachStatement! stmt) {
856
857
858
859
860
861
		if (stmt.collection.error) {
			// ignore inner error
			stmt.error = true;
			return;
		}

862
863
864
865
866
867
868
869
		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;

870
		var collection_type = stmt.collection.static_type.data_type;
871
872
873
874
875
876
877
878
879
880
		if (iterable_type != null && (collection_type == iterable_type || collection_type.is_subtype_of (iterable_type))) {
			stmt.iterator_variable_declarator = new VariableDeclarator ("%s_it".printf (stmt.variable_name));
			stmt.iterator_variable_declarator.type_reference = new TypeReference ();
			stmt.iterator_variable_declarator.type_reference.data_type = iterator_type;
			stmt.iterator_variable_declarator.type_reference.takes_ownership = true;
			stmt.iterator_variable_declarator.type_reference.add_type_argument (stmt.type_reference);

			stmt.add_local_variable (stmt.iterator_variable_declarator);
			stmt.iterator_variable_declarator.active = true;
		} else if (!(collection_type is Array || collection_type == glist_type || collection_type == gslist_type)) {
881
882
883
884
			stmt.error = true;
			Report.error (stmt.source_reference, "Collection not iterable");
			return;
		}
885
886

		stmt.tree_can_fail = stmt.collection.tree_can_fail || stmt.body.tree_can_fail;
887
888
	}

889
	public override void visit_end_return_statement (ReturnStatement! stmt) {
890
891
		if (stmt.return_expression != null && stmt.return_expression.error) {
			// ignore inner error
892
			stmt.error = true;
893