@@ -257,6 +257,88 @@ public void testCompileLambdaCaptureLocalAndField() throws Exception {
257257 formatSource (samMethod .toSource ()));
258258 }
259259
260+ public void testCompileLambdaOuterFieldCaptureInConstructor () throws Exception {
261+ addSnippetClassDecl ("int y = 22;" );
262+ addSnippetClassDecl ("class Foo {" +
263+ "Foo(Runnable r) {}" +
264+ "Foo() {" +
265+ "this(() -> {y = 42;});" +
266+ "}" +
267+ "}" );
268+
269+ JProgram program = compileSnippet ("void" , "new Foo();" , false );
270+ JDeclaredType entrypointType = program .getFromTypeMap ("test.EntryPoint" );
271+
272+ JMethod lambda = findMethod (program .getFromTypeMap ("test.EntryPoint$Foo" ), "lambda$0" );
273+ assertNotNull (lambda );
274+ assertEquals ("{{this$0.y=42;}}" , formatSource (lambda .getBody ().toSource ()));
275+
276+ // Lambda closes over inner class's this$0 reference - lambda type constructor takes that
277+ // parameter and assigns to a field.
278+ JClassType lambdaInnerClass = (JClassType ) getType (program , "test.EntryPoint$Foo$lambda$0$Type" );
279+ assertNotNull (lambdaInnerClass );
280+
281+ JMethod ctor = findMethod (lambdaInnerClass , "EntryPoint$Foo$lambda$0$Type" );
282+ assertTrue (ctor instanceof JConstructor );
283+ System .out .println (ctor .getOriginalParamTypes ());
284+ assertEquals (1 , ctor .getParams ().size ());
285+ assertEquals (entrypointType , ctor .getOriginalParamTypes ().get (0 ));
286+
287+ assertEquals (1 , lambdaInnerClass .getFields ().size ());
288+ assertEquals (entrypointType , lambdaInnerClass .getFields ().get (0 ).getType ());
289+
290+ // interface impl passes this.this$0 to the actual lambda method as a parameter
291+ assertEquals ("{this.this$0=this$0;}" , formatSource (ctor .getBody ().toSource ()));
292+
293+ // abstract method implementation passes field to lambda method
294+ JMethod samMethod = findMethod (lambdaInnerClass , "run" );
295+ assertNotNull (samMethod );
296+ assertEquals ("{EntryPoint$Foo.lambda$0(this.this$0);}" , formatSource (samMethod .getBody ().toSource ()));
297+ }
298+
299+ public void testCompileLambdaOuterFieldCaptureInConstructorSuper () throws Exception {
300+ addSnippetClassDecl ("int y = 22;" );
301+ addSnippetClassDecl ("class Foo {" +
302+ "Foo(Runnable r) {}" +
303+ "}" +
304+ "class Bar extends Foo {" +
305+ "Bar() {" +
306+ "super(() -> {y = 42;});" +
307+ "}" +
308+ "}" );
309+
310+ JProgram program = compileSnippet ("void" , "new Bar();" , false );
311+ JDeclaredType entrypointType = program .getFromTypeMap ("test.EntryPoint" );
312+
313+ JMethod lambda = findMethod (program .getFromTypeMap ("test.EntryPoint$Bar" ), "lambda$0" );
314+ assertNotNull (lambda );
315+ assertEquals (1 , lambda .getParams ().size ());
316+ assertEquals (entrypointType , lambda .getOriginalParamTypes ().get (0 ));
317+ assertEquals ("{{this$0.y=42;}}" , formatSource (lambda .getBody ().toSource ()));
318+
319+ // Lambda closes over inner class's this$0 reference - lambda type constructor takes that
320+ // parameter and assigns to a field.
321+ JClassType lambdaInnerClass = (JClassType ) getType (program , "test.EntryPoint$Bar$lambda$0$Type" );
322+ assertNotNull (lambdaInnerClass );
323+
324+ JMethod ctor = findMethod (lambdaInnerClass , "EntryPoint$Bar$lambda$0$Type" );
325+ assertTrue (ctor instanceof JConstructor );
326+ System .out .println (ctor .getOriginalParamTypes ());
327+ assertEquals (1 , ctor .getParams ().size ());
328+ assertEquals (entrypointType , ctor .getOriginalParamTypes ().get (0 ));
329+
330+ assertEquals (1 , lambdaInnerClass .getFields ().size ());
331+ assertEquals (entrypointType , lambdaInnerClass .getFields ().get (0 ).getType ());
332+
333+ // interface impl passes this.this$0 to the actual lambda method as a parameter
334+ assertEquals ("{this.this$0=this$0;}" , formatSource (ctor .getBody ().toSource ()));
335+
336+ // abstract method implementation passes field to lambda method
337+ JMethod samMethod = findMethod (lambdaInnerClass , "run" );
338+ assertNotNull (samMethod );
339+ assertEquals ("{EntryPoint$Bar.lambda$0(this.this$0);}" , formatSource (samMethod .getBody ().toSource ()));
340+ }
341+
260342 // make sure nested scoping of identically named variables works
261343 public void testCompileLambdaCaptureOuterInnerField () throws Exception {
262344 addSnippetClassDecl ("private int y = 22;" );
0 commit comments