girparser: Skip priv fields
[vala-lang.git] / vala / valasemanticanalyzer.vala
blob6f8407f84077de1aff009e082abc3961fb3dae40
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 public CodeContext context { get; set; }
33 public Symbol root_symbol;
34 public Symbol current_symbol { get; set; }
35 public SourceFile current_source_file { get; set; }
37 public TypeSymbol? current_type_symbol {
38 get {
39 var sym = current_symbol;
40 while (sym != null) {
41 if (sym is TypeSymbol) {
42 return (TypeSymbol) sym;
44 sym = sym.parent_symbol;
46 return null;
50 public Class? current_class {
51 get { return current_type_symbol as Class; }
55 public Struct? current_struct {
56 get { return current_type_symbol as Struct; }
59 public Method? current_method {
60 get {
61 unowned Symbol sym = current_symbol;
62 while (sym is Block) {
63 sym = sym.parent_symbol;
65 return sym as Method;
69 public Method? current_async_method {
70 get {
71 unowned Symbol sym = current_symbol;
72 while (sym is Block || sym is Method) {
73 var m = sym as Method;
74 if (m != null && m.coroutine) {
75 break;
78 sym = sym.parent_symbol;
80 return sym as Method;
84 public PropertyAccessor? current_property_accessor {
85 get {
86 unowned Symbol sym = current_symbol;
87 while (sym is Block) {
88 sym = sym.parent_symbol;
90 return sym as PropertyAccessor;
94 public Symbol? current_method_or_property_accessor {
95 get {
96 unowned Symbol sym = current_symbol;
97 while (sym is Block) {
98 sym = sym.parent_symbol;
100 if (sym is Method) {
101 return sym;
102 } else if (sym is PropertyAccessor) {
103 return sym;
104 } else {
105 return null;
110 public DataType? current_return_type {
111 get {
112 var m = current_method;
113 if (m != null) {
114 return m.return_type;
117 var acc = current_property_accessor;
118 if (acc != null) {
119 if (acc.readable) {
120 return acc.value_type;
121 } else {
122 return void_type;
126 if (is_in_constructor () || is_in_destructor ()) {
127 return void_type;
130 return null;
134 public Block insert_block;
136 public DataType void_type = new VoidType ();
137 public DataType bool_type;
138 public DataType string_type;
139 public DataType regex_type;
140 public DataType uchar_type;
141 public DataType short_type;
142 public DataType ushort_type;
143 public DataType int_type;
144 public DataType uint_type;
145 public DataType long_type;
146 public DataType ulong_type;
147 public DataType size_t_type;
148 public DataType ssize_t_type;
149 public DataType int8_type;
150 public DataType unichar_type;
151 public DataType double_type;
152 public DataType type_type;
153 public Class object_type;
154 public StructValueType gvalue_type;
155 public DataType glist_type;
156 public DataType gslist_type;
157 public DataType garray_type;
158 public DataType gvaluearray_type;
159 public Class gerror_type;
160 public DataType list_type;
161 public DataType tuple_type;
162 public DataType error_type;
164 public int next_lambda_id = 0;
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 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"));
187 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
189 if (context.profile != Profile.DOVA) {
190 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
191 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
192 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
193 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
194 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
195 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
196 size_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("size_t"));
197 ssize_t_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ssize_t"));
198 } else {
199 long_type = int_type;
200 ulong_type = uint_type;
201 size_t_type = uint_type;
202 ssize_t_type = int_type;
205 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
206 if (unichar_struct != null) {
207 unichar_type = new IntegerType (unichar_struct);
210 if (context.profile == Profile.GOBJECT) {
211 var glib_ns = root_symbol.scope.lookup ("GLib");
213 object_type = (Class) glib_ns.scope.lookup ("Object");
214 type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type"));
215 gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value"));
217 glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List"));
218 gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList"));
219 garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array"));
220 gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray"));
222 gerror_type = (Class) glib_ns.scope.lookup ("Error");
223 regex_type = new ObjectType ((Class) root_symbol.scope.lookup ("GLib").scope.lookup ("Regex"));
224 } else if (context.profile == Profile.DOVA) {
225 var dova_ns = root_symbol.scope.lookup ("Dova");
227 object_type = (Class) dova_ns.scope.lookup ("Object");
228 type_type = new ObjectType ((Class) dova_ns.scope.lookup ("Type"));
229 list_type = new ObjectType ((Class) dova_ns.scope.lookup ("List"));
230 tuple_type = new ObjectType ((Class) dova_ns.scope.lookup ("Tuple"));
231 error_type = new ObjectType ((Class) dova_ns.scope.lookup ("Error"));
234 current_symbol = root_symbol;
235 context.root.check (context);
236 context.accept (this);
239 public override void visit_source_file (SourceFile file) {
240 current_source_file = file;
242 file.check (context);
245 // check whether type is at least as accessible as the specified symbol
246 public bool is_type_accessible (Symbol sym, DataType type) {
247 return type.is_accessible (sym);
250 public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
251 if (sym is Field) {
252 var f = (Field) sym;
253 var type = f.variable_type.copy ();
254 if (!lvalue) {
255 type.value_owned = false;
257 return type;
258 } else if (sym is EnumValue) {
259 return new EnumValueType ((Enum) sym.parent_symbol);
260 } else if (sym is Constant) {
261 var c = (Constant) sym;
262 return c.type_reference;
263 } else if (sym is Property) {
264 var prop = (Property) sym;
265 if (lvalue) {
266 if (prop.set_accessor != null && prop.set_accessor.value_type != null) {
267 return prop.set_accessor.value_type.copy ();
269 } else {
270 if (prop.get_accessor != null && prop.get_accessor.value_type != null) {
271 return prop.get_accessor.value_type.copy ();
274 } else if (sym is Parameter) {
275 var p = (Parameter) sym;
276 var type = p.variable_type.copy ();
277 if (!lvalue) {
278 type.value_owned = false;
280 return type;
281 } else if (sym is LocalVariable) {
282 var local = (LocalVariable) sym;
283 var type = local.variable_type.copy ();
284 if (!lvalue && !local.floating) {
285 type.value_owned = false;
287 return type;
288 } else if (sym is Method) {
289 return new MethodType ((Method) sym);
290 } else if (sym is Signal) {
291 return new SignalType ((Signal) sym);
293 return null;
296 public static Symbol? symbol_lookup_inherited (Symbol sym, string name) {
297 var result = sym.scope.lookup (name);
298 if (result != null) {
299 return result;
302 if (sym is Class) {
303 var cl = (Class) sym;
304 // first check interfaces without prerequisites
305 // (prerequisites can be assumed to be met already)
306 foreach (DataType base_type in cl.get_base_types ()) {
307 if (base_type.data_type is Interface) {
308 result = base_type.data_type.scope.lookup (name);
309 if (result != null) {
310 return result;
314 // then check base class recursively
315 if (cl.base_class != null) {
316 return symbol_lookup_inherited (cl.base_class, name);
318 } else if (sym is Struct) {
319 var st = (Struct) sym;
320 if (st.base_type != null) {
321 result = symbol_lookup_inherited (st.base_type.data_type, name);
322 if (result != null) {
323 return result;
326 } else if (sym is Interface) {
327 var iface = (Interface) sym;
328 // first check interface prerequisites recursively
329 foreach (DataType prerequisite in iface.get_prerequisites ()) {
330 if (prerequisite.data_type is Interface) {
331 result = symbol_lookup_inherited (prerequisite.data_type, name);
332 if (result != null) {
333 return result;
337 // then check class prerequisite recursively
338 foreach (DataType prerequisite in iface.get_prerequisites ()) {
339 if (prerequisite.data_type is Class) {
340 result = symbol_lookup_inherited (prerequisite.data_type, name);
341 if (result != null) {
342 return result;
348 return null;
351 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
352 DataType type = null;
354 if (sym is ObjectTypeSymbol) {
355 type = new ObjectType ((ObjectTypeSymbol) sym);
356 } else if (sym is Struct) {
357 var st = (Struct) sym;
358 if (st.is_boolean_type ()) {
359 type = new BooleanType (st);
360 } else if (st.is_integer_type ()) {
361 type = new IntegerType (st);
362 } else if (st.is_floating_type ()) {
363 type = new FloatingType (st);
364 } else {
365 type = new StructValueType (st);
367 } else if (sym is Enum) {
368 type = new EnumValueType ((Enum) sym);
369 } else if (sym is ErrorDomain) {
370 type = new ErrorType ((ErrorDomain) sym, null);
371 } else if (sym is ErrorCode) {
372 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
373 } else {
374 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
375 return new InvalidType ();
378 return type;
381 public bool check_arguments (Expression expr, DataType mtype, List<Parameter> params, List<Expression> args) {
382 Expression prev_arg = null;
383 Iterator<Expression> arg_it = args.iterator ();
385 bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
387 bool ellipsis = false;
388 int i = 0;
389 foreach (Parameter param in params) {
390 if (!param.check (context)) {
391 return false;
394 if (param.ellipsis) {
395 ellipsis = true;
396 break;
399 if (param.params_array) {
400 while (arg_it.next ()) {
401 var arg = arg_it.get ();
402 if (!check_argument (arg, i, param.direction)) {
403 expr.error = true;
404 return false;
407 i++;
410 break;
413 if (arg_it == null || !arg_it.next ()) {
414 if (param.initializer == null) {
415 expr.error = true;
416 var m = mtype as MethodType;
417 if (m != null) {
418 Report.error (expr.source_reference, "%d missing arguments for `%s'".printf (m.get_parameters ().size - args.size, m.to_prototype_string ()));
419 } else {
420 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
422 return false;
423 } else {
424 var invocation_expr = expr as MethodCall;
425 var object_creation_expr = expr as ObjectCreationExpression;
426 if (invocation_expr != null) {
427 invocation_expr.add_argument (param.initializer);
428 } else if (object_creation_expr != null) {
429 object_creation_expr.add_argument (param.initializer);
430 } else {
431 assert_not_reached ();
433 arg_it = null;
435 } else {
436 var arg = arg_it.get ();
437 if (!check_argument (arg, i, param.direction)) {
438 expr.error = true;
439 return false;
442 prev_arg = arg;
444 i++;
448 if (ellipsis) {
449 while (arg_it != null && arg_it.next ()) {
450 var arg = arg_it.get ();
451 if (arg.error) {
452 // ignore inner error
453 expr.error = true;
454 return false;
455 } else if (arg.value_type is SignalType) {
456 arg.error = true;
457 Report.error (arg.source_reference, "Cannot pass signals as arguments");
458 return false;
459 } else if (arg.value_type == null) {
460 // disallow untyped arguments except for type inference of callbacks
461 if (!(arg.symbol_reference is Method)) {
462 expr.error = true;
463 Report.error (expr.source_reference, "Invalid type for argument %d".printf (i + 1));
464 return false;
466 } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
467 // target_type known for printf arguments
468 expr.error = true;
469 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 ()));
470 return false;
473 i++;
475 } else if (!ellipsis && arg_it != null && arg_it.next ()) {
476 expr.error = true;
477 var m = mtype as MethodType;
478 if (m != null) {
479 Report.error (expr.source_reference, "%d extra arguments for `%s'".printf (args.size - m.get_parameters ().size, m.to_prototype_string ()));
480 } else {
481 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
483 return false;
486 if (diag && prev_arg != null) {
487 var format_arg = prev_arg as StringLiteral;
488 if (format_arg != null) {
489 format_arg.value = "\"%s:%d: %s".printf (Path.get_basename (expr.source_reference.file.filename), expr.source_reference.first_line, format_arg.value.substring (1));
493 return true;
496 bool check_argument (Expression arg, int i, ParameterDirection direction) {
497 if (arg.error) {
498 // ignore inner error
499 return false;
500 } else if (arg is NamedArgument) {
501 Report.error (arg.source_reference, "Named arguments are not supported yet");
502 return false;
503 } else if (arg.value_type == null) {
504 // disallow untyped arguments except for type inference of callbacks
505 if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) {
506 Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1));
507 return false;
509 } else if (arg.target_type != null
510 && (direction == ParameterDirection.IN || direction == ParameterDirection.REF)
511 && !arg.value_type.compatible (arg.target_type)) {
512 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 ()));
513 return false;
514 } else if (arg.target_type != null
515 && (direction == ParameterDirection.REF || direction == ParameterDirection.OUT)
516 && !arg.target_type.compatible (arg.value_type)
517 && !(arg is NullLiteral)) {
518 Report.error (arg.source_reference, "Argument %d: Cannot convert from `%s' to `%s'".printf (i + 1, arg.target_type.to_string (), arg.value_type.to_string ()));
519 return false;
520 } else {
521 // 0 => null, 1 => in, 2 => ref, 3 => out
522 int arg_type = 1;
523 if (arg.value_type is NullType) {
524 arg_type = 0;
525 } else if (arg is UnaryExpression) {
526 var unary = (UnaryExpression) arg;
527 if (unary.operator == UnaryOperator.REF) {
528 arg_type = 2;
529 } else if (unary.operator == UnaryOperator.OUT) {
530 arg_type = 3;
534 if (arg_type == 0) {
535 if (direction == ParameterDirection.REF) {
536 Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1));
537 return false;
538 } else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) {
539 Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1));
541 } else if (arg_type == 1) {
542 if (direction != ParameterDirection.IN) {
543 Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1));
544 return false;
546 } else if (arg_type == 2) {
547 if (direction != ParameterDirection.REF) {
548 Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1));
549 return false;
552 // weak variables can only be used with weak ref parameters
553 if (arg.target_type.is_disposable ()) {
554 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
555 /* variable doesn't own the value */
556 Report.error (arg.source_reference, "Argument %d: Cannot pass unowned ref argument to owned reference parameter".printf (i + 1));
557 return false;
561 // owned variables can only be used with owned ref parameters
562 if (arg.value_type.is_disposable ()) {
563 if (!arg.target_type.value_owned) {
564 /* parameter doesn't own the value */
565 Report.error (arg.source_reference, "Argument %d: Cannot pass owned ref argument to unowned reference parameter".printf (i + 1));
566 return false;
569 } else if (arg_type == 3) {
570 if (direction != ParameterDirection.OUT) {
571 Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1));
572 return false;
575 // weak variables can only be used with weak out parameters
576 if (arg.target_type.is_disposable ()) {
577 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
578 /* variable doesn't own the value */
579 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
580 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 private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode node_reference) {
598 // construct a new type reference for the base type with correctly linked type arguments
599 ReferenceType instance_base_type;
600 if (base_type.data_type is Class) {
601 instance_base_type = new ObjectType ((Class) base_type.data_type);
602 } else {
603 instance_base_type = new ObjectType ((Interface) base_type.data_type);
605 foreach (DataType type_arg in base_type.get_type_arguments ()) {
606 // resolve type argument specified in base type (possibly recursively for nested generic types)
607 type_arg = type_arg.get_actual_type (instance_type, null, node_reference);
608 instance_base_type.add_type_argument (type_arg);
610 return instance_base_type;
613 static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode node_reference) {
614 DataType instance_type = derived_instance_type;
616 while (instance_type is PointerType) {
617 var instance_pointer_type = (PointerType) instance_type;
618 instance_type = instance_pointer_type.base_type;
621 if (CodeContext.get ().profile == Profile.DOVA) {
622 while (instance_type is ArrayType) {
623 var instance_array_type = (ArrayType) instance_type;
624 instance_type = new ObjectType ((Class) CodeContext.get ().root.scope.lookup ("Dova").scope.lookup ("Array"));
625 instance_type.add_type_argument (instance_array_type.element_type);
629 if (instance_type is DelegateType && ((DelegateType) instance_type).delegate_symbol == type_symbol) {
630 return instance_type;
631 } else if (instance_type.data_type == type_symbol) {
632 return instance_type;
635 DataType instance_base_type = null;
637 // use same algorithm as symbol_lookup_inherited
638 if (instance_type.data_type is Class) {
639 var cl = (Class) instance_type.data_type;
640 // first check interfaces without prerequisites
641 // (prerequisites can be assumed to be met already)
642 foreach (DataType base_type in cl.get_base_types ()) {
643 if (base_type.data_type is Interface) {
644 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
645 if (instance_base_type != null) {
646 return instance_base_type;
650 // then check base class recursively
651 if (instance_base_type == null) {
652 foreach (DataType base_type in cl.get_base_types ()) {
653 if (base_type.data_type is Class) {
654 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
655 if (instance_base_type != null) {
656 return instance_base_type;
661 } else if (instance_type.data_type is Struct) {
662 var st = (Struct) instance_type.data_type;
663 if (st.base_type != null) {
664 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference);
665 if (instance_base_type != null) {
666 return instance_base_type;
669 } else if (instance_type.data_type is Interface) {
670 var iface = (Interface) instance_type.data_type;
671 // first check interface prerequisites recursively
672 foreach (DataType prerequisite in iface.get_prerequisites ()) {
673 if (prerequisite.data_type is Interface) {
674 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
675 if (instance_base_type != null) {
676 return instance_base_type;
680 if (instance_base_type == null) {
681 // then check class prerequisite recursively
682 foreach (DataType prerequisite in iface.get_prerequisites ()) {
683 if (prerequisite.data_type is Class) {
684 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
685 if (instance_base_type != null) {
686 return instance_base_type;
693 return null;
696 public static DataType? get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, GenericType generic_type, CodeNode node_reference) {
697 DataType actual_type = null;
698 if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
699 if (derived_instance_type != null) {
700 // trace type arguments back to the datatype where the method has been declared
701 var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
703 assert (instance_type != null);
705 int param_index;
706 if (instance_type is DelegateType) {
707 param_index = ((DelegateType) instance_type).delegate_symbol.get_type_parameter_index (generic_type.type_parameter.name);
708 } else {
709 param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name);
711 if (param_index == -1) {
712 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
713 node_reference.error = true;
714 return null;
717 if (param_index < instance_type.get_type_arguments ().size) {
718 actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
721 } else {
722 // generic method
723 var m = (Method) generic_type.type_parameter.parent_symbol;
725 if (method_access == null) {
726 return generic_type;
729 int param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
730 if (param_index == -1) {
731 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
732 node_reference.error = true;
733 return null;
736 if (param_index < method_access.get_type_arguments ().size) {
737 actual_type = (DataType) method_access.get_type_arguments ().get (param_index);
741 if (actual_type == null) {
742 // no actual type available
743 return generic_type;
745 actual_type = actual_type.copy ();
746 actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
747 return actual_type;
750 public bool is_in_instance_method () {
751 var sym = current_symbol;
752 while (sym != null) {
753 if (sym is CreationMethod) {
754 return true;
755 } else if (sym is Method) {
756 var m = (Method) sym;
757 return m.binding == MemberBinding.INSTANCE;
758 } else if (sym is Constructor) {
759 var c = (Constructor) sym;
760 return c.binding == MemberBinding.INSTANCE;
761 } else if (sym is Destructor) {
762 return true;
763 } else if (sym is Property) {
764 var p = (Property) sym;
765 return p.binding == MemberBinding.INSTANCE;
767 sym = sym.parent_symbol;
770 return false;
773 public void visit_member_initializer (MemberInitializer init, DataType type) {
774 init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
775 if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {
776 init.error = true;
777 Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.data_type.get_full_name ()));
778 return;
780 if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) {
781 init.error = true;
782 Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ()));
783 return;
785 DataType member_type = null;
786 if (init.symbol_reference is Field) {
787 var f = (Field) init.symbol_reference;
788 member_type = f.variable_type;
789 } else if (init.symbol_reference is Property) {
790 var prop = (Property) init.symbol_reference;
791 member_type = prop.property_type;
792 if (prop.set_accessor == null || !prop.set_accessor.writable) {
793 init.error = true;
794 Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
795 return;
799 init.initializer.formal_target_type = member_type;
800 init.initializer.target_type = init.initializer.formal_target_type.get_actual_type (type, null, init);;
802 init.check (context);
804 if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) {
805 init.error = true;
806 Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name));
807 return;
811 Struct? get_arithmetic_struct (DataType type) {
812 var result = type.data_type as Struct;
813 if (result == null && type is EnumValueType) {
814 return (Struct) int_type.data_type;
816 return result;
819 public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
820 var left = get_arithmetic_struct (left_type);
821 var right = get_arithmetic_struct (right_type);
823 if (left == null || right == null) {
824 // at least one operand not struct
825 return null;
828 if ((!left.is_floating_type () && !left.is_integer_type ()) ||
829 (!right.is_floating_type () && !right.is_integer_type ())) {
830 // at least one operand not numeric
831 return null;
834 if (left.is_floating_type () == right.is_floating_type ()) {
835 // both operands integer or floating type
836 if (left.get_rank () >= right.get_rank ()) {
837 return left_type;
838 } else {
839 return right_type;
841 } else {
842 // one integer and one floating type operand
843 if (left.is_floating_type ()) {
844 return left_type;
845 } else {
846 return right_type;
851 public Method? find_current_method () {
852 var sym = current_symbol;
853 while (sym != null) {
854 if (sym is Method) {
855 return (Method) sym;
857 sym = sym.parent_symbol;
859 return null;
862 public Method? find_parent_method (Symbol sym) {
863 while (sym is Block) {
864 sym = sym.parent_symbol;
866 return sym as Method;
869 public Symbol? find_parent_method_or_property_accessor (Symbol sym) {
870 while (sym is Block) {
871 sym = sym.parent_symbol;
873 if (sym is Method) {
874 return sym;
875 } else if (sym is PropertyAccessor) {
876 return sym;
877 } else {
878 return null;
882 public bool is_in_constructor () {
883 var sym = current_symbol;
884 while (sym != null) {
885 if (sym is Constructor) {
886 return true;
888 sym = sym.parent_symbol;
890 return false;
893 public bool is_in_destructor () {
894 var sym = current_symbol;
895 while (sym != null) {
896 if (sym is Destructor) {
897 return true;
899 sym = sym.parent_symbol;
901 return false;