valasemanticanalyzer.vala 60.4 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
34
35
36
37
38
/**
 * Code visitor analyzing and checking code.
 */
public class Vala.SemanticAnalyzer : CodeVisitor {
	/**
	 * Specifies whether automatic memory management is active.
	 */
	public bool memory_management { get; set; }
	
	Symbol root_symbol;
	Symbol current_symbol;
	SourceFile current_source_file;
	TypeReference current_return_type;
39
	Class current_class;
40
	Struct current_struct;
41
42
43
44
45
	
	List<weak NamespaceReference> current_using_directives;
	
	TypeReference bool_type;
	TypeReference string_type;
46
	TypeReference int_type;
47
	TypeReference type_type;
48
	DataType pointer_type;
49
50
51
52
	DataType initially_unowned_type;

	private int next_lambda_id = 0;
	
53
	public SemanticAnalyzer (bool manage_memory = true) {
54
55
56
		memory_management = manage_memory;
	}
	
57
58
59
60
61
62
63
64
65
	/**
	 * Analyze and check code in the specified context.
	 *
	 * @param context a code context
	 */
	public void analyze (CodeContext! context) {
		root_symbol = context.get_root ();

		bool_type = new TypeReference ();
66
		bool_type.data_type = (DataType) root_symbol.lookup ("bool").node;
67
68

		string_type = new TypeReference ();
69
		string_type.data_type = (DataType) root_symbol.lookup ("string").node;
70
71

		pointer_type = (DataType) root_symbol.lookup ("pointer").node;
72
		
73
		int_type = new TypeReference ();
74
		int_type.data_type = (DataType) root_symbol.lookup ("int").node;
75
		
76
		// TODO: don't require GLib namespace in semantic analyzer
77
		var glib_ns = root_symbol.lookup ("GLib");
78
79
80
81
82
83
		if (glib_ns != null) {
			initially_unowned_type = (DataType) glib_ns.lookup ("InitiallyUnowned").node;
			
			type_type = new TypeReference ();
			type_type.data_type = (DataType) glib_ns.lookup ("Type").node;
		}
84

85
86
87
88
89
90
91
		current_symbol = root_symbol;
		context.accept (this);
	}
	
	public override void visit_begin_source_file (SourceFile! file) {
		current_source_file = file;
		current_using_directives = file.get_using_directives ();
92
		
93
94
		next_lambda_id = 0;
	}
95

96
97
98
	public override void visit_end_source_file (SourceFile! file) {
		current_using_directives = null;
	}
99

100
101
102
	public override void visit_begin_namespace (Namespace! ns) {
		current_symbol = ns.symbol;
	}
103

104
105
106
107
108
109
	public override void visit_end_namespace (Namespace! ns) {
		current_symbol = current_symbol.parent_symbol;
	}

	public override void visit_begin_class (Class! cl) {
		current_symbol = cl.symbol;
110
		current_class = cl;
111
		
112
113
		if (cl.base_class != null) {
			current_source_file.add_symbol_dependency (cl.base_class.symbol, SourceFileDependencyType.HEADER_FULL);
114
		}
115
116
117
118
		
		foreach (TypeReference base_type_reference in cl.get_base_types ()) {
			current_source_file.add_symbol_dependency (base_type_reference.data_type.symbol, SourceFileDependencyType.HEADER_FULL);
		}
119
	}
120

121
122
	public override void visit_end_class (Class! cl) {
		current_symbol = current_symbol.parent_symbol;
123
		current_class = null;
124
	}
125

126
127
	public override void visit_begin_struct (Struct! st) {
		current_symbol = st.symbol;
128
		current_struct = st;
129
	}
130

131
132
	public override void visit_end_struct (Struct! st) {
		current_symbol = current_symbol.parent_symbol;
133
		current_struct = null;
134
	}
135
136
137
138

	public override void visit_begin_interface (Interface! iface) {
		current_symbol = iface.symbol;
		
139
140
		foreach (TypeReference prerequisite_reference in iface.get_prerequisites ()) {
			current_source_file.add_symbol_dependency (prerequisite_reference.data_type.symbol, SourceFileDependencyType.HEADER_FULL);
141
142
143
144
145
146
		}
	}

	public override void visit_end_interface (Interface! iface) {
		current_symbol = current_symbol.parent_symbol;
	}
147
148
149
150
151
152
153
154
155
	
	public override void visit_constant (Constant! c) {
		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");
			}
		}
	}
156

