--- /dev/null
+Index: vala/valablock.vala
+===================================================================
+--- vala/valablock.vala (revision 1971)
++++ vala/valablock.vala (revision 2004)
+@@ -90,4 +90,29 @@
+ stmt.accept (visitor);
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ owner = analyzer.current_symbol.scope;
++ analyzer.current_symbol = this;
++
++ accept_children (analyzer);
++
++ foreach (LocalVariable local in get_local_variables ()) {
++ local.active = false;
++ }
++
++ foreach (Statement stmt in get_statements()) {
++ add_error_types (stmt.get_error_types ());
++ }
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++
++ return !error;
++ }
+ }
+Index: vala/valalocalvariable.vala
+===================================================================
+--- vala/valalocalvariable.vala (revision 1971)
++++ vala/valalocalvariable.vala (revision 2004)
+@@ -98,4 +98,96 @@
+ variable_type = new_type;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (initializer != null) {
++ initializer.target_type = variable_type;
++ }
++
++ accept_children (analyzer);
++
++ if (variable_type == null) {
++ /* var type */
++
++ if (initializer == null) {
++ error = true;
++ Report.error (source_reference, "var declaration not allowed without initializer");
++ return false;
++ }
++ if (initializer.value_type == null) {
++ error = true;
++ Report.error (source_reference, "var declaration not allowed with non-typed initializer");
++ return false;
++ }
++
++ variable_type = initializer.value_type.copy ();
++ variable_type.value_owned = true;
++ variable_type.floating_reference = false;
++
++ initializer.target_type = variable_type;
++ }
++
++ if (initializer != null) {
++ if (initializer.value_type == null) {
++ if (!(initializer is MemberAccess) && !(initializer is LambdaExpression)) {
++ error = true;
++ Report.error (source_reference, "expression type not allowed as initializer");
++ return false;
++ }
++
++ if (initializer.symbol_reference is Method &&
++ variable_type is DelegateType) {
++ var m = (Method) initializer.symbol_reference;
++ var dt = (DelegateType) variable_type;
++ var cb = dt.delegate_symbol;
++
++ /* check whether method matches callback type */
++ if (!cb.matches_method (m)) {
++ error = true;
++ Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
++ return false;
++ }
++
++ initializer.value_type = variable_type;
++ } else {
++ error = true;
++ Report.error (source_reference, "expression type not allowed as initializer");
++ return false;
++ }
++ }
++
++ if (!initializer.value_type.compatible (variable_type)) {
++ error = true;
++ Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (initializer.value_type.to_string (), variable_type.to_string ()));
++ return false;
++ }
++
++ if (initializer.value_type.is_disposable ()) {
++ /* rhs transfers ownership of the expression */
++ if (!(variable_type is PointerType) && !variable_type.value_owned) {
++ /* lhs doesn't own the value */
++ error = true;
++ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
++ return false;
++ }
++ }
++ }
++
++ analyzer.current_source_file.add_type_dependency (variable_type, SourceFileDependencyType.SOURCE);
++
++ analyzer.current_symbol.scope.add (name, this);
++
++ var block = (Block) analyzer.current_symbol;
++ block.add_local_variable (this);
++
++ active = true;
++
++ return !error;
++ }
+ }
+Index: vala/valainterface.vala
+===================================================================
+--- vala/valainterface.vala (revision 1971)
++++ vala/valainterface.vala (revision 2004)
+@@ -540,4 +540,61 @@
+
+ return null;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ var old_source_file = analyzer.current_source_file;
++ var old_symbol = analyzer.current_symbol;
++
++ if (source_reference != null) {
++ analyzer.current_source_file = source_reference.file;
++ }
++ analyzer.current_symbol = this;
++
++ foreach (DataType prerequisite_reference in get_prerequisites ()) {
++ // check whether prerequisite is at least as accessible as the interface
++ if (!analyzer.is_type_accessible (this, prerequisite_reference)) {
++ error = true;
++ Report.error (source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), get_full_name ()));
++ return false;
++ }
++
++ analyzer.current_source_file.add_type_dependency (prerequisite_reference, SourceFileDependencyType.HEADER_FULL);
++ }
++
++ /* check prerequisites */
++ Class prereq_class;
++ foreach (DataType prereq in get_prerequisites ()) {
++ TypeSymbol class_or_interface = prereq.data_type;
++ /* skip on previous errors */
++ if (class_or_interface == null) {
++ error = true;
++ continue;
++ }
++ /* interfaces are not allowed to have multiple instantiable prerequisites */
++ if (class_or_interface is Class) {
++ if (prereq_class != null) {
++ error = true;
++ Report.error (source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
++ return false;
++ }
++
++ prereq_class = (Class) class_or_interface;
++ }
++ }
++
++ accept_children (analyzer);
++
++ analyzer.current_source_file = old_source_file;
++ analyzer.current_symbol = old_symbol;
++
++ return !error;
++ }
+ }
+Index: vala/valamethod.vala
+===================================================================
+--- vala/valamethod.vala (revision 1971)
++++ vala/valamethod.vala (revision 2004)
+@@ -594,4 +594,152 @@
+ }
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ if (is_abstract) {
++ if (parent_symbol is Class) {
++ var cl = (Class) parent_symbol;
++ if (!cl.is_abstract) {
++ error = true;
++ Report.error (source_reference, "Abstract methods may not be declared in non-abstract classes");
++ return false;
++ }
++ } else if (!(parent_symbol is Interface)) {
++ error = true;
++ Report.error (source_reference, "Abstract methods may not be declared outside of classes and interfaces");
++ return false;
++ }
++ } else if (is_virtual) {
++ if (!(parent_symbol is Class) && !(parent_symbol is Interface)) {
++ error = true;
++ Report.error (source_reference, "Virtual methods may not be declared outside of classes and interfaces");
++ return false;
++ }
++
++ if (parent_symbol is Class) {
++ var cl = (Class) parent_symbol;
++ if (cl.is_compact) {
++ Report.error (source_reference, "Virtual methods may not be declared in compact classes");
++ return false;
++ }
++ }
++ } else if (overrides) {
++ if (!(parent_symbol is Class)) {
++ error = true;
++ Report.error (source_reference, "Methods may not be overridden outside of classes");
++ return false;
++ }
++ }
++
++ if (is_abstract && body != null) {
++ Report.error (source_reference, "Abstract methods cannot have bodies");
++ } else if (external && body != null) {
++ Report.error (source_reference, "Extern methods cannot have bodies");
++ } else if (!is_abstract && !external && !external_package && body == null) {
++ Report.error (source_reference, "Non-abstract, non-extern methods must have bodies");
++ }
++
++ var old_symbol = analyzer.current_symbol;
++ var old_return_type = analyzer.current_return_type;
++ analyzer.current_symbol = this;
++ analyzer.current_return_type = return_type;
++
++ var init_attr = get_attribute ("ModuleInit");
++ if (init_attr != null) {
++ source_reference.file.context.module_init_method = this;
++ }
++
++ if (!is_internal_symbol ()) {
++ if (return_type is ValueType) {
++ analyzer.current_source_file.add_type_dependency (return_type, SourceFileDependencyType.HEADER_FULL);
++ } else {
++ analyzer.current_source_file.add_type_dependency (return_type, SourceFileDependencyType.HEADER_SHALLOW);
++ }
++ }
++ analyzer.current_source_file.add_type_dependency (return_type, SourceFileDependencyType.SOURCE);
++
++ accept_children (analyzer);
++
++ analyzer.current_symbol = old_symbol;
++ analyzer.current_return_type = old_return_type;
++
++ if (analyzer.current_symbol.parent_symbol is Method) {
++ /* lambda expressions produce nested methods */
++ var up_method = (Method) analyzer.current_symbol.parent_symbol;
++ analyzer.current_return_type = up_method.return_type;
++ }
++
++ if (analyzer.current_symbol is Struct) {
++ if (is_abstract || is_virtual || overrides) {
++ Report.error (source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
++ return false;
++ }
++ } else if (overrides && base_method == null) {
++ Report.error (source_reference, "%s: no suitable method found to override".printf (get_full_name ()));
++ }
++
++ // check whether return type is at least as accessible as the method
++ if (!analyzer.is_type_accessible (this, return_type)) {
++ error = true;
++ Report.error (source_reference, "return type `%s` is less accessible than method `%s`".printf (return_type.to_string (), get_full_name ()));
++ return false;
++ }
++
++ foreach (Expression precondition in get_preconditions ()) {
++ if (precondition.error) {
++ // if there was an error in the precondition, skip this check
++ error = true;
++ return false;
++ }
++
++ if (!precondition.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (precondition.source_reference, "Precondition must be boolean");
++ return false;
++ }
++ }
++
++ foreach (Expression postcondition in get_postconditions ()) {
++ if (postcondition.error) {
++ // if there was an error in the postcondition, skip this check
++ error = true;
++ return false;
++ }
++
++ if (!postcondition.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (postcondition.source_reference, "Postcondition must be boolean");
++ return false;
++ }
++ }
++
++ if (tree_can_fail && name == "main") {
++ Report.error (source_reference, "\"main\" method cannot throw errors");
++ }
++
++ // check that all errors that can be thrown in the method body are declared
++ if (body != null) {
++ foreach (DataType body_error_type in body.get_error_types ()) {
++ bool can_propagate_error = false;
++ foreach (DataType method_error_type in get_error_types ()) {
++ if (body_error_type.compatible (method_error_type)) {
++ can_propagate_error = true;
++ }
++ }
++ if (!can_propagate_error) {
++ Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
++ }
++ }
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valafield.vala
+===================================================================
+--- vala/valafield.vala (revision 1971)
++++ vala/valafield.vala (revision 2004)
+@@ -195,4 +195,44 @@
+ }
+ attr.add_argument ("type", new StringLiteral ("\"%s\"".printf (ctype)));
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ if (initializer != null) {
++ initializer.target_type = field_type;
++ }
++
++ accept_children (analyzer);
++
++ if (binding == MemberBinding.INSTANCE && parent_symbol is Interface) {
++ error = true;
++ Report.error (source_reference, "Interfaces may not have instance fields");
++ return false;
++ }
++
++ if (!is_internal_symbol ()) {
++ if (field_type is ValueType) {
++ analyzer.current_source_file.add_type_dependency (field_type, SourceFileDependencyType.HEADER_FULL);
++ } else {
++ analyzer.current_source_file.add_type_dependency (field_type, SourceFileDependencyType.HEADER_SHALLOW);
++ }
++ } else {
++ if (parent_symbol is Namespace) {
++ error = true;
++ Report.error (source_reference, "Namespaces may not have private members");
++ return false;
++ }
++
++ analyzer.current_source_file.add_type_dependency (field_type, SourceFileDependencyType.SOURCE);
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valadostatement.vala
+===================================================================
+--- vala/valadostatement.vala (revision 1971)
++++ vala/valadostatement.vala (revision 2004)
+@@ -86,4 +86,31 @@
+ condition = new_node;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ if (condition.error) {
++ /* if there was an error in the condition, skip this check */
++ error = true;
++ return false;
++ }
++
++ if (!condition.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (condition.source_reference, "Condition must be boolean");
++ return false;
++ }
++
++ add_error_types (condition.get_error_types ());
++ add_error_types (body.get_error_types ());
++
++ return !error;
++ }
+ }
+Index: vala/valanamespace.vala
+===================================================================
+--- vala/valanamespace.vala (revision 1971)
++++ vala/valanamespace.vala (revision 2004)
+@@ -515,4 +515,16 @@
+ }
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ return !error;
++ }
+ }
+Index: vala/valawhilestatement.vala
+===================================================================
+--- vala/valawhilestatement.vala (revision 1971)
++++ vala/valawhilestatement.vala (revision 2004)
+@@ -86,4 +86,31 @@
+ condition = new_node;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ if (condition.error) {
++ /* if there was an error in the condition, skip this check */
++ error = true;
++ return false;
++ }
++
++ if (!condition.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (condition.source_reference, "Condition must be boolean");
++ return false;
++ }
++
++ add_error_types (condition.get_error_types ());
++ add_error_types (body.get_error_types ());
++
++ return !error;
++ }
+ }
+Index: vala/valaconstant.vala
+===================================================================
+--- vala/valaconstant.vala (revision 1971)
++++ vala/valaconstant.vala (revision 2004)
+@@ -150,4 +150,29 @@
+ }
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ type_reference.accept (analyzer);
++
++ if (!external_package) {
++ if (initializer == null) {
++ error = true;
++ Report.error (source_reference, "A const field requires a initializer to be provided");
++ } else {
++ initializer.target_type = type_reference;
++
++ initializer.accept (analyzer);
++ }
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valadynamicproperty.vala
+===================================================================
+--- vala/valadynamicproperty.vala (revision 1971)
++++ vala/valadynamicproperty.vala (revision 2004)
+@@ -40,4 +40,7 @@
+ return new ArrayList<string> ();
+ }
+
++ public override bool check (SemanticAnalyzer analyzer) {
++ return true;
++ }
+ }
+Index: vala/valaforeachstatement.vala
+===================================================================
+--- vala/valaforeachstatement.vala (revision 1971)
++++ vala/valaforeachstatement.vala (revision 2004)
+@@ -134,4 +134,119 @@
+ type_reference = new_type;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ // analyze collection expression first, used for type inference
++ collection.accept (analyzer);
++
++ if (collection.error) {
++ // ignore inner error
++ error = true;
++ return false;
++ } else if (collection.value_type == null) {
++ Report.error (collection.source_reference, "invalid collection expression");
++ error = true;
++ return false;
++ }
++
++ var collection_type = collection.value_type.copy ();
++ collection.target_type = collection_type.copy ();
++
++ DataType element_data_type = null;
++ bool element_owned = false;
++
++ if (collection_type.is_array ()) {
++ var array_type = (ArrayType) collection_type;
++ element_data_type = array_type.element_type;
++ } else if (collection_type.compatible (analyzer.glist_type) || collection_type.compatible (analyzer.gslist_type)) {
++ if (collection_type.get_type_arguments ().size > 0) {
++ element_data_type = (DataType) collection_type.get_type_arguments ().get (0);
++ }
++ } else if (analyzer.iterable_type != null && collection_type.compatible (analyzer.iterable_type)) {
++ element_owned = true;
++
++ if (analyzer.list_type == null || !collection_type.compatible (new ObjectType (analyzer.list_type))) {
++ // don't use iterator objects for lists for performance reasons
++ var foreach_iterator_type = new ObjectType (analyzer.iterator_type);
++ foreach_iterator_type.value_owned = true;
++ foreach_iterator_type.add_type_argument (type_reference);
++ iterator_variable = new LocalVariable (foreach_iterator_type, "%s_it".printf (variable_name));
++
++ add_local_variable (iterator_variable);
++ iterator_variable.active = true;
++ }
++
++ var it_method = (Method) analyzer.iterable_type.data_type.scope.lookup ("iterator");
++ if (it_method.return_type.get_type_arguments ().size > 0) {
++ var type_arg = it_method.return_type.get_type_arguments ().get (0);
++ if (type_arg.type_parameter != null) {
++ element_data_type = SemanticAnalyzer.get_actual_type (collection_type, it_method, type_arg, this);
++ } else {
++ element_data_type = type_arg;
++ }
++ }
++ } else {
++ error = true;
++ Report.error (source_reference, "Gee.List not iterable");
++ return false;
++ }
++
++ if (element_data_type == null) {
++ error = true;
++ Report.error (collection.source_reference, "missing type argument for collection");
++ return false;
++ }
++
++ // analyze element type
++ if (type_reference == null) {
++ // var type
++ type_reference = element_data_type.copy ();
++ } else if (!element_data_type.compatible (type_reference)) {
++ error = true;
++ Report.error (source_reference, "Foreach: Cannot convert from `%s' to `%s'".printf (element_data_type.to_string (), type_reference.to_string ()));
++ return false;
++ } else if (element_data_type.is_disposable () && element_owned && !type_reference.value_owned) {
++ error = true;
++ Report.error (source_reference, "Foreach: Invalid assignment from owned expression to unowned variable");
++ return false;
++ }
++
++ analyzer.current_source_file.add_type_dependency (type_reference, SourceFileDependencyType.SOURCE);
++
++ element_variable = new LocalVariable (type_reference, variable_name);
++
++ body.scope.add (variable_name, element_variable);
++
++ body.add_local_variable (element_variable);
++ element_variable.active = true;
++
++ // analyze body
++ owner = analyzer.current_symbol.scope;
++ analyzer.current_symbol = this;
++
++ body.accept (analyzer);
++
++ foreach (LocalVariable local in get_local_variables ()) {
++ local.active = false;
++ }
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++
++ collection_variable = new LocalVariable (collection_type, "%s_collection".printf (variable_name));
++
++ add_local_variable (collection_variable);
++ collection_variable.active = true;
++
++
++ add_error_types (collection.get_error_types ());
++ add_error_types (body.get_error_types ());
++
++ return !error;
++ }
+ }
+Index: vala/valadeclarationstatement.vala
+===================================================================
+--- vala/valadeclarationstatement.vala (revision 1971)
++++ vala/valadeclarationstatement.vala (revision 2004)
+@@ -48,4 +48,25 @@
+
+ visitor.visit_declaration_statement (this);
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ var local = declaration as LocalVariable;
++ if (local != null && local.initializer != null) {
++ foreach (DataType error_type in local.initializer.get_error_types ()) {
++ // ensure we can trace back which expression may throw errors of this type
++ var initializer_error_type = error_type.copy ();
++ initializer_error_type.source_reference = local.initializer.source_reference;
++
++ add_error_type (initializer_error_type);
++ }
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valaelementaccess.vala
+===================================================================
+--- vala/valaelementaccess.vala (revision 1971)
++++ vala/valaelementaccess.vala (revision 2004)
+@@ -85,4 +85,127 @@
+ }
+ return container.is_pure ();
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ container.accept (analyzer);
++
++ if (container.value_type == null) {
++ /* don't proceed if a child expression failed */
++ error = true;
++ return false;
++ }
++
++ var container_type = container.value_type.data_type;
++
++ if (container is MemberAccess && container.symbol_reference is Signal) {
++ // signal detail access
++ if (get_indices ().size != 1) {
++ error = true;
++ Report.error (source_reference, "Element access with more than one dimension is not supported for signals");
++ return false;
++ }
++ get_indices ().get (0).target_type = analyzer.string_type.copy ();
++ }
++
++ foreach (Expression index in get_indices ()) {
++ index.accept (analyzer);
++ }
++
++ bool index_int_type_check = true;
++
++ var pointer_type = container.value_type as PointerType;
++
++ /* assign a value_type when possible */
++ if (container.value_type is ArrayType) {
++ var array_type = (ArrayType) container.value_type;
++ value_type = array_type.element_type.copy ();
++ if (!lvalue) {
++ value_type.value_owned = false;
++ }
++ } else if (pointer_type != null && !pointer_type.base_type.is_reference_type_or_type_parameter ()) {
++ value_type = pointer_type.base_type.copy ();
++ } else if (container_type == analyzer.string_type.data_type) {
++ if (get_indices ().size != 1) {
++ error = true;
++ Report.error (source_reference, "Element access with more than one dimension is not supported for strings");
++ return false;
++ }
++
++ value_type = analyzer.unichar_type;
++ } else if (container_type != null && analyzer.list_type != null && analyzer.map_type != null &&
++ (container_type.is_subtype_of (analyzer.list_type) || container_type.is_subtype_of (analyzer.map_type))) {
++ Gee.List<Expression> indices = get_indices ();
++ if (indices.size != 1) {
++ error = true;
++ Report.error (source_reference, "Element access with more than one dimension is not supported for the specified type");
++ return false;
++ }
++ Iterator<Expression> indices_it = indices.iterator ();
++ indices_it.next ();
++ var index = indices_it.get ();
++ index_int_type_check = false;
++
++ // lookup symbol in interface instead of class as implemented interface methods are not in VAPI files
++ Symbol get_sym = null;
++ if (container_type.is_subtype_of (analyzer.list_type)) {
++ get_sym = analyzer.list_type.scope.lookup ("get");
++ } else if (container_type.is_subtype_of (analyzer.map_type)) {
++ get_sym = analyzer.map_type.scope.lookup ("get");
++ }
++ var get_method = (Method) get_sym;
++ Gee.List<FormalParameter> get_params = get_method.get_parameters ();
++ Iterator<FormalParameter> get_params_it = get_params.iterator ();
++ get_params_it.next ();
++ var get_param = get_params_it.get ();
++
++ var index_type = get_param.parameter_type;
++ if (index_type.type_parameter != null) {
++ index_type = analyzer.get_actual_type (container.value_type, get_method, get_param.parameter_type, this);
++ }
++
++ if (!index.value_type.compatible (index_type)) {
++ error = true;
++ Report.error (source_reference, "index expression: Cannot convert from `%s' to `%s'".printf (index.value_type.to_string (), index_type.to_string ()));
++ return false;
++ }
++
++ value_type = analyzer.get_actual_type (container.value_type, get_method, get_method.return_type, this).copy ();
++ if (lvalue) {
++ // get () returns owned value, set () accepts unowned value
++ value_type.value_owned = false;
++ }
++ } else if (container is MemberAccess && container.symbol_reference is Signal) {
++ index_int_type_check = false;
++
++ symbol_reference = container.symbol_reference;
++ value_type = container.value_type;
++ } else {
++ error = true;
++ Report.error (source_reference, "The expression `%s' does not denote an Array".printf (container.value_type.to_string ()));
++ }
++
++ if (index_int_type_check) {
++ /* check if the index is of type integer */
++ foreach (Expression e in get_indices ()) {
++ /* don't proceed if a child expression failed */
++ if (e.value_type == null) {
++ return false;
++ }
++
++ /* check if the index is of type integer */
++ if (!(e.value_type.data_type is Struct) || !((Struct) e.value_type.data_type).is_integer_type ()) {
++ error = true;
++ Report.error (e.source_reference, "Expression of integer type expected");
++ }
++ }
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valacatchclause.vala
+===================================================================
+--- vala/valacatchclause.vala (revision 1971)
++++ vala/valacatchclause.vala (revision 2004)
+@@ -1,4 +1,4 @@
+-/* valacatchclause.vala
++/* valacatchvala
+ *
+ * Copyright (C) 2007-2008 Jürg Billeter
+ *
+@@ -62,7 +62,7 @@
+ private DataType _data_type;
+
+ /**
+- * Creates a new catch clause.
++ * Creates a new catch
+ *
+ * @param type_reference error type
+ * @param variable_name error variable name
+@@ -94,4 +94,27 @@
+ error_type = new_type;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (error_type != null) {
++ analyzer.current_source_file.add_type_dependency (error_type, SourceFileDependencyType.SOURCE);
++
++ error_variable = new LocalVariable (error_type.copy (), variable_name);
++
++ body.scope.add (variable_name, error_variable);
++ body.add_local_variable (error_variable);
++ } else {
++ error_type = new ErrorType (null, null, source_reference);
++ }
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valainitializerlist.vala
+===================================================================
+--- vala/valainitializerlist.vala (revision 1971)
++++ vala/valainitializerlist.vala (revision 2004)
+@@ -1,4 +1,4 @@
+-/* valainitializerlist.vala
++/* valainitializervala
+ *
+ * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
+ *
+@@ -31,7 +31,7 @@
+ private Gee.List<Expression> initializers = new ArrayList<Expression> ();
+
+ /**
+- * Appends the specified expression to this initializer list.
++ * Appends the specified expression to this initializer
+ *
+ * @param expr an expression
+ */
+@@ -41,7 +41,7 @@
+ }
+
+ /**
+- * Returns a copy of the expression list.
++ * Returns a copy of the expression
+ *
+ * @return expression list
+ */
+@@ -50,14 +50,14 @@
+ }
+
+ /**
+- * Returns the initializer count in this initializer list.
++ * Returns the initializer count in this initializer
+ */
+ public int size {
+ get { return initializers.size; }
+ }
+
+ /**
+- * Creates a new initializer list.
++ * Creates a new initializer
+ *
+ * @param source_reference reference to source code
+ * @return newly created initializer list
+@@ -92,4 +92,80 @@
+ }
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (target_type == null) {
++ error = true;
++ Report.error (source_reference, "initializer list used for unknown type");
++ return false;
++ } else if (target_type is ArrayType) {
++ /* initializer is used as array initializer */
++ var array_type = (ArrayType) target_type;
++
++ foreach (Expression e in get_initializers ()) {
++ e.target_type = array_type.element_type.copy ();
++ }
++ } else if (target_type.data_type is Struct) {
++ /* initializer is used as struct initializer */
++ var st = (Struct) target_type.data_type;
++
++ var field_it = st.get_fields ().iterator ();
++ foreach (Expression e in get_initializers ()) {
++ Field field = null;
++ while (field == null) {
++ if (!field_it.next ()) {
++ error = true;
++ Report.error (e.source_reference, "too many expressions in initializer list for `%s'".printf (target_type.to_string ()));
++ return false;
++ }
++ field = field_it.get ();
++ if (field.binding != MemberBinding.INSTANCE) {
++ // we only initialize instance fields
++ field = null;
++ }
++ }
++
++ e.target_type = field.field_type.copy ();
++ if (!target_type.value_owned) {
++ e.target_type.value_owned = false;
++ }
++ }
++ } else {
++ error = true;
++ Report.error (source_reference, "initializer list used for `%s', which is neither array nor struct".printf (target_type.to_string ()));
++ return false;
++ }
++
++ accept_children (analyzer);
++
++ bool error = false;
++ foreach (Expression e in get_initializers ()) {
++ if (e.value_type == null) {
++ error = true;
++ continue;
++ }
++
++ var unary = e as UnaryExpression;
++ if (unary != null && (unary.operator == UnaryOperator.REF || unary.operator == UnaryOperator.OUT)) {
++ // TODO check type for ref and out expressions
++ } else if (!e.value_type.compatible (e.target_type)) {
++ error = true;
++ e.error = true;
++ Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.target_type.to_string (), e.value_type.to_string ()));
++ }
++ }
++
++ if (!error) {
++ /* everything seems to be correct */
++ value_type = target_type;
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valaproperty.vala
+===================================================================
+--- vala/valaproperty.vala (revision 1971)
++++ vala/valaproperty.vala (revision 2004)
+@@ -34,7 +34,9 @@
+ get { return _data_type; }
+ set {
+ _data_type = value;
+- _data_type.parent_node = this;
++ if (value != null) {
++ _data_type.parent_node = this;
++ }
+ }
+ }
+
+@@ -409,6 +411,8 @@
+
+ checked = true;
+
++ process_attributes ();
++
+ var old_source_file = analyzer.current_source_file;
+ var old_symbol = analyzer.current_symbol;
+
+Index: vala/valaerrorcode.vala
+===================================================================
+--- vala/valaerrorcode.vala (revision 1971)
++++ vala/valaerrorcode.vala (revision 2004)
+@@ -72,4 +72,16 @@
+ }
+ return cname;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valaformalparameter.vala
+===================================================================
+--- vala/valaformalparameter.vala (revision 1971)
++++ vala/valaformalparameter.vala (revision 2004)
+@@ -174,6 +174,8 @@
+
+ checked = true;
+
++ process_attributes ();
++
+ var old_source_file = analyzer.current_source_file;
+ var old_symbol = analyzer.current_symbol;
+
+Index: vala/valadeletestatement.vala
+===================================================================
+--- vala/valadeletestatement.vala (revision 1971)
++++ vala/valadeletestatement.vala (revision 2004)
+@@ -43,4 +43,26 @@
+ public override void accept_children (CodeVisitor visitor) {
+ expression.accept (visitor);
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ if (expression.error) {
++ // if there was an error in the inner expression, skip this check
++ return false;
++ }
++
++ if (!(expression.value_type is PointerType)) {
++ error = true;
++ Report.error (source_reference, "delete operator not supported for `%s'".printf (expression.value_type.to_string ()));
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valadestructor.vala
+===================================================================
+--- vala/valadestructor.vala (revision 1971)
++++ vala/valadestructor.vala (revision 2004)
+@@ -60,4 +60,21 @@
+ body.accept (visitor);
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ owner = analyzer.current_symbol.scope;
++ analyzer.current_symbol = this;
++
++ accept_children (analyzer);
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++
++ return !error;
++ }
+ }
+Index: vala/valaassignment.vala
+===================================================================
+--- vala/valaassignment.vala (revision 1971)
++++ vala/valaassignment.vala (revision 2004)
+@@ -1,6 +1,6 @@
+ /* valaassignment.vala
+ *
+- * Copyright (C) 2006-2007 Jürg Billeter
++ * Copyright (C) 2006-2008 Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+@@ -97,6 +97,289 @@
+ public override bool is_pure () {
+ return false;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ left.lvalue = true;
++
++ left.accept (analyzer);
++
++ if (left.error) {
++ // skip on error in inner expression
++ error = true;
++ return false;
++ }
++
++ if (left is MemberAccess) {
++ var ma = (MemberAccess) left;
++
++ if (!(ma.symbol_reference is Signal || ma.symbol_reference is DynamicProperty) && ma.value_type == null) {
++ error = true;
++ Report.error (source_reference, "unsupported lvalue in assignment");
++ return false;
++ }
++ if (ma.prototype_access) {
++ error = true;
++ Report.error (source_reference, "Access to instance member `%s' denied".printf (ma.symbol_reference.get_full_name ()));
++ return false;
++ }
++
++ if (ma.error || ma.symbol_reference == null) {
++ error = true;
++ /* if no symbol found, skip this check */
++ return false;
++ }
++
++ if (ma.symbol_reference is DynamicSignal) {
++ // target_type not available for dynamic signals
++ } else if (ma.symbol_reference is Signal) {
++ var sig = (Signal) ma.symbol_reference;
++ right.target_type = new DelegateType (sig.get_delegate (ma.inner.value_type));
++ } else {
++ right.target_type = ma.value_type;
++ }
++ } else if (left is ElementAccess) {
++ var ea = (ElementAccess) left;
++
++ if (ea.container is MemberAccess && ea.container.symbol_reference is Signal) {
++ var ma = (MemberAccess) ea.container;
++ var sig = (Signal) ea.container.symbol_reference;
++ right.target_type = new DelegateType (sig.get_delegate (ma.inner.value_type));
++ } else {
++ right.target_type = left.value_type;
++ }
++ } else if (left is PointerIndirection) {
++ right.target_type = left.value_type;
++ } else {
++ error = true;
++ Report.error (source_reference, "unsupported lvalue in assignment");
++ return false;
++ }
++
++ right.accept (analyzer);
++
++ if (right.error) {
++ // skip on error in inner expression
++ error = true;
++ return false;
++ }
++
++ if (operator != AssignmentOperator.SIMPLE && left is MemberAccess) {
++ // transform into simple assignment
++ // FIXME: only do this if the backend doesn't support
++ // the assignment natively
++
++ var ma = (MemberAccess) left;
++
++ if (!(ma.symbol_reference is Signal)) {
++ var old_value = new MemberAccess (ma.inner, ma.member_name);
++
++ var bin = new BinaryExpression (BinaryOperator.PLUS, old_value, new ParenthesizedExpression (right, right.source_reference));
++ bin.target_type = right.target_type;
++ right.target_type = right.target_type.copy ();
++ right.target_type.value_owned = false;
++
++ if (operator == AssignmentOperator.BITWISE_OR) {
++ bin.operator = BinaryOperator.BITWISE_OR;
++ } else if (operator == AssignmentOperator.BITWISE_AND) {
++ bin.operator = BinaryOperator.BITWISE_AND;
++ } else if (operator == AssignmentOperator.BITWISE_XOR) {
++ bin.operator = BinaryOperator.BITWISE_XOR;
++ } else if (operator == AssignmentOperator.ADD) {
++ bin.operator = BinaryOperator.PLUS;
++ } else if (operator == AssignmentOperator.SUB) {
++ bin.operator = BinaryOperator.MINUS;
++ } else if (operator == AssignmentOperator.MUL) {
++ bin.operator = BinaryOperator.MUL;
++ } else if (operator == AssignmentOperator.DIV) {
++ bin.operator = BinaryOperator.DIV;
++ } else if (operator == AssignmentOperator.PERCENT) {
++ bin.operator = BinaryOperator.MOD;
++ } else if (operator == AssignmentOperator.SHIFT_LEFT) {
++ bin.operator = BinaryOperator.SHIFT_LEFT;
++ } else if (operator == AssignmentOperator.SHIFT_RIGHT) {
++ bin.operator = BinaryOperator.SHIFT_RIGHT;
++ }
++
++ right = bin;
++ right.accept (analyzer);
++
++ operator = AssignmentOperator.SIMPLE;
++ }
++ }
++
++ if (left.symbol_reference is Signal) {
++ var sig = (Signal) left.symbol_reference;
++
++ var m = right.symbol_reference as Method;
++
++ if (m == null) {
++ error = true;
++ Report.error (right.source_reference, "unsupported expression for signal handler");
++ return false;
++ }
++
++ var dynamic_sig = sig as DynamicSignal;
++ if (dynamic_sig != null) {
++ bool first = true;
++ foreach (FormalParameter param in dynamic_sig.handler.value_type.get_parameters ()) {
++ if (first) {
++ // skip sender parameter
++ first = false;
++ } else {
++ dynamic_sig.add_parameter (param.copy ());
++ }
++ }
++ right.target_type = new DelegateType (sig.get_delegate (new ObjectType ((ObjectTypeSymbol) sig.parent_symbol)));
++ } else if (!right.value_type.compatible (right.target_type)) {
++ var delegate_type = (DelegateType) right.target_type;
++
++ error = true;
++ Report.error (right.source_reference, "method `%s' is incompatible with signal `%s', expected `%s'".printf (right.value_type.to_string (), right.target_type.to_string (), delegate_type.delegate_symbol.get_prototype_string (m.name)));
++ return false;
++ }
++ } else if (left is MemberAccess) {
++ var ma = (MemberAccess) left;
++
++ if (ma.symbol_reference is Property) {
++ var prop = (Property) ma.symbol_reference;
++
++ var dynamic_prop = prop as DynamicProperty;
++ if (dynamic_prop != null) {
++ dynamic_prop.property_type = right.value_type.copy ();
++ left.value_type = dynamic_prop.property_type.copy ();
++ }
++
++ if (prop.set_accessor == null
++ || (!prop.set_accessor.writable && !(analyzer.find_current_method () is CreationMethod || analyzer.is_in_constructor ()))) {
++ ma.error = true;
++ Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
++ return false;
++ }
++ } else if (ma.symbol_reference is LocalVariable && right.value_type == null) {
++ var local = (LocalVariable) ma.symbol_reference;
++
++ if (right.symbol_reference is Method &&
++ local.variable_type is DelegateType) {
++ var m = (Method) right.symbol_reference;
++ var dt = (DelegateType) local.variable_type;
++ var cb = dt.delegate_symbol;
++
++ /* check whether method matches callback type */
++ if (!cb.matches_method (m)) {
++ error = true;
++ Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
++ return false;
++ }
++
++ right.value_type = local.variable_type;
++ } else {
++ error = true;
++ Report.error (source_reference, "Assignment: Invalid callback assignment attempt");
++ return false;
++ }
++ } else if (ma.symbol_reference is Field && right.value_type == null) {
++ var f = (Field) ma.symbol_reference;
++
++ if (right.symbol_reference is Method &&
++ f.field_type is DelegateType) {
++ var m = (Method) right.symbol_reference;
++ var dt = (DelegateType) f.field_type;
++ var cb = dt.delegate_symbol;
++
++ /* check whether method matches callback type */
++ if (!cb.matches_method (m)) {
++ f.error = true;
++ Report.error (source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
++ return false;
++ }
++
++ right.value_type = f.field_type;
++ } else {
++ error = true;
++ Report.error (source_reference, "Assignment: Invalid callback assignment attempt");
++ return false;
++ }
++ } else if (left.value_type != null && right.value_type != null) {
++ /* if there was an error on either side,
++ * i.e. {left|right}.value_type == null, skip type check */
++
++ if (!right.value_type.compatible (left.value_type)) {
++ error = true;
++ Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (right.value_type.to_string (), left.value_type.to_string ()));
++ return false;
++ }
++
++ if (right.value_type.is_disposable ()) {
++ /* rhs transfers ownership of the expression */
++ if (!(left.value_type is PointerType) && !left.value_type.value_owned) {
++ /* lhs doesn't own the value */
++ error = true;
++ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
++ }
++ } else if (left.value_type.value_owned) {
++ /* lhs wants to own the value
++ * rhs doesn't transfer the ownership
++ * code generator needs to add reference
++ * increment calls */
++ }
++ }
++ } else if (left is ElementAccess) {
++ var ea = (ElementAccess) left;
++
++ if (!right.value_type.compatible (left.value_type)) {
++ error = true;
++ Report.error (source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (right.value_type.to_string (), left.value_type.to_string ()));
++ return false;
++ }
++
++ if (right.value_type.is_disposable ()) {
++ /* rhs transfers ownership of the expression */
++
++ DataType element_type;
++
++ if (ea.container.value_type is ArrayType) {
++ var array_type = (ArrayType) ea.container.value_type;
++ element_type = array_type.element_type;
++ } else {
++ var args = ea.container.value_type.get_type_arguments ();
++ assert (args.size == 1);
++ element_type = args.get (0);
++ }
++
++ if (!(element_type is PointerType) && !element_type.value_owned) {
++ /* lhs doesn't own the value */
++ error = true;
++ Report.error (source_reference, "Invalid assignment from owned expression to unowned variable");
++ return false;
++ }
++ } else if (left.value_type.value_owned) {
++ /* lhs wants to own the value
++ * rhs doesn't transfer the ownership
++ * code generator needs to add reference
++ * increment calls */
++ }
++ } else {
++ return false;
++ }
++
++ if (left.value_type != null) {
++ value_type = left.value_type.copy ();
++ value_type.value_owned = false;
++ } else {
++ value_type = null;
++ }
++
++ add_error_types (left.get_error_types ());
++ add_error_types (right.get_error_types ());
++
++ return !error;
++ }
+ }
+
+ public enum Vala.AssignmentOperator {
+Index: vala/valalockstatement.vala
+===================================================================
+--- vala/valalockstatement.vala (revision 1971)
++++ vala/valalockstatement.vala (revision 2004)
+@@ -47,4 +47,31 @@
+ body.accept (visitor);
+ visitor.visit_lock_statement (this);
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ /* resource must be a member access and denote a Lockable */
++ if (!(resource is MemberAccess && resource.symbol_reference is Lockable)) {
++ error = true;
++ resource.error = true;
++ Report.error (resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
++ return false;
++ }
++
++ /* parent symbol must be the current class */
++ if (resource.symbol_reference.parent_symbol != analyzer.current_class) {
++ error = true;
++ resource.error = true;
++ Report.error (resource.source_reference, "Only members of the current class are lockable");
++ }
++
++ ((Lockable) resource.symbol_reference).set_lock_used (true);
++
++ return !error;
++ }
+ }
+Index: vala/valathrowstatement.vala
+===================================================================
+--- vala/valathrowstatement.vala (revision 1971)
++++ vala/valathrowstatement.vala (revision 2004)
+@@ -72,4 +72,24 @@
+ error_expression = new_node;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ error_expression.target_type = new ErrorType (null, null, source_reference);
++ error_expression.target_type.value_owned = true;
++
++ accept_children (analyzer);
++
++ var error_type = error_expression.value_type.copy ();
++ error_type.source_reference = source_reference;
++
++ add_error_type (error_type);
++
++ return !error;
++ }
+ }
+Index: vala/valamemberaccess.vala
+===================================================================
+--- vala/valamemberaccess.vala (revision 1971)
++++ vala/valamemberaccess.vala (revision 2004)
+@@ -174,4 +174,355 @@
+ return false;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ Symbol base_symbol = null;
++ FormalParameter this_parameter = null;
++ bool may_access_instance_members = false;
++
++ symbol_reference = null;
++
++ if (qualified) {
++ base_symbol = analyzer.root_symbol;
++ symbol_reference = analyzer.root_symbol.scope.lookup (member_name);
++ } else if (inner == null) {
++ if (member_name == "this") {
++ if (!analyzer.is_in_instance_method ()) {
++ error = true;
++ Report.error (source_reference, "This access invalid outside of instance methods");
++ return false;
++ }
++ }
++
++ base_symbol = analyzer.current_symbol;
++
++ var sym = analyzer.current_symbol;
++ while (sym != null && symbol_reference == null) {
++ if (this_parameter == null) {
++ if (sym is CreationMethod) {
++ var cm = (CreationMethod) sym;
++ this_parameter = cm.this_parameter;
++ may_access_instance_members = true;
++ } else if (sym is Property) {
++ var prop = (Property) sym;
++ this_parameter = prop.this_parameter;
++ may_access_instance_members = true;
++ } else if (sym is Constructor) {
++ var c = (Constructor) sym;
++ this_parameter = c.this_parameter;
++ may_access_instance_members = true;
++ } else if (sym is Destructor) {
++ var d = (Destructor) sym;
++ this_parameter = d.this_parameter;
++ may_access_instance_members = true;
++ } else if (sym is Method) {
++ var m = (Method) sym;
++ this_parameter = m.this_parameter;
++ may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
++ }
++ }
++
++ symbol_reference = analyzer.symbol_lookup_inherited (sym, member_name);
++ sym = sym.parent_symbol;
++ }
++
++ if (symbol_reference == null) {
++ foreach (UsingDirective ns in analyzer.current_source_file.get_using_directives ()) {
++ var local_sym = ns.namespace_symbol.scope.lookup (member_name);
++ if (local_sym != null) {
++ if (symbol_reference != null) {
++ error = true;
++ Report.error (source_reference, "`%s' is an ambiguous reference between `%s' and `%s'".printf (member_name, symbol_reference.get_full_name (), local_sym.get_full_name ()));
++ return false;
++ }
++ symbol_reference = local_sym;
++ }
++ }
++ }
++ } else {
++ if (inner.error) {
++ /* if there was an error in the inner expression, skip this check */
++ error = true;
++ return false;
++ }
++
++ if (pointer_member_access) {
++ var pointer_type = inner.value_type as PointerType;
++ if (pointer_type != null && pointer_type.base_type is ValueType) {
++ // transform foo->bar to (*foo).bar
++ inner = new PointerIndirection (inner, source_reference);
++ inner.accept (analyzer);
++ pointer_member_access = false;
++ }
++ }
++
++ if (inner is MemberAccess) {
++ var ma = (MemberAccess) inner;
++ if (ma.prototype_access) {
++ error = true;
++ Report.error (source_reference, "Access to instance member `%s' denied".printf (inner.symbol_reference.get_full_name ()));
++ return false;
++ }
++ }
++
++ if (inner is MemberAccess || inner is BaseAccess) {
++ base_symbol = inner.symbol_reference;
++
++ if (symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
++ symbol_reference = base_symbol.scope.lookup (member_name);
++ if (inner is BaseAccess) {
++ // inner expression is base access
++ // access to instance members of the base type possible
++ may_access_instance_members = true;
++ }
++ }
++ }
++
++ if (symbol_reference == null && inner.value_type != null) {
++ if (pointer_member_access) {
++ symbol_reference = inner.value_type.get_pointer_member (member_name);
++ } else {
++ if (inner.value_type.data_type != null) {
++ base_symbol = inner.value_type.data_type;
++ }
++ symbol_reference = inner.value_type.get_member (member_name);
++ }
++ if (symbol_reference != null) {
++ // inner expression is variable, field, or parameter
++ // access to instance members of the corresponding type possible
++ may_access_instance_members = true;
++ }
++ }
++
++ if (symbol_reference == null && inner.value_type != null && inner.value_type.is_dynamic) {
++ // allow late bound members for dynamic types
++ var dynamic_object_type = (ObjectType) inner.value_type;
++ if (parent_node is InvocationExpression) {
++ var invoc = (InvocationExpression) parent_node;
++ if (invoc.call == this) {
++ // dynamic method
++ DataType ret_type;
++ if (invoc.target_type != null) {
++ ret_type = invoc.target_type.copy ();
++ ret_type.value_owned = true;
++ } else if (invoc.parent_node is ExpressionStatement) {
++ ret_type = new VoidType ();
++ } else {
++ // expect dynamic object of the same type
++ ret_type = inner.value_type.copy ();
++ }
++ var m = new DynamicMethod (inner.value_type, member_name, ret_type, source_reference);
++ m.invocation = invoc;
++ m.add_error_type (new ErrorType (null, null));
++ m.access = SymbolAccessibility.PUBLIC;
++ m.add_parameter (new FormalParameter.with_ellipsis ());
++ dynamic_object_type.type_symbol.scope.add (null, m);
++ symbol_reference = m;
++ }
++ } else if (parent_node is Assignment) {
++ var a = (Assignment) parent_node;
++ if (a.left == this
++ && (a.operator == AssignmentOperator.ADD
++ || a.operator == AssignmentOperator.SUB)) {
++ // dynamic signal
++ var s = new DynamicSignal (inner.value_type, member_name, new VoidType (), source_reference);
++ s.handler = a.right;
++ s.access = SymbolAccessibility.PUBLIC;
++ dynamic_object_type.type_symbol.scope.add (null, s);
++ symbol_reference = s;
++ } else if (a.left == this) {
++ // dynamic property assignment
++ var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
++ prop.access = SymbolAccessibility.PUBLIC;
++ prop.set_accessor = new PropertyAccessor (false, true, false, null, prop.source_reference);
++ prop.set_accessor.access = SymbolAccessibility.PUBLIC;
++ prop.owner = inner.value_type.data_type.scope;
++ dynamic_object_type.type_symbol.scope.add (null, prop);
++ symbol_reference = prop;
++ }
++ }
++ if (symbol_reference == null) {
++ // dynamic property read access
++ var prop = new DynamicProperty (inner.value_type, member_name, source_reference);
++ if (target_type != null) {
++ prop.property_type = target_type;
++ } else {
++ // expect dynamic object of the same type
++ prop.property_type = inner.value_type.copy ();
++ }
++ prop.access = SymbolAccessibility.PUBLIC;
++ prop.get_accessor = new PropertyAccessor (true, false, false, null, prop.source_reference);
++ prop.get_accessor.access = SymbolAccessibility.PUBLIC;
++ prop.owner = inner.value_type.data_type.scope;
++ dynamic_object_type.type_symbol.scope.add (null, prop);
++ symbol_reference = prop;
++ }
++ if (symbol_reference != null) {
++ may_access_instance_members = true;
++ }
++ }
++ }
++
++ if (symbol_reference == null) {
++ error = true;
++
++ string base_type_name = "(null)";
++ if (inner != null && inner.value_type != null) {
++ base_type_name = inner.value_type.to_string ();
++ } else if (base_symbol != null) {
++ base_type_name = base_symbol.get_full_name ();
++ }
++
++ Report.error (source_reference, "The name `%s' does not exist in the context of `%s'".printf (member_name, base_type_name));
++ return false;
++ }
++
++ var member = symbol_reference;
++ var access = SymbolAccessibility.PUBLIC;
++ bool instance = false;
++ bool klass = false;
++ if (member is Field) {
++ var f = (Field) member;
++ access = f.access;
++ instance = (f.binding == MemberBinding.INSTANCE);
++ klass = (f.binding == MemberBinding.CLASS);
++ } else if (member is Method) {
++ var m = (Method) member;
++ access = m.access;
++ if (!(m is CreationMethod)) {
++ instance = (m.binding == MemberBinding.INSTANCE);
++ }
++ klass = (m.binding == MemberBinding.CLASS);
++ } else if (member is Property) {
++ var prop = (Property) member;
++ if (!prop.check (analyzer)) {
++ error = true;
++ return false;
++ }
++ access = prop.access;
++ if (lvalue) {
++ if (prop.set_accessor == null) {
++ error = true;
++ Report.error (source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
++ return false;
++ }
++ if (prop.access == SymbolAccessibility.PUBLIC) {
++ access = prop.set_accessor.access;
++ } else if (prop.access == SymbolAccessibility.PROTECTED
++ && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
++ access = prop.set_accessor.access;
++ }
++ } else {
++ if (prop.get_accessor == null) {
++ error = true;
++ Report.error (source_reference, "Property `%s' is write-only".printf (prop.get_full_name ()));
++ return false;
++ }
++ if (prop.access == SymbolAccessibility.PUBLIC) {
++ access = prop.get_accessor.access;
++ } else if (prop.access == SymbolAccessibility.PROTECTED
++ && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
++ access = prop.get_accessor.access;
++ }
++ }
++ instance = (prop.binding == MemberBinding.INSTANCE);
++ } else if (member is Signal) {
++ instance = true;
++ }
++
++ if (access == SymbolAccessibility.PRIVATE) {
++ var target_type = member.parent_symbol;
++
++ bool in_target_type = false;
++ for (Symbol this_symbol = analyzer.current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
++ if (target_type == this_symbol) {
++ in_target_type = true;
++ break;
++ }
++ }
++
++ if (!in_target_type) {
++ error = true;
++ Report.error (source_reference, "Access to private member `%s' denied".printf (member.get_full_name ()));
++ return false;
++ }
++ }
++ if ((instance || klass) && !may_access_instance_members) {
++ prototype_access = true;
++
++ if (symbol_reference is Method) {
++ // also set static type for prototype access
++ // required when using instance methods as delegates in constants
++ // TODO replace by MethodPrototype
++ value_type = analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
++ } else if (symbol_reference is Field) {
++ value_type = new FieldPrototype ((Field) symbol_reference);
++ }
++ } else {
++ // implicit this access
++ if (instance && inner == null) {
++ inner = new MemberAccess (null, "this", source_reference);
++ inner.value_type = this_parameter.parameter_type.copy ();
++ inner.symbol_reference = this_parameter;
++ }
++
++ value_type = analyzer.get_value_type_for_symbol (symbol_reference, lvalue);
++
++ // resolve generic return values
++ if (value_type != null && value_type.type_parameter != null) {
++ if (inner != null) {
++ value_type = analyzer.get_actual_type (inner.value_type, symbol_reference, value_type, this);
++ if (value_type == null) {
++ return false;
++ }
++ }
++ }
++
++ if (symbol_reference is Method) {
++ var m = (Method) symbol_reference;
++
++ Method base_method;
++ if (m.base_method != null) {
++ base_method = m.base_method;
++ } else if (m.base_interface_method != null) {
++ base_method = m.base_interface_method;
++ } else {
++ base_method = m;
++ }
++
++ if (instance && base_method.parent_symbol != null) {
++ inner.target_type = analyzer.get_data_type_for_symbol ((TypeSymbol) base_method.parent_symbol);
++ }
++ } else if (symbol_reference is Property) {
++ var prop = (Property) symbol_reference;
++
++ Property base_property;
++ if (prop.base_property != null) {
++ base_property = prop.base_property;
++ } else if (prop.base_interface_property != null) {
++ base_property = prop.base_interface_property;
++ } else {
++ base_property = prop;
++ }
++
++ if (instance && base_property.parent_symbol != null) {
++ inner.target_type = analyzer.get_data_type_for_symbol ((TypeSymbol) base_property.parent_symbol);
++ }
++ } else if ((symbol_reference is Field
++ || symbol_reference is Signal)
++ && instance && symbol_reference.parent_symbol != null) {
++ inner.target_type = analyzer.get_data_type_for_symbol ((TypeSymbol) symbol_reference.parent_symbol);
++ }
++ }
++
++ analyzer.current_source_file.add_symbol_dependency (symbol_reference, SourceFileDependencyType.SOURCE);
++
++ return !error;
++ }
+ }
+Index: vala/valaenumvalue.vala
+===================================================================
+--- vala/valaenumvalue.vala (revision 1971)
++++ vala/valaenumvalue.vala (revision 2004)
+@@ -128,4 +128,18 @@
+ public void set_cname (string cname) {
+ this.cname = cname;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valabinaryexpression.vala
+===================================================================
+--- vala/valabinaryexpression.vala (revision 1971)
++++ vala/valabinaryexpression.vala (revision 2004)
+@@ -20,7 +20,7 @@
+ * Jürg Billeter <j@bitron.ch>
+ */
+
+-using GLib;
++using Gee;
+
+ /**
+ * Represents an expression with two operands in the source code.
+@@ -137,6 +137,169 @@
+ public override bool is_non_null () {
+ return left.is_non_null () && right.is_non_null ();
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (left.error || right.error) {
++ /* if there were any errors in inner expressions, skip type check */
++ error = true;
++ return false;
++ }
++
++ if (left.value_type == null) {
++ Report.error (left.source_reference, "invalid left operand");
++ error = true;
++ return false;
++ }
++
++ if (operator != BinaryOperator.IN && right.value_type == null) {
++ Report.error (right.source_reference, "invalid right operand");
++ error = true;
++ return false;
++ }
++
++ if (left.value_type.data_type == analyzer.string_type.data_type
++ && operator == BinaryOperator.PLUS) {
++ // string concatenation
++
++ if (right.value_type == null || right.value_type.data_type != analyzer.string_type.data_type) {
++ error = true;
++ Report.error (source_reference, "Operands must be strings");
++ return false;
++ }
++
++ value_type = analyzer.string_type.copy ();
++ if (left.is_constant () && right.is_constant ()) {
++ value_type.value_owned = false;
++ } else {
++ value_type.value_owned = true;
++ }
++ } else if (operator == BinaryOperator.PLUS
++ || operator == BinaryOperator.MINUS
++ || operator == BinaryOperator.MUL
++ || operator == BinaryOperator.DIV) {
++ // check for pointer arithmetic
++ if (left.value_type is PointerType) {
++ var offset_type = right.value_type.data_type as Struct;
++ if (offset_type != null && offset_type.is_integer_type ()) {
++ if (operator == BinaryOperator.PLUS
++ || operator == BinaryOperator.MINUS) {
++ // pointer arithmetic: pointer +/- offset
++ value_type = left.value_type.copy ();
++ }
++ } else if (right.value_type is PointerType) {
++ // pointer arithmetic: pointer - pointer
++ value_type = analyzer.size_t_type;
++ }
++ }
++
++ if (value_type == null) {
++ value_type = analyzer.get_arithmetic_result_type (left.value_type, right.value_type);
++ }
++
++ if (value_type == null) {
++ error = true;
++ Report.error (source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (left.value_type.to_string (), right.value_type.to_string ()));
++ return false;
++ }
++ } else if (operator == BinaryOperator.MOD
++ || operator == BinaryOperator.SHIFT_LEFT
++ || operator == BinaryOperator.SHIFT_RIGHT
++ || operator == BinaryOperator.BITWISE_XOR) {
++ value_type = analyzer.get_arithmetic_result_type (left.value_type, right.value_type);
++
++ if (value_type == null) {
++ error = true;
++ Report.error (source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (left.value_type.to_string (), right.value_type.to_string ()));
++ return false;
++ }
++ } else if (operator == BinaryOperator.LESS_THAN
++ || operator == BinaryOperator.GREATER_THAN
++ || operator == BinaryOperator.LESS_THAN_OR_EQUAL
++ || operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
++ if (left.value_type.compatible (analyzer.string_type)
++ && right.value_type.compatible (analyzer.string_type)) {
++ // string comparison
++ } else if (left.value_type is PointerType && right.value_type is PointerType) {
++ // pointer arithmetic
++ } else {
++ var resulting_type = analyzer.get_arithmetic_result_type (left.value_type, right.value_type);
++
++ if (resulting_type == null) {
++ error = true;
++ Report.error (source_reference, "Relational operation not supported for types `%s' and `%s'".printf (left.value_type.to_string (), right.value_type.to_string ()));
++ return false;
++ }
++ }
++
++ value_type = analyzer.bool_type;
++ } else if (operator == BinaryOperator.EQUALITY
++ || operator == BinaryOperator.INEQUALITY) {
++ /* relational operation */
++
++ if (!right.value_type.compatible (left.value_type)
++ && !left.value_type.compatible (right.value_type)) {
++ Report.error (source_reference, "Equality operation: `%s' and `%s' are incompatible".printf (right.value_type.to_string (), left.value_type.to_string ()));
++ error = true;
++ return false;
++ }
++
++ if (left.value_type.compatible (analyzer.string_type)
++ && right.value_type.compatible (analyzer.string_type)) {
++ // string comparison
++ }
++
++ value_type = analyzer.bool_type;
++ } else if (operator == BinaryOperator.BITWISE_AND
++ || operator == BinaryOperator.BITWISE_OR) {
++ // integer type or flags type
++
++ value_type = left.value_type;
++ } else if (operator == BinaryOperator.AND
++ || operator == BinaryOperator.OR) {
++ if (!left.value_type.compatible (analyzer.bool_type) || !right.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (source_reference, "Operands must be boolean");
++ }
++
++ value_type = analyzer.bool_type;
++ } else if (operator == BinaryOperator.IN) {
++ // integer type or flags type or collection/map
++
++ /* handle collections and maps */
++ var container_type = right.value_type.data_type;
++
++ if ((analyzer.collection_type != null && container_type.is_subtype_of (analyzer.collection_type))
++ || (analyzer.map_type != null && container_type.is_subtype_of (analyzer.map_type))) {
++ Symbol contains_sym = null;
++ if (container_type.is_subtype_of (analyzer.collection_type)) {
++ contains_sym = analyzer.collection_type.scope.lookup ("contains");
++ } else if (container_type.is_subtype_of (analyzer.map_type)) {
++ contains_sym = analyzer.map_type.scope.lookup ("contains");
++ }
++ var contains_method = (Method) contains_sym;
++ Gee.List<FormalParameter> contains_params = contains_method.get_parameters ();
++ Iterator<FormalParameter> contains_params_it = contains_params.iterator ();
++ contains_params_it.next ();
++ var contains_param = contains_params_it.get ();
++
++ var key_type = analyzer.get_actual_type (right.value_type, contains_method, contains_param.parameter_type, this);
++ left.target_type = key_type;
++ }
++
++ value_type = analyzer.bool_type;
++
++ } else {
++ assert_not_reached ();
++ }
++
++ return !error;
++ }
+ }
+
+ public enum Vala.BinaryOperator {
+Index: vala/valacreationmethod.vala
+===================================================================
+--- vala/valacreationmethod.vala (revision 1971)
++++ vala/valacreationmethod.vala (revision 2004)
+@@ -114,4 +114,42 @@
+ return "%s%s_%s".printf (parent.get_lower_case_cprefix (), infix, name);
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ if (type_name != null && type_name != analyzer.current_symbol.name) {
++ // type_name is null for constructors generated by GIdlParser
++ Report.error (source_reference, "missing return type in method `%s.%s´".printf (analyzer.current_symbol.get_full_name (), type_name));
++ error = true;
++ return false;
++ }
++
++ analyzer.current_symbol = this;
++ analyzer.current_return_type = return_type;
++
++ accept_children (analyzer);
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++ analyzer.current_return_type = null;
++
++ if (analyzer.current_symbol.parent_symbol is Method) {
++ /* lambda expressions produce nested methods */
++ var up_method = (Method) analyzer.current_symbol.parent_symbol;
++ analyzer.current_return_type = up_method.return_type;
++ }
++
++ if (is_abstract || is_virtual || overrides) {
++ Report.error (source_reference, "The creation method `%s' cannot be marked as override, virtual, or abstract".printf (get_full_name ()));
++ return false;
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valadelegate.vala
+===================================================================
+--- vala/valadelegate.vala (revision 1971)
++++ vala/valadelegate.vala (revision 2004)
+@@ -327,4 +327,18 @@
+
+ return str;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valaobjectcreationexpression.vala
+===================================================================
+--- vala/valaobjectcreationexpression.vala (revision 1971)
++++ vala/valaobjectcreationexpression.vala (revision 2004)
+@@ -149,4 +149,201 @@
+ type_reference = new_type;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (member_name != null) {
++ member_name.accept (analyzer);
++ }
++
++ TypeSymbol type = null;
++
++ if (type_reference == null) {
++ if (member_name == null) {
++ error = true;
++ Report.error (source_reference, "Incomplete object creation expression");
++ return false;
++ }
++
++ if (member_name.symbol_reference == null) {
++ error = true;
++ return false;
++ }
++
++ var constructor_sym = member_name.symbol_reference;
++ var type_sym = member_name.symbol_reference;
++
++ var type_args = member_name.get_type_arguments ();
++
++ if (constructor_sym is Method) {
++ type_sym = constructor_sym.parent_symbol;
++
++ var constructor = (Method) constructor_sym;
++ if (!(constructor_sym is CreationMethod)) {
++ error = true;
++ Report.error (source_reference, "`%s' is not a creation method".printf (constructor.get_full_name ()));
++ return false;
++ }
++
++ symbol_reference = constructor;
++
++ // inner expression can also be base access when chaining constructors
++ var ma = member_name.inner as MemberAccess;
++ if (ma != null) {
++ type_args = ma.get_type_arguments ();
++ }
++ }
++
++ if (type_sym is Class) {
++ type = (TypeSymbol) type_sym;
++ type_reference = new ObjectType ((Class) type);
++ } else if (type_sym is Struct) {
++ type = (TypeSymbol) type_sym;
++ type_reference = new ValueType (type);
++ } else if (type_sym is ErrorCode) {
++ type_reference = new ErrorType ((ErrorDomain) type_sym.parent_symbol, (ErrorCode) type_sym, source_reference);
++ symbol_reference = type_sym;
++ } else {
++ error = true;
++ Report.error (source_reference, "`%s' is not a class, struct, or error code".printf (type_sym.get_full_name ()));
++ return false;
++ }
++
++ foreach (DataType type_arg in type_args) {
++ type_reference.add_type_argument (type_arg);
++
++ analyzer.current_source_file.add_type_dependency (type_arg, SourceFileDependencyType.SOURCE);
++ }
++ } else {
++ type = type_reference.data_type;
++ }
++
++ analyzer.current_source_file.add_symbol_dependency (type, SourceFileDependencyType.SOURCE);
++
++ value_type = type_reference.copy ();
++ value_type.value_owned = true;
++
++ int given_num_type_args = type_reference.get_type_arguments ().size;
++ int expected_num_type_args = 0;
++
++ if (type is Class) {
++ var cl = (Class) type;
++
++ expected_num_type_args = cl.get_type_parameters ().size;
++
++ if (struct_creation) {
++ error = true;
++ Report.error (source_reference, "syntax error, use `new' to create new objects");
++ return false;
++ }
++
++ if (cl.is_abstract) {
++ value_type = null;
++ error = true;
++ Report.error (source_reference, "Can't create instance of abstract class `%s'".printf (cl.get_full_name ()));
++ return false;
++ }
++
++ if (symbol_reference == null) {
++ symbol_reference = cl.default_construction_method;
++ }
++
++ while (cl != null) {
++ if (cl == analyzer.initially_unowned_type) {
++ value_type.floating_reference = true;
++ break;
++ }
++
++ cl = cl.base_class;
++ }
++ } else if (type is Struct) {
++ var st = (Struct) type;
++
++ expected_num_type_args = st.get_type_parameters ().size;
++
++ if (!struct_creation) {
++ Report.warning (source_reference, "deprecated syntax, don't use `new' to initialize structs");
++ }
++
++ if (symbol_reference == null) {
++ symbol_reference = st.default_construction_method;
++ }
++ }
++
++ if (expected_num_type_args > given_num_type_args) {
++ error = true;
++ Report.error (source_reference, "too few type arguments");
++ return false;
++ } else if (expected_num_type_args < given_num_type_args) {
++ error = true;
++ Report.error (source_reference, "too many type arguments");
++ return false;
++ }
++
++ if (symbol_reference == null && get_argument_list ().size != 0) {
++ value_type = null;
++ error = true;
++ Report.error (source_reference, "No arguments allowed when constructing type `%s'".printf (type.get_full_name ()));
++ return false;
++ }
++
++ if (symbol_reference is Method) {
++ var m = (Method) symbol_reference;
++
++ var args = get_argument_list ();
++ Iterator<Expression> arg_it = args.iterator ();
++ foreach (FormalParameter param in m.get_parameters ()) {
++ if (param.ellipsis) {
++ break;
++ }
++
++ if (arg_it.next ()) {
++ Expression arg = arg_it.get ();
++
++ /* store expected type for callback parameters */
++ arg.target_type = param.parameter_type;
++ }
++ }
++
++ foreach (Expression arg in args) {
++ arg.accept (analyzer);
++ }
++
++ analyzer.check_arguments (this, new MethodType (m), m.get_parameters (), args);
++
++ foreach (DataType error_type in m.get_error_types ()) {
++ // ensure we can trace back which expression may throw errors of this type
++ var call_error_type = error_type.copy ();
++ call_error_type.source_reference = source_reference;
++
++ add_error_type (call_error_type);
++ }
++ } else if (type_reference is ErrorType) {
++ accept_children (analyzer);
++
++ if (get_argument_list ().size == 0) {
++ error = true;
++ Report.error (source_reference, "Too few arguments, errors need at least 1 argument");
++ } else {
++ Iterator<Expression> arg_it = get_argument_list ().iterator ();
++ arg_it.next ();
++ var ex = arg_it.get ();
++ if (ex.value_type == null || !ex.value_type.compatible (analyzer.string_type)) {
++ error = true;
++ Report.error (source_reference, "Invalid type for argument 1");
++ }
++ }
++ }
++
++ foreach (MemberInitializer init in get_object_initializer ()) {
++ analyzer.visit_member_initializer (init, type_reference);
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valaerrordomain.vala
+===================================================================
+--- vala/valaerrordomain.vala (revision 1971)
++++ vala/valaerrordomain.vala (revision 2004)
+@@ -215,4 +215,18 @@
+ public override string? get_set_value_function () {
+ return "g_value_set_pointer";
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valaifstatement.vala
+===================================================================
+--- vala/valaifstatement.vala (revision 1971)
++++ vala/valaifstatement.vala (revision 2004)
+@@ -86,4 +86,35 @@
+ condition = new_node;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ if (condition.error) {
++ /* if there was an error in the condition, skip this check */
++ error = true;
++ return false;
++ }
++
++ if (!condition.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (condition.source_reference, "Condition must be boolean");
++ return false;
++ }
++
++ add_error_types (condition.get_error_types ());
++ add_error_types (true_statement.get_error_types ());
++
++ if (false_statement != null) {
++ add_error_types (false_statement.get_error_types ());
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valaswitchsection.vala
+===================================================================
+--- vala/valaswitchsection.vala (revision 1971)
++++ vala/valaswitchsection.vala (revision 2004)
+@@ -80,4 +80,31 @@
+ st.accept (visitor);
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ foreach (SwitchLabel label in get_labels ()) {
++ label.accept (analyzer);
++ }
++
++ owner = analyzer.current_symbol.scope;
++ analyzer.current_symbol = this;
++
++ foreach (Statement st in get_statements ()) {
++ st.accept (analyzer);
++ }
++
++ foreach (LocalVariable local in get_local_variables ()) {
++ local.active = false;
++ }
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++
++ return !error;
++ }
+ }
+Index: vala/valaenum.vala
+===================================================================
+--- vala/valaenum.vala (revision 1971)
++++ vala/valaenum.vala (revision 2004)
+@@ -289,4 +289,26 @@
+ public override string? get_default_value () {
+ return "0";
+ }
++
++ public override string? get_type_signature () {
++ if (is_flags) {
++ return "u";
++ } else {
++ return "i";
++ }
++ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valapropertyaccessor.vala
+===================================================================
+--- vala/valapropertyaccessor.vala (revision 1971)
++++ vala/valapropertyaccessor.vala (revision 2004)
+@@ -131,4 +131,55 @@
+ }
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ var old_return_type = analyzer.current_return_type;
++ if (readable) {
++ analyzer.current_return_type = prop.property_type;
++ } else {
++ // void
++ analyzer.current_return_type = new VoidType ();
++ }
++
++ if (!prop.external_package) {
++ if (body == null && !prop.interface_only && !prop.is_abstract) {
++ /* no accessor body specified, insert default body */
++
++ if (prop.parent_symbol is Interface) {
++ error = true;
++ Report.error (source_reference, "Automatic properties can't be used in interfaces");
++ return false;
++ }
++ automatic_body = true;
++ body = new Block (source_reference);
++ var ma = new MemberAccess.simple ("_%s".printf (prop.name), source_reference);
++ if (readable) {
++ body.add_statement (new ReturnStatement (ma, source_reference));
++ } else {
++ var assignment = new Assignment (ma, new MemberAccess.simple ("value", source_reference), AssignmentOperator.SIMPLE, source_reference);
++ body.add_statement (new ExpressionStatement (assignment));
++ }
++ }
++
++ if (body != null && (writable || construction)) {
++ var value_type = prop.property_type.copy ();
++ value_parameter = new FormalParameter ("value", value_type, source_reference);
++ body.scope.add (value_parameter.name, value_parameter);
++ }
++ }
++
++ accept_children (analyzer);
++
++ analyzer.current_return_type = old_return_type;
++
++ return !error;
++ }
+ }
+Index: vala/valaobjecttype.vala
+===================================================================
+--- vala/valaobjecttype.vala (revision 1971)
++++ vala/valaobjecttype.vala (revision 2004)
+@@ -98,4 +98,8 @@
+ return null;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ return type_symbol.check (analyzer);
++ }
+ }
+Index: vala/valasemanticanalyzer.vala
+===================================================================
+--- vala/valasemanticanalyzer.vala (revision 1971)
++++ vala/valasemanticanalyzer.vala (revision 2004)
+@@ -30,46 +30,44 @@
+ public class Vala.SemanticAnalyzer : CodeVisitor {
+ public CodeContext context { get; set; }
+
+- Symbol root_symbol;
++ public Symbol root_symbol;
+ public Symbol current_symbol { get; set; }
+ public SourceFile current_source_file { get; set; }
+- DataType current_return_type;
+- Class current_class;
+- Struct current_struct;
++ public DataType current_return_type;
++ public Class current_class;
++ public Struct current_struct;
+
+- Gee.List<UsingDirective> current_using_directives;
++ public DataType bool_type;
++ public DataType string_type;
++ public DataType uchar_type;
++ public DataType short_type;
++ public DataType ushort_type;
++ public DataType int_type;
++ public DataType uint_type;
++ public DataType long_type;
++ public DataType ulong_type;
++ public DataType size_t_type;
++ public DataType ssize_t_type;
++ public DataType int8_type;
++ public DataType unichar_type;
++ public DataType double_type;
++ public DataType type_type;
++ public Class object_type;
++ public TypeSymbol initially_unowned_type;
++ public DataType glist_type;
++ public DataType gslist_type;
++ public Class gerror_type;
++ public DataType iterable_type;
++ public Interface iterator_type;
++ public Interface list_type;
++ public Interface collection_type;
++ public Interface map_type;
+
+- DataType bool_type;
+- DataType string_type;
+- DataType uchar_type;
+- DataType short_type;
+- DataType ushort_type;
+- DataType int_type;
+- DataType uint_type;
+- DataType long_type;
+- DataType ulong_type;
+- DataType size_t_type;
+- DataType ssize_t_type;
+- DataType int8_type;
+- DataType unichar_type;
+- DataType double_type;
+- DataType type_type;
+- Class object_type;
+- TypeSymbol initially_unowned_type;
+- DataType glist_type;
+- DataType gslist_type;
+- Class gerror_type;
+- DataType iterable_type;
+- Interface iterator_type;
+- Interface list_type;
+- Interface collection_type;
+- Interface map_type;
+-
+ private int next_lambda_id = 0;
+
+ // keep replaced alive to make sure they remain valid
+ // for the whole execution of CodeNode.accept
+- Gee.List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
++ public Gee.List<CodeNode> replaced_nodes = new ArrayList<CodeNode> ();
+
+ public SemanticAnalyzer () {
+ }
+@@ -129,499 +127,65 @@
+
+ public override void visit_source_file (SourceFile file) {
+ current_source_file = file;
+- current_using_directives = file.get_using_directives ();
+
+ next_lambda_id = 0;
+
+ file.accept_children (this);
+-
+- current_using_directives = null;
+ }
+
+ public override void visit_namespace (Namespace ns) {
+- ns.process_attributes ();
++ ns.check (this);
+ }
+
+ public override void visit_class (Class cl) {
+- cl.process_attributes ();
+-
+- current_symbol = cl;
+- current_class = cl;
+-
+- foreach (DataType base_type_reference in cl.get_base_types ()) {
+- // check whether base type is at least as accessible as the class
+- if (!is_type_accessible (cl, base_type_reference)) {
+- cl.error = true;
+- Report.error (cl.source_reference, "base type `%s` is less accessible than class `%s`".printf (base_type_reference.to_string (), cl.get_full_name ()));
+- return;
+- }
+-
+- current_source_file.add_type_dependency (base_type_reference, SourceFileDependencyType.HEADER_FULL);
+- }
+-
+- cl.accept_children (this);
+-
+- /* compact classes cannot implement interfaces */
+- if (cl.is_compact) {
+- foreach (DataType base_type in cl.get_base_types ()) {
+- if (base_type.data_type is Interface) {
+- cl.error = true;
+- Report.error (cl.source_reference, "compact classes `%s` may not implement interfaces".printf (cl.get_full_name ()));
+- }
+- }
+- }
+-
+- /* gather all prerequisites */
+- Gee.List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
+- foreach (DataType base_type in cl.get_base_types ()) {
+- if (base_type.data_type is Interface) {
+- get_all_prerequisites ((Interface) base_type.data_type, prerequisites);
+- }
+- }
+- /* check whether all prerequisites are met */
+- Gee.List<string> missing_prereqs = new ArrayList<string> ();
+- foreach (TypeSymbol prereq in prerequisites) {
+- if (!class_is_a (cl, prereq)) {
+- missing_prereqs.insert (0, prereq.get_full_name ());
+- }
+- }
+- /* report any missing prerequisites */
+- if (missing_prereqs.size > 0) {
+- cl.error = true;
+-
+- string error_string = "%s: some prerequisites (".printf (cl.get_full_name ());
+- bool first = true;
+- foreach (string s in missing_prereqs) {
+- if (first) {
+- error_string = "%s`%s'".printf (error_string, s);
+- first = false;
+- } else {
+- error_string = "%s, `%s'".printf (error_string, s);
+- }
+- }
+- error_string += ") are not met";
+- Report.error (cl.source_reference, error_string);
+- }
+-
+- /* VAPI classes don't have to specify overridden methods */
+- if (!cl.external_package) {
+- /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
+- foreach (DataType base_type in cl.get_base_types ()) {
+- if (base_type.data_type is Interface) {
+- Interface iface = (Interface) base_type.data_type;
+-
+- if (cl.base_class != null && cl.base_class.is_subtype_of (iface)) {
+- // reimplementation of interface, class is not required to reimplement all methods
+- break;
+- }
+-
+- /* We do not need to do expensive equality checking here since this is done
+- * already. We only need to guarantee the symbols are present.
+- */
+-
+- /* check methods */
+- foreach (Method m in iface.get_methods ()) {
+- if (m.is_abstract) {
+- Symbol sym = null;
+- var base_class = cl;
+- while (base_class != null && !(sym is Method)) {
+- sym = base_class.scope.lookup (m.name);
+- base_class = base_class.base_class;
+- }
+- if (!(sym is Method)) {
+- cl.error = true;
+- Report.error (cl.source_reference, "`%s' does not implement interface method `%s'".printf (cl.get_full_name (), m.get_full_name ()));
+- }
+- }
+- }
+-
+- /* check properties */
+- foreach (Property prop in iface.get_properties ()) {
+- if (prop.is_abstract) {
+- Symbol sym = null;
+- var base_class = cl;
+- while (base_class != null && !(sym is Property)) {
+- sym = base_class.scope.lookup (prop.name);
+- base_class = base_class.base_class;
+- }
+- if (!(sym is Property)) {
+- cl.error = true;
+- Report.error (cl.source_reference, "`%s' does not implement interface property `%s'".printf (cl.get_full_name (), prop.get_full_name ()));
+- }
+- }
+- }
+- }
+- }
+-
+- /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
+- if (!cl.is_abstract) {
+- var base_class = cl.base_class;
+- while (base_class != null && base_class.is_abstract) {
+- foreach (Method base_method in base_class.get_methods ()) {
+- if (base_method.is_abstract) {
+- var override_method = symbol_lookup_inherited (cl, base_method.name) as Method;
+- if (override_method == null || !override_method.overrides) {
+- cl.error = true;
+- Report.error (cl.source_reference, "`%s' does not implement abstract method `%s'".printf (cl.get_full_name (), base_method.get_full_name ()));
+- }
+- }
+- }
+- foreach (Property base_property in base_class.get_properties ()) {
+- if (base_property.is_abstract) {
+- var override_property = symbol_lookup_inherited (cl, base_property.name) as Property;
+- if (override_property == null || !override_property.overrides) {
+- cl.error = true;
+- Report.error (cl.source_reference, "`%s' does not implement abstract property `%s'".printf (cl.get_full_name (), base_property.get_full_name ()));
+- }
+- }
+- }
+- base_class = base_class.base_class;
+- }
+- }
+- }
+-
+- current_symbol = current_symbol.parent_symbol;
+- current_class = null;
++ cl.check (this);
+ }
+
+- private void get_all_prerequisites (Interface iface, Gee.List<TypeSymbol> list) {
+- foreach (DataType prereq in iface.get_prerequisites ()) {
+- TypeSymbol type = prereq.data_type;
+- /* skip on previous errors */
+- if (type == null) {
+- continue;
+- }
+-
+- list.add (type);
+- if (type is Interface) {
+- get_all_prerequisites ((Interface) type, list);
+-
+- }
+- }
+- }
+-
+- private bool class_is_a (Class cl, TypeSymbol t) {
+- if (cl == t) {
+- return true;
+- }
+-
+- foreach (DataType base_type in cl.get_base_types ()) {
+- if (base_type.data_type is Class) {
+- if (class_is_a ((Class) base_type.data_type, t)) {
+- return true;
+- }
+- } else if (base_type.data_type == t) {
+- return true;
+- }
+- }
+-
+- return false;
+- }
+-
+ public override void visit_struct (Struct st) {
+- st.process_attributes ();
+-
+- current_symbol = st;
+- current_struct = st;
+-
+- st.accept_children (this);
+-
+- if (!st.external && !st.external_package && st.get_base_types ().size == 0 && st.get_fields ().size == 0) {
+- Report.error (st.source_reference, "structs cannot be empty");
+- }
+-
+- current_symbol = current_symbol.parent_symbol;
+- current_struct = null;
++ st.check (this);
+ }
+
+ public override void visit_interface (Interface iface) {
+- iface.process_attributes ();
+-
+- current_symbol = iface;
+-
+- foreach (DataType prerequisite_reference in iface.get_prerequisites ()) {
+- // check whether prerequisite is at least as accessible as the interface
+- if (!is_type_accessible (iface, prerequisite_reference)) {
+- iface.error = true;
+- Report.error (iface.source_reference, "prerequisite `%s` is less accessible than interface `%s`".printf (prerequisite_reference.to_string (), iface.get_full_name ()));
+- return;
+- }
+-
+- current_source_file.add_type_dependency (prerequisite_reference, SourceFileDependencyType.HEADER_FULL);
+- }
+-
+- /* check prerequisites */
+- Class prereq_class;
+- foreach (DataType prereq in iface.get_prerequisites ()) {
+- TypeSymbol class_or_interface = prereq.data_type;
+- /* skip on previous errors */
+- if (class_or_interface == null) {
+- iface.error = true;
+- continue;
+- }
+- /* interfaces are not allowed to have multiple instantiable prerequisites */
+- if (class_or_interface is Class) {
+- if (prereq_class != null) {
+- iface.error = true;
+- Report.error (iface.source_reference, "%s: Interfaces cannot have multiple instantiable prerequisites (`%s' and `%s')".printf (iface.get_full_name (), class_or_interface.get_full_name (), prereq_class.get_full_name ()));
+- return;
+- }
+-
+- prereq_class = (Class) class_or_interface;
+- }
+- }
+-
+- iface.accept_children (this);
+-
+- current_symbol = current_symbol.parent_symbol;
++ iface.check (this);
+ }
+
+ public override void visit_enum (Enum en) {
+- en.process_attributes ();
+-
+- en.accept_children (this);
++ en.check (this);
+ }
+
+ public override void visit_enum_value (EnumValue ev) {
+- ev.process_attributes ();
+-
+- ev.accept_children (this);
++ ev.check (this);
+ }
+
+ public override void visit_error_domain (ErrorDomain ed) {
+- ed.process_attributes ();
++ ed.check (this);
++ }
+
+- ed.accept_children (this);
++ public override void visit_error_code (ErrorCode ec) {
++ ec.check (this);
+ }
+
+ public override void visit_delegate (Delegate d) {
+- d.process_attributes ();
+-
+- d.accept_children (this);
++ d.check (this);
+ }
+
+ public override void visit_constant (Constant c) {
+- c.process_attributes ();
+-
+- c.type_reference.accept (this);
+-
+- if (!c.external_package) {
+- if (c.initializer == null) {
+- c.error = true;
+- Report.error (c.source_reference, "A const field requires a initializer to be provided");
+- } else {
+- c.initializer.target_type = c.type_reference;
+-
+- c.initializer.accept (this);
+- }
+- }
++ c.check (this);
+ }
+
+ public override void visit_field (Field f) {
+- f.process_attributes ();
+-
+- if (f.initializer != null) {
+- f.initializer.target_type = f.field_type;
+- }
+-
+- f.accept_children (this);
+-
+- if (f.binding == MemberBinding.INSTANCE && f.parent_symbol is Interface) {
+- f.error = true;
+- Report.error (f.source_reference, "Interfaces may not have instance fields");
+- return;
+- }
+-
+- if (!f.is_internal_symbol ()) {
+- if (f.field_type is ValueType) {
+- current_source_file.add_type_dependency (f.field_type, SourceFileDependencyType.HEADER_FULL);
+- } else {
+- current_source_file.add_type_dependency (f.field_type, SourceFileDependencyType.HEADER_SHALLOW);
+- }
+- } else {
+- if (f.parent_symbol is Namespace) {
+- f.error = true;
+- Report.error (f.source_reference, "Namespaces may not have private members");
+- return;
+- }
+-
+- current_source_file.add_type_dependency (f.field_type, SourceFileDependencyType.SOURCE);
+- }
++ f.check (this);
+ }
+
+ public override void visit_method (Method m) {
+- m.process_attributes ();
+-
+- if (m.is_abstract) {
+- if (m.parent_symbol is Class) {
+- var cl = (Class) m.parent_symbol;
+- if (!cl.is_abstract) {
+- m.error = true;
+- Report.error (m.source_reference, "Abstract methods may not be declared in non-abstract classes");
+- return;
+- }
+- } else if (!(m.parent_symbol is Interface)) {
+- m.error = true;
+- Report.error (m.source_reference, "Abstract methods may not be declared outside of classes and interfaces");
+- return;
+- }
+- } else if (m.is_virtual) {
+- if (!(m.parent_symbol is Class) && !(m.parent_symbol is Interface)) {
+- m.error = true;
+- Report.error (m.source_reference, "Virtual methods may not be declared outside of classes and interfaces");
+- return;
+- }
+-
+- if (m.parent_symbol is Class) {
+- var cl = (Class) m.parent_symbol;
+- if (cl.is_compact) {
+- Report.error (m.source_reference, "Virtual methods may not be declared in compact classes");
+- return;
+- }
+- }
+- } else if (m.overrides) {
+- if (!(m.parent_symbol is Class)) {
+- m.error = true;
+- Report.error (m.source_reference, "Methods may not be overridden outside of classes");
+- return;
+- }
+- }
+-
+- if (m.is_abstract && m.body != null) {
+- Report.error (m.source_reference, "Abstract methods cannot have bodies");
+- } else if (m.external && m.body != null) {
+- Report.error (m.source_reference, "Extern methods cannot have bodies");
+- } else if (!m.is_abstract && !m.external && !m.external_package && m.body == null) {
+- Report.error (m.source_reference, "Non-abstract, non-extern methods must have bodies");
+- }
+-
+- var old_symbol = current_symbol;
+- var old_return_type = current_return_type;
+- current_symbol = m;
+- current_return_type = m.return_type;
+-
+- var init_attr = m.get_attribute ("ModuleInit");
+- if (init_attr != null) {
+- m.source_reference.file.context.module_init_method = m;
+- }
+-
+- if (!m.is_internal_symbol ()) {
+- if (m.return_type is ValueType) {
+- current_source_file.add_type_dependency (m.return_type, SourceFileDependencyType.HEADER_FULL);
+- } else {
+- current_source_file.add_type_dependency (m.return_type, SourceFileDependencyType.HEADER_SHALLOW);
+- }
+- }
+- current_source_file.add_type_dependency (m.return_type, SourceFileDependencyType.SOURCE);
+-
+- m.accept_children (this);
+-
+- current_symbol = old_symbol;
+- current_return_type = old_return_type;
+-
+- if (current_symbol.parent_symbol is Method) {
+- /* lambda expressions produce nested methods */
+- var up_method = (Method) current_symbol.parent_symbol;
+- current_return_type = up_method.return_type;
+- }
+-
+- if (current_symbol is Struct) {
+- if (m.is_abstract || m.is_virtual || m.overrides) {
+- Report.error (m.source_reference, "A struct member `%s' cannot be marked as override, virtual, or abstract".printf (m.get_full_name ()));
+- return;
+- }
+- } else if (m.overrides && m.base_method == null) {
+- Report.error (m.source_reference, "%s: no suitable method found to override".printf (m.get_full_name ()));
+- }
+-
+- // check whether return type is at least as accessible as the method
+- if (!is_type_accessible (m, m.return_type)) {
+- m.error = true;
+- Report.error (m.source_reference, "return type `%s` is less accessible than method `%s`".printf (m.return_type.to_string (), m.get_full_name ()));
+- return;
+- }
+-
+- foreach (Expression precondition in m.get_preconditions ()) {
+- if (precondition.error) {
+- // if there was an error in the precondition, skip this check
+- m.error = true;
+- return;
+- }
+-
+- if (!precondition.value_type.compatible (bool_type)) {
+- m.error = true;
+- Report.error (precondition.source_reference, "Precondition must be boolean");
+- return;
+- }
+- }
+-
+- foreach (Expression postcondition in m.get_postconditions ()) {
+- if (postcondition.error) {
+- // if there was an error in the postcondition, skip this check
+- m.error = true;
+- return;
+- }
+-
+- if (!postcondition.value_type.compatible (bool_type)) {
+- m.error = true;
+- Report.error (postcondition.source_reference, "Postcondition must be boolean");
+- return;
+- }
+- }
+-
+- if (m.tree_can_fail && m.name == "main") {
+- Report.error (m.source_reference, "\"main\" method cannot throw errors");
+- }
+-
+- // check that all errors that can be thrown in the method body are declared
+- if (m.body != null) {
+- foreach (DataType body_error_type in m.body.get_error_types ()) {
+- bool can_propagate_error = false;
+- foreach (DataType method_error_type in m.get_error_types ()) {
+- if (body_error_type.compatible (method_error_type)) {
+- can_propagate_error = true;
+- }
+- }
+- if (!can_propagate_error) {
+- Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
+- }
+- }
+- }
++ m.check (this);
+ }
+
+ public override void visit_creation_method (CreationMethod m) {
+- m.process_attributes ();
+-
+- if (m.type_name != null && m.type_name != current_symbol.name) {
+- // type_name is null for constructors generated by GIdlParser
+- Report.error (m.source_reference, "missing return type in method `%s.%s´".printf (current_symbol.get_full_name (), m.type_name));
+- m.error = true;
+- return;
+- }
+-
+- current_symbol = m;
+- current_return_type = m.return_type;
+-
+- m.accept_children (this);
+-
+- current_symbol = current_symbol.parent_symbol;
+- current_return_type = null;
+-
+- if (current_symbol.parent_symbol is Method) {
+- /* lambda expressions produce nested methods */
+- var up_method = (Method) current_symbol.parent_symbol;
+- current_return_type = up_method.return_type;
+- }
+-
+- if (m.is_abstract || m.is_virtual || m.overrides) {
+- Report.error (m.source_reference, "The creation method `%s' cannot be marked as override, virtual, or abstract".printf (m.get_full_name ()));
+- return;
+- }
++ m.check (this);
+ }
+
+ public override void visit_formal_parameter (FormalParameter p) {
+- p.process_attributes ();
+-
+ p.check (this);
+ }
+
+@@ -640,562 +204,71 @@
+ }
+
+ public override void visit_property (Property prop) {
+- prop.process_attributes ();
+-
+ prop.check (this);
+ }
+
+ public override void visit_property_accessor (PropertyAccessor acc) {
+- acc.process_attributes ();
+-
+- var old_return_type = current_return_type;
+- if (acc.readable) {
+- current_return_type = acc.prop.property_type;
+- } else {
+- // void
+- current_return_type = new VoidType ();
+- }
+-
+- if (!acc.prop.external_package) {
+- if (acc.body == null && !acc.prop.interface_only && !acc.prop.is_abstract) {
+- /* no accessor body specified, insert default body */
+-
+- if (acc.prop.parent_symbol is Interface) {
+- acc.error = true;
+- Report.error (acc.source_reference, "Automatic properties can't be used in interfaces");
+- return;
+- }
+- acc.automatic_body = true;
+- acc.body = new Block (acc.source_reference);
+- var ma = new MemberAccess.simple ("_%s".printf (acc.prop.name), acc.source_reference);
+- if (acc.readable) {
+- acc.body.add_statement (new ReturnStatement (ma, acc.source_reference));
+- } else {
+- var assignment = new Assignment (ma, new MemberAccess.simple ("value", acc.source_reference), AssignmentOperator.SIMPLE, acc.source_reference);
+- acc.body.add_statement (new ExpressionStatement (assignment));
+- }
+- }
+-
+- if (acc.body != null && (acc.writable || acc.construction)) {
+- var value_type = acc.prop.property_type.copy ();
+- acc.value_parameter = new FormalParameter ("value", value_type, acc.source_reference);
+- acc.body.scope.add (acc.value_parameter.name, acc.value_parameter);
+- }
+- }
+-
+- acc.accept_children (this);
+-
+- current_return_type = old_return_type;
++ acc.check (this);
+ }
+
+ public override void visit_signal (Signal sig) {
+- sig.process_attributes ();
+-
+- sig.accept_children (this);
++ sig.check (this);
+ }
+
+ public override void visit_constructor (Constructor c) {
+- c.this_parameter = new FormalParameter ("this", new ObjectType (current_class));
+- c.scope.add (c.this_parameter.name, c.this_parameter);
+-
+- c.owner = current_symbol.scope;
+- current_symbol = c;
+-
+- c.accept_children (this);
+-
+- foreach (DataType body_error_type in c.body.get_error_types ()) {
+- Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
+- }
+-
+- current_symbol = current_symbol.parent_symbol;
++ c.check (this);
+ }
+
+ public override void visit_destructor (Destructor d) {
+- d.owner = current_symbol.scope;
+- current_symbol = d;
+-
+- d.accept_children (this);
+-
+- current_symbol = current_symbol.parent_symbol;
++ d.check (this);
+ }
+
+ public override void visit_block (Block b) {
+- b.owner = current_symbol.scope;
+- current_symbol = b;
+-
+- b.accept_children (this);
+-
+- foreach (LocalVariable local in b.get_local_variables ()) {
+- local.active = false;
+- }
+-
+- foreach (Statement stmt in b.get_statements()) {
+- b.add_error_types (stmt.get_error_types ());
+- }
+-
+- current_symbol = current_symbol.parent_symbol;
++ b.check (this);
+ }
+
+ public override void visit_declaration_statement (DeclarationStatement stmt) {
+- var local = stmt.declaration as LocalVariable;
+- if (local != null && local.initializer != null) {
+- foreach (DataType error_type in local.initializer.get_error_types ()) {
+- // ensure we can trace back which expression may throw errors of this type
+- var initializer_error_type = error_type.copy ();
+- initializer_error_type.source_reference = local.initializer.source_reference;
+-
+- stmt.add_error_type (initializer_error_type);
+- }
+- }
++ stmt.check (this);
+ }
+
+ public override void visit_local_variable (LocalVariable local) {
+- if (local.initializer != null) {
+- local.initializer.target_type = local.variable_type;
+- }
+-
+- local.accept_children (this);
+-
+- if (local.variable_type == null) {
+- /* var type */
+-
+- if (local.initializer == null) {
+- local.error = true;
+- Report.error (local.source_reference, "var declaration not allowed without initializer");
+- return;
+- }
+- if (local.initializer.value_type == null) {
+- local.error = true;
+- Report.error (local.source_reference, "var declaration not allowed with non-typed initializer");
+- return;
+- }
+-
+- local.variable_type = local.initializer.value_type.copy ();
+- local.variable_type.value_owned = true;
+- local.variable_type.floating_reference = false;
+-
+- local.initializer.target_type = local.variable_type;
+- }
+-
+- if (local.initializer != null) {
+- if (local.initializer.value_type == null) {
+- if (!(local.initializer is MemberAccess) && !(local.initializer is LambdaExpression)) {
+- local.error = true;
+- Report.error (local.source_reference, "expression type not allowed as initializer");
+- return;
+- }
+-
+- if (local.initializer.symbol_reference is Method &&
+- local.variable_type is DelegateType) {
+- var m = (Method) local.initializer.symbol_reference;
+- var dt = (DelegateType) local.variable_type;
+- var cb = dt.delegate_symbol;
+-
+- /* check whether method matches callback type */
+- if (!cb.matches_method (m)) {
+- local.error = true;
+- Report.error (local.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
+- return;
+- }
+-
+- local.initializer.value_type = local.variable_type;
+- } else {
+- local.error = true;
+- Report.error (local.source_reference, "expression type not allowed as initializer");
+- return;
+- }
+- }
+-
+- if (!local.initializer.value_type.compatible (local.variable_type)) {
+- local.error = true;
+- Report.error (local.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (local.initializer.value_type.to_string (), local.variable_type.to_string ()));
+- return;
+- }
+-
+- if (local.initializer.value_type.is_disposable ()) {
+- /* rhs transfers ownership of the expression */
+- if (!(local.variable_type is PointerType) && !local.variable_type.value_owned) {
+- /* lhs doesn't own the value */
+- local.error = true;
+- Report.error (local.source_reference, "Invalid assignment from owned expression to unowned variable");
+- return;
+- }
+- }
+- }
+-
+- current_source_file.add_type_dependency (local.variable_type, SourceFileDependencyType.SOURCE);
+-
+- current_symbol.scope.add (local.name, local);
+-
+- var block = (Block) current_symbol;
+- block.add_local_variable (local);
+-
+- local.active = true;
++ local.check (this);
+ }
+
+- /**
+- * Visit operation called for initializer lists
+- *
+- * @param list an initializer list
+- */
+ public override void visit_initializer_list (InitializerList list) {
+- if (list.target_type == null) {
+- list.error = true;
+- Report.error (list.source_reference, "initializer list used for unknown type");
+- return;
+- } else if (list.target_type is ArrayType) {
+- /* initializer is used as array initializer */
+- var array_type = (ArrayType) list.target_type;
+-
+- foreach (Expression e in list.get_initializers ()) {
+- e.target_type = array_type.element_type.copy ();
+- }
+- } else if (list.target_type.data_type is Struct) {
+- /* initializer is used as struct initializer */
+- var st = (Struct) list.target_type.data_type;
+-
+- var field_it = st.get_fields ().iterator ();
+- foreach (Expression e in list.get_initializers ()) {
+- Field field = null;
+- while (field == null) {
+- if (!field_it.next ()) {
+- list.error = true;
+- Report.error (e.source_reference, "too many expressions in initializer list for `%s'".printf (list.target_type.to_string ()));
+- return;
+- }
+- field = field_it.get ();
+- if (field.binding != MemberBinding.INSTANCE) {
+- // we only initialize instance fields
+- field = null;
+- }
+- }
+-
+- e.target_type = field.field_type.copy ();
+- if (!list.target_type.value_owned) {
+- e.target_type.value_owned = false;
+- }
+- }
+- } else {
+- list.error = true;
+- Report.error (list.source_reference, "initializer list used for `%s', which is neither array nor struct".printf (list.target_type.to_string ()));
+- return;
+- }
+-
+- list.accept_children (this);
+-
+- bool error = false;
+- foreach (Expression e in list.get_initializers ()) {
+- if (e.value_type == null) {
+- error = true;
+- continue;
+- }
+-
+- var unary = e as UnaryExpression;
+- if (unary != null && (unary.operator == UnaryOperator.REF || unary.operator == UnaryOperator.OUT)) {
+- // TODO check type for ref and out expressions
+- } else if (!e.value_type.compatible (e.target_type)) {
+- error = true;
+- e.error = true;
+- Report.error (e.source_reference, "Expected initializer of type `%s' but got `%s'".printf (e.target_type.to_string (), e.value_type.to_string ()));
+- }
+- }
+-
+- if (!error) {
+- /* everything seems to be correct */
+- list.value_type = list.target_type;
+- }
++ list.check (this);
+ }
+
+ public override void visit_expression_statement (ExpressionStatement stmt) {
+- if (stmt.expression.error) {
+- // ignore inner error
+- stmt.error = true;
+- return;
+- }
+-
+- stmt.add_error_types (stmt.expression.get_error_types ());
++ stmt.check (this);
+ }
+
+ public override void visit_if_statement (IfStatement stmt) {
+- stmt.accept_children (this);
+-
+- if (stmt.condition.error) {
+- /* if there was an error in the condition, skip this check */
+- stmt.error = true;
+- return;
+- }
+-
+- if (!stmt.condition.value_type.compatible (bool_type)) {
+- stmt.error = true;
+- Report.error (stmt.condition.source_reference, "Condition must be boolean");
+- return;
+- }
+-
+- stmt.add_error_types (stmt.condition.get_error_types ());
+- stmt.add_error_types (stmt.true_statement.get_error_types ());
+-
+- if (stmt.false_statement != null) {
+- stmt.add_error_types (stmt.false_statement.get_error_types ());
+- }
++ stmt.check (this);
+ }
+
+ public override void visit_switch_section (SwitchSection section) {
+- foreach (SwitchLabel label in section.get_labels ()) {
+- label.accept (this);
+- }
+-
+- section.owner = current_symbol.scope;
+- current_symbol = section;
+-
+- foreach (Statement st in section.get_statements ()) {
+- st.accept (this);
+- }
+-
+- foreach (LocalVariable local in section.get_local_variables ()) {
+- local.active = false;
+- }
+-
+- current_symbol = current_symbol.parent_symbol;
++ section.check (this);
+ }
+
+ public override void visit_while_statement (WhileStatement stmt) {
+- stmt.accept_children (this);
+-
+- if (stmt.condition.error) {
+- /* if there was an error in the condition, skip this check */
+- stmt.error = true;
+- return;
+- }
+-
+- if (!stmt.condition.value_type.compatible (bool_type)) {
+- stmt.error = true;
+- Report.error (stmt.condition.source_reference, "Condition must be boolean");
+- return;
+- }
+-
+- stmt.add_error_types (stmt.condition.get_error_types ());
+- stmt.add_error_types (stmt.body.get_error_types ());
++ stmt.check (this);
+ }
+
+ public override void visit_do_statement (DoStatement stmt) {
+- stmt.accept_children (this);
+-
+- if (stmt.condition.error) {
+- /* if there was an error in the condition, skip this check */
+- stmt.error = true;
+- return;
+- }
+-
+- if (!stmt.condition.value_type.compatible (bool_type)) {
+- stmt.error = true;
+- Report.error (stmt.condition.source_reference, "Condition must be boolean");
+- return;
+- }
+-
+- stmt.add_error_types (stmt.condition.get_error_types ());
+- stmt.add_error_types (stmt.body.get_error_types ());
++ stmt.check (this);
+ }
+
+ public override void visit_for_statement (ForStatement stmt) {
+- stmt.accept_children (this);
+-
+- if (stmt.condition != null && stmt.condition.error) {
+- /* if there was an error in the condition, skip this check */
+- stmt.error = true;
+- return;
+- }
+-
+- if (stmt.condition != null && !stmt.condition.value_type.compatible (bool_type)) {
+- stmt.error = true;
+- Report.error (stmt.condition.source_reference, "Condition must be boolean");
+- return;
+- }
+-
+- if (stmt.condition != null) {
+- stmt.add_error_types (stmt.condition.get_error_types ());
+- }
+-
+- stmt.add_error_types (stmt.body.get_error_types ());
+- foreach (Expression exp in stmt.get_initializer ()) {
+- stmt.add_error_types (exp.get_error_types ());
+- }
+- foreach (Expression exp in stmt.get_iterator ()) {
+- stmt.add_error_types (exp.get_error_types ());
+- }
++ stmt.check (this);
+ }
+
+ public override void visit_foreach_statement (ForeachStatement stmt) {
+- // analyze collection expression first, used for type inference
+- stmt.collection.accept (this);
+-
+- if (stmt.collection.error) {
+- // ignore inner error
+- stmt.error = true;
+- return;
+- } else if (stmt.collection.value_type == null) {
+- Report.error (stmt.collection.source_reference, "invalid collection expression");
+- stmt.error = true;
+- return;
+- }
+-
+- var collection_type = stmt.collection.value_type.copy ();
+- stmt.collection.target_type = collection_type.copy ();
+-
+- DataType element_data_type = null;
+- bool element_owned = false;
+-
+- if (collection_type.is_array ()) {
+- var array_type = (ArrayType) collection_type;
+- element_data_type = array_type.element_type;
+- } else if (collection_type.compatible (glist_type) || collection_type.compatible (gslist_type)) {
+- if (collection_type.get_type_arguments ().size > 0) {
+- element_data_type = (DataType) collection_type.get_type_arguments ().get (0);
+- }
+- } else if (iterable_type != null && collection_type.compatible (iterable_type)) {
+- element_owned = true;
+-
+- if (list_type == null || !collection_type.compatible (new ObjectType (list_type))) {
+- // don't use iterator objects for lists for performance reasons
+- var foreach_iterator_type = new ObjectType (iterator_type);
+- foreach_iterator_type.value_owned = true;
+- foreach_iterator_type.add_type_argument (stmt.type_reference);
+- stmt.iterator_variable = new LocalVariable (foreach_iterator_type, "%s_it".printf (stmt.variable_name));
+-
+- stmt.add_local_variable (stmt.iterator_variable);
+- stmt.iterator_variable.active = true;
+- }
+-
+- var it_method = (Method) iterable_type.data_type.scope.lookup ("iterator");
+- if (it_method.return_type.get_type_arguments ().size > 0) {
+- var type_arg = it_method.return_type.get_type_arguments ().get (0);
+- if (type_arg.type_parameter != null) {
+- element_data_type = SemanticAnalyzer.get_actual_type (collection_type, it_method, type_arg, stmt);
+- } else {
+- element_data_type = type_arg;
+- }
+- }
+- } else {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Gee.List not iterable");
+- return;
+- }
+-
+- if (element_data_type == null) {
+- stmt.error = true;
+- Report.error (stmt.collection.source_reference, "missing type argument for collection");
+- return;
+- }
+-
+- // analyze element type
+- if (stmt.type_reference == null) {
+- // var type
+- stmt.type_reference = element_data_type.copy ();
+- } else if (!element_data_type.compatible (stmt.type_reference)) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Foreach: Cannot convert from `%s' to `%s'".printf (element_data_type.to_string (), stmt.type_reference.to_string ()));
+- return;
+- } else if (element_data_type.is_disposable () && element_owned && !stmt.type_reference.value_owned) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Foreach: Invalid assignment from owned expression to unowned variable");
+- return;
+- }
+-
+- current_source_file.add_type_dependency (stmt.type_reference, SourceFileDependencyType.SOURCE);
+-
+- stmt.element_variable = new LocalVariable (stmt.type_reference, stmt.variable_name);
+-
+- stmt.body.scope.add (stmt.variable_name, stmt.element_variable);
+-
+- stmt.body.add_local_variable (stmt.element_variable);
+- stmt.element_variable.active = true;
+-
+- // analyze body
+- stmt.owner = current_symbol.scope;
+- current_symbol = stmt;
+-
+- stmt.body.accept (this);
+-
+- foreach (LocalVariable local in stmt.get_local_variables ()) {
+- local.active = false;
+- }
+-
+- current_symbol = current_symbol.parent_symbol;
+-
+- stmt.collection_variable = new LocalVariable (collection_type, "%s_collection".printf (stmt.variable_name));
+-
+- stmt.add_local_variable (stmt.collection_variable);
+- stmt.collection_variable.active = true;
+-
+-
+- stmt.add_error_types (stmt.collection.get_error_types ());
+- stmt.add_error_types (stmt.body.get_error_types ());
++ stmt.check (this);
+ }
+
+ public override void visit_return_statement (ReturnStatement stmt) {
+- if (stmt.return_expression != null) {
+- stmt.return_expression.target_type = current_return_type;
+- }
+-
+- stmt.accept_children (this);
+-
+- if (stmt.return_expression != null && stmt.return_expression.error) {
+- // ignore inner error
+- stmt.error = true;
+- return;
+- }
+-
+- if (current_return_type == null) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Return not allowed in this context");
+- return;
+- }
+-
+- if (stmt.return_expression == null) {
+- if (current_return_type is VoidType) {
+- return;
+- } else {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Return without value in non-void function");
+- return;
+- }
+- }
+-
+- if (current_return_type is VoidType) {
+- Report.error (stmt.source_reference, "Return with value in void function");
+- return;
+- }
+-
+- if (stmt.return_expression.value_type == null) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Invalid expression in return value");
+- return;
+- }
+-
+- if (!stmt.return_expression.value_type.compatible (current_return_type)) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Return: Cannot convert from `%s' to `%s'".printf (stmt.return_expression.value_type.to_string (), current_return_type.to_string ()));
+- return;
+- }
+-
+- if (stmt.return_expression.value_type.is_disposable () &&
+- !current_return_type.value_owned) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
+- return;
+- }
+-
+- if (stmt.return_expression.symbol_reference is LocalVariable &&
+- stmt.return_expression.value_type.is_disposable () &&
+- !current_return_type.value_owned) {
+- 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");
+- }
+-
+- if (context.non_null && stmt.return_expression is NullLiteral
+- && !current_return_type.nullable) {
+- Report.warning (stmt.source_reference, "`null' incompatible with return type `%s`".printf (current_return_type.to_string ()));
+- }
+-
+- stmt.add_error_types (stmt.return_expression.get_error_types ());
++ stmt.check (this);
+ }
+
+ public override void visit_yield_statement (YieldStatement stmt) {
+@@ -1203,178 +276,27 @@
+ }
+
+ public override void visit_throw_statement (ThrowStatement stmt) {
+- stmt.error_expression.target_type = new ErrorType (null, null, stmt.source_reference);
+- stmt.error_expression.target_type.value_owned = true;
+-
+- stmt.accept_children (this);
+-
+- var error_type = stmt.error_expression.value_type.copy ();
+- error_type.source_reference = stmt.source_reference;
+-
+- stmt.add_error_type (error_type);
++ stmt.check (this);
+ }
+
+ public override void visit_try_statement (TryStatement stmt) {
+- stmt.accept_children (this);
++ stmt.check (this);
+ }
+
+ public override void visit_catch_clause (CatchClause clause) {
+- if (clause.error_type != null) {
+- current_source_file.add_type_dependency (clause.error_type, SourceFileDependencyType.SOURCE);
+-
+- clause.error_variable = new LocalVariable (clause.error_type.copy (), clause.variable_name);
+-
+- clause.body.scope.add (clause.variable_name, clause.error_variable);
+- clause.body.add_local_variable (clause.error_variable);
+- } else {
+- clause.error_type = new ErrorType (null, null, clause.source_reference);
+- }
+-
+- clause.accept_children (this);
++ clause.check (this);
+ }
+
+ public override void visit_lock_statement (LockStatement stmt) {
+- /* resource must be a member access and denote a Lockable */
+- if (!(stmt.resource is MemberAccess && stmt.resource.symbol_reference is Lockable)) {
+- stmt.error = true;
+- stmt.resource.error = true;
+- Report.error (stmt.resource.source_reference, "Expression is either not a member access or does not denote a lockable member");
+- return;
+- }
+-
+- /* parent symbol must be the current class */
+- if (stmt.resource.symbol_reference.parent_symbol != current_class) {
+- stmt.error = true;
+- stmt.resource.error = true;
+- Report.error (stmt.resource.source_reference, "Only members of the current class are lockable");
+- }
+-
+- ((Lockable) stmt.resource.symbol_reference).set_lock_used (true);
++ stmt.check (this);
+ }
+
+ public override void visit_delete_statement (DeleteStatement stmt) {
+- stmt.accept_children (this);
+-
+- if (stmt.expression.error) {
+- // if there was an error in the inner expression, skip this check
+- return;
+- }
+-
+- if (!(stmt.expression.value_type is PointerType)) {
+- stmt.error = true;
+- Report.error (stmt.source_reference, "delete operator not supported for `%s'".printf (stmt.expression.value_type.to_string ()));
+- }
++ stmt.check (this);
+ }
+
+- private int create_sizes_from_initializer_list (InitializerList il, int rank, Gee.List<Literal> sl) {
+- var init = new IntegerLiteral (il.size.to_string (), il.source_reference);
+- init.accept (this);
+- sl.add (init);
+-
+- int subsize = -1;
+- foreach (Expression e in il.get_initializers ()) {
+- if (e is InitializerList) {
+- if (rank == 1) {
+- il.error = true;
+- e.error = true;
+- Report.error (e.source_reference, "Expected array element, got array initializer list");
+- return -1;
+- }
+- int size = create_sizes_from_initializer_list ((InitializerList)e, rank - 1, sl);
+- if (size == -1) {
+- return -1;
+- }
+- if (subsize >= 0 && subsize != size) {
+- il.error = true;
+- Report.error (il.source_reference, "Expected initializer list of size %d, got size %d".printf (subsize, size));
+- return -1;
+- } else {
+- subsize = size;
+- }
+- } else {
+- if (rank != 1) {
+- il.error = true;
+- e.error = true;
+- Report.error (e.source_reference, "Expected array initializer list, got array element");
+- return -1;
+- }
+- }
+- }
+- return il.size;
+- }
+-
+- /**
+- * Visit operations called for array creation expresions.
+- *
+- * @param expr an array creation expression
+- */
+ public override void visit_array_creation_expression (ArrayCreationExpression expr) {
+- Gee.List<Expression> size = expr.get_sizes ();
+- var initlist = expr.initializer_list;
+-
+- if (expr.element_type != null) {
+- expr.element_type.accept (this);
+- }
+-
+- foreach (Expression e in size) {
+- e.accept (this);
+- }
+-
+- var calc_sizes = new ArrayList<Literal> ();
+- if (initlist != null) {
+- initlist.target_type = new ArrayType (expr.element_type, expr.rank, expr.source_reference);
+-
+- initlist.accept (this);
+-
+- var ret = create_sizes_from_initializer_list (initlist, expr.rank, calc_sizes);
+- if (ret == -1) {
+- expr.error = true;
+- }
+- }
+-
+- if (size.size > 0) {
+- /* check for errors in the size list */
+- foreach (Expression e in size) {
+- if (e.value_type == null) {
+- /* return on previous error */
+- return;
+- } else if (!(e.value_type.data_type is Struct) || !((Struct) e.value_type.data_type).is_integer_type ()) {
+- expr.error = true;
+- Report.error (e.source_reference, "Expression of integer type expected");
+- }
+- }
+- } else {
+- if (initlist == null) {
+- expr.error = true;
+- /* this is an internal error because it is already handeld by the parser */
+- Report.error (expr.source_reference, "internal error: initializer list expected");
+- } else {
+- foreach (Expression size in calc_sizes) {
+- expr.append_size (size);
+- }
+- }
+- }
+-
+- if (expr.error) {
+- return;
+- }
+-
+- /* check for wrong elements inside the initializer */
+- if (expr.initializer_list != null && expr.initializer_list.value_type == null) {
+- return;
+- }
+-
+- /* try to construct the type of the array */
+- if (expr.element_type == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Cannot determine the element type of the created array");
+- return;
+- }
+-
+- expr.element_type.value_owned = true;
+-
+- expr.value_type = new ArrayType (expr.element_type, expr.rank, expr.source_reference);
+- expr.value_type.value_owned = true;
++ expr.check (this);
+ }
+
+ public override void visit_boolean_literal (BooleanLiteral expr) {
+@@ -1401,7 +323,7 @@
+ expr.value_type = new NullType (expr.source_reference);
+ }
+
+- private DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
++ public DataType? get_value_type_for_symbol (Symbol sym, bool lvalue) {
+ if (sym is Field) {
+ var f = (Field) sym;
+ var type = f.field_type.copy ();
+@@ -1525,346 +447,7 @@
+ }
+
+ public override void visit_member_access (MemberAccess expr) {
+- Symbol base_symbol = null;
+- FormalParameter this_parameter = null;
+- bool may_access_instance_members = false;
+-
+- expr.symbol_reference = null;
+-
+- if (expr.qualified) {
+- base_symbol = root_symbol;
+- expr.symbol_reference = root_symbol.scope.lookup (expr.member_name);
+- } else if (expr.inner == null) {
+- if (expr.member_name == "this") {
+- if (!is_in_instance_method ()) {
+- expr.error = true;
+- Report.error (expr.source_reference, "This access invalid outside of instance methods");
+- return;
+- }
+- }
+-
+- base_symbol = current_symbol;
+-
+- var sym = current_symbol;
+- while (sym != null && expr.symbol_reference == null) {
+- if (this_parameter == null) {
+- if (sym is CreationMethod) {
+- var cm = (CreationMethod) sym;
+- this_parameter = cm.this_parameter;
+- may_access_instance_members = true;
+- } else if (sym is Property) {
+- var prop = (Property) sym;
+- this_parameter = prop.this_parameter;
+- may_access_instance_members = true;
+- } else if (sym is Constructor) {
+- var c = (Constructor) sym;
+- this_parameter = c.this_parameter;
+- may_access_instance_members = true;
+- } else if (sym is Destructor) {
+- var d = (Destructor) sym;
+- this_parameter = d.this_parameter;
+- may_access_instance_members = true;
+- } else if (sym is Method) {
+- var m = (Method) sym;
+- this_parameter = m.this_parameter;
+- may_access_instance_members = (m.binding == MemberBinding.INSTANCE);
+- }
+- }
+-
+- expr.symbol_reference = symbol_lookup_inherited (sym, expr.member_name);
+- sym = sym.parent_symbol;
+- }
+-
+- if (expr.symbol_reference == null) {
+- foreach (UsingDirective ns in current_using_directives) {
+- var local_sym = ns.namespace_symbol.scope.lookup (expr.member_name);
+- if (local_sym != null) {
+- if (expr.symbol_reference != null) {
+- expr.error = true;
+- 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 ()));
+- return;
+- }
+- expr.symbol_reference = local_sym;
+- }
+- }
+- }
+- } else {
+- if (expr.inner.error) {
+- /* if there was an error in the inner expression, skip this check */
+- expr.error = true;
+- return;
+- }
+-
+- if (expr.pointer_member_access) {
+- var pointer_type = expr.inner.value_type as PointerType;
+- if (pointer_type != null && pointer_type.base_type is ValueType) {
+- // transform foo->bar to (*foo).bar
+- expr.inner = new PointerIndirection (expr.inner, expr.source_reference);
+- expr.inner.accept (this);
+- expr.pointer_member_access = false;
+- }
+- }
+-
+- if (expr.inner is MemberAccess) {
+- var ma = (MemberAccess) expr.inner;
+- if (ma.prototype_access) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Access to instance member `%s' denied".printf (expr.inner.symbol_reference.get_full_name ()));
+- return;
+- }
+- }
+-
+- if (expr.inner is MemberAccess || expr.inner is BaseAccess) {
+- base_symbol = expr.inner.symbol_reference;
+-
+- if (expr.symbol_reference == null && (base_symbol is Namespace || base_symbol is TypeSymbol)) {
+- expr.symbol_reference = base_symbol.scope.lookup (expr.member_name);
+- if (expr.inner is BaseAccess) {
+- // inner expression is base access
+- // access to instance members of the base type possible
+- may_access_instance_members = true;
+- }
+- }
+- }
+-
+- if (expr.symbol_reference == null && expr.inner.value_type != null) {
+- if (expr.pointer_member_access) {
+- expr.symbol_reference = expr.inner.value_type.get_pointer_member (expr.member_name);
+- } else {
+- if (expr.inner.value_type.data_type != null) {
+- base_symbol = expr.inner.value_type.data_type;
+- }
+- expr.symbol_reference = expr.inner.value_type.get_member (expr.member_name);
+- }
+- if (expr.symbol_reference != null) {
+- // inner expression is variable, field, or parameter
+- // access to instance members of the corresponding type possible
+- may_access_instance_members = true;
+- }
+- }
+-
+- if (expr.symbol_reference == null && expr.inner.value_type != null && expr.inner.value_type.is_dynamic) {
+- // allow late bound members for dynamic types
+- var dynamic_object_type = (ObjectType) expr.inner.value_type;
+- if (expr.parent_node is InvocationExpression) {
+- var invoc = (InvocationExpression) expr.parent_node;
+- if (invoc.call == expr) {
+- // dynamic method
+- DataType ret_type;
+- if (invoc.target_type != null) {
+- ret_type = invoc.target_type.copy ();
+- ret_type.value_owned = true;
+- } else if (invoc.parent_node is ExpressionStatement) {
+- ret_type = new VoidType ();
+- } else {
+- // expect dynamic object of the same type
+- ret_type = expr.inner.value_type.copy ();
+- }
+- var m = new DynamicMethod (expr.inner.value_type, expr.member_name, ret_type, expr.source_reference);
+- m.invocation = invoc;
+- m.add_error_type (new ErrorType (null, null));
+- m.access = SymbolAccessibility.PUBLIC;
+- m.add_parameter (new FormalParameter.with_ellipsis ());
+- dynamic_object_type.type_symbol.scope.add (null, m);
+- expr.symbol_reference = m;
+- }
+- } else if (expr.parent_node is Assignment) {
+- var a = (Assignment) expr.parent_node;
+- if (a.left == expr
+- && (a.operator == AssignmentOperator.ADD
+- || a.operator == AssignmentOperator.SUB)) {
+- // dynamic signal
+- var s = new DynamicSignal (expr.inner.value_type, expr.member_name, new VoidType (), expr.source_reference);
+- s.handler = a.right;
+- s.access = SymbolAccessibility.PUBLIC;
+- dynamic_object_type.type_symbol.scope.add (null, s);
+- expr.symbol_reference = s;
+- } else if (a.left == expr) {
+- // dynamic property assignment
+- var prop = new DynamicProperty (expr.inner.value_type, expr.member_name, expr.source_reference);
+- prop.access = SymbolAccessibility.PUBLIC;
+- prop.set_accessor = new PropertyAccessor (false, true, false, null, null);
+- prop.set_accessor.access = SymbolAccessibility.PUBLIC;
+- prop.owner = expr.inner.value_type.data_type.scope;
+- dynamic_object_type.type_symbol.scope.add (null, prop);
+- expr.symbol_reference = prop;
+- }
+- }
+- if (expr.symbol_reference == null) {
+- // dynamic property read access
+- var prop = new DynamicProperty (expr.inner.value_type, expr.member_name, expr.source_reference);
+- if (expr.target_type != null) {
+- prop.property_type = expr.target_type;
+- } else {
+- // expect dynamic object of the same type
+- prop.property_type = expr.inner.value_type.copy ();
+- }
+- prop.access = SymbolAccessibility.PUBLIC;
+- prop.get_accessor = new PropertyAccessor (true, false, false, null, null);
+- prop.get_accessor.access = SymbolAccessibility.PUBLIC;
+- prop.owner = expr.inner.value_type.data_type.scope;
+- dynamic_object_type.type_symbol.scope.add (null, prop);
+- expr.symbol_reference = prop;
+- }
+- if (expr.symbol_reference != null) {
+- may_access_instance_members = true;
+- }
+- }
+- }
+-
+- if (expr.symbol_reference == null) {
+- expr.error = true;
+-
+- string base_type_name = "(null)";
+- if (expr.inner != null && expr.inner.value_type != null) {
+- base_type_name = expr.inner.value_type.to_string ();
+- } else if (base_symbol != null) {
+- base_type_name = base_symbol.get_full_name ();
+- }
+-
+- Report.error (expr.source_reference, "The name `%s' does not exist in the context of `%s'".printf (expr.member_name, base_type_name));
+- return;
+- }
+-
+- var member = expr.symbol_reference;
+- var access = SymbolAccessibility.PUBLIC;
+- bool instance = false;
+- bool klass = false;
+- if (member is Field) {
+- var f = (Field) member;
+- access = f.access;
+- instance = (f.binding == MemberBinding.INSTANCE);
+- klass = (f.binding == MemberBinding.CLASS);
+- } else if (member is Method) {
+- var m = (Method) member;
+- access = m.access;
+- if (!(m is CreationMethod)) {
+- instance = (m.binding == MemberBinding.INSTANCE);
+- }
+- klass = (m.binding == MemberBinding.CLASS);
+- } else if (member is Property) {
+- var prop = (Property) member;
+- if (!prop.check (this)) {
+- expr.error = true;
+- return;
+- }
+- access = prop.access;
+- if (expr.lvalue) {
+- if (prop.set_accessor == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
+- return;
+- }
+- if (prop.access == SymbolAccessibility.PUBLIC) {
+- access = prop.set_accessor.access;
+- } else if (prop.access == SymbolAccessibility.PROTECTED
+- && prop.set_accessor.access != SymbolAccessibility.PUBLIC) {
+- access = prop.set_accessor.access;
+- }
+- } else {
+- if (prop.get_accessor == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Property `%s' is write-only".printf (prop.get_full_name ()));
+- return;
+- }
+- if (prop.access == SymbolAccessibility.PUBLIC) {
+- access = prop.get_accessor.access;
+- } else if (prop.access == SymbolAccessibility.PROTECTED
+- && prop.get_accessor.access != SymbolAccessibility.PUBLIC) {
+- access = prop.get_accessor.access;
+- }
+- }
+- instance = (prop.binding == MemberBinding.INSTANCE);
+- } else if (member is Signal) {
+- instance = true;
+- }
+-
+- if (access == SymbolAccessibility.PRIVATE) {
+- var target_type = member.parent_symbol;
+-
+- bool in_target_type = false;
+- for (Symbol this_symbol = current_symbol; this_symbol != null; this_symbol = this_symbol.parent_symbol) {
+- if (target_type == this_symbol) {
+- in_target_type = true;
+- break;
+- }
+- }
+-
+- if (!in_target_type) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Access to private member `%s' denied".printf (member.get_full_name ()));
+- return;
+- }
+- }
+- if ((instance || klass) && !may_access_instance_members) {
+- expr.prototype_access = true;
+-
+- if (expr.symbol_reference is Method) {
+- // also set static type for prototype access
+- // required when using instance methods as delegates in constants
+- // TODO replace by MethodPrototype
+- expr.value_type = get_value_type_for_symbol (expr.symbol_reference, expr.lvalue);
+- } else if (expr.symbol_reference is Field) {
+- expr.value_type = new FieldPrototype ((Field) expr.symbol_reference);
+- }
+- } else {
+- // implicit this access
+- if (instance && expr.inner == null) {
+- expr.inner = new MemberAccess (null, "this", expr.source_reference);
+- expr.inner.value_type = this_parameter.parameter_type.copy ();
+- expr.inner.symbol_reference = this_parameter;
+- }
+-
+- expr.value_type = get_value_type_for_symbol (expr.symbol_reference, expr.lvalue);
+-
+- // resolve generic return values
+- if (expr.value_type != null && expr.value_type.type_parameter != null) {
+- if (expr.inner != null) {
+- expr.value_type = get_actual_type (expr.inner.value_type, expr.symbol_reference, expr.value_type, expr);
+- if (expr.value_type == null) {
+- return;
+- }
+- }
+- }
+-
+- if (expr.symbol_reference is Method) {
+- var m = (Method) expr.symbol_reference;
+-
+- Method base_method;
+- if (m.base_method != null) {
+- base_method = m.base_method;
+- } else if (m.base_interface_method != null) {
+- base_method = m.base_interface_method;
+- } else {
+- base_method = m;
+- }
+-
+- if (instance && base_method.parent_symbol != null) {
+- expr.inner.target_type = get_data_type_for_symbol ((TypeSymbol) base_method.parent_symbol);
+- }
+- } else if (expr.symbol_reference is Property) {
+- var prop = (Property) expr.symbol_reference;
+-
+- Property base_property;
+- if (prop.base_property != null) {
+- base_property = prop.base_property;
+- } else if (prop.base_interface_property != null) {
+- base_property = prop.base_interface_property;
+- } else {
+- base_property = prop;
+- }
+-
+- if (instance && base_property.parent_symbol != null) {
+- expr.inner.target_type = get_data_type_for_symbol ((TypeSymbol) base_property.parent_symbol);
+- }
+- } else if ((expr.symbol_reference is Field
+- || expr.symbol_reference is Signal)
+- && instance && expr.symbol_reference.parent_symbol != null) {
+- expr.inner.target_type = get_data_type_for_symbol ((TypeSymbol) expr.symbol_reference.parent_symbol);
+- }
+- }
+-
+- current_source_file.add_symbol_dependency (expr.symbol_reference, SourceFileDependencyType.SOURCE);
++ expr.check (this);
+ }
+
+ public static DataType get_data_type_for_symbol (TypeSymbol sym) {
+@@ -1889,300 +472,10 @@
+ }
+
+ public override void visit_invocation_expression (InvocationExpression expr) {
+- expr.call.accept (this);
+-
+- if (expr.call.error) {
+- /* if method resolving didn't succeed, skip this check */
+- expr.error = true;
+- return;
+- }
+-
+- if (expr.call is MemberAccess) {
+- var ma = (MemberAccess) expr.call;
+- if (ma.prototype_access) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Access to instance member `%s' denied".printf (expr.call.symbol_reference.get_full_name ()));
+- return;
+- }
+- }
+-
+- var mtype = expr.call.value_type;
+-
+- if (mtype is ObjectType) {
+- // constructor chain-up
+- var cm = find_current_method () as CreationMethod;
+- assert (cm != null);
+- if (cm.chain_up) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Multiple constructor calls in the same constructor are not permitted");
+- return;
+- }
+- cm.chain_up = true;
+- }
+-
+- // check for struct construction
+- if (expr.call is MemberAccess &&
+- ((expr.call.symbol_reference is CreationMethod
+- && expr.call.symbol_reference.parent_symbol is Struct)
+- || expr.call.symbol_reference is Struct)) {
+- var struct_creation_expression = new ObjectCreationExpression ((MemberAccess) expr.call, expr.source_reference);
+- struct_creation_expression.struct_creation = true;
+- foreach (Expression arg in expr.get_argument_list ()) {
+- struct_creation_expression.add_argument (arg);
+- }
+- struct_creation_expression.target_type = expr.target_type;
+- replaced_nodes.add (expr);
+- expr.parent_node.replace_expression (expr, struct_creation_expression);
+- struct_creation_expression.accept (this);
+- return;
+- } else if (expr.call is MemberAccess
+- && expr.call.symbol_reference is CreationMethod) {
+- // constructor chain-up
+- var cm = find_current_method () as CreationMethod;
+- assert (cm != null);
+- if (cm.chain_up) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Multiple constructor calls in the same constructor are not permitted");
+- return;
+- }
+- cm.chain_up = true;
+- }
+-
+- Gee.List<FormalParameter> params;
+-
+- if (mtype != null && mtype.is_invokable ()) {
+- params = mtype.get_parameters ();
+- } else {
+- expr.error = true;
+- Report.error (expr.source_reference, "invocation not supported in this context");
+- return;
+- }
+-
+- Expression last_arg = null;
+-
+- var args = expr.get_argument_list ();
+- Iterator<Expression> arg_it = args.iterator ();
+- foreach (FormalParameter param in params) {
+- if (param.ellipsis) {
+- break;
+- }
+-
+- if (arg_it.next ()) {
+- Expression arg = arg_it.get ();
+-
+- /* store expected type for callback parameters */
+- arg.target_type = param.parameter_type;
+-
+- // resolve generic type parameters
+- var ma = expr.call as MemberAccess;
+- if (arg.target_type.type_parameter != null) {
+- if (ma != null && ma.inner != null) {
+- arg.target_type = get_actual_type (ma.inner.value_type, ma.symbol_reference, arg.target_type, arg);
+- assert (arg.target_type != null);
+- }
+- }
+-
+- last_arg = arg;
+- }
+- }
+-
+- // printf arguments
+- if (mtype is MethodType && ((MethodType) mtype).method_symbol.printf_format) {
+- StringLiteral format_literal = null;
+- if (last_arg != null) {
+- // use last argument as format string
+- format_literal = last_arg as StringLiteral;
+- } else {
+- // use instance as format string for string.printf (...)
+- var ma = expr.call as MemberAccess;
+- if (ma != null) {
+- format_literal = ma.inner as StringLiteral;
+- }
+- }
+- if (format_literal != null) {
+- string format = format_literal.eval ();
+-
+- bool unsupported_format = false;
+-
+- weak string format_it = format;
+- unichar c = format_it.get_char ();
+- while (c != '\0') {
+- if (c != '%') {
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- continue;
+- }
+-
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- // flags
+- while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- }
+- // field width
+- while (c >= '0' && c <= '9') {
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- }
+- // precision
+- if (c == '.') {
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- while (c >= '0' && c <= '9') {
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- }
+- }
+- // length modifier
+- int length = 0;
+- if (c == 'h') {
+- length = -1;
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- if (c == 'h') {
+- length = -2;
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- }
+- } else if (c == 'l') {
+- length = 1;
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- } else if (c == 'z') {
+- length = 2;
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- }
+- // conversion specifier
+- DataType param_type = null;
+- if (c == 'd' || c == 'i' || c == 'c') {
+- // integer
+- if (length == -2) {
+- param_type = int8_type;
+- } else if (length == -1) {
+- param_type = short_type;
+- } else if (length == 0) {
+- param_type = int_type;
+- } else if (length == 1) {
+- param_type = long_type;
+- } else if (length == 2) {
+- param_type = ssize_t_type;
+- }
+- } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
+- // unsigned integer
+- if (length == -2) {
+- param_type = uchar_type;
+- } else if (length == -1) {
+- param_type = ushort_type;
+- } else if (length == 0) {
+- param_type = uint_type;
+- } else if (length == 1) {
+- param_type = ulong_type;
+- } else if (length == 2) {
+- param_type = size_t_type;
+- }
+- } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
+- || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
+- // double
+- param_type = double_type;
+- } else if (c == 's') {
+- // string
+- param_type = string_type;
+- } else if (c == 'p') {
+- // pointer
+- param_type = new PointerType (new VoidType ());
+- } else if (c == '%') {
+- // literal %
+- } else {
+- unsupported_format = true;
+- break;
+- }
+- if (c != '\0') {
+- format_it = format_it.next_char ();
+- c = format_it.get_char ();
+- }
+- if (param_type != null) {
+- if (arg_it.next ()) {
+- Expression arg = arg_it.get ();
+-
+- arg.target_type = param_type;
+- } else {
+- Report.error (expr.source_reference, "Too few arguments for specified format");
+- return;
+- }
+- }
+- }
+- if (!unsupported_format && arg_it.next ()) {
+- Report.error (expr.source_reference, "Too many arguments for specified format");
+- return;
+- }
+- }
+- }
+-
+- foreach (Expression arg in expr.get_argument_list ()) {
+- arg.accept (this);
+- }
+-
+- DataType ret_type;
+-
+- ret_type = mtype.get_return_type ();
+- params = mtype.get_parameters ();
+-
+- if (ret_type is VoidType) {
+- // void return type
+- if (!(expr.parent_node is ExpressionStatement)
+- && !(expr.parent_node is ForStatement)
+- && !(expr.parent_node is YieldStatement)) {
+- // A void method invocation can be in the initializer or
+- // iterator of a for statement
+- expr.error = true;
+- Report.error (expr.source_reference, "invocation of void method not allowed as expression");
+- return;
+- }
+- }
+-
+- // resolve generic return values
+- var ma = expr.call as MemberAccess;
+- if (ret_type.type_parameter != null) {
+- if (ma != null && ma.inner != null) {
+- ret_type = get_actual_type (ma.inner.value_type, ma.symbol_reference, ret_type, expr);
+- if (ret_type == null) {
+- return;
+- }
+- }
+- }
+- Gee.List<DataType> resolved_type_args = new ArrayList<DataType> ();
+- foreach (DataType type_arg in ret_type.get_type_arguments ()) {
+- if (type_arg.type_parameter != null && ma != null && ma.inner != null) {
+- resolved_type_args.add (get_actual_type (ma.inner.value_type, ma.symbol_reference, type_arg, expr));
+- } else {
+- resolved_type_args.add (type_arg);
+- }
+- }
+- ret_type = ret_type.copy ();
+- ret_type.remove_all_type_arguments ();
+- foreach (DataType resolved_type_arg in resolved_type_args) {
+- ret_type.add_type_argument (resolved_type_arg);
+- }
+-
+- if (mtype is MethodType) {
+- var m = ((MethodType) mtype).method_symbol;
+- foreach (DataType error_type in m.get_error_types ()) {
+- // ensure we can trace back which expression may throw errors of this type
+- var call_error_type = error_type.copy ();
+- call_error_type.source_reference = expr.source_reference;
+-
+- expr.add_error_type (call_error_type);
+- }
+- }
+-
+- expr.value_type = ret_type;
+-
+- check_arguments (expr, mtype, params, expr.get_argument_list ());
++ expr.check (this);
+ }
+
+- private bool check_arguments (Expression expr, DataType mtype, Gee.List<FormalParameter> params, Gee.List<Expression> args) {
++ public bool check_arguments (Expression expr, DataType mtype, Gee.List<FormalParameter> params, Gee.List<Expression> args) {
+ Expression prev_arg = null;
+ Iterator<Expression> arg_it = args.iterator ();
+
+@@ -2480,121 +773,10 @@
+ }
+
+ public override void visit_element_access (ElementAccess expr) {
+- expr.container.accept (this);
+-
+- if (expr.container.value_type == null) {
+- /* don't proceed if a child expression failed */
+- expr.error = true;
+- return;
+- }
+-
+- var container_type = expr.container.value_type.data_type;
+-
+- if (expr.container is MemberAccess && expr.container.symbol_reference is Signal) {
+- // signal detail access
+- if (expr.get_indices ().size != 1) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Element access with more than one dimension is not supported for signals");
+- return;
+- }
+- expr.get_indices ().get (0).target_type = string_type.copy ();
+- }
+-
+- foreach (Expression index in expr.get_indices ()) {
+- index.accept (this);
+- }
+-
+- bool index_int_type_check = true;
+-
+- var pointer_type = expr.container.value_type as PointerType;
+-
+- /* assign a value_type when possible */
+- if (expr.container.value_type is ArrayType) {
+- var array_type = (ArrayType) expr.container.value_type;
+- expr.value_type = array_type.element_type.copy ();
+- if (!expr.lvalue) {
+- expr.value_type.value_owned = false;
+- }
+- } else if (pointer_type != null && !pointer_type.base_type.is_reference_type_or_type_parameter ()) {
+- expr.value_type = pointer_type.base_type.copy ();
+- } else if (container_type == string_type.data_type) {
+- if (expr.get_indices ().size != 1) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Element access with more than one dimension is not supported for strings");
+- return;
+- }
+-
+- expr.value_type = unichar_type;
+- } else if (container_type != null && list_type != null && map_type != null &&
+- (container_type.is_subtype_of (list_type) || container_type.is_subtype_of (map_type))) {
+- Gee.List<Expression> indices = expr.get_indices ();
+- if (indices.size != 1) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Element access with more than one dimension is not supported for the specified type");
+- return;
+- }
+- Iterator<Expression> indices_it = indices.iterator ();
+- indices_it.next ();
+- var index = indices_it.get ();
+- index_int_type_check = false;
+-
+- // lookup symbol in interface instead of class as implemented interface methods are not in VAPI files
+- Symbol get_sym = null;
+- if (container_type.is_subtype_of (list_type)) {
+- get_sym = list_type.scope.lookup ("get");
+- } else if (container_type.is_subtype_of (map_type)) {
+- get_sym = map_type.scope.lookup ("get");
+- }
+- var get_method = (Method) get_sym;
+- Gee.List<FormalParameter> get_params = get_method.get_parameters ();
+- Iterator<FormalParameter> get_params_it = get_params.iterator ();
+- get_params_it.next ();
+- var get_param = get_params_it.get ();
+-
+- var index_type = get_param.parameter_type;
+- if (index_type.type_parameter != null) {
+- index_type = get_actual_type (expr.container.value_type, get_method, get_param.parameter_type, expr);
+- }
+-
+- if (!index.value_type.compatible (index_type)) {
+- expr.error = true;
+- Report.error (expr.source_reference, "index expression: Cannot convert from `%s' to `%s'".printf (index.value_type.to_string (), index_type.to_string ()));
+- return;
+- }
+-
+- expr.value_type = get_actual_type (expr.container.value_type, get_method, get_method.return_type, expr).copy ();
+- if (expr.lvalue) {
+- // get () returns owned value, set () accepts unowned value
+- expr.value_type.value_owned = false;
+- }
+- } else if (expr.container is MemberAccess && expr.container.symbol_reference is Signal) {
+- index_int_type_check = false;
+-
+- expr.symbol_reference = expr.container.symbol_reference;
+- expr.value_type = expr.container.value_type;
+- } else {
+- expr.error = true;
+- Report.error (expr.source_reference, "The expression `%s' does not denote an Array".printf (expr.container.value_type.to_string ()));
+- }
+-
+- if (index_int_type_check) {
+- /* check if the index is of type integer */
+- foreach (Expression e in expr.get_indices ()) {
+- /* don't proceed if a child expression failed */
+- if (e.value_type == null) {
+- return;
+- }
+-
+- /* check if the index is of type integer */
+- if (!(e.value_type.data_type is Struct) || !((Struct) e.value_type.data_type).is_integer_type ()) {
+- expr.error = true;
+- Report.error (e.source_reference, "Expression of integer type expected");
+- }
+- }
+- }
++ expr.check (this);
+ }
+
+- private bool is_in_instance_method () {
++ public bool is_in_instance_method () {
+ var sym = current_symbol;
+ while (sym != null) {
+ if (sym is CreationMethod) {
+@@ -2652,195 +834,10 @@
+ }
+
+ public override void visit_object_creation_expression (ObjectCreationExpression expr) {
+- if (expr.member_name != null) {
+- expr.member_name.accept (this);
+- }
+-
+- TypeSymbol type = null;
+-
+- if (expr.type_reference == null) {
+- if (expr.member_name == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Incomplete object creation expression");
+- return;
+- }
+-
+- if (expr.member_name.symbol_reference == null) {
+- expr.error = true;
+- return;
+- }
+-
+- var constructor_sym = expr.member_name.symbol_reference;
+- var type_sym = expr.member_name.symbol_reference;
+-
+- var type_args = expr.member_name.get_type_arguments ();
+-
+- if (constructor_sym is Method) {
+- type_sym = constructor_sym.parent_symbol;
+-
+- var constructor = (Method) constructor_sym;
+- if (!(constructor_sym is CreationMethod)) {
+- expr.error = true;
+- Report.error (expr.source_reference, "`%s' is not a creation method".printf (constructor.get_full_name ()));
+- return;
+- }
+-
+- expr.symbol_reference = constructor;
+-
+- // inner expression can also be base access when chaining constructors
+- var ma = expr.member_name.inner as MemberAccess;
+- if (ma != null) {
+- type_args = ma.get_type_arguments ();
+- }
+- }
+-
+- if (type_sym is Class) {
+- type = (TypeSymbol) type_sym;
+- expr.type_reference = new ObjectType ((Class) type);
+- } else if (type_sym is Struct) {
+- type = (TypeSymbol) type_sym;
+- expr.type_reference = new ValueType (type);
+- } else if (type_sym is ErrorCode) {
+- expr.type_reference = new ErrorType ((ErrorDomain) type_sym.parent_symbol, (ErrorCode) type_sym, expr.source_reference);
+- expr.symbol_reference = type_sym;
+- } else {
+- expr.error = true;
+- Report.error (expr.source_reference, "`%s' is not a class, struct, or error code".printf (type_sym.get_full_name ()));
+- return;
+- }
+-
+- foreach (DataType type_arg in type_args) {
+- expr.type_reference.add_type_argument (type_arg);
+-
+- current_source_file.add_type_dependency (type_arg, SourceFileDependencyType.SOURCE);
+- }
+- } else {
+- type = expr.type_reference.data_type;
+- }
+-
+- current_source_file.add_symbol_dependency (type, SourceFileDependencyType.SOURCE);
+-
+- expr.value_type = expr.type_reference.copy ();
+- expr.value_type.value_owned = true;
+-
+- int given_num_type_args = expr.type_reference.get_type_arguments ().size;
+- int expected_num_type_args = 0;
+-
+- if (type is Class) {
+- var cl = (Class) type;
+-
+- expected_num_type_args = cl.get_type_parameters ().size;
+-
+- if (expr.struct_creation) {
+- expr.error = true;
+- Report.error (expr.source_reference, "syntax error, use `new' to create new objects");
+- return;
+- }
+-
+- if (cl.is_abstract) {
+- expr.value_type = null;
+- expr.error = true;
+- Report.error (expr.source_reference, "Can't create instance of abstract class `%s'".printf (cl.get_full_name ()));
+- return;
+- }
+-
+- if (expr.symbol_reference == null) {
+- expr.symbol_reference = cl.default_construction_method;
+- }
+-
+- while (cl != null) {
+- if (cl == initially_unowned_type) {
+- expr.value_type.floating_reference = true;
+- break;
+- }
+-
+- cl = cl.base_class;
+- }
+- } else if (type is Struct) {
+- var st = (Struct) type;
+-
+- expected_num_type_args = st.get_type_parameters ().size;
+-
+- if (!expr.struct_creation) {
+- Report.warning (expr.source_reference, "deprecated syntax, don't use `new' to initialize structs");
+- }
+-
+- if (expr.symbol_reference == null) {
+- expr.symbol_reference = st.default_construction_method;
+- }
+- }
+-
+- if (expected_num_type_args > given_num_type_args) {
+- expr.error = true;
+- Report.error (expr.source_reference, "too few type arguments");
+- return;
+- } else if (expected_num_type_args < given_num_type_args) {
+- expr.error = true;
+- Report.error (expr.source_reference, "too many type arguments");
+- return;
+- }
+-
+- if (expr.symbol_reference == null && expr.get_argument_list ().size != 0) {
+- expr.value_type = null;
+- expr.error = true;
+- Report.error (expr.source_reference, "No arguments allowed when constructing type `%s'".printf (type.get_full_name ()));
+- return;
+- }
+-
+- if (expr.symbol_reference is Method) {
+- var m = (Method) expr.symbol_reference;
+-
+- var args = expr.get_argument_list ();
+- Iterator<Expression> arg_it = args.iterator ();
+- foreach (FormalParameter param in m.get_parameters ()) {
+- if (param.ellipsis) {
+- break;
+- }
+-
+- if (arg_it.next ()) {
+- Expression arg = arg_it.get ();
+-
+- /* store expected type for callback parameters */
+- arg.target_type = param.parameter_type;
+- }
+- }
+-
+- foreach (Expression arg in args) {
+- arg.accept (this);
+- }
+-
+- check_arguments (expr, new MethodType (m), m.get_parameters (), args);
+-
+- foreach (DataType error_type in m.get_error_types ()) {
+- // ensure we can trace back which expression may throw errors of this type
+- var call_error_type = error_type.copy ();
+- call_error_type.source_reference = expr.source_reference;
+-
+- expr.add_error_type (call_error_type);
+- }
+- } else if (expr.type_reference is ErrorType) {
+- expr.accept_children (this);
+-
+- if (expr.get_argument_list ().size == 0) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Too few arguments, errors need at least 1 argument");
+- } else {
+- Iterator<Expression> arg_it = expr.get_argument_list ().iterator ();
+- arg_it.next ();
+- var ex = arg_it.get ();
+- if (ex.value_type == null || !ex.value_type.compatible (string_type)) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Invalid type for argument 1");
+- }
+- }
+- }
+-
+- foreach (MemberInitializer init in expr.get_object_initializer ()) {
+- visit_member_initializer (init, expr.type_reference);
+- }
++ expr.check (this);
+ }
+
+- void visit_member_initializer (MemberInitializer init, DataType type) {
++ public void visit_member_initializer (MemberInitializer init, DataType type) {
+ init.accept (this);
+
+ init.symbol_reference = symbol_lookup_inherited (type.data_type, init.name);
+@@ -3084,7 +1081,7 @@
+ expr.value_type.value_owned = true;
+ }
+
+- private DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
++ public DataType? get_arithmetic_result_type (DataType left_type, DataType right_type) {
+ if (!(left_type.data_type is Struct) || !(right_type.data_type is Struct)) {
+ // at least one operand not struct
+ return null;
+@@ -3117,158 +1114,7 @@
+ }
+
+ public override void visit_binary_expression (BinaryExpression expr) {
+- if (expr.left.error || expr.right.error) {
+- /* if there were any errors in inner expressions, skip type check */
+- expr.error = true;
+- return;
+- }
+-
+- if (expr.left.value_type == null) {
+- Report.error (expr.left.source_reference, "invalid left operand");
+- expr.error = true;
+- return;
+- }
+-
+- if (expr.operator != BinaryOperator.IN && expr.right.value_type == null) {
+- Report.error (expr.right.source_reference, "invalid right operand");
+- expr.error = true;
+- return;
+- }
+-
+- if (expr.left.value_type.data_type == string_type.data_type
+- && expr.operator == BinaryOperator.PLUS) {
+- // string concatenation
+-
+- if (expr.right.value_type == null || expr.right.value_type.data_type != string_type.data_type) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Operands must be strings");
+- return;
+- }
+-
+- expr.value_type = string_type.copy ();
+- if (expr.left.is_constant () && expr.right.is_constant ()) {
+- expr.value_type.value_owned = false;
+- } else {
+- expr.value_type.value_owned = true;
+- }
+- } else if (expr.operator == BinaryOperator.PLUS
+- || expr.operator == BinaryOperator.MINUS
+- || expr.operator == BinaryOperator.MUL
+- || expr.operator == BinaryOperator.DIV) {
+- // check for pointer arithmetic
+- if (expr.left.value_type is PointerType) {
+- var offset_type = expr.right.value_type.data_type as Struct;
+- if (offset_type != null && offset_type.is_integer_type ()) {
+- if (expr.operator == BinaryOperator.PLUS
+- || expr.operator == BinaryOperator.MINUS) {
+- // pointer arithmetic: pointer +/- offset
+- expr.value_type = expr.left.value_type.copy ();
+- }
+- } else if (expr.right.value_type is PointerType) {
+- // pointer arithmetic: pointer - pointer
+- expr.value_type = size_t_type;
+- }
+- }
+-
+- if (expr.value_type == null) {
+- expr.value_type = get_arithmetic_result_type (expr.left.value_type, expr.right.value_type);
+- }
+-
+- if (expr.value_type == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr.left.value_type.to_string (), expr.right.value_type.to_string ()));
+- return;
+- }
+- } else if (expr.operator == BinaryOperator.MOD
+- || expr.operator == BinaryOperator.SHIFT_LEFT
+- || expr.operator == BinaryOperator.SHIFT_RIGHT
+- || expr.operator == BinaryOperator.BITWISE_XOR) {
+- expr.value_type = get_arithmetic_result_type (expr.left.value_type, expr.right.value_type);
+-
+- if (expr.value_type == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Arithmetic operation not supported for types `%s' and `%s'".printf (expr.left.value_type.to_string (), expr.right.value_type.to_string ()));
+- return;
+- }
+- } else if (expr.operator == BinaryOperator.LESS_THAN
+- || expr.operator == BinaryOperator.GREATER_THAN
+- || expr.operator == BinaryOperator.LESS_THAN_OR_EQUAL
+- || expr.operator == BinaryOperator.GREATER_THAN_OR_EQUAL) {
+- if (expr.left.value_type.compatible (string_type)
+- && expr.right.value_type.compatible (string_type)) {
+- // string comparison
+- } else if (expr.left.value_type is PointerType && expr.right.value_type is PointerType) {
+- // pointer arithmetic
+- } else {
+- var resulting_type = get_arithmetic_result_type (expr.left.value_type, expr.right.value_type);
+-
+- if (resulting_type == null) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Relational operation not supported for types `%s' and `%s'".printf (expr.left.value_type.to_string (), expr.right.value_type.to_string ()));
+- return;
+- }
+- }
+-
+- expr.value_type = bool_type;
+- } else if (expr.operator == BinaryOperator.EQUALITY
+- || expr.operator == BinaryOperator.INEQUALITY) {
+- /* relational operation */
+-
+- if (!expr.right.value_type.compatible (expr.left.value_type)
+- && !expr.left.value_type.compatible (expr.right.value_type)) {
+- Report.error (expr.source_reference, "Equality operation: `%s' and `%s' are incompatible".printf (expr.right.value_type.to_string (), expr.left.value_type.to_string ()));
+- expr.error = true;
+- return;
+- }
+-
+- if (expr.left.value_type.compatible (string_type)
+- && expr.right.value_type.compatible (string_type)) {
+- // string comparison
+- }
+-
+- expr.value_type = bool_type;
+- } else if (expr.operator == BinaryOperator.BITWISE_AND
+- || expr.operator == BinaryOperator.BITWISE_OR) {
+- // integer type or flags type
+-
+- expr.value_type = expr.left.value_type;
+- } else if (expr.operator == BinaryOperator.AND
+- || expr.operator == BinaryOperator.OR) {
+- if (!expr.left.value_type.compatible (bool_type) || !expr.right.value_type.compatible (bool_type)) {
+- expr.error = true;
+- Report.error (expr.source_reference, "Operands must be boolean");
+- }
+-
+- expr.value_type = bool_type;
+- } else if (expr.operator == BinaryOperator.IN) {
+- // integer type or flags type or collection/map
+-
+- /* handle collections and maps */
+- var container_type = expr.right.value_type.data_type;
+-
+- if ((collection_type != null && container_type.is_subtype_of (collection_type))
+- || (map_type != null && container_type.is_subtype_of (map_type))) {
+- Symbol contains_sym = null;
+- if (container_type.is_subtype_of (collection_type)) {
+- contains_sym = collection_type.scope.lookup ("contains");
+- } else if (container_type.is_subtype_of (map_type)) {
+- contains_sym = map_type.scope.lookup ("contains");
+- }
+- var contains_method = (Method) contains_sym;
+- Gee.List<FormalParameter> contains_params = contains_method.get_parameters ();
+- Iterator<FormalParameter> contains_params_it = contains_params.iterator ();
+- contains_params_it.next ();
+- var contains_param = contains_params_it.get ();
+-
+- var key_type = get_actual_type (expr.right.value_type, contains_method, contains_param.parameter_type, expr);
+- expr.left.target_type = key_type;
+- }
+-
+- expr.value_type = bool_type;
+-
+- } else {
+- assert_not_reached ();
+- }
++ expr.check (this);
+ }
+
+ public override void visit_type_check (TypeCheck expr) {
+@@ -3314,7 +1160,7 @@
+ return result;
+ }
+
+- private Method? find_current_method () {
++ public Method? find_current_method () {
+ var sym = current_symbol;
+ while (sym != null) {
+ if (sym is Method) {
+@@ -3325,7 +1171,7 @@
+ return null;
+ }
+
+- private bool is_in_constructor () {
++ public bool is_in_constructor () {
+ var sym = current_symbol;
+ while (sym != null) {
+ if (sym is Constructor) {
+@@ -3405,277 +1251,6 @@
+ }
+
+ public override void visit_assignment (Assignment a) {
+- a.left.lvalue = true;
+-
+- a.left.accept (this);
+-
+- if (a.left.error) {
+- // skip on error in inner expression
+- a.error = true;
+- return;
+- }
+-
+- if (a.left is MemberAccess) {
+- var ma = (MemberAccess) a.left;
+-
+- if (!(ma.symbol_reference is Signal || ma.symbol_reference is DynamicProperty) && ma.value_type == null) {
+- a.error = true;
+- Report.error (a.source_reference, "unsupported lvalue in assignment");
+- return;
+- }
+- if (ma.prototype_access) {
+- a.error = true;
+- Report.error (a.source_reference, "Access to instance member `%s' denied".printf (ma.symbol_reference.get_full_name ()));
+- return;
+- }
+-
+- if (ma.error || ma.symbol_reference == null) {
+- a.error = true;
+- /* if no symbol found, skip this check */
+- return;
+- }
+-
+- if (ma.symbol_reference is DynamicSignal) {
+- // target_type not available for dynamic signals
+- } else if (ma.symbol_reference is Signal) {
+- var sig = (Signal) ma.symbol_reference;
+- a.right.target_type = new DelegateType (sig.get_delegate (ma.inner.value_type));
+- } else {
+- a.right.target_type = ma.value_type;
+- }
+- } else if (a.left is ElementAccess) {
+- var ea = (ElementAccess) a.left;
+-
+- if (ea.container is MemberAccess && ea.container.symbol_reference is Signal) {
+- var ma = (MemberAccess) ea.container;
+- var sig = (Signal) ea.container.symbol_reference;
+- a.right.target_type = new DelegateType (sig.get_delegate (ma.inner.value_type));
+- } else {
+- a.right.target_type = a.left.value_type;
+- }
+- } else if (a.left is PointerIndirection) {
+- a.right.target_type = a.left.value_type;
+- } else {
+- a.error = true;
+- Report.error (a.source_reference, "unsupported lvalue in assignment");
+- return;
+- }
+-
+- a.right.accept (this);
+-
+- if (a.right.error) {
+- // skip on error in inner expression
+- a.error = true;
+- return;
+- }
+-
+- if (a.operator != AssignmentOperator.SIMPLE && a.left is MemberAccess) {
+- // transform into simple assignment
+- // FIXME: only do this if the backend doesn't support
+- // the assignment natively
+-
+- var ma = (MemberAccess) a.left;
+-
+- if (!(ma.symbol_reference is Signal)) {
+- var old_value = new MemberAccess (ma.inner, ma.member_name);
+-
+- var bin = new BinaryExpression (BinaryOperator.PLUS, old_value, new ParenthesizedExpression (a.right, a.right.source_reference));
+- bin.target_type = a.right.target_type;
+- a.right.target_type = a.right.target_type.copy ();
+- a.right.target_type.value_owned = false;
+-
+- if (a.operator == AssignmentOperator.BITWISE_OR) {
+- bin.operator = BinaryOperator.BITWISE_OR;
+- } else if (a.operator == AssignmentOperator.BITWISE_AND) {
+- bin.operator = BinaryOperator.BITWISE_AND;
+- } else if (a.operator == AssignmentOperator.BITWISE_XOR) {
+- bin.operator = BinaryOperator.BITWISE_XOR;
+- } else if (a.operator == AssignmentOperator.ADD) {
+- bin.operator = BinaryOperator.PLUS;
+- } else if (a.operator == AssignmentOperator.SUB) {
+- bin.operator = BinaryOperator.MINUS;
+- } else if (a.operator == AssignmentOperator.MUL) {
+- bin.operator = BinaryOperator.MUL;
+- } else if (a.operator == AssignmentOperator.DIV) {
+- bin.operator = BinaryOperator.DIV;
+- } else if (a.operator == AssignmentOperator.PERCENT) {
+- bin.operator = BinaryOperator.MOD;
+- } else if (a.operator == AssignmentOperator.SHIFT_LEFT) {
+- bin.operator = BinaryOperator.SHIFT_LEFT;
+- } else if (a.operator == AssignmentOperator.SHIFT_RIGHT) {
+- bin.operator = BinaryOperator.SHIFT_RIGHT;
+- }
+-
+- a.right = bin;
+- a.right.accept (this);
+-
+- a.operator = AssignmentOperator.SIMPLE;
+- }
+- }
+-
+- if (a.left.symbol_reference is Signal) {
+- var sig = (Signal) a.left.symbol_reference;
+-
+- var m = a.right.symbol_reference as Method;
+-
+- if (m == null) {
+- a.error = true;
+- Report.error (a.right.source_reference, "unsupported expression for signal handler");
+- return;
+- }
+-
+- var dynamic_sig = sig as DynamicSignal;
+- if (dynamic_sig != null) {
+- bool first = true;
+- foreach (FormalParameter param in dynamic_sig.handler.value_type.get_parameters ()) {
+- if (first) {
+- // skip sender parameter
+- first = false;
+- } else {
+- dynamic_sig.add_parameter (param.copy ());
+- }
+- }
+- a.right.target_type = new DelegateType (sig.get_delegate (new ObjectType ((ObjectTypeSymbol) sig.parent_symbol)));
+- } else if (!a.right.value_type.compatible (a.right.target_type)) {
+- var delegate_type = (DelegateType) a.right.target_type;
+-
+- a.error = true;
+- Report.error (a.right.source_reference, "method `%s' is incompatible with signal `%s', expected `%s'".printf (a.right.value_type.to_string (), a.right.target_type.to_string (), delegate_type.delegate_symbol.get_prototype_string (m.name)));
+- return;
+- }
+- } else if (a.left is MemberAccess) {
+- var ma = (MemberAccess) a.left;
+-
+- if (ma.symbol_reference is Property) {
+- var prop = (Property) ma.symbol_reference;
+-
+- var dynamic_prop = prop as DynamicProperty;
+- if (dynamic_prop != null) {
+- dynamic_prop.property_type = a.right.value_type.copy ();
+- a.left.value_type = dynamic_prop.property_type.copy ();
+- }
+-
+- if (prop.set_accessor == null
+- || (!prop.set_accessor.writable && !(find_current_method () is CreationMethod || is_in_constructor ()))) {
+- ma.error = true;
+- Report.error (ma.source_reference, "Property `%s' is read-only".printf (prop.get_full_name ()));
+- return;
+- }
+- } else if (ma.symbol_reference is LocalVariable && a.right.value_type == null) {
+- var local = (LocalVariable) ma.symbol_reference;
+-
+- if (a.right.symbol_reference is Method &&
+- local.variable_type is DelegateType) {
+- var m = (Method) a.right.symbol_reference;
+- var dt = (DelegateType) local.variable_type;
+- var cb = dt.delegate_symbol;
+-
+- /* check whether method matches callback type */
+- if (!cb.matches_method (m)) {
+- a.error = true;
+- Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
+- return;
+- }
+-
+- a.right.value_type = local.variable_type;
+- } else {
+- a.error = true;
+- Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
+- return;
+- }
+- } else if (ma.symbol_reference is Field && a.right.value_type == null) {
+- var f = (Field) ma.symbol_reference;
+-
+- if (a.right.symbol_reference is Method &&
+- f.field_type is DelegateType) {
+- var m = (Method) a.right.symbol_reference;
+- var dt = (DelegateType) f.field_type;
+- var cb = dt.delegate_symbol;
+-
+- /* check whether method matches callback type */
+- if (!cb.matches_method (m)) {
+- f.error = true;
+- Report.error (a.source_reference, "declaration of method `%s' doesn't match declaration of callback `%s'".printf (m.get_full_name (), cb.get_full_name ()));
+- return;
+- }
+-
+- a.right.value_type = f.field_type;
+- } else {
+- a.error = true;
+- Report.error (a.source_reference, "Assignment: Invalid callback assignment attempt");
+- return;
+- }
+- } else if (a.left.value_type != null && a.right.value_type != null) {
+- /* if there was an error on either side,
+- * i.e. a.{left|right}.value_type == null, skip type check */
+-
+- if (!a.right.value_type.compatible (a.left.value_type)) {
+- a.error = true;
+- Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.value_type.to_string (), a.left.value_type.to_string ()));
+- return;
+- }
+-
+- if (a.right.value_type.is_disposable ()) {
+- /* rhs transfers ownership of the expression */
+- if (!(a.left.value_type is PointerType) && !a.left.value_type.value_owned) {
+- /* lhs doesn't own the value */
+- a.error = true;
+- Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable");
+- }
+- } else if (a.left.value_type.value_owned) {
+- /* lhs wants to own the value
+- * rhs doesn't transfer the ownership
+- * code generator needs to add reference
+- * increment calls */
+- }
+- }
+- } else if (a.left is ElementAccess) {
+- var ea = (ElementAccess) a.left;
+-
+- if (!a.right.value_type.compatible (a.left.value_type)) {
+- a.error = true;
+- Report.error (a.source_reference, "Assignment: Cannot convert from `%s' to `%s'".printf (a.right.value_type.to_string (), a.left.value_type.to_string ()));
+- return;
+- }
+-
+- if (a.right.value_type.is_disposable ()) {
+- /* rhs transfers ownership of the expression */
+-
+- DataType element_type;
+-
+- if (ea.container.value_type is ArrayType) {
+- var array_type = (ArrayType) ea.container.value_type;
+- element_type = array_type.element_type;
+- } else {
+- var args = ea.container.value_type.get_type_arguments ();
+- assert (args.size == 1);
+- element_type = args.get (0);
+- }
+-
+- if (!(element_type is PointerType) && !element_type.value_owned) {
+- /* lhs doesn't own the value */
+- a.error = true;
+- Report.error (a.source_reference, "Invalid assignment from owned expression to unowned variable");
+- return;
+- }
+- } else if (a.left.value_type.value_owned) {
+- /* lhs wants to own the value
+- * rhs doesn't transfer the ownership
+- * code generator needs to add reference
+- * increment calls */
+- }
+- } else {
+- return;
+- }
+-
+- if (a.left.value_type != null) {
+- a.value_type = a.left.value_type.copy ();
+- a.value_type.value_owned = false;
+- } else {
+- a.value_type = null;
+- }
+-
+- a.add_error_types (a.left.get_error_types ());
+- a.add_error_types (a.right.get_error_types ());
++ a.check (this);
+ }
+ }
+Index: vala/valasignal.vala
+===================================================================
+--- vala/valasignal.vala (revision 1971)
++++ vala/valasignal.vala (revision 2004)
+@@ -218,5 +218,19 @@
+
+ return generated_method;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+
+Index: vala/valaexpressionstatement.vala
+===================================================================
+--- vala/valaexpressionstatement.vala (revision 1971)
++++ vala/valaexpressionstatement.vala (revision 2004)
+@@ -1,6 +1,6 @@
+ /* valaexpressionstatement.vala
+ *
+- * Copyright (C) 2006-2007 Jürg Billeter
++ * Copyright (C) 2006-2008 Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+@@ -85,4 +85,22 @@
+
+ return null;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (expression.error) {
++ // ignore inner error
++ error = true;
++ return false;
++ }
++
++ add_error_types (expression.get_error_types ());
++
++ return !error;
++ }
+ }
+Index: vala/valainvocationexpression.vala
+===================================================================
+--- vala/valainvocationexpression.vala (revision 1971)
++++ vala/valainvocationexpression.vala (revision 2004)
+@@ -120,4 +120,306 @@
+ public override bool is_pure () {
+ return false;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ call.accept (analyzer);
++
++ if (call.error) {
++ /* if method resolving didn't succeed, skip this check */
++ error = true;
++ return false;
++ }
++
++ if (call is MemberAccess) {
++ var ma = (MemberAccess) call;
++ if (ma.prototype_access) {
++ error = true;
++ Report.error (source_reference, "Access to instance member `%s' denied".printf (call.symbol_reference.get_full_name ()));
++ return false;
++ }
++ }
++
++ var mtype = call.value_type;
++
++ if (mtype is ObjectType) {
++ // constructor chain-up
++ var cm = analyzer.find_current_method () as CreationMethod;
++ assert (cm != null);
++ if (cm.chain_up) {
++ error = true;
++ Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted");
++ return false;
++ }
++ cm.chain_up = true;
++ }
++
++ // check for struct construction
++ if (call is MemberAccess &&
++ ((call.symbol_reference is CreationMethod
++ && call.symbol_reference.parent_symbol is Struct)
++ || call.symbol_reference is Struct)) {
++ var struct_creation_expression = new ObjectCreationExpression ((MemberAccess) call, source_reference);
++ struct_creation_expression.struct_creation = true;
++ foreach (Expression arg in get_argument_list ()) {
++ struct_creation_expression.add_argument (arg);
++ }
++ struct_creation_expression.target_type = target_type;
++ analyzer.replaced_nodes.add (this);
++ parent_node.replace_expression (this, struct_creation_expression);
++ struct_creation_expression.accept (analyzer);
++ return false;
++ } else if (call is MemberAccess
++ && call.symbol_reference is CreationMethod) {
++ // constructor chain-up
++ var cm = analyzer.find_current_method () as CreationMethod;
++ assert (cm != null);
++ if (cm.chain_up) {
++ error = true;
++ Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted");
++ return false;
++ }
++ cm.chain_up = true;
++ }
++
++ Gee.List<FormalParameter> params;
++
++ if (mtype != null && mtype.is_invokable ()) {
++ params = mtype.get_parameters ();
++ } else {
++ error = true;
++ Report.error (source_reference, "invocation not supported in this context");
++ return false;
++ }
++
++ Expression last_arg = null;
++
++ var args = get_argument_list ();
++ Iterator<Expression> arg_it = args.iterator ();
++ foreach (FormalParameter param in params) {
++ if (param.ellipsis) {
++ break;
++ }
++
++ if (arg_it.next ()) {
++ Expression arg = arg_it.get ();
++
++ /* store expected type for callback parameters */
++ arg.target_type = param.parameter_type;
++
++ // resolve generic type parameters
++ var ma = call as MemberAccess;
++ if (arg.target_type.type_parameter != null) {
++ if (ma != null && ma.inner != null) {
++ arg.target_type = analyzer.get_actual_type (ma.inner.value_type, ma.symbol_reference, arg.target_type, arg);
++ assert (arg.target_type != null);
++ }
++ }
++
++ last_arg = arg;
++ }
++ }
++
++ // printf arguments
++ if (mtype is MethodType && ((MethodType) mtype).method_symbol.printf_format) {
++ StringLiteral format_literal = null;
++ if (last_arg != null) {
++ // use last argument as format string
++ format_literal = last_arg as StringLiteral;
++ } else {
++ // use instance as format string for string.printf (...)
++ var ma = call as MemberAccess;
++ if (ma != null) {
++ format_literal = ma.inner as StringLiteral;
++ }
++ }
++ if (format_literal != null) {
++ string format = format_literal.eval ();
++
++ bool unsupported_format = false;
++
++ weak string format_it = format;
++ unichar c = format_it.get_char ();
++ while (c != '\0') {
++ if (c != '%') {
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ continue;
++ }
++
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ // flags
++ while (c == '#' || c == '0' || c == '-' || c == ' ' || c == '+') {
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ }
++ // field width
++ while (c >= '0' && c <= '9') {
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ }
++ // precision
++ if (c == '.') {
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ while (c >= '0' && c <= '9') {
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ }
++ }
++ // length modifier
++ int length = 0;
++ if (c == 'h') {
++ length = -1;
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ if (c == 'h') {
++ length = -2;
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ }
++ } else if (c == 'l') {
++ length = 1;
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ } else if (c == 'z') {
++ length = 2;
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ }
++ // conversion specifier
++ DataType param_type = null;
++ if (c == 'd' || c == 'i' || c == 'c') {
++ // integer
++ if (length == -2) {
++ param_type = analyzer.int8_type;
++ } else if (length == -1) {
++ param_type = analyzer.short_type;
++ } else if (length == 0) {
++ param_type = analyzer.int_type;
++ } else if (length == 1) {
++ param_type = analyzer.long_type;
++ } else if (length == 2) {
++ param_type = analyzer.ssize_t_type;
++ }
++ } else if (c == 'o' || c == 'u' || c == 'x' || c == 'X') {
++ // unsigned integer
++ if (length == -2) {
++ param_type = analyzer.uchar_type;
++ } else if (length == -1) {
++ param_type = analyzer.ushort_type;
++ } else if (length == 0) {
++ param_type = analyzer.uint_type;
++ } else if (length == 1) {
++ param_type = analyzer.ulong_type;
++ } else if (length == 2) {
++ param_type = analyzer.size_t_type;
++ }
++ } else if (c == 'e' || c == 'E' || c == 'f' || c == 'F'
++ || c == 'g' || c == 'G' || c == 'a' || c == 'A') {
++ // double
++ param_type = analyzer.double_type;
++ } else if (c == 's') {
++ // string
++ param_type = analyzer.string_type;
++ } else if (c == 'p') {
++ // pointer
++ param_type = new PointerType (new VoidType ());
++ } else if (c == '%') {
++ // literal %
++ } else {
++ unsupported_format = true;
++ break;
++ }
++ if (c != '\0') {
++ format_it = format_it.next_char ();
++ c = format_it.get_char ();
++ }
++ if (param_type != null) {
++ if (arg_it.next ()) {
++ Expression arg = arg_it.get ();
++
++ arg.target_type = param_type;
++ } else {
++ Report.error (source_reference, "Too few arguments for specified format");
++ return false;
++ }
++ }
++ }
++ if (!unsupported_format && arg_it.next ()) {
++ Report.error (source_reference, "Too many arguments for specified format");
++ return false;
++ }
++ }
++ }
++
++ foreach (Expression arg in get_argument_list ()) {
++ arg.accept (analyzer);
++ }
++
++ DataType ret_type;
++
++ ret_type = mtype.get_return_type ();
++ params = mtype.get_parameters ();
++
++ if (ret_type is VoidType) {
++ // void return type
++ if (!(parent_node is ExpressionStatement)
++ && !(parent_node is ForStatement)
++ && !(parent_node is YieldStatement)) {
++ // A void method invocation can be in the initializer or
++ // iterator of a for statement
++ error = true;
++ Report.error (source_reference, "invocation of void method not allowed as expression");
++ return false;
++ }
++ }
++
++ // resolve generic return values
++ var ma = call as MemberAccess;
++ if (ret_type.type_parameter != null) {
++ if (ma != null && ma.inner != null) {
++ ret_type = analyzer.get_actual_type (ma.inner.value_type, ma.symbol_reference, ret_type, this);
++ if (ret_type == null) {
++ return false;
++ }
++ }
++ }
++ Gee.List<DataType> resolved_type_args = new ArrayList<DataType> ();
++ foreach (DataType type_arg in ret_type.get_type_arguments ()) {
++ if (type_arg.type_parameter != null && ma != null && ma.inner != null) {
++ resolved_type_args.add (analyzer.get_actual_type (ma.inner.value_type, ma.symbol_reference, type_arg, this));
++ } else {
++ resolved_type_args.add (type_arg);
++ }
++ }
++ ret_type = ret_type.copy ();
++ ret_type.remove_all_type_arguments ();
++ foreach (DataType resolved_type_arg in resolved_type_args) {
++ ret_type.add_type_argument (resolved_type_arg);
++ }
++
++ if (mtype is MethodType) {
++ var m = ((MethodType) mtype).method_symbol;
++ foreach (DataType error_type in m.get_error_types ()) {
++ // ensure we can trace back which expression may throw errors of this type
++ var call_error_type = error_type.copy ();
++ call_error_type.source_reference = source_reference;
++
++ add_error_type (call_error_type);
++ }
++ }
++
++ value_type = ret_type;
++
++ analyzer.check_arguments (this, mtype, params, get_argument_list ());
++
++ return !error;
++ }
+ }
+Index: vala/valatrystatement.vala
+===================================================================
+--- vala/valatrystatement.vala (revision 1971)
++++ vala/valatrystatement.vala (revision 2004)
+@@ -86,4 +86,16 @@
+ finally_body.accept (visitor);
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ return !error;
++ }
+ }
+Index: vala/valareturnstatement.vala
+===================================================================
+--- vala/valareturnstatement.vala (revision 1971)
++++ vala/valareturnstatement.vala (revision 2004)
+@@ -70,4 +70,77 @@
+ return_expression = new_node;
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ if (return_expression != null) {
++ return_expression.target_type = analyzer.current_return_type;
++ }
++
++ accept_children (analyzer);
++
++ if (return_expression != null && return_expression.error) {
++ // ignore inner error
++ error = true;
++ return false;
++ }
++
++ if (analyzer.current_return_type == null) {
++ error = true;
++ Report.error (source_reference, "Return not allowed in this context");
++ return false;
++ }
++
++ if (return_expression == null) {
++ if (!(analyzer.current_return_type is VoidType)) {
++ error = true;
++ Report.error (source_reference, "Return without value in non-void function");
++ }
++ return !error;
++ }
++
++ if (analyzer.current_return_type is VoidType) {
++ Report.error (source_reference, "Return with value in void function");
++ return false;
++ }
++
++ if (return_expression.value_type == null) {
++ error = true;
++ Report.error (source_reference, "Invalid expression in return value");
++ return false;
++ }
++
++ if (!return_expression.value_type.compatible (analyzer.current_return_type)) {
++ error = true;
++ Report.error (source_reference, "Return: Cannot convert from `%s' to `%s'".printf (return_expression.value_type.to_string (), analyzer.current_return_type.to_string ()));
++ return false;
++ }
++
++ if (return_expression.value_type.is_disposable () &&
++ !analyzer.current_return_type.value_owned) {
++ error = true;
++ Report.error (source_reference, "Return value transfers ownership but method return type hasn't been declared to transfer ownership");
++ return false;
++ }
++
++ if (return_expression.symbol_reference is LocalVariable &&
++ return_expression.value_type.is_disposable () &&
++ !analyzer.current_return_type.value_owned) {
++ Report.warning (source_reference, "Local variable with strong reference used as return value and method return type hasn't been declared to transfer ownership");
++ }
++
++ if (analyzer.context.non_null && return_expression is NullLiteral
++ && !analyzer.current_return_type.nullable) {
++ Report.warning (source_reference, "`null' incompatible with return type `%s`".printf (analyzer.current_return_type.to_string ()));
++ }
++
++ add_error_types (return_expression.get_error_types ());
++
++ return !error;
++ }
+ }
+Index: vala/valaclass.vala
+===================================================================
+--- vala/valaclass.vala (revision 1971)
++++ vala/valaclass.vala (revision 2004)
+@@ -814,5 +814,202 @@
+ }
+ }
+ }
++
++ private void get_all_prerequisites (Interface iface, Gee.List<TypeSymbol> list) {
++ foreach (DataType prereq in iface.get_prerequisites ()) {
++ TypeSymbol type = prereq.data_type;
++ /* skip on previous errors */
++ if (type == null) {
++ continue;
++ }
++
++ list.add (type);
++ if (type is Interface) {
++ get_all_prerequisites ((Interface) type, list);
++
++ }
++ }
++ }
++
++ private bool class_is_a (Class cl, TypeSymbol t) {
++ if (cl == t) {
++ return true;
++ }
++
++ foreach (DataType base_type in cl.get_base_types ()) {
++ if (base_type.data_type is Class) {
++ if (class_is_a ((Class) base_type.data_type, t)) {
++ return true;
++ }
++ } else if (base_type.data_type == t) {
++ return true;
++ }
++ }
++
++ return false;
++ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ var old_source_file = analyzer.current_source_file;
++ var old_symbol = analyzer.current_symbol;
++ var old_class = analyzer.current_class;
++
++ if (source_reference != null) {
++ analyzer.current_source_file = source_reference.file;
++ }
++ analyzer.current_symbol = this;
++ analyzer.current_class = this;
++
++ foreach (DataType base_type_reference in get_base_types ()) {
++ if (!base_type_reference.check (analyzer)) {
++ error = true;
++ return false;
++ }
++
++ // check whether base type is at least as accessible as the class
++ if (!analyzer.is_type_accessible (this, base_type_reference)) {
++ error = true;
++ Report.error (source_reference, "base type `%s` is less accessible than class `%s`".printf (base_type_reference.to_string (), get_full_name ()));
++ return false;
++ }
++
++ analyzer.current_source_file.add_type_dependency (base_type_reference, SourceFileDependencyType.HEADER_FULL);
++ }
++
++ accept_children (analyzer);
++
++ /* compact classes cannot implement interfaces */
++ if (is_compact) {
++ foreach (DataType base_type in get_base_types ()) {
++ if (base_type.data_type is Interface) {
++ error = true;
++ Report.error (source_reference, "compact classes `%s` may not implement interfaces".printf (get_full_name ()));
++ }
++ }
++ }
++
++ /* gather all prerequisites */
++ Gee.List<TypeSymbol> prerequisites = new ArrayList<TypeSymbol> ();
++ foreach (DataType base_type in get_base_types ()) {
++ if (base_type.data_type is Interface) {
++ get_all_prerequisites ((Interface) base_type.data_type, prerequisites);
++ }
++ }
++ /* check whether all prerequisites are met */
++ Gee.List<string> missing_prereqs = new ArrayList<string> ();
++ foreach (TypeSymbol prereq in prerequisites) {
++ if (!class_is_a (this, prereq)) {
++ missing_prereqs.insert (0, prereq.get_full_name ());
++ }
++ }
++ /* report any missing prerequisites */
++ if (missing_prereqs.size > 0) {
++ error = true;
++
++ string error_string = "%s: some prerequisites (".printf (get_full_name ());
++ bool first = true;
++ foreach (string s in missing_prereqs) {
++ if (first) {
++ error_string = "%s`%s'".printf (error_string, s);
++ first = false;
++ } else {
++ error_string = "%s, `%s'".printf (error_string, s);
++ }
++ }
++ error_string += ") are not met";
++ Report.error (source_reference, error_string);
++ }
++
++ /* VAPI classes don't have to specify overridden methods */
++ if (!external_package) {
++ /* all abstract symbols defined in base types have to be at least defined (or implemented) also in this type */
++ foreach (DataType base_type in get_base_types ()) {
++ if (base_type.data_type is Interface) {
++ Interface iface = (Interface) base_type.data_type;
++
++ if (base_class != null && base_class.is_subtype_of (iface)) {
++ // reimplementation of interface, class is not required to reimplement all methods
++ break;
++ }
++
++ /* We do not need to do expensive equality checking here since this is done
++ * already. We only need to guarantee the symbols are present.
++ */
++
++ /* check methods */
++ foreach (Method m in iface.get_methods ()) {
++ if (m.is_abstract) {
++ Symbol sym = null;
++ var base_class = this;
++ while (base_class != null && !(sym is Method)) {
++ sym = base_class.scope.lookup (m.name);
++ base_class = base_class.base_class;
++ }
++ if (!(sym is Method)) {
++ error = true;
++ Report.error (source_reference, "`%s' does not implement interface method `%s'".printf (get_full_name (), m.get_full_name ()));
++ }
++ }
++ }
++
++ /* check properties */
++ foreach (Property prop in iface.get_properties ()) {
++ if (prop.is_abstract) {
++ Symbol sym = null;
++ var base_class = this;
++ while (base_class != null && !(sym is Property)) {
++ sym = base_class.scope.lookup (prop.name);
++ base_class = base_class.base_class;
++ }
++ if (!(sym is Property)) {
++ error = true;
++ Report.error (source_reference, "`%s' does not implement interface property `%s'".printf (get_full_name (), prop.get_full_name ()));
++ }
++ }
++ }
++ }
++ }
++
++ /* all abstract symbols defined in base classes have to be implemented in non-abstract classes */
++ if (!is_abstract) {
++ var base_class = base_class;
++ while (base_class != null && base_class.is_abstract) {
++ foreach (Method base_method in base_class.get_methods ()) {
++ if (base_method.is_abstract) {
++ var override_method = analyzer.symbol_lookup_inherited (this, base_method.name) as Method;
++ if (override_method == null || !override_method.overrides) {
++ error = true;
++ Report.error (source_reference, "`%s' does not implement abstract method `%s'".printf (get_full_name (), base_method.get_full_name ()));
++ }
++ }
++ }
++ foreach (Property base_property in base_class.get_properties ()) {
++ if (base_property.is_abstract) {
++ var override_property = analyzer.symbol_lookup_inherited (this, base_property.name) as Property;
++ if (override_property == null || !override_property.overrides) {
++ error = true;
++ Report.error (source_reference, "`%s' does not implement abstract property `%s'".printf (get_full_name (), base_property.get_full_name ()));
++ }
++ }
++ }
++ base_class = base_class.base_class;
++ }
++ }
++ }
++
++ analyzer.current_source_file = old_source_file;
++ analyzer.current_symbol = old_symbol;
++ analyzer.current_class = old_class;
++
++ return !error;
++ }
+ }
+
+Index: vala/valaforstatement.vala
+===================================================================
+--- vala/valaforstatement.vala (revision 1971)
++++ vala/valaforstatement.vala (revision 2004)
+@@ -156,4 +156,40 @@
+ }
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ accept_children (analyzer);
++
++ if (condition != null && condition.error) {
++ /* if there was an error in the condition, skip this check */
++ error = true;
++ return false;
++ }
++
++ if (condition != null && !condition.value_type.compatible (analyzer.bool_type)) {
++ error = true;
++ Report.error (condition.source_reference, "Condition must be boolean");
++ return false;
++ }
++
++ if (condition != null) {
++ add_error_types (condition.get_error_types ());
++ }
++
++ add_error_types (body.get_error_types ());
++ foreach (Expression exp in get_initializer ()) {
++ add_error_types (exp.get_error_types ());
++ }
++ foreach (Expression exp in get_iterator ()) {
++ add_error_types (exp.get_error_types ());
++ }
++
++ return !error;
++ }
+ }
+Index: vala/valaarraycreationexpression.vala
+===================================================================
+--- vala/valaarraycreationexpression.vala (revision 1971)
++++ vala/valaarraycreationexpression.vala (revision 2004)
+@@ -106,4 +106,118 @@
+ element_type = new_type;
+ }
+ }
++
++ private int create_sizes_from_initializer_list (SemanticAnalyzer analyzer, InitializerList il, int rank, Gee.List<Literal> sl) {
++ var init = new IntegerLiteral (il.size.to_string (), il.source_reference);
++ init.accept (analyzer);
++ sl.add (init);
++
++ int subsize = -1;
++ foreach (Expression e in il.get_initializers ()) {
++ if (e is InitializerList) {
++ if (rank == 1) {
++ il.error = true;
++ e.error = true;
++ Report.error (e.source_reference, "Expected array element, got array initializer list");
++ return -1;
++ }
++ int size = create_sizes_from_initializer_list (analyzer, (InitializerList) e, rank - 1, sl);
++ if (size == -1) {
++ return -1;
++ }
++ if (subsize >= 0 && subsize != size) {
++ il.error = true;
++ Report.error (il.source_reference, "Expected initializer list of size %d, got size %d".printf (subsize, size));
++ return -1;
++ } else {
++ subsize = size;
++ }
++ } else {
++ if (rank != 1) {
++ il.error = true;
++ e.error = true;
++ Report.error (e.source_reference, "Expected array initializer list, got array element");
++ return -1;
++ }
++ }
++ }
++ return il.size;
++ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ Gee.List<Expression> size = get_sizes ();
++ var initlist = initializer_list;
++
++ if (element_type != null) {
++ element_type.accept (analyzer);
++ }
++
++ foreach (Expression e in size) {
++ e.accept (analyzer);
++ }
++
++ var calc_sizes = new ArrayList<Literal> ();
++ if (initlist != null) {
++ initlist.target_type = new ArrayType (element_type, rank, source_reference);
++
++ initlist.accept (analyzer);
++
++ var ret = create_sizes_from_initializer_list (analyzer, initlist, rank, calc_sizes);
++ if (ret == -1) {
++ error = true;
++ }
++ }
++
++ if (size.size > 0) {
++ /* check for errors in the size list */
++ foreach (Expression e in size) {
++ if (e.value_type == null) {
++ /* return on previous error */
++ return false;
++ } else if (!(e.value_type.data_type is Struct) || !((Struct) e.value_type.data_type).is_integer_type ()) {
++ error = true;
++ Report.error (e.source_reference, "Expression of integer type expected");
++ }
++ }
++ } else {
++ if (initlist == null) {
++ error = true;
++ /* this is an internal error because it is already handeld by the parser */
++ Report.error (source_reference, "internal error: initializer list expected");
++ } else {
++ foreach (Expression size in calc_sizes) {
++ append_size (size);
++ }
++ }
++ }
++
++ if (error) {
++ return false;
++ }
++
++ /* check for wrong elements inside the initializer */
++ if (initializer_list != null && initializer_list.value_type == null) {
++ return false;
++ }
++
++ /* try to construct the type of the array */
++ if (element_type == null) {
++ error = true;
++ Report.error (source_reference, "Cannot determine the element type of the created array");
++ return false;
++ }
++
++ element_type.value_owned = true;
++
++ value_type = new ArrayType (element_type, rank, source_reference);
++ value_type.value_owned = true;
++
++ return !error;
++ }
+ }
+Index: vala/valastruct.vala
+===================================================================
+--- vala/valastruct.vala (revision 1971)
++++ vala/valastruct.vala (revision 2004)
+@@ -605,4 +605,28 @@
+
+ return false;
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ process_attributes ();
++
++ analyzer.current_symbol = this;
++ analyzer.current_struct = this;
++
++ accept_children (analyzer);
++
++ if (!external && !external_package && get_base_types ().size == 0 && get_fields ().size == 0) {
++ Report.error (source_reference, "structs cannot be empty");
++ }
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++ analyzer.current_struct = null;
++
++ return !error;
++ }
+ }
+Index: vala/valaconstructor.vala
+===================================================================
+--- vala/valaconstructor.vala (revision 1971)
++++ vala/valaconstructor.vala (revision 2004)
+@@ -60,4 +60,28 @@
+ body.accept (visitor);
+ }
+ }
++
++ public override bool check (SemanticAnalyzer analyzer) {
++ if (checked) {
++ return !error;
++ }
++
++ checked = true;
++
++ this_parameter = new FormalParameter ("this", new ObjectType (analyzer.current_class));
++ scope.add (this_parameter.name, this_parameter);
++
++ owner = analyzer.current_symbol.scope;
++ analyzer.current_symbol = this;
++
++ accept_children (analyzer);
++
++ foreach (DataType body_error_type in body.get_error_types ()) {
++ Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
++ }
++
++ analyzer.current_symbol = analyzer.current_symbol.parent_symbol;
++
++ return !error;
++ }
+ }
+Index: ChangeLog
+===================================================================
+--- ChangeLog (revision 1971)
++++ ChangeLog (revision 2004)
+@@ -1,5 +1,273 @@
++2008-11-09 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaclass.vala:
++ * vala/valainterface.vala:
++ * vala/valamemberaccess.vala:
++ * vala/valaobjecttype.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Ensure attributes of base types are processed before querying
++ C header filenames
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valablock.vala:
++ * vala/valacatchclause.vala:
++ * vala/valadeclarationstatement.vala:
++ * vala/valadeletestatement.vala:
++ * vala/valadostatement.vala:
++ * vala/valaexpressionstatement.vala:
++ * vala/valaforstatement.vala:
++ * vala/valaifstatement.vala:
++ * vala/valainitializerlist.vala:
++ * vala/valalocalvariable.vala:
++ * vala/valalockstatement.vala:
++ * vala/valasemanticanalyzer.vala:
++ * vala/valaswitchsection.vala:
++ * vala/valatrystatement.vala:
++ * vala/valawhilestatement.vala:
++
++ Move statement checking to code nodes
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vapi/glib-2.0.vapi:
++
++ Add g_rmdir binding
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valadbusclientmodule.vala:
++
++ Fix D-Bus methods with out parameters but no return value
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaconstant.vala:
++ * vala/valaconstructor.vala:
++ * vala/valacreationmethod.vala:
++ * vala/valadestructor.vala:
++ * vala/valafield.vala:
++ * vala/valaformalparameter.vala:
++ * vala/valaproperty.vala:
++ * vala/valapropertyaccessor.vala:
++ * vala/valasemanticanalyzer.vala:
++ * vala/valasignal.vala:
++
++ Move member checking to code nodes
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valadelegate.vala:
++ * vala/valaenum.vala:
++ * vala/valaenumvalue.vala:
++ * vala/valaerrorcode.vala:
++ * vala/valaerrordomain.vala:
++ * vala/valainterface.vala:
++ * vala/valanamespace.vala:
++ * vala/valasemanticanalyzer.vala:
++ * vala/valastruct.vala:
++
++ Move type symbol checking to code nodes
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaarraycreationexpression.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move array creation expression checking to
++ ArrayCreationExpression.check
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valasemanticanalyzer.vala:
++ * vala/valathrowstatement.vala:
++
++ Move throw statement checking to ThrowStatement.check
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valareturnstatement.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move return statement checking to ReturnStatement.check
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaforeachstatement.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move foreach statement checking to ForeachStatement.check
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaelementaccess.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move element access checking to ElementAccess.check
++
++2008-11-07 Jürg Billeter <j@bitron.ch>
++
++ * vapigen/valagirparser.vala:
++
++ Set source_reference in parsed nodes
++
++2008-11-06 Jürg Billeter <j@bitron.ch>
++
++ * vala/valamethod.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move method checking to Method.check
++
++2008-11-06 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaclass.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move class checking to Class.check
++
++2008-11-06 Jürg Billeter <j@bitron.ch>
++
++ * gobject/Makefile.am:
++ * gobject/valaccodedynamicsignalmodule.vala:
++ * gobject/valaccodegenerator.vala:
++ * gobject/valadbusclientmodule.vala:
++ * gobject/valagerrormodule.vala:
++ * gobject/valagobjectmodule.vala:
++
++ Move dynamic signal generation to GObjectModule and
++ DBusClientModule
++
++2008-11-06 Jürg Billeter <j@bitron.ch>
++
++ * gobject/Makefile.am:
++ * gobject/valaccodedynamicpropertymodule.vala:
++ * gobject/valaccodedynamicsignalmodule.vala:
++ * gobject/valaccodegenerator.vala:
++ * gobject/valadbusclientmodule.vala:
++ * gobject/valagobjectmodule.vala:
++
++ Move dynamic property generation to GObjectModule and
++ DBusClientModule
++
++2008-11-06 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodebasemodule.vala:
++ * gobject/valagobjectmodule.vala:
++
++ Move constructor code generation to GObjectModule
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * vala/valainvocationexpression.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move invocation expression checking to InvocationExpression.check
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * vala/valamemberaccess.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move member access checking to MemberAccess.check
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * vala/valabinaryexpression.vala:
++ * vala/valaobjectcreationexpression.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move object creation expression checking to
++ ObjectCreationExpression.check
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * vala/valabinaryexpression.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move binary expression checking to BinaryExpression.check
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaassignment.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Move assignment checking to Assignment.check
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * vala/valaenum.vala:
++ * gobject/valadbusclientmodule.vala:
++ * gobject/valagsignalmodule.vala:
++
++ Support enums in D-Bus clients and servers, fixes bug 534105
++
++2008-11-05 Jürg Billeter <j@bitron.ch>
++
++ * gobject/Makefile.am:
++ * gobject/valaccodebasemodule.vala:
++ * gobject/valaccodecontrolflowmodule.vala:
++ * gobject/valaccodegenerator.vala:
++ * gobject/valaccodememberaccessmodule.vala:
++
++ Add CCodeControlFlowModule
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * vala/valadynamicproperty.vala:
++ * vala/valaproperty.vala:
++ * vala/valasemanticanalyzer.vala:
++
++ Fix crash when using dynamic properties, fixes bug 559304
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodememberaccessmodule.vala:
++ * gobject/valagsignalmodule.vala:
++
++ Move signal emission to GSignalModule
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodebasemodule.vala:
++ * gobject/valaccodedelegatemodule.vala:
++
++ Move delegate wrapper generation to CCodeDelegateModule
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodearraymodule.vala:
++ * gobject/valaccodebasemodule.vala:
++
++ Move array dup wrapper generation to CCodeArrayModule
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodebasemodule.vala:
++ * gobject/valagobjectmodule.vala:
++
++ Move construct property assignment to GObjectModule
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodeassignmentmodule.vala:
++ * gobject/valagsignalmodule.vala:
++
++ Move signal connection and disconnection to GSignalModule
++
++2008-11-04 Jürg Billeter <j@bitron.ch>
++
++ * gobject/valaccodearraymodule.vala:
++ * gobject/valagsignalmodule.vala:
++
++ Move detailed signal emission to GSignalModule
++
+ 2008-11-03 Jürg Billeter <j@bitron.ch>
+
++ * configure.ac: Post-release version bump
++
++2008-11-03 Jürg Billeter <j@bitron.ch>
++
+ * NEWS: update for 0.5.1 release
+
+ 2008-11-03 Jürg Billeter <j@bitron.ch>
+Index: vapigen/valagirparser.vala
+===================================================================
+--- vapigen/valagirparser.vala (revision 1971)
++++ vapigen/valagirparser.vala (revision 2004)
+@@ -153,7 +153,10 @@
+ ns = new Namespace (namespace_name);
+ new_namespace = true;
+ } else {
+- ns.source_reference = new SourceReference (current_source_file);
++ if (ns.external_package) {
++ ns.attributes = null;
++ ns.source_reference = get_current_src ();
++ }
+ }
+
+ string cheader = get_attribute (ns.name, "c:header-filename");
+@@ -221,7 +224,7 @@
+
+ Struct parse_alias () {
+ start_element ("alias");
+- var st = new Struct (reader.get_attribute ("name"));
++ var st = new Struct (reader.get_attribute ("name"), get_current_src ());
+ st.access = SymbolAccessibility.PUBLIC;
+ st.add_base_type (parse_type_from_name (reader.get_attribute ("target")));
+ next ();
+@@ -231,7 +234,7 @@
+
+ Enum parse_enumeration () {
+ start_element ("enumeration");
+- var en = new Enum (reader.get_attribute ("name"));
++ var en = new Enum (reader.get_attribute ("name"), get_current_src ());
+ en.access = SymbolAccessibility.PUBLIC;
+ next ();
+
+@@ -274,7 +277,7 @@
+
+ Enum parse_bitfield () {
+ start_element ("bitfield");
+- var en = new Enum (reader.get_attribute ("name"));
++ var en = new Enum (reader.get_attribute ("name"), get_current_src ());
+ en.access = SymbolAccessibility.PUBLIC;
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+@@ -308,7 +311,7 @@
+ } else {
+ return_type = new VoidType ();
+ }
+- var m = new Method (name, return_type);
++ var m = new Method (name, return_type, get_current_src ());
+ m.access = SymbolAccessibility.PUBLIC;
+ m.binding = MemberBinding.STATIC;
+ var parameters = new ArrayList<FormalParameter> ();
+@@ -360,14 +363,14 @@
+ if (reader.name == "varargs") {
+ start_element ("varargs");
+ next ();
+- param = new FormalParameter.with_ellipsis ();
++ param = new FormalParameter.with_ellipsis (get_current_src ());
+ end_element ("varargs");
+ } else {
+ var type = parse_type (out array_length_idx);
+ if (transfer == "full") {
+ type.value_owned = true;
+ }
+- param = new FormalParameter (name, type);
++ param = new FormalParameter (name, type, get_current_src ());
+ if (direction == "out") {
+ param.direction = ParameterDirection.OUT;
+ } else if (direction == "inout") {
+@@ -455,7 +458,7 @@
+
+ Struct parse_record () {
+ start_element ("record");
+- var st = new Struct (reader.get_attribute ("name"));
++ var st = new Struct (reader.get_attribute ("name"), get_current_src ());
+ st.access = SymbolAccessibility.PUBLIC;
+ next ();
+ while (current_token == MarkupTokenType.START_ELEMENT) {
+@@ -479,7 +482,7 @@
+
+ Class parse_class () {
+ start_element ("class");
+- var cl = new Class (reader.get_attribute ("name"));
++ var cl = new Class (reader.get_attribute ("name"), get_current_src ());
+ cl.access = SymbolAccessibility.PUBLIC;
+
+ string parent = reader.get_attribute ("parent");
+@@ -575,7 +578,7 @@
+
+ Interface parse_interface () {
+ start_element ("interface");
+- var iface = new Interface (reader.get_attribute ("name"));
++ var iface = new Interface (reader.get_attribute ("name"), get_current_src ());
+ iface.access = SymbolAccessibility.PUBLIC;
+ next ();
+ var methods = new ArrayList<Method> ();
+@@ -619,7 +622,7 @@
+ string name = reader.get_attribute ("name");
+ next ();
+ var type = parse_type ();
+- var field = new Field (name, type, null);
++ var field = new Field (name, type, null, get_current_src ());
+ field.access = SymbolAccessibility.PUBLIC;
+ end_element ("field");
+ return field;
+@@ -630,7 +633,7 @@
+ string name = string.joinv ("_", reader.get_attribute ("name").split ("-"));
+ next ();
+ var type = parse_type ();
+- var prop = new Property (name, type, null, null);
++ var prop = new Property (name, type, null, null, get_current_src ());
+ prop.access = SymbolAccessibility.PUBLIC;
+ prop.get_accessor = new PropertyAccessor (true, false, false, null, null);
+ prop.set_accessor = new PropertyAccessor (false, true, false, null, null);
+@@ -648,7 +651,7 @@
+ } else {
+ return_type = new VoidType ();
+ }
+- var d = new Delegate (name, return_type);
++ var d = new Delegate (name, return_type, get_current_src ());
+ d.access = SymbolAccessibility.PUBLIC;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+@@ -669,7 +672,7 @@
+
+ var return_type = parse_return_value ();
+
+- var m = new CreationMethod (null, name);
++ var m = new CreationMethod (null, name, get_current_src ());
+ m.access = SymbolAccessibility.PUBLIC;
+ m.has_construct_function = false;
+ if (m.name.has_prefix ("new_")) {
+@@ -698,7 +701,7 @@
+ } else {
+ return_type = new VoidType ();
+ }
+- var m = new Method (name, return_type);
++ var m = new Method (name, return_type, get_current_src ());
+ m.access = SymbolAccessibility.PUBLIC;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+ start_element ("parameters");
+@@ -726,7 +729,7 @@
+ } else {
+ return_type = new VoidType ();
+ }
+- var m = new Method (name, return_type);
++ var m = new Method (name, return_type, get_current_src ());
+ m.access = SymbolAccessibility.PUBLIC;
+ m.is_virtual = true;
+ if (current_token == MarkupTokenType.START_ELEMENT && reader.name == "parameters") {
+@@ -828,7 +831,7 @@
+ string name = reader.get_attribute ("name");
+ next ();
+ var type = parse_type ();
+- var c = new Constant (name, type, null, null);
++ var c = new Constant (name, type, null, get_current_src ());
+ c.access = SymbolAccessibility.PUBLIC;
+ end_element ("constant");
+ return c;
+Index: vapi/glib-2.0.vapi
+===================================================================
+--- vapi/glib-2.0.vapi (revision 1971)
++++ vapi/glib-2.0.vapi (revision 2004)
+@@ -2205,6 +2205,8 @@
+ public static int create_with_parents (string pathname, int mode);
+ [CCode (cname = "mkdtemp")]
+ public static weak string mkdtemp (string template);
++ [CCode (cname = "g_rmdir")]
++ public static int remove (string filename);
+ }
+
+ [Compact]
+Index: configure.ac
+===================================================================
+--- configure.ac (revision 1971)
++++ configure.ac (revision 2004)
+@@ -1,4 +1,4 @@
+-AC_INIT([vala], [0.5.1], [j@bitron.ch], [vala])
++AC_INIT([vala], [0.5.2], [j@bitron.ch], [vala])
+ AC_CONFIG_SRCDIR([Makefile.am])
+ AC_CONFIG_HEADERS(config.h)
+ AM_INIT_AUTOMAKE([dist-bzip2])
+Index: gobject/valaccodedynamicpropertymodule.vala
+===================================================================
+--- gobject/valaccodedynamicpropertymodule.vala (revision 1971)
++++ gobject/valaccodedynamicpropertymodule.vala (revision 2004)
+@@ -1,238 +0,0 @@
+-/* valaccodedynamicpropertymodule.vala
+- *
+- * Copyright (C) 2008 Jürg Billeter
+- *
+- * This library is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Lesser General Public
+- * License as published by the Free Software Foundation; either
+- * version 2.1 of the License, or (at your option) any later version.
+-
+- * This library is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * Lesser General Public License for more details.
+-
+- * You should have received a copy of the GNU Lesser General Public
+- * License along with this library; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+- *
+- * Author:
+- * Jürg Billeter <j@bitron.ch>
+- */
+-
+-using GLib;
+-using Gee;
+-
+-/**
+- * The link between a dynamic property and generated code.
+- */
+-public class Vala.CCodeDynamicPropertyModule : CCodeDelegateModule {
+- int dynamic_property_id;
+-
+- public CCodeDynamicPropertyModule (CCodeGenerator codegen, CCodeModule? next) {
+- base (codegen, next);
+- }
+-
+- public override string get_dynamic_property_getter_cname (DynamicProperty node) {
+- string getter_cname = "_dynamic_get_%s%d".printf (node.name, dynamic_property_id++);
+-
+- var dynamic_property = (DynamicProperty) node;
+-
+- var func = new CCodeFunction (getter_cname, node.property_type.get_cname ());
+- func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
+-
+- func.add_parameter (new CCodeFormalParameter ("obj", dynamic_property.dynamic_type.get_cname ()));
+-
+- var block = new CCodeBlock ();
+- if (dynamic_property.dynamic_type.data_type == dbus_object_type) {
+- generate_dbus_property_getter_wrapper (node, block);
+- } else if (dynamic_property.dynamic_type.data_type != null
+- && dynamic_property.dynamic_type.data_type.is_subtype_of (gobject_type)) {
+- generate_gobject_property_getter_wrapper (node, block);
+- } else {
+- Report.error (node.source_reference, "dynamic properties are not supported for `%s'".printf (dynamic_property.dynamic_type.to_string ()));
+- }
+-
+- // append to C source file
+- source_type_member_declaration.append (func.copy ());
+-
+- func.block = block;
+- source_type_member_definition.append (func);
+-
+- return getter_cname;
+- }
+-
+- public override string get_dynamic_property_setter_cname (DynamicProperty node) {
+- string setter_cname = "_dynamic_set_%s%d".printf (node.name, dynamic_property_id++);
+-
+- var dynamic_property = (DynamicProperty) node;
+-
+- var func = new CCodeFunction (setter_cname, "void");
+- func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
+-
+- func.add_parameter (new CCodeFormalParameter ("obj", dynamic_property.dynamic_type.get_cname ()));
+- func.add_parameter (new CCodeFormalParameter ("value", node.property_type.get_cname ()));
+-
+- var block = new CCodeBlock ();
+- if (dynamic_property.dynamic_type.data_type == dbus_object_type) {
+- generate_dbus_property_setter_wrapper (node, block);
+- } else if (dynamic_property.dynamic_type.data_type != null
+- && dynamic_property.dynamic_type.data_type.is_subtype_of (gobject_type)) {
+- generate_gobject_property_setter_wrapper (node, block);
+- } else {
+- Report.error (node.source_reference, "dynamic properties are not supported for `%s'".printf (dynamic_property.dynamic_type.to_string ()));
+- }
+-
+- // append to C source file
+- source_type_member_declaration.append (func.copy ());
+-
+- func.block = block;
+- source_type_member_definition.append (func);
+-
+- return setter_cname;
+- }
+-
+- void generate_gobject_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
+- var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
+- cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+- block.add_statement (cdecl);
+-
+- var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
+- call.add_argument (new CCodeIdentifier ("obj"));
+- call.add_argument (node.get_canonical_cconstant ());
+- call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
+- call.add_argument (new CCodeConstant ("NULL"));
+-
+- block.add_statement (new CCodeExpressionStatement (call));
+-
+- block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+- }
+-
+- void generate_gobject_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
+- var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
+- call.add_argument (new CCodeIdentifier ("obj"));
+- call.add_argument (node.get_canonical_cconstant ());
+- call.add_argument (new CCodeIdentifier ("value"));
+- call.add_argument (new CCodeConstant ("NULL"));
+-
+- block.add_statement (new CCodeExpressionStatement (call));
+- }
+-
+- void create_dbus_property_proxy (DynamicProperty node, CCodeBlock block) {
+- var prop_proxy_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_new_from_proxy"));
+- prop_proxy_call.add_argument (new CCodeIdentifier ("obj"));
+- prop_proxy_call.add_argument (new CCodeConstant ("DBUS_INTERFACE_PROPERTIES"));
+- prop_proxy_call.add_argument (new CCodeConstant ("NULL"));
+-
+- var prop_proxy_decl = new CCodeDeclaration ("DBusGProxy*");
+- prop_proxy_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("property_proxy", prop_proxy_call));
+- block.add_statement (prop_proxy_decl);
+- }
+-
+- void generate_dbus_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
+- create_dbus_property_proxy (node, block);
+-
+- // initialize GValue
+- var cvalinit = new CCodeInitializerList ();
+- cvalinit.append (new CCodeConstant ("0"));
+-
+- var cval_decl = new CCodeDeclaration ("GValue");
+- cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("gvalue", cvalinit));
+- block.add_statement (cval_decl);
+-
+- var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
+-
+- // call Get method on property proxy
+- var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
+- cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
+- block.add_statement (cdecl);
+-
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
+- ccall.add_argument (new CCodeIdentifier ("property_proxy"));
+- ccall.add_argument (new CCodeConstant ("\"Get\""));
+- ccall.add_argument (new CCodeConstant ("NULL"));
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
+- var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
+- get_iface.add_argument (new CCodeIdentifier ("obj"));
+- ccall.add_argument (get_iface);
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
+- ccall.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (node.name))));
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
+- ccall.add_argument (val_ptr);
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+-
+- block.add_statement (new CCodeExpressionStatement (ccall));
+-
+- // unref property proxy
+- var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
+- prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
+- block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
+-
+- // assign value to result variable
+- var cget_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_get_value_function ()));
+- cget_call.add_argument (val_ptr);
+- var assign = new CCodeAssignment (new CCodeIdentifier ("result"), cget_call);
+- block.add_statement (new CCodeExpressionStatement (assign));
+-
+- // return result
+- block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+- }
+-
+- void generate_dbus_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
+- create_dbus_property_proxy (node, block);
+-
+- // initialize GValue
+- var cvalinit = new CCodeInitializerList ();
+- cvalinit.append (new CCodeConstant ("0"));
+-
+- var cval_decl = new CCodeDeclaration ("GValue");
+- cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("gvalue", cvalinit));
+- block.add_statement (cval_decl);
+-
+- var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
+-
+- var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+- cinit_call.add_argument (val_ptr);
+- cinit_call.add_argument (new CCodeIdentifier (node.property_type.data_type.get_type_id ()));
+- block.add_statement (new CCodeExpressionStatement (cinit_call));
+-
+- var cset_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_set_value_function ()));
+- cset_call.add_argument (val_ptr);
+- cset_call.add_argument (new CCodeIdentifier ("value"));
+- block.add_statement (new CCodeExpressionStatement (cset_call));
+-
+- // call Set method on property proxy
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
+- ccall.add_argument (new CCodeIdentifier ("property_proxy"));
+- ccall.add_argument (new CCodeConstant ("\"Set\""));
+- ccall.add_argument (new CCodeConstant ("NULL"));
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
+- var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
+- get_iface.add_argument (new CCodeIdentifier ("obj"));
+- ccall.add_argument (get_iface);
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
+- ccall.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (node.name))));
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
+- ccall.add_argument (val_ptr);
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+-
+- ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+-
+- block.add_statement (new CCodeExpressionStatement (ccall));
+-
+- // unref property proxy
+- var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
+- prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
+- block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
+- }
+-}
+Index: gobject/valaccodedynamicsignalmodule.vala
+===================================================================
+--- gobject/valaccodedynamicsignalmodule.vala (revision 1971)
++++ gobject/valaccodedynamicsignalmodule.vala (revision 2004)
+@@ -1,195 +0,0 @@
+-/* valaccodedynamicsignalmodule.vala
+- *
+- * Copyright (C) 2007-2008 Jürg Billeter
+- *
+- * This library is free software; you can redistribute it and/or
+- * modify it under the terms of the GNU Lesser General Public
+- * License as published by the Free Software Foundation; either
+- * version 2.1 of the License, or (at your option) any later version.
+-
+- * This library is distributed in the hope that it will be useful,
+- * but WITHOUT ANY WARRANTY; without even the implied warranty of
+- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+- * Lesser General Public License for more details.
+-
+- * You should have received a copy of the GNU Lesser General Public
+- * License along with this library; if not, write to the Free Software
+- * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+- *
+- * Author:
+- * Jürg Billeter <j@bitron.ch>
+- */
+-
+-using GLib;
+-using Gee;
+-
+-/**
+- * The link between a dynamic signal and generated code.
+- */
+-public class Vala.CCodeDynamicSignalModule : CCodeDynamicPropertyModule {
+- public CCodeDynamicSignalModule (CCodeGenerator codegen, CCodeModule? next) {
+- base (codegen, next);
+- }
+-
+- int signal_wrapper_id;
+-
+- public override string get_dynamic_signal_cname (DynamicSignal node) {
+- return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
+- }
+-
+- public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal node) {
+- var dynamic_signal = (DynamicSignal) node;
+-
+- string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (node));
+- var func = new CCodeFunction (connect_wrapper_name, "void");
+- func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
+- func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
+- func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
+- func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
+- var block = new CCodeBlock ();
+- if (dynamic_signal.dynamic_type.data_type == dbus_object_type) {
+- generate_dbus_connect_wrapper (node, block);
+- } else if (dynamic_signal.dynamic_type.data_type != null
+- && dynamic_signal.dynamic_type.data_type.is_subtype_of (gobject_type)) {
+- generate_gobject_connect_wrapper (node, block);
+- } else {
+- Report.error (node.source_reference, "dynamic signals are not supported for `%s'".printf (dynamic_signal.dynamic_type.to_string ()));
+- }
+-
+- // append to C source file
+- source_type_member_declaration.append (func.copy ());
+-
+- func.block = block;
+- source_type_member_definition.append (func);
+-
+- return connect_wrapper_name;
+- }
+-
+- public override string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal node) {
+- var dynamic_signal = (DynamicSignal) node;
+-
+- string disconnect_wrapper_name = "_%sdisconnect".printf (get_dynamic_signal_cname (node));
+- var func = new CCodeFunction (disconnect_wrapper_name, "void");
+- func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
+- func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
+- func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
+- func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
+- var block = new CCodeBlock ();
+- if (dynamic_signal.dynamic_type.data_type == dbus_object_type) {
+- generate_dbus_disconnect_wrapper (node, block);
+- } else {
+- Report.error (node.source_reference, "dynamic signals are not supported for `%s'".printf (dynamic_signal.dynamic_type.to_string ()));
+- }
+-
+- // append to C source file
+- source_type_member_declaration.append (func.copy ());
+-
+- func.block = block;
+- source_type_member_definition.append (func);
+-
+- return disconnect_wrapper_name;
+- }
+-
+- void generate_gobject_connect_wrapper (DynamicSignal node, CCodeBlock block) {
+- var dynamic_signal = (DynamicSignal) node;
+-
+- var m = (Method) dynamic_signal.handler.symbol_reference;
+-
+- node.accept (codegen);
+-
+- string connect_func = "g_signal_connect_object";
+- if (m.binding != MemberBinding.INSTANCE) {
+- connect_func = "g_signal_connect";
+- }
+-
+- var call = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
+- call.add_argument (new CCodeIdentifier ("obj"));
+- call.add_argument (new CCodeIdentifier ("signal_name"));
+- call.add_argument (new CCodeIdentifier ("handler"));
+- call.add_argument (new CCodeIdentifier ("data"));
+-
+- if (m.binding == MemberBinding.INSTANCE) {
+- call.add_argument (new CCodeConstant ("0"));
+- }
+-
+- block.add_statement (new CCodeExpressionStatement (call));
+- }
+-
+- void generate_dbus_connect_wrapper (DynamicSignal node, CCodeBlock block) {
+- var dynamic_signal = (DynamicSignal) node;
+-
+- var m = (Method) dynamic_signal.handler.symbol_reference;
+-
+- node.accept (codegen);
+-
+- // FIXME should only be done once per marshaller
+- var register_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_register_marshaller"));
+- head.generate_marshaller (node.get_parameters (), node.return_type, true);
+- register_call.add_argument (new CCodeIdentifier (head.get_marshaller_function (node.get_parameters (), node.return_type, null, true)));
+- register_call.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
+-
+- var add_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_add_signal"));
+- add_call.add_argument (new CCodeIdentifier ("obj"));
+- add_call.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (node.name))));
+-
+- bool first = true;
+- foreach (FormalParameter param in m.get_parameters ()) {
+- if (first) {
+- // skip sender parameter
+- first = false;
+- continue;
+- }
+-
+- var array_type = param.parameter_type as ArrayType;
+- if (array_type != null) {
+- if (array_type.element_type.data_type == string_type.data_type) {
+- register_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
+- add_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
+- } else {
+- if (array_type.element_type.data_type.get_type_id () == null) {
+- Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
+- return;
+- }
+-
+- var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
+- carray_type.add_argument (new CCodeConstant ("\"GArray\""));
+- carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
+- register_call.add_argument (carray_type);
+- add_call.add_argument (carray_type);
+- }
+- } else {
+- if (param.parameter_type.get_type_id () == null) {
+- Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
+- return;
+- }
+-
+- register_call.add_argument (new CCodeIdentifier (param.parameter_type.get_type_id ()));
+- add_call.add_argument (new CCodeIdentifier (param.parameter_type.get_type_id ()));
+- }
+- }
+- register_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+- add_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
+-
+- block.add_statement (new CCodeExpressionStatement (register_call));
+- block.add_statement (new CCodeExpressionStatement (add_call));
+-
+- var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_connect_signal"));
+- call.add_argument (new CCodeIdentifier ("obj"));
+- call.add_argument (new CCodeIdentifier ("signal_name"));
+- call.add_argument (new CCodeIdentifier ("handler"));
+- call.add_argument (new CCodeIdentifier ("data"));
+- call.add_argument (new CCodeConstant ("NULL"));
+- block.add_statement (new CCodeExpressionStatement (call));
+- }
+-
+- void generate_dbus_disconnect_wrapper (DynamicSignal node, CCodeBlock block) {
+- var dynamic_signal = (DynamicSignal) node;
+-
+- var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_disconnect_signal"));
+- call.add_argument (new CCodeIdentifier ("obj"));
+- call.add_argument (new CCodeIdentifier ("signal_name"));
+- call.add_argument (new CCodeIdentifier ("handler"));
+- call.add_argument (new CCodeIdentifier ("data"));
+- block.add_statement (new CCodeExpressionStatement (call));
+- }
+-}
+Index: gobject/valagsignalmodule.vala
+===================================================================
+--- gobject/valagsignalmodule.vala (revision 1971)
++++ gobject/valagsignalmodule.vala (revision 2004)
+@@ -47,6 +47,17 @@
+ return ("VOID");
+ } else if (dbus && t.get_type_signature ().has_prefix ("(")) {
+ return ("BOXED");
++ } else if (t.data_type is Enum) {
++ var en = (Enum) t.data_type;
++ if (dbus) {
++ if (en.is_flags) {
++ return ("UINT");
++ } else {
++ return ("INT");
++ }
++ } else {
++ return en.get_marshaller_type_name ();
++ }
+ } else {
+ return t.data_type.get_marshaller_type_name ();
+ }
+@@ -266,6 +277,13 @@
+ get_value_function = "g_value_get_pointer";
+ } else if (dbus && p.parameter_type.get_type_signature ().has_prefix ("(")) {
+ get_value_function = "g_value_get_boxed";
++ } else if (dbus && p.parameter_type.data_type is Enum) {
++ var en = (Enum) p.parameter_type.data_type;
++ if (en.is_flags) {
++ get_value_function = "g_value_get_uint";
++ } else {
++ get_value_function = "g_value_get_int";
++ }
+ } else {
+ get_value_function = p.parameter_type.data_type.get_get_value_function ();
+ }
+@@ -306,6 +324,13 @@
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_object"));
+ } else if (dbus && return_type.get_type_signature ().has_prefix ("(")) {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_take_boxed"));
++ } else if (dbus && return_type.data_type is Enum) {
++ var en = (Enum) return_type.data_type;
++ if (en.is_flags) {
++ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_uint"));
++ } else {
++ set_fc = new CCodeFunctionCall (new CCodeIdentifier ("g_value_set_int"));
++ }
+ } else {
+ set_fc = new CCodeFunctionCall (new CCodeIdentifier (return_type.data_type.get_set_value_function ()));
+ }
+@@ -378,5 +403,228 @@
+
+ return csignew;
+ }
++
++ public override void visit_element_access (ElementAccess expr) {
++ if (expr.container is MemberAccess && expr.container.symbol_reference is Signal) {
++ // detailed signal emission
++ var sig = (Signal) expr.symbol_reference;
++ var ma = (MemberAccess) expr.container;
++
++ expr.accept_children (codegen);
++
++ var detail_expr = expr.get_indices ().get (0) as StringLiteral;
++ string signal_detail = detail_expr.eval ();
++
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
++
++ // FIXME: use C cast if debugging disabled
++ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
++ ccast.add_argument ((CCodeExpression) ma.inner.ccodenode);
++ ccall.add_argument (ccast);
++
++ ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
++
++ expr.ccodenode = ccall;
++ } else {
++ base.visit_element_access (expr);
++ }
++ }
++
++ CCodeExpression? emit_signal_assignment (Assignment assignment) {
++ var sig = (Signal) assignment.left.symbol_reference;
++
++ var m = (Method) assignment.right.symbol_reference;
++
++ string connect_func;
++ bool disconnect = false;
++
++ if (assignment.operator == AssignmentOperator.ADD) {
++ if (sig is DynamicSignal) {
++ connect_func = head.get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
++ } else {
++ connect_func = "g_signal_connect_object";
++ if (m.binding != MemberBinding.INSTANCE) {
++ connect_func = "g_signal_connect";
++ }
++ }
++ } else if (assignment.operator == AssignmentOperator.SUB) {
++ if (sig is DynamicSignal) {
++ connect_func = head.get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
++ } else {
++ connect_func = "g_signal_handlers_disconnect_matched";
++ }
++ disconnect = true;
++ } else {
++ assignment.error = true;
++ Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
++ return null;
++ }
++
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
++
++ string signal_detail = null;
++
++ // first argument: instance of sender
++ MemberAccess ma;
++ if (assignment.left is ElementAccess) {
++ var ea = (ElementAccess) assignment.left;
++ ma = (MemberAccess) ea.container;
++ var detail_expr = ea.get_indices ().get (0) as StringLiteral;
++ if (detail_expr == null) {
++ assignment.error = true;
++ Report.error (detail_expr.source_reference, "internal error: only literal string details supported");
++ return null;
++ }
++ signal_detail = detail_expr.eval ();
++ } else {
++ ma = (MemberAccess) assignment.left;
++ }
++ if (ma.inner != null) {
++ ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
++ } else {
++ ccall.add_argument (new CCodeIdentifier ("self"));
++ }
++
++ if (sig is DynamicSignal) {
++ // dynamic_signal_connect or dynamic_signal_disconnect
++
++ // second argument: signal name
++ ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
++ } else if (!disconnect) {
++ // g_signal_connect_object or g_signal_connect
++
++ // second argument: signal name
++ ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
++ } else {
++ // g_signal_handlers_disconnect_matched
++
++ // second argument: mask
++ if (signal_detail == null) {
++ ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
++ } else {
++ ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
++ }
++
++ // get signal id
++ var ccomma = new CCodeCommaExpression ();
++ var temp_decl = get_temp_variable (uint_type);
++ temp_vars.insert (0, temp_decl);
++ var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
++ parse_call.add_argument (sig.get_canonical_cconstant (signal_detail));
++ var decl_type = (TypeSymbol) sig.parent_symbol;
++ parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
++ parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
++ if (signal_detail == null) {
++ parse_call.add_argument (new CCodeConstant ("NULL"));
++ } else {
++ var detail_temp_decl = get_temp_variable (gquark_type);
++ temp_vars.insert (0, detail_temp_decl);
++ parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (detail_temp_decl.name)));
++ }
++ parse_call.add_argument (new CCodeConstant ("FALSE"));
++ ccomma.append_expression (parse_call);
++ ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
++
++ // third argument: signal_id
++ ccall.add_argument (ccomma);
++
++ // fourth argument: detail
++ ccall.add_argument (new CCodeConstant ("0"));
++ // fifth argument: closure
++ ccall.add_argument (new CCodeConstant ("NULL"));
++ }
++
++ // third resp. sixth argument: handler
++ ccall.add_argument (new CCodeCastExpression ((CCodeExpression) assignment.right.ccodenode, "GCallback"));
++
++ if (m.binding == MemberBinding.INSTANCE) {
++ // g_signal_connect_object or g_signal_handlers_disconnect_matched
++ // or dynamic_signal_connect or dynamic_signal_disconnect
++
++ // fourth resp. seventh argument: object/user_data
++ if (assignment.right is MemberAccess) {
++ var right_ma = (MemberAccess) assignment.right;
++ if (right_ma.inner != null) {
++ ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
++ } else {
++ ccall.add_argument (new CCodeIdentifier ("self"));
++ }
++ } else if (assignment.right is LambdaExpression) {
++ ccall.add_argument (new CCodeIdentifier ("self"));
++ }
++ if (!disconnect && !(sig is DynamicSignal)) {
++ // g_signal_connect_object
++
++ // fifth argument: connect_flags
++ ccall.add_argument (new CCodeConstant ("0"));
++ }
++ } else {
++ // g_signal_connect or g_signal_handlers_disconnect_matched
++ // or dynamic_signal_connect or dynamic_signal_disconnect
++
++ // fourth resp. seventh argument: user_data
++ ccall.add_argument (new CCodeConstant ("NULL"));
++ }
++
++ return ccall;
++ }
++
++ public override void visit_assignment (Assignment assignment) {
++ if (assignment.left.symbol_reference is Signal) {
++ assignment.right.accept (codegen);
++
++ if (assignment.left.error || assignment.right.error) {
++ assignment.error = true;
++ return;
++ }
++
++ assignment.ccodenode = emit_signal_assignment (assignment);
++ } else {
++ base.visit_assignment (assignment);
++ }
++ }
++
++ public override void visit_member_access (MemberAccess expr) {
++ CCodeExpression pub_inst = null;
++
++ if (expr.inner != null) {
++ pub_inst = (CCodeExpression) expr.inner.ccodenode;
++ }
++
++ if (expr.symbol_reference is Signal) {
++ var sig = (Signal) expr.symbol_reference;
++ var cl = (TypeSymbol) sig.parent_symbol;
++
++ if (expr.inner is BaseAccess && sig.is_virtual) {
++ var m = sig.get_method_handler ();
++ var base_class = (Class) m.parent_symbol;
++ var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
++ vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
++
++ expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name);
++ return;
++ }
++
++ if (sig.has_emitter) {
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
++
++ ccall.add_argument (pub_inst);
++ expr.ccodenode = ccall;
++ } else {
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
++
++ // FIXME: use C cast if debugging disabled
++ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
++ ccast.add_argument (pub_inst);
++ ccall.add_argument (ccast);
++
++ ccall.add_argument (sig.get_canonical_cconstant ());
++
++ expr.ccodenode = ccall;
++ }
++ } else {
++ base.visit_member_access (expr);
++ }
++ }
+ }
+
+Index: gobject/valaccodememberaccessmodule.vala
+===================================================================
+--- gobject/valaccodememberaccessmodule.vala (revision 1971)
++++ gobject/valaccodememberaccessmodule.vala (revision 2004)
+@@ -23,12 +23,23 @@
+
+ using GLib;
+
+-public class Vala.CCodeMemberAccessModule : CCodeMethodModule {
++public class Vala.CCodeMemberAccessModule : CCodeControlFlowModule {
+ public CCodeMemberAccessModule (CCodeGenerator codegen, CCodeModule? next) {
+ base (codegen, next);
+ }
+
+- private void process_cmember (MemberAccess expr, CCodeExpression? pub_inst, DataType? base_type) {
++ public override void visit_member_access (MemberAccess expr) {
++ CCodeExpression pub_inst = null;
++ DataType base_type = null;
++
++ if (expr.inner != null) {
++ pub_inst = (CCodeExpression) expr.inner.ccodenode;
++
++ if (expr.inner.value_type != null) {
++ base_type = expr.inner.value_type;
++ }
++ }
++
+ if (expr.symbol_reference is Method) {
+ var m = (Method) expr.symbol_reference;
+
+@@ -259,53 +270,7 @@
+ }
+ }
+ }
+- } else if (expr.symbol_reference is Signal) {
+- var sig = (Signal) expr.symbol_reference;
+- var cl = (TypeSymbol) sig.parent_symbol;
+-
+- if (expr.inner is BaseAccess && sig.is_virtual) {
+- var m = sig.get_method_handler ();
+- var base_class = (Class) m.parent_symbol;
+- var vcast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (base_class.get_upper_case_cname (null))));
+- vcast.add_argument (new CCodeIdentifier ("%s_parent_class".printf (current_class.get_lower_case_cname (null))));
+-
+- expr.ccodenode = new CCodeMemberAccess.pointer (vcast, m.name);
+- return;
+- }
+-
+- if (sig.has_emitter) {
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("%s_%s".printf (cl.get_lower_case_cname (null), sig.name)));
+-
+- ccall.add_argument (pub_inst);
+- expr.ccodenode = ccall;
+- } else {
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
+-
+- // FIXME: use C cast if debugging disabled
+- var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+- ccast.add_argument (pub_inst);
+- ccall.add_argument (ccast);
+-
+- ccall.add_argument (sig.get_canonical_cconstant ());
+-
+- expr.ccodenode = ccall;
+- }
+ }
+ }
+-
+- public override void visit_member_access (MemberAccess expr) {
+- CCodeExpression pub_inst = null;
+- DataType base_type = null;
+-
+- if (expr.inner != null) {
+- pub_inst = (CCodeExpression) expr.inner.ccodenode;
+-
+- if (expr.inner.value_type != null) {
+- base_type = expr.inner.value_type;
+- }
+- }
+-
+- process_cmember (expr, pub_inst, base_type);
+- }
+ }
+
+Index: gobject/valadbusclientmodule.vala
+===================================================================
+--- gobject/valadbusclientmodule.vala (revision 1971)
++++ gobject/valadbusclientmodule.vala (revision 2004)
+@@ -29,6 +29,8 @@
+ * The link between a dynamic method and generated code.
+ */
+ public class Vala.DBusClientModule : GAsyncModule {
++ int dynamic_property_id;
++
+ public DBusClientModule (CCodeGenerator codegen, CCodeModule? next) {
+ base (codegen, next);
+ }
+@@ -433,6 +435,10 @@
+ block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+ }
+ } else {
++ if (found_out) {
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++ }
++
+ block.add_statement (new CCodeExpressionStatement (ccall));
+
+ // don't access result when error occured
+@@ -460,6 +466,13 @@
+ }
+ carray_type.add_argument (get_dbus_g_type (array_type.element_type));
+ return carray_type;
++ } else if (data_type.data_type is Enum) {
++ var en = (Enum) data_type.data_type;
++ if (en.is_flags) {
++ return new CCodeIdentifier ("G_TYPE_UINT");
++ } else {
++ return new CCodeIdentifier ("G_TYPE_INT");
++ }
+ } else if (data_type.data_type == null) {
+ critical ("Internal error during DBus type generation with: %s", data_type.to_string ());
+ return new CCodeIdentifier ("G_TYPE_NONE");
+@@ -502,4 +515,291 @@
+ return true;
+ }
+ }
++
++ public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
++ if (prop.dynamic_type.data_type != dbus_object_type) {
++ return base.get_dynamic_property_getter_cname (prop);
++ }
++
++ string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
++
++ var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
++ func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
++
++ func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
++
++ var block = new CCodeBlock ();
++ generate_dbus_property_getter_wrapper (prop, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return getter_cname;
++ }
++
++ public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
++ if (prop.dynamic_type.data_type != dbus_object_type) {
++ return base.get_dynamic_property_setter_cname (prop);
++ }
++
++ string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
++
++ var func = new CCodeFunction (setter_cname, "void");
++ func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
++
++ func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
++ func.add_parameter (new CCodeFormalParameter ("value", prop.property_type.get_cname ()));
++
++ var block = new CCodeBlock ();
++ generate_dbus_property_setter_wrapper (prop, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return setter_cname;
++ }
++
++ void create_dbus_property_proxy (DynamicProperty node, CCodeBlock block) {
++ var prop_proxy_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_new_from_proxy"));
++ prop_proxy_call.add_argument (new CCodeIdentifier ("obj"));
++ prop_proxy_call.add_argument (new CCodeConstant ("DBUS_INTERFACE_PROPERTIES"));
++ prop_proxy_call.add_argument (new CCodeConstant ("NULL"));
++
++ var prop_proxy_decl = new CCodeDeclaration ("DBusGProxy*");
++ prop_proxy_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("property_proxy", prop_proxy_call));
++ block.add_statement (prop_proxy_decl);
++ }
++
++ void generate_dbus_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
++ create_dbus_property_proxy (node, block);
++
++ // initialize GValue
++ var cvalinit = new CCodeInitializerList ();
++ cvalinit.append (new CCodeConstant ("0"));
++
++ var cval_decl = new CCodeDeclaration ("GValue");
++ cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("gvalue", cvalinit));
++ block.add_statement (cval_decl);
++
++ var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
++
++ // call Get method on property proxy
++ var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
++ cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
++ block.add_statement (cdecl);
++
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
++ ccall.add_argument (new CCodeIdentifier ("property_proxy"));
++ ccall.add_argument (new CCodeConstant ("\"Get\""));
++ ccall.add_argument (new CCodeConstant ("NULL"));
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
++ var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
++ get_iface.add_argument (new CCodeIdentifier ("obj"));
++ ccall.add_argument (get_iface);
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
++ ccall.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (node.name))));
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
++ ccall.add_argument (val_ptr);
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++
++ block.add_statement (new CCodeExpressionStatement (ccall));
++
++ // unref property proxy
++ var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
++ prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
++ block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
++
++ // assign value to result variable
++ var cget_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_get_value_function ()));
++ cget_call.add_argument (val_ptr);
++ var assign = new CCodeAssignment (new CCodeIdentifier ("result"), cget_call);
++ block.add_statement (new CCodeExpressionStatement (assign));
++
++ // return result
++ block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
++ }
++
++ void generate_dbus_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
++ create_dbus_property_proxy (node, block);
++
++ // initialize GValue
++ var cvalinit = new CCodeInitializerList ();
++ cvalinit.append (new CCodeConstant ("0"));
++
++ var cval_decl = new CCodeDeclaration ("GValue");
++ cval_decl.add_declarator (new CCodeVariableDeclarator.with_initializer ("gvalue", cvalinit));
++ block.add_statement (cval_decl);
++
++ var val_ptr = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("gvalue"));
++
++ var cinit_call = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
++ cinit_call.add_argument (val_ptr);
++ cinit_call.add_argument (new CCodeIdentifier (node.property_type.data_type.get_type_id ()));
++ block.add_statement (new CCodeExpressionStatement (cinit_call));
++
++ var cset_call = new CCodeFunctionCall (new CCodeIdentifier (node.property_type.data_type.get_set_value_function ()));
++ cset_call.add_argument (val_ptr);
++ cset_call.add_argument (new CCodeIdentifier ("value"));
++ block.add_statement (new CCodeExpressionStatement (cset_call));
++
++ // call Set method on property proxy
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_call"));
++ ccall.add_argument (new CCodeIdentifier ("property_proxy"));
++ ccall.add_argument (new CCodeConstant ("\"Set\""));
++ ccall.add_argument (new CCodeConstant ("NULL"));
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
++ var get_iface = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_get_interface"));
++ get_iface.add_argument (new CCodeIdentifier ("obj"));
++ ccall.add_argument (get_iface);
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_STRING"));
++ ccall.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (node.name))));
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_VALUE"));
++ ccall.add_argument (val_ptr);
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++
++ ccall.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++
++ block.add_statement (new CCodeExpressionStatement (ccall));
++
++ // unref property proxy
++ var prop_proxy_unref = new CCodeFunctionCall (new CCodeIdentifier ("g_object_unref"));
++ prop_proxy_unref.add_argument (new CCodeIdentifier ("property_proxy"));
++ block.add_statement (new CCodeExpressionStatement (prop_proxy_unref));
++ }
++
++ public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
++ if (sig.dynamic_type.data_type != dbus_object_type) {
++ return base.get_dynamic_signal_connect_wrapper_name (sig);
++ }
++
++ string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
++ var func = new CCodeFunction (connect_wrapper_name, "void");
++ func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
++ func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
++ func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
++ func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
++ var block = new CCodeBlock ();
++ generate_dbus_connect_wrapper (sig, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return connect_wrapper_name;
++ }
++
++ public override string get_dynamic_signal_disconnect_wrapper_name (DynamicSignal sig) {
++ if (sig.dynamic_type.data_type != dbus_object_type) {
++ return base.get_dynamic_signal_disconnect_wrapper_name (sig);
++ }
++
++ string disconnect_wrapper_name = "_%sdisconnect".printf (get_dynamic_signal_cname (sig));
++ var func = new CCodeFunction (disconnect_wrapper_name, "void");
++ func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
++ func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
++ func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
++ func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
++ var block = new CCodeBlock ();
++ generate_dbus_disconnect_wrapper (sig, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return disconnect_wrapper_name;
++ }
++
++ void generate_dbus_connect_wrapper (DynamicSignal sig, CCodeBlock block) {
++ var m = (Method) sig.handler.symbol_reference;
++
++ sig.accept (codegen);
++
++ // FIXME should only be done once per marshaller
++ var register_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_object_register_marshaller"));
++ head.generate_marshaller (sig.get_parameters (), sig.return_type, true);
++ register_call.add_argument (new CCodeIdentifier (head.get_marshaller_function (sig.get_parameters (), sig.return_type, null, true)));
++ register_call.add_argument (new CCodeIdentifier ("G_TYPE_NONE"));
++
++ var add_call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_add_signal"));
++ add_call.add_argument (new CCodeIdentifier ("obj"));
++ add_call.add_argument (new CCodeConstant ("\"%s\"".printf (Symbol.lower_case_to_camel_case (sig.name))));
++
++ bool first = true;
++ foreach (FormalParameter param in m.get_parameters ()) {
++ if (first) {
++ // skip sender parameter
++ first = false;
++ continue;
++ }
++
++ var array_type = param.parameter_type as ArrayType;
++ if (array_type != null) {
++ if (array_type.element_type.data_type == string_type.data_type) {
++ register_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
++ add_call.add_argument (new CCodeIdentifier ("G_TYPE_STRV"));
++ } else {
++ if (array_type.element_type.data_type.get_type_id () == null) {
++ Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
++ return;
++ }
++
++ var carray_type = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_type_get_collection"));
++ carray_type.add_argument (new CCodeConstant ("\"GArray\""));
++ carray_type.add_argument (new CCodeIdentifier (array_type.element_type.data_type.get_type_id ()));
++ register_call.add_argument (carray_type);
++ add_call.add_argument (carray_type);
++ }
++ } else {
++ if (param.parameter_type.get_type_id () == null) {
++ Report.error (param.source_reference, "unsupported parameter type for D-Bus signals");
++ return;
++ }
++
++ register_call.add_argument (new CCodeIdentifier (param.parameter_type.get_type_id ()));
++ add_call.add_argument (new CCodeIdentifier (param.parameter_type.get_type_id ()));
++ }
++ }
++ register_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++ add_call.add_argument (new CCodeIdentifier ("G_TYPE_INVALID"));
++
++ block.add_statement (new CCodeExpressionStatement (register_call));
++ block.add_statement (new CCodeExpressionStatement (add_call));
++
++ var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_connect_signal"));
++ call.add_argument (new CCodeIdentifier ("obj"));
++ call.add_argument (new CCodeIdentifier ("signal_name"));
++ call.add_argument (new CCodeIdentifier ("handler"));
++ call.add_argument (new CCodeIdentifier ("data"));
++ call.add_argument (new CCodeConstant ("NULL"));
++ block.add_statement (new CCodeExpressionStatement (call));
++ }
++
++ void generate_dbus_disconnect_wrapper (DynamicSignal sig, CCodeBlock block) {
++ var call = new CCodeFunctionCall (new CCodeIdentifier ("dbus_g_proxy_disconnect_signal"));
++ call.add_argument (new CCodeIdentifier ("obj"));
++ call.add_argument (new CCodeIdentifier ("signal_name"));
++ call.add_argument (new CCodeIdentifier ("handler"));
++ call.add_argument (new CCodeIdentifier ("data"));
++ block.add_statement (new CCodeExpressionStatement (call));
++ }
+ }
+Index: gobject/valagerrormodule.vala
+===================================================================
+--- gobject/valagerrormodule.vala (revision 1971)
++++ gobject/valagerrormodule.vala (revision 2004)
+@@ -23,7 +23,7 @@
+ using GLib;
+ using Gee;
+
+-public class Vala.GErrorModule : CCodeDynamicSignalModule {
++public class Vala.GErrorModule : CCodeDelegateModule {
+ private int current_try_id = 0;
+ private int next_try_id = 0;
+
+Index: gobject/valaccodeassignmentmodule.vala
+===================================================================
+--- gobject/valaccodeassignmentmodule.vala (revision 1971)
++++ gobject/valaccodeassignmentmodule.vala (revision 2004)
+@@ -89,145 +89,6 @@
+ }
+ }
+
+- CCodeExpression? emit_signal_assignment (Assignment assignment) {
+- var sig = (Signal) assignment.left.symbol_reference;
+-
+- var m = (Method) assignment.right.symbol_reference;
+-
+- string connect_func;
+- bool disconnect = false;
+-
+- if (assignment.operator == AssignmentOperator.ADD) {
+- if (sig is DynamicSignal) {
+- connect_func = head.get_dynamic_signal_connect_wrapper_name ((DynamicSignal) sig);
+- } else {
+- connect_func = "g_signal_connect_object";
+- if (m.binding != MemberBinding.INSTANCE) {
+- connect_func = "g_signal_connect";
+- }
+- }
+- } else if (assignment.operator == AssignmentOperator.SUB) {
+- if (sig is DynamicSignal) {
+- connect_func = head.get_dynamic_signal_disconnect_wrapper_name ((DynamicSignal) sig);
+- } else {
+- connect_func = "g_signal_handlers_disconnect_matched";
+- }
+- disconnect = true;
+- } else {
+- assignment.error = true;
+- Report.error (assignment.source_reference, "Specified compound assignment type for signals not supported.");
+- return null;
+- }
+-
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
+-
+- string signal_detail = null;
+-
+- // first argument: instance of sender
+- MemberAccess ma;
+- if (assignment.left is ElementAccess) {
+- var ea = (ElementAccess) assignment.left;
+- ma = (MemberAccess) ea.container;
+- var detail_expr = ea.get_indices ().get (0) as StringLiteral;
+- if (detail_expr == null) {
+- assignment.error = true;
+- Report.error (detail_expr.source_reference, "internal error: only literal string details supported");
+- return null;
+- }
+- signal_detail = detail_expr.eval ();
+- } else {
+- ma = (MemberAccess) assignment.left;
+- }
+- if (ma.inner != null) {
+- ccall.add_argument ((CCodeExpression) get_ccodenode (ma.inner));
+- } else {
+- ccall.add_argument (new CCodeIdentifier ("self"));
+- }
+-
+- if (sig is DynamicSignal) {
+- // dynamic_signal_connect or dynamic_signal_disconnect
+-
+- // second argument: signal name
+- ccall.add_argument (new CCodeConstant ("\"%s\"".printf (sig.name)));
+- } else if (!disconnect) {
+- // g_signal_connect_object or g_signal_connect
+-
+- // second argument: signal name
+- ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
+- } else {
+- // g_signal_handlers_disconnect_matched
+-
+- // second argument: mask
+- if (signal_detail == null) {
+- ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
+- } else {
+- ccall.add_argument (new CCodeConstant ("G_SIGNAL_MATCH_ID | G_SIGNAL_MATCH_DETAIL | G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA"));
+- }
+-
+- // get signal id
+- var ccomma = new CCodeCommaExpression ();
+- var temp_decl = get_temp_variable (uint_type);
+- temp_vars.insert (0, temp_decl);
+- var parse_call = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_parse_name"));
+- parse_call.add_argument (sig.get_canonical_cconstant (signal_detail));
+- var decl_type = (TypeSymbol) sig.parent_symbol;
+- parse_call.add_argument (new CCodeIdentifier (decl_type.get_type_id ()));
+- parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (temp_decl.name)));
+- if (signal_detail == null) {
+- parse_call.add_argument (new CCodeConstant ("NULL"));
+- } else {
+- var detail_temp_decl = get_temp_variable (gquark_type);
+- temp_vars.insert (0, detail_temp_decl);
+- parse_call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier (detail_temp_decl.name)));
+- }
+- parse_call.add_argument (new CCodeConstant ("FALSE"));
+- ccomma.append_expression (parse_call);
+- ccomma.append_expression (new CCodeIdentifier (temp_decl.name));
+-
+- // third argument: signal_id
+- ccall.add_argument (ccomma);
+-
+- // fourth argument: detail
+- ccall.add_argument (new CCodeConstant ("0"));
+- // fifth argument: closure
+- ccall.add_argument (new CCodeConstant ("NULL"));
+- }
+-
+- // third resp. sixth argument: handler
+- ccall.add_argument (new CCodeCastExpression ((CCodeExpression) assignment.right.ccodenode, "GCallback"));
+-
+- if (m.binding == MemberBinding.INSTANCE) {
+- // g_signal_connect_object or g_signal_handlers_disconnect_matched
+- // or dynamic_signal_connect or dynamic_signal_disconnect
+-
+- // fourth resp. seventh argument: object/user_data
+- if (assignment.right is MemberAccess) {
+- var right_ma = (MemberAccess) assignment.right;
+- if (right_ma.inner != null) {
+- ccall.add_argument ((CCodeExpression) right_ma.inner.ccodenode);
+- } else {
+- ccall.add_argument (new CCodeIdentifier ("self"));
+- }
+- } else if (assignment.right is LambdaExpression) {
+- ccall.add_argument (new CCodeIdentifier ("self"));
+- }
+- if (!disconnect && !(sig is DynamicSignal)) {
+- // g_signal_connect_object
+-
+- // fifth argument: connect_flags
+- ccall.add_argument (new CCodeConstant ("0"));
+- }
+- } else {
+- // g_signal_connect or g_signal_handlers_disconnect_matched
+- // or dynamic_signal_connect or dynamic_signal_disconnect
+-
+- // fourth resp. seventh argument: user_data
+- ccall.add_argument (new CCodeConstant ("NULL"));
+- }
+-
+- return ccall;
+- }
+-
+ private CCodeExpression? emit_non_array_element_access (Assignment assignment) {
+ // custom element access
+ CCodeExpression rhs = (CCodeExpression) assignment.right.ccodenode;
+@@ -373,8 +234,6 @@
+
+ if (assignment.left.symbol_reference is Property) {
+ assignment.ccodenode = emit_property_assignment (assignment);
+- } else if (assignment.left.symbol_reference is Signal) {
+- assignment.ccodenode = emit_signal_assignment (assignment);
+ } else if (assignment.left is ElementAccess
+ && !(((ElementAccess) assignment.left).container.value_type is ArrayType)
+ && !(((ElementAccess) assignment.left).container.value_type is PointerType)) {
+Index: gobject/valaccodecontrolflowmodule.vala
+===================================================================
+--- gobject/valaccodecontrolflowmodule.vala (revision 0)
++++ gobject/valaccodecontrolflowmodule.vala (revision 2004)
+@@ -0,0 +1,572 @@
++/* valaccodecontrolflowmodule.vala
++ *
++ * Copyright (C) 2006-2008 Jürg Billeter, Raffaele Sandrini
++ *
++ * This library is free software; you can redistribute it and/or
++ * modify it under the terms of the GNU Lesser General Public
++ * License as published by the Free Software Foundation; either
++ * version 2.1 of the License, or (at your option) any later version.
++
++ * This library is distributed in the hope that it will be useful,
++ * but WITHOUT ANY WARRANTY; without even the implied warranty of
++ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
++ * Lesser General Public License for more details.
++
++ * You should have received a copy of the GNU Lesser General Public
++ * License along with this library; if not, write to the Free Software
++ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
++ *
++ * Author:
++ * Jürg Billeter <j@bitron.ch>
++ * Raffaele Sandrini <raffaele@sandrini.ch>
++ */
++
++using GLib;
++using Gee;
++
++public class Vala.CCodeControlFlowModule : CCodeMethodModule {
++ public CCodeControlFlowModule (CCodeGenerator codegen, CCodeModule? next) {
++ base (codegen, next);
++ }
++
++ public override void visit_if_statement (IfStatement stmt) {
++ stmt.accept_children (codegen);
++
++ if (stmt.false_statement != null) {
++ stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
++ } else {
++ stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
++ }
++
++ create_temp_decl (stmt, stmt.condition.temp_vars);
++ }
++
++ void visit_string_switch_statement (SwitchStatement stmt) {
++ // we need a temporary variable to save the property value
++ var temp_var = get_temp_variable (stmt.expression.value_type, true, stmt);
++ stmt.expression.temp_vars.insert (0, temp_var);
++
++ var ctemp = new CCodeIdentifier (temp_var.name);
++ var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
++ var czero = new CCodeConstant ("0");
++
++ var cswitchblock = new CCodeFragment ();
++ stmt.ccodenode = cswitchblock;
++
++ var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), ctemp);
++ var cquark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
++ cquark.add_argument (ctemp);
++
++ var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cquark);
++
++ temp_var = get_temp_variable (gquark_type);
++ stmt.expression.temp_vars.insert (0, temp_var);
++
++ int label_count = 0;
++
++ foreach (SwitchSection section in stmt.get_sections ()) {
++ if (section.has_default_label ()) {
++ continue;
++ }
++
++ foreach (SwitchLabel label in section.get_labels ()) {
++ var cexpr = (CCodeExpression) label.expression.ccodenode;
++
++ if (is_constant_ccode_expression (cexpr)) {
++ var cname = "%s_label%d".printf (temp_var.name, label_count++);
++ var cdecl = new CCodeDeclaration (gquark_type.get_cname ());
++
++ cdecl.modifiers = CCodeModifiers.STATIC;
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (cname, czero));
++
++ cswitchblock.append (cdecl);
++ }
++ }
++ }
++
++ cswitchblock.append (new CCodeExpressionStatement (cinit));
++
++ ctemp = new CCodeIdentifier (temp_var.name);
++ cinit = new CCodeAssignment (ctemp, ccond);
++
++ cswitchblock.append (new CCodeExpressionStatement (cinit));
++ create_temp_decl (stmt, stmt.expression.temp_vars);
++
++ Gee.List<Statement> default_statements = null;
++ label_count = 0;
++
++ // generate nested if statements
++ CCodeStatement ctopstmt = null;
++ CCodeIfStatement coldif = null;
++
++ foreach (SwitchSection section in stmt.get_sections ()) {
++ if (section.has_default_label ()) {
++ default_statements = section.get_statements ();
++ continue;
++ }
++
++ CCodeBinaryExpression cor = null;
++ foreach (SwitchLabel label in section.get_labels ()) {
++ var cexpr = (CCodeExpression) label.expression.ccodenode;
++
++ if (is_constant_ccode_expression (cexpr)) {
++ var cname = new CCodeIdentifier ("%s_label%d".printf (temp_var.name, label_count++));
++ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, czero, cname);
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
++ var cinit = new CCodeParenthesizedExpression (new CCodeAssignment (cname, ccall));
++
++ ccall.add_argument (cexpr);
++
++ cexpr = new CCodeConditionalExpression (ccond, cname, cinit);
++ } else {
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
++ ccall.add_argument (cexpr);
++ cexpr = ccall;
++ }
++
++ var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, cexpr);
++
++ if (cor == null) {
++ cor = ccmp;
++ } else {
++ cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
++ }
++ }
++
++ var cblock = new CCodeBlock ();
++ foreach (CodeNode body_stmt in section.get_statements ()) {
++ if (body_stmt.ccodenode is CCodeFragment) {
++ foreach (CCodeNode cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
++ cblock.add_statement (cstmt);
++ }
++ } else {
++ cblock.add_statement (body_stmt.ccodenode);
++ }
++ }
++
++ var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
++ var cif = new CCodeIfStatement (cor, cdo);
++
++ if (coldif != null) {
++ coldif.false_statement = cif;
++ } else {
++ ctopstmt = cif;
++ }
++
++ coldif = cif;
++ }
++
++ if (default_statements != null) {
++ var cblock = new CCodeBlock ();
++ foreach (CodeNode body_stmt in default_statements) {
++ cblock.add_statement (body_stmt.ccodenode);
++ }
++
++ var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
++
++ if (coldif == null) {
++ // there is only one section and that section
++ // contains a default label
++ ctopstmt = cdo;
++ } else {
++ coldif.false_statement = cdo;
++ }
++ }
++
++ cswitchblock.append (ctopstmt);
++ }
++
++ public override void visit_switch_statement (SwitchStatement stmt) {
++ if (stmt.expression.value_type.compatible (string_type)) {
++ visit_string_switch_statement (stmt);
++ return;
++ }
++
++ var cswitch = new CCodeSwitchStatement ((CCodeExpression) stmt.expression.ccodenode);
++ stmt.ccodenode = cswitch;
++
++ foreach (SwitchSection section in stmt.get_sections ()) {
++ if (section.has_default_label ()) {
++ cswitch.add_statement (new CCodeLabel ("default"));
++ var cdefaultblock = new CCodeBlock ();
++ cswitch.add_statement (cdefaultblock);
++ foreach (CodeNode default_stmt in section.get_statements ()) {
++ cdefaultblock.add_statement (default_stmt.ccodenode);
++ }
++ continue;
++ }
++
++ foreach (SwitchLabel label in section.get_labels ()) {
++ cswitch.add_statement (new CCodeCaseStatement ((CCodeExpression) label.expression.ccodenode));
++ }
++
++ var cblock = new CCodeBlock ();
++ cswitch.add_statement (cblock);
++ foreach (CodeNode body_stmt in section.get_statements ()) {
++ cblock.add_statement (body_stmt.ccodenode);
++ }
++ }
++ }
++
++ public override void visit_switch_section (SwitchSection section) {
++ visit_block (section);
++ }
++
++ public override void visit_while_statement (WhileStatement stmt) {
++ stmt.accept_children (codegen);
++
++ stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
++
++ create_temp_decl (stmt, stmt.condition.temp_vars);
++ }
++
++ public override void visit_do_statement (DoStatement stmt) {
++ stmt.accept_children (codegen);
++
++ stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
++
++ create_temp_decl (stmt, stmt.condition.temp_vars);
++ }
++
++ public override void visit_for_statement (ForStatement stmt) {
++ stmt.accept_children (codegen);
++
++ CCodeExpression ccondition = null;
++ if (stmt.condition != null) {
++ ccondition = (CCodeExpression) stmt.condition.ccodenode;
++ }
++
++ var cfor = new CCodeForStatement (ccondition, (CCodeStatement) stmt.body.ccodenode);
++ stmt.ccodenode = cfor;
++
++ foreach (Expression init_expr in stmt.get_initializer ()) {
++ cfor.add_initializer ((CCodeExpression) init_expr.ccodenode);
++ create_temp_decl (stmt, init_expr.temp_vars);
++ }
++
++ foreach (Expression it_expr in stmt.get_iterator ()) {
++ cfor.add_iterator ((CCodeExpression) it_expr.ccodenode);
++ create_temp_decl (stmt, it_expr.temp_vars);
++ }
++
++ if (stmt.condition != null) {
++ create_temp_decl (stmt, stmt.condition.temp_vars);
++ }
++ }
++
++ public override void visit_foreach_statement (ForeachStatement stmt) {
++ stmt.element_variable.active = true;
++ stmt.collection_variable.active = true;
++ if (stmt.iterator_variable != null) {
++ stmt.iterator_variable.active = true;
++ }
++
++ visit_block (stmt);
++
++ var cblock = new CCodeBlock ();
++ // sets #line
++ stmt.ccodenode = cblock;
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, stmt.collection.temp_vars);
++ cblock.add_statement (cfrag);
++
++ var collection_backup = stmt.collection_variable;
++ var collection_type = collection_backup.variable_type.copy ();
++ var ccoldecl = new CCodeDeclaration (collection_type.get_cname ());
++ var ccolvardecl = new CCodeVariableDeclarator.with_initializer (collection_backup.name, (CCodeExpression) stmt.collection.ccodenode);
++ ccolvardecl.line = cblock.line;
++ ccoldecl.add_declarator (ccolvardecl);
++ cblock.add_statement (ccoldecl);
++
++ if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
++ // exception handling
++ var cfrag = new CCodeFragment ();
++ head.add_simple_check (stmt.collection, cfrag);
++ cblock.add_statement (cfrag);
++ }
++
++ if (stmt.collection.value_type is ArrayType) {
++ var array_type = (ArrayType) stmt.collection.value_type;
++
++ var array_len = head.get_array_length_cexpression (stmt.collection);
++
++ // store array length for use by _vala_array_free
++ var clendecl = new CCodeDeclaration ("int");
++ clendecl.add_declarator (new CCodeVariableDeclarator.with_initializer (head.get_array_length_cname (collection_backup.name, 1), array_len));
++ cblock.add_statement (clendecl);
++
++ if (array_len is CCodeConstant) {
++ // the array has no length parameter i.e. it is NULL-terminated array
++
++ var it_name = "%s_it".printf (stmt.variable_name);
++
++ var citdecl = new CCodeDeclaration (collection_type.get_cname ());
++ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
++ cblock.add_statement (citdecl);
++
++ var cbody = new CCodeBlock ();
++
++ CCodeExpression element_expr = new CCodeIdentifier ("*%s".printf (it_name));
++
++ var element_type = array_type.element_type.copy ();
++ element_type.value_owned = false;
++ element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, temp_vars);
++ cbody.add_statement (cfrag);
++ temp_vars.clear ();
++
++ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
++ cbody.add_statement (cdecl);
++
++ // add array length variable for stacked arrays
++ if (stmt.type_reference is ArrayType) {
++ var inner_array_type = (ArrayType) stmt.type_reference;
++ for (int dim = 1; dim <= inner_array_type.rank; dim++) {
++ cdecl = new CCodeDeclaration ("int");
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (head.get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
++ cbody.add_statement (cdecl);
++ }
++ }
++
++ cbody.add_statement (stmt.body.ccodenode);
++
++ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("*%s".printf (it_name)), new CCodeConstant ("NULL"));
++
++ var cfor = new CCodeForStatement (ccond, cbody);
++
++ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
++
++ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
++ cblock.add_statement (cfor);
++ } else {
++ // the array has a length parameter
++
++ var it_name = (stmt.variable_name + "_it");
++
++ var citdecl = new CCodeDeclaration ("int");
++ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
++ cblock.add_statement (citdecl);
++
++ var cbody = new CCodeBlock ();
++
++ CCodeExpression element_expr = new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name));
++
++ var element_type = array_type.element_type.copy ();
++ element_type.value_owned = false;
++ element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, temp_vars);
++ cbody.add_statement (cfrag);
++ temp_vars.clear ();
++
++ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
++ cbody.add_statement (cdecl);
++
++ // add array length variable for stacked arrays
++ if (stmt.type_reference is ArrayType) {
++ var inner_array_type = (ArrayType) stmt.type_reference;
++ for (int dim = 1; dim <= inner_array_type.rank; dim++) {
++ cdecl = new CCodeDeclaration ("int");
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (head.get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
++ cbody.add_statement (cdecl);
++ }
++ }
++
++ cbody.add_statement (stmt.body.ccodenode);
++
++ var ccond_ind1 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, array_len, new CCodeConstant ("-1"));
++ var ccond_ind2 = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), array_len);
++ var ccond_ind = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_ind1, ccond_ind2);
++
++ /* only check for null if the containers elements are of reference-type */
++ CCodeBinaryExpression ccond;
++ if (array_type.element_type.is_reference_type_or_type_parameter ()) {
++ var ccond_term1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, array_len, new CCodeConstant ("-1"));
++ var ccond_term2 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)), new CCodeConstant ("NULL"));
++ var ccond_term = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_term1, ccond_term2);
++
++ ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeParenthesizedExpression (ccond_ind), new CCodeParenthesizedExpression (ccond_term));
++ } else {
++ /* assert when trying to iterate over value-type arrays of unknown length */
++ var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
++ cassert.add_argument (ccond_ind1);
++ cblock.add_statement (new CCodeExpressionStatement (cassert));
++
++ ccond = ccond_ind2;
++ }
++
++ var cfor = new CCodeForStatement (ccond, cbody);
++ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
++ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
++ cblock.add_statement (cfor);
++ }
++ } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
++ // iterating over a GList or GSList
++
++ var it_name = "%s_it".printf (stmt.variable_name);
++
++ var citdecl = new CCodeDeclaration (collection_type.get_cname ());
++ var citvardecl = new CCodeVariableDeclarator (it_name);
++ citvardecl.line = cblock.line;
++ citdecl.add_declarator (citvardecl);
++ cblock.add_statement (citdecl);
++
++ var cbody = new CCodeBlock ();
++
++ CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data");
++
++ if (collection_type.get_type_arguments ().size != 1) {
++ Report.error (stmt.source_reference, "internal error: missing generic type argument");
++ stmt.error = true;
++ return;
++ }
++
++ var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
++ element_data_type.value_owned = false;
++ element_data_type.is_type_argument = true;
++ element_expr = transform_expression (element_expr, element_data_type, stmt.type_reference);
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, temp_vars);
++ cbody.add_statement (cfrag);
++ temp_vars.clear ();
++
++ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
++ var cvardecl = new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr);
++ cvardecl.line = cblock.line;
++ cdecl.add_declarator (cvardecl);
++ cbody.add_statement (cdecl);
++
++ cbody.add_statement (stmt.body.ccodenode);
++
++ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (it_name), new CCodeConstant ("NULL"));
++
++ var cfor = new CCodeForStatement (ccond, cbody);
++
++ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
++
++ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "next")));
++ cblock.add_statement (cfor);
++ } else if (list_type != null && stmt.collection.value_type.compatible (new ObjectType (list_type))) {
++ // iterating over a Gee.List, use integer to avoid the cost of an iterator object
++
++ var it_name = "%s_it".printf (stmt.variable_name);
++
++ var citdecl = new CCodeDeclaration ("int");
++ citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
++ cblock.add_statement (citdecl);
++
++ var cbody = new CCodeBlock ();
++
++ var get_method = (Method) list_type.scope.lookup ("get");
++ var get_ccall = new CCodeFunctionCall (new CCodeIdentifier (get_method.get_cname ()));
++ get_ccall.add_argument (new InstanceCast (new CCodeIdentifier (collection_backup.name), list_type));
++ get_ccall.add_argument (new CCodeIdentifier (it_name));
++ CCodeExpression element_expr = get_ccall;
++
++ var element_type = SemanticAnalyzer.get_actual_type (stmt.collection.value_type, get_method, get_method.return_type, stmt);
++
++ element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, temp_vars);
++ cbody.add_statement (cfrag);
++ temp_vars.clear ();
++
++ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
++ var cvardecl = new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr);
++ cvardecl.line = cblock.line;
++ cdecl.add_declarator (cvardecl);
++ cbody.add_statement (cdecl);
++
++ cbody.add_statement (stmt.body.ccodenode);
++
++ var list_len = new CCodeFunctionCall (new CCodeIdentifier ("gee_collection_get_size"));
++ list_len.add_argument (new InstanceCast (new CCodeIdentifier (collection_backup.name), this.collection_type));
++
++ var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), list_len);
++
++ var cfor = new CCodeForStatement (ccond, cbody);
++ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
++ cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
++ cfor.line = cblock.line;
++ cblock.add_statement (cfor);
++ } else if (iterable_type != null && stmt.collection.value_type.compatible (new ObjectType (iterable_type))) {
++ // iterating over a Gee.Iterable, use iterator
++
++ var it_name = "%s_it".printf (stmt.variable_name);
++
++ var citdecl = new CCodeDeclaration (iterator_type.get_cname () + "*");
++ var it_method = (Method) iterable_type.scope.lookup ("iterator");
++ var it_ccall = new CCodeFunctionCall (new CCodeIdentifier (it_method.get_cname ()));
++ it_ccall.add_argument (new InstanceCast (new CCodeIdentifier (collection_backup.name), iterable_type));
++ var citvardecl = new CCodeVariableDeclarator.with_initializer (it_name, it_ccall);
++ citvardecl.line = cblock.line;
++ citdecl.add_declarator (citvardecl);
++ cblock.add_statement (citdecl);
++
++ var cbody = new CCodeBlock ();
++
++ var get_method = (Method) iterator_type.scope.lookup ("get");
++ var get_ccall = new CCodeFunctionCall (new CCodeIdentifier (get_method.get_cname ()));
++ get_ccall.add_argument (new CCodeIdentifier (it_name));
++ CCodeExpression element_expr = get_ccall;
++
++ Iterator<DataType> type_arg_it = it_method.return_type.get_type_arguments ().iterator ();
++ type_arg_it.next ();
++ var it_type = SemanticAnalyzer.get_actual_type (stmt.collection.value_type, it_method, type_arg_it.get (), stmt);
++
++ element_expr = transform_expression (element_expr, it_type, stmt.type_reference);
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, temp_vars);
++ cbody.add_statement (cfrag);
++ temp_vars.clear ();
++
++ var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
++ var cvardecl = new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr);
++ cvardecl.line = cblock.line;
++ cdecl.add_declarator (cvardecl);
++ cbody.add_statement (cdecl);
++
++ cbody.add_statement (stmt.body.ccodenode);
++
++ var next_method = (Method) iterator_type.scope.lookup ("next");
++ var next_ccall = new CCodeFunctionCall (new CCodeIdentifier (next_method.get_cname ()));
++ next_ccall.add_argument (new CCodeIdentifier (it_name));
++
++ var cwhile = new CCodeWhileStatement (next_ccall, cbody);
++ cwhile.line = cblock.line;
++ cblock.add_statement (cwhile);
++ }
++
++ foreach (LocalVariable local in stmt.get_local_variables ()) {
++ if (requires_destroy (local.variable_type)) {
++ var ma = new MemberAccess.simple (local.name);
++ ma.symbol_reference = local;
++ var cunref = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (local.name)), local.variable_type, ma));
++ cunref.line = cblock.line;
++ cblock.add_statement (cunref);
++ }
++ }
++ }
++
++ public override void visit_break_statement (BreakStatement stmt) {
++ stmt.ccodenode = new CCodeBreakStatement ();
++
++ create_local_free (stmt, true);
++ }
++
++ public override void visit_continue_statement (ContinueStatement stmt) {
++ stmt.ccodenode = new CCodeContinueStatement ();
++
++ create_local_free (stmt, true);
++ }
++}
++
+Index: gobject/valaccodebasemodule.vala
+===================================================================
+--- gobject/valaccodebasemodule.vala (revision 1971)
++++ gobject/valaccodebasemodule.vala (revision 2004)
+@@ -78,7 +78,6 @@
+ public Gee.Set<string> c_keywords;
+
+ public int next_temp_var_id = 0;
+- private int next_array_dup_id = 0;
+ public bool in_creation_method = false;
+ public bool in_constructor = false;
+ public bool in_static_or_class_ctor = false;
+@@ -213,36 +212,6 @@
+ }
+ }
+
+- public override CCodeExpression get_construct_property_assignment (CCodeConstant canonical_cconstant, DataType property_type, CCodeExpression value) {
+- // this property is used as a construction parameter
+- var cpointer = new CCodeIdentifier ("__params_it");
+-
+- var ccomma = new CCodeCommaExpression ();
+- // set name in array for current parameter
+- var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
+- var cnameassign = new CCodeAssignment (cnamemember, canonical_cconstant);
+- ccomma.append_expression (cnameassign);
+-
+- var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
+-
+- // initialize GValue in array for current parameter
+- var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
+- cvalueinit.add_argument (gvaluearg);
+- cvalueinit.add_argument (new CCodeIdentifier (property_type.get_type_id ()));
+- ccomma.append_expression (cvalueinit);
+-
+- // set GValue for current parameter
+- var cvalueset = new CCodeFunctionCall (get_value_setter_function (property_type));
+- cvalueset.add_argument (gvaluearg);
+- cvalueset.add_argument (value);
+- ccomma.append_expression (cvalueset);
+-
+- // move pointer to next parameter in array
+- ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
+-
+- return ccomma;
+- }
+-
+ private CCodeIncludeDirective get_internal_include (string filename) {
+ return new CCodeIncludeDirective (filename, context.library == null);
+ }
+@@ -939,7 +908,7 @@
+ }
+ }
+
+- private bool is_constant_ccode_expression (CCodeExpression cexpr) {
++ public bool is_constant_ccode_expression (CCodeExpression cexpr) {
+ if (cexpr is CCodeConstant) {
+ return true;
+ } else if (cexpr is CCodeBinaryExpression) {
+@@ -1208,133 +1177,6 @@
+ current_return_type = null;
+ }
+
+- public override void visit_constructor (Constructor c) {
+- current_method_inner_error = false;
+- in_constructor = true;
+-
+- if (c.binding == MemberBinding.CLASS || c.binding == MemberBinding.STATIC) {
+- in_static_or_class_ctor = true;
+- }
+- c.accept_children (codegen);
+- in_static_or_class_ctor = false;
+-
+- in_constructor = false;
+-
+- var cl = (Class) c.parent_symbol;
+-
+- if (c.binding == MemberBinding.INSTANCE) {
+- function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
+- function.modifiers = CCodeModifiers.STATIC;
+-
+- function.add_parameter (new CCodeFormalParameter ("type", "GType"));
+- function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
+- function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
+-
+- source_type_member_declaration.append (function.copy ());
+-
+-
+- var cblock = new CCodeBlock ();
+- var cdecl = new CCodeDeclaration ("GObject *");
+- cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
+- cblock.add_statement (cdecl);
+-
+- cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
+- cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
+- cblock.add_statement (cdecl);
+-
+- cdecl = new CCodeDeclaration ("GObjectClass *");
+- cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
+- cblock.add_statement (cdecl);
+-
+-
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
+- ccall.add_argument (new CCodeIdentifier (cl.get_type_id ()));
+- var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
+- ccast.add_argument (ccall);
+- cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
+-
+- ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
+- ccall.add_argument (new CCodeIdentifier ("klass"));
+- ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
+- ccast.add_argument (ccall);
+- cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
+-
+-
+- ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
+- ccall.add_argument (new CCodeIdentifier ("type"));
+- ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
+- ccall.add_argument (new CCodeIdentifier ("construct_properties"));
+- cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
+-
+-
+- ccall = new InstanceCast (new CCodeIdentifier ("obj"), cl);
+-
+- cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
+-
+- cblock.add_statement (cdecl);
+-
+- if (current_method_inner_error) {
+- /* always separate error parameter and inner_error local variable
+- * as error may be set to NULL but we're always interested in inner errors
+- */
+- var cdecl = new CCodeDeclaration ("GError *");
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
+- cblock.add_statement (cdecl);
+- }
+-
+-
+- cblock.add_statement (c.body.ccodenode);
+-
+- cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
+-
+- function.block = cblock;
+-
+- if (c.source_reference.comment != null) {
+- source_type_member_definition.append (new CCodeComment (c.source_reference.comment));
+- }
+- source_type_member_definition.append (function);
+- } else if (c.binding == MemberBinding.CLASS) {
+- // class constructor
+-
+- var base_init = new CCodeFunction ("%s_base_init".printf (cl.get_lower_case_cname (null)), "void");
+- base_init.add_parameter (new CCodeFormalParameter ("klass", "%sClass *".printf (cl.get_cname ())));
+- base_init.modifiers = CCodeModifiers.STATIC;
+-
+- source_type_member_declaration.append (base_init.copy ());
+-
+- var block = (CCodeBlock) c.body.ccodenode;
+- if (current_method_inner_error) {
+- /* always separate error parameter and inner_error local variable
+- * as error may be set to NULL but we're always interested in inner errors
+- */
+- var cdecl = new CCodeDeclaration ("GError *");
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
+- block.prepend_statement (cdecl);
+- }
+-
+- base_init.block = block;
+-
+- source_type_member_definition.append (base_init);
+- } else if (c.binding == MemberBinding.STATIC) {
+- // static class constructor
+- // add to class_init
+-
+- if (current_method_inner_error) {
+- /* always separate error parameter and inner_error local variable
+- * as error may be set to NULL but we're always interested in inner errors
+- */
+- var cdecl = new CCodeDeclaration ("GError *");
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
+- class_init_fragment.append (cdecl);
+- }
+-
+- class_init_fragment.append (c.body.ccodenode);
+- } else {
+- Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
+- }
+- }
+-
+ public override void visit_destructor (Destructor d) {
+ current_method_inner_error = false;
+
+@@ -1600,12 +1442,12 @@
+ }
+ }
+
+- public CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference) {
+- var cl = type.data_type as Class;
++ public virtual CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference) {
+ if (type is ErrorType) {
+ return new CCodeIdentifier ("g_error_copy");
+ } else if (type.data_type != null) {
+ string dup_function;
++ var cl = type.data_type as Class;
+ if (type.data_type.is_reference_counting ()) {
+ dup_function = type.data_type.get_ref_function ();
+ if (type.data_type is Interface && dup_function == null) {
+@@ -1631,8 +1473,6 @@
+ } else if (type.type_parameter != null && current_type_symbol is Class) {
+ string func_name = "%s_dup_func".printf (type.type_parameter.name.down ());
+ return new CCodeMemberAccess.pointer (new CCodeMemberAccess.pointer (new CCodeIdentifier ("self"), "priv"), func_name);
+- } else if (type is ArrayType) {
+- return new CCodeIdentifier (generate_array_dup_wrapper ((ArrayType) type));
+ } else if (type is PointerType) {
+ var pointer_type = (PointerType) type;
+ return get_dup_func_expression (pointer_type.base_type, source_reference);
+@@ -1641,78 +1481,6 @@
+ }
+ }
+
+- string generate_array_dup_wrapper (ArrayType array_type) {
+- string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
+-
+- if (!add_wrapper (dup_func)) {
+- // wrapper already defined
+- return dup_func;
+- }
+-
+- // declaration
+-
+- var function = new CCodeFunction (dup_func, array_type.get_cname ());
+- function.modifiers = CCodeModifiers.STATIC;
+-
+- function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname ()));
+- // total length over all dimensions
+- function.add_parameter (new CCodeFormalParameter ("length", "int"));
+-
+- // definition
+-
+- var block = new CCodeBlock ();
+-
+- if (requires_copy (array_type.element_type)) {
+- var old_temp_vars = temp_vars;
+-
+- var cdecl = new CCodeDeclaration (array_type.get_cname ());
+- var cvardecl = new CCodeVariableDeclarator ("result");
+- cdecl.add_declarator (cvardecl);
+- var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
+- gnew.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+- gnew.add_argument (new CCodeIdentifier ("length"));
+- cvardecl.initializer = gnew;
+- block.add_statement (cdecl);
+-
+- var idx_decl = new CCodeDeclaration ("int");
+- idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
+- block.add_statement (idx_decl);
+-
+- var loop_body = new CCodeBlock ();
+- loop_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type))));
+-
+- var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")), loop_body);
+- cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
+- cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
+- block.add_statement (cfor);
+-
+- block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, temp_vars);
+- block.add_statement (cfrag);
+- temp_vars = old_temp_vars;
+- } else {
+- var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
+- dup_call.add_argument (new CCodeIdentifier ("self"));
+-
+- var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
+- sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
+- dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
+-
+- block.add_statement (new CCodeReturnStatement (dup_call));
+- }
+-
+- // append to file
+-
+- source_type_member_declaration.append (function.copy ());
+-
+- function.block = block;
+- source_type_member_definition.append (function);
+-
+- return dup_func;
+- }
+-
+ private string generate_struct_dup_wrapper (ValueType value_type) {
+ string dup_func = "_%sdup".printf (value_type.type_symbol.get_lower_case_cprefix ());
+
+@@ -2084,546 +1852,6 @@
+ ((CodeNode) stmt).ccodenode = cfrag;
+ }
+
+- public override void visit_if_statement (IfStatement stmt) {
+- stmt.accept_children (codegen);
+-
+- if (stmt.false_statement != null) {
+- stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode, (CCodeStatement) stmt.false_statement.ccodenode);
+- } else {
+- stmt.ccodenode = new CCodeIfStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.true_statement.ccodenode);
+- }
+-
+- create_temp_decl (stmt, stmt.condition.temp_vars);
+- }
+-
+- void visit_string_switch_statement (SwitchStatement stmt) {
+- // we need a temporary variable to save the property value
+- var temp_var = get_temp_variable (stmt.expression.value_type, true, stmt);
+- stmt.expression.temp_vars.insert (0, temp_var);
+-
+- var ctemp = new CCodeIdentifier (temp_var.name);
+- var cinit = new CCodeAssignment (ctemp, (CCodeExpression) stmt.expression.ccodenode);
+- var czero = new CCodeConstant ("0");
+-
+- var cswitchblock = new CCodeFragment ();
+- stmt.ccodenode = cswitchblock;
+-
+- var cisnull = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), ctemp);
+- var cquark = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
+- cquark.add_argument (ctemp);
+-
+- var ccond = new CCodeConditionalExpression (cisnull, new CCodeConstant ("0"), cquark);
+-
+- temp_var = get_temp_variable (gquark_type);
+- stmt.expression.temp_vars.insert (0, temp_var);
+-
+- int label_count = 0;
+-
+- foreach (SwitchSection section in stmt.get_sections ()) {
+- if (section.has_default_label ()) {
+- continue;
+- }
+-
+- foreach (SwitchLabel label in section.get_labels ()) {
+- var cexpr = (CCodeExpression) label.expression.ccodenode;
+-
+- if (is_constant_ccode_expression (cexpr)) {
+- var cname = "%s_label%d".printf (temp_var.name, label_count++);
+- var cdecl = new CCodeDeclaration (gquark_type.get_cname ());
+-
+- cdecl.modifiers = CCodeModifiers.STATIC;
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (cname, czero));
+-
+- cswitchblock.append (cdecl);
+- }
+- }
+- }
+-
+- cswitchblock.append (new CCodeExpressionStatement (cinit));
+-
+- ctemp = new CCodeIdentifier (temp_var.name);
+- cinit = new CCodeAssignment (ctemp, ccond);
+-
+- cswitchblock.append (new CCodeExpressionStatement (cinit));
+- create_temp_decl (stmt, stmt.expression.temp_vars);
+-
+- Gee.List<Statement> default_statements = null;
+- label_count = 0;
+-
+- // generate nested if statements
+- CCodeStatement ctopstmt = null;
+- CCodeIfStatement coldif = null;
+-
+- foreach (SwitchSection section in stmt.get_sections ()) {
+- if (section.has_default_label ()) {
+- default_statements = section.get_statements ();
+- continue;
+- }
+-
+- CCodeBinaryExpression cor = null;
+- foreach (SwitchLabel label in section.get_labels ()) {
+- var cexpr = (CCodeExpression) label.expression.ccodenode;
+-
+- if (is_constant_ccode_expression (cexpr)) {
+- var cname = new CCodeIdentifier ("%s_label%d".printf (temp_var.name, label_count++));
+- var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, czero, cname);
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_static_string"));
+- var cinit = new CCodeParenthesizedExpression (new CCodeAssignment (cname, ccall));
+-
+- ccall.add_argument (cexpr);
+-
+- cexpr = new CCodeConditionalExpression (ccond, cname, cinit);
+- } else {
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_quark_from_string"));
+- ccall.add_argument (cexpr);
+- cexpr = ccall;
+- }
+-
+- var ccmp = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, ctemp, cexpr);
+-
+- if (cor == null) {
+- cor = ccmp;
+- } else {
+- cor = new CCodeBinaryExpression (CCodeBinaryOperator.OR, cor, ccmp);
+- }
+- }
+-
+- var cblock = new CCodeBlock ();
+- foreach (CodeNode body_stmt in section.get_statements ()) {
+- if (body_stmt.ccodenode is CCodeFragment) {
+- foreach (CCodeNode cstmt in ((CCodeFragment) body_stmt.ccodenode).get_children ()) {
+- cblock.add_statement (cstmt);
+- }
+- } else {
+- cblock.add_statement (body_stmt.ccodenode);
+- }
+- }
+-
+- var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
+- var cif = new CCodeIfStatement (cor, cdo);
+-
+- if (coldif != null) {
+- coldif.false_statement = cif;
+- } else {
+- ctopstmt = cif;
+- }
+-
+- coldif = cif;
+- }
+-
+- if (default_statements != null) {
+- var cblock = new CCodeBlock ();
+- foreach (CodeNode body_stmt in default_statements) {
+- cblock.add_statement (body_stmt.ccodenode);
+- }
+-
+- var cdo = new CCodeDoStatement (cblock, new CCodeConstant ("0"));
+-
+- if (coldif == null) {
+- // there is only one section and that section
+- // contains a default label
+- ctopstmt = cdo;
+- } else {
+- coldif.false_statement = cdo;
+- }
+- }
+-
+- cswitchblock.append (ctopstmt);
+- }
+-
+- public override void visit_switch_statement (SwitchStatement stmt) {
+- if (stmt.expression.value_type.compatible (string_type)) {
+- visit_string_switch_statement (stmt);
+- return;
+- }
+-
+- var cswitch = new CCodeSwitchStatement ((CCodeExpression) stmt.expression.ccodenode);
+- stmt.ccodenode = cswitch;
+-
+- foreach (SwitchSection section in stmt.get_sections ()) {
+- if (section.has_default_label ()) {
+- cswitch.add_statement (new CCodeLabel ("default"));
+- var cdefaultblock = new CCodeBlock ();
+- cswitch.add_statement (cdefaultblock);
+- foreach (CodeNode default_stmt in section.get_statements ()) {
+- cdefaultblock.add_statement (default_stmt.ccodenode);
+- }
+- continue;
+- }
+-
+- foreach (SwitchLabel label in section.get_labels ()) {
+- cswitch.add_statement (new CCodeCaseStatement ((CCodeExpression) label.expression.ccodenode));
+- }
+-
+- var cblock = new CCodeBlock ();
+- cswitch.add_statement (cblock);
+- foreach (CodeNode body_stmt in section.get_statements ()) {
+- cblock.add_statement (body_stmt.ccodenode);
+- }
+- }
+- }
+-
+- public override void visit_switch_section (SwitchSection section) {
+- visit_block (section);
+- }
+-
+- public override void visit_while_statement (WhileStatement stmt) {
+- stmt.accept_children (codegen);
+-
+- stmt.ccodenode = new CCodeWhileStatement ((CCodeExpression) stmt.condition.ccodenode, (CCodeStatement) stmt.body.ccodenode);
+-
+- create_temp_decl (stmt, stmt.condition.temp_vars);
+- }
+-
+- public override void visit_do_statement (DoStatement stmt) {
+- stmt.accept_children (codegen);
+-
+- stmt.ccodenode = new CCodeDoStatement ((CCodeStatement) stmt.body.ccodenode, (CCodeExpression) stmt.condition.ccodenode);
+-
+- create_temp_decl (stmt, stmt.condition.temp_vars);
+- }
+-
+- public override void visit_for_statement (ForStatement stmt) {
+- stmt.accept_children (codegen);
+-
+- CCodeExpression ccondition = null;
+- if (stmt.condition != null) {
+- ccondition = (CCodeExpression) stmt.condition.ccodenode;
+- }
+-
+- var cfor = new CCodeForStatement (ccondition, (CCodeStatement) stmt.body.ccodenode);
+- stmt.ccodenode = cfor;
+-
+- foreach (Expression init_expr in stmt.get_initializer ()) {
+- cfor.add_initializer ((CCodeExpression) init_expr.ccodenode);
+- create_temp_decl (stmt, init_expr.temp_vars);
+- }
+-
+- foreach (Expression it_expr in stmt.get_iterator ()) {
+- cfor.add_iterator ((CCodeExpression) it_expr.ccodenode);
+- create_temp_decl (stmt, it_expr.temp_vars);
+- }
+-
+- if (stmt.condition != null) {
+- create_temp_decl (stmt, stmt.condition.temp_vars);
+- }
+- }
+-
+- public override void visit_foreach_statement (ForeachStatement stmt) {
+- stmt.element_variable.active = true;
+- stmt.collection_variable.active = true;
+- if (stmt.iterator_variable != null) {
+- stmt.iterator_variable.active = true;
+- }
+-
+- visit_block (stmt);
+-
+- var cblock = new CCodeBlock ();
+- // sets #line
+- stmt.ccodenode = cblock;
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, stmt.collection.temp_vars);
+- cblock.add_statement (cfrag);
+-
+- var collection_backup = stmt.collection_variable;
+- var collection_type = collection_backup.variable_type.copy ();
+- var ccoldecl = new CCodeDeclaration (collection_type.get_cname ());
+- var ccolvardecl = new CCodeVariableDeclarator.with_initializer (collection_backup.name, (CCodeExpression) stmt.collection.ccodenode);
+- ccolvardecl.line = cblock.line;
+- ccoldecl.add_declarator (ccolvardecl);
+- cblock.add_statement (ccoldecl);
+-
+- if (stmt.tree_can_fail && stmt.collection.tree_can_fail) {
+- // exception handling
+- var cfrag = new CCodeFragment ();
+- head.add_simple_check (stmt.collection, cfrag);
+- cblock.add_statement (cfrag);
+- }
+-
+- if (stmt.collection.value_type is ArrayType) {
+- var array_type = (ArrayType) stmt.collection.value_type;
+-
+- var array_len = head.get_array_length_cexpression (stmt.collection);
+-
+- // store array length for use by _vala_array_free
+- var clendecl = new CCodeDeclaration ("int");
+- clendecl.add_declarator (new CCodeVariableDeclarator.with_initializer (head.get_array_length_cname (collection_backup.name, 1), array_len));
+- cblock.add_statement (clendecl);
+-
+- if (array_len is CCodeConstant) {
+- // the array has no length parameter i.e. it is NULL-terminated array
+-
+- var it_name = "%s_it".printf (stmt.variable_name);
+-
+- var citdecl = new CCodeDeclaration (collection_type.get_cname ());
+- citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+- cblock.add_statement (citdecl);
+-
+- var cbody = new CCodeBlock ();
+-
+- CCodeExpression element_expr = new CCodeIdentifier ("*%s".printf (it_name));
+-
+- var element_type = array_type.element_type.copy ();
+- element_type.value_owned = false;
+- element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, temp_vars);
+- cbody.add_statement (cfrag);
+- temp_vars.clear ();
+-
+- var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
+- cbody.add_statement (cdecl);
+-
+- // add array length variable for stacked arrays
+- if (stmt.type_reference is ArrayType) {
+- var inner_array_type = (ArrayType) stmt.type_reference;
+- for (int dim = 1; dim <= inner_array_type.rank; dim++) {
+- cdecl = new CCodeDeclaration ("int");
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (head.get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
+- cbody.add_statement (cdecl);
+- }
+- }
+-
+- cbody.add_statement (stmt.body.ccodenode);
+-
+- var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier ("*%s".printf (it_name)), new CCodeConstant ("NULL"));
+-
+- var cfor = new CCodeForStatement (ccond, cbody);
+-
+- cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
+-
+- cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+- cblock.add_statement (cfor);
+- } else {
+- // the array has a length parameter
+-
+- var it_name = (stmt.variable_name + "_it");
+-
+- var citdecl = new CCodeDeclaration ("int");
+- citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+- cblock.add_statement (citdecl);
+-
+- var cbody = new CCodeBlock ();
+-
+- CCodeExpression element_expr = new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name));
+-
+- var element_type = array_type.element_type.copy ();
+- element_type.value_owned = false;
+- element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, temp_vars);
+- cbody.add_statement (cfrag);
+- temp_vars.clear ();
+-
+- var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr));
+- cbody.add_statement (cdecl);
+-
+- // add array length variable for stacked arrays
+- if (stmt.type_reference is ArrayType) {
+- var inner_array_type = (ArrayType) stmt.type_reference;
+- for (int dim = 1; dim <= inner_array_type.rank; dim++) {
+- cdecl = new CCodeDeclaration ("int");
+- cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer (head.get_array_length_cname (stmt.variable_name, dim), new CCodeConstant ("-1")));
+- cbody.add_statement (cdecl);
+- }
+- }
+-
+- cbody.add_statement (stmt.body.ccodenode);
+-
+- var ccond_ind1 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, array_len, new CCodeConstant ("-1"));
+- var ccond_ind2 = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), array_len);
+- var ccond_ind = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_ind1, ccond_ind2);
+-
+- /* only check for null if the containers elements are of reference-type */
+- CCodeBinaryExpression ccond;
+- if (array_type.element_type.is_reference_type_or_type_parameter ()) {
+- var ccond_term1 = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, array_len, new CCodeConstant ("-1"));
+- var ccond_term2 = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeElementAccess (new CCodeIdentifier (collection_backup.name), new CCodeIdentifier (it_name)), new CCodeConstant ("NULL"));
+- var ccond_term = new CCodeBinaryExpression (CCodeBinaryOperator.AND, ccond_term1, ccond_term2);
+-
+- ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, new CCodeParenthesizedExpression (ccond_ind), new CCodeParenthesizedExpression (ccond_term));
+- } else {
+- /* assert when trying to iterate over value-type arrays of unknown length */
+- var cassert = new CCodeFunctionCall (new CCodeIdentifier ("g_assert"));
+- cassert.add_argument (ccond_ind1);
+- cblock.add_statement (new CCodeExpressionStatement (cassert));
+-
+- ccond = ccond_ind2;
+- }
+-
+- var cfor = new CCodeForStatement (ccond, cbody);
+- cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
+- cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+- cblock.add_statement (cfor);
+- }
+- } else if (stmt.collection.value_type.compatible (new ObjectType (glist_type)) || stmt.collection.value_type.compatible (new ObjectType (gslist_type))) {
+- // iterating over a GList or GSList
+-
+- var it_name = "%s_it".printf (stmt.variable_name);
+-
+- var citdecl = new CCodeDeclaration (collection_type.get_cname ());
+- var citvardecl = new CCodeVariableDeclarator (it_name);
+- citvardecl.line = cblock.line;
+- citdecl.add_declarator (citvardecl);
+- cblock.add_statement (citdecl);
+-
+- var cbody = new CCodeBlock ();
+-
+- CCodeExpression element_expr = new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "data");
+-
+- if (collection_type.get_type_arguments ().size != 1) {
+- Report.error (stmt.source_reference, "internal error: missing generic type argument");
+- stmt.error = true;
+- return;
+- }
+-
+- var element_data_type = collection_type.get_type_arguments ().get (0).copy ();
+- element_data_type.value_owned = false;
+- element_data_type.is_type_argument = true;
+- element_expr = transform_expression (element_expr, element_data_type, stmt.type_reference);
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, temp_vars);
+- cbody.add_statement (cfrag);
+- temp_vars.clear ();
+-
+- var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+- var cvardecl = new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr);
+- cvardecl.line = cblock.line;
+- cdecl.add_declarator (cvardecl);
+- cbody.add_statement (cdecl);
+-
+- cbody.add_statement (stmt.body.ccodenode);
+-
+- var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, new CCodeIdentifier (it_name), new CCodeConstant ("NULL"));
+-
+- var cfor = new CCodeForStatement (ccond, cbody);
+-
+- cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeIdentifier (collection_backup.name)));
+-
+- cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeMemberAccess.pointer (new CCodeIdentifier (it_name), "next")));
+- cblock.add_statement (cfor);
+- } else if (list_type != null && stmt.collection.value_type.compatible (new ObjectType (list_type))) {
+- // iterating over a Gee.List, use integer to avoid the cost of an iterator object
+-
+- var it_name = "%s_it".printf (stmt.variable_name);
+-
+- var citdecl = new CCodeDeclaration ("int");
+- citdecl.add_declarator (new CCodeVariableDeclarator (it_name));
+- cblock.add_statement (citdecl);
+-
+- var cbody = new CCodeBlock ();
+-
+- var get_method = (Method) list_type.scope.lookup ("get");
+- var get_ccall = new CCodeFunctionCall (new CCodeIdentifier (get_method.get_cname ()));
+- get_ccall.add_argument (new InstanceCast (new CCodeIdentifier (collection_backup.name), list_type));
+- get_ccall.add_argument (new CCodeIdentifier (it_name));
+- CCodeExpression element_expr = get_ccall;
+-
+- var element_type = SemanticAnalyzer.get_actual_type (stmt.collection.value_type, get_method, get_method.return_type, stmt);
+-
+- element_expr = transform_expression (element_expr, element_type, stmt.type_reference);
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, temp_vars);
+- cbody.add_statement (cfrag);
+- temp_vars.clear ();
+-
+- var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+- var cvardecl = new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr);
+- cvardecl.line = cblock.line;
+- cdecl.add_declarator (cvardecl);
+- cbody.add_statement (cdecl);
+-
+- cbody.add_statement (stmt.body.ccodenode);
+-
+- var list_len = new CCodeFunctionCall (new CCodeIdentifier ("gee_collection_get_size"));
+- list_len.add_argument (new InstanceCast (new CCodeIdentifier (collection_backup.name), this.collection_type));
+-
+- var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier (it_name), list_len);
+-
+- var cfor = new CCodeForStatement (ccond, cbody);
+- cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeConstant ("0")));
+- cfor.add_iterator (new CCodeAssignment (new CCodeIdentifier (it_name), new CCodeBinaryExpression (CCodeBinaryOperator.PLUS, new CCodeIdentifier (it_name), new CCodeConstant ("1"))));
+- cfor.line = cblock.line;
+- cblock.add_statement (cfor);
+- } else if (iterable_type != null && stmt.collection.value_type.compatible (new ObjectType (iterable_type))) {
+- // iterating over a Gee.Iterable, use iterator
+-
+- var it_name = "%s_it".printf (stmt.variable_name);
+-
+- var citdecl = new CCodeDeclaration (iterator_type.get_cname () + "*");
+- var it_method = (Method) iterable_type.scope.lookup ("iterator");
+- var it_ccall = new CCodeFunctionCall (new CCodeIdentifier (it_method.get_cname ()));
+- it_ccall.add_argument (new InstanceCast (new CCodeIdentifier (collection_backup.name), iterable_type));
+- var citvardecl = new CCodeVariableDeclarator.with_initializer (it_name, it_ccall);
+- citvardecl.line = cblock.line;
+- citdecl.add_declarator (citvardecl);
+- cblock.add_statement (citdecl);
+-
+- var cbody = new CCodeBlock ();
+-
+- var get_method = (Method) iterator_type.scope.lookup ("get");
+- var get_ccall = new CCodeFunctionCall (new CCodeIdentifier (get_method.get_cname ()));
+- get_ccall.add_argument (new CCodeIdentifier (it_name));
+- CCodeExpression element_expr = get_ccall;
+-
+- Iterator<DataType> type_arg_it = it_method.return_type.get_type_arguments ().iterator ();
+- type_arg_it.next ();
+- var it_type = SemanticAnalyzer.get_actual_type (stmt.collection.value_type, it_method, type_arg_it.get (), stmt);
+-
+- element_expr = transform_expression (element_expr, it_type, stmt.type_reference);
+-
+- var cfrag = new CCodeFragment ();
+- append_temp_decl (cfrag, temp_vars);
+- cbody.add_statement (cfrag);
+- temp_vars.clear ();
+-
+- var cdecl = new CCodeDeclaration (stmt.type_reference.get_cname ());
+- var cvardecl = new CCodeVariableDeclarator.with_initializer (stmt.variable_name, element_expr);
+- cvardecl.line = cblock.line;
+- cdecl.add_declarator (cvardecl);
+- cbody.add_statement (cdecl);
+-
+- cbody.add_statement (stmt.body.ccodenode);
+-
+- var next_method = (Method) iterator_type.scope.lookup ("next");
+- var next_ccall = new CCodeFunctionCall (new CCodeIdentifier (next_method.get_cname ()));
+- next_ccall.add_argument (new CCodeIdentifier (it_name));
+-
+- var cwhile = new CCodeWhileStatement (next_ccall, cbody);
+- cwhile.line = cblock.line;
+- cblock.add_statement (cwhile);
+- }
+-
+- foreach (LocalVariable local in stmt.get_local_variables ()) {
+- if (requires_destroy (local.variable_type)) {
+- var ma = new MemberAccess.simple (local.name);
+- ma.symbol_reference = local;
+- var cunref = new CCodeExpressionStatement (get_unref_expression (new CCodeIdentifier (get_variable_cname (local.name)), local.variable_type, ma));
+- cunref.line = cblock.line;
+- cblock.add_statement (cunref);
+- }
+- }
+- }
+-
+- public override void visit_break_statement (BreakStatement stmt) {
+- stmt.ccodenode = new CCodeBreakStatement ();
+-
+- create_local_free (stmt, true);
+- }
+-
+- public override void visit_continue_statement (ContinueStatement stmt) {
+- stmt.ccodenode = new CCodeContinueStatement ();
+-
+- create_local_free (stmt, true);
+- }
+-
+ public void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop) {
+ var b = (Block) sym;
+
+@@ -2661,7 +1889,7 @@
+ }
+ }
+
+- private void create_local_free (CodeNode stmt, bool stop_at_loop = false) {
++ public void create_local_free (CodeNode stmt, bool stop_at_loop = false) {
+ var cfrag = new CCodeFragment ();
+
+ append_local_free (current_symbol, cfrag, stop_at_loop);
+@@ -2992,7 +2220,7 @@
+ return true;
+ }
+
+- private CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
++ public CCodeExpression? get_ref_cexpression (DataType expression_type, CCodeExpression cexpr, Expression? expr, CodeNode node) {
+ if (expression_type is ValueType && !expression_type.nullable) {
+ // normal value type, no null check
+ // (copy (&expr, &temp), temp)
+@@ -3785,7 +3013,7 @@
+ return cexpr;
+ }
+
+- private CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
++ public virtual CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
+ var cexpr = source_cexpr;
+
+ if (expression_type.data_type != null && expression_type.data_type == target_type.data_type) {
+@@ -3811,180 +3039,11 @@
+ } else {
+ return cexpr;
+ }
+- } else if (target_type is DelegateType && expression_type is MethodType) {
+- var dt = (DelegateType) target_type;
+- var mt = (MethodType) expression_type;
+-
+- var method = mt.method_symbol;
+- if (method.base_method != null) {
+- method = method.base_method;
+- } else if (method.base_interface_method != null) {
+- method = method.base_interface_method;
+- }
+-
+- return new CCodeIdentifier (generate_delegate_wrapper (method, dt.delegate_symbol));
+ } else {
+ return cexpr;
+ }
+ }
+
+- private string generate_delegate_wrapper (Method m, Delegate d) {
+- string delegate_name;
+- var sig = d.parent_symbol as Signal;
+- var dynamic_sig = sig as DynamicSignal;
+- if (dynamic_sig != null) {
+- delegate_name = head.get_dynamic_signal_cname (dynamic_sig);
+- } else if (sig != null) {
+- delegate_name = sig.parent_symbol.get_lower_case_cprefix () + sig.get_cname ();
+- } else {
+- delegate_name = Symbol.camel_case_to_lower_case (d.get_cname ());
+- }
+-
+- string wrapper_name = "_%s_%s".printf (m.get_cname (), delegate_name);
+-
+- if (!add_wrapper (wrapper_name)) {
+- // wrapper already defined
+- return wrapper_name;
+- }
+-
+- // declaration
+-
+- var function = new CCodeFunction (wrapper_name, m.return_type.get_cname ());
+- function.modifiers = CCodeModifiers.STATIC;
+- m.ccodenode = function;
+-
+- var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
+-
+- if (d.has_target) {
+- var cparam = new CCodeFormalParameter ("self", "gpointer");
+- cparam_map.set (get_param_pos (d.cinstance_parameter_position), cparam);
+- }
+-
+- var d_params = d.get_parameters ();
+- foreach (FormalParameter param in d_params) {
+- // ensure that C code node has been generated
+- param.accept (codegen);
+-
+- cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
+-
+- // handle array parameters
+- if (!param.no_array_length && param.parameter_type is ArrayType) {
+- var array_type = (ArrayType) param.parameter_type;
+-
+- var length_ctype = "int";
+- if (param.direction != ParameterDirection.IN) {
+- length_ctype = "int*";
+- }
+-
+- for (int dim = 1; dim <= array_type.rank; dim++) {
+- var cparam = new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), length_ctype);
+- cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
+- }
+- }
+-
+- }
+-
+- if (m.get_error_types ().size > 0) {
+- var cparam = new CCodeFormalParameter ("error", "GError**");
+- cparam_map.set (get_param_pos (-1), cparam);
+- }
+-
+- // append C parameters in the right order
+- int last_pos = -1;
+- int min_pos;
+- while (true) {
+- min_pos = -1;
+- foreach (int pos in cparam_map.get_keys ()) {
+- if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+- min_pos = pos;
+- }
+- }
+- if (min_pos == -1) {
+- break;
+- }
+- function.add_parameter (cparam_map.get (min_pos));
+- last_pos = min_pos;
+- }
+-
+-
+- // definition
+-
+- var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
+-
+- int i = 0;
+- if (m.binding == MemberBinding.INSTANCE) {
+- CCodeExpression arg;
+- if (d.has_target) {
+- arg = new CCodeIdentifier ("self");
+- } else {
+- // use first delegate parameter as instance
+- arg = new CCodeIdentifier ((d_params.get (0).ccodenode as CCodeFormalParameter).name);
+- i = 1;
+- }
+- carg_map.set (get_param_pos (m.cinstance_parameter_position), arg);
+- }
+-
+- foreach (FormalParameter param in m.get_parameters ()) {
+- CCodeExpression arg;
+- arg = new CCodeIdentifier ((d_params.get (i).ccodenode as CCodeFormalParameter).name);
+- carg_map.set (get_param_pos (param.cparameter_position), arg);
+-
+- // handle array arguments
+- if (!param.no_array_length && param.parameter_type is ArrayType) {
+- var array_type = (ArrayType) param.parameter_type;
+- for (int dim = 1; dim <= array_type.rank; dim++) {
+- CCodeExpression clength;
+- if (d_params.get (i).no_array_length) {
+- clength = new CCodeConstant ("-1");
+- } else {
+- clength = new CCodeIdentifier (head.get_array_length_cname (d_params.get (i).name, dim));
+- }
+- carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), clength);
+- }
+- }
+-
+- i++;
+- }
+-
+- if (m.get_error_types ().size > 0) {
+- carg_map.set (get_param_pos (-1), new CCodeIdentifier ("error"));
+- }
+-
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
+-
+- // append C arguments in the right order
+- last_pos = -1;
+- while (true) {
+- min_pos = -1;
+- foreach (int pos in carg_map.get_keys ()) {
+- if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
+- min_pos = pos;
+- }
+- }
+- if (min_pos == -1) {
+- break;
+- }
+- ccall.add_argument (carg_map.get (min_pos));
+- last_pos = min_pos;
+- }
+-
+- var block = new CCodeBlock ();
+- if (m.return_type is VoidType) {
+- block.add_statement (new CCodeExpressionStatement (ccall));
+- } else {
+- block.add_statement (new CCodeReturnStatement (ccall));
+- }
+-
+- // append to file
+-
+- source_type_member_declaration.append (function.copy ());
+-
+- function.block = block;
+- source_type_member_definition.append (function);
+-
+- return wrapper_name;
+- }
+-
+ public CCodeFunctionCall get_property_set_call (Property prop, MemberAccess ma, CCodeExpression cexpr) {
+ if (ma.inner is BaseAccess) {
+ if (prop.base_property != null) {
+Index: gobject/valaccodedelegatemodule.vala
+===================================================================
+--- gobject/valaccodedelegatemodule.vala (revision 1971)
++++ gobject/valaccodedelegatemodule.vala (revision 2004)
+@@ -21,7 +21,7 @@
+ * Raffaele Sandrini <raffaele@sandrini.ch>
+ */
+
+-using GLib;
++using Gee;
+
+ /**
+ * The link between an assignment and generated code.
+@@ -166,4 +166,179 @@
+ public override string get_delegate_target_destroy_notify_cname (string delegate_cname) {
+ return "%s_target_destroy_notify".printf (delegate_cname);
+ }
++
++ public override CCodeExpression get_implicit_cast_expression (CCodeExpression source_cexpr, DataType? expression_type, DataType? target_type, Expression? expr = null) {
++ if (target_type is DelegateType && expression_type is MethodType) {
++ var dt = (DelegateType) target_type;
++ var mt = (MethodType) expression_type;
++
++ var method = mt.method_symbol;
++ if (method.base_method != null) {
++ method = method.base_method;
++ } else if (method.base_interface_method != null) {
++ method = method.base_interface_method;
++ }
++
++ return new CCodeIdentifier (generate_delegate_wrapper (method, dt.delegate_symbol));
++ } else {
++ return base.get_implicit_cast_expression (source_cexpr, expression_type, target_type, expr);
++ }
++ }
++
++ private string generate_delegate_wrapper (Method m, Delegate d) {
++ string delegate_name;
++ var sig = d.parent_symbol as Signal;
++ var dynamic_sig = sig as DynamicSignal;
++ if (dynamic_sig != null) {
++ delegate_name = head.get_dynamic_signal_cname (dynamic_sig);
++ } else if (sig != null) {
++ delegate_name = sig.parent_symbol.get_lower_case_cprefix () + sig.get_cname ();
++ } else {
++ delegate_name = Symbol.camel_case_to_lower_case (d.get_cname ());
++ }
++
++ string wrapper_name = "_%s_%s".printf (m.get_cname (), delegate_name);
++
++ if (!add_wrapper (wrapper_name)) {
++ // wrapper already defined
++ return wrapper_name;
++ }
++
++ // declaration
++
++ var function = new CCodeFunction (wrapper_name, m.return_type.get_cname ());
++ function.modifiers = CCodeModifiers.STATIC;
++ m.ccodenode = function;
++
++ var cparam_map = new HashMap<int,CCodeFormalParameter> (direct_hash, direct_equal);
++
++ if (d.has_target) {
++ var cparam = new CCodeFormalParameter ("self", "gpointer");
++ cparam_map.set (get_param_pos (d.cinstance_parameter_position), cparam);
++ }
++
++ var d_params = d.get_parameters ();
++ foreach (FormalParameter param in d_params) {
++ // ensure that C code node has been generated
++ param.accept (codegen);
++
++ cparam_map.set (get_param_pos (param.cparameter_position), (CCodeFormalParameter) param.ccodenode);
++
++ // handle array parameters
++ if (!param.no_array_length && param.parameter_type is ArrayType) {
++ var array_type = (ArrayType) param.parameter_type;
++
++ var length_ctype = "int";
++ if (param.direction != ParameterDirection.IN) {
++ length_ctype = "int*";
++ }
++
++ for (int dim = 1; dim <= array_type.rank; dim++) {
++ var cparam = new CCodeFormalParameter (head.get_array_length_cname (param.name, dim), length_ctype);
++ cparam_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), cparam);
++ }
++ }
++
++ }
++
++ if (m.get_error_types ().size > 0) {
++ var cparam = new CCodeFormalParameter ("error", "GError**");
++ cparam_map.set (get_param_pos (-1), cparam);
++ }
++
++ // append C parameters in the right order
++ int last_pos = -1;
++ int min_pos;
++ while (true) {
++ min_pos = -1;
++ foreach (int pos in cparam_map.get_keys ()) {
++ if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
++ min_pos = pos;
++ }
++ }
++ if (min_pos == -1) {
++ break;
++ }
++ function.add_parameter (cparam_map.get (min_pos));
++ last_pos = min_pos;
++ }
++
++
++ // definition
++
++ var carg_map = new HashMap<int,CCodeExpression> (direct_hash, direct_equal);
++
++ int i = 0;
++ if (m.binding == MemberBinding.INSTANCE) {
++ CCodeExpression arg;
++ if (d.has_target) {
++ arg = new CCodeIdentifier ("self");
++ } else {
++ // use first delegate parameter as instance
++ arg = new CCodeIdentifier ((d_params.get (0).ccodenode as CCodeFormalParameter).name);
++ i = 1;
++ }
++ carg_map.set (get_param_pos (m.cinstance_parameter_position), arg);
++ }
++
++ foreach (FormalParameter param in m.get_parameters ()) {
++ CCodeExpression arg;
++ arg = new CCodeIdentifier ((d_params.get (i).ccodenode as CCodeFormalParameter).name);
++ carg_map.set (get_param_pos (param.cparameter_position), arg);
++
++ // handle array arguments
++ if (!param.no_array_length && param.parameter_type is ArrayType) {
++ var array_type = (ArrayType) param.parameter_type;
++ for (int dim = 1; dim <= array_type.rank; dim++) {
++ CCodeExpression clength;
++ if (d_params.get (i).no_array_length) {
++ clength = new CCodeConstant ("-1");
++ } else {
++ clength = new CCodeIdentifier (head.get_array_length_cname (d_params.get (i).name, dim));
++ }
++ carg_map.set (get_param_pos (param.carray_length_parameter_position + 0.01 * dim), clength);
++ }
++ }
++
++ i++;
++ }
++
++ if (m.get_error_types ().size > 0) {
++ carg_map.set (get_param_pos (-1), new CCodeIdentifier ("error"));
++ }
++
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier (m.get_cname ()));
++
++ // append C arguments in the right order
++ last_pos = -1;
++ while (true) {
++ min_pos = -1;
++ foreach (int pos in carg_map.get_keys ()) {
++ if (pos > last_pos && (min_pos == -1 || pos < min_pos)) {
++ min_pos = pos;
++ }
++ }
++ if (min_pos == -1) {
++ break;
++ }
++ ccall.add_argument (carg_map.get (min_pos));
++ last_pos = min_pos;
++ }
++
++ var block = new CCodeBlock ();
++ if (m.return_type is VoidType) {
++ block.add_statement (new CCodeExpressionStatement (ccall));
++ } else {
++ block.add_statement (new CCodeReturnStatement (ccall));
++ }
++
++ // append to file
++
++ source_type_member_declaration.append (function.copy ());
++
++ function.block = block;
++ source_type_member_definition.append (function);
++
++ return wrapper_name;
++ }
+ }
+Index: gobject/valaccodearraymodule.vala
+===================================================================
+--- gobject/valaccodearraymodule.vala (revision 1971)
++++ gobject/valaccodearraymodule.vala (revision 2004)
+@@ -28,6 +28,8 @@
+ * The link between an assignment and generated code.
+ */
+ public class Vala.CCodeArrayModule : CCodeInvocationExpressionModule {
++ private int next_array_dup_id = 0;
++
+ public CCodeArrayModule (CCodeGenerator codegen, CCodeModule? next) {
+ base (codegen, next);
+ }
+@@ -280,26 +282,6 @@
+ get_ccall.add_argument (cindex);
+
+ expr.ccodenode = convert_from_generic_pointer (get_ccall, expr.value_type);
+- } else if (expr.container is MemberAccess && expr.container.symbol_reference is Signal) {
+- // should be moved to the GSignal module
+-
+- // detailed signal emission
+- var sig = (Signal) expr.symbol_reference;
+- var ma = (MemberAccess) expr.container;
+-
+- var detail_expr = expr.get_indices ().get (0) as StringLiteral;
+- string signal_detail = detail_expr.eval ();
+-
+- var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_signal_emit_by_name"));
+-
+- // FIXME: use C cast if debugging disabled
+- var ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT"));
+- ccast.add_argument ((CCodeExpression) ma.inner.ccodenode);
+- ccall.add_argument (ccast);
+-
+- ccall.add_argument (sig.get_canonical_cconstant (signal_detail));
+-
+- expr.ccodenode = ccall;
+ } else {
+ // access to element in an array
+ for (int i = 1; i < rank; i++) {
+@@ -416,4 +398,84 @@
+
+ source_type_member_definition.append (fun);
+ }
++
++ public override CCodeExpression? get_dup_func_expression (DataType type, SourceReference? source_reference) {
++ if (type is ArrayType) {
++ return new CCodeIdentifier (generate_array_dup_wrapper ((ArrayType) type));
++ } else {
++ return base.get_dup_func_expression (type, source_reference);
++ }
++ }
++
++ string generate_array_dup_wrapper (ArrayType array_type) {
++ string dup_func = "_vala_array_dup%d".printf (++next_array_dup_id);
++
++ if (!add_wrapper (dup_func)) {
++ // wrapper already defined
++ return dup_func;
++ }
++
++ // declaration
++
++ var function = new CCodeFunction (dup_func, array_type.get_cname ());
++ function.modifiers = CCodeModifiers.STATIC;
++
++ function.add_parameter (new CCodeFormalParameter ("self", array_type.get_cname ()));
++ // total length over all dimensions
++ function.add_parameter (new CCodeFormalParameter ("length", "int"));
++
++ // definition
++
++ var block = new CCodeBlock ();
++
++ if (requires_copy (array_type.element_type)) {
++ var old_temp_vars = temp_vars;
++
++ var cdecl = new CCodeDeclaration (array_type.get_cname ());
++ var cvardecl = new CCodeVariableDeclarator ("result");
++ cdecl.add_declarator (cvardecl);
++ var gnew = new CCodeFunctionCall (new CCodeIdentifier ("g_new0"));
++ gnew.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
++ gnew.add_argument (new CCodeIdentifier ("length"));
++ cvardecl.initializer = gnew;
++ block.add_statement (cdecl);
++
++ var idx_decl = new CCodeDeclaration ("int");
++ idx_decl.add_declarator (new CCodeVariableDeclarator ("i"));
++ block.add_statement (idx_decl);
++
++ var loop_body = new CCodeBlock ();
++ loop_body.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeElementAccess (new CCodeIdentifier ("result"), new CCodeIdentifier ("i")), get_ref_cexpression (array_type.element_type, new CCodeElementAccess (new CCodeIdentifier ("self"), new CCodeIdentifier ("i")), null, array_type))));
++
++ var cfor = new CCodeForStatement (new CCodeBinaryExpression (CCodeBinaryOperator.LESS_THAN, new CCodeIdentifier ("i"), new CCodeIdentifier ("length")), loop_body);
++ cfor.add_initializer (new CCodeAssignment (new CCodeIdentifier ("i"), new CCodeConstant ("0")));
++ cfor.add_iterator (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, new CCodeIdentifier ("i")));
++ block.add_statement (cfor);
++
++ block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
++
++ var cfrag = new CCodeFragment ();
++ append_temp_decl (cfrag, temp_vars);
++ block.add_statement (cfrag);
++ temp_vars = old_temp_vars;
++ } else {
++ var dup_call = new CCodeFunctionCall (new CCodeIdentifier ("g_memdup"));
++ dup_call.add_argument (new CCodeIdentifier ("self"));
++
++ var sizeof_call = new CCodeFunctionCall (new CCodeIdentifier ("sizeof"));
++ sizeof_call.add_argument (new CCodeIdentifier (array_type.element_type.get_cname ()));
++ dup_call.add_argument (new CCodeBinaryExpression (CCodeBinaryOperator.MUL, new CCodeIdentifier ("length"), sizeof_call));
++
++ block.add_statement (new CCodeReturnStatement (dup_call));
++ }
++
++ // append to file
++
++ source_type_member_declaration.append (function.copy ());
++
++ function.block = block;
++ source_type_member_definition.append (function);
++
++ return dup_func;
++ }
+ }
+Index: gobject/Makefile.am
+===================================================================
+--- gobject/Makefile.am (revision 1971)
++++ gobject/Makefile.am (revision 2004)
+@@ -16,9 +16,8 @@
+ valaccodeassignmentmodule.vala \
+ valaccodebasemodule.vala \
+ valaccodecompiler.vala \
++ valaccodecontrolflowmodule.vala \
+ valaccodedelegatemodule.vala \
+- valaccodedynamicpropertymodule.vala \
+- valaccodedynamicsignalmodule.vala \
+ valaccodegenerator.vala \
+ valaccodeinvocationexpressionmodule.vala \
+ valaccodememberaccessmodule.vala \
+Index: gobject/valagobjectmodule.vala
+===================================================================
+--- gobject/valagobjectmodule.vala (revision 1971)
++++ gobject/valagobjectmodule.vala (revision 2004)
+@@ -24,6 +24,9 @@
+ using GLib;
+
+ public class Vala.GObjectModule : GTypeModule {
++ int dynamic_property_id;
++ int signal_wrapper_id;
++
+ public GObjectModule (CCodeGenerator codegen, CCodeModule? next) {
+ base (codegen, next);
+ }
+@@ -1453,5 +1456,290 @@
+
+ return cspec;
+ }
++
++ public override CCodeExpression get_construct_property_assignment (CCodeConstant canonical_cconstant, DataType property_type, CCodeExpression value) {
++ // this property is used as a construction parameter
++ var cpointer = new CCodeIdentifier ("__params_it");
++
++ var ccomma = new CCodeCommaExpression ();
++ // set name in array for current parameter
++ var cnamemember = new CCodeMemberAccess.pointer (cpointer, "name");
++ var cnameassign = new CCodeAssignment (cnamemember, canonical_cconstant);
++ ccomma.append_expression (cnameassign);
++
++ var gvaluearg = new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeMemberAccess.pointer (cpointer, "value"));
++
++ // initialize GValue in array for current parameter
++ var cvalueinit = new CCodeFunctionCall (new CCodeIdentifier ("g_value_init"));
++ cvalueinit.add_argument (gvaluearg);
++ cvalueinit.add_argument (new CCodeIdentifier (property_type.get_type_id ()));
++ ccomma.append_expression (cvalueinit);
++
++ // set GValue for current parameter
++ var cvalueset = new CCodeFunctionCall (get_value_setter_function (property_type));
++ cvalueset.add_argument (gvaluearg);
++ cvalueset.add_argument (value);
++ ccomma.append_expression (cvalueset);
++
++ // move pointer to next parameter in array
++ ccomma.append_expression (new CCodeUnaryExpression (CCodeUnaryOperator.POSTFIX_INCREMENT, cpointer));
++
++ return ccomma;
++ }
++
++ public override void visit_constructor (Constructor c) {
++ current_method_inner_error = false;
++ in_constructor = true;
++
++ if (c.binding == MemberBinding.CLASS || c.binding == MemberBinding.STATIC) {
++ in_static_or_class_ctor = true;
++ }
++ c.accept_children (codegen);
++ in_static_or_class_ctor = false;
++
++ in_constructor = false;
++
++ var cl = (Class) c.parent_symbol;
++
++ if (c.binding == MemberBinding.INSTANCE) {
++ function = new CCodeFunction ("%s_constructor".printf (cl.get_lower_case_cname (null)), "GObject *");
++ function.modifiers = CCodeModifiers.STATIC;
++
++ function.add_parameter (new CCodeFormalParameter ("type", "GType"));
++ function.add_parameter (new CCodeFormalParameter ("n_construct_properties", "guint"));
++ function.add_parameter (new CCodeFormalParameter ("construct_properties", "GObjectConstructParam *"));
++
++ source_type_member_declaration.append (function.copy ());
++
++
++ var cblock = new CCodeBlock ();
++ var cdecl = new CCodeDeclaration ("GObject *");
++ cdecl.add_declarator (new CCodeVariableDeclarator ("obj"));
++ cblock.add_statement (cdecl);
++
++ cdecl = new CCodeDeclaration ("%sClass *".printf (cl.get_cname ()));
++ cdecl.add_declarator (new CCodeVariableDeclarator ("klass"));
++ cblock.add_statement (cdecl);
++
++ cdecl = new CCodeDeclaration ("GObjectClass *");
++ cdecl.add_declarator (new CCodeVariableDeclarator ("parent_class"));
++ cblock.add_statement (cdecl);
++
++
++ var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek"));
++ ccall.add_argument (new CCodeIdentifier (cl.get_type_id ()));
++ var ccast = new CCodeFunctionCall (new CCodeIdentifier ("%s_CLASS".printf (cl.get_upper_case_cname (null))));
++ ccast.add_argument (ccall);
++ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("klass"), ccast)));
++
++ ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_type_class_peek_parent"));
++ ccall.add_argument (new CCodeIdentifier ("klass"));
++ ccast = new CCodeFunctionCall (new CCodeIdentifier ("G_OBJECT_CLASS"));
++ ccast.add_argument (ccall);
++ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("parent_class"), ccast)));
++
++
++ ccall = new CCodeFunctionCall (new CCodeMemberAccess.pointer (new CCodeIdentifier ("parent_class"), "constructor"));
++ ccall.add_argument (new CCodeIdentifier ("type"));
++ ccall.add_argument (new CCodeIdentifier ("n_construct_properties"));
++ ccall.add_argument (new CCodeIdentifier ("construct_properties"));
++ cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeIdentifier ("obj"), ccall)));
++
++
++ ccall = new InstanceCast (new CCodeIdentifier ("obj"), cl);
++
++ cdecl = new CCodeDeclaration ("%s *".printf (cl.get_cname ()));
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("self", ccall));
++
++ cblock.add_statement (cdecl);
++
++ if (current_method_inner_error) {
++ /* always separate error parameter and inner_error local variable
++ * as error may be set to NULL but we're always interested in inner errors
++ */
++ var cdecl = new CCodeDeclaration ("GError *");
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
++ cblock.add_statement (cdecl);
++ }
++
++
++ cblock.add_statement (c.body.ccodenode);
++
++ cblock.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("obj")));
++
++ function.block = cblock;
++
++ if (c.source_reference.comment != null) {
++ source_type_member_definition.append (new CCodeComment (c.source_reference.comment));
++ }
++ source_type_member_definition.append (function);
++ } else if (c.binding == MemberBinding.CLASS) {
++ // class constructor
++
++ var base_init = new CCodeFunction ("%s_base_init".printf (cl.get_lower_case_cname (null)), "void");
++ base_init.add_parameter (new CCodeFormalParameter ("klass", "%sClass *".printf (cl.get_cname ())));
++ base_init.modifiers = CCodeModifiers.STATIC;
++
++ source_type_member_declaration.append (base_init.copy ());
++
++ var block = (CCodeBlock) c.body.ccodenode;
++ if (current_method_inner_error) {
++ /* always separate error parameter and inner_error local variable
++ * as error may be set to NULL but we're always interested in inner errors
++ */
++ var cdecl = new CCodeDeclaration ("GError *");
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
++ block.prepend_statement (cdecl);
++ }
++
++ base_init.block = block;
++
++ source_type_member_definition.append (base_init);
++ } else if (c.binding == MemberBinding.STATIC) {
++ // static class constructor
++ // add to class_init
++
++ if (current_method_inner_error) {
++ /* always separate error parameter and inner_error local variable
++ * as error may be set to NULL but we're always interested in inner errors
++ */
++ var cdecl = new CCodeDeclaration ("GError *");
++ cdecl.add_declarator (new CCodeVariableDeclarator.with_initializer ("inner_error", new CCodeConstant ("NULL")));
++ class_init_fragment.append (cdecl);
++ }
++
++ class_init_fragment.append (c.body.ccodenode);
++ } else {
++ Report.error (c.source_reference, "internal error: constructors must have instance, class, or static binding");
++ }
++ }
++
++ public override string get_dynamic_property_getter_cname (DynamicProperty prop) {
++ if (prop.dynamic_type.data_type == null
++ || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
++ return base.get_dynamic_property_getter_cname (prop);
++ }
++
++ string getter_cname = "_dynamic_get_%s%d".printf (prop.name, dynamic_property_id++);
++
++ var func = new CCodeFunction (getter_cname, prop.property_type.get_cname ());
++ func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
++
++ func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
++
++ var block = new CCodeBlock ();
++ generate_gobject_property_getter_wrapper (prop, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return getter_cname;
++ }
++
++ public override string get_dynamic_property_setter_cname (DynamicProperty prop) {
++ if (prop.dynamic_type.data_type == null
++ || !prop.dynamic_type.data_type.is_subtype_of (gobject_type)) {
++ return base.get_dynamic_property_setter_cname (prop);
++ }
++
++ string setter_cname = "_dynamic_set_%s%d".printf (prop.name, dynamic_property_id++);
++
++ var func = new CCodeFunction (setter_cname, "void");
++ func.modifiers |= CCodeModifiers.STATIC | CCodeModifiers.INLINE;
++
++ func.add_parameter (new CCodeFormalParameter ("obj", prop.dynamic_type.get_cname ()));
++ func.add_parameter (new CCodeFormalParameter ("value", prop.property_type.get_cname ()));
++
++ var block = new CCodeBlock ();
++ generate_gobject_property_setter_wrapper (prop, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return setter_cname;
++ }
++
++ void generate_gobject_property_getter_wrapper (DynamicProperty node, CCodeBlock block) {
++ var cdecl = new CCodeDeclaration (node.property_type.get_cname ());
++ cdecl.add_declarator (new CCodeVariableDeclarator ("result"));
++ block.add_statement (cdecl);
++
++ var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_get"));
++ call.add_argument (new CCodeIdentifier ("obj"));
++ call.add_argument (node.get_canonical_cconstant ());
++ call.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("result")));
++ call.add_argument (new CCodeConstant ("NULL"));
++
++ block.add_statement (new CCodeExpressionStatement (call));
++
++ block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
++ }
++
++ void generate_gobject_property_setter_wrapper (DynamicProperty node, CCodeBlock block) {
++ var call = new CCodeFunctionCall (new CCodeIdentifier ("g_object_set"));
++ call.add_argument (new CCodeIdentifier ("obj"));
++ call.add_argument (node.get_canonical_cconstant ());
++ call.add_argument (new CCodeIdentifier ("value"));
++ call.add_argument (new CCodeConstant ("NULL"));
++
++ block.add_statement (new CCodeExpressionStatement (call));
++ }
++
++ public override string get_dynamic_signal_cname (DynamicSignal node) {
++ return "dynamic_%s%d_".printf (node.name, signal_wrapper_id++);
++ }
++
++ public override string get_dynamic_signal_connect_wrapper_name (DynamicSignal sig) {
++ if (sig.dynamic_type.data_type == null
++ || !sig.dynamic_type.data_type.is_subtype_of (gobject_type)) {
++ return base.get_dynamic_signal_connect_wrapper_name (sig);
++ }
++
++ string connect_wrapper_name = "_%sconnect".printf (get_dynamic_signal_cname (sig));
++ var func = new CCodeFunction (connect_wrapper_name, "void");
++ func.add_parameter (new CCodeFormalParameter ("obj", "gpointer"));
++ func.add_parameter (new CCodeFormalParameter ("signal_name", "const char *"));
++ func.add_parameter (new CCodeFormalParameter ("handler", "GCallback"));
++ func.add_parameter (new CCodeFormalParameter ("data", "gpointer"));
++ var block = new CCodeBlock ();
++ generate_gobject_connect_wrapper (sig, block);
++
++ // append to C source file
++ source_type_member_declaration.append (func.copy ());
++
++ func.block = block;
++ source_type_member_definition.append (func);
++
++ return connect_wrapper_name;
++ }
++
++ void generate_gobject_connect_wrapper (DynamicSignal sig, CCodeBlock block) {
++ var m = (Method) sig.handler.symbol_reference;
++
++ sig.accept (codegen);
++
++ string connect_func = "g_signal_connect_object";
++ if (m.binding != MemberBinding.INSTANCE) {
++ connect_func = "g_signal_connect";
++ }
++
++ var call = new CCodeFunctionCall (new CCodeIdentifier (connect_func));
++ call.add_argument (new CCodeIdentifier ("obj"));
++ call.add_argument (new CCodeIdentifier ("signal_name"));
++ call.add_argument (new CCodeIdentifier ("handler"));
++ call.add_argument (new CCodeIdentifier ("data"));
++
++ if (m.binding == MemberBinding.INSTANCE) {
++ call.add_argument (new CCodeConstant ("0"));
++ }
++
++ block.add_statement (new CCodeExpressionStatement (call));
++ }
+ }
+
+Index: gobject/valaccodegenerator.vala
+===================================================================
+--- gobject/valaccodegenerator.vala (revision 1971)
++++ gobject/valaccodegenerator.vala (revision 2004)
+@@ -35,13 +35,12 @@
+ head = new CCodeBaseModule (this, head);
+ head = new CCodeStructModule (this, head);
+ head = new CCodeMethodModule (this, head);
++ head = new CCodeControlFlowModule (this, head);
+ head = new CCodeMemberAccessModule (this, head);
+ head = new CCodeAssignmentModule (this, head);
+ head = new CCodeInvocationExpressionModule (this, head);
+ head = new CCodeArrayModule (this, head);
+ head = new CCodeDelegateModule (this, head);
+- head = new CCodeDynamicPropertyModule (this, head);
+- head = new CCodeDynamicSignalModule (this, head);
+ head = new GErrorModule (this, head);
+ head = new GTypeModule (this, head);
+ head = new GObjectModule (this, head);