]> git.ipfire.org Git - thirdparty/vala.git/commitdiff
dova: Add initial support for error handling
authorJürg Billeter <j@bitron.ch>
Sat, 6 Feb 2010 13:25:41 +0000 (14:25 +0100)
committerJürg Billeter <j@bitron.ch>
Tue, 8 Jun 2010 07:47:21 +0000 (09:47 +0200)
codegen/Makefile.am
codegen/valaccodegenerator.vala
codegen/valadovabasemodule.vala
codegen/valadovaerrormodule.vala [new file with mode: 0644]
codegen/valadovamethodcallmodule.vala
codegen/valadovaobjectmodule.vala
vala/valacatchclause.vala
vala/valaflowanalyzer.vala
vala/valamethod.vala
vala/valasemanticanalyzer.vala
vala/valathrowstatement.vala

index c62b6f6eb2a23413dfcaa07b8d161d62a7959a1b..7581eb61feb49309d7a23fe2e3b80d1b657e0201 100644 (file)
@@ -39,6 +39,7 @@ libvala_la_VALASOURCES = \
        valadovabasemodule.vala \
        valadovacontrolflowmodule.vala \
        valadovadelegatemodule.vala \
+       valadovaerrormodule.vala \
        valadovamemberaccessmodule.vala \
        valadovamethodcallmodule.vala \
        valadovamethodmodule.vala \
