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