Release 0.7.8
[vala-lang.git] / vala / valasemanticanalyzer.vala
blobb18fe9663b33239905e7b394edeb4797962411a8
1 /* valasemanticanalyzer.vala
3 * Copyright (C) 2006-2009 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 var sym = current_symbol;
62 while (sym is Block) {
63 sym = sym.parent_symbol;
65 return sym as Method;
69 public PropertyAccessor? current_property_accessor {
70 get {
71 var sym = current_symbol;
72 while (sym is Block) {
73 sym = sym.parent_symbol;
75 return sym as PropertyAccessor;
79 public DataType? current_return_type {
80 get {
81 var m = current_method;
82 if (m != null) {
83 return m.return_type;
86 var acc = current_property_accessor;
87 if (acc != null) {
88 if (acc.readable) {
89 return acc.value_type;
90 } else {
91 return void_type;
95 return null;
99 public Block insert_block;
101 public DataType void_type = new VoidType ();
102 public DataType bool_type;
103 public DataType string_type;
104 public DataType uchar_type;
105 public DataType short_type;
106 public DataType ushort_type;
107 public DataType int_type;
108 public DataType uint_type;
109 public DataType long_type;
110 public DataType ulong_type;
111 public DataType size_t_type;
112 public DataType ssize_t_type;
113 public DataType int8_type;
114 public DataType unichar_type;
115 public DataType double_type;
116 public DataType type_type;
117 public Class object_type;
118 public StructValueType gvalue_type;
119 public DataType glist_type;
120 public DataType gslist_type;
121 public DataType garray_type;
122 public DataType gvaluearray_type;
123 public Class gerror_type;
125 public int next_lambda_id = 0;
127 // keep replaced alive to make sure they remain valid
128 // for the whole execution of CodeNode.accept
129 public List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
131 public SemanticAnalyzer () {
135 * Analyze and check code in the specified context.
137 * @param context a code context
139 public void analyze (CodeContext context) {
140 this.context = context;
142 root_symbol = context.root;
144 bool_type = new BooleanType ((Struct) root_symbol.scope.lookup ("bool"));
145 string_type = new ObjectType ((Class) root_symbol.scope.lookup ("string"));
147 uchar_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uchar"));
148 short_type = new IntegerType ((Struct) root_symbol.scope.lookup ("short"));
149 ushort_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ushort"));
150 int_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int"));
151 uint_type = new IntegerType ((Struct) root_symbol.scope.lookup ("uint"));
152 long_type = new IntegerType ((Struct) root_symbol.scope.lookup ("long"));
153 ulong_type = new IntegerType ((Struct) root_symbol.scope.lookup ("ulong"));
154 int8_type = new IntegerType ((Struct) root_symbol.scope.lookup ("int8"));
155 double_type = new FloatingType ((Struct) root_symbol.scope.lookup ("double"));
157 var unichar_struct = (Struct) root_symbol.scope.lookup ("unichar");
158 if (unichar_struct != null) {
159 unichar_type = new IntegerType (unichar_struct);
161 var size_t_struct = (Struct) root_symbol.scope.lookup ("size_t");
162 if (size_t_struct != null) {
163 size_t_type = new IntegerType (size_t_struct);
165 var ssize_t_struct = (Struct) root_symbol.scope.lookup ("ssize_t");
166 if (ssize_t_struct != null) {
167 ssize_t_type = new IntegerType (ssize_t_struct);
170 if (context.profile == Profile.GOBJECT) {
171 var glib_ns = root_symbol.scope.lookup ("GLib");
173 object_type = (Class) glib_ns.scope.lookup ("Object");
174 type_type = new IntegerType ((Struct) glib_ns.scope.lookup ("Type"));
175 gvalue_type = new StructValueType ((Struct) glib_ns.scope.lookup ("Value"));
177 glist_type = new ObjectType ((Class) glib_ns.scope.lookup ("List"));
178 gslist_type = new ObjectType ((Class) glib_ns.scope.lookup ("SList"));
179 garray_type = new ObjectType ((Class) glib_ns.scope.lookup ("Array"));
180 gvaluearray_type = new ObjectType ((Class) glib_ns.scope.lookup ("ValueArray"));
182 gerror_type = (Class) glib_ns.scope.lookup ("Error");
185 current_symbol = root_symbol;
186 context.root.check (this);
187 context.accept (this);
190 public override void visit_source_file (SourceFile file) {
191 current_source_file = file;
193 file.check (this);
196 // check whether type is at least as accessible as the specified symbol
197 public bool is_type_accessible (Symbol sym, DataType type) {
198 foreach (Symbol type_symbol in type.get_symbols ()) {
199 Scope method_scope = sym.get_top_accessible_scope ();
200 Scope type_scope = type_symbol.get_top_accessible_scope ();
201 if ((method_scope == null && type_scope != null)
202 || (method_scope != null && !method_scope.is_subscope_of (type_scope))) {
203 return false;
207 return true;
210 public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
211 if (sym is Field) {
212 var f = (Field) sym;
213 var type = f.field_type.copy ();
214 if (!lvalue) {
215 type.value_owned = false;
217 return type;
218 } else if (sym is Constant) {
219 var c = (Constant) sym;
220 return c.type_reference;
221 } else if (sym is Property) {
222 var prop = (Property) sym;
223 if (lvalue) {
224 if (prop.set_accessor != null && prop.set_accessor.value_type != null) {
225 return prop.set_accessor.value_type.copy ();
227 } else {
228 if (prop.get_accessor != null && prop.get_accessor.value_type != null) {
229 return prop.get_accessor.value_type.copy ();
232 } else if (sym is FormalParameter) {
233 var p = (FormalParameter) sym;
234 var type = p.parameter_type.copy ();
235 if (!lvalue) {
236 type.value_owned = false;
238 return type;
239 } else if (sym is LocalVariable) {
240 var local = (LocalVariable) sym;
241 var type = local.variable_type.copy ();
242 if (!lvalue && !local.floating) {
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 Method) {
249 return new MethodType ((Method) sym);
250 } else if (sym is Signal) {
251 return new SignalType ((Signal) sym);
253 return null;
256 public static Symbol? symbol_lookup_inherited (Symbol sym, string name) {
257 var result = sym.scope.lookup (name);
258 if (result != null) {
259 return result;
262 if (sym is Class) {
263 var cl = (Class) sym;
264 // first check interfaces without prerequisites
265 // (prerequisites can be assumed to be met already)
266 foreach (DataType base_type in cl.get_base_types ()) {
267 if (base_type.data_type is Interface) {
268 result = base_type.data_type.scope.lookup (name);
269 if (result != null) {
270 return result;
274 // then check base class recursively
275 if (cl.base_class != null) {
276 return symbol_lookup_inherited (cl.base_class, name);
278 } else if (sym is Struct) {
279 var st = (Struct) sym;
280 if (st.base_type != null) {
281 result = symbol_lookup_inherited (st.base_type.data_type, name);
282 if (result != null) {
283 return result;
286 } else if (sym is Interface) {
287 var iface = (Interface) sym;
288 // first check interface prerequisites recursively
289 foreach (DataType prerequisite in iface.get_prerequisites ()) {
290 if (prerequisite.data_type is Interface) {
291 result = symbol_lookup_inherited (prerequisite.data_type, name);
292 if (result != null) {
293 return result;
297 // then check class prerequisite recursively
298 foreach (DataType prerequisite in iface.get_prerequisites ()) {
299 if (prerequisite.data_type is Class) {
300 result = symbol_lookup_inherited (prerequisite.data_type, name);
301 if (result != null) {
302 return result;
308 return null;
311 public static DataType get_data_type_for_symbol (TypeSymbol sym) {
312 DataType type = null;
314 if (sym is ObjectTypeSymbol) {
315 type = new ObjectType ((ObjectTypeSymbol) sym);
316 } else if (sym is Struct) {
317 var st = (Struct) sym;
318 if (st.is_boolean_type ()) {
319 type = new BooleanType (st);
320 } else if (st.is_integer_type ()) {
321 type = new IntegerType (st);
322 } else if (st.is_floating_type ()) {
323 type = new FloatingType (st);
324 } else {
325 type = new StructValueType (st);
327 } else if (sym is Enum) {
328 type = new EnumValueType ((Enum) sym);
329 } else if (sym is ErrorDomain) {
330 type = new ErrorType ((ErrorDomain) sym, null);
331 } else if (sym is ErrorCode) {
332 type = new ErrorType ((ErrorDomain) sym.parent_symbol, (ErrorCode) sym);
333 } else {
334 Report.error (null, "internal error: `%s' is not a supported type".printf (sym.get_full_name ()));
335 return new InvalidType ();
338 return type;
341 public bool check_arguments (Expression expr, DataType mtype, List<FormalParameter> params, List<Expression> args) {
342 Expression prev_arg = null;
343 Iterator<Expression> arg_it = args.iterator ();
345 bool diag = (mtype is MethodType && ((MethodType) mtype).method_symbol.get_attribute ("Diagnostics") != null);
347 bool ellipsis = false;
348 int i = 0;
349 foreach (FormalParameter param in params) {
350 if (!param.check (this)) {
351 return false;
354 if (param.ellipsis) {
355 ellipsis = true;
356 break;
359 if (param.params_array) {
360 while (arg_it.next ()) {
361 var arg = arg_it.get ();
362 if (!check_argument (arg, i, param.direction)) {
363 expr.error = true;
364 return false;
367 i++;
370 break;
373 if (arg_it == null || !arg_it.next ()) {
374 if (param.default_expression == null) {
375 expr.error = true;
376 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
377 return false;
378 } else {
379 var invocation_expr = expr as MethodCall;
380 var object_creation_expr = expr as ObjectCreationExpression;
381 if (invocation_expr != null) {
382 invocation_expr.add_argument (param.default_expression);
383 } else if (object_creation_expr != null) {
384 object_creation_expr.add_argument (param.default_expression);
385 } else {
386 assert_not_reached ();
388 arg_it = null;
390 } else {
391 var arg = arg_it.get ();
392 if (!check_argument (arg, i, param.direction)) {
393 expr.error = true;
394 return false;
397 prev_arg = arg;
399 i++;
403 if (ellipsis) {
404 while (arg_it != null && arg_it.next ()) {
405 var arg = arg_it.get ();
406 if (arg.error) {
407 // ignore inner error
408 expr.error = true;
409 return false;
410 } else if (arg.value_type is SignalType) {
411 arg.error = true;
412 Report.error (arg.source_reference, "Cannot pass signals as arguments");
413 return false;
414 } else if (arg.value_type == null) {
415 // disallow untyped arguments except for type inference of callbacks
416 if (!(arg.symbol_reference is Method)) {
417 expr.error = true;
418 Report.error (expr.source_reference, "Invalid type for argument %d".printf (i + 1));
419 return false;
421 } else if (arg.target_type != null && !arg.value_type.compatible (arg.target_type)) {
422 // target_type known for printf arguments
423 expr.error = true;
424 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 ()));
425 return false;
428 i++;
430 } else if (!ellipsis && arg_it != null && arg_it.next ()) {
431 expr.error = true;
432 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (mtype.to_string (), args.size));
433 return false;
436 if (diag && prev_arg != null) {
437 var format_arg = prev_arg as StringLiteral;
438 if (format_arg != null) {
439 format_arg.value = "\"%s:%d: %s".printf (Path.get_basename (expr.source_reference.file.filename), expr.source_reference.first_line, format_arg.value.offset (1));
443 return true;
446 bool check_argument (Expression arg, int i, ParameterDirection direction) {
447 if (arg.error) {
448 // ignore inner error
449 return false;
450 } else if (arg is NamedArgument) {
451 Report.error (arg.source_reference, "Named arguments are not supported yet");
452 return false;
453 } else if (arg.value_type == null) {
454 // disallow untyped arguments except for type inference of callbacks
455 if (!(arg.target_type is DelegateType) || !(arg.symbol_reference is Method)) {
456 Report.error (arg.source_reference, "Invalid type for argument %d".printf (i + 1));
457 return false;
459 } else if (arg.target_type != null
460 && (direction == ParameterDirection.IN || direction == ParameterDirection.REF)
461 && !arg.value_type.compatible (arg.target_type)) {
462 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 ()));
463 return false;
464 } else if (arg.target_type != null
465 && (direction == ParameterDirection.REF || direction == ParameterDirection.OUT)
466 && !arg.target_type.compatible (arg.value_type)
467 && !(arg is NullLiteral)) {
468 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 ()));
469 return false;
470 } else {
471 // 0 => null, 1 => in, 2 => ref, 3 => out
472 int arg_type = 1;
473 if (arg.value_type is NullType) {
474 arg_type = 0;
475 } else if (arg is UnaryExpression) {
476 var unary = (UnaryExpression) arg;
477 if (unary.operator == UnaryOperator.REF) {
478 arg_type = 2;
479 } else if (unary.operator == UnaryOperator.OUT) {
480 arg_type = 3;
484 if (arg_type == 0) {
485 if (direction == ParameterDirection.REF) {
486 Report.error (arg.source_reference, "Argument %d: Cannot pass null to reference parameter".printf (i + 1));
487 return false;
488 } else if (direction != ParameterDirection.OUT && !arg.target_type.nullable) {
489 Report.warning (arg.source_reference, "Argument %d: Cannot pass null to non-null parameter type".printf (i + 1));
491 } else if (arg_type == 1) {
492 if (direction != ParameterDirection.IN) {
493 Report.error (arg.source_reference, "Argument %d: Cannot pass value to reference or output parameter".printf (i + 1));
494 return false;
496 } else if (arg_type == 2) {
497 if (direction != ParameterDirection.REF) {
498 Report.error (arg.source_reference, "Argument %d: Cannot pass ref argument to non-reference parameter".printf (i + 1));
499 return false;
502 // weak variables can only be used with weak ref parameters
503 if (arg.target_type.is_disposable ()) {
504 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
505 /* variable doesn't own the value */
506 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
507 return false;
510 } else if (arg_type == 3) {
511 if (direction != ParameterDirection.OUT) {
512 Report.error (arg.source_reference, "Argument %d: Cannot pass out argument to non-output parameter".printf (i + 1));
513 return false;
516 // weak variables can only be used with weak out parameters
517 if (arg.target_type.is_disposable ()) {
518 if (!(arg.value_type is PointerType) && !arg.value_type.value_owned) {
519 /* variable doesn't own the value */
520 Report.error (arg.source_reference, "Invalid assignment from owned expression to unowned variable");
521 return false;
526 return true;
529 private static DataType? get_instance_base_type (DataType instance_type, DataType base_type, CodeNode node_reference) {
530 // construct a new type reference for the base type with correctly linked type arguments
531 ReferenceType instance_base_type;
532 if (base_type.data_type is Class) {
533 instance_base_type = new ObjectType ((Class) base_type.data_type);
534 } else {
535 instance_base_type = new ObjectType ((Interface) base_type.data_type);
537 foreach (DataType type_arg in base_type.get_type_arguments ()) {
538 // resolve type argument specified in base type (possibly recursively for nested generic types)
539 type_arg = type_arg.get_actual_type (instance_type, null, node_reference);
540 instance_base_type.add_type_argument (type_arg);
542 return instance_base_type;
545 static DataType? get_instance_base_type_for_member (DataType derived_instance_type, TypeSymbol type_symbol, CodeNode node_reference) {
546 DataType instance_type = derived_instance_type;
548 while (instance_type is PointerType) {
549 var instance_pointer_type = (PointerType) instance_type;
550 instance_type = instance_pointer_type.base_type;
553 if (instance_type.data_type == type_symbol) {
554 return instance_type;
557 DataType instance_base_type = null;
559 // use same algorithm as symbol_lookup_inherited
560 if (instance_type.data_type is Class) {
561 var cl = (Class) instance_type.data_type;
562 // first check interfaces without prerequisites
563 // (prerequisites can be assumed to be met already)
564 foreach (DataType base_type in cl.get_base_types ()) {
565 if (base_type.data_type is Interface) {
566 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
567 if (instance_base_type != null) {
568 return instance_base_type;
572 // then check base class recursively
573 if (instance_base_type == null) {
574 foreach (DataType base_type in cl.get_base_types ()) {
575 if (base_type.data_type is Class) {
576 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, base_type, node_reference), type_symbol, node_reference);
577 if (instance_base_type != null) {
578 return instance_base_type;
583 } else if (instance_type.data_type is Struct) {
584 var st = (Struct) instance_type.data_type;
585 if (st.base_type != null) {
586 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, st.base_type, node_reference), type_symbol, node_reference);
587 if (instance_base_type != null) {
588 return instance_base_type;
591 } else if (instance_type.data_type is Interface) {
592 var iface = (Interface) instance_type.data_type;
593 // first check interface prerequisites recursively
594 foreach (DataType prerequisite in iface.get_prerequisites ()) {
595 if (prerequisite.data_type is Interface) {
596 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
597 if (instance_base_type != null) {
598 return instance_base_type;
602 if (instance_base_type == null) {
603 // then check class prerequisite recursively
604 foreach (DataType prerequisite in iface.get_prerequisites ()) {
605 if (prerequisite.data_type is Class) {
606 instance_base_type = get_instance_base_type_for_member (get_instance_base_type (instance_type, prerequisite, node_reference), type_symbol, node_reference);
607 if (instance_base_type != null) {
608 return instance_base_type;
615 return null;
618 public static DataType? get_actual_type (DataType? derived_instance_type, MemberAccess? method_access, GenericType generic_type, CodeNode node_reference) {
619 DataType actual_type = null;
620 if (generic_type.type_parameter.parent_symbol is TypeSymbol) {
621 if (derived_instance_type != null) {
622 // trace type arguments back to the datatype where the method has been declared
623 var instance_type = get_instance_base_type_for_member (derived_instance_type, (TypeSymbol) generic_type.type_parameter.parent_symbol, node_reference);
625 assert (instance_type != null);
627 int param_index = instance_type.data_type.get_type_parameter_index (generic_type.type_parameter.name);
628 if (param_index == -1) {
629 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
630 node_reference.error = true;
631 return null;
634 if (param_index < instance_type.get_type_arguments ().size) {
635 actual_type = (DataType) instance_type.get_type_arguments ().get (param_index);
638 } else {
639 // generic method
640 var m = (Method) generic_type.type_parameter.parent_symbol;
642 if (method_access == null) {
643 return generic_type;
646 int param_index = m.get_type_parameter_index (generic_type.type_parameter.name);
647 if (param_index == -1) {
648 Report.error (node_reference.source_reference, "internal error: unknown type parameter %s".printf (generic_type.type_parameter.name));
649 node_reference.error = true;
650 return null;
653 if (param_index < method_access.get_type_arguments ().size) {
654 actual_type = (DataType) method_access.get_type_arguments ().get (param_index);
658 if (actual_type == null) {
659 // no actual type available
660 return generic_type;
662 actual_type = actual_type.copy ();
663 actual_type.value_owned = actual_type.value_owned && generic_type.value_owned;
664 return actual_type;
667 public bool is_in_instance_method () {
668 var sym = current_symbol;
669 while (sym != null) {
670 if (sym is CreationMethod) {
671 return true;
672 } else if (sym is Method) {
673 var m = (Method) sym;
674 return m.binding == MemberBinding.INSTANCE;
675 } else if (sym is Constructor) {
676 var c = (Constructor) sym;
677 return c.binding == MemberBinding.INSTANCE;
678 } else if (sym is Destructor) {
679 return true;
680 } else if (sym is Property) {
681 var p = (Property) sym;
682 return p.binding == MemberBinding.INSTANCE;
684 sym = sym.parent_symbol;
687 return false;
690 public void visit_member_initializer (MemberInitializer init, DataType type) {
691 init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
692 if (!(init.symbol_reference is Field || init.symbol_reference is Property)) {
693 init.error = true;
694 Report.error (init.source_reference, "Invalid member `%s' in `%s'".printf (init.name, type.data_type.get_full_name ()));
695 return;
697 if (init.symbol_reference.access != SymbolAccessibility.PUBLIC) {
698 init.error = true;
699 Report.error (init.source_reference, "Access to private member `%s' denied".printf (init.symbol_reference.get_full_name ()));
700 return;
702 DataType member_type = null;
703 if (init.symbol_reference is Field) {
704 var f = (Field) init.symbol_reference;
705 member_type = f.field_type;
706 } else if (init.symbol_reference is Property) {
707 var prop = (Property) init.symbol_reference;
708 member_type = prop.property_type;
709 if (prop.set_accessor == null || !prop.set_accessor.writable) {
710 init.error = true;
711 Report.error (init.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
712 return;
716 init.initializer.target_type = member_type;
718 init.check (this);
720 if (init.initializer.value_type == null || !init.initializer.value_type.compatible (init.initializer.target_type)) {
721 init.error = true;
722 Report.error (init.source_reference, "Invalid type for member `%s'".printf (init.name));
723 return;
727 Struct? get_arithmetic_struct (DataType type) {
728 var result = type.data_type as Struct;
729 if (result == null && type is EnumValueType) {
730 return (Struct) int_type.data_type;
732 return result;
735 public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
736 var left = get_arithmetic_struct (left_type);
737 var right = get_arithmetic_struct (right_type);
739 if (left == null || right == null) {
740 // at least one operand not struct
741 return null;
744 if ((!left.is_floating_type () && !left.is_integer_type ()) ||
745 (!right.is_floating_type () && !right.is_integer_type ())) {
746 // at least one operand not numeric
747 return null;
750 if (left.is_floating_type () == right.is_floating_type ()) {
751 // both operands integer or floating type
752 if (left.get_rank () >= right.get_rank ()) {
753 return left_type;
754 } else {
755 return right_type;
757 } else {
758 // one integer and one floating type operand
759 if (left.is_floating_type ()) {
760 return left_type;
761 } else {
762 return right_type;
767 public Method? find_current_method () {
768 var sym = current_symbol;
769 while (sym != null) {
770 if (sym is Method) {
771 return (Method) sym;
773 sym = sym.parent_symbol;
775 return null;
778 public Method? find_parent_method (Symbol sym) {
779 while (sym is Block) {
780 sym = sym.parent_symbol;
782 return sym as Method;
785 public bool is_in_constructor () {
786 var sym = current_symbol;
787 while (sym != null) {
788 if (sym is Constructor) {
789 return true;
791 sym = sym.parent_symbol;
793 return false;