index e2155cf74763339a90cf80a3ceca63a48e89ce3c..b32ba3ccb3885b9cbe3699a2208837ccf98c6a04 100644 (file)
@@ -65,8 +65,9 @@ public class Vala.CCodeGenerator : CodeGenerator {
                        head = new DovaArrayModule (this, head);
                        head = new DovaObjectModule (this, head);
                        head = new DovaValueModule (this, head);
-                       */
                        head = new DovaDelegateModule (this, head);
+                       */
+                       head = new DovaErrorModule (this, head);
                } else {
                        /* included by inheritance
                        head = new CCodeBaseModule (this, head);
index f58a52540ebca51df42909515ec2ce1b49cbd744..01c3fb77517509408f13347628a02cb1f40d4d79 100644 (file)
@@ -130,6 +130,7 @@ internal class Vala.DovaBaseModule : CCodeModule {
        public Class value_class;
        public Class array_class;
        public Class delegate_class;
+       public Class error_class;
 
        Set<Symbol> generated_external_symbols;
 
@@ -208,6 +209,7 @@ internal class Vala.DovaBaseModule : CCodeModule {
                value_class = (Class) dova_ns.scope.lookup ("Value");
                array_class = (Class) dova_ns.scope.lookup ("Array");
                delegate_class = (Class) dova_ns.scope.lookup ("Delegate");
+               error_class = (Class) dova_ns.scope.lookup ("Error");
 
                header_declarations = new CCodeDeclarationSpace ();
                internal_header_declarations = new CCodeDeclarationSpace ();
diff --git a/codegen/valadovaerrormodule.vala b/codegen/valadovaerrormodule.vala
new file mode 100644 (file)
index 0000000..9da609a
--- /dev/null
@@ -0,0 +1,343 @@
+/* valadovaerrormodule.vala
+ *
+ * Copyright (C) 2008-2010  Jürg Billeter
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2.1 of the License, or (at your option) any later version.
+
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+ * Lesser General Public License for more details.
+
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
+ *
+ * Author:
+ *     Jürg Billeter <j@bitron.ch>
+ *     Thijs Vermeir <thijsvermeir@gmail.com>
+ */
+
+using GLib;
+
+internal class Vala.DovaErrorModule : DovaDelegateModule {
+       private int current_try_id = 0;
+       private int next_try_id = 0;
+       private bool is_in_catch = false;
+
+       public DovaErrorModule (CCodeGenerator codegen, CCodeModule? next) {
+               base (codegen, next);
+       }
+
+       public override void visit_throw_statement (ThrowStatement stmt) {
+               stmt.accept_children (codegen);
+
+               var cfrag = new CCodeFragment ();
+
+               // method will fail
+               current_method_inner_error = true;
+               var cassign = new CCodeAssignment (get_variable_cexpression ("_inner_error_"), (CCodeExpression) stmt.error_expression.ccodenode);
+               cfrag.append (new CCodeExpressionStatement (cassign));
+
+               head.add_simple_check (stmt, cfrag, true);
+
+               stmt.ccodenode = cfrag;
+
+               create_temp_decl (stmt, stmt.error_expression.temp_vars);
+       }
+
+       public virtual CCodeStatement return_with_exception () {
+               // propagate error
+               var cerror_block = new CCodeBlock ();
+               cerror_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (new CCodeUnaryExpression (CCodeUnaryOperator.POINTER_INDIRECTION, new CCodeIdentifier ("error")), get_variable_cexpression ("_inner_error_"))));
+               cerror_block.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression ("_inner_error_"), new CCodeConstant ("NULL"))));
+
+               // free local variables
+               var free_frag = new CCodeFragment ();
+               append_local_free (current_symbol, free_frag, false);
+               cerror_block.add_statement (free_frag);
+
+               if (current_method is CreationMethod) {
+                       var cl = current_method.parent_symbol as Class;
+                       var unref_call = new CCodeFunctionCall (new CCodeIdentifier (cl.get_unref_function ()));
+                       unref_call.add_argument (new CCodeIdentifier ("self"));
+                       cerror_block.add_statement (new CCodeExpressionStatement (unref_call));
+                       cerror_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
+               } else if (current_return_type is VoidType) {
+                       cerror_block.add_statement (new CCodeReturnStatement ());
+               } else {
+                       cerror_block.add_statement (new CCodeReturnStatement (default_value_for_type (current_return_type, false)));
+               }
+
+               return cerror_block;
+       }
+
+       CCodeStatement uncaught_error_statement (CCodeExpression inner_error, CCodeBlock? block = null, bool unexpected = false) {
+               var cerror_block = block;
+               if (cerror_block == null) {
+                       cerror_block = new CCodeBlock ();
+               }
+
+               // free local variables
+               var free_frag = new CCodeFragment ();
+               append_local_free (current_symbol, free_frag, false);
+               cerror_block.add_statement (free_frag);
+
+               // TODO log uncaught error as critical warning
+
+               if (current_method is CreationMethod) {
+                       cerror_block.add_statement (new CCodeReturnStatement (new CCodeConstant ("NULL")));
+               } else if (current_return_type is VoidType) {
+                       cerror_block.add_statement (new CCodeReturnStatement ());
+               } else if (current_return_type != null) {
+                       cerror_block.add_statement (new CCodeReturnStatement (default_value_for_type (current_return_type, false)));
+               }
+
+               return cerror_block;
+       }
+
+       bool in_finally_block (CodeNode node) {
+               var current_node = node;
+               while (current_node != null) {
+                       var try_stmt = current_node.parent_node as TryStatement;
+                       if (try_stmt != null && try_stmt.finally_body == current_node) {
+                               return true;
+                       }
+                       current_node = current_node.parent_node;
+               }
+               return false;
+       }
+
+       public override void add_simple_check (CodeNode node, CCodeFragment cfrag, bool always_fails = false) {
+               current_method_inner_error = true;
+
+               var inner_error = get_variable_cexpression ("_inner_error_");
+
+               CCodeStatement cerror_handler = null;
+
+               if (current_try != null) {
+                       // surrounding try found
+                       var cerror_block = new CCodeBlock ();
+
+                       // free local variables
+                       var free_frag = new CCodeFragment ();
+                       append_error_free (current_symbol, free_frag, current_try);
+                       cerror_block.add_statement (free_frag);
+
+                       var error_types = new ArrayList<DataType> ();
+                       foreach (DataType node_error_type in node.get_error_types ()) {
+                               error_types.add (node_error_type);
+                       }
+
+                       bool has_general_catch_clause = false;
+
+                       if (!is_in_catch) {
+                               var handled_error_types = new ArrayList<DataType> ();
+                               foreach (CatchClause clause in current_try.get_catch_clauses ()) {
+                                       // keep track of unhandled error types
+                                       foreach (DataType node_error_type in error_types) {
+                                               if (clause.error_type == null || node_error_type.compatible (clause.error_type)) {
+                                                       handled_error_types.add (node_error_type);
+                                               }
+                                       }
+                                       foreach (DataType handled_error_type in handled_error_types) {
+                                               error_types.remove (handled_error_type);
+                                       }
+                                       handled_error_types.clear ();
+
+                                       // go to catch clause if error domain matches
+                                       var cgoto_stmt = new CCodeGotoStatement (clause.clabel_name);
+
+                                       if (clause.error_type.equals (new ObjectType (error_class))) {
+                                               // general catch clause, this should be the last one
+                                               has_general_catch_clause = true;
+                                               cerror_block.add_statement (cgoto_stmt);
+                                               break;
+                                       } else {
+                                               var catch_type = clause.error_type as ObjectType;
+                                               var cgoto_block = new CCodeBlock ();
+                                               cgoto_block.add_statement (cgoto_stmt);
+
+                                               var type_check = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_is_a"));
+                                               type_check.add_argument (inner_error);
+                                               type_check.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (catch_type.type_symbol.get_lower_case_cname ()))));
+
+                                               cerror_block.add_statement (new CCodeIfStatement (type_check, cgoto_block));
+                                       }
+                               }
+                       }
+
+                       if (has_general_catch_clause) {
+                               // every possible error is already caught
+                               // as there is a general catch clause
+                               // no need to do anything else
+                       } else if (error_types.size > 0) {
+                               // go to finally clause if no catch clause matches
+                               // and there are still unhandled error types
+                               cerror_block.add_statement (new CCodeGotoStatement ("__finally%d".printf (current_try_id)));
+                       } else if (in_finally_block (node)) {
+                               // do not check unexpected errors happening within finally blocks
+                               // as jump out of finally block is not supported
+                       } else {
+                               // should never happen with correct bindings
+                               uncaught_error_statement (inner_error, cerror_block, true);
+                       }
+
+                       cerror_handler = cerror_block;
+               } else if (current_method != null && current_method.get_error_types ().size > 0) {
+                       // current method can fail, propagate error
+                       CCodeExpression ccond = null;
+
+                       foreach (DataType error_type in current_method.get_error_types ()) {
+                               // If Dova.Error is allowed we propagate everything
+                               if (error_type.equals (new ObjectType (error_class))) {
+                                       ccond = null;
+                                       break;
+                               }
+
+                               // Check the allowed error domains to propagate
+                               var type_check = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_is_a"));
+                               type_check.add_argument (inner_error);
+                               type_check.add_argument (new CCodeFunctionCall (new CCodeIdentifier ("%s_type_get".printf (error_class.get_lower_case_cname ()))));
+                               if (ccond == null) {
+                                       ccond = type_check;
+                               } else {
+                                       ccond = new CCodeBinaryExpression (CCodeBinaryOperator.OR, ccond, type_check);
+                               }
+                       }
+
+                       if (ccond == null) {
+                               cerror_handler = return_with_exception ();
+                       } else {
+                               var cerror_block = new CCodeBlock ();
+                               cerror_block.add_statement (new CCodeIfStatement (ccond,
+                                       return_with_exception (),
+                                       uncaught_error_statement (inner_error)));
+                               cerror_handler = cerror_block;
+                       }
+               } else {
+                       cerror_handler = uncaught_error_statement (inner_error);
+               }
+
+               if (always_fails) {
+                       // inner_error is always set, avoid unnecessary if statement
+                       // eliminates C warnings
+                       cfrag.append (cerror_handler);
+               } else {
+                       var ccond = new CCodeBinaryExpression (CCodeBinaryOperator.INEQUALITY, inner_error, new CCodeConstant ("NULL"));
+                       cfrag.append (new CCodeIfStatement (ccond, cerror_handler));
+               }
+       }
+
+       public override void visit_try_statement (TryStatement stmt) {
+               int this_try_id = next_try_id++;
+
+               var old_try = current_try;
+               var old_try_id = current_try_id;
+               var old_is_in_catch = is_in_catch;
+               current_try = stmt;
+               current_try_id = this_try_id;
+               is_in_catch = true;
+
+               foreach (CatchClause clause in stmt.get_catch_clauses ()) {
+                       clause.clabel_name = "__catch%d_%s".printf (this_try_id, clause.error_type.get_lower_case_cname ());
+               }
+
+               if (stmt.finally_body != null) {
+                       stmt.finally_body.accept (codegen);
+               }
+
+               is_in_catch = false;
+               stmt.body.accept (codegen);
+               is_in_catch = true;
+
+               foreach (CatchClause clause in stmt.get_catch_clauses ()) {
+                       clause.accept (codegen);
+               }
+
+               current_try = old_try;
+               current_try_id = old_try_id;
+               is_in_catch = old_is_in_catch;
+
+               var cfrag = new CCodeFragment ();
+               cfrag.append (stmt.body.ccodenode);
+
+               foreach (CatchClause clause in stmt.get_catch_clauses ()) {
+                       cfrag.append (new CCodeGotoStatement ("__finally%d".printf (this_try_id)));
+                       cfrag.append (clause.ccodenode);
+               }
+
+               cfrag.append (new CCodeLabel ("__finally%d".printf (this_try_id)));
+               if (stmt.finally_body != null) {
+                       cfrag.append (stmt.finally_body.ccodenode);
+               }
+
+               // check for errors not handled by this try statement
+               // may be handled by outer try statements or propagated
+               add_simple_check (stmt, cfrag, !stmt.after_try_block_reachable);
+
+               stmt.ccodenode = cfrag;
+       }
+
+       public override void visit_catch_clause (CatchClause clause) {
+               if (clause.error_variable != null) {
+                       clause.error_variable.active = true;
+               }
+
+               current_method_inner_error = true;
+
+               generate_type_declaration (clause.error_type, source_declarations);
+
+               clause.accept_children (codegen);
+
+               var cfrag = new CCodeFragment ();
+               cfrag.append (new CCodeLabel (clause.clabel_name));
+
+               var cblock = new CCodeBlock ();
+
+               string variable_name;
+               if (clause.variable_name != null) {
+                       variable_name = get_variable_cname (clause.variable_name);
+               } else {
+                       variable_name = "__err";
+               }
+
+               if (clause.variable_name != null) {
+                       var cdecl = new CCodeDeclaration (clause.error_type.get_cname ());
+                       cdecl.add_declarator (new CCodeVariableDeclarator (variable_name, get_variable_cexpression ("_inner_error_")));
+                       cblock.add_statement (cdecl);
+               } else {
+                       // error object is not used within catch statement, clear it
+                       var cclear = new CCodeFunctionCall (new CCodeIdentifier ("dova_object_unref"));
+                       cclear.add_argument (get_variable_cexpression ("_inner_error_"));
+                       cblock.add_statement (new CCodeExpressionStatement (cclear));
+               }
+               cblock.add_statement (new CCodeExpressionStatement (new CCodeAssignment (get_variable_cexpression ("_inner_error_"), new CCodeConstant ("NULL"))));
+
+               cblock.add_statement (clause.body.ccodenode);
+
+               cfrag.append (cblock);
+
+               clause.ccodenode = cfrag;
+       }
+
+       public override void append_local_free (Symbol sym, CCodeFragment cfrag, bool stop_at_loop = false) {
+               var finally_block = (Block) null;
+               if (sym.parent_node is TryStatement) {
+                       finally_block = (sym.parent_node as TryStatement).finally_body;
+               } else if (sym.parent_node is CatchClause) {
+                       finally_block = (sym.parent_node.parent_node as TryStatement).finally_body;
+               }
+
+               if (finally_block != null) {
+                       cfrag.append (finally_block.ccodenode);
+               }
+
+               base.append_local_free (sym, cfrag, stop_at_loop);
+       }
+}
+
+// vim:sw=8 noet
index aca95707128777d2110f98db1488476b19e9c271..53817ffad4a55a0aed5f9ac1815c8eab3b0681ad 100644 (file)
@@ -224,6 +224,13 @@ internal class Vala.DovaMethodCallModule : DovaAssignmentModule {
                        ccall_expr = ccomma;
                }
 
