[vala] dova: Add initial support for error handling
- From: Jürg Billeter <juergbi src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [vala] dova: Add initial support for error handling
- Date: Tue, 8 Jun 2010 07:51:03 +0000 (UTC)
commit 31cb78817cb9cc87c18f0d9b12e6a4efa4ec5222
Author: Jürg Billeter <j bitron ch>
Date: Sat Feb 6 14:25:41 2010 +0100
dova: Add initial support for error handling
codegen/Makefile.am | 1 +
codegen/valaccodegenerator.vala | 3 +-
codegen/valadovabasemodule.vala | 2 +
codegen/valadovaerrormodule.vala | 343 +++++++++++++++++++++++++++++++++
codegen/valadovamethodcallmodule.vala | 7 +
codegen/valadovaobjectmodule.vala | 19 ++
vala/valacatchclause.vala | 7 +-
vala/valaflowanalyzer.vala | 56 ++++--
vala/valamethod.vala | 3 +-
vala/valasemanticanalyzer.vala | 2 +
vala/valathrowstatement.vala | 4 +-
11 files changed, 428 insertions(+), 19 deletions(-)
---
diff --git a/codegen/Makefile.am b/codegen/Makefile.am
index c62b6f6..7581eb6 100644
--- a/codegen/Makefile.am
+++ b/codegen/Makefile.am
@@ -39,6 +39,7 @@ libvala_la_VALASOURCES = \
valadovabasemodule.vala \
valadovacontrolflowmodule.vala \
valadovadelegatemodule.vala \
+ valadovaerrormodule.vala \
valadovamemberaccessmodule.vala \
valadovamethodcallmodule.vala \
valadovamethodmodule.vala \
diff --git a/codegen/valaccodegenerator.vala b/codegen/valaccodegenerator.vala
index e2155cf..b32ba3c 100644
--- a/codegen/valaccodegenerator.vala
+++ b/codegen/valaccodegenerator.vala
@@ -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);
diff --git a/codegen/valadovabasemodule.vala b/codegen/valadovabasemodule.vala
index f58a525..01c3fb7 100644
--- a/codegen/valadovabasemodule.vala
+++ b/codegen/valadovabasemodule.vala
@@ -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
index 0000000..9da609a
--- /dev/null
+++ b/codegen/valadovaerrormodule.vala
@@ -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
diff --git a/codegen/valadovamethodcallmodule.vala b/codegen/valadovamethodcallmodule.vala
index aca9570..53817ff 100644
--- a/codegen/valadovamethodcallmodule.vala
+++ b/codegen/valadovamethodcallmodule.vala
@@ -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;
}
}
diff --git a/codegen/valadovaobjectmodule.vala b/codegen/valadovaobjectmodule.vala
index 276cbf5..30eb4da 100644
--- a/codegen/valadovaobjectmodule.vala
+++ b/codegen/valadovaobjectmodule.vala
@@ -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) {
diff --git a/vala/valacatchclause.vala b/vala/valacatchclause.vala
index 4ac98be..efe71d0 100644
--- a/vala/valacatchclause.vala
+++ b/vala/valacatchclause.vala
@@ -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);
diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala
index d95ef5f..37fc7ea 100644
--- a/vala/valaflowanalyzer.vala
+++ b/vala/valaflowanalyzer.vala
@@ -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;
diff --git a/vala/valamethod.vala b/vala/valamethod.vala
index 3619638..61a5aa1 100644
--- a/vala/valamethod.vala
+++ b/vala/valamethod.vala
@@ -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()));
}
}
diff --git a/vala/valasemanticanalyzer.vala b/vala/valasemanticanalyzer.vala
index 4981738..70685dc 100644
--- a/vala/valasemanticanalyzer.vala
+++ b/vala/valasemanticanalyzer.vala
@@ -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;
diff --git a/vala/valathrowstatement.vala b/vala/valathrowstatement.vala
index 2a90ba3..e3d5da9 100644
--- a/vala/valathrowstatement.vala
+++ b/vala/valathrowstatement.vala
@@ -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;
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]