Capture enclosing instance of a lambda

- ECj can tell to Jack to not capture the enclosing instance of a lambda
 when it is needed. Thus, we force to capture the enclosing instance of a
lambda when a creation of an object need this enclosing instance as parameter
of its constructor

Bug: 27330340
Bug: 27301904
Change-Id: I137e9395b1f0a30562474d79338d84b8b94b24bf
diff --git a/jack-tests/tests/com/android/jack/java8/LambdaTest.java b/jack-tests/tests/com/android/jack/java8/LambdaTest.java
index 2700d71..c7fa480 100644
--- a/jack-tests/tests/com/android/jack/java8/LambdaTest.java
+++ b/jack-tests/tests/com/android/jack/java8/LambdaTest.java
@@ -192,6 +192,10 @@
       AbstractTestTools.getTestRootDir("com.android.jack.java8.lambda.test035"),
       "com.android.jack.java8.lambda.test035.jack.Tests");
 
+  private RuntimeTestInfo LAMBDA036 = new RuntimeTestInfo(
+      AbstractTestTools.getTestRootDir("com.android.jack.java8.lambda.test036"),
+      "com.android.jack.java8.lambda.test036.jack.Tests");
+
   @Test
   public void testLamba001() throws Exception {
     run(LAMBDA001);
@@ -405,6 +409,11 @@
     run(LAMBDA035);
   }
 
+  @Test
+  public void testLamba036() throws Exception {
+    run(LAMBDA036);
+  }
+
   private void run(@Nonnull RuntimeTestInfo rti) throws Exception {
     new RuntimeTestHelper(rti)
         .setSourceLevel(SourceLevel.JAVA_8)
diff --git a/jack-tests/tests/com/android/jack/java8/lambda/test036/jack/Tests.java b/jack-tests/tests/com/android/jack/java8/lambda/test036/jack/Tests.java
new file mode 100644
index 0000000..fb44e51
--- /dev/null
+++ b/jack-tests/tests/com/android/jack/java8/lambda/test036/jack/Tests.java
@@ -0,0 +1,48 @@
+/*
+ * Copyright (C) 2016 The Android Open Source Project
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *      http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+package com.android.jack.java8.lambda.test036.jack;
+
+import org.junit.Assert;
+import org.junit.Test;
+
+import java.util.ArrayList;
+import java.util.List;
+
+interface I {
+  int getLength();
+}
+
+/**
+ * Test that trigger a bug where enclosing instance of a lambda expression is not captured.
+ */
+public class Tests {
+
+  @Test
+  public void test() {
+    class A<T> {
+      List<T> l;
+
+      public A(List<T> l) {
+        this.l = l;
+      }
+    }
+
+    List<Integer> list = new ArrayList<>();
+    I i = () -> new A<>(list).l.size();
+    Assert.assertEquals(0, i.getLength());
+  }
+}
diff --git a/jack/src/com/android/jack/ir/impl/JackIrBuilder.java b/jack/src/com/android/jack/ir/impl/JackIrBuilder.java
index 44e1d9f..b269071 100644
--- a/jack/src/com/android/jack/ir/impl/JackIrBuilder.java
+++ b/jack/src/com/android/jack/ir/impl/JackIrBuilder.java
@@ -1726,6 +1726,8 @@
         }
       }
 
+      boolean shouldCaptureInstance =
+          lambdaExpression.shouldCaptureInstance | curMethod.forceCaptureOfThis;
       // Do not move before generateImplicitReturn since the method need the method where return
       // must be added
       popMethodInfo();
@@ -1735,7 +1737,7 @@
           getJMethodIdWithReturnType(lambdaExpression.descriptor.original()),
           lambdaMethodInfo.method,
           (JDefinedInterface) getTypeMap().get(getLambdaType(lambdaExpression, blockScope)),
-          lambdaExpression.shouldCaptureInstance, getInterfaceBounds(lambdaExpression, blockScope));
+          shouldCaptureInstance, getInterfaceBounds(lambdaExpression, blockScope));
       lambda.addBridgeMethodIds(getBridges(lambdaExpression));
 
       // Capture all local variable that are not already moved into fields
@@ -3433,6 +3435,7 @@
               JMultiExpression multiExpr = new JMultiExpression(info, exprs);
               call.addArg(multiExpr);
             } else {
+              curMethod.forceCaptureOfThis = true;
               // check supplementary error
               getEmulationPath(scope, argType, false /* onlyExactMatch */,
                   true /* denyEnclosingArgInConstructorCall */, x);
@@ -3695,6 +3698,7 @@
     public final MethodScope scope;
     @Nonnull
     private final AstVisitor ast;
+    private boolean forceCaptureOfThis;
 
     public MethodInfo(@Nonnull AstVisitor ast, @Nonnull JMethod method,
         @CheckForNull JMethodBody methodBody, @CheckForNull MethodScope methodScope) {