[vala/wip/bug567269: 2/5] Allow multiple chain-up calls in the constructor



commit 7b06c4cc003b75b2e847ba12909cbb64e5e1c13b
Author: Simon Werbeck <simon werbeck gmail com>
Date:   Thu Nov 27 15:24:44 2014 +0100

    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

 tests/Makefile.am                 |    1 +
 tests/chainup/class-multiple.vala |   49 +++++++++++++++++++++++++++++++++++++
 vala/valaflowanalyzer.vala        |   21 +++++++++++++--
 vala/valamethodcall.vala          |    4 ---
 4 files changed, 68 insertions(+), 7 deletions(-)
---
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 7225478..718601f 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 0000000..3781f31
--- /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 853eae7..e073c4c 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<Symbol, List<Variable>> var_map, Variable var_symbol) {
+       Variable process_assignment (Map<Symbol, List<Variable>> var_map, Variable var_symbol, CodeNode 
node_reference) {
                var variable_stack = var_map.get (var_symbol);
                if (variable_stack == null) {
                        variable_stack = new ArrayList<Variable> ();
@@ -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 415191a..2b43ec8 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;
 


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