vala: Add consts/methods to retrieve and check library version
[vala-gnome.git] / vala / valasemanticanalyzer.vala
blobc0c075f9aa361b66bd901c477e8f2153b8ea1d5d
1 /* valasemanticanalyzer.vala
3 * Copyright (C) 2006-2010 Jürg Billeter
4 * Copyright (C) 2006-2008 Raffaele Sandrini
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.
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.
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
20 * Author:
21 * Jürg Billeter <j@bitron.ch>
22 * Raffaele Sandrini <raffaele@sandrini.ch>
25 using GLib;
27 /**
28 * Code visitor analyzing and checking code.
30 public class Vala.SemanticAnalyzer : CodeVisitor {
31 CodeContext context;
33 public Symbol current_symbol { get; set; }
34 public SourceFile current_source_file { get; set; }
36 public TypeSymbol? current_type_symbol {
37 get {
38 var sym = current_symbol;
39 while (sym != null) {
40 if (sym is TypeSymbol) {
41 return (TypeSymbol) sym;
43 sym = sym.parent_symbol;
45 return null;
49 public Class? current_class {
50 get { return current_type_symbol as Class; }
54 public Struct? current_struct {
55 get { return current_type_symbol as Struct; }
58 public Method? current_method {
59 get {
60 unowned Symbol sym = current_symbol;
61 while (sym is Block) {
62 sym = sym.parent_symbol;
64 return sym as Method;
68 public Method? current_async_method {
69 get {
70 unowned Symbol sym = current_symbol;
71 while (sym is Block || sym is Method) {
72 var m = sym as Method;
73 if (m != null && m.coroutine) {
74 break;
77 sym = sym.parent_symbol;
79 return sym as Method;
83 public PropertyAccessor? current_property_accessor {
84 get {
85 unowned Symbol sym = current_symbol;
86 while (sym is Block) {
87 sym = sym.parent_symbol;
89 return sym as PropertyAccessor;
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;
99 if (sym is Method) {
100 return sym;
101 } else if (sym is PropertyAccessor) {
102 return sym;
103 } else {
104 return null;
109 public DataType? current_return_type {
110 get {
111 var m = current_method;
112 if (m != null) {
113 return m.return_type;
116 var acc = current_property_accessor;
117 if (acc != null) {
118 if (acc.readable) {
119 return acc.value_type;
120 } else {
121 return void_type;
125 if (is_in_constructor () || is_in_destructor ()) {
126 return void_type;
129 return null;
133 public Block insert_block;
135 public DataType void_type = new VoidType ();
136 public DataType bool_type;
137 public DataType string_type;
138 public DataType regex_type;
139 public DataType uchar_type;
140 public DataType short_type;
141 public DataType ushort_type;
142 public DataType int_type;
143 public DataType uint_type;
144 public DataType long_type;
145 public DataType ulong_type;
146 public DataType size_t_type;
147 public DataType ssize_t_type;
148 public DataType int8_type;
149 public DataType unichar_type;
150 public DataType double_type;
151 public DataType type_type;
152 public DataType va_list_type;
153 public Class object_type;
154 public StructValueType gvalue_type;
155 public ObjectType gvariant_type;
156 public DataType glist_type;
157 public DataType gslist_type;
158 public DataType garray_type;
159 public DataType gvaluearray_type;
160 public Class gerror_type;
161 public DataType list_type;
162 public DataType tuple_type;
163 public Class gsource_type;
165 // keep replaced alive to make sure they remain valid
166 // for the whole execution of CodeNode.accept
167 public List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
169 public SemanticAnalyzer () {
173 * Analyze and check code in the specified context.
175 * @param context a code context
177 public void analyze (CodeContext context) {
178 this.context = context;
180 var root_symbol = context.root;
182 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
183 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
184 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
185 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
187 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
188 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
189 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
190 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
191 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
192 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
193 size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
194 ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
195 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
196 va_list_type = new StructValueType ((Struct) root_symbol.scope.lookup ("va_list"));
198 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
199 if (unichar_struct != null) {
200 unichar_type = new IntegerType (unichar_struct);
203 if (context.profile == Profile.GOBJECT) {
204 var glib_ns = root_symbol.scope.lookup ("GLib");
206 object_type = (Class) glib_ns.scope.lookup ("Object");
207 type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type"));
208 gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value"));
209 gvariant_type = new ObjectType ((Class) glib_ns.scope.lookup ("Variant"));
211 glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List"));
212 gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList"));
213 garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array"));
214 gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray"));
216 gerror_type = (Class) glib_ns.scope.lookup ("Error");
217 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
219 gsource_type = (Class) glib_ns.scope.lookup ("Source");
222 current_symbol = root_symbol;
223 context.root.check (context);
224 context.accept (this);
226 this.context = null;
229 public override void visit_source_file (SourceFile file) {
230 current_source_file = file;
232 file.check (context);
235 // check whether type is at least as accessible as the specified symbol
236 public bool is_type_accessible (Symbol sym, DataType type) {
237 return type.is_accessible (sym);
240 public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
241 if (sym is Field) {
242 var f = (Field) sym;
243 var type = f.variable_type.copy ();
244 if (!lvalue) {
245 type.value_owned = false;
247 return type;
248 } else if (sym is EnumValue) {
249 return new EnumValueType ((Enum) sym.parent_symbol);
250 } else if (sym is Constant) {
251 var c = (Constant) sym;
252 return c.type_reference;
253 } else if (sym is Property) {
254 var prop = (Property) sym;
255 if (lvalue) {
256 if (prop.set_accessor != null && prop.set_accessor.value_type != null) {
257 return prop.set_accessor.value_type.copy ();
259 } else {
260 if (prop.get_accessor != null && prop.get_accessor.value_type != null) {
261 return prop.get_accessor.value_type.copy ();
264 } else if (sym is Parameter) {
265 var p = (Parameter) sym;
266 var type = p.variable_type.copy ();
267 if (!lvalue) {
268 type.value_owned = false;
270 return type;
271 } else if (sym is LocalVariable) {
272 var local = (LocalVariable) sym;
273 var type = local.variable_type.copy ();
274 if (!lvalue) {
275 type.value_owned = false;
277 return type;
278 } else if (sym is Method) {
279 return new MethodType ((Method) sym);
280 } else if (sym is Signal) {
281 return new SignalType ((Signal) sym);
283 return null;
286 public static Symbol? symbol_lookup_inherited (Symbol sym, string name) {
287 var result = sym.scope.lookup (name);
288 if (result != null) {
289 return result;
292 if (sym is Class) {
293 var cl = (Class) sym;
294 // first check interfaces without prerequisites
295 // (prerequisites can be assumed to be met already)
296 foreach (DataType base_type in cl.get_base_types ()) {
297 if (base_type.data_type is Interface) {
298 result = base_type.data_type.scope.lookup (name);
299 if (result != null) {
300 return result;
304 // then check base class recursively
305 if (cl.base_class != null) {
306 return symbol_lookup_inherited (cl.base_class, name);
308 } else if (sym is Struct) {
309 var st = (Struct) sym;
310 if (st.base_type != null) {
311 result = symbol_lookup_inherited (st.base_type.data_type, name);
312 if (result != null) {
313 return result;
316 } else if (sym is Interface) {
317 var iface = (Interface) sym;
318 // first check interface prerequisites recursively
319 foreach (DataType prerequisite in iface.get_prerequisites ()) {
320 if (prerequisite.data_type is Interface) {
321 result = symbol_lookup_inherited (prerequisite.data_type, name);
322 if (result != null) {
323 return result;
327 // then check class prerequisite recursively
328 foreach (DataType prerequisite in iface.get_prerequisites ()) {
329 if (prerequisite.data_type is Class) {
330 result = symbol_lookup_inherited (prerequisite.data_type, name);
331 if (result != null) {
332 return result;
338 return null;
341 public static DataType get_data_type_for_symbol (Symbol sym) {
342 DataType type = null;
344 List<TypeParameter> type_parameters = null;
345 if (sym is ObjectTypeSymbol) {
346 type = new ObjectType ((ObjectTypeSymbol) sym);
347 type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters ();
348 } else if (sym is Struct) {
349 var st = (Struct) sym;
350 if (st.is_boolean_type ()) {
351 type = new BooleanType (st);
352 } else if (st.is_integer_type ()) {
353 type = new IntegerType (st);
354 } else if (st.is_floating_type ()) {
355 type = new FloatingType (st);
356 } else {
357 type = new StructValueType (st);
359 type_parameters = st.get_type_parameters ();
360 } else if (sym is Enum) {
361 type = new EnumValueType ((Enum) sym);
362 } else if (sym is ErrorDomain) {
363 type = new ErrorType ((ErrorDomain) sym, null);
364 } else if (sym is ErrorCode) {
365 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
366 } else {
367 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
368 return new InvalidType ();
371 if (type_parameters != null) {
372 foreach (var type_param in type_parameters) {
373 var type_arg = new GenericType (type_param);
374 type_arg.value_owned = true;
375 type.add_type_argument (type_arg);
379 return type;
382 public static Symbol? get_symbol_for_data_type (DataType type) {
383 Symbol? sym = null;
385 if (type is ObjectType) {
386 sym = ((ObjectType) type).type_symbol;
387 } else if (type is ClassType) {
388 sym = ((ClassType) type).class_symbol;
389 } else if (type is InterfaceType) {
390 sym = ((InterfaceType) type).interface_symbol;
391 } else if (type is MethodType) {
392 sym = ((MethodType) type).method_symbol;
393 } else if (type is SignalType) {
394 sym = ((SignalType) type).signal_symbol;
395 } else if (type is DelegateType) {
396 sym = ((DelegateType) type).delegate_symbol;
397 } else if (type is ValueType) {
398 sym = ((ValueType) type).type_symbol;
401 return sym;
404 public bool check_arguments (Expression expr, DataType mtype, List<Parameter> params, List<Expression> args) {
405 Expression prev_arg = null;
406 Iterator<Expression> arg_it = args.iterator ();
408 bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
410 bool ellipsis = false;
411 int i = 0;
412 foreach (Parameter param in params) {
413 if (param.ellipsis) {
414 ellipsis = true;
415 break;
418 if (param.params_array) {
419 while (arg_it.next ()) {
420 var arg = arg_it.get ();
421 if (!check_argument (arg, i, param.direction)) {
422 expr.error = true;
423 return false;
426 i++;
429 break;
432 if (arg_it == null || !arg_it.next ()) {
433 if (param.initializer == null) {
434 expr.error = true;
435 var m = mtype as MethodType;
436 if (m != null) {
437 Report.error (expr.source_reference, "%d missing arguments for `%s'".printf (m.get_parameters ().size - args.size, m.to_prototype_string ()));
438 } else {
439 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
441 return false;
442 } else {
443 var invocation_expr = expr as MethodCall;
444 var object_creation_expr = expr as ObjectCreationExpression;
445 if (invocation_expr != null) {
446 invocation_expr.add_argument (param.initializer);
447 } else if (object_creation_expr != null) {
448 object_creation_expr.add_argument (param.initializer);
449 } else {
450 assert_not_reached ();
452 arg_it = null;
454 } else {
455 var arg = arg_it.get ();
456 if (!check_argument (arg, i, param.direction)) {
457 expr.error = true;
458 return false;
461 prev_arg = arg;
463 i++;
467 if (ellipsis && !check_variadic_arguments (arg_it, i, expr.source_reference)) {
468 expr.error = true;
469 return false;
470 } else if (!ellipsis && arg_it != null && arg_it.next ()) {
471 expr.error = true;
472 var m = mtype as MethodType;
473 if (m != null) {
474 Report.error (expr.source_reference, "%d extra arguments for `%s'".printf (args.size - m.get_parameters ().size, m.to_prototype_string ()));
475 } else {
476 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
478 return false;
481 if (diag && prev_arg != null) {
482 var format_arg = prev_arg as StringLiteral;
483 if (format_arg != null) {
484 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));
488 return true;
491 bool check_argument (Expression arg, int i, ParameterDirection direction) {
492 if (arg.error) {
493 // ignore inner error
494 return false;
495 } else if (arg is NamedArgument) {
496 Report.error (arg.source_reference, "Named arguments are not supported yet");
497 return false;
498 } else if (arg.value_type == null) {
499 // disallow untyped arguments except for type inference of callbacks
500 if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) {
501 Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1));
502 return false;
504 } else {
505 // 0 => null, 1 => in, 2 => ref, 3 => out
506 int arg_type = 1;
507 if (arg.value_type is NullType) {
508 arg_type = 0;
509 } else if (arg is UnaryExpression) {
510 var unary = (UnaryExpression) arg;
511 if (unary.operator == UnaryOperator.REF) {
512 arg_type = 2;
513 } else if (unary.operator == UnaryOperator.OUT) {
514 arg_type = 3;
518 if (arg_type == 0) {
519 if (direction == ParameterDirection.REF) {
520 Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1));
521 return false;
522 } else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) {
523 Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1));
525 } else if (arg_type == 1) {
526 if (direction != ParameterDirection.IN) {
527 Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1));
528 return false;
530 } else if (arg_type == 2) {
531 if (direction != ParameterDirection.REF) {
532 Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1));
533 return false;
536 // weak variables can only be used with weak ref parameters
537 if (arg.target_type.is_disposable ()) {
538 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
539 /* variable doesn't own the value */
540 Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter".printf (i + 1));
541 return false;
545 // owned variables can only be used with owned ref parameters
546 if (arg.value_type.is_disposable ()) {
547 if (!arg.target_type.value_owned) {
548 /* parameter doesn't own the value */
549 Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter".printf (i + 1));
550 return false;
553 } else if (arg_type == 3) {
554 if (direction != ParameterDirection.OUT) {
555 Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1));
556 return false;
559 // weak variables can only be used with weak out parameters
560 if (arg.target_type.is_disposable ()) {
561 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
562 /* variable doesn't own the value */
563 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
564 return false;
570 if (arg.target_type != null) {
571 if ((direction == ParameterDirection.IN || direction == ParameterDirection.REF)
572 && !arg.value_type.compatible (arg.target_type)) {
573 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 ()));
574 return false;
575 } else if ((direction == ParameterDirection.REF || direction == ParameterDirection.OUT)
576 && !arg.target_type.compatible (arg.value_type)
577 && !(arg is NullLiteral)) {
578 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 ()));
579 return false;
583 var ma = arg as MemberAccess;
584 if (ma != null && ma.prototype_access) {
585 // allow prototype access if target type is delegate without target
586 var deleg_type = arg.target_type as DelegateType;
587 if (deleg_type == null || deleg_type.delegate_symbol.has_target) {
588 Report.error (arg.source_reference, "Access to instance member `%s' denied".printf (arg.symbol_reference.get_full_name ()));
589 return false;
592 return true;
595 public bool check_variadic_arguments (Iterator<Expression>? arg_it, int i, SourceReference source_reference) {
596 while (arg_it != null && arg_it.next ()) {
597 var arg = arg_it.get ();
598 if (arg.error) {
599 // ignore inner error
600 return false;
601 } else if (arg.value_type is SignalType) {
602 arg.error = true;
603 Report.error (arg.source_reference, "Cannot pass signals as arguments");
604 return false;
605 } else if (arg.value_type == null) {
606 // disallow untyped arguments except for type inference of callbacks
607 if (!(arg.symbol_reference is Method)) {
608 Report.error (source_reference, "Invalid type for argument %d".printf (i + 1));
609 return false;
611 } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
612 // target_type known for printf arguments
613 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 ()));
614 return false;
617 i++;
620 return true;
623 public bool check_print_format (string format, Iterator<Expression> arg_it, SourceReference source_reference) {
624 bool unsupported_format = false;
626 weak string format_it = format;
627 unichar c = format_it.get_char ();
628 while (c != '\0') {
629 if (c != '%') {
630 format_it = format_it.next_char ();
631 c = format_it.get_char ();
632 continue;
635 format_it = format_it.next_char ();
636 c = format_it.get_char ();
637 // flags
638 while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
639 format_it = format_it.next_char ();
640 c = format_it.get_char ();
642 // field width
643 while (c >= '0' && c <= '9') {
644 format_it = format_it.next_char ();
645 c = format_it.get_char ();
647 // precision
648 if (c == '.') {
649 format_it = format_it.next_char ();
650 c = format_it.get_char ();
651 while (c >= '0' && c <= '9') {
652 format_it = format_it.next_char ();
653 c = format_it.get_char ();
656 // length modifier
657 int length = 0;
658 if (c == 'h') {
659 length = -1;
660 format_it = format_it.next_char ();
661 c = format_it.get_char ();
662 if (c == 'h') {
663 length = -2;
664 format_it = format_it.next_char ();
665 c = format_it.get_char ();
667 } else if (c == 'l') {
668 length = 1;
669 format_it = format_it.next_char ();
670 c = format_it.get_char ();
671 } else if (c == 'z') {
672 length = 2;
673 format_it = format_it.next_char ();
674 c = format_it.get_char ();
676 // conversion specifier
677 DataType param_type = null;
678 if (c == 'd' || c == 'i' || c == 'c') {
679 // integer
680 if (length == -2) {
681 param_type = int8_type;
682 } else if (length == -1) {
683 param_type = short_type;
684 } else if (length == 0) {
685 param_type = int_type;
686 } else if (length == 1) {
687 param_type = long_type;
688 } else if (length == 2) {
689 param_type = ssize_t_type;
691 } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
692 // unsigned integer
693 if (length == -2) {
694 param_type = uchar_type;
695 } else if (length == -1) {
696 param_type = ushort_type;
697 } else if (length == 0) {
698 param_type = uint_type;
699 } else if (length == 1) {
700 param_type = ulong_type;
701 } else if (length == 2) {
702 param_type = size_t_type;
704 } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
705 || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
706 // double
707 param_type = double_type;
708 } else if (c == 's') {
709 // string
710 param_type = string_type;
711 } else if (c == 'p') {
712 // pointer
713 param_type = new PointerType (new VoidType ());
714 } else if (c == '%') {
715 // literal %
716 } else {
717 unsupported_format = true;
718 break;
720 if (c != '\0') {
721 format_it = format_it.next_char ();
722 c = format_it.get_char ();
724 if (param_type != null) {
725 if (arg_it.next ()) {
726 Expression arg = arg_it.get ();
728 arg.target_type = param_type;
729 } else {
730 Report.error (source_reference, "Too few arguments for specified format");
731 return false;
735 if (!unsupported_format && arg_it.next ()) {
736 Report.error (source_reference, "Too many arguments for specified format");
737 return false;
740 return true;
743 private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode node_reference) {
744 // construct a new type reference for the base type with correctly linked type arguments
745 DataType instance_base_type;
746 if (base_type.data_type is ObjectTypeSymbol) {
747 instance_base_type = new ObjectType ((ObjectTypeSymbol) base_type.data_type);
748 } else if (base_type.data_type is Struct) {
749 instance_base_type = new StructValueType ((Struct) base_type.data_type);
750 } else {
751 assert_not_reached ();
753 foreach (DataType type_arg in base_type.get_type_arguments ()) {
754 // resolve type argument specified in base type (possibly recursively for nested generic types)
755 type_arg = type_arg.get_actual_type (instance_type, null, node_reference);
756 instance_base_type.add_type_argument (type_arg);
758 return instance_base_type;
761 internal static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode node_reference) {
762 DataType instance_type = derived_instance_type;
764 while (instance_type is PointerType) {
765 var instance_pointer_type = (PointerType) instance_type;
766 instance_type = instance_pointer_type.base_type;
769 if (instance_type is DelegateType && ((DelegateType) instance_type).delegate_symbol == type_symbol) {
770 return instance_type;
771 } else if (instance_type.data_type == type_symbol) {
772 return instance_type;
775 DataType instance_base_type = null;
777 // use same algorithm as symbol_lookup_inherited
778 if (instance_type.data_type is Class) {
779 var cl = (Class) instance_type.data_type;
780 // first check interfaces without prerequisites
781 // (prerequisites can be assumed to be met already)
782 foreach (DataType base_type in cl.get_base_types ()) {
783 if (base_type.data_type is Interface) {
784 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
785 if (instance_base_type != null) {
786 return instance_base_type;
790 // then check base class recursively
791 if (instance_base_type == null) {
792 foreach (DataType base_type in cl.get_base_types ()) {
793 if (base_type.data_type is Class) {
794 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
795 if (instance_base_type != null) {
796 return instance_base_type;
801 } else if (instance_type.data_type is Struct) {
802 var st = (Struct) instance_type.data_type;
803 if (st.base_type != null) {
804 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference);
805 if (instance_base_type != null) {
806 return instance_base_type;
809 } else if (instance_type.data_type is Interface) {
810 var iface = (Interface) instance_type.data_type;
811 // first check interface prerequisites recursively
812 foreach (DataType prerequisite in iface.get_prerequisites ()) {
813 if (prerequisite.data_type is Interface) {
814 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
815 if (instance_base_type != null) {
816 return instance_base_type;
820 if (instance_base_type == null) {
821 // then check class prerequisite recursively
822 foreach (DataType prerequisite in iface.get_prerequisites ()) {
823 if (prerequisite.data_type is Class) {
824 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
825 if (instance_base_type != null) {
826 return instance_base_type;
833 return null;
836 public static DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, GenericType generic_type, CodeNode node_reference) {
837 DataType actual_type = null;
838 if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
839 if (derived_instance_type != null) {
840 // trace type arguments back to the datatype where the method has been declared
841 var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
843 if (instance_type == null) {
844 CodeNode? reference = get_symbol_for_data_type (derived_instance_type);
845 Report.error ((reference ?? node_reference).source_reference, "The type-parameter `%s' is missing".printf (generic_type.to_string ()));
846 node_reference.error = true;
847 return new InvalidType ();
850 int param_index;
851 if (instance_type is DelegateType) {
852 param_index = ((DelegateType) instance_type).delegate_symbol.get_type_parameter_index (generic_type.type_parameter.name);
853 } else {
854 param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name);
856 if (param_index == -1) {
857 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
858 node_reference.error = true;
859 return new InvalidType ();
862 if (param_index < instance_type.get_type_arguments ().size) {
863 actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
866 } else {
867 // generic method
868 var m = (Method) generic_type.type_parameter.parent_symbol;
870 int param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
871 if (param_index == -1) {
872 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
873 node_reference.error = true;
874 return new InvalidType ();
877 if (method_type_arguments != null) {
878 if (param_index < method_type_arguments.size) {
879 actual_type = (DataType) method_type_arguments.get (param_index);
884 if (actual_type == null) {
885 // no actual type available
886 return generic_type;
888 actual_type = actual_type.copy ();
889 actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
890 return actual_type;
893 public bool is_in_instance_method () {
894 var sym = current_symbol;
895 while (sym != null) {
896 if (sym is CreationMethod) {
897 return true;
898 } else if (sym is Method) {
899 var m = (Method) sym;
900 return m.binding == MemberBinding.INSTANCE;
901 } else if (sym is Constructor) {
902 var c = (Constructor) sym;
903 return c.binding == MemberBinding.INSTANCE;
904 } else if (sym is Destructor) {
905 var d = (Destructor) sym;
906 return d.binding == MemberBinding.INSTANCE;
907 } else if (sym is Property) {
908 var p = (Property) sym;
909 return p.binding == MemberBinding.INSTANCE;
911 sym = sym.parent_symbol;
914 return false;
917 // Create an access to a temporary variable, with proper reference transfer if needed
918 public static Expression create_temp_access (LocalVariable local, DataType? target_type) {
919 Expression temp_access = new MemberAccess.simple (local.name, local.source_reference);
921 var target_owned = target_type != null && target_type.value_owned;
922 if (target_owned && local.variable_type.is_disposable ()) {
923 temp_access = new ReferenceTransferExpression (temp_access, local.source_reference);
924 temp_access.target_type = target_type != null ? target_type.copy () : local.variable_type.copy ();
925 temp_access.target_type.value_owned = true;
926 } else {
927 temp_access.target_type = target_type != null ? target_type.copy () : null;
930 return temp_access;
933 public void visit_member_initializer (MemberInitializer init, DataType type) {
934 init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
935 if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {
936 init.error = true;
937 Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.data_type.get_full_name ()));
938 return;
940 if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) {
941 init.error = true;
942 Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ()));
943 return;
945 DataType member_type = null;
946 if (init.symbol_reference is Field) {
947 var f = (Field) init.symbol_reference;
948 member_type = f.variable_type;
949 } else if (init.symbol_reference is Property) {
950 var prop = (Property) init.symbol_reference;
951 member_type = prop.property_type;
952 if (prop.set_accessor == null || !prop.set_accessor.writable) {
953 init.error = true;
954 Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
955 return;
959 init.initializer.formal_target_type = member_type;
960 init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init);
962 init.check (context);
964 if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) {
965 init.error = true;
966 Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name));
967 return;
971 Struct? get_arithmetic_struct (DataType type) {
972 var result = type.data_type as Struct;
973 if (result == null && type is EnumValueType) {
974 return (Struct) int_type.data_type;
976 return result;
979 public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
980 var left = get_arithmetic_struct (left_type);
981 var right = get_arithmetic_struct (right_type);
983 if (left == null || right == null) {
984 // at least one operand not struct
985 return null;
988 if ((!left.is_floating_type () && !left.is_integer_type ()) ||
989 (!right.is_floating_type () && !right.is_integer_type ())) {
990 // at least one operand not numeric
991 return null;
994 if (left.is_floating_type () == right.is_floating_type ()) {
995 // both operands integer or floating type
996 if (left.rank >= right.rank) {
997 return left_type;
998 } else {
999 return right_type;
1001 } else {
1002 // one integer and one floating type operand
1003 if (left.is_floating_type ()) {
1004 return left_type;
1005 } else {
1006 return right_type;
1011 public Method? find_current_method () {
1012 var sym = current_symbol;
1013 while (sym != null) {
1014 if (sym is Method) {
1015 return (Method) sym;
1017 sym = sym.parent_symbol;
1019 return null;
1022 public Method? find_parent_method (Symbol sym) {
1023 while (sym is Block) {
1024 sym = sym.parent_symbol;
1026 return sym as Method;
1029 public Symbol? find_parent_method_or_property_accessor (Symbol sym) {
1030 while (sym is Block) {
1031 sym = sym.parent_symbol;
1033 if (sym is Method) {
1034 return sym;
1035 } else if (sym is PropertyAccessor) {
1036 return sym;
1037 } else {
1038 return null;
1042 public bool is_in_constructor () {
1043 var sym = current_symbol;
1044 while (sym != null) {
1045 if (sym is Constructor) {
1046 return true;
1048 sym = sym.parent_symbol;
1050 return false;
1053 public bool is_in_destructor () {
1054 var sym = current_symbol;
1055 while (sym != null) {
1056 if (sym is Destructor) {
1057 return true;
1059 sym = sym.parent_symbol;
1061 return false;