vala: Move next_lambda_id into LambdaExpression
[vala-gnome.git] / vala / valasemanticanalyzer.vala
blob5424d7fd0b718fdb7cd99fcbc3c98dca020d397b
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 DataType error_type;
164 public Class gsource_type;
166 // keep replaced alive to make sure they remain valid
167 // for the whole execution of CodeNode.accept
168 public List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
170 public SemanticAnalyzer () {
174 * Analyze and check code in the specified context.
176 * @param context a code context
178 public void analyze (CodeContext context) {
179 this.context = context;
181 var root_symbol = context.root;
183 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
184 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
185 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
186 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
188 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
189 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
190 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
191 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
192 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
193 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
194 size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
195 ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
196 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
197 va_list_type = new StructValueType ((Struct) root_symbol.scope.lookup ("va_list"));
199 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
200 if (unichar_struct != null) {
201 unichar_type = new IntegerType (unichar_struct);
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");
221 current_symbol = root_symbol;
222 context.root.check (context);
223 context.accept (this);
225 this.context = null;
228 public override void visit_source_file (SourceFile file) {
229 current_source_file = file;
231 file.check (context);
234 // check whether type is at least as accessible as the specified symbol
235 public bool is_type_accessible (Symbol sym, DataType type) {
236 return type.is_accessible (sym);
239 public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
240 if (sym is Field) {
241 var f = (Field) sym;
242 var type = f.variable_type.copy ();
243 if (!lvalue) {
244 type.value_owned = false;
246 return type;
247 } else if (sym is EnumValue) {
248 return new EnumValueType ((Enum) sym.parent_symbol);
249 } else if (sym is Constant) {
250 var c = (Constant) sym;
251 return c.type_reference;
252 } else if (sym is Property) {
253 var prop = (Property) sym;
254 if (lvalue) {
255 if (prop.set_accessor != null && prop.set_accessor.value_type != null) {
256 return prop.set_accessor.value_type.copy ();
258 } else {
259 if (prop.get_accessor != null && prop.get_accessor.value_type != null) {
260 return prop.get_accessor.value_type.copy ();
263 } else if (sym is Parameter) {
264 var p = (Parameter) sym;
265 var type = p.variable_type.copy ();
266 if (!lvalue) {
267 type.value_owned = false;
269 return type;
270 } else if (sym is LocalVariable) {
271 var local = (LocalVariable) sym;
272 var type = local.variable_type.copy ();
273 if (!lvalue) {
274 type.value_owned = false;
276 return type;
277 } else if (sym is Method) {
278 return new MethodType ((Method) sym);
279 } else if (sym is Signal) {
280 return new SignalType ((Signal) sym);
282 return null;
285 public static Symbol? symbol_lookup_inherited (Symbol sym, string name) {
286 var result = sym.scope.lookup (name);
287 if (result != null) {
288 return result;
291 if (sym is Class) {
292 var cl = (Class) sym;
293 // first check interfaces without prerequisites
294 // (prerequisites can be assumed to be met already)
295 foreach (DataType base_type in cl.get_base_types ()) {
296 if (base_type.data_type is Interface) {
297 result = base_type.data_type.scope.lookup (name);
298 if (result != null) {
299 return result;
303 // then check base class recursively
304 if (cl.base_class != null) {
305 return symbol_lookup_inherited (cl.base_class, name);
307 } else if (sym is Struct) {
308 var st = (Struct) sym;
309 if (st.base_type != null) {
310 result = symbol_lookup_inherited (st.base_type.data_type, name);
311 if (result != null) {
312 return result;
315 } else if (sym is Interface) {
316 var iface = (Interface) sym;
317 // first check interface prerequisites recursively
318 foreach (DataType prerequisite in iface.get_prerequisites ()) {
319 if (prerequisite.data_type is Interface) {
320 result = symbol_lookup_inherited (prerequisite.data_type, name);
321 if (result != null) {
322 return result;
326 // then check class prerequisite recursively
327 foreach (DataType prerequisite in iface.get_prerequisites ()) {
328 if (prerequisite.data_type is Class) {
329 result = symbol_lookup_inherited (prerequisite.data_type, name);
330 if (result != null) {
331 return result;
337 return null;
340 public static DataType get_data_type_for_symbol (Symbol sym) {
341 DataType type = null;
343 List<TypeParameter> type_parameters = null;
344 if (sym is ObjectTypeSymbol) {
345 type = new ObjectType ((ObjectTypeSymbol) sym);
346 type_parameters = ((ObjectTypeSymbol) sym).get_type_parameters ();
347 } else if (sym is Struct) {
348 var st = (Struct) sym;
349 if (st.is_boolean_type ()) {
350 type = new BooleanType (st);
351 } else if (st.is_integer_type ()) {
352 type = new IntegerType (st);
353 } else if (st.is_floating_type ()) {
354 type = new FloatingType (st);
355 } else {
356 type = new StructValueType (st);
358 type_parameters = st.get_type_parameters ();
359 } else if (sym is Enum) {
360 type = new EnumValueType ((Enum) sym);
361 } else if (sym is ErrorDomain) {
362 type = new ErrorType ((ErrorDomain) sym, null);
363 } else if (sym is ErrorCode) {
364 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
365 } else {
366 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
367 return new InvalidType ();
370 if (type_parameters != null) {
371 foreach (var type_param in type_parameters) {
372 var type_arg = new GenericType (type_param);
373 type_arg.value_owned = true;
374 type.add_type_argument (type_arg);
378 return type;
381 public static Symbol? get_symbol_for_data_type (DataType type) {
382 Symbol? sym = null;
384 if (type is ObjectType) {
385 sym = ((ObjectType) type).type_symbol;
386 } else if (type is ClassType) {
387 sym = ((ClassType) type).class_symbol;
388 } else if (type is InterfaceType) {
389 sym = ((InterfaceType) type).interface_symbol;
390 } else if (type is MethodType) {
391 sym = ((MethodType) type).method_symbol;
392 } else if (type is SignalType) {
393 sym = ((SignalType) type).signal_symbol;
394 } else if (type is DelegateType) {
395 sym = ((DelegateType) type).delegate_symbol;
396 } else if (type is ValueType) {
397 sym = ((ValueType) type).type_symbol;
400 return sym;
403 public bool check_arguments (Expression expr, DataType mtype, List<Parameter> params, List<Expression> args) {
404 Expression prev_arg = null;
405 Iterator<Expression> arg_it = args.iterator ();
407 bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
409 bool ellipsis = false;
410 int i = 0;
411 foreach (Parameter param in params) {
412 if (!param.check (context)) {
413 return false;
416 if (param.ellipsis) {
417 ellipsis = true;
418 break;
421 if (param.params_array) {
422 while (arg_it.next ()) {
423 var arg = arg_it.get ();
424 if (!check_argument (arg, i, param.direction)) {
425 expr.error = true;
426 return false;
429 i++;
432 break;
435 if (arg_it == null || !arg_it.next ()) {
436 if (param.initializer == null) {
437 expr.error = true;
438 var m = mtype as MethodType;
439 if (m != null) {
440 Report.error (expr.source_reference, "%d missing arguments for `%s'".printf (m.get_parameters ().size - args.size, m.to_prototype_string ()));
441 } else {
442 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
444 return false;
445 } else {
446 var invocation_expr = expr as MethodCall;
447 var object_creation_expr = expr as ObjectCreationExpression;
448 if (invocation_expr != null) {
449 invocation_expr.add_argument (param.initializer);
450 } else if (object_creation_expr != null) {
451 object_creation_expr.add_argument (param.initializer);
452 } else {
453 assert_not_reached ();
455 arg_it = null;
457 } else {
458 var arg = arg_it.get ();
459 if (!check_argument (arg, i, param.direction)) {
460 expr.error = true;
461 return false;
464 prev_arg = arg;
466 i++;
470 if (ellipsis && !check_variadic_arguments (arg_it, i, expr.source_reference)) {
471 expr.error = true;
472 return false;
473 } else if (!ellipsis && arg_it != null && arg_it.next ()) {
474 expr.error = true;
475 var m = mtype as MethodType;
476 if (m != null) {
477 Report.error (expr.source_reference, "%d extra arguments for `%s'".printf (args.size - m.get_parameters ().size, m.to_prototype_string ()));
478 } else {
479 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
481 return false;
484 if (diag && prev_arg != null) {
485 var format_arg = prev_arg as StringLiteral;
486 if (format_arg != null) {
487 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));
491 return true;
494 bool check_argument (Expression arg, int i, ParameterDirection direction) {
495 if (arg.error) {
496 // ignore inner error
497 return false;
498 } else if (arg is NamedArgument) {
499 Report.error (arg.source_reference, "Named arguments are not supported yet");
500 return false;
501 } else if (arg.value_type == null) {
502 // disallow untyped arguments except for type inference of callbacks
503 if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) {
504 Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1));
505 return false;
507 } else {
508 // 0 => null, 1 => in, 2 => ref, 3 => out
509 int arg_type = 1;
510 if (arg.value_type is NullType) {
511 arg_type = 0;
512 } else if (arg is UnaryExpression) {
513 var unary = (UnaryExpression) arg;
514 if (unary.operator == UnaryOperator.REF) {
515 arg_type = 2;
516 } else if (unary.operator == UnaryOperator.OUT) {
517 arg_type = 3;
521 if (arg_type == 0) {
522 if (direction == ParameterDirection.REF) {
523 Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1));
524 return false;
525 } else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) {
526 Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1));
528 } else if (arg_type == 1) {
529 if (direction != ParameterDirection.IN) {
530 Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1));
531 return false;
533 } else if (arg_type == 2) {
534 if (direction != ParameterDirection.REF) {
535 Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1));
536 return false;
539 // weak variables can only be used with weak ref parameters
540 if (arg.target_type.is_disposable ()) {
541 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
542 /* variable doesn't own the value */
543 Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter".printf (i + 1));
544 return false;
548 // owned variables can only be used with owned ref parameters
549 if (arg.value_type.is_disposable ()) {
550 if (!arg.target_type.value_owned) {
551 /* parameter doesn't own the value */
552 Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter".printf (i + 1));
553 return false;
556 } else if (arg_type == 3) {
557 if (direction != ParameterDirection.OUT) {
558 Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1));
559 return false;
562 // weak variables can only be used with weak out parameters
563 if (arg.target_type.is_disposable ()) {
564 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
565 /* variable doesn't own the value */
566 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
567 return false;
573 if (arg.target_type != null) {
574 if ((direction == ParameterDirection.IN || direction == ParameterDirection.REF)
575 && !arg.value_type.compatible (arg.target_type)) {
576 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 ()));
577 return false;
578 } else if ((direction == ParameterDirection.REF || direction == ParameterDirection.OUT)
579 && !arg.target_type.compatible (arg.value_type)
580 && !(arg is NullLiteral)) {
581 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 ()));
582 return false;
586 var ma = arg as MemberAccess;
587 if (ma != null && ma.prototype_access) {
588 // allow prototype access if target type is delegate without target
589 var deleg_type = arg.target_type as DelegateType;
590 if (deleg_type == null || deleg_type.delegate_symbol.has_target) {
591 Report.error (arg.source_reference, "Access to instance member `%s' denied".printf (arg.symbol_reference.get_full_name ()));
592 return false;
595 return true;
598 public bool check_variadic_arguments (Iterator<Expression>? arg_it, int i, SourceReference source_reference) {
599 while (arg_it != null && arg_it.next ()) {
600 var arg = arg_it.get ();
601 if (arg.error) {
602 // ignore inner error
603 return false;
604 } else if (arg.value_type is SignalType) {
605 arg.error = true;
606 Report.error (arg.source_reference, "Cannot pass signals as arguments");
607 return false;
608 } else if (arg.value_type == null) {
609 // disallow untyped arguments except for type inference of callbacks
610 if (!(arg.symbol_reference is Method)) {
611 Report.error (source_reference, "Invalid type for argument %d".printf (i + 1));
612 return false;
614 } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
615 // target_type known for printf arguments
616 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 ()));
617 return false;
620 i++;
623 return true;
626 public bool check_print_format (string format, Iterator<Expression> arg_it, SourceReference source_reference) {
627 bool unsupported_format = false;
629 weak string format_it = format;
630 unichar c = format_it.get_char ();
631 while (c != '\0') {
632 if (c != '%') {
633 format_it = format_it.next_char ();
634 c = format_it.get_char ();
635 continue;
638 format_it = format_it.next_char ();
639 c = format_it.get_char ();
640 // flags
641 while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
642 format_it = format_it.next_char ();
643 c = format_it.get_char ();
645 // field width
646 while (c >= '0' && c <= '9') {
647 format_it = format_it.next_char ();
648 c = format_it.get_char ();
650 // precision
651 if (c == '.') {
652 format_it = format_it.next_char ();
653 c = format_it.get_char ();
654 while (c >= '0' && c <= '9') {
655 format_it = format_it.next_char ();
656 c = format_it.get_char ();
659 // length modifier
660 int length = 0;
661 if (c == 'h') {
662 length = -1;
663 format_it = format_it.next_char ();
664 c = format_it.get_char ();
665 if (c == 'h') {
666 length = -2;
667 format_it = format_it.next_char ();
668 c = format_it.get_char ();
670 } else if (c == 'l') {
671 length = 1;
672 format_it = format_it.next_char ();
673 c = format_it.get_char ();
674 } else if (c == 'z') {
675 length = 2;
676 format_it = format_it.next_char ();
677 c = format_it.get_char ();
679 // conversion specifier
680 DataType param_type = null;
681 if (c == 'd' || c == 'i' || c == 'c') {
682 // integer
683 if (length == -2) {
684 param_type = int8_type;
685 } else if (length == -1) {
686 param_type = short_type;
687 } else if (length == 0) {
688 param_type = int_type;
689 } else if (length == 1) {
690 param_type = long_type;
691 } else if (length == 2) {
692 param_type = ssize_t_type;
694 } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
695 // unsigned integer
696 if (length == -2) {
697 param_type = uchar_type;
698 } else if (length == -1) {
699 param_type = ushort_type;
700 } else if (length == 0) {
701 param_type = uint_type;
702 } else if (length == 1) {
703 param_type = ulong_type;
704 } else if (length == 2) {
705 param_type = size_t_type;
707 } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
708 || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
709 // double
710 param_type = double_type;
711 } else if (c == 's') {
712 // string
713 param_type = string_type;
714 } else if (c == 'p') {
715 // pointer
716 param_type = new PointerType (new VoidType ());
717 } else if (c == '%') {
718 // literal %
719 } else {
720 unsupported_format = true;
721 break;
723 if (c != '\0') {
724 format_it = format_it.next_char ();
725 c = format_it.get_char ();
727 if (param_type != null) {
728 if (arg_it.next ()) {
729 Expression arg = arg_it.get ();
731 arg.target_type = param_type;
732 } else {
733 Report.error (source_reference, "Too few arguments for specified format");
734 return false;
738 if (!unsupported_format && arg_it.next ()) {
739 Report.error (source_reference, "Too many arguments for specified format");
740 return false;
743 return true;
746 private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode node_reference) {
747 // construct a new type reference for the base type with correctly linked type arguments
748 DataType instance_base_type;
749 if (base_type.data_type is ObjectTypeSymbol) {
750 instance_base_type = new ObjectType ((ObjectTypeSymbol) base_type.data_type);
751 } else if (base_type.data_type is Struct) {
752 instance_base_type = new StructValueType ((Struct) base_type.data_type);
753 } else {
754 assert_not_reached ();
756 foreach (DataType type_arg in base_type.get_type_arguments ()) {
757 // resolve type argument specified in base type (possibly recursively for nested generic types)
758 type_arg = type_arg.get_actual_type (instance_type, null, node_reference);
759 instance_base_type.add_type_argument (type_arg);
761 return instance_base_type;
764 internal static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode node_reference) {
765 DataType instance_type = derived_instance_type;
767 while (instance_type is PointerType) {
768 var instance_pointer_type = (PointerType) instance_type;
769 instance_type = instance_pointer_type.base_type;
772 if (instance_type is DelegateType && ((DelegateType) instance_type).delegate_symbol == type_symbol) {
773 return instance_type;
774 } else if (instance_type.data_type == type_symbol) {
775 return instance_type;
778 DataType instance_base_type = null;
780 // use same algorithm as symbol_lookup_inherited
781 if (instance_type.data_type is Class) {
782 var cl = (Class) instance_type.data_type;
783 // first check interfaces without prerequisites
784 // (prerequisites can be assumed to be met already)
785 foreach (DataType base_type in cl.get_base_types ()) {
786 if (base_type.data_type is Interface) {
787 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
788 if (instance_base_type != null) {
789 return instance_base_type;
793 // then check base class recursively
794 if (instance_base_type == null) {
795 foreach (DataType base_type in cl.get_base_types ()) {
796 if (base_type.data_type is Class) {
797 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
798 if (instance_base_type != null) {
799 return instance_base_type;
804 } else if (instance_type.data_type is Struct) {
805 var st = (Struct) instance_type.data_type;
806 if (st.base_type != null) {
807 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference);
808 if (instance_base_type != null) {
809 return instance_base_type;
812 } else if (instance_type.data_type is Interface) {
813 var iface = (Interface) instance_type.data_type;
814 // first check interface prerequisites recursively
815 foreach (DataType prerequisite in iface.get_prerequisites ()) {
816 if (prerequisite.data_type is Interface) {
817 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
818 if (instance_base_type != null) {
819 return instance_base_type;
823 if (instance_base_type == null) {
824 // then check class prerequisite recursively
825 foreach (DataType prerequisite in iface.get_prerequisites ()) {
826 if (prerequisite.data_type is Class) {
827 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
828 if (instance_base_type != null) {
829 return instance_base_type;
836 return null;
839 public static DataType get_actual_type (DataType? derived_instance_type, List<DataType>? method_type_arguments, GenericType generic_type, CodeNode node_reference) {
840 DataType actual_type = null;
841 if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
842 if (derived_instance_type != null) {
843 // trace type arguments back to the datatype where the method has been declared
844 var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
846 if (instance_type == null) {
847 CodeNode? reference = get_symbol_for_data_type (derived_instance_type);
848 Report.error ((reference ?? node_reference).source_reference, "The type-parameter `%s' is missing".printf (generic_type.to_string ()));
849 node_reference.error = true;
850 return new InvalidType ();
853 int param_index;
854 if (instance_type is DelegateType) {
855 param_index = ((DelegateType) instance_type).delegate_symbol.get_type_parameter_index (generic_type.type_parameter.name);
856 } else {
857 param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name);
859 if (param_index == -1) {
860 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
861 node_reference.error = true;
862 return new InvalidType ();
865 if (param_index < instance_type.get_type_arguments ().size) {
866 actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
869 } else {
870 // generic method
871 var m = (Method) generic_type.type_parameter.parent_symbol;
873 int param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
874 if (param_index == -1) {
875 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
876 node_reference.error = true;
877 return new InvalidType ();
880 if (method_type_arguments != null) {
881 if (param_index < method_type_arguments.size) {
882 actual_type = (DataType) method_type_arguments.get (param_index);
887 if (actual_type == null) {
888 // no actual type available
889 return generic_type;
891 actual_type = actual_type.copy ();
892 actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
893 return actual_type;
896 public bool is_in_instance_method () {
897 var sym = current_symbol;
898 while (sym != null) {
899 if (sym is CreationMethod) {
900 return true;
901 } else if (sym is Method) {
902 var m = (Method) sym;
903 return m.binding == MemberBinding.INSTANCE;
904 } else if (sym is Constructor) {
905 var c = (Constructor) sym;
906 return c.binding == MemberBinding.INSTANCE;
907 } else if (sym is Destructor) {
908 var d = (Destructor) sym;
909 return d.binding == MemberBinding.INSTANCE;
910 } else if (sym is Property) {
911 var p = (Property) sym;
912 return p.binding == MemberBinding.INSTANCE;
914 sym = sym.parent_symbol;
917 return false;
920 // Create an access to a temporary variable, with proper reference transfer if needed
921 public static Expression create_temp_access (LocalVariable local, DataType? target_type) {
922 Expression temp_access = new MemberAccess.simple (local.name, local.source_reference);
924 var target_owned = target_type != null && target_type.value_owned;
925 if (target_owned && local.variable_type.is_disposable ()) {
926 temp_access = new ReferenceTransferExpression (temp_access, local.source_reference);
927 temp_access.target_type = target_type != null ? target_type.copy () : local.variable_type.copy ();
928 temp_access.target_type.value_owned = true;
929 } else {
930 temp_access.target_type = target_type != null ? target_type.copy () : null;
933 return temp_access;
936 public void visit_member_initializer (MemberInitializer init, DataType type) {
937 init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
938 if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {
939 init.error = true;
940 Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.data_type.get_full_name ()));
941 return;
943 if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) {
944 init.error = true;
945 Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ()));
946 return;
948 DataType member_type = null;
949 if (init.symbol_reference is Field) {
950 var f = (Field) init.symbol_reference;
951 member_type = f.variable_type;
952 } else if (init.symbol_reference is Property) {
953 var prop = (Property) init.symbol_reference;
954 member_type = prop.property_type;
955 if (prop.set_accessor == null || !prop.set_accessor.writable) {
956 init.error = true;
957 Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
958 return;
962 init.initializer.formal_target_type = member_type;
963 init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init);
965 init.check (context);
967 if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) {
968 init.error = true;
969 Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name));
970 return;
974 Struct? get_arithmetic_struct (DataType type) {
975 var result = type.data_type as Struct;
976 if (result == null && type is EnumValueType) {
977 return (Struct) int_type.data_type;
979 return result;
982 public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
983 var left = get_arithmetic_struct (left_type);
984 var right = get_arithmetic_struct (right_type);
986 if (left == null || right == null) {
987 // at least one operand not struct
988 return null;
991 if ((!left.is_floating_type () && !left.is_integer_type ()) ||
992 (!right.is_floating_type () && !right.is_integer_type ())) {
993 // at least one operand not numeric
994 return null;
997 if (left.is_floating_type () == right.is_floating_type ()) {
998 // both operands integer or floating type
999 if (left.get_rank () >= right.get_rank ()) {
1000 return left_type;
1001 } else {
1002 return right_type;
1004 } else {
1005 // one integer and one floating type operand
1006 if (left.is_floating_type ()) {
1007 return left_type;
1008 } else {
1009 return right_type;
1014 public Method? find_current_method () {
1015 var sym = current_symbol;
1016 while (sym != null) {
1017 if (sym is Method) {
1018 return (Method) sym;
1020 sym = sym.parent_symbol;
1022 return null;
1025 public Method? find_parent_method (Symbol sym) {
1026 while (sym is Block) {
1027 sym = sym.parent_symbol;
1029 return sym as Method;
1032 public Symbol? find_parent_method_or_property_accessor (Symbol sym) {
1033 while (sym is Block) {
1034 sym = sym.parent_symbol;
1036 if (sym is Method) {
1037 return sym;
1038 } else if (sym is PropertyAccessor) {
1039 return sym;
1040 } else {
1041 return null;
1045 public bool is_in_constructor () {
1046 var sym = current_symbol;
1047 while (sym != null) {
1048 if (sym is Constructor) {
1049 return true;
1051 sym = sym.parent_symbol;
1053 return false;
1056 public bool is_in_destructor () {
1057 var sym = current_symbol;
1058 while (sym != null) {
1059 if (sym is Destructor) {
1060 return true;
1062 sym = sym.parent_symbol;
1064 return false;