remove obsolete ref modifier and callback keyword
[vala-lang.git] / vala / valasemanticanalyzer.vala
blob12375d712aa55857925432ab18e0457b8c591a1c
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
19 * Author:
20 * Jürg Billeter <j@bitron.ch>
21 * Raffaele Sandrini <rasa@gmx.ch>
24 using GLib;
26 /**
27 * Code visitor analyzing and checking code.
29 public class Vala.SemanticAnalyzer : CodeVisitor {
30 /**
31 * Specifies whether automatic memory management is active.
33 public bool memory_management { get; set; }
35 Symbol root_symbol;
36 Symbol current_symbol;
37 SourceFile current_source_file;
38 TypeReference current_return_type;
39 Class current_class;
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;
52 DataType glist_type;
53 DataType gslist_type;
55 private int next_lambda_id = 0;
57 public SemanticAnalyzer (bool manage_memory = true) {
58 memory_management = manage_memory;
61 /**
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 ();
106 next_lambda_id = 0;
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;
123 current_class = cl;
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) {
151 cl.error = true;
153 string error_string = "%s: some prerequisites (".printf (cl.symbol.get_full_name ());
154 bool first = true;
155 foreach (string s in missing_prereqs) {
156 if (first) {
157 error_string = "%s`%s'".printf (error_string, s);
158 first = false;
159 } else {
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.
176 /* check methods */
177 foreach (Method m in iface.get_methods ()) {
178 if (m.is_abstract) {
179 var sym = cl.symbol.lookup (m.name);
180 if (sym == null || !(sym.node is Method) || ((Method) sym.node).base_interface_method != m) {
181 cl.error = true;
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 ()) {
196 if (m.is_abstract) {
197 var sym = cl.symbol.lookup (m.name);
198 if (sym == null || !(sym.node is Method) || ((Method) sym.node).base_method != m) {
199 cl.error = true;
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 */
218 if (type == null) {
219 continue;
222 ret.prepend (type);
223 if (type is Interface) {
224 ret.concat (get_all_prerequisites ((Interface) type));
229 ret.reverse ();
230 return #ret;
233 private bool class_is_a (Class! cl, DataType! t) {
234 if (cl == t) {
235 return true;
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)) {
241 return true;
243 } else if (base_type.data_type == t) {
244 return true;
248 return false;
251 public override void visit_struct (Struct! st) {
252 current_symbol = st.symbol;
253 current_struct = st;
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 */
271 Class prereq_class;
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) {
276 iface.error = true;
277 continue;
279 /* interfaces are not allowed to have multiple instantiable prerequisites */
280 if (class_or_interface is Class) {
281 if (prereq_class != null) {
282 iface.error = true;
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 ()));
284 return;
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) {
303 c.error = true;
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);
317 } else {
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 ()));
364 return;
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)) {
375 m.error = true;
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 ()));
377 return;
380 m.base_method = base_method;
381 return;
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)) {
399 m.error = true;
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 ()));
401 return;
404 m.base_interface_method = base_method;
405 return;
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;
420 while (cl != null) {
421 if (cl == initially_unowned_type) {
422 m.return_type.floating_reference = true;
423 break;
426 cl = cl.base_class;
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 ()));
458 return;
462 if (m.body != null && current_class != null) {
463 int n_params = 0;
464 foreach (Statement stmt in m.body.get_statements ()) {
465 int params = stmt.get_number_of_set_construction_parameters ();
466 if (params == -1) {
467 m.error = true;
468 Report.error (stmt.source_reference, "class creation methods only allow property assignment statements");
469 return;
471 n_params += params;
473 m.n_construction_params = n_params;
477 public override void visit_formal_parameter (FormalParameter! p) {
478 p.accept_children (this);
480 if (!p.ellipsis) {
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)) {
491 p.error = true;
492 Report.error (p.source_reference, "construct parameters are only allowed in type creation methods");
493 return;
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)) {
503 p.error = true;
504 Report.error (p.source_reference, "class `%s' does not contain a property named `%s'".printf (current_class.symbol.get_full_name (), p.name));
505 return;
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)) {
521 prop.error = true;
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 ()));
523 return;
526 prop.base_property = base_property;
527 return;
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)) {
545 prop.error = true;
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 ()));
547 return;
550 prop.base_interface_property = base_property;
551 return;
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) {
573 prop.error = true;
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;
583 if (acc.readable) {
584 current_return_type = prop.type_reference;
585 } else {
586 // void
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) {
632 /* var type */
634 if (decl.initializer == null) {
635 decl.error = true;
636 Report.error (decl.source_reference, "var declaration not allowed without initializer");
637 return;
639 if (decl.initializer.static_type == null) {
640 decl.error = true;
641 Report.error (decl.source_reference, "var declaration not allowed with non-typed initializer");
642 return;
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)) {
653 decl.error = true;
654 Report.error (decl.source_reference, "expression type not allowed as initializer");
655 return;
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)) {
665 decl.error = true;
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 ()));
667 return;
670 decl.initializer.static_type = decl.type_reference;
671 } else {
672 decl.error = true;
673 Report.error (decl.source_reference, "expression type not allowed as initializer");
674 return;
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 */
683 decl.error = true;
684 Report.error (decl.source_reference, "Invalid assignment from owned expression to unowned variable");
685 return;
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 ();
717 if (rank > 1) {
718 child_type.data_type = edt.element_type.get_array (rank - 1);
719 } else {
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 ();
738 int rank = edt.rank;
739 var child_type = list.expected_type.copy ();
740 bool error = false;
742 if (rank > 1) {
743 child_type.data_type = edt.element_type.get_array (rank - 1);
744 foreach (Expression e in inits) {
745 if (e.static_type == null) {
746 error = true;
747 continue;
749 if (!(e is InitializerList)) {
750 error = true;
751 e.error = true;
752 Report.error (e.source_reference, "Initializer list expected");
753 continue;
755 if (!e.static_type.equals (child_type)) {
756 error = true;
757 e.error = true;
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));
761 } else {
762 child_type.data_type = edt.element_type;
763 foreach (Expression e in inits) {
764 if (e.static_type == null) {
765 error = true;
766 continue;
768 if (!is_type_compatible (e.static_type, child_type)) {
769 error = true;
770 e.error = true;
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));
776 if (!error) {
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");
787 return;
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 */
794 stmt.error = true;
795 return;
798 if (stmt.condition.static_type.data_type != bool_type.data_type) {
799 stmt.error = true;
800 Report.error (stmt.condition.source_reference, "Condition must be boolean");
801 return;
805 public override void visit_while_statement (WhileStatement! stmt) {
806 if (stmt.condition.static_type.data_type != bool_type.data_type) {
807 stmt.error = true;
808 Report.error (stmt.condition.source_reference, "Condition must be boolean");
809 return;
813 public override void visit_for_statement (ForStatement! stmt) {
814 if (stmt.condition.static_type.data_type != bool_type.data_type) {
815 stmt.error = true;
816 Report.error (stmt.condition.source_reference, "Condition must be boolean");
817 return;
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)) {
836 stmt.error = true;
837 Report.error (stmt.source_reference, "Collection not iterable");
838 return;
842 public override void visit_end_return_statement (ReturnStatement! stmt) {
843 if (current_return_type == null) {
844 stmt.error = true;
845 Report.error (stmt.source_reference, "Return not allowed in this context");
846 return;
849 if (stmt.return_expression == null && current_return_type.data_type != null) {
850 stmt.error = true;
851 Report.error (stmt.source_reference, "Return without value in non-void function");
852 return;
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");
859 return;
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 ()));
865 return;
868 if (stmt.return_expression != null &&
869 stmt.return_expression.static_type.transfers_ownership &&
870 !current_return_type.transfers_ownership) {
871 stmt.error = true;
872 Report.error (stmt.source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
873 return;
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)) {
893 stmt.error = true;
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");
896 return;
899 /* parent symbol must be the current class */
900 if (stmt.resource.symbol_reference.parent_symbol.node != current_class) {
901 stmt.error = true;
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) {
923 int i;
924 List<weak Expression> size = expr.get_sizes ();
926 /* check for errors in the size list */
927 if (size != null) {
928 foreach (Expression e in size) {
929 if (e.static_type == null) {
930 /* return on previous error */
931 return;
932 } else if (!(e.static_type.data_type is Struct) || !((Struct) e.static_type.data_type).is_integer_type ()) {
933 expr.error = true;
934 Report.error (e.source_reference, "Expression of integer type expected");
938 if (expr.error) {
939 return;
943 /* check for wrong elements inside the initializer */
944 if (expr.initializer_list != null && expr.initializer_list.static_type == null) {
945 return;
948 /* try to construct the type of the array */
949 if (expr.element_type == null) {
950 expr.error = true;
951 Report.error (expr.source_reference, "Cannot determine the element type of the created array");
952 return;
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);
958 } else {
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;
1012 return type;
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;
1024 return type;
1026 return null;
1029 public static Symbol symbol_lookup_inherited (Symbol! sym, string! name) {
1030 var result = sym.lookup (name);
1031 if (result != null) {
1032 return result;
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) {
1040 return result;
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) {
1048 return result;
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) {
1056 return result;
1061 return 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;
1077 return null;
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) {
1097 expr.error = true;
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 ()));
1099 return;
1101 expr.symbol_reference = local_sym;
1105 } else {
1106 if (expr.inner.error) {
1107 /* if there was an error in the inner expression, skip this check */
1108 expr.error = true;
1109 return;
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) {
1127 expr.error = true;
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 ()));
1129 return;
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) {
1145 expr.error = true;
1146 Report.error (expr.source_reference, "Access to private member `%s' denied".printf (member.symbol.get_full_name ()));
1147 return;
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) {
1171 return true;
1174 /* null is not compatible with any other type (i.e. value types) */
1175 return false;
1178 /* temporarily ignore type parameters */
1179 if (expected_type.type_parameter != null) {
1180 return true;
1183 if (expression_type.data_type is Array != expected_type.data_type is Array) {
1184 return false;
1187 if (expression_type.data_type is Enum && expected_type.data_type == int_type.data_type) {
1188 return true;
1191 if (expression_type.data_type == expected_type.data_type) {
1192 return true;
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 ()) {
1201 return true;
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 ()) {
1207 return true;
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 */
1218 expr.error = true;
1219 return;
1222 var msym = expr.call.symbol_reference;
1224 if (msym == null) {
1225 /* if no symbol found, skip this check */
1226 expr.error = true;
1227 return;
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 ();
1236 } else {
1237 expr.error = true;
1238 Report.error (expr.source_reference, "invocation not supported in this context");
1239 return;
1241 } else {
1242 expr.error = true;
1243 Report.error (expr.source_reference, "invocation not supported in this context");
1244 return;
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) {
1251 break;
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;
1272 int i = 0;
1273 foreach (FormalParameter param in params) {
1274 if (param.ellipsis) {
1275 ellipsis = true;
1276 break;
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) {
1286 expr.error = true;
1287 Report.error (expr.source_reference, "Too few arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ()));
1288 return false;
1290 } else {
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)) {
1295 expr.error = true;
1296 Report.error (expr.source_reference, "Invalid type for argument %d".printf (i + 1));
1297 return false;
1299 } else if (!is_type_compatible (arg.static_type, param.type_reference)) {
1300 expr.error = true;
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 ()));
1302 return false;
1305 prev_arg_it = arg_it;
1306 arg_it = arg_it.next;
1308 i++;
1312 if (!ellipsis && arg_it != null) {
1313 expr.error = true;
1314 Report.error (expr.source_reference, "Too many arguments, method `%s' does not take %d arguments".printf (msym.get_full_name (), args.length ()));
1315 return false;
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));
1326 return true;
1329 public override void visit_end_invocation_expression (InvocationExpression! expr) {
1330 if (expr.error) {
1331 return;
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) {
1345 // void return type
1346 if (!(expr.parent_node is ExpressionStatement)) {
1347 expr.error = true;
1348 Report.error (expr.source_reference, "invocation of void method not allowed as expression");
1349 return;
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");
1357 expr.error = true;
1358 return;
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");
1364 expr.error = true;
1365 return;
1366 } else {
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 ();
1377 } else {
1378 Report.error (expr.source_reference, "internal error: unsupported generic type");
1379 expr.error = true;
1380 return;
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));
1393 expr.error = true;
1394 return;
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");
1406 expr.error = true;
1407 return;
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));
1412 expr.error = true;
1413 return;
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));
1418 expr.error = true;
1419 return;
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 */
1433 expr.error = true;
1434 return;
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) {
1442 expr.error = true;
1443 Report.error (expr.source_reference, "internal error: array reference with %d type arguments, expected 1".printf (args.length ()));
1444 return;
1447 expr.static_type = (TypeReference) args.data;
1448 } else {
1449 expr.error = true;
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) {
1457 return;
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 ()) {
1462 expr.error = true;
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) {
1471 expr.error = true;
1472 Report.error (expr.source_reference, "Base access invalid outside of class and struct");
1473 return;
1474 } else if (current_struct.get_base_types ().length () != 1) {
1475 expr.error = true;
1476 Report.error (expr.source_reference, "Base access invalid without base type %d".printf (current_struct.get_base_types ().length ()));
1477 return;
1479 expr.static_type = current_struct.get_base_types ().first ().data;
1480 } else {
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) {
1497 expr.error = true;
1498 Report.error (expr.source_reference, "Incomplete object creation expression");
1499 return;
1502 if (expr.member_name.symbol_reference == null) {
1503 expr.error = true;
1504 return;
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)) {
1517 expr.error = true;
1518 Report.error (expr.source_reference, "`%s' is not a creation method".printf (constructor.symbol.get_full_name ()));
1519 return;
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;
1529 } else {
1530 expr.error = true;
1531 Report.error (expr.source_reference, "`%s' is not a class or struct".printf (type.symbol.get_full_name ()));
1532 return;
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);
1540 } else {
1541 type = expr.type_reference.data_type;
1544 if (!type.is_reference_type ()) {
1545 expr.error = true;
1546 Report.error (expr.source_reference, "Can't create instance of value type `%s'".printf (expr.type_reference.to_string ()));
1547 return;
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;
1560 expr.error = true;
1561 Report.error (expr.source_reference, "Can't create instance of abstract class `%s'".printf (cl.symbol.get_full_name ()));
1562 return;
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;
1572 break;
1575 cl = cl.base_class;
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;
1587 expr.error = true;
1588 Report.error (expr.source_reference, "No arguments allowed when constructing type `%s'".printf (type.symbol.get_full_name ()));
1589 return;
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)) {
1608 return false;
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)) {
1617 return false;
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 */
1627 expr.error = true;
1628 return;
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)) {
1634 expr.error = true;
1635 Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
1636 return;
1639 expr.static_type = expr.inner.static_type;
1640 } else if (expr.operator == UnaryOperator.LOGICAL_NEGATION) {
1641 // boolean type
1642 if (expr.inner.static_type.data_type != bool_type.data_type) {
1643 expr.error = true;
1644 Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
1645 return;
1648 expr.static_type = expr.inner.static_type;
1649 } else if (expr.operator == UnaryOperator.BITWISE_COMPLEMENT) {
1650 // integer type
1651 if (!is_integer_type (expr.inner.static_type)) {
1652 expr.error = true;
1653 Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
1654 return;
1657 expr.static_type = expr.inner.static_type;
1658 } else if (expr.operator == UnaryOperator.INCREMENT ||
1659 expr.operator == UnaryOperator.DECREMENT) {
1660 // integer type
1661 if (!is_integer_type (expr.inner.static_type)) {
1662 expr.error = true;
1663 Report.error (expr.source_reference, "Operator not supported for `%s'".printf (expr.inner.static_type.to_string ()));
1664 return;
1667 var ma = find_member_access (expr.inner);
1668 if (ma == null) {
1669 expr.error = true;
1670 Report.error (expr.source_reference, "Prefix operators not supported for this expression");
1671 return;
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);
1680 return;
1681 } else if (expr.operator == UnaryOperator.REF) {
1682 // value type
1684 expr.static_type = expr.inner.static_type;
1685 } else if (expr.operator == UnaryOperator.OUT) {
1686 // reference type
1688 expr.static_type = expr.inner.static_type;
1689 } else {
1690 expr.error = true;
1691 Report.error (expr.source_reference, "internal error: unsupported unary operator");
1692 return;
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;
1706 return null;
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 */
1712 return;
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) {
1726 return;
1728 if (expr.inner.static_type == null) {
1729 expr.error = true;
1730 Report.error (expr.source_reference, "internal error: unknown type of inner expression");
1731 return;
1733 if (!(expr.inner.static_type.data_type is Pointer)) {
1734 expr.error = true;
1735 Report.error (expr.source_reference, "Pointer indirection not supported for this expression");
1736 return;
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) {
1748 return;
1750 if (expr.inner.static_type == null) {
1751 expr.error = true;
1752 Report.error (expr.source_reference, "internal error: unknown type of inner expression");
1753 return;
1755 if (expr.inner.static_type.data_type == null) {
1756 expr.error = true;
1757 Report.error (expr.source_reference, "Address-of operator not supported for this expression");
1758 return;
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 */
1769 expr.error = true;
1770 return;
1773 if (!(expr.inner is MemberAccess || expr.inner is ElementAccess)) {
1774 expr.error = true;
1775 Report.error (expr.source_reference, "Reference transfer not supported for this expression");
1776 return;
1779 if (!expr.inner.static_type.takes_ownership) {
1780 expr.error = true;
1781 Report.error (expr.source_reference, "No reference to be transferred");
1782 return;
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
1793 return null;
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
1802 return null;
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 ()) {
1808 return left_type;
1809 } else {
1810 return right_type;
1812 } else {
1813 // one integer and one floating type operand
1814 if (left.is_floating_type ()) {
1815 return left_type;
1816 } else {
1817 return right_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 */
1825 expr.error = true;
1826 return;
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) {
1832 expr.error = true;
1833 Report.error (expr.source_reference, "Operands must be strings");
1834 return;
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) {
1852 expr.error = true;
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 ()));
1854 return;
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) {
1863 expr.error = true;
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 ()));
1865 return;
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);
1882 } else {
1883 var resulting_type = get_arithmetic_result_type (expr.left.static_type, expr.right.static_type);
1885 if (resulting_type == null) {
1886 expr.error = true;
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 ()));
1888 return;
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 ()));
1900 expr.error = true;
1901 return;
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) {
1926 expr.error = true;
1927 Report.error (expr.source_reference, "Operands must be boolean");
1930 expr.static_type = bool_type;
1931 } else {
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 */
1939 expr.error = true;
1940 return;
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) {
1959 last_type = type;
1960 if (type.error) {
1961 base_type = new TypeReference ();
1962 base_type.error = true;
1963 return base_type;
1965 if (type.data_type == null && type.type_parameter == null) {
1966 if (!null_found) {
1967 null_found = true;
1968 if (val_struct_found || enum_found) {
1969 base_type.error = true;
1970 break;
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;
1978 break;
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;
1986 break;
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;
1996 break;
1999 } else {
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;
2004 break;
2008 } else if (type.data_type is Enum) {
2009 if (!enum_found) {
2010 enum_found = true;
2011 if (class_or_iface_found || type_param_found || ref_struct_found || val_struct_found) {
2012 base_type.error = true;
2013 break;
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;
2021 break;
2024 } else {
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 ()));
2028 return base_type;
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;
2037 } else {
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;
2042 } else {
2043 base_type.error = true;
2044 break;
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 ()));
2057 return base_type;
2060 public override void visit_conditional_expression (ConditionalExpression! expr) {
2061 if (expr.condition.static_type.data_type != bool_type.data_type) {
2062 expr.error = true;
2063 Report.error (expr.condition.source_reference, "Condition must be boolean");
2064 return;
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);
2077 next_lambda_id++;
2079 return result;
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;
2090 return null;
2093 private bool is_in_constructor () {
2094 var sym = current_symbol;
2095 while (sym != null) {
2096 if (sym.node is Constructor) {
2097 return true;
2099 sym = sym.parent_symbol;
2101 return false;
2104 public override void visit_begin_lambda_expression (LambdaExpression! l) {
2105 if (l.expected_type == null || !(l.expected_type.data_type is Callback)) {
2106 l.error = true;
2107 Report.error (l.source_reference, "lambda expression not allowed in this context");
2108 return;
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;
2115 } else {
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 */
2130 break;
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 */
2146 l.error = true;
2147 Report.error (l.source_reference, "lambda expression: too many parameters");
2148 return;
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));
2158 } else {
2159 block.add_statement (new ExpressionStatement (l.expression_body));
2162 l.method.body = block;
2163 } else {
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) {
2177 a.error = true;
2178 /* if no symbol found, skip this check */
2179 return;
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) {
2189 // do nothing
2190 } else if (a.left is PointerIndirection) {
2191 // do nothing
2192 } else {
2193 a.error = true;
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) {
2200 a.error = true;
2201 return;
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;
2238 a.right = bin;
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) {
2252 a.error = true;
2253 Report.error (a.right.source_reference, "unsupported expression for signal handler");
2254 return;
2257 var m = (Method) a.right.symbol_reference.node;
2259 if (m.instance && m.access != MemberAccessibility.PRIVATE) {
2260 /* TODO: generate wrapper function */
2262 ma.error = true;
2263 Report.error (a.right.source_reference, "public instance methods not yet supported as signal handlers");
2264 return;
2267 if (m.instance) {
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) {
2280 ma.error = true;
2281 Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.symbol.get_full_name ()));
2282 return;
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)) {
2295 decl.error = true;
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 ()));
2297 return;
2300 a.right.static_type = decl.type_reference;
2301 } else {
2302 a.error = true;
2303 Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
2304 return;
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)) {
2317 f.error = true;
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 ()));
2319 return;
2322 a.right.static_type = f.type_reference;
2323 } else {
2324 a.error = true;
2325 Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
2326 return;
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 */
2332 a.error = true;
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 ()));
2334 return;
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 */
2342 a.error = true;
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 */
2359 a.error = true;
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 ()));
2361 return;
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) {
2370 a.error = true;
2371 Report.error (ea.source_reference, "internal error: array reference without type arguments");
2372 return;
2374 var element_type = (TypeReference) args.data;
2376 if (!element_type.takes_ownership) {
2377 /* lhs doesn't own the value */
2378 a.error = true;
2379 Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable");
2380 return;
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 */
2389 } else {
2390 return;
2393 a.static_type = a.left.static_type;