1/* valasemanticanalyzer.vala
2 *
3 * Copyright (C) 2006-2010  Jürg Billeter
4 * Copyright (C) 2006-2008  Raffaele Sandrini
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
14 * Lesser General Public License for more details.
15
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 *
20 * Author:
21 * 	Jürg Billeter <j@bitron.ch>
22 *	Raffaele Sandrini <raffaele@sandrini.ch>
23 */
24
25using GLib;
26
27/**
28 * Code visitor analyzing and checking code.
29 */
30public class Vala.SemanticAnalyzer : CodeVisitor {
31	CodeContext context;
32
33	public Symbol? current_symbol { get; set; }
34	public SourceFile current_source_file { get; set; }
35
36	public TypeSymbol? current_type_symbol {
37		get {
38			unowned Symbol? sym = current_symbol;
39			while (sym != null) {
40				if (sym is TypeSymbol) {
41					return (TypeSymbol) sym;
42				}
43				sym = sym.parent_symbol;
44			}
45			return null;
46		}
47	}
48
49	public Class? current_class {
50		get { return current_type_symbol as Class; }
51	}
52
53
54	public Struct? current_struct {
55		get { return current_type_symbol as Struct; }
56	}
57
58	public Method? current_method {
59		get {
60			unowned Symbol? sym = current_symbol;
61			while (sym is Block) {
62				sym = sym.parent_symbol;
63			}
64			return sym as Method;
65		}
66	}
67
68	public Method? current_async_method {
69		get {
70			unowned Symbol? sym = current_symbol;
71			while (sym is Block || sym is Method) {
72				unowned Method? m = sym as Method;
73				if (m != null && m.coroutine) {
74					break;
75				}
76
77				sym = sym.parent_symbol;
78			}
79			return sym as Method;
80		}
81	}
82
83	public PropertyAccessor? current_property_accessor {
84		get {
85			unowned Symbol? sym = current_symbol;
86			while (sym is Block) {
87				sym = sym.parent_symbol;
88			}
89			return sym as PropertyAccessor;
90		}
91	}
92
93	public Symbol? current_method_or_property_accessor {
94		get {
95			unowned Symbol? sym = current_symbol;
96			while (sym is Block) {
97				sym = sym.parent_symbol;
98			}
99			if (sym is Method) {
100				return sym;
101			} else if (sym is PropertyAccessor) {
102				return sym;
103			} else {
104				return null;
105			}
106		}
107	}
108
109	public DataType? current_return_type {
110		get {
111			unowned Method? m = current_method;
112			if (m != null) {
113				return m.return_type;
114			}
115
116			unowned PropertyAccessor? acc = current_property_accessor;
117			if (acc != null) {
118				if (acc.readable) {
119					return acc.value_type;
120				} else {
121					return void_type;
122				}
123			}
124
125			if (is_in_constructor () || is_in_destructor ()) {
126				return void_type;
127			}
128
129			return null;
130		}
131	}
132
133	public Block insert_block;
134
135	public DataType void_type = new VoidType ();
136	public DataType bool_type;
137	public DataType char_type;
138	public DataType uchar_type;
139	public DataType short_type;
140	public DataType ushort_type;
141	public DataType int_type;
142	public DataType uint_type;
143	public DataType long_type;
144	public DataType ulong_type;
145	public DataType int8_type;
146	public DataType uint8_type;
147	public DataType int16_type;
148	public DataType uint16_type;
149	public DataType int32_type;
150	public DataType uint32_type;
151	public DataType size_t_type;
152	public DataType ssize_t_type;
153	public DataType unichar_type;
154	public DataType double_type;
155	public DataType string_type;
156	public DataType regex_type;
157	public DataType type_type;
158	public DataType va_list_type;
159	public Class object_type;
160	public StructValueType gvalue_type;
161	public ObjectType gvariant_type;
162	public DataType glist_type;
163	public DataType gslist_type;
164	public DataType garray_type;
165	public DataType gvaluearray_type;
166	public Class gerror_type;
167	public DataType list_type;
168	public DataType tuple_type;
169	public Class gsource_type;
170	public DataType delegate_target_type;
171	public DelegateType delegate_target_destroy_type;
172	public DelegateType generics_dup_func_type;
173
174	Delegate destroy_notify;
175
176	// keep replaced alive to make sure they remain valid
177	// for the whole execution of CodeNode.accept
178	public List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
179
180	public SemanticAnalyzer () {
181	}
182
183	/**
184	 * Analyze and check code in the specified context.
185	 *
186	 * @param context a code context
187	 */
188	public void analyze (CodeContext context) {
189		this.context = context;
190
191		var root_symbol = context.root;
192
193		bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
194		char_type = new IntegerType ((Struct) root_symbol.scope.lookup ("char"));
195		uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
196		short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
197		ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
198		int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
199		uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
200		long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
201		ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
202		int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
203		uint8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint8"));
204		int16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int16"));
205		uint16_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint16"));
206		int32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int32"));
207		uint32_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint32"));
208		size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
209		ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
210		double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
211		string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
212		va_list_type = new StructValueType ((Struct) root_symbol.scope.lookup ("va_list"));
213
214		var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
215		if (unichar_struct != null) {
216			unichar_type = new IntegerType (unichar_struct);
217		}
218
219		if (context.profile == Profile.GOBJECT) {
220			var glib_ns = root_symbol.scope.lookup ("GLib");
221
222			object_type = (Class) glib_ns.scope.lookup ("Object");
223			type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type"));
224			gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value"));
225			gvariant_type = new ObjectType ((Class) glib_ns.scope.lookup ("Variant"));
226
227			glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List"));
228			gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList"));
229			garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array"));
230			gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray"));
231
232			gerror_type = (Class) glib_ns.scope.lookup ("Error");
233			regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
234
235			gsource_type = (Class) glib_ns.scope.lookup ("Source");
236
237			delegate_target_type = new StructValueType ((Struct) glib_ns.scope.lookup ("pointer"));
238			destroy_notify = (Delegate) glib_ns.scope.lookup ("DestroyNotify");
239			delegate_target_destroy_type = new DelegateType (destroy_notify);
240
241			generics_dup_func_type = new DelegateType ((Delegate) glib_ns.scope.lookup ("BoxedCopyFunc"));
242		} else {
243			delegate_target_type = new PointerType (new VoidType ());
244			destroy_notify = new Delegate ("ValaDestroyNotify", new VoidType ());
245			destroy_notify.add_parameter (new Parameter ("data", new PointerType (new VoidType ())));
246			destroy_notify.has_target = false;
247			destroy_notify.owner = context.root.scope;
248			delegate_target_destroy_type = new DelegateType (destroy_notify);
249		}
250
251		current_symbol = root_symbol;
252		context.root.check (context);
253		context.accept (this);
254
255		this.context = null;
256	}
257
258	public override void visit_source_file (SourceFile file) {
259		current_source_file = file;
260
261		file.check (context);
262	}
263
264	// check whether type is at least as accessible as the specified symbol
265	public bool is_type_accessible (Symbol sym, DataType type) {
266		return type.is_accessible (sym);
267	}
268
269	public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
270		if (sym is Field) {
271			unowned Field f = (Field) sym;
272			var type = f.variable_type.copy ();
273			if (!lvalue) {
274				type.value_owned = false;
275			}
276			return type;
277		} else if (sym is EnumValue) {
278			return new EnumValueType ((Enum) sym.parent_symbol);
279		} else if (sym is Constant) {
280			unowned Constant c = (Constant) sym;
281			return c.type_reference.copy ();
282		} else if (sym is Property) {
283			unowned Property prop = (Property) sym;
284			if (lvalue) {
285				if (prop.set_accessor != null && prop.set_accessor.value_type != null) {
286					return prop.set_accessor.value_type.copy ();
287				}
288			} else {
289				if (prop.get_accessor != null && prop.get_accessor.value_type != null) {
290					return prop.get_accessor.value_type.copy ();
291				}
292			}
293		} else if (sym is Parameter) {
294			unowned Parameter p = (Parameter) sym;
295			var type = p.variable_type.copy ();
296			if (!lvalue) {
297				type.value_owned = false;
298			}
299			return type;
300		} else if (sym is LocalVariable) {
301			unowned LocalVariable local = (LocalVariable) sym;
302			var type = local.variable_type.copy ();
303			if (!lvalue) {
304				type.value_owned = false;
305			}
306			return type;
307		} else if (sym is Method) {
308			return new MethodType ((Method) sym);
309		} else if (sym is Signal) {
310			return new SignalType ((Signal) sym);
311		}
312		return null;
313	}
314
315	public static Symbol? symbol_lookup_inherited (Symbol sym, string name) {
316		var result = sym.scope.lookup (name);
317		if (result != null) {
318			return result;
319		}
320
321		if (sym is Class) {
322			unowned Class cl = (Class) sym;
323			// first check interfaces without prerequisites
324			// (prerequisites can be assumed to be met already)
325			foreach (DataType base_type in cl.get_base_types ()) {
326				if (base_type.type_symbol is Interface) {
327					result = base_type.type_symbol.scope.lookup (name);
328					if (result != null) {
329						return result;
330					}
331				}
332			}
333			// then check base class recursively
334			if (cl.base_class != null) {
335				return symbol_lookup_inherited (cl.base_class, name);
336			}
337		} else if (sym is Struct) {
338			unowned Struct st = (Struct) sym;
339			if (st.base_type != null) {
340				result = symbol_lookup_inherited (st.base_type.type_symbol, name);
341				if (result != null) {
342					return result;
343				}
344			}
345		} else if (sym is Interface) {
346			unowned Interface iface = (Interface) sym;
347			// first check interface prerequisites recursively
348			foreach (DataType prerequisite in iface.get_prerequisites ()) {
349				if (prerequisite.type_symbol is Interface) {
350					result = symbol_lookup_inherited (prerequisite.type_symbol, name);
351					if (result != null) {
352						return result;
353					}
354				}
355			}
356			// then check class prerequisite recursively
357			foreach (DataType prerequisite in iface.get_prerequisites ()) {
358				if (prerequisite.type_symbol is Class) {
359					result = symbol_lookup_inherited (prerequisite.type_symbol, name);
360					if (result != null) {
361						return result;
362					}
363				}
364			}
365		}
366
367		return null;
368	}
369
370	public static DataType get_data_type_for_symbol (Symbol sym) {
371		DataType type;
372
373		List<TypeParameter> type_parameters = null;
374		if (sym is ObjectTypeSymbol) {
375			unowned Class cl = sym as Class;
376			if (cl != null && cl.is_error_base) {
377				type = new ErrorType (null, null);
378			} else {
379				type = new ObjectType ((ObjectTypeSymbol) sym);
380				type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters ();
381			}
382		} else if (sym is Struct) {
383			unowned Struct st = (Struct) sym;
384			if (st.is_boolean_type ()) {
385				type = new BooleanType (st);
386			} else if (st.is_integer_type ()) {
387				type = new IntegerType (st);
388			} else if (st.is_floating_type ()) {
389				type = new FloatingType (st);
390			} else {
391				type = new StructValueType (st);
392			}
393			type_parameters = st.get_type_parameters ();
394		} else if (sym is Enum) {
395			type = new EnumValueType ((Enum) sym);
396		} else if (sym is ErrorDomain) {
397			type = new ErrorType ((ErrorDomain) sym, null);
398		} else if (sym is ErrorCode) {
399			type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
400		} else {
401			Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
402			return new InvalidType ();
403		}
404
405		if (type_parameters != null) {
406			foreach (var type_param in type_parameters) {
407				var type_arg = new GenericType (type_param);
408				type_arg.value_owned = true;
409				type.add_type_argument (type_arg);
410			}
411		}
412
413		return type;
414	}
415
416	public static unowned Symbol? get_symbol_for_data_type (DataType type) {
417		unowned Symbol? sym = null;
418
419		if (type is ObjectType) {
420			sym = ((ObjectType) type).type_symbol;
421		} else if (type is ClassType) {
422			sym = ((ClassType) type).class_symbol;
423		} else if (type is InterfaceType) {
424			sym = ((InterfaceType) type).interface_symbol;
425		} else if (type is MethodType) {
426			sym = ((MethodType) type).method_symbol;
427		} else if (type is SignalType) {
428			sym = ((SignalType) type).signal_symbol;
429		} else if (type is DelegateType) {
430			sym = ((DelegateType) type).delegate_symbol;
431		} else if (type is ValueType) {
432			sym = ((ValueType) type).type_symbol;
433		}
434
435		return sym;
436	}
437
438	public bool is_gobject_property (Property prop) {
439		unowned ObjectTypeSymbol? type_sym = prop.parent_symbol as ObjectTypeSymbol;
440		if (type_sym == null || !type_sym.is_subtype_of (object_type)) {
441			return false;
442		}
443
444		if (prop.binding != MemberBinding.INSTANCE) {
445			return false;
446		}
447
448		if (prop.access == SymbolAccessibility.PRIVATE) {
449			return false;
450		}
451
452		if (!is_gobject_property_type (prop.property_type)) {
453			if (prop.property_type is ArrayType && (!prop.get_attribute_bool ("CCode", "array_length", true)
454			    && prop.get_attribute_bool ("CCode", "array_null_terminated", false))) {
455				// null-terminated arrays without length are allowed
456			} else if (prop.property_type is DelegateType && !prop.get_attribute_bool ("CCode", "delegate_target", true)) {
457				// delegates omitting their target are allowed
458			} else {
459				return false;
460			}
461		}
462
463		if (type_sym is Class && prop.base_interface_property != null &&
464		    !is_gobject_property (prop.base_interface_property)) {
465			return false;
466		}
467
468		if (!prop.name[0].isalpha ()) {
469			// GObject requires properties to start with a letter
470			return false;
471		}
472
473		if (type_sym is Interface && !prop.is_abstract && !prop.external && !prop.external_package) {
474			// GObject does not support non-abstract interface properties,
475			// however we assume external properties always are GObject properties
476			return false;
477		}
478
479		if (type_sym is Interface && type_sym.get_attribute ("DBus") != null) {
480			// GObject properties not currently supported in D-Bus interfaces
481			return false;
482		}
483
484		return true;
485	}
486
487	public bool is_gobject_property_type (DataType property_type) {
488		unowned Struct? st = property_type.type_symbol as Struct;
489		if (st != null) {
490			if (!st.is_simple_type () && st.get_attribute_bool ("CCode", "has_type_id", true)) {
491				// Allow GType-based struct types
492			} else if (property_type.nullable) {
493				return false;
494			} else if (!st.get_attribute_bool ("CCode", "has_type_id", true)) {
495				return false;
496			}
497		}
498
499		if (property_type is ArrayType && ((ArrayType) property_type).element_type.type_symbol != string_type.type_symbol) {
500			return false;
501		}
502
503		unowned DelegateType? d = property_type as DelegateType;
504		if (d != null && d.delegate_symbol.has_target) {
505			return false;
506		}
507
508		return true;
509	}
510
511	public bool check_arguments (Expression expr, DataType mtype, List<Parameter> params, List<Expression> args) {
512		bool error = false;
513
514		Expression prev_arg = null;
515		Iterator<Expression> arg_it = args.iterator ();
516
517		bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
518
519		bool ellipsis = false;
520		int i = 0;
521		foreach (Parameter param in params) {
522			if (param.ellipsis) {
523				ellipsis = true;
524				break;
525			}
526
527			if (param.params_array) {
528				while (arg_it.next ()) {
529					var arg = arg_it.get ();
530					if (!check_argument (arg, i, param.direction)) {
531						expr.error = true;
532						error = true;
533					}
534
535					i++;
536				}
537
538				break;
539			}
540
541			if (arg_it == null || !arg_it.next ()) {
542				if (param.initializer == null) {
543					expr.error = true;
544					unowned MethodType? m = mtype as MethodType;
545					if (m != null) {
546						Report.error (expr.source_reference, "%d missing arguments for `%s'".printf (m.get_parameters ().size - args.size, m.to_prototype_string ()));
547					} else {
548						Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
549					}
550					error = true;
551				} else {
552					unowned MethodCall? invocation_expr = expr as MethodCall;
553					unowned ObjectCreationExpression? object_creation_expr = expr as ObjectCreationExpression;
554					if (invocation_expr != null) {
555						invocation_expr.add_argument (param.initializer);
556					} else if (object_creation_expr != null) {
557						object_creation_expr.add_argument (param.initializer);
558					} else {
559						assert_not_reached ();
560					}
561					arg_it = null;
562				}
563			} else {
564				var arg = arg_it.get ();
565				if (!check_argument (arg, i, param.direction)) {
566					expr.error = true;
567					error = true;
568				}
569
570				prev_arg = arg;
571
572				i++;
573			}
574		}
575
576		if (ellipsis && !check_variadic_arguments (arg_it, i, expr.source_reference)) {
577			expr.error = true;
578			error = true;
579		} else if (!ellipsis && arg_it != null && arg_it.next ()) {
580			expr.error = true;
581			unowned MethodType? m = mtype as MethodType;
582			if (m != null) {
583				Report.error (expr.source_reference, "%d extra arguments for `%s'".printf (args.size - m.get_parameters ().size, m.to_prototype_string ()));
584			} else {
585				Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
586			}
587			error = true;
588		}
589
590		if (diag && prev_arg != null) {
591			unowned StringLiteral? format_arg = prev_arg as StringLiteral;
592			if (format_arg != null) {
593				format_arg.value = "\"%s:%d: %s".printf (Path.get_basename (expr.source_reference.file.filename), expr.source_reference.begin.line, format_arg.value.substring (1));
594			}
595		}
596
597		return !error;
598	}
599
600	bool check_argument (Expression arg, int i, ParameterDirection direction) {
601		if (arg.error) {
602			// ignore inner error
603			return false;
604		} else if (arg is NamedArgument) {
605			Report.error (arg.source_reference, "Named arguments are not supported yet");
606			return false;
607		} else if (arg.value_type == null) {
608			// disallow untyped arguments except for type inference of callbacks
609			if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) {
610				Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1));
611				return false;
612			}
613		} else {
614			// 0 => null, 1 => in, 2 => ref, 3 => out
615			int arg_type = 1;
616			if (arg.value_type is NullType) {
617				arg_type = 0;
618			} else if (arg is UnaryExpression) {
619				var unary = (UnaryExpression) arg;
620				if (unary.operator == UnaryOperator.REF) {
621					arg_type = 2;
622				} else if (unary.operator == UnaryOperator.OUT) {
623					arg_type = 3;
624				}
625			}
626
627			if (arg_type == 0) {
628				if (direction == ParameterDirection.REF) {
629					Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1));
630					return false;
631				} else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) {
632					Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1));
633				}
634			} else if (arg_type == 1) {
635				if (direction != ParameterDirection.IN) {
636					Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1));
637					return false;
638				}
639			} else if (arg_type == 2) {
640				if (direction != ParameterDirection.REF) {
641					Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1));
642					return false;
643				}
644
645				// weak variables can only be used with weak ref parameters
646				if (arg.target_type.is_disposable ()) {
647					if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
648						/* variable doesn't own the value */
649						Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter".printf (i + 1));
650						return false;
651					}
652				}
653
654				// owned variables can only be used with owned ref parameters
655				if (arg.value_type.is_disposable ()) {
656					if (!arg.target_type.value_owned) {
657						/* parameter doesn't own the value */
658						Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter".printf (i + 1));
659						return false;
660					}
661				}
662			} else if (arg_type == 3) {
663				if (direction != ParameterDirection.OUT) {
664					Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1));
665					return false;
666				}
667
668				// weak variables can only be used with weak out parameters
669				if (arg.target_type.is_disposable ()) {
670					if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
671						/* variable doesn't own the value */
672						Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
673						return false;
674					}
675				}
676			}
677		}
678
679		if (arg.target_type != null) {
680			if ((direction == ParameterDirection.IN || direction == ParameterDirection.REF)
681			    && !arg.value_type.compatible (arg.target_type)) {
682				Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.value_type.to_prototype_string (), arg.target_type.to_prototype_string ()));
683				return false;
684			} else if ((direction == ParameterDirection.REF || direction == ParameterDirection.OUT)
685		                && !arg.target_type.compatible (arg.value_type)
686		                && !(arg is NullLiteral)) {
687				Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.target_type.to_prototype_string (), arg.value_type.to_prototype_string ()));
688				return false;
689			}
690		}
691
692		unowned MemberAccess? ma = arg as MemberAccess;
693		if (ma != null && ma.prototype_access) {
694			// allow prototype access if target type is delegate without target
695			unowned DelegateType? deleg_type = arg.target_type as DelegateType;
696			if (deleg_type == null || deleg_type.delegate_symbol.has_target) {
697				Report.error (arg.source_reference, "Access to instance member `%s' denied".printf (arg.symbol_reference.get_full_name ()));
698				return false;
699			}
700		}
701		return true;
702	}
703
704	public bool check_variadic_arguments (Iterator<Expression>? arg_it, int i, SourceReference? source_reference = null) {
705		while (arg_it != null && arg_it.next ()) {
706			var arg = arg_it.get ();
707			if (arg.error) {
708				// ignore inner error
709				return false;
710			} else if (arg.value_type is SignalType) {
711				arg.error = true;
712				Report.error (arg.source_reference, "Cannot pass signals as arguments");
713				return false;
714			} else if (arg.value_type == null) {
715				// disallow untyped arguments except for type inference of callbacks
716				if (!(arg.symbol_reference is Method)) {
717					Report.error (source_reference, "Invalid type for argument %d".printf (i + 1));
718					return false;
719				}
720			} else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
721				// target_type known for printf arguments
722				Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.value_type.to_string (), arg.target_type.to_string ()));
723				return false;
724			}
725
726			i++;
727		}
728
729		return true;
730	}
731
732	public bool check_print_format (string format, Iterator<Expression> arg_it, SourceReference? source_reference = null) {
733		bool unsupported_format = false;
734
735		weak string format_it = format;
736		unichar c = format_it.get_char ();
737		while (c != '\0') {
738			if (c != '%') {
739				format_it = format_it.next_char ();
740				c = format_it.get_char ();
741				continue;
742			}
743
744			format_it = format_it.next_char ();
745			c = format_it.get_char ();
746			// flags
747			while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
748				format_it = format_it.next_char ();
749				c = format_it.get_char ();
750			}
751			// field width
752			while (c >= '0' && c <= '9') {
753				format_it = format_it.next_char ();
754				c = format_it.get_char ();
755			}
756			// precision
757			if (c == '.') {
758				format_it = format_it.next_char ();
759				c = format_it.get_char ();
760				while (c >= '0' && c <= '9') {
761					format_it = format_it.next_char ();
762					c = format_it.get_char ();
763				}
764			}
765			// length modifier
766			int length = 0;
767			if (c == 'h') {
768				length = -1;
769				format_it = format_it.next_char ();
770				c = format_it.get_char ();
771				if (c == 'h') {
772					length = -2;
773					format_it = format_it.next_char ();
774					c = format_it.get_char ();
775				}
776			} else if (c == 'l') {
777				length = 1;
778				format_it = format_it.next_char ();
779				c = format_it.get_char ();
780			} else if (c == 'z') {
781				length = 2;
782				format_it = format_it.next_char ();
783				c = format_it.get_char ();
784			}
785			// conversion specifier
786			DataType param_type = null;
787			if (c == 'd' || c == 'i' || c == 'c') {
788				// integer
789				if (length == -2) {
790					param_type = int8_type;
791				} else if (length == -1) {
792					param_type = short_type;
793				} else if (length == 0) {
794					param_type = int_type;
795				} else if (length == 1) {
796					param_type = long_type;
797				} else if (length == 2) {
798					param_type = ssize_t_type;
799				}
800			} else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
801				// unsigned integer
802				if (length == -2) {
803					param_type = uchar_type;
804				} else if (length == -1) {
805					param_type = ushort_type;
806				} else if (length == 0) {
807					param_type = uint_type;
808				} else if (length == 1) {
809					param_type = ulong_type;
810				} else if (length == 2) {
811					param_type = size_t_type;
812				}
813			} else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
814					   || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
815				// double
816				param_type = double_type;
817			} else if (c == 's') {
818				// string
819				param_type = string_type;
820			} else if (c == 'p') {
821				// pointer
822				param_type = new PointerType (new VoidType ());
823			} else if (c == '%') {
824				// literal %
825			} else {
826				unsupported_format = true;
827				break;
828			}
829			if (c != '\0') {
830				format_it = format_it.next_char ();
831				c = format_it.get_char ();
832			}
833			if (param_type != null) {
834				if (arg_it.next ()) {
835					Expression arg = arg_it.get ();
836
837					arg.target_type = param_type;
838				} else {
839					Report.error (source_reference, "Too few arguments for specified format");
840					return false;
841				}
842			}
843		}
844		if (!unsupported_format && arg_it.next ()) {
845			Report.error (source_reference, "Too many arguments for specified format");
846			return false;
847		}
848
849		return true;
850	}
851
852	private static DataType get_instance_base_type (DataType instance_type, DataType base_type, CodeNode? node_reference) {
853		// construct a new type reference for the base type with correctly linked type arguments
854		DataType instance_base_type;
855		if (base_type.type_symbol is ObjectTypeSymbol) {
856			instance_base_type = new ObjectType ((ObjectTypeSymbol) base_type.type_symbol);
857		} else if (base_type.type_symbol is Struct) {
858			instance_base_type = new StructValueType ((Struct) base_type.type_symbol);
859		} else {
860			assert_not_reached ();
861		}
862		foreach (DataType type_arg in base_type.get_type_arguments ()) {
863			// resolve type argument specified in base type (possibly recursively for nested generic types)
864			type_arg = type_arg.get_actual_type (instance_type, null, node_reference);
865			instance_base_type.add_type_argument (type_arg);
866		}
867		return instance_base_type;
868	}
869
870	internal static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode? node_reference) {
871		DataType instance_type = derived_instance_type;
872
873		while (instance_type is PointerType) {
874			unowned PointerType instance_pointer_type = (PointerType) instance_type;
875			instance_type = instance_pointer_type.base_type;
876		}
877
878		if (instance_type is DelegateType && ((DelegateType) instance_type).delegate_symbol == type_symbol) {
879			return instance_type;
880		} else if (instance_type.type_symbol == type_symbol) {
881			return instance_type;
882		}
883
884		DataType? instance_base_type = null;
885
886		// use same algorithm as symbol_lookup_inherited
887		if (instance_type.type_symbol is Class) {
888			unowned Class cl = (Class) instance_type.type_symbol;
889			// first check interfaces without prerequisites
890			// (prerequisites can be assumed to be met already)
891			foreach (DataType base_type in cl.get_base_types ()) {
892				if (base_type.type_symbol is Interface) {
893					instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
894					if (instance_base_type != null) {
895						return instance_base_type;
896					}
897				}
898			}
899			// then check base class recursively
900			if (instance_base_type == null) {
901				foreach (DataType base_type in cl.get_base_types ()) {
902					if (base_type.type_symbol is Class) {
903						instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
904						if (instance_base_type != null) {
905							return instance_base_type;
906						}
907					}
908				}
909			}
910		} else if (instance_type.type_symbol is Struct) {
911			unowned Struct st = (Struct) instance_type.type_symbol;
912			if (st.base_type != null) {
913				instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference);
914				if (instance_base_type != null) {
915					return instance_base_type;
916				}
917			}
918		} else if (instance_type.type_symbol is Interface) {
919			unowned Interface iface = (Interface) instance_type.type_symbol;
920			// first check interface prerequisites recursively
921			foreach (DataType prerequisite in iface.get_prerequisites ()) {
922				if (prerequisite.type_symbol is Interface) {
923					instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
924					if (instance_base_type != null) {
925						return instance_base_type;
926					}
927				}
928			}
929			if (instance_base_type == null) {
930				// then check class prerequisite recursively
931				foreach (DataType prerequisite in iface.get_prerequisites ()) {
932					if (prerequisite.type_symbol is Class) {
933						instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
934						if (instance_base_type != null) {
935							return instance_base_type;
936						}
937					}
938				}
939			}
940		}
941
942		return null;
943	}
944
945	public static DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, GenericType generic_type, CodeNode? node_reference) {
946		DataType actual_type = null;
947		if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
948			if (derived_instance_type != null) {
949				// trace type arguments back to the datatype where the method has been declared
950				var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
951
952				if (instance_type == null) {
953					if (node_reference != null) {
954						CodeNode? reference = get_symbol_for_data_type (derived_instance_type);
955						Report.error ((reference ?? node_reference).source_reference, "The type-parameter `%s' is missing".printf (generic_type.to_string ()));
956						node_reference.error = true;
957					}
958					return new InvalidType ();
959				}
960
961				int param_index;
962				if (instance_type is DelegateType) {
963					param_index = ((DelegateType) instance_type).delegate_symbol.get_type_parameter_index (generic_type.type_parameter.name);
964				} else {
965					param_index = instance_type.type_symbol.get_type_parameter_index (generic_type.type_parameter.name);
966				}
967				if (param_index == -1) {
968					if (node_reference != null) {
969						Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
970						node_reference.error = true;
971					}
972					return new InvalidType ();
973				}
974
975				if (param_index < instance_type.get_type_arguments ().size) {
976					actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
977				}
978			}
979		} else {
980			// generic method
981			unowned Method m = (Method) generic_type.type_parameter.parent_symbol;
982
983			int param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
984			if (param_index == -1) {
985				if (node_reference != null) {
986					Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
987					node_reference.error = true;
988				}
989				return new InvalidType ();
990			}
991
992			if (method_type_arguments != null) {
993				if (param_index < method_type_arguments.size) {
994					actual_type = (DataType) method_type_arguments.get (param_index);
995				}
996			}
997		}
998
999		if (actual_type == null) {
1000			// no actual type available
1001			return generic_type;
1002		}
1003		actual_type = actual_type.copy ();
1004		actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
1005		return actual_type;
1006	}
1007
1008	public bool is_in_instance_method () {
1009		unowned Symbol? sym = current_symbol;
1010		while (sym != null) {
1011			if (sym is CreationMethod) {
1012				return true;
1013			} else if (sym is Method) {
1014				unowned Method m = (Method) sym;
1015				return m.binding == MemberBinding.INSTANCE;
1016			} else if (sym is Constructor) {
1017				unowned Constructor c = (Constructor) sym;
1018				return c.binding == MemberBinding.INSTANCE;
1019			} else if (sym is Destructor) {
1020				unowned Destructor d = (Destructor) sym;
1021				return d.binding == MemberBinding.INSTANCE;
1022			} else if (sym is Property) {
1023				unowned Property p = (Property) sym;
1024				return p.binding == MemberBinding.INSTANCE;
1025			}
1026			sym = sym.parent_symbol;
1027		}
1028
1029		return false;
1030	}
1031
1032	// Create an access to a temporary variable, with proper reference transfer if needed
1033	public static Expression create_temp_access (LocalVariable local, DataType? target_type) {
1034		Expression temp_access = new MemberAccess.simple (local.name, local.source_reference);
1035
1036		var target_owned = target_type != null && target_type.value_owned;
1037		if (target_owned && local.variable_type.is_disposable ()) {
1038			temp_access = new ReferenceTransferExpression (temp_access, local.source_reference);
1039			temp_access.target_type = target_type != null ? target_type.copy () : local.variable_type.copy ();
1040			temp_access.target_type.value_owned = true;
1041		} else {
1042			temp_access.target_type = target_type != null ? target_type.copy () : null;
1043		}
1044
1045		return temp_access;
1046	}
1047
1048	public void visit_member_initializer (MemberInitializer init, DataType type) {
1049		init.symbol_reference = symbol_lookup_inherited (type.type_symbol, init.name);
1050		if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {
1051			init.error = true;
1052			Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.type_symbol.get_full_name ()));
1053			return;
1054		}
1055		if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) {
1056			init.error = true;
1057			Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ()));
1058			return;
1059		}
1060		DataType member_type = null;
1061		if (init.symbol_reference is Field) {
1062			unowned Field f = (Field) init.symbol_reference;
1063			member_type = f.variable_type;
1064		} else if (init.symbol_reference is Property) {
1065			unowned Property prop = (Property) init.symbol_reference;
1066			member_type = prop.property_type;
1067			if (prop.set_accessor == null || !prop.set_accessor.writable) {
1068				init.error = true;
1069				Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
1070				return;
1071			}
1072		}
1073
1074		init.initializer.formal_target_type = member_type;
1075		init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init);
1076
1077		if (!init.check (context)) {
1078			return;
1079		}
1080
1081		if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) {
1082			init.error = true;
1083			Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name));
1084			return;
1085		}
1086	}
1087
1088	unowned Struct? get_arithmetic_struct (DataType type) {
1089		unowned Struct? result = type.type_symbol as Struct;
1090		if (result == null && type is EnumValueType) {
1091			return (Struct) int_type.type_symbol;
1092		}
1093		return result;
1094	}
1095
1096	public unowned DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
1097		unowned Struct? left = get_arithmetic_struct (left_type);
1098		unowned Struct? right = get_arithmetic_struct (right_type);
1099
1100		if (left == null || right == null) {
1101			// at least one operand not struct
1102			return null;
1103		}
1104
1105		if ((!left.is_floating_type () && !left.is_integer_type ()) ||
1106		    (!right.is_floating_type () && !right.is_integer_type ())) {
1107			// at least one operand not numeric
1108			return null;
1109		}
1110
1111		if (left.is_floating_type () == right.is_floating_type ()) {
1112			// both operands integer or floating type
1113			if (left.rank >= right.rank) {
1114				return left_type;
1115			} else {
1116				return right_type;
1117			}
1118		} else {
1119			// one integer and one floating type operand
1120			if (left.is_floating_type ()) {
1121				return left_type;
1122			} else {
1123				return right_type;
1124			}
1125		}
1126	}
1127
1128	public unowned Method? find_current_method () {
1129		unowned Symbol? sym = current_symbol;
1130		while (sym != null) {
1131			if (sym is Method) {
1132				return (Method) sym;
1133			}
1134			sym = sym.parent_symbol;
1135		}
1136		return null;
1137	}
1138
1139	public static unowned Method? find_parent_method (Symbol sym) {
1140		while (sym is Block) {
1141			sym = sym.parent_symbol;
1142		}
1143		return sym as Method;
1144	}
1145
1146	public static unowned Symbol? find_parent_method_or_property_accessor (Symbol sym) {
1147		while (sym is Block) {
1148			sym = sym.parent_symbol;
1149		}
1150		if (sym is Method) {
1151			return sym;
1152		} else if (sym is PropertyAccessor) {
1153			return sym;
1154		} else {
1155			return null;
1156		}
1157	}
1158
1159	public static unowned TypeSymbol? find_parent_type_symbol (Symbol sym) {
1160		while (sym != null) {
1161			if (sym is TypeSymbol) {
1162				return (TypeSymbol) sym;
1163			}
1164			sym = sym.parent_symbol;
1165		}
1166		return null;
1167	}
1168
1169	public static DataType? get_this_type (Symbol s, TypeSymbol? parent = null) {
1170		unowned TypeSymbol? parent_type = parent ?? find_parent_type_symbol (s);
1171		if (parent_type == null) {
1172			Report.error (parent_type.source_reference, "internal: Unsupported symbol type");
1173			return new InvalidType ();
1174		}
1175
1176		MemberBinding binding;
1177		if (s is Method) {
1178			binding = ((Method) s).binding;
1179		} else if (s is Constructor) {
1180			binding = ((Constructor) s).binding;
1181		} else if (s is Destructor) {
1182			binding = ((Destructor) s).binding;
1183		} else if (s is Property) {
1184			binding = ((Property) s).binding;
1185		} else {
1186			Report.error (s.source_reference, "internal: Unsupported symbol type");
1187			return new InvalidType ();
1188		}
1189
1190		DataType? this_type = null;
1191		List<TypeParameter>? type_parameters = null;
1192		switch (binding) {
1193		case MemberBinding.INSTANCE:
1194			if (parent_type is Class) {
1195				this_type = new ObjectType ((Class) parent_type);
1196				type_parameters = ((Class) parent_type).get_type_parameters ();
1197			} else if (parent_type is Interface) {
1198				this_type = new ObjectType ((Interface) parent_type);
1199				type_parameters = ((Interface) parent_type).get_type_parameters ();
1200			} else if (parent_type is Struct) {
1201				this_type = new StructValueType ((Struct) parent_type);
1202				type_parameters = ((Struct) parent_type).get_type_parameters ();
1203			} else if (parent_type is Enum) {
1204				this_type = new EnumValueType ((Enum) parent_type);
1205			} else {
1206				Report.error (parent_type.source_reference, "internal: Unsupported symbol type");
1207				this_type = new InvalidType ();
1208			}
1209			break;
1210		case MemberBinding.CLASS:
1211			if (parent_type is Class) {
1212				this_type = new ClassType ((Class) parent_type);
1213			} else if (parent_type is Interface) {
1214				this_type = new InterfaceType ((Interface) parent_type);
1215			} else {
1216				Report.error (parent_type.source_reference, "internal: Unsupported symbol type");
1217				this_type = new InvalidType ();
1218			}
1219			break;
1220		case MemberBinding.STATIC:
1221		default:
1222			Report.error (s.source_reference, "internal: Does not support a parent instance");
1223			this_type = new InvalidType ();
1224			break;
1225		}
1226
1227		if (type_parameters != null) {
1228			foreach (var type_param in type_parameters) {
1229				var type_arg = new GenericType (type_param);
1230				type_arg.value_owned = true;
1231				this_type.add_type_argument (type_arg);
1232			}
1233		}
1234
1235		return this_type;
1236	}
1237
1238	public bool is_in_constructor () {
1239		unowned Symbol? sym = current_symbol;
1240		while (sym != null) {
1241			if (sym is Constructor) {
1242				return true;
1243			}
1244			sym = sym.parent_symbol;
1245		}
1246		return false;
1247	}
1248
1249	public bool is_in_destructor () {
1250		unowned Symbol? sym = current_symbol;
1251		while (sym != null) {
1252			if (sym is Destructor) {
1253				return true;
1254			}
1255			sym = sym.parent_symbol;
1256		}
1257		return false;
1258	}
1259
1260	public bool is_reference_type_argument (DataType type_arg) {
1261		if (type_arg is ErrorType || (type_arg.type_symbol != null && type_arg.type_symbol.is_reference_type ())) {
1262			return true;
1263		} else {
1264			return false;
1265		}
1266	}
1267
1268	public bool is_nullable_value_type_argument (DataType type_arg) {
1269		if (type_arg is ValueType && type_arg.nullable) {
1270			return true;
1271		} else {
1272			return false;
1273		}
1274	}
1275
1276	public bool is_signed_integer_type_argument (DataType type_arg) {
1277		unowned Struct? st = type_arg.type_symbol as Struct;
1278		if (type_arg is EnumValueType) {
1279			return true;
1280		} else if (type_arg.nullable) {
1281			return false;
1282		} else if (st == null) {
1283			return false;
1284		} else if (st.is_subtype_of (bool_type.type_symbol)) {
1285			return true;
1286		} else if (st.is_subtype_of (char_type.type_symbol)) {
1287			return true;
1288		} else if (unichar_type != null && st.is_subtype_of (unichar_type.type_symbol)) {
1289			return true;
1290		} else if (st.is_subtype_of (short_type.type_symbol)) {
1291			return true;
1292		} else if (st.is_subtype_of (int_type.type_symbol)) {
1293			return true;
1294		} else if (st.is_subtype_of (long_type.type_symbol)) {
1295			return true;
1296		} else if (st.is_subtype_of (int8_type.type_symbol)) {
1297			return true;
1298		} else if (st.is_subtype_of (int16_type.type_symbol)) {
1299			return true;
1300		} else if (st.is_subtype_of (int32_type.type_symbol)) {
1301			return true;
1302		} else if (st.is_subtype_of (type_type.type_symbol)) {
1303			return true;
1304		} else {
1305			return false;
1306		}
1307	}
1308
1309	public bool is_unsigned_integer_type_argument (DataType type_arg) {
1310		unowned Struct? st = type_arg.type_symbol as Struct;
1311		if (st == null) {
1312			return false;
1313		} else if (type_arg.nullable) {
1314			return false;
1315		} else if (st.is_subtype_of (uchar_type.type_symbol)) {
1316			return true;
1317		} else if (st.is_subtype_of (ushort_type.type_symbol)) {
1318			return true;
1319		} else if (st.is_subtype_of (uint_type.type_symbol)) {
1320			return true;
1321		} else if (st.is_subtype_of (ulong_type.type_symbol)) {
1322			return true;
1323		} else if (st.is_subtype_of (uint8_type.type_symbol)) {
1324			return true;
1325		} else if (st.is_subtype_of (uint16_type.type_symbol)) {
1326			return true;
1327		} else if (st.is_subtype_of (uint32_type.type_symbol)) {
1328			return true;
1329		} else {
1330			return false;
1331		}
1332	}
1333
1334	public void check_type (DataType type) {
1335		foreach (var type_arg in type.get_type_arguments ()) {
1336			check_type (type_arg);
1337			check_type_argument (type_arg);
1338		}
1339	}
1340
1341	public void check_type_arguments (MemberAccess access) {
1342		foreach (var type_arg in access.get_type_arguments ()) {
1343			check_type (type_arg);
1344			check_type_argument (type_arg);
1345		}
1346	}
1347
1348	void check_type_argument (DataType type_arg) {
1349		if (type_arg is GenericType
1350		    || type_arg is PointerType
1351		    || type_arg is VoidType
1352		    || is_reference_type_argument (type_arg)
1353		    || is_nullable_value_type_argument (type_arg)
1354		    || is_signed_integer_type_argument (type_arg)
1355		    || is_unsigned_integer_type_argument (type_arg)) {
1356			// no error
1357		} else if (type_arg is DelegateType) {
1358			var delegate_type = (DelegateType) type_arg;
1359			if (delegate_type.delegate_symbol.has_target) {
1360				Report.error (type_arg.source_reference, "Delegates with target are not supported as generic type arguments");
1361			}
1362		} else if (type_arg is ArrayType) {
1363			Report.error (type_arg.source_reference, "Arrays are not supported as generic type arguments");
1364		} else {
1365			Report.error (type_arg.source_reference, "`%s' is not a supported generic type argument, use `?' to box value types".printf (type_arg.to_string ()));
1366		}
1367	}
1368}
1369