157
	public override void visit_field (Field! f) {
158
		if (f.access != MemberAccessibility.PRIVATE) {
159
			if (f.type_reference.data_type != null) {
160
				/* is null if it references a type parameter */
161
				current_source_file.add_symbol_dependency (f.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
162
			}
163
		} else {
164
			if (f.type_reference.data_type != null) {
165
				/* is null if it references a type parameter */
166
				current_source_file.add_symbol_dependency (f.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
167
168
			}
		}
169
	}
170

171
	public override void visit_begin_method (Method! m) {	
172
173
174
		current_symbol = m.symbol;
		current_return_type = m.return_type;
		
175
		if (m.return_type.data_type != null) {
176
			/* is null if it is void or a reference to a type parameter */
177
			current_source_file.add_symbol_dependency (m.return_type.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
178
		}
179
	}
180

181
182
	private void find_base_class_method (Method! m, Class! cl) {
		var sym = cl.symbol.lookup (m.name);
183
184
185
186
187
188
189
190
191
192
193
194
195
196
		if (sym != null && sym.node is Method) {
			var base_method = (Method) sym.node;
			if (base_method.is_abstract || base_method.is_virtual) {
				if (!m.equals (base_method)) {
					m.error = true;
					Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.symbol.get_full_name (), base_method.symbol.get_full_name ()));
					return;
				}
				
				m.base_method = base_method;
				return;
			}
		}

197
198
199
200
201
202
		if (cl.base_class != null) {
			find_base_class_method (m, cl.base_class);
		}
	}

	private void find_base_interface_method (Method! m, Class! cl) {
203
		// FIXME report error if multiple possible base methods are found
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
		foreach (TypeReference type in cl.get_base_types ()) {
			if (type.data_type is Interface) {
				var sym = type.data_type.symbol.lookup (m.name);
				if (sym != null && sym.node is Method) {
					var base_method = (Method) sym.node;
					if (base_method.is_abstract) {
						if (!m.equals (base_method)) {
							m.error = true;
							Report.error (m.source_reference, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m.symbol.get_full_name (), base_method.symbol.get_full_name ()));
							return;
						}
						
						m.base_interface_method = base_method;
						return;
					}
219
220
221
222
223
				}
			}
		}
	}

224
225
226
	public override void visit_end_method (Method! m) {
		current_symbol = current_symbol.parent_symbol;
		current_return_type = null;
227

228
229
		if (current_symbol.parent_symbol != null &&
		    current_symbol.parent_symbol.node is Method) {
230
231
232
233
234
			/* lambda expressions produce nested methods */
			var up_method = (Method) current_symbol.parent_symbol.node;
			current_return_type = up_method.return_type;
		}
		
235
236
237
238
239
240
		if (current_symbol.node is Class) {
			if (!(m is CreationMethod)) {
				find_base_interface_method (m, (Class) current_symbol.node);
				if (m.is_virtual || m.overrides) {
					find_base_class_method (m, (Class) current_symbol.node);
					if (m.base_method == null) {
241
						Report.error (m.source_reference, "%s: no suitable method found to override".printf (m.symbol.get_full_name ()));
242
					}
243
				}
244
245
246
			}
		} else if (current_symbol.node is Struct) {
			if (m.is_abstract || m.is_virtual || m.overrides) {
247
248
				Report.error (m.source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m.symbol.get_full_name ()));
				return;
249
250
			}
		}
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
	}
	
	public override void visit_begin_creation_method (CreationMethod! m) {
		m.return_type = new TypeReference ();
		m.return_type.data_type = (DataType) current_symbol.node;
		m.return_type.transfers_ownership = true;
		
		if (current_symbol.node is Class) {
			// check for floating reference
			var cl = (Class) current_symbol.node;
			while (cl != null) {
				if (cl == initially_unowned_type) {
					m.return_type.floating_reference = true;
					break;
				}
			
				cl = cl.base_class;
			}
		}
		
		if (m.body != null) {
			m.body.construction = true;
		}
		
		current_symbol = m.symbol;
		current_return_type = m.return_type;
	}
	
	public override void visit_end_creation_method (CreationMethod! m) {
		visit_end_method (m);
281
		
282
		if (m.body != null) {
283
284
285
286
			int n_params = 0;
			foreach (Statement stmt in m.body.get_statements ()) {
				int params = stmt.get_number_of_set_construction_parameters ();
				if (params == -1) {
287
288
289
					m.error = true;
					Report.error (stmt.source_reference, "type creation methods only allow property assignment statements");
					return;
290
291
292
293
294
295
				}
				n_params += params;
				stmt.construction = true;
			}
			m.n_construction_params = n_params;
		}
296
	}
297

