From: Simon Werbeck Date: Wed, 26 Nov 2014 13:08:41 +0000 (+0100) Subject: Allow 'static' lambdas before chainup X-Git-Url: http://git.ipfire.org/cgi-bin/gitweb.cgi?a=commitdiff_plain;h=f5a4f20e12b3cecc87ffb3e4e4a42e1cfb192e88;p=thirdparty%2Fvala.git 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 --- diff --git a/codegen/valaccodebasemodule.vala b/codegen/valaccodebasemodule.vala index d93db9c19..4fd0105fa 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 718601fc3..ab30ae345 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 000000000..6f5c1d0be --- /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 6d0264e2c..737b79d74 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) 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 85f8bbb63..3bc9eb13b 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 (); }