[vala/wip/bug567269: 5/5] Allow 'static' lambdas before chainup



commit a305cc3e2f81f344a6a6dad2340efed4a0569b1b
Author: Simon Werbeck <simon werbeck gmail com>
Date:   Wed Nov 26 14:08:41 2014 +0100

    Allow 'static' lambdas before chainup
    
    If a lambda expression does not use its instance parameter, it is safe
    to use before a chainup expression. To make this work, usage of 'this'
    has to be tracked and the code generator needs to make use of this
    information.
    
    https://bugzilla.gnome.org/show_bug.cgi?id=567269

 codegen/valaccodebasemodule.vala     |    2 +-
 tests/Makefile.am                    |    1 +
 tests/chainup/class-with-lambda.vala |   22 ++++++++++++++++++++++
 vala/valalambdaexpression.vala       |   13 ++++++++++++-
 vala/valamemberaccess.vala           |   24 ++++++++++++++++++++++++
 5 files changed, 60 insertions(+), 2 deletions(-)
---
diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala
index d93db9c..4fd0105 100644
--- a/codegen/valaccodebasemodule.vala
+++ b/codegen/valaccodebasemodule.vala
@@ -5634,7 +5634,7 @@ public abstract class Vala.CCodeBaseModule : CodeGenerator {
                                set_delegate_target_destroy_notify (lambda, new CCodeConstant ("NULL"));
                        }
                        set_delegate_target (lambda, delegate_target);
-               } else if (get_this_type () != null) {
+               } else if (lambda.method.binding == MemberBinding.INSTANCE && get_this_type () != null) {
                        CCodeExpression delegate_target = get_result_cexpression ("self");
                        delegate_target = convert_to_generic_pointer (delegate_target, get_this_type ());
                        if (expr_owned || delegate_type.is_called_once) {
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 718601f..ab30ae3 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -62,6 +62,7 @@ TESTS = \
        chainup/class-object.vala \
        chainup/class-this.vala \
        chainup/class-this-foo.vala \
+       chainup/class-with-lambda.vala \
        chainup/method-lambda-base.vala \
        chainup/no-chainup.vala \
        chainup/struct-base.vala \
diff --git a/tests/chainup/class-with-lambda.vala b/tests/chainup/class-with-lambda.vala
new file mode 100644
index 0000000..6f5c1d0
--- /dev/null
+++ b/tests/chainup/class-with-lambda.vala
@@ -0,0 +1,22 @@
+public class Foo : Object {
+       public Foo.lambda_after () {
+               this ();
+               SourceFunc f = () => this != null;
+               assert (f ());
+       }
+
+       public Foo.lambda_before () {
+               SourceFunc f = () => {
+                       SourceFunc g = () => true;
+                       return g ();
+               };
+               this ();
+               assert (f ());
+       }
+}
+
+void main () {
+       Foo foo;
+       foo = new Foo.lambda_after ();
+       foo = new Foo.lambda_before ();
+}
diff --git a/vala/valalambdaexpression.vala b/vala/valalambdaexpression.vala
index 6d0264e..737b79d 100644
--- a/vala/valalambdaexpression.vala
+++ b/vala/valalambdaexpression.vala
@@ -239,6 +239,17 @@ public class Vala.LambdaExpression : Expression {
 
                method.check (context);
 
+               if (in_creation_method && method.this_parameter != null) {
+                       if (!method.this_parameter.used) {
+                               method.scope.remove ("this");
+                               method.this_parameter = null;
+                               method.binding = MemberBinding.STATIC;
+                       } else if (m != null && m.this_parameter != null) {
+                               // track usage inside nested lambda expressions
+                               m.this_parameter.used |= method.this_parameter.used;
+                       }
+               }
+
                value_type = new MethodType (method);
                value_type.value_owned = target_type.value_owned;
 
@@ -256,7 +267,7 @@ public class Vala.LambdaExpression : Expression {
                if (method.closure) {
                        method.get_captured_variables ((Collection<LocalVariable>) collection);
                }
-               if (in_creation_method) {
+               if (in_creation_method && method.this_parameter != null && method.this_parameter.used) {
                        Symbol sym = (Block) parent_statement.parent_node;
                        do {
                                sym = sym.parent_symbol;
diff --git a/vala/valamemberaccess.vala b/vala/valamemberaccess.vala
index b445ecb..4fac98a 100644
--- a/vala/valamemberaccess.vala
+++ b/vala/valamemberaccess.vala
@@ -281,6 +281,7 @@ public class Vala.MemberAccess : Expression {
                                                inner.value_type = this_parameter.variable_type.copy ();
                                                inner.value_type.value_owned = false;
                                                inner.symbol_reference = this_parameter;
+                                               inner.symbol_reference.used = true;
 
                                                symbol_reference = inner.value_type.get_member (member_name);
                                        }
@@ -508,6 +509,17 @@ public class Vala.MemberAccess : Expression {
                                local.captured = true;
                                block.captured = true;
                        }
+
+                       // track usage of instance parameter for flow analysis.
+                       // When accessing generic type information, instance access
+                       // is needed to copy/destroy generic values.
+                       var generic_type = local.variable_type as GenericType;
+                       if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
+                               var m = context.analyzer.current_method_or_property_accessor as Method;
+                               if (m != null && m.binding == MemberBinding.INSTANCE) {
+                                       m.this_parameter.used = true;
+                               }
+                       }
                } else if (member is Parameter) {
                        var param = (Parameter) member;
                        var m = param.parent_symbol as Method;
@@ -548,6 +560,17 @@ public class Vala.MemberAccess : Expression {
                                        acc.body.captured = true;
                                }
                        }
+
+                       // track usage of instance parameter for flow analysis.
+                       // When accessing generic type information, instance access
+                       // is needed to copy/destroy generic values.
+                       var generic_type = param.variable_type as GenericType;
+                       if (generic_type != null && generic_type.type_parameter.parent_symbol is TypeSymbol) {
+                               m = context.analyzer.current_method_or_property_accessor as Method;
+                               if (m != null && m.binding == MemberBinding.INSTANCE) {
+                                       m.this_parameter.used = true;
+                               }
+                       }
                } else if (member is Field) {
                        var f = (Field) member;
                        access = f.access;
@@ -796,6 +819,7 @@ public class Vala.MemberAccess : Expression {
                                inner.value_type = this_parameter.variable_type.copy ();
                                inner.value_type.value_owned = false;
                                inner.symbol_reference = this_parameter;
+                               inner.symbol_reference.used = true;
                        } else {
                                check_lvalue_access ();
                        }


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