298
299
	public override void visit_formal_parameter (FormalParameter! p) {
		if (!p.ellipsis) {
300
			if (p.type_reference.data_type != null) {
301
				/* is null if it references a type parameter */
302
303
				current_source_file.add_symbol_dependency (p.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
				current_source_file.add_symbol_dependency (p.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
304
305
			}
		}
306
307
308
309
310
311
312
313
314
315
316
317
318
		
		/* special treatment for construct formal parameters used in creation methods */
		if (p.construct_parameter) {
			if (!(p.symbol.parent_symbol.node is CreationMethod)) {
				p.error = true;
				Report.error (p.source_reference, "construct parameters are only allowed in type creation methods");
				return;
			}
			
			var method_body = ((CreationMethod)p.symbol.parent_symbol.node).body;
			var left = new MemberAccess.simple (p.name);
			var right = new MemberAccess.simple (p.name);
			
319
320
321
			/* try to lookup the requested property */
			var prop_sym = symbol_lookup_inherited (current_class.symbol, p.name);
			if (!(prop_sym.node is Property)) {
322
323
324
325
326
327
328
329
330
331
				p.error = true;
				Report.error (p.source_reference, "class `%s' does not contain a property named `%s'".printf (current_class.symbol.get_full_name (), p.name));
				return;
			}
			left.symbol_reference = prop_sym;
			
			right.symbol_reference = p.symbol;
			
			method_body.add_statement (new ExpressionStatement (new Assignment (left, right)));
		}
332
	}
333

334
	public override void visit_end_property (Property! prop) {
335
		if (prop.type_reference.data_type != null) {
336
			/* is null if it references a type parameter */
337
338
			current_source_file.add_symbol_dependency (prop.type_reference.data_type.symbol, SourceFileDependencyType.HEADER_SHALLOW);
			current_source_file.add_symbol_dependency (prop.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
339
		}
340
	}
341

342
343
344
345
346
	public override void visit_begin_property_accessor (PropertyAccessor! acc) {
		var prop = (Property) acc.symbol.parent_symbol.node;
		
		if (acc.readable) {
			current_return_type = prop.type_reference;
347
348
349
		} else {
			// void
			current_return_type = new TypeReference ();
350
		}
351
	}
352

353
354
355
	public override void visit_end_property_accessor (PropertyAccessor! acc) {
		current_return_type = null;
	}
356

357
358
359
	public override void visit_begin_constructor (Constructor! c) {
		current_symbol = c.symbol;
	}
360

361
362
363
	public override void visit_end_constructor (Constructor! c) {
		current_symbol = current_symbol.parent_symbol;
	}
364

365
366
367
	public override void visit_begin_destructor (Destructor! d) {
		current_symbol = d.symbol;
	}
368

369
370
371
	public override void visit_end_destructor (Destructor! d) {
		current_symbol = current_symbol.parent_symbol;
	}
372

373
374
375
376
377
378
379
380
381
382
	public override void visit_named_argument (NamedArgument! n) {
	}

	public override void visit_begin_block (Block! b) {
		current_symbol = b.symbol;
	}

	public override void visit_end_block (Block! b) {
		foreach (VariableDeclarator decl in b.get_local_variables ()) {
			decl.symbol.active = false;
383
		}
384
385
386
	
		current_symbol = current_symbol.parent_symbol;
	}
387

388
389
390
391
392
393
394
395
	public override void visit_variable_declarator (VariableDeclarator! decl) {
		if (decl.type_reference == null) {
			/* var type */
			
			if (decl.initializer == null) {
				decl.error = true;
				Report.error (decl.source_reference, "var declaration not allowed without initializer");
				return;
396
			}
397
398
399
400
401
402
403
			if (decl.initializer.static_type == null) {
				decl.error = true;
				Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
				return;
			}
			
			decl.type_reference = decl.initializer.static_type.copy ();
404
405
			decl.type_reference.takes_ownership = decl.type_reference.transfers_ownership;
			decl.type_reference.transfers_ownership = false;
406
		}
407
408
409
410
		
		if (decl.initializer != null) {
			if (decl.initializer.static_type == null) {
				if (!(decl.initializer is MemberAccess)) {
411
					decl.error = true;
412
					Report.error (decl.source_reference, "expression type not allowed as initializer");
413
414
415
					return;
				}
				
416
				if (decl.initializer.symbol_reference.node is Method &&
417
				    decl.type_reference.data_type is Callback) {
418
					var m = (Method) decl.initializer.symbol_reference.node;
419
					var cb = (Callback) decl.type_reference.data_type;
420
					
421
422
					/* check whether method matches callback type */
					if (!cb.matches_method (m)) {
423
						decl.error = true;
424
						Report.error (decl.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.symbol.get_full_name (), cb.symbol.get_full_name ()));
425
426
						return;
					}
427
428
429
430
431
432
					
					decl.initializer.static_type = decl.type_reference;
				} else {
					decl.error = true;
					Report.error (decl.source_reference, "expression type not allowed as initializer");
					return;
433
				}
434
435
436
			}
		
			if (memory_management) {
437
				if (decl.initializer.static_type.transfers_ownership) {
438
					/* rhs transfers ownership of the expression */
439
					if (!decl.type_reference.takes_ownership) {
440
441
442
						/* lhs doesn't own the value
						 * promote lhs type */
						
443
						decl.type_reference.takes_ownership = true;
444
445
446
					}
				}
			}
447
		}
448
		
449
450
		if (decl.type_reference.data_type != null) {
			current_source_file.add_symbol_dependency (decl.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
451
452
		}

453
		decl.symbol = new Symbol (decl);
454
		current_symbol.add (decl.name, decl.symbol);
455
		
456
457
458
459
460
		var block = (Block) current_symbol.node;
		block.add_local_variable (decl);
		
		decl.symbol.active = true;
	}
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
	
	/**
	 * 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 ();
			
			if (rank > 1) {
				child_type.data_type = edt.element_type.get_array (rank - 1);
			} else {
				child_type.data_type = edt.element_type;
			}
				
			foreach (Expression e in inits) {
				e.expected_type = child_type.copy ();
			}
		}
	}
	
	/**
	 * 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;
			
			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));
					}
				}
			}
			
			if (!error) {
				/* everything seems to be correct */
				list.static_type = list.expected_type;
			}
		}
	}
