From: Simon Werbeck Date: Thu, 27 Nov 2014 14:24:44 +0000 (+0100) Subject: Allow multiple chain-up calls in the constructor X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=7b06c4cc003b75b2e847ba12909cbb64e5e1c13b;p=thirdparty%2Fvala.git Allow multiple chain-up calls in the constructor This requires that the instance parameter is initialized at the end of the constructor. Another issue is the possibility of initializing 'this' more than once, so I added a warning when this is the case. https://bugzilla.gnome.org/show_bug.cgi?id=567269 --- diff --git a/tests/Makefile.am b/tests/Makefile.am index 722547848..718601fc3 100644 --- a/tests/Makefile.am +++ b/tests/Makefile.am @@ -58,6 +58,7 @@ TESTS = \ chainup/base-struct-invalid.test \ chainup/class-base.vala \ chainup/class-base-foo.vala \ + chainup/class-multiple.vala \ chainup/class-object.vala \ chainup/class-this.vala \ chainup/class-this-foo.vala \ diff --git a/tests/chainup/class-multiple.vala b/tests/chainup/class-multiple.vala new file mode 100644 index 000000000..3781f3101 --- /dev/null +++ b/tests/chainup/class-multiple.vala @@ -0,0 +1,49 @@ +public class Foo { + public bool success; + + Foo.first () { + success = true; + } + + Foo.second () { + assert_not_reached (); + } + + public Foo (bool cond) { + if (cond) { + this.first (); + } else { + this.second (); + } + } +} + +public class Bar { + public bool success; + + public Bar.first () { + success = true; + } + + public Bar.second () { + assert_not_reached (); + } +} + +public class Baz : Bar { + public Baz (bool cond) { + if (cond) { + base.first (); + } else { + base.second (); + } + } +} + +void main () { + var foo = new Foo (true); + assert (foo.success); + + var baz = new Baz (true); + assert (baz.success); +} diff --git a/vala/valaflowanalyzer.vala b/vala/valaflowanalyzer.vala index 853eae73d..e073c4c21 100644 --- a/vala/valaflowanalyzer.vala +++ b/vala/valaflowanalyzer.vala @@ -207,6 +207,16 @@ public class Vala.FlowAnalyzer : CodeVisitor { m.return_block.add_node (param_ma); } } + + // ensure instance parameter is defined at end of creation method + if (m is CreationMethod) { + var cm = (CreationMethod) m; + if (cm.chain_up) { + var this_ma = new MemberAccess.simple ("this"); + this_ma.symbol_reference = cm.this_parameter; + m.return_block.add_node (this_ma); + } + } } current_block = new BasicBlock (); @@ -435,7 +445,7 @@ public class Vala.FlowAnalyzer : CodeVisitor { void check_block_variables (BasicBlock block) { foreach (PhiFunction phi in block.get_phi_functions ()) { - Variable versioned_var = process_assignment (var_map, phi.original_variable); + Variable versioned_var = process_assignment (var_map, phi.original_variable, phi.original_variable.parent_symbol); phi_functions.set (versioned_var, phi); } @@ -466,7 +476,7 @@ public class Vala.FlowAnalyzer : CodeVisitor { node.get_defined_variables (defined_variables); foreach (Variable variable in defined_variables) { - process_assignment (var_map, variable); + process_assignment (var_map, variable, node); } } @@ -506,7 +516,7 @@ public class Vala.FlowAnalyzer : CodeVisitor { } } - Variable process_assignment (Map> var_map, Variable var_symbol) { + Variable process_assignment (Map> var_map, Variable var_symbol, CodeNode node_reference) { var variable_stack = var_map.get (var_symbol); if (variable_stack == null) { variable_stack = new ArrayList (); @@ -519,6 +529,11 @@ public class Vala.FlowAnalyzer : CodeVisitor { if (var_symbol is LocalVariable) { versioned_var = new LocalVariable (var_symbol.variable_type.copy (), var_symbol.name, null, var_symbol.source_reference); } else { + if (var_symbol.name == "this" && var_symbol.parent_symbol is CreationMethod && ((CreationMethod) var_symbol.parent_symbol).chain_up) { + if (variable_stack.size > 0) { + Report.warning (node_reference.source_reference, "possible reassignment of `this'"); + } + } // parameter versioned_var = new Parameter (var_symbol.name, var_symbol.variable_type.copy (), var_symbol.source_reference); } diff --git a/vala/valamethodcall.vala b/vala/valamethodcall.vala index 415191ab6..2b43ec842 100644 --- a/vala/valamethodcall.vala +++ b/vala/valamethodcall.vala @@ -238,10 +238,6 @@ public class Vala.MethodCall : Expression { error = true; Report.error (source_reference, "invocation not supported in this context"); return false; - } else if (cm.chain_up) { - error = true; - Report.error (source_reference, "Multiple constructor calls in the same constructor are not permitted"); - return false; } cm.chain_up = true;