[vala/wip/transform: 3/4] Collect error_types on demand to allow transformations



commit f0d6babed1d2013754c4964d96518215df4123f9
Author: Luca Bruno <lucabru src gnome org>
Date:   Sun Aug 7 12:44:41 2011 +0200

    Collect error_types on demand to allow transformations

 codegen/valaccodedelegatemodule.vala   |    6 +-
 codegen/valaccodemethodmodule.vala     |    6 +-
 codegen/valadovaerrormodule.vala       |   10 ++--
 codegen/valagasyncmodule.vala          |    2 +-
 codegen/valagdbusclientmodule.vala     |    4 +-
 codegen/valagdbusservermodule.vala     |    4 +-
 codegen/valagerrormodule.vala          |   10 ++--
 vala/valaassignment.vala               |    8 ++-
 vala/valablock.vala                    |   11 +++-
 vala/valacodenode.vala                 |   46 +++------------
 vala/valacodewriter.vala               |    8 ++-
 vala/valaconstructor.vala              |    4 +-
 vala/valacreationmethod.vala           |   24 +++++---
 vala/valadeclarationstatement.vala     |   21 +++----
 vala/valadelegate.vala                 |   65 ++++++++++++++++-----
 vala/valaexpressionstatement.vala      |    6 +-
 vala/valaflowanalyzer.vala             |    4 +-
 vala/valaforeachstatement.vala         |   11 +++-
 vala/valagirparser.vala                |   23 ++++++--
 vala/valaifstatement.vala              |   15 +++--
 vala/valalambdaexpression.vala         |    4 +-
 vala/valaloop.vala                     |    6 +-
 vala/valamethod.vala                   |   99 ++++++++++++++++++++++---------
 vala/valamethodcall.vala               |   59 +++++++------------
 vala/valaobjectcreationexpression.vala |   24 ++++----
 vala/valaparser.vala                   |    2 +-
 vala/valapropertyaccessor.vala         |    4 +-
 vala/valareturnstatement.vala          |    8 ++-
 vala/valastatementlist.vala            |    6 ++
 vala/valaswitchsection.vala            |   12 ++--
 vala/valaswitchstatement.vala          |    7 ++-
 vala/valathrowstatement.vala           |   14 +++--
 vala/valatrystatement.vala             |   49 ++++++++--------
 vapigen/valagidlparser.vala            |    6 +-
 34 files changed, 347 insertions(+), 241 deletions(-)
---
diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala
index 6975e8e..01f65dd 100644
--- a/codegen/valaccodedelegatemodule.vala
+++ b/codegen/valaccodedelegatemodule.vala
@@ -110,7 +110,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
 			var cparam = new CCodeParameter ("user_data", "void*");
 			cfundecl.add_parameter (cparam);
 		}
-		if (d.get_error_types ().size > 0) {
+		if (d.tree_can_fail) {
 			var cparam = new CCodeParameter ("error", "GError**");
 			cfundecl.add_parameter (cparam);
 		}
@@ -258,7 +258,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
 			cparam_map.set (get_param_pos (-3), cparam);
 		}
 
