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