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