1 /* valasemanticanalyzer.vala
3 * Copyright (C) 2006-2007 Jürg Billeter, Raffaele Sandrini
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <rasa@gmx.ch>
27 * Code visitor analyzing and checking code.
29 public class Vala
.SemanticAnalyzer
: CodeVisitor
{
31 * Specifies whether automatic memory management is active.
33 public bool memory_management
{ get; set; }
36 Symbol current_symbol
;
37 SourceFile current_source_file
;
38 TypeReference current_return_type
;
40 Struct current_struct
;
42 List
<weak NamespaceReference
> current_using_directives
;
44 TypeReference bool_type
;
45 TypeReference string_type
;
46 TypeReference int_type
;
47 TypeReference uint_type
;
48 TypeReference ulong_type
;
49 TypeReference type_type
;
50 DataType pointer_type
;
51 DataType initially_unowned_type
;
55 private int next_lambda_id
= 0;
57 public SemanticAnalyzer (bool manage_memory
= true) {
58 memory_management
= manage_memory
;
62 * Analyze and check code in the specified context.
64 * @param context a code context
66 public void analyze (CodeContext
! context
) {
67 root_symbol
= context
.get_root ();
69 bool_type
= new
TypeReference ();
70 bool_type
.data_type
= (DataType
) root_symbol
.lookup ("bool").node
;
72 string_type
= new
TypeReference ();
73 string_type
.data_type
= (DataType
) root_symbol
.lookup ("string").node
;
75 pointer_type
= (DataType
) root_symbol
.lookup ("pointer").node
;
77 int_type
= new
TypeReference ();
78 int_type
.data_type
= (DataType
) root_symbol
.lookup ("int").node
;
80 uint_type
= new
TypeReference ();
81 uint_type
.data_type
= (DataType
) root_symbol
.lookup ("uint").node
;
83 ulong_type
= new
TypeReference ();
84 ulong_type
.data_type
= (DataType
) root_symbol
.lookup ("ulong").node
;
86 // TODO: don't require GLib namespace in semantic analyzer
87 var glib_ns
= root_symbol
.lookup ("GLib");
88 if (glib_ns
!= null) {
89 initially_unowned_type
= (DataType
) glib_ns
.lookup ("InitiallyUnowned").node
;
91 type_type
= new
TypeReference ();
92 type_type
.data_type
= (DataType
) glib_ns
.lookup ("Type").node
;
94 glist_type
= (DataType
) glib_ns
.lookup ("List").node
;
95 gslist_type
= (DataType
) glib_ns
.lookup ("SList").node
;
98 current_symbol
= root_symbol
;
99 context
.accept (this
);
102 public override void visit_source_file (SourceFile
! file
) {
103 current_source_file
= file
;
104 current_using_directives
= file
.get_using_directives ();
108 file
.accept_children (this
);
110 current_using_directives
= null;
113 public override void visit_namespace (Namespace
! ns
) {
114 current_symbol
= ns
.symbol
;
116 ns
.accept_children (this
);
118 current_symbol
= current_symbol
.parent_symbol
;
121 public override void visit_class (Class
! cl
) {
122 current_symbol
= cl
.symbol
;
125 if (cl
.base_class
!= null) {
126 current_source_file
.add_symbol_dependency (cl
.base_class
.symbol
, SourceFileDependencyType
.HEADER_FULL
);
129 foreach (TypeReference base_type_reference
in cl
.get_base_types ()) {
130 current_source_file
.add_symbol_dependency (base_type_reference
.data_type
.symbol
, SourceFileDependencyType
.HEADER_FULL
);
133 cl
.accept_children (this
);
135 /* gather all prerequisites */
136 List
<DataType
> prerequisites
= null;
137 foreach (TypeReference base_type
in cl
.get_base_types ()) {
138 if (base_type
.data_type is Interface
) {
139 prerequisites
.concat (get_all_prerequisites ((Interface
) base_type
.data_type
));
142 /* check whether all prerequisites are met */
143 List
<string> missing_prereqs
= null;
144 foreach (DataType prereq
in prerequisites
) {
145 if (!class_is_a (cl
, prereq
)) {
146 missing_prereqs
.prepend (prereq
.symbol
.get_full_name ());
149 /* report any missing prerequisites */
150 if (missing_prereqs
!= null) {
153 string error_string
= "%s: some prerequisites (".printf (cl
.symbol
.get_full_name ());
155 foreach (string s
in missing_prereqs
) {
157 error_string
= "%s`%s'".printf (error_string
, s
);
160 error_string
= "%s, `%s'".printf (error_string
, s
);
163 error_string
+= ") are not met";
164 Report
.error (cl
.source_reference
, error_string
);
167 /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
168 foreach (TypeReference base_type
in cl
.get_base_types ()) {
169 if (base_type
.data_type is Interface
) {
170 Interface iface
= (Interface
) base_type
.data_type
;
172 /* We do not need to do expensive equality checking here since this is done
173 * already. We only need to guarantee the symbols are present.
177 foreach (Method m
in iface
.get_methods ()) {
179 var sym
= cl
.symbol
.lookup (m
.name
);
180 if (sym
== null || !(sym
.node is Method
) || ((Method
) sym
.node
).base_interface_method
!= m
) {
182 Report
.error (cl
.source_reference
, "`%s' does not implement interface method `%s'".printf (cl
.symbol
.get_full_name (), m
.symbol
.get_full_name ()));
189 /* all abstract symbols defined in base classes have to be implemented in non-abstract classes
190 * VAPI classes don't have to specify overridden methods
192 if (!cl
.is_abstract
&& !cl
.source_reference
.file
.pkg
) {
193 var base_class
= cl
.base_class
;
194 while (base_class
!= null && base_class
.is_abstract
) {
195 foreach (Method m
in base_class
.get_methods ()) {
197 var sym
= cl
.symbol
.lookup (m
.name
);
198 if (sym
== null || !(sym
.node is Method
) || ((Method
) sym
.node
).base_method
!= m
) {
200 Report
.error (cl
.source_reference
, "`%s' does not implement abstract method `%s'".printf (cl
.symbol
.get_full_name (), m
.symbol
.get_full_name ()));
204 base_class
= base_class
.base_class
;
208 current_symbol
= current_symbol
.parent_symbol
;
209 current_class
= null;
212 private List
<DataType
> get_all_prerequisites (Interface
! iface
) {
213 List
<DataType
> ret
= null;
215 foreach (TypeReference prereq
in iface
.get_prerequisites ()) {
216 DataType type
= prereq
.data_type
;
217 /* skip on previous errors */
223 if (type is Interface
) {
224 ret
.concat (get_all_prerequisites ((Interface
) type
));
233 private bool class_is_a (Class
! cl
, DataType
! t
) {
238 foreach (TypeReference base_type
in cl
.get_base_types ()) {
239 if (base_type
.data_type is Class
) {
240 if (class_is_a ((Class
) base_type
.data_type
, t
)) {
243 } else if (base_type
.data_type
== t
) {
251 public override void visit_struct (Struct
! st
) {
252 current_symbol
= st
.symbol
;
255 st
.accept_children (this
);
257 current_symbol
= current_symbol
.parent_symbol
;
258 current_struct
= null;
261 public override void visit_interface (Interface
! iface
) {
262 current_symbol
= iface
.symbol
;
264 foreach (TypeReference prerequisite_reference
in iface
.get_prerequisites ()) {
265 current_source_file
.add_symbol_dependency (prerequisite_reference
.data_type
.symbol
, SourceFileDependencyType
.HEADER_FULL
);
268 iface
.accept_children (this
);
270 /* check prerequisites */
272 foreach (TypeReference prereq
in iface
.get_prerequisites ()) {
273 DataType class_or_interface
= prereq
.data_type
;
274 /* skip on previous errors */
275 if (class_or_interface
== null) {
279 /* interfaces are not allowed to have multiple instantiable prerequisites */
280 if (class_or_interface is Class
) {
281 if (prereq_class
!= null) {
283 Report
.error (iface
.source_reference
, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (iface
.symbol
.get_full_name (), class_or_interface
.symbol
.get_full_name (), prereq_class
.symbol
.get_full_name ()));
287 prereq_class
= (Class
)class_or_interface
;
291 current_symbol
= current_symbol
.parent_symbol
;
294 public override void visit_callback (Callback
! cb
) {
295 cb
.accept_children (this
);
298 public override void visit_constant (Constant
! c
) {
299 c
.accept_children (this
);
301 if (!current_source_file
.pkg
) {
302 if (c
.initializer
== null) {
304 Report
.error (c
.source_reference
, "A const field requires a initializer to be provided");
309 public override void visit_field (Field
! f
) {
310 f
.accept_children (this
);
312 if (f
.access
!= MemberAccessibility
.PRIVATE
) {
313 if (f
.type_reference
.data_type
!= null) {
314 /* is null if it references a type parameter */
315 current_source_file
.add_symbol_dependency (f
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.HEADER_SHALLOW
);
318 if (f
.type_reference
.data_type
!= null) {
319 /* is null if it references a type parameter */
320 current_source_file
.add_symbol_dependency (f
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
325 public override void visit_method (Method
! m
) {
326 current_symbol
= m
.symbol
;
327 current_return_type
= m
.return_type
;
329 var init_attr
= m
.get_attribute ("ModuleInit");
330 if (init_attr
!= null) {
331 m
.source_reference
.file
.context
.module_init_method
= m
;
334 if (m
.return_type
.data_type
!= null) {
335 /* is null if it is void or a reference to a type parameter */
336 current_source_file
.add_symbol_dependency (m
.return_type
.data_type
.symbol
, SourceFileDependencyType
.HEADER_SHALLOW
);
339 m
.accept_children (this
);
341 current_symbol
= current_symbol
.parent_symbol
;
342 current_return_type
= null;
344 if (current_symbol
.parent_symbol
!= null &&
345 current_symbol
.parent_symbol
.node is Method
) {
346 /* lambda expressions produce nested methods */
347 var up_method
= (Method
) current_symbol
.parent_symbol
.node
;
348 current_return_type
= up_method
.return_type
;
351 if (current_symbol
.node is Class
) {
352 if (!(m is CreationMethod
)) {
353 find_base_interface_method (m
, (Class
) current_symbol
.node
);
354 if (m
.is_virtual
|| m
.overrides
) {
355 find_base_class_method (m
, (Class
) current_symbol
.node
);
356 if (m
.base_method
== null) {
357 Report
.error (m
.source_reference
, "%s: no suitable method found to override".printf (m
.symbol
.get_full_name ()));
361 } else if (current_symbol
.node is Struct
) {
362 if (m
.is_abstract
|| m
.is_virtual
|| m
.overrides
) {
363 Report
.error (m
.source_reference
, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m
.symbol
.get_full_name ()));
369 private void find_base_class_method (Method
! m
, Class
! cl
) {
370 var sym
= cl
.symbol
.lookup (m
.name
);
371 if (sym
!= null && sym
.node is Method
) {
372 var base_method
= (Method
) sym
.node
;
373 if (base_method
.is_abstract
|| base_method
.is_virtual
) {
374 if (!m
.equals (base_method
)) {
376 Report
.error (m
.source_reference
, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m
.symbol
.get_full_name (), base_method
.symbol
.get_full_name ()));
380 m
.base_method
= base_method
;
385 if (cl
.base_class
!= null) {
386 find_base_class_method (m
, cl
.base_class
);
390 private void find_base_interface_method (Method
! m
, Class
! cl
) {
391 // FIXME report error if multiple possible base methods are found
392 foreach (TypeReference type
in cl
.get_base_types ()) {
393 if (type
.data_type is Interface
) {
394 var sym
= type
.data_type
.symbol
.lookup (m
.name
);
395 if (sym
!= null && sym
.node is Method
) {
396 var base_method
= (Method
) sym
.node
;
397 if (base_method
.is_abstract
) {
398 if (!m
.equals (base_method
)) {
400 Report
.error (m
.source_reference
, "Return type and/or parameters of overriding method `%s' do not match overridden method `%s'.".printf (m
.symbol
.get_full_name (), base_method
.symbol
.get_full_name ()));
404 m
.base_interface_method
= base_method
;
412 public override void visit_creation_method (CreationMethod
! m
) {
413 m
.return_type
= new
TypeReference ();
414 m
.return_type
.data_type
= (DataType
) current_symbol
.node
;
415 m
.return_type
.transfers_ownership
= true;
417 if (current_symbol
.node is Class
) {
418 // check for floating reference
419 var cl
= (Class
) current_symbol
.node
;
421 if (cl
== initially_unowned_type
) {
422 m
.return_type
.floating_reference
= true;
430 current_symbol
= m
.symbol
;
431 current_return_type
= m
.return_type
;
433 m
.accept_children (this
);
435 current_symbol
= current_symbol
.parent_symbol
;
436 current_return_type
= null;
438 if (current_symbol
.parent_symbol
!= null &&
439 current_symbol
.parent_symbol
.node is Method
) {
440 /* lambda expressions produce nested methods */
441 var up_method
= (Method
) current_symbol
.parent_symbol
.node
;
442 current_return_type
= up_method
.return_type
;
445 if (current_symbol
.node is Class
) {
446 if (!(m is CreationMethod
)) {
447 find_base_interface_method (m
, (Class
) current_symbol
.node
);
448 if (m
.is_virtual
|| m
.overrides
) {
449 find_base_class_method (m
, (Class
) current_symbol
.node
);
450 if (m
.base_method
== null) {
451 Report
.error (m
.source_reference
, "%s: no suitable method found to override".printf (m
.symbol
.get_full_name ()));
455 } else if (current_symbol
.node is Struct
) {
456 if (m
.is_abstract
|| m
.is_virtual
|| m
.overrides
) {
457 Report
.error (m
.source_reference
, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m
.symbol
.get_full_name ()));
462 if (m
.body
!= null && current_class
!= null) {
464 foreach (Statement stmt
in m
.body
.get_statements ()) {
465 int params
= stmt
.get_number_of_set_construction_parameters ();
468 Report
.error (stmt
.source_reference
, "class creation methods only allow property assignment statements");
473 m
.n_construction_params
= n_params
;
477 public override void visit_formal_parameter (FormalParameter
! p
) {
478 p
.accept_children (this
);
481 if (p
.type_reference
.data_type
!= null) {
482 /* is null if it references a type parameter */
483 current_source_file
.add_symbol_dependency (p
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.HEADER_SHALLOW
);
484 current_source_file
.add_symbol_dependency (p
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
488 /* special treatment for construct formal parameters used in creation methods */
489 if (p
.construct_parameter
) {
490 if (!(p
.symbol
.parent_symbol
.node is CreationMethod
)) {
492 Report
.error (p
.source_reference
, "construct parameters are only allowed in type creation methods");
496 var method_body
= ((CreationMethod
)p
.symbol
.parent_symbol
.node
).body
;
497 var left
= new MemberAccess
.simple (p
.name
);
498 var right
= new MemberAccess
.simple (p
.name
);
500 /* try to lookup the requested property */
501 var prop_sym
= symbol_lookup_inherited (current_class
.symbol
, p
.name
);
502 if (!(prop_sym
.node is Property
)) {
504 Report
.error (p
.source_reference
, "class `%s' does not contain a property named `%s'".printf (current_class
.symbol
.get_full_name (), p
.name
));
507 left
.symbol_reference
= prop_sym
;
509 right
.symbol_reference
= p
.symbol
;
511 method_body
.add_statement (new
ExpressionStatement (new
Assignment (left
, right
)));
515 private void find_base_class_property (Property
! prop
, Class
! cl
) {
516 var sym
= cl
.symbol
.lookup (prop
.name
);
517 if (sym
!= null && sym
.node is Property
) {
518 var base_property
= (Property
) sym
.node
;
519 if (base_property
.is_abstract
|| base_property
.is_virtual
) {
520 if (!prop
.equals (base_property
)) {
522 Report
.error (prop
.source_reference
, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop
.symbol
.get_full_name (), base_property
.symbol
.get_full_name ()));
526 prop
.base_property
= base_property
;
531 if (cl
.base_class
!= null) {
532 find_base_class_property (prop
, cl
.base_class
);
536 private void find_base_interface_property (Property
! prop
, Class
! cl
) {
537 // FIXME report error if multiple possible base properties are found
538 foreach (TypeReference type
in cl
.get_base_types ()) {
539 if (type
.data_type is Interface
) {
540 var sym
= type
.data_type
.symbol
.lookup (prop
.name
);
541 if (sym
!= null && sym
.node is Property
) {
542 var base_property
= (Property
) sym
.node
;
543 if (base_property
.is_abstract
) {
544 if (!prop
.equals (base_property
)) {
546 Report
.error (prop
.source_reference
, "Type and/or accessors of overriding property `%s' do not match overridden property `%s'.".printf (prop
.symbol
.get_full_name (), base_property
.symbol
.get_full_name ()));
550 prop
.base_interface_property
= base_property
;
558 public override void visit_property (Property
! prop
) {
559 prop
.accept_children (this
);
561 if (prop
.type_reference
.data_type
!= null) {
562 /* is null if it references a type parameter */
563 current_source_file
.add_symbol_dependency (prop
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.HEADER_SHALLOW
);
564 current_source_file
.add_symbol_dependency (prop
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
567 if (prop
.symbol
.parent_symbol
.node is Class
) {
568 var cl
= (Class
) prop
.symbol
.parent_symbol
.node
;
569 find_base_interface_property (prop
, cl
);
570 if (prop
.is_virtual
|| prop
.overrides
) {
571 find_base_class_property (prop
, cl
);
572 if (prop
.base_property
== null) {
574 Report
.error (prop
.source_reference
, "%s: no suitable property found to override".printf (prop
.symbol
.get_full_name ()));
580 public override void visit_property_accessor (PropertyAccessor
! acc
) {
581 var prop
= (Property
) acc
.symbol
.parent_symbol
.node
;
584 current_return_type
= prop
.type_reference
;
587 current_return_type
= new
TypeReference ();
590 acc
.accept_children (this
);
592 current_return_type
= null;
595 public override void visit_signal (Signal
! sig
) {
596 sig
.accept_children (this
);
599 public override void visit_constructor (Constructor
! c
) {
600 current_symbol
= c
.symbol
;
602 c
.accept_children (this
);
604 current_symbol
= current_symbol
.parent_symbol
;
607 public override void visit_destructor (Destructor
! d
) {
608 current_symbol
= d
.symbol
;
610 d
.accept_children (this
);
612 current_symbol
= current_symbol
.parent_symbol
;
615 public override void visit_named_argument (NamedArgument
! n
) {
618 public override void visit_begin_block (Block
! b
) {
619 current_symbol
= b
.symbol
;
622 public override void visit_end_block (Block
! b
) {
623 foreach (VariableDeclarator decl
in b
.get_local_variables ()) {
624 decl
.symbol
.active
= false;
627 current_symbol
= current_symbol
.parent_symbol
;
630 public override void visit_variable_declarator (VariableDeclarator
! decl
) {
631 if (decl
.type_reference
== null) {
634 if (decl
.initializer
== null) {
636 Report
.error (decl
.source_reference
, "var declaration not allowed without initializer");
639 if (decl
.initializer
.static_type
== null) {
641 Report
.error (decl
.source_reference
, "var declaration not allowed with non-typed initializer");
645 decl
.type_reference
= decl
.initializer
.static_type
.copy ();
646 decl
.type_reference
.takes_ownership
= (decl
.type_reference
.data_type
== null || decl
.type_reference
.data_type
.is_reference_type ());
647 decl
.type_reference
.transfers_ownership
= false;
650 if (decl
.initializer
!= null) {
651 if (decl
.initializer
.static_type
== null) {
652 if (!(decl
.initializer is MemberAccess
)) {
654 Report
.error (decl
.source_reference
, "expression type not allowed as initializer");
658 if (decl
.initializer
.symbol_reference
.node is Method
&&
659 decl
.type_reference
.data_type is Callback
) {
660 var m
= (Method
) decl
.initializer
.symbol_reference
.node
;
661 var cb
= (Callback
) decl
.type_reference
.data_type
;
663 /* check whether method matches callback type */
664 if (!cb
.matches_method (m
)) {
666 Report
.error (decl
.source_reference
, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m
.symbol
.get_full_name (), cb
.symbol
.get_full_name ()));
670 decl
.initializer
.static_type
= decl
.type_reference
;
673 Report
.error (decl
.source_reference
, "expression type not allowed as initializer");
678 if (memory_management
) {
679 if (decl
.initializer
.static_type
.transfers_ownership
) {
680 /* rhs transfers ownership of the expression */
681 if (!decl
.type_reference
.takes_ownership
) {
682 /* lhs doesn't own the value */
684 Report
.error (decl
.source_reference
, "Invalid assignment from owned expression to unowned variable");
691 if (decl
.type_reference
.data_type
!= null) {
692 current_source_file
.add_symbol_dependency (decl
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
695 decl
.symbol
= new
Symbol (decl
);
696 current_symbol
.add (decl
.name
, decl
.symbol
);
698 var block
= (Block
) current_symbol
.node
;
699 block
.add_local_variable (decl
);
701 decl
.symbol
.active
= true;
705 * Visit operation called for initializer lists
707 * @param list an initializer list
709 public override void visit_begin_initializer_list (InitializerList
! list
) {
710 if (list
.expected_type
!= null && list
.expected_type
.data_type is Array
) {
711 /* initializer is used as array initializer */
712 Array edt
= (Array
)list
.expected_type
.data_type
;
713 var inits
= list
.get_initializers ();
714 int rank
= ((Array
)list
.expected_type
.data_type
).rank
;
715 var child_type
= list
.expected_type
.copy ();
718 child_type
.data_type
= edt
.element_type
.get_array (rank
- 1);
720 child_type
.data_type
= edt
.element_type
;
723 foreach (Expression e
in inits
) {
724 e
.expected_type
= child_type
.copy ();
730 * Visit operation called for initializer lists
732 * @param list an initializer list
734 public override void visit_end_initializer_list (InitializerList
! list
) {
735 if (list
.expected_type
!= null && list
.expected_type
.data_type is Array
) {
736 Array edt
= (Array
)list
.expected_type
.data_type
;
737 var inits
= list
.get_initializers ();
739 var child_type
= list
.expected_type
.copy ();
743 child_type
.data_type
= edt
.element_type
.get_array (rank
- 1);
744 foreach (Expression e
in inits
) {
745 if (e
.static_type
== null) {
749 if (!(e is InitializerList
)) {
752 Report
.error (e
.source_reference
, "Initializer list expected");
755 if (!e
.static_type
.equals (child_type
)) {
758 Report
.error (e
.source_reference
, "Expected initializer list of type `%s' but got `%s'".printf (child_type
.data_type
.name
, e
.static_type
.data_type
.name
));
762 child_type
.data_type
= edt
.element_type
;
763 foreach (Expression e
in inits
) {
764 if (e
.static_type
== null) {
768 if (!is_type_compatible (e
.static_type
, child_type
)) {
771 Report
.error (e
.source_reference
, "Expected initializer of type `%s' but got `%s'".printf (child_type
.data_type
.name
, e
.static_type
.data_type
.name
));
777 /* everything seems to be correct */
778 list
.static_type
= list
.expected_type
;
783 public override void visit_expression_statement (ExpressionStatement
! stmt
) {
784 if (stmt
.expression
.static_type
!= null &&
785 stmt
.expression
.static_type
.transfers_ownership
) {
786 Report
.warning (stmt
.source_reference
, "Short-living reference");
791 public override void visit_if_statement (IfStatement
! stmt
) {
792 if (stmt
.condition
.error
) {
793 /* if there was an error in the condition, skip this check */
798 if (stmt
.condition
.static_type
.data_type
!= bool_type
.data_type
) {
800 Report
.error (stmt
.condition
.source_reference
, "Condition must be boolean");
805 public override void visit_while_statement (WhileStatement
! stmt
) {
806 if (stmt
.condition
.static_type
.data_type
!= bool_type
.data_type
) {
808 Report
.error (stmt
.condition
.source_reference
, "Condition must be boolean");
813 public override void visit_for_statement (ForStatement
! stmt
) {
814 if (stmt
.condition
.static_type
.data_type
!= bool_type
.data_type
) {
816 Report
.error (stmt
.condition
.source_reference
, "Condition must be boolean");
821 public override void visit_begin_foreach_statement (ForeachStatement
! stmt
) {
822 if (stmt
.type_reference
.data_type
!= null) {
823 current_source_file
.add_symbol_dependency (stmt
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
826 stmt
.variable_declarator
= new
VariableDeclarator (stmt
.variable_name
);
827 stmt
.variable_declarator
.type_reference
= stmt
.type_reference
;
829 stmt
.variable_declarator
.symbol
= new
Symbol (stmt
.variable_declarator
);
830 stmt
.body
.symbol
.add (stmt
.variable_name
, stmt
.variable_declarator
.symbol
);
833 public override void visit_end_foreach_statement (ForeachStatement
! stmt
) {
834 var collection_type
= stmt
.collection
.static_type
.data_type
;
835 if (!(collection_type is Array
|| collection_type
== glist_type
|| collection_type
== gslist_type
)) {
837 Report
.error (stmt
.source_reference
, "Collection not iterable");
842 public override void visit_end_return_statement (ReturnStatement
! stmt
) {
843 if (current_return_type
== null) {
845 Report
.error (stmt
.source_reference
, "Return not allowed in this context");
849 if (stmt
.return_expression
== null && current_return_type
.data_type
!= null) {
851 Report
.error (stmt
.source_reference
, "Return without value in non-void function");
855 if (stmt
.return_expression
!= null &&
856 current_return_type
.data_type
== null &&
857 current_return_type
.type_parameter
== null) {
858 Report
.error (stmt
.source_reference
, "Return with value in void function");
862 if (stmt
.return_expression
!= null &&
863 !is_type_compatible (stmt
.return_expression
.static_type
, current_return_type
)) {
864 Report
.error (stmt
.source_reference
, "Return: Cannot convert from `%s' to `%s'".printf (stmt
.return_expression
.static_type
.to_string (), current_return_type
.to_string ()));
868 if (stmt
.return_expression
!= null &&
869 stmt
.return_expression
.static_type
.transfers_ownership
&&
870 !current_return_type
.transfers_ownership
) {
872 Report
.error (stmt
.source_reference
, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
876 if (stmt
.return_expression
!= null &&
877 stmt
.return_expression
.symbol_reference
!= null &&
878 stmt
.return_expression
.symbol_reference
.node is VariableDeclarator
&&
879 stmt
.return_expression
.static_type
.takes_ownership
&&
880 !current_return_type
.transfers_ownership
) {
881 Report
.warning (stmt
.source_reference
, "Local variable with strong reference used as return value and method return type hasn't been declared to transfer ownership");
886 * Visit operation called for lock statements.
888 * @param stmt a lock statement
890 public override void visit_lock_statement (LockStatement
! stmt
) {
891 /* resource must be a member access and denote a Lockable */
892 if (!(stmt
.resource is MemberAccess
&& stmt
.resource
.symbol_reference
.node is Lockable
)) {
894 stmt
.resource
.error
= true;
895 Report
.error (stmt
.resource
.source_reference
, "Expression is either not a member access or does not denote a lockable member");
899 /* parent symbol must be the current class */
900 if (stmt
.resource
.symbol_reference
.parent_symbol
.node
!= current_class
) {
902 stmt
.resource
.error
= true;
903 Report
.error (stmt
.resource
.source_reference
, "Only members of the current class are lockable");
906 ((Lockable
)stmt
.resource
.symbol_reference
.node
).set_lock_used (true);
909 public override void visit_begin_array_creation_expression (ArrayCreationExpression
! expr
) {
910 if (expr
.initializer_list
!= null) {
911 expr
.initializer_list
.expected_type
= expr
.element_type
.copy ();
912 expr
.initializer_list
.expected_type
.data_type
= expr
.initializer_list
.expected_type
.data_type
.get_array (expr
.rank
);
913 // FIXME: add element type to type_argument
918 * Visit operations called for array creation expresions.
920 * @param expr an array creation expression
922 public override void visit_end_array_creation_expression (ArrayCreationExpression
! expr
) {
924 List
<weak Expression
> size
= expr
.get_sizes ();
926 /* check for errors in the size list */
928 foreach (Expression e
in size
) {
929 if (e
.static_type
== null) {
930 /* return on previous error */
932 } else if (!(e
.static_type
.data_type is Struct
) || !((Struct
) e
.static_type
.data_type
).is_integer_type ()) {
934 Report
.error (e
.source_reference
, "Expression of integer type expected");
943 /* check for wrong elements inside the initializer */
944 if (expr
.initializer_list
!= null && expr
.initializer_list
.static_type
== null) {
948 /* try to construct the type of the array */
949 if (expr
.element_type
== null) {
951 Report
.error (expr
.source_reference
, "Cannot determine the element type of the created array");
955 expr
.static_type
= expr
.element_type
.copy ();
956 if (expr
.element_type
.data_type
!= null) {
957 expr
.static_type
.data_type
= expr
.element_type
.data_type
.get_array (expr
.rank
);
959 expr
.static_type
.data_type
= expr
.element_type
.type_parameter
.get_array (expr
.rank
);
961 expr
.static_type
.transfers_ownership
= true;
962 expr
.static_type
.takes_ownership
= true;
964 expr
.static_type
.add_type_argument (expr
.element_type
);
967 public override void visit_boolean_literal (BooleanLiteral
! expr
) {
968 expr
.static_type
= bool_type
;
971 public override void visit_character_literal (CharacterLiteral
! expr
) {
972 expr
.static_type
= new
TypeReference ();
973 expr
.static_type
.data_type
= (DataType
) root_symbol
.lookup ("char").node
;
976 public override void visit_integer_literal (IntegerLiteral
! expr
) {
977 expr
.static_type
= new
TypeReference ();
978 expr
.static_type
.data_type
= (DataType
) root_symbol
.lookup (expr
.get_type_name ()).node
;
981 public override void visit_real_literal (RealLiteral
! expr
) {
982 expr
.static_type
= new
TypeReference ();
983 expr
.static_type
.data_type
= (DataType
) root_symbol
.lookup (expr
.get_type_name ()).node
;
986 public override void visit_string_literal (StringLiteral
! expr
) {
987 expr
.static_type
= string_type
.copy ();
988 expr
.static_type
.non_null
= true;
991 public override void visit_null_literal (NullLiteral
! expr
) {
992 /* empty TypeReference represents null */
994 expr
.static_type
= new
TypeReference ();
997 public override void visit_literal_expression (LiteralExpression
! expr
) {
998 expr
.static_type
= expr
.literal
.static_type
;
1001 private TypeReference
get_static_type_for_node (CodeNode
! node
) {
1002 if (node is Field
) {
1003 var f
= (Field
) node
;
1004 return f
.type_reference
;
1005 } else if (node is Constant
) {
1006 var c
= (Constant
) node
;
1007 return c
.type_reference
;
1008 } else if (node is Property
) {
1009 var prop
= (Property
) node
;
1010 var type
= prop
.type_reference
.copy ();
1011 type
.takes_ownership
= false;
1013 } else if (node is FormalParameter
) {
1014 var p
= (FormalParameter
) node
;
1015 return p
.type_reference
;
1016 } else if (node is TypeReference
) {
1017 return (TypeReference
) node
;
1018 } else if (node is VariableDeclarator
) {
1019 var decl
= (VariableDeclarator
) node
;
1020 return decl
.type_reference
;
1021 } else if (node is EnumValue
|| node is FlagsValue
) {
1022 var type
= new
TypeReference ();
1023 type
.data_type
= (DataType
) node
.symbol
.parent_symbol
.node
;
1029 public static Symbol
symbol_lookup_inherited (Symbol
! sym
, string! name
) {
1030 var result
= sym
.lookup (name
);
1031 if (result
!= null) {
1035 if (sym
.node is Class
) {
1036 var cl
= (Class
) sym
.node
;
1037 foreach (TypeReference base_type
in cl
.get_base_types ()) {
1038 result
= symbol_lookup_inherited (base_type
.data_type
.symbol
, name
);
1039 if (result
!= null) {
1043 } else if (sym
.node is Struct
) {
1044 var st
= (Struct
) sym
.node
;
1045 foreach (TypeReference base_type
in st
.get_base_types ()) {
1046 result
= symbol_lookup_inherited (base_type
.data_type
.symbol
, name
);
1047 if (result
!= null) {
1051 } else if (sym
.node is Interface
) {
1052 var iface
= (Interface
) sym
.node
;
1053 foreach (TypeReference prerequisite
in iface
.get_prerequisites ()) {
1054 result
= symbol_lookup_inherited (prerequisite
.data_type
.symbol
, name
);
1055 if (result
!= null) {
1064 public override void visit_parenthesized_expression (ParenthesizedExpression
! expr
) {
1065 expr
.static_type
= expr
.inner
.static_type
.copy ();
1066 // don't call g_object_ref_sink on inner and outer expression
1067 expr
.static_type
.floating_reference
= false;
1070 private DataType
find_parent_type (Symbol sym
) {
1071 while (sym
!= null) {
1072 if (sym
.node is DataType
) {
1073 return (DataType
) sym
.node
;
1075 sym
= sym
.parent_symbol
;
1080 public override void visit_member_access (MemberAccess
! expr
) {
1081 Symbol base_symbol
= null;
1083 if (expr
.inner
== null) {
1084 base_symbol
= current_symbol
;
1086 var sym
= current_symbol
;
1087 while (sym
!= null && expr
.symbol_reference
== null) {
1088 expr
.symbol_reference
= symbol_lookup_inherited (sym
, expr
.member_name
);
1089 sym
= sym
.parent_symbol
;
1092 if (expr
.symbol_reference
== null) {
1093 foreach (NamespaceReference ns
in current_using_directives
) {
1094 var local_sym
= ns
.namespace_symbol
.lookup (expr
.member_name
);
1095 if (local_sym
!= null) {
1096 if (expr
.symbol_reference
!= null) {
1098 Report
.error (expr
.source_reference
, "`%s' is an ambiguous reference between `%s' and `%s'".printf (expr
.member_name
, expr
.symbol_reference
.get_full_name (), local_sym
.get_full_name ()));
1101 expr
.symbol_reference
= local_sym
;
1106 if (expr
.inner
.error
) {
1107 /* if there was an error in the inner expression, skip this check */
1112 if (expr
.inner is MemberAccess
|| expr
.inner is BaseAccess
) {
1113 base_symbol
= expr
.inner
.symbol_reference
;
1114 if (base_symbol
.node is Namespace
||
1115 base_symbol
.node is DataType
) {
1116 expr
.symbol_reference
= base_symbol
.lookup (expr
.member_name
);
1120 if (expr
.symbol_reference
== null && expr
.inner
.static_type
!= null) {
1121 base_symbol
= expr
.inner
.static_type
.data_type
.symbol
;
1122 expr
.symbol_reference
= symbol_lookup_inherited (base_symbol
, expr
.member_name
);
1126 if (expr
.symbol_reference
== null) {
1128 Report
.error (expr
.source_reference
, "The name `%s' does not exist in the context of `%s'".printf (expr
.member_name
, base_symbol
.get_full_name ()));
1132 var member
= expr
.symbol_reference
.node
;
1133 MemberAccessibility access
= MemberAccessibility
.PUBLIC
;
1134 if (member is Field
) {
1135 access
= ((Field
) member
).access
;
1136 } else if (member is Method
) {
1137 access
= ((Method
) member
).access
;
1140 if (access
== MemberAccessibility
.PRIVATE
) {
1141 var target_type
= (DataType
) member
.symbol
.parent_symbol
.node
;
1142 var this_type
= find_parent_type (current_symbol
);
1144 if (target_type
!= this_type
) {
1146 Report
.error (expr
.source_reference
, "Access to private member `%s' denied".printf (member
.symbol
.get_full_name ()));
1151 current_source_file
.add_symbol_dependency (expr
.symbol_reference
, SourceFileDependencyType
.SOURCE
);
1153 expr
.static_type
= get_static_type_for_node (expr
.symbol_reference
.node
);
1156 private bool is_type_compatible (TypeReference
! expression_type
, TypeReference
! expected_type
) {
1157 /* only null is compatible to null */
1158 if (expected_type
.data_type
== null && expected_type
.type_parameter
== null) {
1159 return (expression_type
.data_type
== null && expected_type
.type_parameter
== null);
1162 if (expression_type
.data_type
== null) {
1163 /* null can be cast to any reference or array type or pointer type */
1164 if (expected_type
.type_parameter
!= null ||
1165 expected_type
.data_type
.is_reference_type () ||
1166 expected_type
.is_out
||
1167 expected_type
.data_type is Pointer
||
1168 expected_type
.data_type is Array
||
1169 expected_type
.data_type is Callback
||
1170 expected_type
.data_type
== pointer_type
) {
1174 /* null is not compatible with any other type (i.e. value types) */
1178 /* temporarily ignore type parameters */
1179 if (expected_type
.type_parameter
!= null) {
1183 if (expression_type
.data_type is Array
!= expected_type
.data_type is Array
) {
1187 if (expression_type
.data_type is Enum
&& expected_type
.data_type
== int_type
.data_type
) {
1191 if (expression_type
.data_type
== expected_type
.data_type
) {
1195 if (expression_type
.data_type is Struct
&& expected_type
.data_type is Struct
) {
1196 var expr_struct
= (Struct
) expression_type
.data_type
;
1197 var expect_struct
= (Struct
) expected_type
.data_type
;
1199 /* integer types may be implicitly cast to floating point types */
1200 if (expr_struct
.is_integer_type () && expect_struct
.is_floating_type ()) {
1204 if ((expr_struct
.is_integer_type () && expect_struct
.is_integer_type ()) ||
1205 (expr_struct
.is_floating_type () && expect_struct
.is_floating_type ())) {
1206 if (expr_struct
.get_rank () <= expect_struct
.get_rank ()) {
1212 return expression_type
.data_type
.is_subtype_of (expected_type
.data_type
);
1215 public override void visit_begin_invocation_expression (InvocationExpression
! expr
) {
1216 if (expr
.call
.error
) {
1217 /* if method resolving didn't succeed, skip this check */
1222 var msym
= expr
.call
.symbol_reference
;
1225 /* if no symbol found, skip this check */
1230 List
<weak FormalParameter
> params
;
1232 if (msym
.node is Invokable
) {
1233 var m
= (Invokable
) msym
.node
;
1234 if (m
.is_invokable ()) {
1235 params
= m
.get_parameters ();
1238 Report
.error (expr
.source_reference
, "invocation not supported in this context");
1243 Report
.error (expr
.source_reference
, "invocation not supported in this context");
1247 var args
= expr
.get_argument_list ();
1248 weak List
<weak Expression
> arg_it
= args
;
1249 foreach (FormalParameter param
in params
) {
1250 if (param
.ellipsis
) {
1254 if (arg_it
!= null) {
1255 var arg
= (Expression
) arg_it
.data
;
1257 /* store expected type for callback parameters */
1258 arg
.expected_type
= param
.type_reference
;
1260 arg_it
= arg_it
.next
;
1265 private bool check_arguments (Expression
! expr
, Symbol
! msym
, List
<FormalParameter
> params
, List
<Expression
> args
) {
1266 weak List
<weak Expression
> prev_arg_it
= null;
1267 weak List
<weak Expression
> arg_it
= args
;
1269 bool diag
= (msym
.node
.get_attribute ("Diagnostics") != null);
1271 bool ellipsis
= false;
1273 foreach (FormalParameter param
in params
) {
1274 if (param
.ellipsis
) {
1279 /* header file necessary if we need to cast argument */
1280 if (param
.type_reference
.data_type
!= null) {
1281 current_source_file
.add_symbol_dependency (param
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
1284 if (arg_it
== null) {
1285 if (param
.default_expression
== null) {
1287 Report
.error (expr
.source_reference
, "Too few arguments, method `%s' does not take %d arguments".printf (msym
.get_full_name (), args
.length ()));
1291 var arg
= (Expression
) arg_it
.data
;
1292 if (arg
.static_type
== null) {
1293 // disallow untyped arguments except for type inference of callbacks
1294 if (!(param
.type_reference
.data_type is Callback
)) {
1296 Report
.error (expr
.source_reference
, "Invalid type for argument %d".printf (i
+ 1));
1299 } else if (!is_type_compatible (arg
.static_type
, param
.type_reference
)) {
1301 Report
.error (expr
.source_reference
, "Argument %d: Cannot convert from `%s' to `%s'".printf (i
+ 1, arg
.static_type
.to_string (), param
.type_reference
.to_string ()));
1305 prev_arg_it
= arg_it
;
1306 arg_it
= arg_it
.next
;
1312 if (!ellipsis
&& arg_it
!= null) {
1314 Report
.error (expr
.source_reference
, "Too many arguments, method `%s' does not take %d arguments".printf (msym
.get_full_name (), args
.length ()));
1318 if (diag
&& prev_arg_it
!= null) {
1319 var format_arg
= (Expression
) prev_arg_it
.data
;
1320 if (format_arg is LiteralExpression
) {
1321 var format_lit
= (StringLiteral
) ((LiteralExpression
) format_arg
).literal
;
1322 format_lit
.value
= "\"%s:%d: %s".printf (expr
.source_reference
.file
.filename
, expr
.source_reference
.first_line
, format_lit
.value
.offset (1));
1329 public override void visit_end_invocation_expression (InvocationExpression
! expr
) {
1334 var msym
= expr
.call
.symbol_reference
;
1336 TypeReference ret_type
;
1337 List
<weak FormalParameter
> params
;
1339 if (msym
.node is Invokable
) {
1340 var m
= (Invokable
) msym
.node
;
1341 ret_type
= m
.get_return_type ();
1342 params
= m
.get_parameters ();
1344 if (ret_type
.data_type
== null && ret_type
.type_parameter
== null) {
1346 if (!(expr
.parent_node is ExpressionStatement
)) {
1348 Report
.error (expr
.source_reference
, "invocation of void method not allowed as expression");
1353 // resolve generic return values
1354 if (ret_type
.type_parameter
!= null) {
1355 if (!(expr
.call is MemberAccess
)) {
1356 Report
.error (((CodeNode
) m
).source_reference
, "internal error: unsupported generic return value");
1360 var ma
= (MemberAccess
) expr
.call
;
1361 if (ma
.inner
== null) {
1362 // TODO resolve generic return values within the type hierarchy if possible
1363 Report
.error (expr
.source_reference
, "internal error: resolving generic return values within type hierarchy not supported yet");
1367 TypeReference instance_type
= ma
.inner
.static_type
;
1368 // trace type arguments back to the datatype where the method has been declared
1369 while (instance_type
.data_type
!= msym
.parent_symbol
.node
) {
1370 List
<weak TypeReference
> base_types
= null;
1371 if (instance_type
.data_type is Class
) {
1372 var cl
= (Class
) instance_type
.data_type
;
1373 base_types
= cl
.get_base_types ();
1374 } else if (instance_type
.data_type is Interface
) {
1375 var iface
= (Interface
) instance_type
.data_type
;
1376 base_types
= iface
.get_prerequisites ();
1378 Report
.error (expr
.source_reference
, "internal error: unsupported generic type");
1382 foreach (TypeReference base_type
in base_types
) {
1383 if (symbol_lookup_inherited (base_type
.data_type
.symbol
, msym
.name
) != null) {
1384 // construct a new type reference for the base type with correctly linked type arguments
1385 var instance_base_type
= new
TypeReference ();
1386 instance_base_type
.data_type
= base_type
.data_type
;
1387 foreach (TypeReference type_arg
in base_type
.get_type_arguments ()) {
1388 if (type_arg
.type_parameter
!= null) {
1389 // link to type argument of derived type
1390 int param_index
= instance_type
.data_type
.get_type_parameter_index (type_arg
.type_parameter
.name
);
1391 if (param_index
== -1) {
1392 Report
.error (expr
.source_reference
, "internal error: unknown type parameter %s".printf (type_arg
.type_parameter
.name
));
1396 type_arg
= instance_type
.get_type_arguments ().nth_data (param_index
);
1398 instance_base_type
.add_type_argument (type_arg
);
1400 instance_type
= instance_base_type
;
1404 if (instance_type
.data_type
!= msym
.parent_symbol
.node
) {
1405 Report
.error (expr
.source_reference
, "internal error: generic type parameter tracing not supported yet");
1409 int param_index
= instance_type
.data_type
.get_type_parameter_index (ret_type
.type_parameter
.name
);
1410 if (param_index
== -1) {
1411 Report
.error (expr
.source_reference
, "internal error: unknown type parameter %s".printf (ret_type
.type_parameter
.name
));
1415 ret_type
= (TypeReference
) instance_type
.get_type_arguments ().nth_data (param_index
);
1416 if (ret_type
== null) {
1417 Report
.error (expr
.source_reference
, "internal error: no actual argument found for type parameter %s".printf (ret_type
.type_parameter
.name
));
1425 expr
.static_type
= ret_type
;
1427 check_arguments (expr
, msym
, params
, expr
.get_argument_list ());
1430 public override void visit_element_access (ElementAccess
! expr
) {
1431 if (expr
.container
.static_type
== null) {
1432 /* don't proceed if a child expression failed */
1437 /* assign a static_type when possible */
1438 if (expr
.container
.static_type
.data_type is Array
) {
1439 var args
= expr
.container
.static_type
.get_type_arguments ();
1441 if (args
.length () != 1) {
1443 Report
.error (expr
.source_reference
, "internal error: array reference with %d type arguments, expected 1".printf (args
.length ()));
1447 expr
.static_type
= (TypeReference
) args
.data
;
1450 Report
.error (expr
.source_reference
, "The expression `%s' does not denote an Array".printf (expr
.container
.static_type
.to_string ()));
1453 /* check if the index is of type integer */
1454 foreach (Expression e
in expr
.get_indices ()) {
1455 /* don't proceed if a child expression failed */
1456 if (e
.static_type
== null) {
1460 /* check if the index is of type integer */
1461 if (!(e
.static_type
.data_type is Struct
) || !((Struct
) e
.static_type
.data_type
).is_integer_type ()) {
1463 Report
.error (e
.source_reference
, "Expression of integer type expected");
1468 public override void visit_base_access (BaseAccess
! expr
) {
1469 if (current_class
== null) {
1470 if (current_struct
== null) {
1472 Report
.error (expr
.source_reference
, "Base access invalid outside of class and struct");
1474 } else if (current_struct
.get_base_types ().length () != 1) {
1476 Report
.error (expr
.source_reference
, "Base access invalid without base type %d".printf (current_struct
.get_base_types ().length ()));
1479 expr
.static_type
= current_struct
.get_base_types ().first ().data
;
1481 expr
.static_type
= new
TypeReference ();
1482 expr
.static_type
.data_type
= current_class
.base_class
;
1485 expr
.symbol_reference
= expr
.static_type
.data_type
.symbol
;
1488 public override void visit_postfix_expression (PostfixExpression
! expr
) {
1489 expr
.static_type
= expr
.inner
.static_type
;
1492 public override void visit_end_object_creation_expression (ObjectCreationExpression
! expr
) {
1493 DataType type
= null;
1495 if (expr
.type_reference
== null) {
1496 if (expr
.member_name
== null) {
1498 Report
.error (expr
.source_reference
, "Incomplete object creation expression");
1502 if (expr
.member_name
.symbol_reference
== null) {
1507 var constructor_node
= expr
.member_name
.symbol_reference
.node
;
1508 var type_node
= expr
.member_name
.symbol_reference
.node
;
1510 var type_args
= expr
.member_name
.get_type_arguments ();
1512 if (constructor_node is Method
) {
1513 type_node
= constructor_node
.symbol
.parent_symbol
.node
;
1515 var constructor
= (Method
) constructor_node
;
1516 if (!(constructor_node is CreationMethod
)) {
1518 Report
.error (expr
.source_reference
, "`%s' is not a creation method".printf (constructor
.symbol
.get_full_name ()));
1522 expr
.symbol_reference
= constructor
.symbol
;
1524 type_args
= ((MemberAccess
) expr
.member_name
.inner
).get_type_arguments ();
1527 if (type_node is Class
|| type_node is Struct
) {
1528 type
= (DataType
) type_node
;
1531 Report
.error (expr
.source_reference
, "`%s' is not a class or struct".printf (type
.symbol
.get_full_name ()));
1535 expr
.type_reference
= new
TypeReference ();
1536 expr
.type_reference
.data_type
= type
;
1537 foreach (TypeReference type_arg
in type_args
) {
1538 expr
.type_reference
.add_type_argument (type_arg
);
1541 type
= expr
.type_reference
.data_type
;
1544 if (!type
.is_reference_type ()) {
1546 Report
.error (expr
.source_reference
, "Can't create instance of value type `%s'".printf (expr
.type_reference
.to_string ()));
1550 current_source_file
.add_symbol_dependency (type
.symbol
, SourceFileDependencyType
.SOURCE
);
1552 expr
.static_type
= expr
.type_reference
.copy ();
1553 expr
.static_type
.transfers_ownership
= true;
1555 if (type is Class
) {
1556 var cl
= (Class
) type
;
1558 if (cl
.is_abstract
) {
1559 expr
.static_type
= null;
1561 Report
.error (expr
.source_reference
, "Can't create instance of abstract class `%s'".printf (cl
.symbol
.get_full_name ()));
1565 if (expr
.symbol_reference
== null && cl
.default_construction_method
!= null) {
1566 expr
.symbol_reference
= cl
.default_construction_method
.symbol
;
1569 while (cl
!= null) {
1570 if (cl
== initially_unowned_type
) {
1571 expr
.static_type
.floating_reference
= true;
1577 } else if (type is Struct
) {
1578 var st
= (Struct
) type
;
1580 if (expr
.symbol_reference
== null && st
.default_construction_method
!= null) {
1581 expr
.symbol_reference
= st
.default_construction_method
.symbol
;
1585 if (expr
.symbol_reference
== null && expr
.get_argument_list ().length () != 0) {
1586 expr
.static_type
= null;
1588 Report
.error (expr
.source_reference
, "No arguments allowed when constructing type `%s'".printf (type
.symbol
.get_full_name ()));
1592 if (expr
.symbol_reference
!= null) {
1593 var m
= (Method
) expr
.symbol_reference
.node
;
1594 check_arguments (expr
, m
.symbol
, m
.get_parameters (), expr
.get_argument_list ());
1598 public override void visit_sizeof_expression (SizeofExpression
! expr
) {
1599 expr
.static_type
= ulong_type
;
1602 public override void visit_typeof_expression (TypeofExpression
! expr
) {
1603 expr
.static_type
= type_type
;
1606 private bool is_numeric_type (TypeReference
! type
) {
1607 if (!(type
.data_type is Struct
)) {
1611 var st
= (Struct
) type
.data_type
;
1612 return st
.is_integer_type () || st
.is_floating_type ();
1615 private bool is_integer_type (TypeReference
! type
) {
1616 if (!(type
.data_type is Struct
)) {
1620 var st
= (Struct
) type
.data_type
;
1621 return st
.is_integer_type ();
1624 public override void visit_unary_expression (UnaryExpression
! expr
) {
1625 if (expr
.inner
.error
) {
1626 /* if there was an error in the inner expression, skip type check */
1631 if (expr
.operator
== UnaryOperator
.PLUS
|| expr
.operator
== UnaryOperator
.MINUS
) {
1632 // integer or floating point type
1633 if (!is_numeric_type (expr
.inner
.static_type
)) {
1635 Report
.error (expr
.source_reference
, "Operator not supported for `%s'".printf (expr
.inner
.static_type
.to_string ()));
1639 expr
.static_type
= expr
.inner
.static_type
;
1640 } else if (expr
.operator
== UnaryOperator
.LOGICAL_NEGATION
) {
1642 if (expr
.inner
.static_type
.data_type
!= bool_type
.data_type
) {
1644 Report
.error (expr
.source_reference
, "Operator not supported for `%s'".printf (expr
.inner
.static_type
.to_string ()));
1648 expr
.static_type
= expr
.inner
.static_type
;
1649 } else if (expr
.operator
== UnaryOperator
.BITWISE_COMPLEMENT
) {
1651 if (!is_integer_type (expr
.inner
.static_type
)) {
1653 Report
.error (expr
.source_reference
, "Operator not supported for `%s'".printf (expr
.inner
.static_type
.to_string ()));
1657 expr
.static_type
= expr
.inner
.static_type
;
1658 } else if (expr
.operator
== UnaryOperator
.INCREMENT
||
1659 expr
.operator
== UnaryOperator
.DECREMENT
) {
1661 if (!is_integer_type (expr
.inner
.static_type
)) {
1663 Report
.error (expr
.source_reference
, "Operator not supported for `%s'".printf (expr
.inner
.static_type
.to_string ()));
1667 var ma
= find_member_access (expr
.inner
);
1670 Report
.error (expr
.source_reference
, "Prefix operators not supported for this expression");
1674 var old_value
= new
MemberAccess (ma
.inner
, ma
.member_name
);
1675 var bin
= new
BinaryExpression (expr
.operator
== UnaryOperator
.INCREMENT ? BinaryOperator
.PLUS
: BinaryOperator
.MINUS
, old_value
, new
LiteralExpression (new
IntegerLiteral ("1")));
1677 var assignment
= new
Assignment (ma
, bin
);
1678 expr
.parent_node
.replace (expr
, assignment
);
1679 assignment
.accept (this
);
1681 } else if (expr
.operator
== UnaryOperator
.REF
) {
1684 expr
.static_type
= expr
.inner
.static_type
;
1685 } else if (expr
.operator
== UnaryOperator
.OUT
) {
1688 expr
.static_type
= expr
.inner
.static_type
;
1691 Report
.error (expr
.source_reference
, "internal error: unsupported unary operator");
1696 private MemberAccess
find_member_access (Expression
! expr
) {
1697 if (expr is ParenthesizedExpression
) {
1698 var pe
= (ParenthesizedExpression
) expr
;
1699 return find_member_access (pe
.inner
);
1702 if (expr is MemberAccess
) {
1703 return (MemberAccess
) expr
;
1709 public override void visit_cast_expression (CastExpression
! expr
) {
1710 if (expr
.type_reference
.data_type
== null && expr
.type_reference
.type_parameter
== null) {
1711 /* if type resolving didn't succeed, skip this check */
1715 // FIXME: check whether cast is allowed
1717 if (expr
.type_reference
.data_type
!= null) {
1718 current_source_file
.add_symbol_dependency (expr
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
1721 expr
.static_type
= expr
.type_reference
;
1724 public override void visit_pointer_indirection (PointerIndirection
! expr
) {
1725 if (expr
.inner
.error
) {
1728 if (expr
.inner
.static_type
== null) {
1730 Report
.error (expr
.source_reference
, "internal error: unknown type of inner expression");
1733 if (!(expr
.inner
.static_type
.data_type is Pointer
)) {
1735 Report
.error (expr
.source_reference
, "Pointer indirection not supported for this expression");
1739 var pointer
= (Pointer
) expr
.inner
.static_type
.data_type
;
1741 expr
.static_type
= new
TypeReference ();
1742 expr
.static_type
.data_type
= pointer
.referent_type
;
1743 expr
.static_type
.takes_ownership
= expr
.inner
.static_type
.takes_ownership
;
1746 public override void visit_addressof_expression (AddressofExpression
! expr
) {
1747 if (expr
.inner
.error
) {
1750 if (expr
.inner
.static_type
== null) {
1752 Report
.error (expr
.source_reference
, "internal error: unknown type of inner expression");
1755 if (expr
.inner
.static_type
.data_type
== null) {
1757 Report
.error (expr
.source_reference
, "Address-of operator not supported for this expression");
1761 expr
.static_type
= new
TypeReference ();
1762 expr
.static_type
.data_type
= expr
.inner
.static_type
.data_type
.get_pointer ();
1763 expr
.static_type
.takes_ownership
= expr
.inner
.static_type
.takes_ownership
;
1766 public override void visit_reference_transfer_expression (ReferenceTransferExpression
! expr
) {
1767 if (expr
.inner
.error
) {
1768 /* if there was an error in the inner expression, skip type check */
1773 if (!(expr
.inner is MemberAccess
|| expr
.inner is ElementAccess
)) {
1775 Report
.error (expr
.source_reference
, "Reference transfer not supported for this expression");
1779 if (!expr
.inner
.static_type
.takes_ownership
) {
1781 Report
.error (expr
.source_reference
, "No reference to be transferred");
1785 expr
.static_type
= expr
.inner
.static_type
.copy ();
1786 expr
.static_type
.transfers_ownership
= true;
1787 expr
.static_type
.takes_ownership
= false;
1790 private TypeReference
get_arithmetic_result_type (TypeReference
! left_type
, TypeReference
! right_type
) {
1791 if (!(left_type
.data_type is Struct
) || !(right_type
.data_type is Struct
)) {
1792 // at least one operand not struct
1796 var left
= (Struct
) left_type
.data_type
;
1797 var right
= (Struct
) right_type
.data_type
;
1799 if ((!left
.is_floating_type () && !left
.is_integer_type ()) ||
1800 (!right
.is_floating_type () && !right
.is_integer_type ())) {
1801 // at least one operand not numeric
1805 if (left
.is_floating_type () == right
.is_floating_type ()) {
1806 // both operands integer or floating type
1807 if (left
.get_rank () >= right
.get_rank ()) {
1813 // one integer and one floating type operand
1814 if (left
.is_floating_type ()) {
1822 public override void visit_binary_expression (BinaryExpression
! expr
) {
1823 if (expr
.left
.error
|| expr
.right
.error
) {
1824 /* if there were any errors in inner expressions, skip type check */
1829 if (expr
.left
.static_type
.data_type
== string_type
.data_type
1830 && expr
.operator
== BinaryOperator
.PLUS
) {
1831 if (expr
.right
.static_type
.data_type
!= string_type
.data_type
) {
1833 Report
.error (expr
.source_reference
, "Operands must be strings");
1837 /* string concatenation: convert to a.concat (b) */
1839 var concat_call
= new
InvocationExpression (new
MemberAccess (expr
.left
, "concat"));
1840 concat_call
.add_argument (expr
.right
);
1842 expr
.parent_node
.replace (expr
, concat_call
);
1844 concat_call
.accept (this
);
1845 } else if (expr
.operator
== BinaryOperator
.PLUS
1846 || expr
.operator
== BinaryOperator
.MINUS
1847 || expr
.operator
== BinaryOperator
.MUL
1848 || expr
.operator
== BinaryOperator
.DIV
) {
1849 expr
.static_type
= get_arithmetic_result_type (expr
.left
.static_type
, expr
.right
.static_type
);
1851 if (expr
.static_type
== null) {
1853 Report
.error (expr
.source_reference
, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr
.left
.static_type
.to_string (), expr
.right
.static_type
.to_string ()));
1856 } else if (expr
.operator
== BinaryOperator
.MOD
1857 || expr
.operator
== BinaryOperator
.SHIFT_LEFT
1858 || expr
.operator
== BinaryOperator
.SHIFT_RIGHT
1859 || expr
.operator
== BinaryOperator
.BITWISE_XOR
) {
1860 expr
.static_type
= get_arithmetic_result_type (expr
.left
.static_type
, expr
.right
.static_type
);
1862 if (expr
.static_type
== null) {
1864 Report
.error (expr
.source_reference
, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr
.left
.static_type
.to_string (), expr
.right
.static_type
.to_string ()));
1867 } else if (expr
.operator
== BinaryOperator
.LESS_THAN
1868 || expr
.operator
== BinaryOperator
.GREATER_THAN
1869 || expr
.operator
== BinaryOperator
.LESS_THAN_OR_EQUAL
1870 || expr
.operator
== BinaryOperator
.GREATER_THAN_OR_EQUAL
) {
1871 if (expr
.left
.static_type
.data_type
== string_type
.data_type
1872 && expr
.right
.static_type
.data_type
== string_type
.data_type
) {
1873 /* string comparison: convert to a.collate (b) OP 0 */
1875 var cmp_call
= new
InvocationExpression (new
MemberAccess (expr
.left
, "collate"));
1876 cmp_call
.add_argument (expr
.right
);
1877 expr
.left
= cmp_call
;
1879 expr
.right
= new
LiteralExpression (new
IntegerLiteral ("0"));
1881 expr
.left
.accept (this
);
1883 var resulting_type
= get_arithmetic_result_type (expr
.left
.static_type
, expr
.right
.static_type
);
1885 if (resulting_type
== null) {
1887 Report
.error (expr
.source_reference
, "Relational operation not supported for types `%s' and `%s'".printf (expr
.left
.static_type
.to_string (), expr
.right
.static_type
.to_string ()));
1892 expr
.static_type
= bool_type
;
1893 } else if (expr
.operator
== BinaryOperator
.EQUALITY
1894 || expr
.operator
== BinaryOperator
.INEQUALITY
) {
1895 /* relational operation */
1897 if (!is_type_compatible (expr
.right
.static_type
, expr
.left
.static_type
)
1898 && !is_type_compatible (expr
.left
.static_type
, expr
.right
.static_type
)) {
1899 Report
.error (expr
.source_reference
, "Equality operation: `%s' and `%s' are incompatible, comparison would always evaluate to false".printf (expr
.right
.static_type
.to_string (), expr
.left
.static_type
.to_string ()));
1904 if (expr
.left
.static_type
.data_type
== string_type
.data_type
1905 && expr
.right
.static_type
.data_type
== string_type
.data_type
) {
1906 /* string comparison: convert to a.collate (b) OP 0 */
1908 var cmp_call
= new
InvocationExpression (new
MemberAccess (expr
.left
, "collate"));
1909 cmp_call
.add_argument (expr
.right
);
1910 expr
.left
= cmp_call
;
1912 expr
.right
= new
LiteralExpression (new
IntegerLiteral ("0"));
1914 expr
.left
.accept (this
);
1917 expr
.static_type
= bool_type
;
1918 } else if (expr
.operator
== BinaryOperator
.BITWISE_AND
1919 || expr
.operator
== BinaryOperator
.BITWISE_OR
) {
1920 // integer type or flags type
1922 expr
.static_type
= expr
.left
.static_type
;
1923 } else if (expr
.operator
== BinaryOperator
.AND
1924 || expr
.operator
== BinaryOperator
.OR
) {
1925 if (expr
.left
.static_type
.data_type
!= bool_type
.data_type
|| expr
.right
.static_type
.data_type
!= bool_type
.data_type
) {
1927 Report
.error (expr
.source_reference
, "Operands must be boolean");
1930 expr
.static_type
= bool_type
;
1932 assert_not_reached ();
1936 public override void visit_type_check (TypeCheck
! expr
) {
1937 if (expr
.type_reference
.data_type
== null) {
1938 /* if type resolving didn't succeed, skip this check */
1943 current_source_file
.add_symbol_dependency (expr
.type_reference
.data_type
.symbol
, SourceFileDependencyType
.SOURCE
);
1945 expr
.static_type
= bool_type
;
1948 private TypeReference
compute_common_base_type (List
<TypeReference
> types
) {
1949 bool null_found
= false;
1950 bool class_or_iface_found
= false;
1951 bool type_param_found
= false;
1952 bool ref_struct_found
= false;
1953 bool val_struct_found
= false;
1954 bool enum_found
= false;
1955 bool callback_found
= false;
1956 TypeReference base_type
= null;
1957 TypeReference last_type
= null;
1958 foreach (TypeReference type
in types
) {
1961 base_type
= new
TypeReference ();
1962 base_type
.error
= true;
1965 if (type
.data_type
== null && type
.type_parameter
== null) {
1968 if (val_struct_found
|| enum_found
) {
1969 base_type
.error
= true;
1973 } else if (type
.data_type is Class
|| type
.data_type is Interface
) {
1974 if (!class_or_iface_found
) {
1975 class_or_iface_found
= true;
1976 if (type_param_found
|| ref_struct_found
|| val_struct_found
|| enum_found
|| callback_found
) {
1977 base_type
.error
= true;
1981 } else if (type
.type_parameter
!= null) {
1982 if (!type_param_found
) {
1983 type_param_found
= true;
1984 if (class_or_iface_found
|| ref_struct_found
|| val_struct_found
|| enum_found
|| callback_found
) {
1985 base_type
.error
= true;
1989 } else if (type
.data_type is Struct
) {
1990 var st
= (Struct
) type
.data_type
;
1991 if (st
.is_reference_type ()) {
1992 if (!ref_struct_found
) {
1993 ref_struct_found
= true;
1994 if (class_or_iface_found
|| type_param_found
|| val_struct_found
|| enum_found
|| callback_found
) {
1995 base_type
.error
= true;
2000 if (!val_struct_found
) {
2001 val_struct_found
= true;
2002 if (class_or_iface_found
|| type_param_found
|| ref_struct_found
|| enum_found
|| callback_found
) {
2003 base_type
.error
= true;
2008 } else if (type
.data_type is Enum
) {
2011 if (class_or_iface_found
|| type_param_found
|| ref_struct_found
|| val_struct_found
) {
2012 base_type
.error
= true;
2016 } else if (type
.data_type is Callback
) {
2017 if (!callback_found
) {
2018 callback_found
= true;
2019 if (class_or_iface_found
|| type_param_found
|| ref_struct_found
|| val_struct_found
|| enum_found
) {
2020 base_type
.error
= true;
2025 base_type
= new
TypeReference ();
2026 base_type
.error
= true;
2027 Report
.error (type
.source_reference
, "internal error: unsupported type `%s'".printf (type
.to_string ()));
2030 if (base_type
== null) {
2031 base_type
= new
TypeReference ();
2032 base_type
.data_type
= type
.data_type
;
2033 base_type
.type_parameter
= type
.type_parameter
;
2034 base_type
.non_null
= type
.non_null
;
2035 base_type
.is_null
= type
.is_null
;
2036 base_type
.transfers_ownership
= type
.transfers_ownership
;
2038 if (base_type
.data_type
!= type
.data_type
) {
2039 if (is_type_compatible (type
, base_type
)) {
2040 } else if (is_type_compatible (base_type
, type
)) {
2041 base_type
.data_type
= type
.data_type
;
2043 base_type
.error
= true;
2047 base_type
.non_null
= base_type
.non_null
&& type
.non_null
;
2048 base_type
.is_null
= base_type
.is_null
&& type
.is_null
;
2049 // if one subexpression transfers ownership, all subexpressions must transfer ownership
2050 // FIXME add ref calls to subexpressions that don't transfer ownership
2051 base_type
.transfers_ownership
= base_type
.transfers_ownership
|| type
.transfers_ownership
;
2054 if (base_type
!= null && base_type
.error
) {
2055 Report
.error (last_type
.source_reference
, "`%s' is incompatible with `%s'".printf (last_type
.to_string (), base_type
.to_string ()));
2060 public override void visit_conditional_expression (ConditionalExpression
! expr
) {
2061 if (expr
.condition
.static_type
.data_type
!= bool_type
.data_type
) {
2063 Report
.error (expr
.condition
.source_reference
, "Condition must be boolean");
2067 /* FIXME: support memory management */
2068 List
<TypeReference
> types
;
2069 types
.append (expr
.true_expression
.static_type
);
2070 types
.append (expr
.false_expression
.static_type
);
2071 expr
.static_type
= compute_common_base_type (types
);
2074 private string get_lambda_name () {
2075 var result
= "__lambda%d".printf (next_lambda_id
);
2082 private Method
find_current_method () {
2083 var sym
= current_symbol
;
2084 while (sym
!= null) {
2085 if (sym
.node is Method
) {
2086 return (Method
) sym
.node
;
2088 sym
= sym
.parent_symbol
;
2093 private bool is_in_constructor () {
2094 var sym
= current_symbol
;
2095 while (sym
!= null) {
2096 if (sym
.node is Constructor
) {
2099 sym
= sym
.parent_symbol
;
2104 public override void visit_begin_lambda_expression (LambdaExpression
! l
) {
2105 if (l
.expected_type
== null || !(l
.expected_type
.data_type is Callback
)) {
2107 Report
.error (l
.source_reference
, "lambda expression not allowed in this context");
2111 bool in_instance_method
= false;
2112 var current_method
= find_current_method ();
2113 if (current_method
!= null) {
2114 in_instance_method
= current_method
.instance
;
2116 in_instance_method
= is_in_constructor ();
2119 var cb
= (Callback
) l
.expected_type
.data_type
;
2120 l
.method
= new
Method (get_lambda_name (), cb
.return_type
);
2121 l
.method
.instance
= cb
.instance
&& in_instance_method
;
2122 l
.method
.symbol
= new
Symbol (l
.method
);
2123 l
.method
.symbol
.parent_symbol
= current_symbol
;
2125 var lambda_params
= l
.get_parameters ();
2126 weak List
<weak FormalParameter
> lambda_param_it
= lambda_params
;
2127 foreach (FormalParameter cb_param
in cb
.get_parameters ()) {
2128 if (lambda_param_it
== null) {
2129 /* lambda expressions are allowed to have less parameters */
2133 var lambda_param
= (string) lambda_param_it
.data
;
2135 var param
= new
FormalParameter (lambda_param
, cb_param
.type_reference
);
2136 param
.symbol
= new
Symbol (param
);
2137 l
.method
.symbol
.add (param
.name
, param
.symbol
);
2139 l
.method
.add_parameter (param
);
2141 lambda_param_it
= lambda_param_it
.next
;
2144 if (lambda_param_it
!= null) {
2145 /* lambda expressions may not expect more parameters */
2147 Report
.error (l
.source_reference
, "lambda expression: too many parameters");
2151 if (l
.expression_body
!= null) {
2152 var block
= new
Block ();
2153 block
.symbol
= new
Symbol (block
);
2154 block
.symbol
.parent_symbol
= l
.method
.symbol
;
2156 if (l
.method
.return_type
.data_type
!= null) {
2157 block
.add_statement (new
ReturnStatement (l
.expression_body
));
2159 block
.add_statement (new
ExpressionStatement (l
.expression_body
));
2162 l
.method
.body
= block
;
2164 l
.method
.body
= l
.statement_body
;
2165 l
.method
.body
.symbol
.parent_symbol
= l
.method
.symbol
;
2168 /* lambda expressions should be usable like MemberAccess of a method */
2169 l
.symbol_reference
= l
.method
.symbol
;
2172 public override void visit_begin_assignment (Assignment
! a
) {
2173 if (a
.left is MemberAccess
) {
2174 var ma
= (MemberAccess
) a
.left
;
2176 if (ma
.error
|| ma
.symbol_reference
== null) {
2178 /* if no symbol found, skip this check */
2182 if (ma
.symbol_reference
.node is Signal
) {
2183 var sig
= (Signal
) ma
.symbol_reference
.node
;
2185 a
.right
.expected_type
= new
TypeReference ();
2186 a
.right
.expected_type
.data_type
= sig
.get_callback ();
2188 } else if (a
.left is ElementAccess
) {
2190 } else if (a
.left is PointerIndirection
) {
2194 Report
.error (a
.source_reference
, "unsupported lvalue in assignment");
2198 public override void visit_end_assignment (Assignment
! a
) {
2199 if (a
.error
|| a
.left
.error
|| a
.right
.error
) {
2204 if (a
.operator
!= AssignmentOperator
.SIMPLE
&& a
.left is MemberAccess
) {
2205 // transform into simple assignment
2206 // FIXME: only do this if the backend doesn't support
2207 // the assignment natively
2209 var ma
= (MemberAccess
) a
.left
;
2211 if (!(ma
.symbol_reference
.node is Signal
)) {
2212 var old_value
= new
MemberAccess (ma
.inner
, ma
.member_name
);
2214 var bin
= new
BinaryExpression (BinaryOperator
.PLUS
, old_value
, new
ParenthesizedExpression (a
.right
, a
.right
.source_reference
));
2216 if (a
.operator
== AssignmentOperator
.BITWISE_OR
) {
2217 bin
.operator
= BinaryOperator
.BITWISE_OR
;
2218 } else if (a
.operator
== AssignmentOperator
.BITWISE_AND
) {
2219 bin
.operator
= BinaryOperator
.BITWISE_AND
;
2220 } else if (a
.operator
== AssignmentOperator
.BITWISE_XOR
) {
2221 bin
.operator
= BinaryOperator
.BITWISE_XOR
;
2222 } else if (a
.operator
== AssignmentOperator
.ADD
) {
2223 bin
.operator
= BinaryOperator
.PLUS
;
2224 } else if (a
.operator
== AssignmentOperator
.SUB
) {
2225 bin
.operator
= BinaryOperator
.MINUS
;
2226 } else if (a
.operator
== AssignmentOperator
.MUL
) {
2227 bin
.operator
= BinaryOperator
.MUL
;
2228 } else if (a
.operator
== AssignmentOperator
.DIV
) {
2229 bin
.operator
= BinaryOperator
.DIV
;
2230 } else if (a
.operator
== AssignmentOperator
.PERCENT
) {
2231 bin
.operator
= BinaryOperator
.MOD
;
2232 } else if (a
.operator
== AssignmentOperator
.SHIFT_LEFT
) {
2233 bin
.operator
= BinaryOperator
.SHIFT_LEFT
;
2234 } else if (a
.operator
== AssignmentOperator
.SHIFT_RIGHT
) {
2235 bin
.operator
= BinaryOperator
.SHIFT_RIGHT
;
2239 a
.right
.accept (this
);
2241 a
.operator
= AssignmentOperator
.SIMPLE
;
2245 if (a
.left is MemberAccess
) {
2246 var ma
= (MemberAccess
) a
.left
;
2248 if (ma
.symbol_reference
.node is Signal
) {
2249 var sig
= (Signal
) ma
.symbol_reference
.node
;
2251 if (a
.right
.symbol_reference
== null) {
2253 Report
.error (a
.right
.source_reference
, "unsupported expression for signal handler");
2257 var m
= (Method
) a
.right
.symbol_reference
.node
;
2259 if (m
.instance
&& m
.access
!= MemberAccessibility
.PRIVATE
) {
2260 /* TODO: generate wrapper function */
2263 Report
.error (a
.right
.source_reference
, "public instance methods not yet supported as signal handlers");
2268 /* instance signal handlers must have the self
2269 * parameter at the end
2270 * do not use G_CONNECT_SWAPPED as this would
2271 * rearrange the parameters for instance
2272 * methods and non-instance methods
2274 m
.instance_last
= true;
2276 } else if (ma
.symbol_reference
.node is Property
) {
2277 var prop
= (Property
) ma
.symbol_reference
.node
;
2279 if (prop
.set_accessor
== null) {
2281 Report
.error (ma
.source_reference
, "Property `%s' is read-only".printf (prop
.symbol
.get_full_name ()));
2284 } else if (ma
.symbol_reference
.node is VariableDeclarator
&& a
.right
.static_type
== null) {
2285 var decl
= (VariableDeclarator
) ma
.symbol_reference
.node
;
2287 var right_ma
= (MemberAccess
) a
.right
;
2288 if (right_ma
.symbol_reference
.node is Method
&&
2289 decl
.type_reference
.data_type is Callback
) {
2290 var m
= (Method
) right_ma
.symbol_reference
.node
;
2291 var cb
= (Callback
) decl
.type_reference
.data_type
;
2293 /* check whether method matches callback type */
2294 if (!cb
.matches_method (m
)) {
2296 Report
.error (a
.source_reference
, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m
.symbol
.get_full_name (), cb
.symbol
.get_full_name ()));
2300 a
.right
.static_type
= decl
.type_reference
;
2303 Report
.error (a
.source_reference
, "Assignment: Invalid callback assignment attempt");
2306 } else if (ma
.symbol_reference
.node is Field
&& a
.right
.static_type
== null) {
2307 var f
= (Field
) ma
.symbol_reference
.node
;
2309 var right_ma
= (MemberAccess
) a
.right
;
2310 if (right_ma
.symbol_reference
.node is Method
&&
2311 f
.type_reference
.data_type is Callback
) {
2312 var m
= (Method
) right_ma
.symbol_reference
.node
;
2313 var cb
= (Callback
) f
.type_reference
.data_type
;
2315 /* check whether method matches callback type */
2316 if (!cb
.matches_method (m
)) {
2318 Report
.error (a
.source_reference
, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m
.symbol
.get_full_name (), cb
.symbol
.get_full_name ()));
2322 a
.right
.static_type
= f
.type_reference
;
2325 Report
.error (a
.source_reference
, "Assignment: Invalid callback assignment attempt");
2328 } else if (a
.left
.static_type
!= null && a
.right
.static_type
!= null) {
2329 if (!is_type_compatible (a
.right
.static_type
, a
.left
.static_type
)) {
2330 /* if there was an error on either side,
2331 * i.e. a.{left|right}.static_type == null, skip type check */
2333 Report
.error (a
.source_reference
, "Assignment: Cannot convert from `%s' to `%s'".printf (a
.right
.static_type
.to_string (), a
.left
.static_type
.to_string ()));
2337 if (memory_management
) {
2338 if (a
.right
.static_type
.transfers_ownership
) {
2339 /* rhs transfers ownership of the expression */
2340 if (!a
.left
.static_type
.takes_ownership
) {
2341 /* lhs doesn't own the value */
2343 Report
.error (a
.source_reference
, "Invalid assignment from owned expression to unowned variable");
2345 } else if (a
.left
.static_type
.takes_ownership
) {
2346 /* lhs wants to own the value
2347 * rhs doesn't transfer the ownership
2348 * code generator needs to add reference
2349 * increment calls */
2353 } else if (a
.left is ElementAccess
) {
2354 var ea
= (ElementAccess
) a
.left
;
2356 if (!is_type_compatible (a
.right
.static_type
, a
.left
.static_type
)) {
2357 /* if there was an error on either side,
2358 * i.e. a.{left|right}.static_type == null, skip type check */
2360 Report
.error (a
.source_reference
, "Assignment: Cannot convert from `%s' to `%s'".printf (a
.right
.static_type
.to_string (), a
.left
.static_type
.to_string ()));
2364 if (memory_management
) {
2365 if (a
.right
.static_type
.transfers_ownership
) {
2366 /* rhs transfers ownership of the expression */
2368 var args
= ea
.container
.static_type
.get_type_arguments ();
2369 if (args
.length () != 1) {
2371 Report
.error (ea
.source_reference
, "internal error: array reference without type arguments");
2374 var element_type
= (TypeReference
) args
.data
;
2376 if (!element_type
.takes_ownership
) {
2377 /* lhs doesn't own the value */
2379 Report
.error (a
.source_reference
, "Invalid assignment from owned expression to unowned variable");
2382 } else if (a
.left
.static_type
.takes_ownership
) {
2383 /* lhs wants to own the value
2384 * rhs doesn't transfer the ownership
2385 * code generator needs to add reference
2386 * increment calls */
2393 a
.static_type
= a
.left
.static_type
;