+               if (expr.tree_can_fail) {
+                       // method can fail
+                       current_method_inner_error = true;
+                       // add &inner_error before the ellipsis arguments
+                       ccall.add_argument (new CCodeUnaryExpression (CCodeUnaryOperator.ADDRESS_OF, get_variable_cexpression ("_inner_error_")));
+               }
+
                expr.ccodenode = ccall_expr;
        }
 }
index 276cbf58265415c27c5dbe16b12cdf9cc28b0a27..30eb4da2c6f19daa687c5e4fd3c675f1dcc856dc 100644 (file)
@@ -1060,6 +1060,8 @@ internal class Vala.DovaObjectModule : DovaArrayModule {
 
                m.accept_children (codegen);
 
+               bool inner_error = current_method_inner_error;
+
                current_symbol = old_symbol;
                current_method_inner_error = old_method_inner_error;
                next_temp_var_id = old_next_temp_var_id;
@@ -1125,6 +1127,12 @@ internal class Vala.DovaObjectModule : DovaArrayModule {
                                        function.block.add_statement (new CCodeReturnStatement (new CCodeIdentifier ("result")));
                                }
 
+                               if (inner_error) {
+                                       var cdecl = new CCodeDeclaration ("DovaError *");
+                                       cdecl.add_declarator (new CCodeVariableDeclarator ("_inner_error_", new CCodeConstant ("NULL")));
+                                       cinit.append (cdecl);
+                               }
+
                                var st = m.parent_symbol as Struct;
                                if (m is CreationMethod && st != null && (st.is_boolean_type () || st.is_integer_type () || st.is_floating_type ())) {
                                        var cdecl = new CCodeDeclaration (st.get_cname ());
@@ -1491,6 +1499,17 @@ internal class Vala.DovaObjectModule : DovaArrayModule {
 
                        generate_type_declaration (m.return_type, decl_space);
                }
+
+               if (m.get_error_types ().size > 0 || (m.base_method != null && m.base_method.get_error_types ().size > 0)) {
+                       var cparam = new CCodeFormalParameter ("error", "DovaError**");
+                       func.add_parameter (cparam);
+                       if (vdeclarator != null) {
+                               vdeclarator.add_parameter (cparam);
+                       }
+                       if (vcall != null) {
+                               vcall.add_argument (new CCodeIdentifier ("error"));
+                       }
+               }
        }
 
        public override void visit_element_access (ElementAccess expr) {
index 4ac98be3f0f0e2d1ade4b33965d61b053a1a3a60..efe71d0766759523f81da258afdccb994907a408 100644 (file)
@@ -124,7 +124,12 @@ public class Vala.CatchClause : CodeNode {
 
                        error_variable.checked = true;
                } else {
-                       error_type = new ErrorType (null, null, source_reference);
+                       // generic catch clause
+                       if (analyzer.context.profile == Profile.GOBJECT) {
+                               error_type = new ErrorType (null, null, source_reference);
+                       } else {
+                               error_type = analyzer.error_type;
+                       }
                }
 
                error_type.check (analyzer);
index d95ef5f668cf661326906ded7a1228ce749bcc42..37fc7ea472f33b48b0100bb674bf0b7bfc7fff05 100644 (file)
@@ -33,6 +33,7 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                public bool is_error_target { get; set; }
                public ErrorDomain? error_domain { get; set; }
                public ErrorCode? error_code { get; set; }
+               public Class? error_class { get; set; }
                public bool is_finally_clause { get; set; }
                public BasicBlock basic_block { get; set; }
                public BasicBlock? last_block { get; set; }
@@ -53,11 +54,12 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        is_return_target = true;
                }
 
-               public JumpTarget.error_target (BasicBlock basic_block, CatchClause catch_clause, ErrorDomain? error_domain, ErrorCode? error_code) {
+               public JumpTarget.error_target (BasicBlock basic_block, CatchClause catch_clause, ErrorDomain? error_domain, ErrorCode? error_code, Class? error_class) {
                        this.basic_block = basic_block;
                        this.catch_clause = catch_clause;
                        this.error_domain = error_domain;
                        this.error_code = error_code;
+                       this.error_class = error_class;
                        is_error_target = true;
                }
 
@@ -836,6 +838,7 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                        // exceptional control flow
                        foreach (DataType error_data_type in node.get_error_types()) {
                                var error_type = error_data_type as ErrorType;
+                               var error_class = error_data_type.data_type as Class;
                                current_block = last_block;
                                unreachable_reported = true;
 
@@ -847,20 +850,34 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                                                unreachable_reported = false;
                                                break;
                                        } else if (jump_target.is_error_target) {
-                                               if (jump_target.error_domain == null
-                                                   || (jump_target.error_domain == error_type.error_domain
-                                                       && (jump_target.error_code == null
-                                                           || jump_target.error_code == error_type.error_code))) {
+                                               if (context.profile == Profile.GOBJECT) {
+                                                       if (jump_target.error_domain == null
+                                                           || (jump_target.error_domain == error_type.error_domain
+                                                               && (jump_target.error_code == null
+                                                                   || jump_target.error_code == error_type.error_code))) {
+                                                               // error can always be caught by this catch clause
+                                                               // following catch clauses cannot be reached by this error
+                                                               current_block.connect (jump_target.basic_block);
+                                                               current_block = null;
+                                                               unreachable_reported = false;
+                                                               break;
+                                                       } else if (error_type.error_domain == null
+                                                                  || (error_type.error_domain == jump_target.error_domain
+                                                                      && (error_type.error_code == null
+                                                                          || error_type.error_code == jump_target.error_code))) {
+                                                               // error might be caught by this catch clause
+                                                               // unknown at compile time
+                                                               // following catch clauses might still be reached by this error
+                                                               current_block.connect (jump_target.basic_block);
+                                                       }
+                                               } else if (jump_target.error_class == null || jump_target.error_class == error_class) {
                                                        // error can always be caught by this catch clause
                                                        // following catch clauses cannot be reached by this error
                                                        current_block.connect (jump_target.basic_block);
                                                        current_block = null;
                                                        unreachable_reported = false;
                                                        break;
-                                               } else if (error_type.error_domain == null
-                                                          || (error_type.error_domain == jump_target.error_domain
-                                                              && (error_type.error_code == null
-                                                                  || error_type.error_code == jump_target.error_code))) {
+                                               } else if (jump_target.error_class.is_subtype_of (error_class)) {
                                                        // error might be caught by this catch clause
                                                        // unknown at compile time
                                                        // following catch clauses might still be reached by this error
@@ -934,10 +951,15 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                for (int i = catch_clauses.size - 1; i >= 0; i--) {
                        var catch_clause = catch_clauses[i];
                        if (catch_clause.error_type != null) {
-                               var error_type = catch_clause.error_type as ErrorType;
-                               jump_stack.add (new JumpTarget.error_target (new BasicBlock (), catch_clause, catch_clause.error_type.data_type as ErrorDomain, error_type.error_code));
+                               if (context.profile == Profile.GOBJECT) {
+                                       var error_type = catch_clause.error_type as ErrorType;
+                                       jump_stack.add (new JumpTarget.error_target (new BasicBlock (), catch_clause, catch_clause.error_type.data_type as ErrorDomain, error_type.error_code, null));
+                               } else {
+                                       var error_class = catch_clause.error_type.data_type as Class;
+                                       jump_stack.add (new JumpTarget.error_target (new BasicBlock (), catch_clause, null, null, error_class));
+                               }
                        } else {
-                               jump_stack.add (new JumpTarget.error_target (new BasicBlock (), catch_clause, null, null));
+                               jump_stack.add (new JumpTarget.error_target (new BasicBlock (), catch_clause, null, null, null));
                        }
                }
 
@@ -968,8 +990,14 @@ public class Vala.FlowAnalyzer : CodeVisitor {
                                        break;
                                }
 
-                               if (prev_target.error_domain == jump_target.error_domain &&
-                                 prev_target.error_code == jump_target.error_code) {
+                               if (context.profile == Profile.GOBJECT) {
+                                       if (prev_target.error_domain == jump_target.error_domain &&
+                                           prev_target.error_code == jump_target.error_code) {
+                                               Report.error (stmt.source_reference, "double catch clause of same error detected");
+                                               stmt.error = true;
+                                               return;
+                                       }
+                               } else if (prev_target.error_class == jump_target.error_class) {
                                        Report.error (stmt.source_reference, "double catch clause of same error detected");
                                        stmt.error = true;
                                        return;
index 36196385e0f73a3686ba4648c12ffc2d74554899..61a5aa1689daabc6e12d230f96d3cde1e770b4ff 100644 (file)
@@ -919,7 +919,8 @@ public class Vala.Method : Member {
                                                can_propagate_error = true;
                                        }
                                }
-                               if (!can_propagate_error && !((ErrorType) body_error_type).dynamic_error) {
+                               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()));
                                }
                        }
index 49817386bed3e59e733b73ffec22811c0a660740..70685dc5afa6cf26531683df9a9ecbf1c1d0ee4c 100644 (file)
@@ -155,6 +155,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
        public Class gerror_type;
        public DataType list_type;
        public DataType tuple_type;
+       public DataType error_type;
 
        public int next_lambda_id = 0;
 
@@ -224,6 +225,7 @@ public class Vala.SemanticAnalyzer : CodeVisitor {
                        type_type = new ObjectType ((Class) dova_ns.scope.lookup ("Type"));
                        list_type = new ObjectType ((Class) dova_ns.scope.lookup ("List"));
                        tuple_type = new ObjectType ((Class) dova_ns.scope.lookup ("Tuple"));
+                       error_type = new ObjectType ((Class) dova_ns.scope.lookup ("Error"));
                }
 
                current_symbol = root_symbol;
index 2a90ba37ea8ef0a1fb2d2fd969ec95e969bfa454..e3d5da9eb20da026785bc9765d475154b211d999 100644 (file)
@@ -1,6 +1,6 @@
 /* valathrowstatement.vala
  *
- * Copyright (C) 2007-2009  Jürg Billeter
+ * Copyright (C) 2007-2010  Jürg Billeter
  *
  * This library is free software; you can redistribute it and/or
  * modify it under the terms of the GNU Lesser General Public
@@ -94,7 +94,7 @@ public class Vala.ThrowStatement : CodeNode, Statement {
                                return false;
                        }
 
-                       if (!(error_expression.value_type is ErrorType)) {
+                       if (analyzer.context.profile == Profile.GOBJECT && !(error_expression.value_type is ErrorType)) {
                                Report.error (error_expression.source_reference, "`%s' is not an error type".printf (error_expression.value_type.to_string ()));
                                error = true;
                                return false;