540

541
542
	public override void visit_expression_statement (ExpressionStatement! stmt) {
		if (stmt.expression.static_type != null &&
543
		    stmt.expression.static_type.transfers_ownership) {
544
545
			Report.warning (stmt.source_reference, "Short-living reference");
			return;
546
		}
547
	}
548

549
	public override void visit_if_statement (IfStatement! stmt) {
550
551
552
553
554
555
		if (stmt.condition.error) {
			/* if there was an error in the condition, skip this check */
			stmt.error = true;
			return;
		}
		
556
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
557
558
559
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
560
		}
561
	}
562

563
	public override void visit_while_statement (WhileStatement! stmt) {
564
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
565
566
567
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
568
		}
569
	}
570

571
	public override void visit_for_statement (ForStatement! stmt) {
572
		if (stmt.condition.static_type.data_type != bool_type.data_type) {
573
574
575
			stmt.error = true;
			Report.error (stmt.condition.source_reference, "Condition must be boolean");
			return;
576
		}
577
	}
578

579
	public override void visit_begin_foreach_statement (ForeachStatement! stmt) {
580
581
		if (stmt.type_reference.data_type != null) {
			current_source_file.add_symbol_dependency (stmt.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
582
		}
583
		
584
		stmt.variable_declarator = new VariableDeclarator (stmt.variable_name);
585
586
		stmt.variable_declarator.type_reference = stmt.type_reference;
	
587
		stmt.variable_declarator.symbol = new Symbol (stmt.variable_declarator);
588
		stmt.body.symbol.add (stmt.variable_name, stmt.variable_declarator.symbol);
589
	}
590

591
	public override void visit_end_return_statement (ReturnStatement! stmt) {
592
593
594
595
596
		if (current_return_type == null) {
			Report.error (stmt.source_reference, "Return not allowed in this context");
			return;
		}
		
597
		if (stmt.return_expression == null && current_return_type.data_type != null) {
598
			Report.error (stmt.source_reference, "Return without value in non-void function");
599
			return;
600
		}
601
		
602
603
604
605
		if (stmt.return_expression != null &&
		    current_return_type.data_type == null &&
		    current_return_type.type_parameter == null) {
			Report.error (stmt.source_reference, "Return with value in void function");
606
607
608
609
610
611
612
613
614
			return;
		}
		
		if (stmt.return_expression != null &&
		     !is_type_compatible (stmt.return_expression.static_type, current_return_type)) {
			Report.error (stmt.source_reference, "Return: Cannot convert from `%s' to `%s'".printf (stmt.return_expression.static_type.to_string (), current_return_type.to_string ()));
			return;
		}
		
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
		if (stmt.return_expression != null &&
		    stmt.return_expression.static_type.transfers_ownership &&
		    !current_return_type.transfers_ownership) {
			stmt.error = true;
			Report.error (stmt.source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
			return;
		}
		
		if (stmt.return_expression != null &&
		    stmt.return_expression.symbol_reference != null &&
		    stmt.return_expression.symbol_reference.node is VariableDeclarator &&
		    stmt.return_expression.static_type.takes_ownership &&
		    !current_return_type.transfers_ownership) {
			Report.warning (stmt.source_reference, "Local variable with strong reference used as return value and method return type hasn't been declared to transfer ownership");
		}
630
	}
631
	
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
	/**
	 * Visit operation called for lock statements.
	 *
	 * @param stmt a lock statement
	 */
	public override void visit_lock_statement (LockStatement! stmt) {
		/* resource must be a member access and denote a Lockable */
		if (!(stmt.resource is MemberAccess && stmt.resource.symbol_reference.node is Lockable)) {
		    	stmt.error = true;
			stmt.resource.error = true;
			Report.error (stmt.resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
			return;
		}
		
		/* parent symbol must be the current class */
		if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
		    	stmt.error = true;
			stmt.resource.error = true;
			Report.error (stmt.resource.source_reference, "Only members of the current class are lockable");
		}
		
		((Lockable)stmt.resource.symbol_reference.node).set_lock_used (true);
	}
	
656
657
658
659
	public override void visit_begin_array_creation_expression (ArrayCreationExpression! expr) {
		if (expr.initializer_list != null) {
			expr.initializer_list.expected_type = expr.element_type.copy ();
			expr.initializer_list.expected_type.data_type = expr.initializer_list.expected_type.data_type.get_array (expr.rank);
660
			// FIXME: add element type to type_argument
661
662
663
664
665
666
667
668
669
670
		}
	}
	
	/**
	 * Visit operations called for array creation expresions.
	 *
	 * @param expr an array creation expression
	 */
	public override void visit_end_array_creation_expression (ArrayCreationExpression! expr) {
		int i;
671
		List<weak Expression> size = expr.get_sizes ();
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
		
		/* check for errors in the size list */
		if (size != null) {
			foreach (Expression e in size) {
				if (e.static_type == null) {
					/* return on previous error */
					return;
				} else if (e.static_type.data_type != int_type.data_type) {
					expr.error = true;
					Report.error (e.source_reference, "Expected expression of type ´int'");
				}
			}
			
			if (expr.error) {
				return;
			}
		}
		
		/* check for wrong elements inside the initializer */
		if (expr.initializer_list != null && expr.initializer_list.static_type == null) {
			return;
		}
		
		/* try to construct the type of the array */
696
		if (expr.element_type == null) {
697
698
699
700
			expr.error = true;
			Report.error (expr.source_reference, "Cannot determine the element type of the created array");
			return;
		}
701
702

		expr.static_type = expr.element_type.copy ();
703
704
705
706
707
		if (expr.element_type.data_type != null) {
			expr.static_type.data_type = expr.element_type.data_type.get_array (expr.rank);
		} else {
			expr.static_type.data_type = expr.element_type.type_parameter.get_array (expr.rank);
		}
708
709
710
711
		expr.static_type.transfers_ownership = true;
		expr.static_type.takes_ownership = true;
		
		expr.static_type.add_type_argument (expr.element_type);
712
	}	
713

714
715
716
717
718
719
	public override void visit_boolean_literal (BooleanLiteral! expr) {
		expr.static_type = bool_type;
	}

	public override void visit_character_literal (CharacterLiteral! expr) {
		expr.static_type = new TypeReference ();
720
		expr.static_type.data_type = (DataType) root_symbol.lookup ("char").node;
721
722
723
724
	}

	public override void visit_integer_literal (IntegerLiteral! expr) {
		expr.static_type = new TypeReference ();
725
		expr.static_type.data_type = (DataType) root_symbol.lookup (expr.get_type_name ()).node;
726
727
	}

728
	public override void visit_real_literal (RealLiteral! expr) {
729
		expr.static_type = new TypeReference ();
730
		expr.static_type.data_type = (DataType) root_symbol.lookup (expr.get_type_name ()).node;
731
732
733
	}

	public override void visit_string_literal (StringLiteral! expr) {
734
735
		expr.static_type = string_type.copy ();
		expr.static_type.non_null = true;
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
	}

	public override void visit_null_literal (NullLiteral! expr) {
		/* empty TypeReference represents null */
		
		expr.static_type = new TypeReference ();
	}

	public override void visit_literal_expression (LiteralExpression! expr) {
		expr.static_type = expr.literal.static_type;
	}
	
	ref TypeReference get_static_type_for_node (CodeNode! node) {
		if (node is Field) {
			var f = (Field) node;
			return f.type_reference;
		} else if (node is Constant) {
			var c = (Constant) node;
			return c.type_reference;
		} else if (node is Property) {
			var prop = (Property) node;
			var type = prop.type_reference.copy ();
758
			type.takes_ownership = false;
759
760
761
762
763
764
765
766
767
768
769
			return type;
		} else if (node is FormalParameter) {
			var p = (FormalParameter) node;
			return p.type_reference;
		} else if (node is TypeReference) {
			return (TypeReference) node;
		} else if (node is VariableDeclarator) {
			var decl = (VariableDeclarator) node;
			return decl.type_reference;
		} else if (node is EnumValue) {
			var type = new TypeReference ();
770
			type.data_type = (DataType) node.symbol.parent_symbol.node;
771
772
773
774
775
776
777
			return type;
		}
		return null;
	}
	
	Symbol symbol_lookup_inherited (Symbol! sym, string! name) {
		var result = sym.lookup (name);
778
779
780
781
782
		if (result != null) {
			return result;
		}

		if (sym.node is Class) {
783
			var cl = (Class) sym.node;
784
785
786
787
788
789
			foreach (TypeReference base_type in cl.get_base_types ()) {
				result = symbol_lookup_inherited (base_type.data_type.symbol, name);
				if (result != null) {
					return result;
				}
			}
790
791
792
793
794
795
796
797
		} else if (sym.node is Struct) {
			var st = (Struct) sym.node;
			foreach (TypeReference base_type in st.get_base_types ()) {
				result = symbol_lookup_inherited (base_type.data_type.symbol, name);
				if (result != null) {
					return result;
				}
			}
798
799
		} else if (sym.node is Interface) {
			var iface = (Interface) sym.node;
800
801
			foreach (TypeReference prerequisite in iface.get_prerequisites ()) {
				result = symbol_lookup_inherited (prerequisite.data_type.symbol, name);
802
803
804
				if (result != null) {
					return result;
				}
805
806
			}
		}
807
808

		return null;
809
	}
810

811
812
813
	public override void visit_parenthesized_expression (ParenthesizedExpression! expr) {
		expr.static_type = expr.inner.static_type;
	}
814

815
816
817
818
819
820
821
822
823
824
	private DataType find_parent_type (Symbol sym) {
		while (sym != null) {
			if (sym.node is DataType) {
				return (DataType) sym.node;
			}
			sym = sym.parent_symbol;
		}
		return null;
	}

825
826
	public override void visit_member_access (MemberAccess! expr) {
		Symbol base_symbol = null;
827

828
829
830
831
832
833
834
835
		if (expr.inner == null) {
			base_symbol = current_symbol;
		
			var sym = current_symbol;
			while (sym != null && expr.symbol_reference == null) {
				expr.symbol_reference = symbol_lookup_inherited (sym, expr.member_name);
				sym = sym.parent_symbol;
			}
836

837
838
839
840
841
			if (expr.symbol_reference == null) {
				foreach (NamespaceReference ns in current_using_directives) {
					var local_sym = ns.namespace_symbol.lookup (expr.member_name);
					if (local_sym != null) {
						if (expr.symbol_reference != null) {
842
							expr.error = true;
843
844
							Report.error (expr.source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (expr.member_name, expr.symbol_reference.get_full_name (), local_sym.get_full_name ()));
							return;
845
						}
846
						expr.symbol_reference = local_sym;
847
848
					}
				}
849
			}
850
851
852
		} else {
			if (expr.inner.error) {
				/* if there was an error in the inner expression, skip this check */
853
				expr.error = true;
854
				return;
855
			}
856
		
857
858
			if (expr.inner is MemberAccess || expr.inner is BaseAccess) {
				base_symbol = expr.inner.symbol_reference;
859
860
861
862
				if (base_symbol.node is Namespace ||
				    base_symbol.node is DataType) {
					expr.symbol_reference = base_symbol.lookup (expr.member_name);
				}
863
864
			}
			
865
			if (expr.symbol_reference == null && expr.inner.static_type != null) {
866
				base_symbol = expr.inner.static_type.data_type.symbol;
867
				expr.symbol_reference = symbol_lookup_inherited (base_symbol, expr.member_name);
868
			}
869
		}
870
			
871
872
873
874
875
876
		if (expr.symbol_reference == null) {
			expr.error = true;
			Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, base_symbol.get_full_name ()));
			return;
		}
		
877
878
879
880
881
882
883
884
		var member = expr.symbol_reference.node;
		MemberAccessibility access = MemberAccessibility.PUBLIC;
		if (member is Field) {
			access = ((Field) member).access;
		} else if (member is Method) {
			access = ((Method) member).access;
		}
		
885
		if (access == MemberAccessibility.PRIVATE) {
886
887
888
889
890
891
892
893
894
895
			var target_type = (DataType) member.symbol.parent_symbol.node;
			var this_type = find_parent_type (current_symbol);
			
			if (target_type != this_type) {
				expr.error = true;
				Report.error (expr.source_reference, "Access to private member `%s' denied".printf (member.symbol.get_full_name ()));
				return;
			}
		}
		
896
897
898
899
900
901
902
		current_source_file.add_symbol_dependency (expr.symbol_reference, SourceFileDependencyType.SOURCE);

		expr.static_type = get_static_type_for_node (expr.symbol_reference.node);
	}
	
	private bool is_type_compatible (TypeReference! expression_type, TypeReference! expected_type) {
		/* only null is compatible to null */
903
904
		if (expected_type.data_type == null && expected_type.type_parameter == null) {
			return (expression_type.data_type == null && expected_type.type_parameter == null);
905
906
		}

907
908
909
910
911
912
913
914
915
916
917
918
919
		if (expression_type.data_type == null) {
			/* null can be cast to any reference or array type */
			if (expected_type.type_parameter != null ||
			    expected_type.data_type.is_reference_type () ||
			    expected_type.reference_to_value_type ||
			    expected_type.data_type is Array ||
			    expected_type.data_type is Callback ||
			    expected_type.data_type == pointer_type) {
				return true;
			}
			
			/* null is not compatible with any other type (i.e. value types) */
			return false;
920
921
922
923
924
925
926
		}
	
		/* temporarily ignore type parameters */
		if (expected_type.type_parameter != null) {
			return true;
		}
		
927
		if (expression_type.data_type is Array != expected_type.data_type is Array) {
928
929
930
			return false;
		}
		
931
932
933
934
		if (expression_type.data_type is Enum && expected_type.data_type == int_type.data_type) {
			return true;
		}
		
935
		if (expression_type.data_type == expected_type.data_type) {
936
937
938
			return true;
		}
		
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
		if (expression_type.data_type is Struct && expected_type.data_type is Struct) {
			var expr_struct = (Struct) expression_type.data_type;
			var expect_struct = (Struct) expected_type.data_type;

			/* integer types may be implicitly cast to floating point types */
			if (expr_struct.is_integer_type () && expect_struct.is_floating_type ()) {
				return true;
			}

			if ((expr_struct.is_integer_type () && expect_struct.is_integer_type ()) ||
			    (expr_struct.is_floating_type () && expect_struct.is_floating_type ())) {
				if (expr_struct.get_rank () <= expect_struct.get_rank ()) {
					return true;
				}
			}
954
955
		}
		
956
		return expression_type.data_type.is_subtype_of (expected_type.data_type);
957
	}