-		if (m.get_error_types ().size > 0) {
+		if (m.tree_can_fail) {
 			var cparam = new CCodeParameter ("error", "GError**");
 			cparam_map.set (get_param_pos (-1), cparam);
 		}
@@ -376,7 +376,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule {
 			carg_map.set (get_param_pos (-3), new CCodeIdentifier ("result"));
 		}
 
-		if (m.get_error_types ().size > 0) {
+		if (m.tree_can_fail) {
 			carg_map.set (get_param_pos (-1), new CCodeIdentifier ("error"));
 		}
 
diff --git a/codegen/valaccodemethodmodule.vala b/codegen/valaccodemethodmodule.vala
index 9d8a802..49ef5c4 100644
--- a/codegen/valaccodemethodmodule.vala
+++ b/codegen/valaccodemethodmodule.vala
@@ -107,8 +107,10 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule {
 			}
 		}
 
-		if (m.get_error_types ().size > 0 || (m.base_method != null && m.base_method.get_error_types ().size > 0) || (m.base_interface_method != null && m.base_interface_method.get_error_types ().size > 0)) {
-			foreach (DataType error_type in m.get_error_types ()) {
+		if (m.tree_can_fail || (m.base_method != null && m.base_method.tree_can_fail) || (m.base_interface_method != null && m.base_interface_method.tree_can_fail)) {
+			var error_types = new ArrayList<DataType> ();
+			m.get_error_types (error_types);
+			foreach (DataType error_type in error_types) {
 				generate_type_declaration (error_type, decl_space);
 			}
 
diff --git a/codegen/valadovaerrormodule.vala b/codegen/valadovaerrormodule.vala
index 68f7a86..78b5be2 100644
--- a/codegen/valadovaerrormodule.vala
+++ b/codegen/valadovaerrormodule.vala
@@ -95,9 +95,7 @@ public class Vala.DovaErrorModule : DovaDelegateModule {
 			append_local_free (current_symbol, false, current_try);
 
 			var error_types = new ArrayList<DataType> ();
-			foreach (DataType node_error_type in node.get_error_types ()) {
-				error_types.add (node_error_type);
-			}
+			node.get_error_types (error_types);
 
 			bool has_general_catch_clause = false;
 
@@ -150,11 +148,13 @@ public class Vala.DovaErrorModule : DovaDelegateModule {
 			} else {
 				assert_not_reached ();
 			}
-		} else if (current_method != null && current_method.get_error_types ().size > 0) {
+		} else if (current_method != null && current_method.tree_can_fail) {
 			// current method can fail, propagate error
 			CCodeExpression ccond = null;
 
-			foreach (DataType error_type in current_method.get_error_types ()) {
+			var error_types = new ArrayList<DataType> ();
+			current_method.get_error_types (error_types);
+			foreach (DataType error_type in error_types) {
 				// If Dova.Error is allowed we propagate everything
 				if (error_type.equals (new ObjectType (error_class))) {
 					ccond = null;
diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala
index a7c4af1..737c8bf 100644
--- a/codegen/valagasyncmodule.vala
+++ b/codegen/valagasyncmodule.vala
@@ -418,7 +418,7 @@ public class Vala.GAsyncModule : GSignalModule {
 		var simple_async_result_cast = new CCodeFunctionCall (new CCodeIdentifier ("G_SIMPLE_ASYNC_RESULT"));
 		simple_async_result_cast.add_argument (new CCodeIdentifier ("_res_"));
 
-		if (m.get_error_types ().size > 0) {
+		if (m.tree_can_fail) {
 			// propagate error from async method
 			var propagate_error = new CCodeFunctionCall (new CCodeIdentifier ("g_simple_async_result_propagate_error"));
 			propagate_error.add_argument (simple_async_result_cast);
diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala
index 695ccbc..a47b95c 100644
--- a/codegen/valagdbusclientmodule.vala
+++ b/codegen/valagdbusclientmodule.vala
@@ -526,7 +526,9 @@ public class Vala.GDBusClientModule : GDBusModule {
 			timeout.add_argument (gdbusproxy);
 
 			// register errors
-			foreach (var error_type in m.get_error_types ()) {
+			var error_types = new ArrayList<DataType> ();
+			m.get_error_types (error_types);
+			foreach (var error_type in error_types) {
 				var errtype = (ErrorType) error_type;
 				if (errtype.error_domain != null) {
 					ccode.add_expression (new CCodeIdentifier (get_ccode_upper_case_name (errtype.error_domain)));
diff --git a/codegen/valagdbusservermodule.vala b/codegen/valagdbusservermodule.vala
index c92a444..436db89 100644
--- a/codegen/valagdbusservermodule.vala
+++ b/codegen/valagdbusservermodule.vala
@@ -232,7 +232,7 @@ public class Vala.GDBusServerModule : GDBusClientModule {
 		}
 
 		if (!m.coroutine || ready) {
-			if (m.get_error_types ().size > 0) {
+			if (m.tree_can_fail) {
 				ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, new CCodeIdentifier ("error")));
 			}
 		}
@@ -244,7 +244,7 @@ public class Vala.GDBusServerModule : GDBusClientModule {
 				ccode.add_assignment (new CCodeIdentifier ("result"), ccall);
 			}
 
-			if (m.get_error_types ().size > 0) {
+			if (m.tree_can_fail) {
 				ccode.open_if (new CCodeIdentifier ("error"));
 
 				var return_error = new CCodeFunctionCall (new CCodeIdentifier ("g_dbus_method_invocation_return_gerror"));
diff --git a/codegen/valagerrormodule.vala b/codegen/valagerrormodule.vala
index 10a080a..aa6e8f4 100644
--- a/codegen/valagerrormodule.vala
+++ b/codegen/valagerrormodule.vala
@@ -185,9 +185,7 @@ public class Vala.GErrorModule : CCodeDelegateModule {
 			}
 
 			var error_types = new ArrayList<DataType> ();
-			foreach (DataType node_error_type in node.get_error_types ()) {
-				error_types.add (node_error_type);
-			}
+			node.get_error_types (error_types);
 
 			bool has_general_catch_clause = false;
 
@@ -252,11 +250,13 @@ public class Vala.GErrorModule : CCodeDelegateModule {
 				// should never happen with correct bindings
 				uncaught_error_statement (inner_error, true);
 			}
-		} else if (current_method != null && current_method.get_error_types ().size > 0) {
+		} else if (current_method != null && current_method.tree_can_fail) {
 			// current method can fail, propagate error
 			CCodeBinaryExpression ccond = null;
 
-			foreach (DataType error_type in current_method.get_error_types ()) {
+			var error_types = new ArrayList<DataType> ();
+			current_method.get_error_types (error_types);
+			foreach (DataType error_type in error_types) {
 				// If GLib.Error is allowed we propagate everything
 				if (error_type.equals (gerror_type)) {
 					ccond = null;
diff --git a/vala/valaassignment.vala b/vala/valaassignment.vala
index 69434a5..41fbcfe 100644
--- a/vala/valaassignment.vala
+++ b/vala/valaassignment.vala
@@ -97,6 +97,11 @@ public class Vala.Assignment : Expression {
 		return false;
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		left.get_error_types (collection, source_reference);
+		right.get_error_types (collection, source_reference);
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -440,9 +445,6 @@ public class Vala.Assignment : Expression {
 			value_type = null;
 		}
 
-		add_error_types (left.get_error_types ());
-		add_error_types (right.get_error_types ());
-
 		return !error;
 	}
 
diff --git a/vala/valablock.vala b/vala/valablock.vala
index 0daff83..df2f1eb 100644
--- a/vala/valablock.vala
+++ b/vala/valablock.vala
@@ -158,12 +158,17 @@ public class Vala.Block : Symbol, Statement {
 			constant.active = false;
 		}
 
+		return !error;
+	}
+
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (source_reference == null) {
+			source_reference = this.source_reference;
+		}
 		// use get_statements () instead of statement_list to not miss errors within StatementList objects
 		foreach (Statement stmt in get_statements ()) {
-			add_error_types (stmt.get_error_types ());
+			stmt.get_error_types (collection, source_reference);
 		}
-
-		return !error;
 	}
 
 	public override void emit (CodeGenerator codegen) {
diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala
index c3d6429..7a8f668 100644
--- a/vala/valacodenode.vala
+++ b/vala/valacodenode.vala
@@ -62,52 +62,19 @@ public abstract class Vala.CodeNode {
 	 * Specifies that this node or a child node may throw an exception.
 	 */
 	public bool tree_can_fail { 
-		get { return _error_types != null && _error_types.size > 0; }
+		get {
+			var error_types = new ArrayList<DataType> ();
+			get_error_types (error_types);
+			return error_types.size > 0;
+		}
 	}
 
-	private List<DataType> _error_types;
-	private static List<DataType> _empty_type_list;
 	private AttributeCache[] attributes_cache;
 
 	static int last_temp_nr = 0;
 	static int next_attribute_cache_index = 0;
 
 	/**
-	 * Specifies the exceptions that can be thrown by this node or a child node
-	 */
-	public List<DataType> get_error_types () { 
-		if (_error_types != null) {
-			return _error_types;
-		}
-		if (_empty_type_list == null) {
-			_empty_type_list = new ArrayList<DataType> ();
-		}
-		return _empty_type_list;
-	}
-
-	/**
-	 * Adds an error type to the exceptions that can be thrown by this node
-	 * or a child node 
-	 */
-	public void add_error_type (DataType error_type) {
-		if (_error_types == null) {
-			_error_types = new ArrayList<DataType> ();
-		}
-		_error_types.add (error_type);
-		error_type.parent_node = this;
-	}
-
-	/**
-	 * Adds a collection of error types to the exceptions that can be thrown by this node
-	 * or a child node 
-	 */
-	public void add_error_types (List<DataType> error_types) {
-		foreach (DataType error_type in error_types) {
-			add_error_type (error_type);
-		}
-	}
-
-	/**
 	 * Visits this code node with the specified CodeVisitor.
 	 *
 	 * @param visitor the visitor to be called while traversing
@@ -383,6 +350,9 @@ public abstract class Vala.CodeNode {
 	public virtual void get_used_variables (Collection<Variable> collection) {
 	}
 
+	public virtual void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+	}
+
 	public static string get_temp_name () {
 		return "." + (++last_temp_nr).to_string ();
 	}
diff --git a/vala/valacodewriter.vala b/vala/valacodewriter.vala
index 922134f..66b4ea4 100644
--- a/vala/valacodewriter.vala
+++ b/vala/valacodewriter.vala
@@ -664,7 +664,9 @@ public class Vala.CodeWriter : CodeVisitor {
 		
 		write_params (cb.get_parameters ());
 
-		write_error_domains (cb.get_error_types ());
+		var error_types = new ArrayList<DataType> ();
+		cb.get_error_types (error_types);
+		write_error_domains (error_types);
 
 		write_string (";");
 
@@ -758,7 +760,9 @@ public class Vala.CodeWriter : CodeVisitor {
 		write_params (m.get_parameters ());
 
 		if (context.profile != Profile.DOVA) {
-			write_error_domains (m.get_error_types ());
+			var error_types = new ArrayList<DataType> ();
+			m.get_error_types (error_types);
+			write_error_domains (error_types);
 		}
 
 		write_code_block (m.body);
diff --git a/vala/valaconstructor.vala b/vala/valaconstructor.vala
index 3d19596..86f24de 100644
--- a/vala/valaconstructor.vala
+++ b/vala/valaconstructor.vala
@@ -74,7 +74,9 @@ public class Vala.Constructor : Subroutine {
 			body.check (context);
 		}
 
-		foreach (DataType body_error_type in body.get_error_types ()) {
+		var body_errors = new ArrayList<DataType> ();
+		body.get_error_types (body_errors);
+		foreach (DataType body_error_type in body_errors) {
 			if (!((ErrorType) body_error_type).dynamic_error) {
 				Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
 			}
diff --git a/vala/valacreationmethod.vala b/vala/valacreationmethod.vala
index c8fb157..0ab396f 100644
--- a/vala/valacreationmethod.vala
+++ b/vala/valacreationmethod.vala
@@ -60,8 +60,10 @@ public class Vala.CreationMethod : Method {
 			param.accept (visitor);
 		}
 
-		foreach (DataType error_type in get_error_types ()) {
-			error_type.accept (visitor);
+		if (error_types != null) {
+			foreach (DataType error_type in error_types) {
+				error_type.accept (visitor);
+			}
 		}
 
 		foreach (Expression precondition in get_preconditions ()) {
@@ -95,8 +97,10 @@ public class Vala.CreationMethod : Method {
 			param.check (context);
 		}
 
-		foreach (DataType error_type in get_error_types ()) {
-			error_type.check (context);
+		if (error_types != null) {
+			foreach (DataType error_type in error_types) {
+				error_type.check (context);
+			}
 		}
 
 		foreach (Expression precondition in get_preconditions ()) {
@@ -141,11 +145,15 @@ public class Vala.CreationMethod : Method {
 
 		// 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 ()) {
+			var body_errors = new ArrayList<DataType> ();
+			body.get_error_types (body_errors);
+			foreach (DataType body_error_type in body_errors) {
 				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 (error_types != null) {
+					foreach (DataType method_error_type in error_types) {
+						if (body_error_type.compatible (method_error_type)) {
+							can_propagate_error = true;
+						}
 					}
 				}
 				if (!can_propagate_error && !((ErrorType) body_error_type).dynamic_error) {
diff --git a/vala/valadeclarationstatement.vala b/vala/valadeclarationstatement.vala
index c4c778f..12303cd 100644
--- a/vala/valadeclarationstatement.vala
+++ b/vala/valadeclarationstatement.vala
@@ -62,6 +62,16 @@ public class Vala.DeclarationStatement : CodeNode, Statement {
 		declaration.accept (visitor);
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (source_reference == null) {
+			source_reference = this.source_reference;
+		}
+		var local = declaration as LocalVariable;
+		if (local != null && local.initializer != null) {
+			local.initializer.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -71,17 +81,6 @@ public class Vala.DeclarationStatement : CodeNode, Statement {
 
 		declaration.check (context);
 
-		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;
 	}
 
diff --git a/vala/valadelegate.vala b/vala/valadelegate.vala
index 71de1aa..d09bf92 100644
--- a/vala/valadelegate.vala
+++ b/vala/valadelegate.vala
@@ -68,6 +68,8 @@ public class Vala.Delegate : TypeSymbol {
 	private DataType _return_type;
 	private bool? _has_target;
 
+	private List<DataType> error_types;
+
 	/**
 	 * Creates a new delegate.
 	 *
@@ -186,12 +188,16 @@ public class Vala.Delegate : TypeSymbol {
 		}
 
 		// method may throw less but not more errors than the delegate
-		foreach (DataType method_error_type in m.get_error_types ()) {
+		var method_errors = new ArrayList<DataType> ();
+		m.get_error_types (method_errors);
+		foreach (DataType method_error_type in method_errors) {
 			bool match = false;
-			foreach (DataType delegate_error_type in get_error_types ()) {
-				if (method_error_type.compatible (delegate_error_type)) {
-					match = true;
-					break;
+			if (error_types != null) {
+				foreach (DataType delegate_error_type in error_types) {
+					if (method_error_type.compatible (delegate_error_type)) {
+						match = true;
+						break;
+					}
 				}
 			}
 
@@ -218,8 +224,10 @@ public class Vala.Delegate : TypeSymbol {
 			param.accept (visitor);
 		}
 
-		foreach (DataType error_type in get_error_types ()) {
-			error_type.accept (visitor);
+		if (error_types != null) {
+			foreach (DataType error_type in error_types) {
+				error_type.accept (visitor);
+			}
 		}
 	}
 
@@ -227,16 +235,43 @@ public class Vala.Delegate : TypeSymbol {
 		return false;
 	}
 
+	/**
+	 * Adds an error type to the exceptions that can be
+	 * thrown by this delegate.
+	 */
+	public void add_error_type (DataType error_type) {
+		if (error_types == null) {
+			error_types = new ArrayList<DataType> ();
+		}
+		error_types.add (error_type);
+		error_type.parent_node = this;
+	}
+
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (error_types != null) {
+			foreach (var error_type in error_types) {
+				if (source_reference != null) {
+					var type = error_type.copy ();
+					type.source_reference = source_reference;
+					collection.add (type);
+				} else {
+					collection.add (error_type);
+				}
+			}
+		}
+	}
+
 	public override void replace_type (DataType old_type, DataType new_type) {
 		if (return_type == old_type) {
 			return_type = new_type;
 			return;
 		}
-		var error_types = get_error_types ();
-		for (int i = 0; i < error_types.size; i++) {
-			if (error_types[i] == old_type) {
-				error_types[i] = new_type;
-				return;
+		if (error_types != null) {
+			for (int i = 0; i < error_types.size; i++) {
+				if (error_types[i] == old_type) {
+					error_types[i] = new_type;
+					return;
+				}
 			}
 		}
 	}
@@ -306,8 +341,10 @@ public class Vala.Delegate : TypeSymbol {
 			param.check (context);
 		}
 
-		foreach (DataType error_type in get_error_types ()) {
-			error_type.check (context);
+		if (error_types != null) {
+			foreach (DataType error_type in error_types) {
+				error_type.check (context);
+			}
 		}
 
 		return !error;
diff --git a/vala/valaexpressionstatement.vala b/vala/valaexpressionstatement.vala
index 6d01a98..c0c55f3 100644
--- a/vala/valaexpressionstatement.vala
+++ b/vala/valaexpressionstatement.vala
@@ -80,11 +80,13 @@ public class Vala.ExpressionStatement : CodeNode, Statement {
 			return false;
 		}
 
-		add_error_types (expression.get_error_types ());
-
 		return !error;
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		expression.get_error_types (collection, source_reference);
+	}
+
 	public override void emit (CodeGenerator codegen) {
 		expression.emit (codegen);
 
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index ada3254..fffb17a 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -851,7 +851,9 @@ public class Vala.FlowAnalyzer : CodeVisitor {
 			var last_block = current_block;
 
 			// exceptional control flow
-			foreach (DataType error_data_type in node.get_error_types()) {
+			var error_types = new ArrayList<DataType> ();
+			node.get_error_types (error_types);
+			foreach (DataType error_data_type in error_types) {
 				var error_type = error_data_type as ErrorType;
 				var error_class = error_data_type.data_type as Class;
 				current_block = last_block;
diff --git a/vala/valaforeachstatement.vala b/vala/valaforeachstatement.vala
index 68df1d6..3195159 100644
--- a/vala/valaforeachstatement.vala
+++ b/vala/valaforeachstatement.vala
@@ -373,12 +373,17 @@ public class Vala.ForeachStatement : Block {
 		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;
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (source_reference == null) {
+			source_reference = this.source_reference;
+		}
+		this.collection.get_error_types (collection, source_reference);
+		body.get_error_types (collection, source_reference);
+	}
+
 	public override void emit (CodeGenerator codegen) {
 		if (use_iterator) {
 			base.emit (codegen);
diff --git a/vala/valagirparser.vala b/vala/valagirparser.vala
index 645e215..825f2f1 100644
--- a/vala/valagirparser.vala
+++ b/vala/valagirparser.vala
@@ -2617,12 +2617,21 @@ public class Vala.GirParser : CodeVisitor {
 
 		if (!(metadata.get_expression (ArgumentType.THROWS) is NullLiteral)) {
 			if (metadata.has_argument (ArgumentType.THROWS)) {
-				var error_types = metadata.get_string(ArgumentType.THROWS).split(",");
-				foreach (var error_type in error_types) {
-					s.add_error_type (parse_type_from_string (error_type, true, metadata.get_source_reference (ArgumentType.THROWS)));
+				var error_types = metadata.get_string (ArgumentType.THROWS).split(",");
+				foreach (var error_type_name in error_types) {
+					var error_type = parse_type_from_string (error_type_name, true, metadata.get_source_reference (ArgumentType.THROWS));
+					if (s is Method) {
+						((Method) s).add_error_type (error_type);
+					} else {
+						((Delegate) s).add_error_type (error_type);
+					}
 				}
 			} else if (throws_string == "1") {
-				s.add_error_type (new ErrorType (null, null));
+				if (s is Method) {
+					((Method) s).add_error_type (new ErrorType (null, null));
+				} else {
+					((Delegate) s).add_error_type (new ErrorType (null, null));
+				}
 			}
 		}
 
@@ -3275,8 +3284,10 @@ public class Vala.GirParser : CodeVisitor {
 					}
 				}
 
-				foreach (DataType error_type in finish_method.get_error_types ()) {
-					method.add_error_type (error_type.copy ());
+				var error_types = new ArrayList<DataType> ();
+				finish_method.get_error_types (error_types, method.source_reference);
+				foreach (DataType error_type in error_types) {
+					method.add_error_type (error_type);
 				}
 				finish_method_node.processed = true;
 				finish_method_node.merged = true;
diff --git a/vala/valaifstatement.vala b/vala/valaifstatement.vala
index 7655ffd..f2d22e7 100644
--- a/vala/valaifstatement.vala
+++ b/vala/valaifstatement.vala
@@ -102,6 +102,14 @@ public class Vala.IfStatement : CodeNode, Statement {
 		}
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		condition.get_error_types (collection, source_reference);
+		true_statement.get_error_types (collection, source_reference);
+		if (false_statement != null) {
+			false_statement.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -130,13 +138,6 @@ public class Vala.IfStatement : CodeNode, Statement {
 			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;
 	}
 
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index 2c9f066..3859285 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -199,7 +199,9 @@ public class Vala.LambdaExpression : Expression {
 			return false;
 		}
 
-		foreach (var error_type in cb.get_error_types ()) {
+		var error_types = new ArrayList<DataType> ();
+		cb.get_error_types (error_types);
+		foreach (var error_type in error_types) {
 			method.add_error_type (error_type.copy ());
 		}
 
diff --git a/vala/valaloop.vala b/vala/valaloop.vala
index 5782070..bf44a9c 100644
--- a/vala/valaloop.vala
+++ b/vala/valaloop.vala
@@ -61,6 +61,10 @@ public class Vala.Loop : CodeNode, Statement {
 		body.accept (visitor);
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		body.get_error_types (collection, source_reference);
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -70,8 +74,6 @@ public class Vala.Loop : CodeNode, Statement {
 
 		body.check (context);
 
-		add_error_types (body.get_error_types ());
-
 		return !error;
 	}
 
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 9edb525..09b5de1 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -179,6 +179,8 @@ public class Vala.Method : Subroutine {
 	private List<Expression> postconditions;
 	private DataType _return_type;
 
+	protected List<DataType> error_types;
+
 	private weak Method _base_method;
 	private Method _base_interface_method;
 	private bool base_methods_valid;
@@ -248,8 +250,10 @@ public class Vala.Method : Subroutine {
 			param.accept (visitor);
 		}
 
-		foreach (DataType error_type in get_error_types ()) {
-			error_type.accept (visitor);
+		if (error_types != null) {
+			foreach (DataType error_type in error_types) {
+				error_type.accept (visitor);
+			}
 		}
 
 		if (result_var != null) {
@@ -334,18 +338,22 @@ public class Vala.Method : Subroutine {
 		}
 
 		/* this method may throw less but not more errors than the base method */
-		foreach (DataType method_error_type in get_error_types ()) {
-			bool match = false;
-			foreach (DataType base_method_error_type in base_method.get_error_types ()) {
-				if (method_error_type.compatible (base_method_error_type)) {
-					match = true;
-					break;
+		var base_method_errors = new ArrayList<DataType> ();
+		base_method.get_error_types (base_method_errors);
+		if (error_types != null) {
+			foreach (DataType method_error_type in error_types) {
+				bool match = false;
+				foreach (DataType base_method_error_type in base_method_errors) {
+					if (method_error_type.compatible (base_method_error_type)) {
+						match = true;
+						break;
+					}
 				}
-			}
 
-			if (!match) {
-				invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
-				return false;
+				if (!match) {
+					invalid_match = "incompatible error type `%s'".printf (method_error_type.to_string ());
+					return false;
+				}
 			}
 		}
 		if (base_method.coroutine != this.coroutine) {
@@ -456,16 +464,43 @@ public class Vala.Method : Subroutine {
 		return _empty_expression_list;
 	}
 
+	/**
+	 * Adds an error type to the exceptions that can be
+	 * thrown by this method.
+	 */
+	public void add_error_type (DataType error_type) {
+		if (error_types == null) {
+			error_types = new ArrayList<DataType> ();
+		}
+		error_types.add (error_type);
+		error_type.parent_node = this;
+	}
+
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (error_types != null) {
+			foreach (var error_type in error_types) {
+				if (source_reference != null) {
+					var type = error_type.copy ();
+					type.source_reference = source_reference;
+					collection.add (type);
+				} else {
+					collection.add (error_type);
+				}
+			}
+		}
+	}
+
 	public override void replace_type (DataType old_type, DataType new_type) {
 		if (return_type == old_type) {
 			return_type = new_type;
 			return;
 		}
-		var error_types = get_error_types ();
-		for (int i = 0; i < error_types.size; i++) {
-			if (error_types[i] == old_type) {
-				error_types[i] = new_type;
-				return;
+		if (error_types != null) {
+			for (int i = 0; i < error_types.size; i++) {
+				if (error_types[i] == old_type) {
+					error_types[i] = new_type;
+					return;
+				}
 			}
 		}
 	}
@@ -561,7 +596,7 @@ public class Vala.Method : Subroutine {
 			this_parameter.variable_type.value_owned = true;
 		}
 		if (get_attribute ("NoThrow") != null) {
-			get_error_types ().clear ();
+			error_types = null;
 		}
 
 		if (is_abstract) {
@@ -646,14 +681,16 @@ public class Vala.Method : Subroutine {
 			}
 		}
 
-		foreach (DataType error_type in get_error_types ()) {
-			error_type.check (context);
+		if (error_types != null) {
+			foreach (DataType error_type in error_types) {
+				error_type.check (context);
 
-			// check whether error type is at least as accessible as the method
-			if (!context.analyzer.is_type_accessible (this, error_type)) {
-				error = true;
-				Report.error (source_reference, "error type `%s` is less accessible than method `%s`".printf (error_type.to_string (), get_full_name ()));
-				return false;
+				// check whether error type is at least as accessible as the method
+				if (!context.analyzer.is_type_accessible (this, error_type)) {
+					error = true;
+					Report.error (source_reference, "error type `%s` is less accessible than method `%s`".printf (error_type.to_string (), get_full_name ()));
+					return false;
+				}
 			}
 		}
 
@@ -732,11 +769,15 @@ public class Vala.Method : Subroutine {
 
 		// 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 ()) {
+			var body_errors = new ArrayList<DataType> ();
+			body.get_error_types (body_errors);
+			foreach (DataType body_error_type in body_errors) {
 				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 (error_types != null) {
+					foreach (DataType method_error_type in error_types) {
+						if (body_error_type.compatible (method_error_type)) {
+							can_propagate_error = true;
+						}
 					}
 				}
 				bool is_dynamic_error = body_error_type is ErrorType && ((ErrorType) body_error_type).dynamic_error;
diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala
index b5c2af4..132cc67 100644
--- a/vala/valamethodcall.vala
+++ b/vala/valamethodcall.vala
@@ -147,6 +147,27 @@ public class Vala.MethodCall : Expression {
 		}
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (source_reference == null) {
+			source_reference = this.source_reference;
+		}
+		var mtype = call.value_type;
+		if (mtype is MethodType) {
+			var m = ((MethodType) mtype).method_symbol;
+			if (!(m != null && m.coroutine && !is_yield_expression && ((MemberAccess) call).member_name != "end")) {
+				m.get_error_types (collection, source_reference);
+			}
+		} else if (mtype is ObjectType) {
+			// constructor
+			var cl = (Class) ((ObjectType) mtype).type_symbol;
+			var m = cl.default_construction_method;
+			m.get_error_types (collection, source_reference);
+		} else if (mtype is DelegateType) {
+			var d = ((DelegateType) mtype).delegate_symbol;
+			d.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -583,19 +604,7 @@ public class Vala.MethodCall : Expression {
 				}
 				current_method.yield_count++;
 			}
-			if (m != null && m.coroutine && !is_yield_expression && ((MemberAccess) call).member_name != "end") {
-				// .begin call of async method, no error can happen here
-			} else {
-				foreach (DataType error_type in m.get_error_types ()) {
-					may_throw = true;
 
-					// 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);
-				}
-			}
 			if (m.returns_floating_reference) {
 				value_type.floating_reference = true;
 			}
@@ -682,30 +691,6 @@ public class Vala.MethodCall : Expression {
 					value_type = formal_value_type.get_actual_type (target_object_type, call as MemberAccess, this);
 				}
 			}
-		} else if (mtype is ObjectType) {
-			// constructor
-			var cl = (Class) ((ObjectType) mtype).type_symbol;
-			var m = cl.default_construction_method;
-			foreach (DataType error_type in m.get_error_types ()) {
-				may_throw = true;
-
-				// 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 (mtype is DelegateType) {
-			var d = ((DelegateType) mtype).delegate_symbol;
-			foreach (DataType error_type in d.get_error_types ()) {
-				may_throw = true;
-
-				// 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);
-			}
 		}
 
 		if (!context.analyzer.check_arguments (this, mtype, params, get_argument_list ())) {
@@ -713,7 +698,7 @@ public class Vala.MethodCall : Expression {
 			return false;
 		}
 
-		if (may_throw) {
+		if (tree_can_fail) {
 			if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
 				// simple statements, no side effects after method call
 			} else if (!(context.analyzer.get_current_symbol (this) is Block)) {
diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala
index 9a18774..210fb86 100644
--- a/vala/valaobjectcreationexpression.vala
+++ b/vala/valaobjectcreationexpression.vala
@@ -228,8 +228,6 @@ public class Vala.ObjectCreationExpression : Expression {
 		value_type = type_reference.copy ();
 		value_type.value_owned = true;
 
-		bool may_throw = false;
-
 		int given_num_type_args = type_reference.get_type_arguments ().size;
 		int expected_num_type_args = 0;
 
@@ -351,16 +349,6 @@ public class Vala.ObjectCreationExpression : Expression {
 			}
 
 			context.analyzer.check_arguments (this, new MethodType (m), m.get_parameters (), args);
-
-			foreach (DataType error_type in m.get_error_types ()) {
-				may_throw = true;
-
-				// 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) {
 			if (type_reference != null) {
 				type_reference.check (context);
@@ -396,7 +384,7 @@ public class Vala.ObjectCreationExpression : Expression {
 			context.analyzer.visit_member_initializer (init, type_reference);
 		}
 
-		if (may_throw) {
+		if (tree_can_fail) {
 			if (parent_node is LocalVariable || parent_node is ExpressionStatement) {
 				// simple statements, no side effects after method call
 			} else if (!(context.analyzer.get_current_symbol (this) is Block)) {
@@ -437,6 +425,16 @@ public class Vala.ObjectCreationExpression : Expression {
 		return !error;
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (symbol_reference is Method) {
+			if (source_reference == null) {
+				source_reference = this.source_reference;
+			}
+			var m = (Method) symbol_reference;
+			m.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override void emit (CodeGenerator codegen) {
 		foreach (Expression arg in argument_list) {
 			arg.emit (codegen);
diff --git a/vala/valaparser.vala b/vala/valaparser.vala
index 6aedb92..c118294 100644
--- a/vala/valaparser.vala
+++ b/vala/valaparser.vala
@@ -2788,7 +2788,7 @@ public class Vala.Parser : CodeVisitor {
 		} else {
 			if (accept (TokenType.THROWS)) {
 				do {
-					prop.add_error_type (parse_type (true, false));
+					parse_type (true, false);
 				} while (accept (TokenType.COMMA));
 				Report.error (prop.source_reference, "properties throwing errors are not supported yet");
 			}
diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala
index 1f6769b..3c56e01 100644
--- a/vala/valapropertyaccessor.vala
+++ b/vala/valapropertyaccessor.vala
@@ -170,7 +170,9 @@ public class Vala.PropertyAccessor : Subroutine {
 			body.check (context);
 
 			if (context.profile != Profile.DOVA) {
-				foreach (DataType body_error_type in body.get_error_types ()) {
+				var error_types = new ArrayList<DataType> ();
+				body.get_error_types (error_types);
+				foreach (DataType body_error_type in error_types) {
 					if (!((ErrorType) body_error_type).dynamic_error) {
 						Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string()));
 					}
diff --git a/vala/valareturnstatement.vala b/vala/valareturnstatement.vala
index ee14a71..6760aff 100644
--- a/vala/valareturnstatement.vala
+++ b/vala/valareturnstatement.vala
@@ -70,6 +70,12 @@ public class Vala.ReturnStatement : CodeNode, Statement {
 		}
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (return_expression != null) {
+			return_expression.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -145,8 +151,6 @@ public class Vala.ReturnStatement : CodeNode, Statement {
 			Report.warning (source_reference, "`null' incompatible with return type `%s`".printf (current_return_type.to_string ()));
 		}
 
-		add_error_types (return_expression.get_error_types ());
-
 		return !error;
 	}
 
diff --git a/vala/valastatementlist.vala b/vala/valastatementlist.vala
index 934227a..5159598 100644
--- a/vala/valastatementlist.vala
+++ b/vala/valastatementlist.vala
@@ -48,6 +48,12 @@ public class Vala.StatementList : CodeNode, Statement {
 		list.insert (index, stmt);
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		foreach (var stmt in list) {
+			stmt.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override void accept (CodeVisitor visitor) {
 		foreach (Statement stmt in list) {
 			stmt.accept (visitor);
diff --git a/vala/valaswitchsection.vala b/vala/valaswitchsection.vala
index b79e39e..5580ac6 100644
--- a/vala/valaswitchsection.vala
+++ b/vala/valaswitchsection.vala
@@ -81,6 +81,13 @@ public class Vala.SwitchSection : Block {
 		}
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		// use get_statements () instead of statement_list to not miss errors within StatementList objects
+		foreach (var stmt in get_statements ()) {
+			stmt.get_error_types (collection, source_reference);
+		}
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -102,11 +109,6 @@ public class Vala.SwitchSection : Block {
 			local.active = false;
 		}
 
-		// use get_statements () instead of statement_list to not miss errors within StatementList objects
-		foreach (Statement stmt in get_statements ()) {
-			add_error_types (stmt.get_error_types ());
-		}
-
 		return !error;
 	}
 
diff --git a/vala/valaswitchstatement.vala b/vala/valaswitchstatement.vala
index 12ad04b..bb4cc50 100644
--- a/vala/valaswitchstatement.vala
+++ b/vala/valaswitchstatement.vala
@@ -92,6 +92,12 @@ public class Vala.SwitchStatement : CodeNode, Statement {
 			expression = new_node;
 		}
 	}
+
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		foreach (SwitchSection section in sections) {
+			section.get_error_types (collection, source_reference);
+		}
+	}
 	
 	public override bool check (CodeContext context) {
 		if (checked) {
@@ -137,7 +143,6 @@ public class Vala.SwitchStatement : CodeNode, Statement {
 					Report.error (label.expression.source_reference, "Switch statement already contains this label");
 				}
 			}
-			add_error_types (section.get_error_types ());
 		}
 
 		return !error;
diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala
index 2dbcc3d..5de6447 100644
--- a/vala/valathrowstatement.vala
+++ b/vala/valathrowstatement.vala
@@ -72,6 +72,15 @@ public class Vala.ThrowStatement : CodeNode, Statement {
 		}
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		if (source_reference == null) {
+			source_reference = this.source_reference;
+		}
+		var error_type = error_expression.value_type.copy ();
+		error_type.source_reference = source_reference;
+		collection.add (error_type);
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -105,11 +114,6 @@ public class Vala.ThrowStatement : CodeNode, Statement {
 			}
 		}
 
-		var error_type = error_expression.value_type.copy ();
-		error_type.source_reference = source_reference;
-
-		add_error_type (error_type);
-
 		return !error;
 	}
 
diff --git a/vala/valatrystatement.vala b/vala/valatrystatement.vala
index 38000f5..3ae8924 100644
--- a/vala/valatrystatement.vala
+++ b/vala/valatrystatement.vala
@@ -104,6 +104,31 @@ public class Vala.TryStatement : CodeNode, Statement {
 		}
 	}
 
+	public override void get_error_types (Collection<DataType> collection, SourceReference? source_reference = null) {
+		var error_types = new ArrayList<DataType> ();
+		body.get_error_types (error_types, source_reference);
+
+		foreach (CatchClause clause in catch_clauses) {
+			for (int i=0; i < error_types.size; i++) {
+				var error_type = error_types[i];
+				if (clause.error_type == null || error_type.compatible (clause.error_type)) {
+					error_types.remove_at (i);
+					i--;
+				}
+			}
+
+			clause.body.get_error_types (collection, source_reference);
+		}
+
+		if (finally_body != null) {
+			finally_body.get_error_types (collection, source_reference);
+		}
+
+		foreach (var error_type in error_types) {
+			collection.add (error_type);
+		}
+	}
+
 	public override bool check (CodeContext context) {
 		if (checked) {
 			return !error;
@@ -113,38 +138,14 @@ public class Vala.TryStatement : CodeNode, Statement {
 
 		body.check (context);
 
-		var error_types = new ArrayList<DataType> ();
-		foreach (DataType body_error_type in body.get_error_types ()) {
-			error_types.add (body_error_type);
-		}
-
-		var handled_error_types = new ArrayList<DataType> ();
 		foreach (CatchClause clause in catch_clauses) {
-			foreach (DataType body_error_type in error_types) {
-				if (clause.error_type == null || body_error_type.compatible (clause.error_type)) {
-					handled_error_types.add (body_error_type);
-				}
-			}
-			foreach (DataType handled_error_type in handled_error_types) {
-				error_types.remove (handled_error_type);
-			}
-			handled_error_types.clear ();
-
 			clause.check (context);
-			foreach (DataType body_error_type in clause.body.get_error_types ()) {
-				error_types.add (body_error_type);
-			}
 		}
 
 		if (finally_body != null) {
 			finally_body.check (context);
-			foreach (DataType body_error_type in finally_body.get_error_types ()) {
-				error_types.add (body_error_type);
-			}
 		}
 
-		add_error_types (error_types);
-
 		return !error;
 	}
 
diff --git a/vapigen/valagidlparser.vala b/vapigen/valagidlparser.vala
index e3d0728..30bdb19 100644
--- a/vapigen/valagidlparser.vala
+++ b/vapigen/valagidlparser.vala
@@ -1757,8 +1757,10 @@ public class Vala.GIdlParser : CodeVisitor {
 							m.add_parameter (async_param);
 						}
 					}
-					foreach (DataType error_type in finish_method.get_error_types ()) {
-						m.add_error_type (error_type.copy ());
+					var error_types = new ArrayList<DataType> ();
+					finish_method.get_error_types (error_types, m.source_reference);
+					foreach (DataType error_type in error_types) {
+						m.add_error_type (error_type);
 					}
 					finish_methods.add (finish_method);
 				}



[Date Prev][Date Next]   [Thread Prev][Thread Next]   [Thread Index] [Date Index] [Author Index]