vapi: Update GIR-based bindings
[vala-gnome.git] / vala / valasemanticanalyzer.vala
bloba0535ad4224b0fdbc9c89804d28452637b4ccc10
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 var glib_ns = root_symbol.scope.lookup ("GLib");
205 object_type = (Class) glib_ns.scope.lookup ("Object");
206 type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type"));
207 gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value"));
208 gvariant_type = new ObjectType ((Class) glib_ns.scope.lookup ("Variant"));
210 glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List"));
211 gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList"));
212 garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array"));
213 gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray"));
215 gerror_type = (Class) glib_ns.scope.lookup ("Error");
216 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
218 gsource_type = (Class) glib_ns.scope.lookup ("Source");
220 current_symbol = root_symbol;
221 context.root.check (context);
222 context.accept (this);
224 this.context = null;
227 public override void visit_source_file (SourceFile file) {
228 current_source_file = file;
230 file.check (context);
233 // check whether type is at least as accessible as the specified symbol
234 public bool is_type_accessible (Symbol sym, DataType type) {
235 return type.is_accessible (sym);
238 public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
239 if (sym is Field) {
240 var f = (Field) sym;
241 var type = f.variable_type.copy ();
242 if (!lvalue) {
243 type.value_owned = false;
245 return type;
246 } else if (sym is EnumValue) {
247 return new EnumValueType ((Enum) sym.parent_symbol);
248 } else if (sym is Constant) {
249 var c = (Constant) sym;
250 return c.type_reference;
251 } else if (sym is Property) {
252 var prop = (Property) sym;
253 if (lvalue) {
254 if (prop.set_accessor != null && prop.set_accessor.value_type != null) {
255 return prop.set_accessor.value_type.copy ();
257 } else {
258 if (prop.get_accessor != null && prop.get_accessor.value_type != null) {
259 return prop.get_accessor.value_type.copy ();
262 } else if (sym is Parameter) {
263 var p = (Parameter) sym;
264 var type = p.variable_type.copy ();
265 if (!lvalue) {
266 type.value_owned = false;
268 return type;
269 } else if (sym is LocalVariable) {
270 var local = (LocalVariable) sym;
271 var type = local.variable_type.copy ();
272 if (!lvalue) {
273 type.value_owned = false;
275 return type;
276 } else if (sym is Method) {
277 return new MethodType ((Method) sym);
278 } else if (sym is Signal) {
279 return new SignalType ((Signal) sym);
281 return null;
284 public static Symbol? symbol_lookup_inherited (Symbol sym, string name) {
285 var result = sym.scope.lookup (name);
286 if (result != null) {
287 return result;
290 if (sym is Class) {
291 var cl = (Class) sym;
292 // first check interfaces without prerequisites
293 // (prerequisites can be assumed to be met already)
294 foreach (DataType base_type in cl.get_base_types ()) {
295 if (base_type.data_type is Interface) {
296 result = base_type.data_type.scope.lookup (name);
297 if (result != null) {
298 return result;
302 // then check base class recursively
303 if (cl.base_class != null) {
304 return symbol_lookup_inherited (cl.base_class, name);
306 } else if (sym is Struct) {
307 var st = (Struct) sym;
308 if (st.base_type != null) {
309 result = symbol_lookup_inherited (st.base_type.data_type, name);
310 if (result != null) {
311 return result;
314 } else if (sym is Interface) {
315 var iface = (Interface) sym;
316 // first check interface prerequisites recursively
317 foreach (DataType prerequisite in iface.get_prerequisites ()) {
318 if (prerequisite.data_type is Interface) {
319 result = symbol_lookup_inherited (prerequisite.data_type, name);
320 if (result != null) {
321 return result;
325 // then check class prerequisite recursively
326 foreach (DataType prerequisite in iface.get_prerequisites ()) {
327 if (prerequisite.data_type is Class) {
328 result = symbol_lookup_inherited (prerequisite.data_type, name);
329 if (result != null) {
330 return result;
336 return null;
339 public static DataType get_data_type_for_symbol (Symbol sym) {
340 DataType type = null;
342 List<TypeParameter> type_parameters = null;
343 if (sym is ObjectTypeSymbol) {
344 type = new ObjectType ((ObjectTypeSymbol) sym);
345 type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters ();
346 } else if (sym is Struct) {
347 var st = (Struct) sym;
348 if (st.is_boolean_type ()) {
349 type = new BooleanType (st);
350 } else if (st.is_integer_type ()) {
351 type = new IntegerType (st);
352 } else if (st.is_floating_type ()) {
353 type = new FloatingType (st);
354 } else {
355 type = new StructValueType (st);
357 type_parameters = st.get_type_parameters ();
358 } else if (sym is Enum) {
359 type = new EnumValueType ((Enum) sym);
360 } else if (sym is ErrorDomain) {
361 type = new ErrorType ((ErrorDomain) sym, null);
362 } else if (sym is ErrorCode) {
363 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
364 } else {
365 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
366 return new InvalidType ();
369 if (type_parameters != null) {
370 foreach (var type_param in type_parameters) {
371 var type_arg = new GenericType (type_param);
372 type_arg.value_owned = true;
373 type.add_type_argument (type_arg);
377 return type;
380 public static Symbol? get_symbol_for_data_type (DataType type) {
381 Symbol? sym = null;
383 if (type is ObjectType) {
384 sym = ((ObjectType) type).type_symbol;
385 } else if (type is ClassType) {
386 sym = ((ClassType) type).class_symbol;
387 } else if (type is InterfaceType) {
388 sym = ((InterfaceType) type).interface_symbol;
389 } else if (type is MethodType) {
390 sym = ((MethodType) type).method_symbol;
391 } else if (type is SignalType) {
392 sym = ((SignalType) type).signal_symbol;
393 } else if (type is DelegateType) {
394 sym = ((DelegateType) type).delegate_symbol;
395 } else if (type is ValueType) {
396 sym = ((ValueType) type).type_symbol;
399 return sym;
402 public bool check_arguments (Expression expr, DataType mtype, List<Parameter> params, List<Expression> args) {
403 Expression prev_arg = null;
404 Iterator<Expression> arg_it = args.iterator ();
406 bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
408 bool ellipsis = false;
409 int i = 0;
410 foreach (Parameter param in params) {
411 if (!param.check (context)) {
412 return false;
415 if (param.ellipsis) {
416 ellipsis = true;
417 break;
420 if (param.params_array) {
421 while (arg_it.next ()) {
422 var arg = arg_it.get ();
423 if (!check_argument (arg, i, param.direction)) {
424 expr.error = true;
425 return false;
428 i++;
431 break;
434 if (arg_it == null || !arg_it.next ()) {
435 if (param.initializer == null) {
436 expr.error = true;
437 var m = mtype as MethodType;
438 if (m != null) {
439 Report.error (expr.source_reference, "%d missing arguments for `%s'".printf (m.get_parameters ().size - args.size, m.to_prototype_string ()));
440 } else {
441 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
443 return false;
444 } else {
445 var invocation_expr = expr as MethodCall;
446 var object_creation_expr = expr as ObjectCreationExpression;
447 if (invocation_expr != null) {
448 invocation_expr.add_argument (param.initializer);
449 } else if (object_creation_expr != null) {
450 object_creation_expr.add_argument (param.initializer);
451 } else {
452 assert_not_reached ();
454 arg_it = null;
456 } else {
457 var arg = arg_it.get ();
458 if (!check_argument (arg, i, param.direction)) {
459 expr.error = true;
460 return false;
463 prev_arg = arg;
465 i++;
469 if (ellipsis && !check_variadic_arguments (arg_it, i, expr.source_reference)) {
470 expr.error = true;
471 return false;
472 } else if (!ellipsis && arg_it != null && arg_it.next ()) {
473 expr.error = true;
474 var m = mtype as MethodType;
475 if (m != null) {
476 Report.error (expr.source_reference, "%d extra arguments for `%s'".printf (args.size - m.get_parameters ().size, m.to_prototype_string ()));
477 } else {
478 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
480 return false;
483 if (diag && prev_arg != null) {
484 var format_arg = prev_arg as StringLiteral;
485 if (format_arg != null) {
486 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));
490 return true;
493 bool check_argument (Expression arg, int i, ParameterDirection direction) {
494 if (arg.error) {
495 // ignore inner error
496 return false;
497 } else if (arg is NamedArgument) {
498 Report.error (arg.source_reference, "Named arguments are not supported yet");
499 return false;
500 } else if (arg.value_type == null) {
501 // disallow untyped arguments except for type inference of callbacks
502 if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) {
503 Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1));
504 return false;
506 } else {
507 // 0 => null, 1 => in, 2 => ref, 3 => out
508 int arg_type = 1;
509 if (arg.value_type is NullType) {
510 arg_type = 0;
511 } else if (arg is UnaryExpression) {
512 var unary = (UnaryExpression) arg;
513 if (unary.operator == UnaryOperator.REF) {
514 arg_type = 2;
515 } else if (unary.operator == UnaryOperator.OUT) {
516 arg_type = 3;
520 if (arg_type == 0) {
521 if (direction == ParameterDirection.REF) {
522 Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1));
523 return false;
524 } else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) {
525 Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1));
527 } else if (arg_type == 1) {
528 if (direction != ParameterDirection.IN) {
529 Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1));
530 return false;
532 } else if (arg_type == 2) {
533 if (direction != ParameterDirection.REF) {
534 Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1));
535 return false;
538 // weak variables can only be used with weak ref parameters
539 if (arg.target_type.is_disposable ()) {
540 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
541 /* variable doesn't own the value */
542 Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter".printf (i + 1));
543 return false;
547 // owned variables can only be used with owned ref parameters
548 if (arg.value_type.is_disposable ()) {
549 if (!arg.target_type.value_owned) {
550 /* parameter doesn't own the value */
551 Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter".printf (i + 1));
552 return false;
555 } else if (arg_type == 3) {
556 if (direction != ParameterDirection.OUT) {
557 Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1));
558 return false;
561 // weak variables can only be used with weak out parameters
562 if (arg.target_type.is_disposable ()) {
563 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
564 /* variable doesn't own the value */
565 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
566 return false;
572 if (arg.target_type != null) {
573 if ((direction == ParameterDirection.IN || direction == ParameterDirection.REF)
574 && !arg.value_type.compatible (arg.target_type)) {
575 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 ()));
576 return false;
577 } else if ((direction == ParameterDirection.REF || direction == ParameterDirection.OUT)
578 && !arg.target_type.compatible (arg.value_type)
579 && !(arg is NullLiteral)) {
580 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 ()));
581 return false;
585 var ma = arg as MemberAccess;
586 if (ma != null && ma.prototype_access) {
587 // allow prototype access if target type is delegate without target
588 var deleg_type = arg.target_type as DelegateType;
589 if (deleg_type == null || deleg_type.delegate_symbol.has_target) {
590 Report.error (arg.source_reference, "Access to instance member `%s' denied".printf (arg.symbol_reference.get_full_name ()));
591 return false;
594 return true;
597 public bool check_variadic_arguments (Iterator<Expression>? arg_it, int i, SourceReference source_reference) {
598 while (arg_it != null && arg_it.next ()) {
599 var arg = arg_it.get ();
600 if (arg.error) {
601 // ignore inner error
602 return false;
603 } else if (arg.value_type is SignalType) {
604 arg.error = true;
605 Report.error (arg.source_reference, "Cannot pass signals as arguments");
606 return false;
607 } else if (arg.value_type == null) {
608 // disallow untyped arguments except for type inference of callbacks
609 if (!(arg.symbol_reference is Method)) {
610 Report.error (source_reference, "Invalid type for argument %d".printf (i + 1));
611 return false;
613 } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
614 // target_type known for printf arguments
615 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 ()));
616 return false;
619 i++;
622 return true;
625 public bool check_print_format (string format, Iterator<Expression> arg_it, SourceReference source_reference) {
626 bool unsupported_format = false;
628 weak string format_it = format;
629 unichar c = format_it.get_char ();
630 while (c != '\0') {
631 if (c != '%') {
632 format_it = format_it.next_char ();
633 c = format_it.get_char ();
634 continue;
637 format_it = format_it.next_char ();
638 c = format_it.get_char ();
639 // flags
640 while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
641 format_it = format_it.next_char ();
642 c = format_it.get_char ();
644 // field width
645 while (c >= '0' && c <= '9') {
646 format_it = format_it.next_char ();
647 c = format_it.get_char ();
649 // precision
650 if (c == '.') {
651 format_it = format_it.next_char ();
652 c = format_it.get_char ();
653 while (c >= '0' && c <= '9') {
654 format_it = format_it.next_char ();
655 c = format_it.get_char ();
658 // length modifier
659 int length = 0;
660 if (c == 'h') {
661 length = -1;
662 format_it = format_it.next_char ();
663 c = format_it.get_char ();
664 if (c == 'h') {
665 length = -2;
666 format_it = format_it.next_char ();
667 c = format_it.get_char ();
669 } else if (c == 'l') {
670 length = 1;
671 format_it = format_it.next_char ();
672 c = format_it.get_char ();
673 } else if (c == 'z') {
674 length = 2;
675 format_it = format_it.next_char ();
676 c = format_it.get_char ();
678 // conversion specifier
679 DataType param_type = null;
680 if (c == 'd' || c == 'i' || c == 'c') {
681 // integer
682 if (length == -2) {
683 param_type = int8_type;
684 } else if (length == -1) {
685 param_type = short_type;
686 } else if (length == 0) {
687 param_type = int_type;
688 } else if (length == 1) {
689 param_type = long_type;
690 } else if (length == 2) {
691 param_type = ssize_t_type;
693 } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
694 // unsigned integer
695 if (length == -2) {
696 param_type = uchar_type;
697 } else if (length == -1) {
698 param_type = ushort_type;
699 } else if (length == 0) {
700 param_type = uint_type;
701 } else if (length == 1) {
702 param_type = ulong_type;
703 } else if (length == 2) {
704 param_type = size_t_type;
706 } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
707 || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
708 // double
709 param_type = double_type;
710 } else if (c == 's') {
711 // string
712 param_type = string_type;
713 } else if (c == 'p') {
714 // pointer
715 param_type = new PointerType (new VoidType ());
716 } else if (c == '%') {
717 // literal %
718 } else {
719 unsupported_format = true;
720 break;
722 if (c != '\0') {
723 format_it = format_it.next_char ();
724 c = format_it.get_char ();
726 if (param_type != null) {
727 if (arg_it.next ()) {
728 Expression arg = arg_it.get ();
730 arg.target_type = param_type;
731 } else {
732 Report.error (source_reference, "Too few arguments for specified format");
733 return false;
737 if (!unsupported_format && arg_it.next ()) {
738 Report.error (source_reference, "Too many arguments for specified format");
739 return false;
742 return true;
745 private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode node_reference) {
746 // construct a new type reference for the base type with correctly linked type arguments
747 DataType instance_base_type;
748 if (base_type.data_type is ObjectTypeSymbol) {
749 instance_base_type = new ObjectType ((ObjectTypeSymbol) base_type.data_type);
750 } else if (base_type.data_type is Struct) {
751 instance_base_type = new StructValueType ((Struct) base_type.data_type);
752 } else {
753 assert_not_reached ();
755 foreach (DataType type_arg in base_type.get_type_arguments ()) {
756 // resolve type argument specified in base type (possibly recursively for nested generic types)
757 type_arg = type_arg.get_actual_type (instance_type, null, node_reference);
758 instance_base_type.add_type_argument (type_arg);
760 return instance_base_type;
763 internal static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode node_reference) {
764 DataType instance_type = derived_instance_type;
766 while (instance_type is PointerType) {
767 var instance_pointer_type = (PointerType) instance_type;
768 instance_type = instance_pointer_type.base_type;
771 if (instance_type is DelegateType && ((DelegateType) instance_type).delegate_symbol == type_symbol) {
772 return instance_type;
773 } else if (instance_type.data_type == type_symbol) {
774 return instance_type;
777 DataType instance_base_type = null;
779 // use same algorithm as symbol_lookup_inherited
780 if (instance_type.data_type is Class) {
781 var cl = (Class) instance_type.data_type;
782 // first check interfaces without prerequisites
783 // (prerequisites can be assumed to be met already)
784 foreach (DataType base_type in cl.get_base_types ()) {
785 if (base_type.data_type is Interface) {
786 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
787 if (instance_base_type != null) {
788 return instance_base_type;
792 // then check base class recursively
793 if (instance_base_type == null) {
794 foreach (DataType base_type in cl.get_base_types ()) {
795 if (base_type.data_type is Class) {
796 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
797 if (instance_base_type != null) {
798 return instance_base_type;
803 } else if (instance_type.data_type is Struct) {
804 var st = (Struct) instance_type.data_type;
805 if (st.base_type != null) {
806 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference);
807 if (instance_base_type != null) {
808 return instance_base_type;
811 } else if (instance_type.data_type is Interface) {
812 var iface = (Interface) instance_type.data_type;
813 // first check interface prerequisites recursively
814 foreach (DataType prerequisite in iface.get_prerequisites ()) {
815 if (prerequisite.data_type is Interface) {
816 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
817 if (instance_base_type != null) {
818 return instance_base_type;
822 if (instance_base_type == null) {
823 // then check class prerequisite recursively
824 foreach (DataType prerequisite in iface.get_prerequisites ()) {
825 if (prerequisite.data_type is Class) {
826 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
827 if (instance_base_type != null) {
828 return instance_base_type;
835 return null;
838 public static DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, GenericType generic_type, CodeNode node_reference) {
839 DataType actual_type = null;
840 if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
841 if (derived_instance_type != null) {
842 // trace type arguments back to the datatype where the method has been declared
843 var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
845 if (instance_type == null) {
846 CodeNode? reference = get_symbol_for_data_type (derived_instance_type);
847 Report.error ((reference ?? node_reference).source_reference, "The type-parameter `%s' is missing".printf (generic_type.to_string ()));
848 node_reference.error = true;
849 return new InvalidType ();
852 int param_index;
853 if (instance_type is DelegateType) {
854 param_index = ((DelegateType) instance_type).delegate_symbol.get_type_parameter_index (generic_type.type_parameter.name);
855 } else {
856 param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name);
858 if (param_index == -1) {
859 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
860 node_reference.error = true;
861 return new InvalidType ();
864 if (param_index < instance_type.get_type_arguments ().size) {
865 actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
868 } else {
869 // generic method
870 var m = (Method) generic_type.type_parameter.parent_symbol;
872 int param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
873 if (param_index == -1) {
874 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
875 node_reference.error = true;
876 return new InvalidType ();
879 if (method_type_arguments != null) {
880 if (param_index < method_type_arguments.size) {
881 actual_type = (DataType) method_type_arguments.get (param_index);
886 if (actual_type == null) {
887 // no actual type available
888 return generic_type;
890 actual_type = actual_type.copy ();
891 actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
892 return actual_type;
895 public bool is_in_instance_method () {
896 var sym = current_symbol;
897 while (sym != null) {
898 if (sym is CreationMethod) {
899 return true;
900 } else if (sym is Method) {
901 var m = (Method) sym;
902 return m.binding == MemberBinding.INSTANCE;
903 } else if (sym is Constructor) {
904 var c = (Constructor) sym;
905 return c.binding == MemberBinding.INSTANCE;
906 } else if (sym is Destructor) {
907 var d = (Destructor) sym;
908 return d.binding == MemberBinding.INSTANCE;
909 } else if (sym is Property) {
910 var p = (Property) sym;
911 return p.binding == MemberBinding.INSTANCE;
913 sym = sym.parent_symbol;
916 return false;
919 // Create an access to a temporary variable, with proper reference transfer if needed
920 public static Expression create_temp_access (LocalVariable local, DataType? target_type) {
921 Expression temp_access = new MemberAccess.simple (local.name, local.source_reference);
923 var target_owned = target_type != null && target_type.value_owned;
924 if (target_owned && local.variable_type.is_disposable ()) {
925 temp_access = new ReferenceTransferExpression (temp_access, local.source_reference);
926 temp_access.target_type = target_type != null ? target_type.copy () : local.variable_type.copy ();
927 temp_access.target_type.value_owned = true;
928 } else {
929 temp_access.target_type = target_type != null ? target_type.copy () : null;
932 return temp_access;
935 public void visit_member_initializer (MemberInitializer init, DataType type) {
936 init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
937 if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {
938 init.error = true;
939 Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.data_type.get_full_name ()));
940 return;
942 if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) {
943 init.error = true;
944 Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ()));
945 return;
947 DataType member_type = null;
948 if (init.symbol_reference is Field) {
949 var f = (Field) init.symbol_reference;
950 member_type = f.variable_type;
951 } else if (init.symbol_reference is Property) {
952 var prop = (Property) init.symbol_reference;
953 member_type = prop.property_type;
954 if (prop.set_accessor == null || !prop.set_accessor.writable) {
955 init.error = true;
956 Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
957 return;
961 init.initializer.formal_target_type = member_type;
962 init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init);
964 init.check (context);
966 if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) {
967 init.error = true;
968 Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name));
969 return;
973 Struct? get_arithmetic_struct (DataType type) {
974 var result = type.data_type as Struct;
975 if (result == null && type is EnumValueType) {
976 return (Struct) int_type.data_type;
978 return result;
981 public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
982 var left = get_arithmetic_struct (left_type);
983 var right = get_arithmetic_struct (right_type);
985 if (left == null || right == null) {
986 // at least one operand not struct
987 return null;
990 if ((!left.is_floating_type () && !left.is_integer_type ()) ||
991 (!right.is_floating_type () && !right.is_integer_type ())) {
992 // at least one operand not numeric
993 return null;
996 if (left.is_floating_type () == right.is_floating_type ()) {
997 // both operands integer or floating type
998 if (left.get_rank () >= right.get_rank ()) {
999 return left_type;
1000 } else {
1001 return right_type;
1003 } else {
1004 // one integer and one floating type operand
1005 if (left.is_floating_type ()) {
1006 return left_type;
1007 } else {
1008 return right_type;
1013 public Method? find_current_method () {
1014 var sym = current_symbol;
1015 while (sym != null) {
1016 if (sym is Method) {
1017 return (Method) sym;
1019 sym = sym.parent_symbol;
1021 return null;
1024 public Method? find_parent_method (Symbol sym) {
1025 while (sym is Block) {
1026 sym = sym.parent_symbol;
1028 return sym as Method;
1031 public Symbol? find_parent_method_or_property_accessor (Symbol sym) {
1032 while (sym is Block) {
1033 sym = sym.parent_symbol;
1035 if (sym is Method) {
1036 return sym;
1037 } else if (sym is PropertyAccessor) {
1038 return sym;
1039 } else {
1040 return null;
1044 public bool is_in_constructor () {
1045 var sym = current_symbol;
1046 while (sym != null) {
1047 if (sym is Constructor) {
1048 return true;
1050 sym = sym.parent_symbol;
1052 return false;
1055 public bool is_in_destructor () {
1056 var sym = current_symbol;
1057 while (sym != null) {
1058 if (sym is Destructor) {
1059 return true;
1061 sym = sym.parent_symbol;
1063 return false;