958

959
960
961
962
963
964
965
966
967
	public override void visit_begin_invocation_expression (InvocationExpression! expr) {
		if (expr.call.error) {
			/* if method resolving didn't succeed, skip this check */
			expr.error = true;
			return;
		}
		
		var msym = expr.call.symbol_reference;
		
968
969
970
971
972
973
		if (msym == null) {
			/* if no symbol found, skip this check */
			expr.error = true;
			return;
		}
		
974
		List<weak FormalParameter> params;
975
		
976
977
978
979
		if (msym.node is Invokable) {
			var m = (Invokable) msym.node;
			if (m.is_invokable ()) {
				params = m.get_parameters ();
980
			} else {
981
				expr.error = true;
982
				Report.error (expr.source_reference, "invocation not supported in this context");
983
984
				return;
			}
985
986
987
988
989
990
		} else {
			expr.error = true;
			Report.error (expr.source_reference, "invocation not supported in this context");
			return;
		}
	
991
992
		var args = expr.get_argument_list ();
		List arg_it = args;
993
994
995
996
997
998
999
		foreach (FormalParameter param in params) {
			if (param.ellipsis) {
				break;
			}
			
			if (arg_it != null) {
				var arg = (Expression) arg_it.data;
1000

1001
1002
1003
1004
				/* store expected type for callback parameters */
				arg.expected_type = param.type_reference;
				
				arg_it = arg_it.next;
1005
1006
			}
		}
1007
1008
	}
	
