From: Luca Bruno Date: Sun, 7 Aug 2011 10:44:41 +0000 (+0200) Subject: Collect error_types on demand to allow transformations X-Git-Tag: 0.43.1~182 X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=6395a2efe8f166fe8b2595fc2ba08dc4bcc69216;p=thirdparty%2Fvala.git Collect error_types on demand to allow transformations --- diff --git a/codegen/valaccodedelegatemodule.vala b/codegen/valaccodedelegatemodule.vala index 042e2be05..478302969 100644 --- a/codegen/valaccodedelegatemodule.vala +++ b/codegen/valaccodedelegatemodule.vala @@ -115,7 +115,7 @@ public class Vala.CCodeDelegateModule : CCodeArrayModule { var cparam = new CCodeParameter ("user_data", "gpointer"); 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); } @@ -263,7 +263,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); } @@ -387,7 +387,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 b536e749f..cdedbee67 100644 --- a/codegen/valaccodemethodmodule.vala +++ b/codegen/valaccodemethodmodule.vala @@ -110,7 +110,9 @@ public abstract class Vala.CCodeMethodModule : CCodeStructModule { } if (m.has_error_type_parameter ()) { - foreach (DataType error_type in m.get_error_types ()) { + var error_types = new ArrayList (); + m.get_error_types (error_types); + foreach (DataType error_type in error_types) { generate_type_declaration (error_type, decl_space); } diff --git a/codegen/valagasyncmodule.vala b/codegen/valagasyncmodule.vala index f234afdb4..89da47c40 100644 --- a/codegen/valagasyncmodule.vala +++ b/codegen/valagasyncmodule.vala @@ -615,7 +615,7 @@ public class Vala.GAsyncModule : GtkModule { var ccall = new CCodeFunctionCall (new CCodeIdentifier ("g_task_propagate_pointer")); ccall.add_argument (async_result_cast); - if (m.get_error_types ().size > 0) { + if (m.tree_can_fail) { ccall.add_argument (new CCodeIdentifier ("error")); } else { ccall.add_argument (new CCodeConstant ("NULL")); @@ -633,7 +633,7 @@ public class Vala.GAsyncModule : GtkModule { } // If a task is cancelled, g_task_propagate_pointer returns NULL - if (m.get_error_types ().size > 0 || has_cancellable) { + if (m.tree_can_fail || has_cancellable) { var is_null = new CCodeBinaryExpression (CCodeBinaryOperator.EQUALITY, new CCodeConstant ("NULL"), data_var); ccode.open_if (is_null); diff --git a/codegen/valagdbusclientmodule.vala b/codegen/valagdbusclientmodule.vala index 32a45de21..91bdce363 100644 --- a/codegen/valagdbusclientmodule.vala +++ b/codegen/valagdbusclientmodule.vala @@ -566,7 +566,7 @@ public class Vala.GDBusClientModule : GDBusModule { ccode.add_declaration ("GUnixFDList*", new CCodeVariableDeclarator ("_fd_list")); } - bool has_error_argument = (m.get_error_types ().size > 0); + bool has_error_argument = m.tree_can_fail; CCodeExpression error_argument; if (has_error_argument) { error_argument = new CCodeIdentifier ("error"); @@ -593,7 +593,9 @@ public class Vala.GDBusClientModule : GDBusModule { } // register errors - foreach (var error_type in m.get_error_types ()) { + var error_types = new ArrayList (); + 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 e1984e24f..6b2f31ab4 100644 --- a/codegen/valagdbusservermodule.vala +++ b/codegen/valagdbusservermodule.vala @@ -273,7 +273,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"))); } } @@ -285,7 +285,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 ea8367fd3..a0cefb9d1 100644 --- a/codegen/valagerrormodule.vala +++ b/codegen/valagerrormodule.vala @@ -191,9 +191,7 @@ public class Vala.GErrorModule : CCodeDelegateModule { } var error_types = new ArrayList (); - 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; @@ -258,11 +256,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 (); + 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 98c9c77c1..440ac5edc 100644 --- a/vala/valaassignment.vala +++ b/vala/valaassignment.vala @@ -101,6 +101,11 @@ public class Vala.Assignment : Expression { return left.is_accessible (sym) && right.is_accessible (sym); } + public override void get_error_types (Collection 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; @@ -388,9 +393,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/valabinaryexpression.vala b/vala/valabinaryexpression.vala index be62ed64d..1e24968aa 100644 --- a/vala/valabinaryexpression.vala +++ b/vala/valabinaryexpression.vala @@ -154,6 +154,11 @@ public class Vala.BinaryExpression : Expression { return left.is_accessible (sym) && right.is_accessible (sym); } + public override void get_error_types (Collection 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; diff --git a/vala/valablock.vala b/vala/valablock.vala index cfe0e2498..7419b5b9d 100644 --- a/vala/valablock.vala +++ b/vala/valablock.vala @@ -170,17 +170,19 @@ public class Vala.Block : Symbol, Statement { constant.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 ()); - } - context.analyzer.current_symbol = old_symbol; context.analyzer.insert_block = old_insert_block; return !error; } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + // use get_statements () instead of statement_list to not miss errors within StatementList objects + foreach (Statement stmt in get_statements ()) { + stmt.get_error_types (collection, source_reference); + } + } + public override void emit (CodeGenerator codegen) { codegen.visit_block (this); } diff --git a/vala/valacallabletype.vala b/vala/valacallabletype.vala index 0642fa644..c604de8ec 100644 --- a/vala/valacallabletype.vala +++ b/vala/valacallabletype.vala @@ -90,7 +90,8 @@ public abstract class Vala.CallableType : DataType { builder.append_c (')'); // Append error-types - var error_types = get_error_types (); + var error_types = new ArrayList (); + get_error_types (error_types); if (error_types.size > 0) { builder.append (" throws "); diff --git a/vala/valacastexpression.vala b/vala/valacastexpression.vala index 5c050be2a..18ed153b8 100644 --- a/vala/valacastexpression.vala +++ b/vala/valacastexpression.vala @@ -122,6 +122,10 @@ public class Vala.CastExpression : Expression { } } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + inner.get_error_types (collection, source_reference); + } + public override bool check (CodeContext context) { if (checked) { return !error; diff --git a/vala/valacodenode.vala b/vala/valacodenode.vala index e8ab35725..216b5604f 100644 --- a/vala/valacodenode.vala +++ b/vala/valacodenode.vala @@ -62,51 +62,18 @@ 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 (); + get_error_types (error_types); + return error_types.size > 0; + } } - private List _error_types; - private static List _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 get_error_types () { - if (_error_types != null) { - return _error_types; - } - if (_empty_type_list == null) { - _empty_type_list = new ArrayList (); - } - 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 (); - } - _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 error_types) { - foreach (DataType error_type in error_types) { - add_error_type (error_type); - } - } - /** * Visits this code node with the specified CodeVisitor. * @@ -377,6 +344,9 @@ public abstract class Vala.CodeNode { public virtual void get_used_variables (Collection collection) { } + public virtual void get_error_types (Collection 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 a71a6a382..38fc217f3 100644 --- a/vala/valacodewriter.vala +++ b/vala/valacodewriter.vala @@ -706,7 +706,9 @@ public class Vala.CodeWriter : CodeVisitor { write_params (cb.get_parameters ()); - write_error_domains (cb.get_error_types ()); + var error_types = new ArrayList (); + cb.get_error_types (error_types); + write_error_domains (error_types); write_string (";"); @@ -794,7 +796,9 @@ public class Vala.CodeWriter : CodeVisitor { write_params (m.get_parameters ()); - write_error_domains (m.get_error_types ()); + var error_types = new ArrayList (); + m.get_error_types (error_types); + write_error_domains (error_types); write_code_block (m.body); diff --git a/vala/valaconditionalexpression.vala b/vala/valaconditionalexpression.vala index 98facaaed..27f7d8618 100644 --- a/vala/valaconditionalexpression.vala +++ b/vala/valaconditionalexpression.vala @@ -104,6 +104,12 @@ public class Vala.ConditionalExpression : Expression { return condition.is_accessible (sym) && true_expression.is_accessible (sym) && false_expression.is_accessible (sym); } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + condition.get_error_types (collection, source_reference); + true_expression.get_error_types (collection, source_reference); + false_expression.get_error_types (collection, source_reference); + } + public override bool check (CodeContext context) { if (checked) { return !error; diff --git a/vala/valaconstructor.vala b/vala/valaconstructor.vala index d16fc13a4..ae8f19e8d 100644 --- a/vala/valaconstructor.vala +++ b/vala/valaconstructor.vala @@ -77,7 +77,9 @@ public class Vala.Constructor : Subroutine { body.check (context); } - foreach (DataType body_error_type in body.get_error_types ()) { + var body_errors = new ArrayList (); + 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 198f031c1..ae8daab38 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 ()) { @@ -109,8 +111,10 @@ public class Vala.CreationMethod : Method { i++; } - 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 ()) { @@ -172,11 +176,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 (); + 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 f0a3d4161..ab652e906 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 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 258fe4d4e..16db6f1b8 100644 --- a/vala/valadelegate.vala +++ b/vala/valadelegate.vala @@ -68,6 +68,8 @@ public class Vala.Delegate : TypeSymbol, Callable { private DataType _return_type; private bool? _has_target; + private List error_types; + /** * Creates a new delegate. * @@ -185,21 +187,23 @@ public class Vala.Delegate : TypeSymbol, Callable { return false; } - var error_types = get_error_types (); - var method_error_types = m.get_error_types (); + var method_error_types = new ArrayList (); + m.get_error_types (method_error_types); // method must throw error if the delegate does - if (error_types.size > 0 && method_error_types.size == 0) { + if (error_types != null && error_types.size > 0 && method_error_types.size == 0) { return false; } // method may throw less but not more errors than the delegate foreach (DataType method_error_type in method_error_types) { bool match = false; - foreach (DataType delegate_error_type in 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; + } } } @@ -226,8 +230,10 @@ public class Vala.Delegate : TypeSymbol, Callable { 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); + } } } @@ -235,16 +241,43 @@ public class Vala.Delegate : TypeSymbol, Callable { 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 (); + } + error_types.add (error_type); + error_type.parent_node = this; + } + + public override void get_error_types (Collection 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; + } } } } @@ -272,8 +305,10 @@ public class Vala.Delegate : TypeSymbol, Callable { 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); + } } context.analyzer.current_source_file = old_source_file; diff --git a/vala/valadelegatetype.vala b/vala/valadelegatetype.vala index 0f4edfdb3..4fbaca175 100644 --- a/vala/valadelegatetype.vala +++ b/vala/valadelegatetype.vala @@ -189,9 +189,13 @@ public class Vala.DelegateType : CallableType { } // target-delegate may throw less but not more errors than the delegate - foreach (DataType error_type in get_error_types ()) { + var error_types = new ArrayList (); + get_error_types (error_types); + foreach (DataType error_type in error_types) { bool match = false; - foreach (DataType delegate_error_type in dt_target.get_error_types ()) { + var delegate_error_types = new ArrayList (); + dt_target.get_error_types (delegate_error_types); + foreach (DataType delegate_error_type in delegate_error_types) { if (error_type.compatible (delegate_error_type)) { match = true; break; diff --git a/vala/valaelementaccess.vala b/vala/valaelementaccess.vala index 62cd1a65d..88c396ae1 100644 --- a/vala/valaelementaccess.vala +++ b/vala/valaelementaccess.vala @@ -106,6 +106,13 @@ public class Vala.ElementAccess : Expression { return container.is_accessible (sym); } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + container.get_error_types (collection, source_reference); + foreach (Expression e in indices) { + e.get_error_types (collection, source_reference); + } + } + public override bool check (CodeContext context) { if (checked) { return !error; diff --git a/vala/valaexpressionstatement.vala b/vala/valaexpressionstatement.vala index 912e5d91a..43cebbe62 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 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 8b436f5f0..dc7e471a3 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -870,7 +870,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 (); + 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 416fb55d2..d0e35485d 100644 --- a/vala/valaforeachstatement.vala +++ b/vala/valaforeachstatement.vala @@ -380,12 +380,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 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 8d266917a..23958dbe9 100644 --- a/vala/valagirparser.vala +++ b/vala/valagirparser.vala @@ -1007,7 +1007,7 @@ public class Vala.GirParser : CodeVisitor { // ensure getter vfunc if the property is abstract if (m != null) { getter.process (parser); - if (m.return_type is VoidType || m.get_parameters().size != 0 || m.get_error_types ().size > 0) { + if (m.return_type is VoidType || m.get_parameters().size != 0 || m.tree_can_fail) { prop.set_attribute ("NoAccessorMethod", true); } else { if (getter.name == name) { @@ -1034,7 +1034,7 @@ public class Vala.GirParser : CodeVisitor { // ensure setter vfunc if the property is abstract if (m != null) { setter.process (parser); - if (!(m.return_type is VoidType || m.return_type is BooleanType) || m.get_parameters ().size != 1 || m.get_error_types ().size > 0) { + if (!(m.return_type is VoidType || m.return_type is BooleanType) || m.get_parameters ().size != 1 || m.tree_can_fail) { prop.set_attribute ("NoAccessorMethod", true); prop.set_attribute ("ConcreteAccessor", false); } else { @@ -3188,12 +3188,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)); + } } } @@ -3710,7 +3719,9 @@ public class Vala.GirParser : CodeVisitor { deleg.add_parameter (param.copy ()); } - foreach (var error_type in orig.get_error_types ()) { + var error_types = new ArrayList (); + orig.get_error_types (error_types, alias.source_reference); + foreach (var error_type in error_types) { deleg.add_error_type (error_type.copy ()); } @@ -4118,8 +4129,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 (); + 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 0f9476d36..61c87ba3f 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 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 3223e747a..a22497e70 100644 --- a/vala/valalambdaexpression.vala +++ b/vala/valalambdaexpression.vala @@ -197,7 +197,9 @@ public class Vala.LambdaExpression : Expression { return false; } - foreach (var error_type in cb.get_error_types ()) { + var error_types = new ArrayList (); + 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 4e6edbe63..ce6894633 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 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/valamemberaccess.vala b/vala/valamemberaccess.vala index 64263ba3e..805b168f3 100644 --- a/vala/valamemberaccess.vala +++ b/vala/valamemberaccess.vala @@ -193,6 +193,12 @@ public class Vala.MemberAccess : Expression { } } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + if (inner != null) { + inner.get_error_types (collection, source_reference); + } + } + public override bool check (CodeContext context) { if (checked) { return !error; diff --git a/vala/valamethod.vala b/vala/valamethod.vala index 1db46ae45..f567b246e 100644 --- a/vala/valamethod.vala +++ b/vala/valamethod.vala @@ -188,6 +188,8 @@ public class Vala.Method : Subroutine, Callable { private List postconditions; private DataType _return_type; + protected List error_types; + private weak Method _base_method; private weak Method _base_interface_method; private DataType _base_interface_type; @@ -272,9 +274,11 @@ public class Vala.Method : Subroutine, Callable { param.accept (visitor); } - foreach (DataType error_type in get_error_types ()) { + if (error_types != null) { + foreach (DataType error_type in error_types) { error_type.accept (visitor); } + } if (result_var != null) { result_var.accept (visitor); @@ -387,9 +391,12 @@ public class Vala.Method : Subroutine, Callable { } /* this method may throw less but not more errors than the base method */ - foreach (DataType method_error_type in get_error_types ()) { + var base_method_errors = new ArrayList (); + 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.get_error_types ()) { + foreach (DataType base_method_error_type in base_method_errors) { if (method_error_type.compatible (base_method_error_type)) { match = true; break; @@ -401,6 +408,7 @@ public class Vala.Method : Subroutine, Callable { return false; } } + } if (base_method.coroutine != this.coroutine) { invalid_match = "async mismatch"; return false; @@ -509,6 +517,32 @@ public class Vala.Method : Subroutine, Callable { 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 (); + } + error_types.add (error_type); + error_type.parent_node = this; + } + + public override void get_error_types (Collection 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 (base_interface_type == old_type) { base_interface_type = new_type; @@ -518,7 +552,7 @@ public class Vala.Method : Subroutine, Callable { return_type = new_type; return; } - var error_types = get_error_types (); + if (error_types != null) { for (int i = 0; i < error_types.size; i++) { if (error_types[i] == old_type) { error_types[i] = new_type; @@ -526,6 +560,7 @@ public class Vala.Method : Subroutine, Callable { } } } + } private void find_base_methods () { if (base_methods_valid) { @@ -635,7 +670,7 @@ public class Vala.Method : Subroutine, Callable { this_parameter.variable_type.value_owned = true; } if (get_attribute ("NoThrow") != null) { - get_error_types ().clear (); + error_types = null; } if (parent_symbol is Class && (is_abstract || is_virtual)) { @@ -746,7 +781,8 @@ public class Vala.Method : Subroutine, Callable { } } - foreach (DataType error_type in get_error_types ()) { + 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 @@ -756,6 +792,7 @@ public class Vala.Method : Subroutine, Callable { return false; } } + } if (result_var != null) { result_var.check (context); @@ -849,13 +886,17 @@ public class Vala.Method : Subroutine, Callable { // 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 (); + 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 (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; if (!can_propagate_error && !is_dynamic_error) { Report.warning (body_error_type.source_reference, "unhandled error `%s'".printf (body_error_type.to_string())); @@ -872,7 +913,9 @@ public class Vala.Method : Subroutine, Callable { bool throws_gerror = false; bool throws_gioerror = false; bool throws_gdbuserror = false; - foreach (DataType error_type in get_error_types ()) { + var error_types = new ArrayList (); + get_error_types (error_types); + foreach (DataType error_type in error_types) { if (!(error_type is ErrorType)) { continue; } @@ -1123,7 +1166,7 @@ public class Vala.Method : Subroutine, Callable { } public bool has_error_type_parameter () { - if (get_error_types ().size > 0) { + if (tree_can_fail) { return true; } if (base_method != null && base_method != this && base_method.has_error_type_parameter ()) { diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index 082e061f7..a09db9b11 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -142,6 +142,27 @@ public class Vala.MethodCall : Expression { return call.is_accessible (sym); } + public override void get_error_types (Collection 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; @@ -471,8 +492,6 @@ public class Vala.MethodCall : Expression { formal_value_type = ret_type.copy (); value_type = formal_value_type.get_actual_type (target_object_type, method_type_args, this); - bool may_throw = false; - if (mtype is MethodType) { var m = ((MethodType) mtype).method_symbol; if (is_yield_expression) { @@ -485,19 +504,7 @@ public class Vala.MethodCall : Expression { Report.error (source_reference, "yield expression not available outside async method"); } } - 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; } @@ -505,7 +512,7 @@ public class Vala.MethodCall : Expression { ((MemberAccess) call).inner.lvalue = true; } // avoid passing possible null to ref_sink_function without checking - if (may_throw && !value_type.nullable && value_type.floating_reference && ret_type is ObjectType) { + if (tree_can_fail && !value_type.nullable && value_type.floating_reference && ret_type is ObjectType) { value_type.nullable = true; } @@ -589,30 +596,6 @@ public class Vala.MethodCall : Expression { mtype = new MethodType (m.get_end_method ()); } } - } 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 ())) { @@ -628,7 +611,7 @@ public class Vala.MethodCall : Expression { } } - 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.current_symbol is Block)) { diff --git a/vala/valaobjectcreationexpression.vala b/vala/valaobjectcreationexpression.vala index 8bef09b25..4b609aee7 100644 --- a/vala/valaobjectcreationexpression.vala +++ b/vala/valaobjectcreationexpression.vala @@ -246,8 +246,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; @@ -423,16 +421,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); @@ -484,7 +472,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.current_symbol is Block)) { @@ -519,6 +507,16 @@ public class Vala.ObjectCreationExpression : Expression { return !error; } + public override void get_error_types (Collection 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 01ad01d29..f52fba893 100644 --- a/vala/valaparser.vala +++ b/vala/valaparser.vala @@ -2805,7 +2805,7 @@ public class Vala.Parser : CodeVisitor { 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/valapointerindirection.vala b/vala/valapointerindirection.vala index 97f6473a8..20dbcbfde 100644 --- a/vala/valapointerindirection.vala +++ b/vala/valapointerindirection.vala @@ -73,6 +73,10 @@ public class Vala.PointerIndirection : Expression { return inner.is_accessible (sym); } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + inner.get_error_types (collection, source_reference); + } + public override bool check (CodeContext context) { if (checked) { return !error; diff --git a/vala/valapropertyaccessor.vala b/vala/valapropertyaccessor.vala index 46952bb19..e348c2510 100644 --- a/vala/valapropertyaccessor.vala +++ b/vala/valapropertyaccessor.vala @@ -197,7 +197,9 @@ public class Vala.PropertyAccessor : Subroutine { body.check (context); - foreach (DataType body_error_type in body.get_error_types ()) { + var error_types = new ArrayList (); + 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 83e81a2cc..cdb782cf2 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 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; @@ -138,8 +144,6 @@ public class Vala.ReturnStatement : CodeNode, Statement { Report.warning (source_reference, "`null' incompatible with return type `%s'".printf (context.analyzer.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 934227a1a..515959815 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 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 156740f80..2b0da5837 100644 --- a/vala/valaswitchsection.vala +++ b/vala/valaswitchsection.vala @@ -85,6 +85,13 @@ public class Vala.SwitchSection : Block { } } + public override void get_error_types (Collection 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; @@ -111,11 +118,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 ()); - } - context.analyzer.current_symbol = old_symbol; context.analyzer.insert_block = old_insert_block; diff --git a/vala/valaswitchstatement.vala b/vala/valaswitchstatement.vala index 66dab0193..78cfa3d82 100644 --- a/vala/valaswitchstatement.vala +++ b/vala/valaswitchstatement.vala @@ -93,6 +93,12 @@ public class Vala.SwitchStatement : CodeNode, Statement { } } + public override void get_error_types (Collection 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) { return !error; @@ -140,7 +146,6 @@ public class Vala.SwitchStatement : CodeNode, Statement { } } } - add_error_types (section.get_error_types ()); } return !error; diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala index d4cade7a2..9349b1818 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 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; @@ -107,11 +116,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 7e82228a5..fcacfc7fb 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 collection, SourceReference? source_reference = null) { + var error_types = new ArrayList (); + 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; @@ -119,38 +144,14 @@ public class Vala.TryStatement : CodeNode, Statement { body.check (context); - var error_types = new ArrayList (); - foreach (DataType body_error_type in body.get_error_types ()) { - error_types.add (body_error_type); - } - - var handled_error_types = new ArrayList (); 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/vala/valaunaryexpression.vala b/vala/valaunaryexpression.vala index 87f4032ef..7ccbecb1d 100644 --- a/vala/valaunaryexpression.vala +++ b/vala/valaunaryexpression.vala @@ -150,6 +150,10 @@ public class Vala.UnaryExpression : Expression { return null; } + public override void get_error_types (Collection collection, SourceReference? source_reference = null) { + inner.get_error_types (collection, source_reference); + } + public override bool check (CodeContext context) { if (checked) { return !error; diff --git a/valadoc/symbolresolver.vala b/valadoc/symbolresolver.vala index 4980e88ab..adf19a34a 100644 --- a/valadoc/symbolresolver.vala +++ b/valadoc/symbolresolver.vala @@ -37,8 +37,10 @@ public class Valadoc.Drivers.SymbolResolver : Visitor { return symbol_map.get (symbol); } - private void resolve_thrown_list (Symbol symbol, Vala.List types) { - foreach (Vala.DataType type in types) { + private void resolve_thrown_list (Symbol symbol, Vala.Symbol vala_symbol) { + var error_types = new Vala.ArrayList (); + vala_symbol.get_error_types (error_types); + foreach (Vala.DataType type in error_types) { Vala.ErrorDomain vala_edom = (Vala.ErrorDomain) type.data_type; Symbol? edom = symbol_map.get (vala_edom); symbol.add_child (edom ?? glib_error); @@ -216,7 +218,7 @@ public class Valadoc.Drivers.SymbolResolver : Visitor { resolve_type_reference (item.return_type); - resolve_thrown_list (item, vala_delegate.get_error_types ()); + resolve_thrown_list (item, vala_delegate); item.accept_all_children (this, false); } @@ -248,7 +250,7 @@ public class Valadoc.Drivers.SymbolResolver : Visitor { item.base_method = (Method?) resolve (base_vala_method); } - resolve_thrown_list (item, vala_method.get_error_types ()); + resolve_thrown_list (item, vala_method); resolve_type_reference (item.return_type); diff --git a/vapigen/valagidlparser.vala b/vapigen/valagidlparser.vala index a187c6df3..1d07cc63a 100644 --- a/vapigen/valagidlparser.vala +++ b/vapigen/valagidlparser.vala @@ -1817,8 +1817,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 (); + 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); }