1009
	private bool check_arguments (Expression! expr, Symbol! msym, List<FormalParameter> params, List<Expression> args) {
1010
		List prev_arg_it = null;
1011
		List arg_it = args;
1012
		
1013
1014
		bool diag = (msym.node.get_attribute ("Diagnostics") != null);
		
1015
1016
1017
1018
1019
1020
		bool ellipsis = false;
		int i = 0;
		foreach (FormalParameter param in params) {
			if (param.ellipsis) {
				ellipsis = true;
				break;
1021
			}
1022
1023

			/* header file necessary if we need to cast argument */
1024
1025
			if (param.type_reference.data_type != null) {
				current_source_file.add_symbol_dependency (param.type_reference.data_type.symbol, SourceFileDependencyType.SOURCE);
1026
			}
1027

1028
1029
			if (arg_it == null) {
				if (param.default_expression == null) {
1030
					expr.error = true;
1031
					Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ()));
1032
					return false;
1033
				}
1034
1035
1036
1037
1038
			} else {
				var arg = (Expression) arg_it.data;
				if (arg.static_type != null && !is_type_compatible (arg.static_type, param.type_reference)) {
					/* if there was an error in the argument,
					 * i.e. arg.static_type == null, skip type check */
1039
					expr.error = true;
1040
					Report.error (expr.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.static_type.to_string (), param.type_reference.to_string ()));
1041
					return false;
1042
				}
1043
				
1044
				prev_arg_it = arg_it;
1045
				arg_it = arg_it.next;
1046

1047
				i++;
1048
			}
1049
		}
1050
		
1051
		if (!ellipsis && arg_it != null) {
1052
			expr.error = true;
1053
			Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ()));
1054
1055
1056
			return false;
		}
		
1057
1058
1059
1060
1061
1062
1063
1064
		if (diag && prev_arg_it != null) {
			var format_arg = (Expression) prev_arg_it.data;
			if (format_arg is LiteralExpression) {
				var format_lit = (StringLiteral) ((LiteralExpression) format_arg).literal;
				format_lit.value = "\"%s:%d: %s".printf (expr.source_reference.file.filename, expr.source_reference.first_line, format_lit.value.offset (1));
			}
		}
		
1065
1066
1067
1068
1069
		return true;
	}

	public override void visit_end_invocation_expression (InvocationExpression! expr) {
		if (expr.error) {
1070
1071
			return;
		}
1072
1073
1074
1075
		
		var msym = expr.call.symbol_reference;
		
		TypeReference ret_type;
1076
		List<weak FormalParameter> params;
1077
		
1078
1079
1080
		if (msym.node is Invokable) {
			var m = (Invokable) msym.node;
			ret_type = m.get_return_type ();
1081
1082
1083
1084
1085
1086
			params = m.get_parameters ();
		}
	
		expr.static_type = ret_type;
		
		check_arguments (expr, msym, params, expr.get_argument_list ());
1087
1088
	}	
	
1089
1090
	public override void visit_element_access (ElementAccess! expr) {		
		if (expr.container.static_type == null) {
1091
			/* don't proceed if a child expression failed */
1092
			expr.error = true;
1093
1094
1095
1096
			return;
		}
		
		/* assign a static_type when possible */
1097
		if (expr.container.static_type.data_type is Array) {
1098
1099
1100
1101
1102
1103
1104
1105
1106
			var args = expr.container.static_type.get_type_arguments ();
			
			if (args.length () != 1) {
				expr.error = true;
				Report.error (expr.source_reference, "internal error: array reference without type arguments");
				return;
			}
			
			expr.static_type = (TypeReference) args.data;
1107
1108
1109
1110
1111
		} else {
			expr.error = true;
			Report.error (expr.source_reference, "The expression `%s' does not denote an Array".printf (expr.container.static_type.to_string ()));
		}
		
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
		/* check if the index is of type integer */		
		foreach (Expression e in expr.get_indices ()) {
			/* don't proceed if a child expression failed */
			if (e.static_type == null) {
				return;
			}
			
			/* check if the index is of type integer */
			if (e.static_type.data_type != int_type.data_type) {
				expr.error = true;
				Report.error (e.source_reference, "Expression of type `int' expected");
			}
1124
		}
1125
	}
1126
1127
1128

	public override void visit_base_access (BaseAccess! expr) {
		if (current_class == null) {
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
			if (current_struct == null) {
				expr.error = true;
				Report.error (expr.source_reference, "Base access invalid outside of class and struct");
				return;
			} else if (current_struct.get_base_types ().length () != 1) {
				expr.error = true;
				Report.error (expr.source_reference, "Base access invalid without base type %d".printf (current_struct.get_base_types ().length ()));
				return;
			}
			expr.static_type = current_struct.get_base_types ().first ().data;
		} else {
			expr.static_type = new TypeReference ();
			expr.static_type.data_type = current_class.base_class;
1142
1143
		}

1144
		expr