diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectTransformer.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectTransformer.java index ba713728a9f..c02e7fb142d 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectTransformer.java @@ -146,7 +146,8 @@ public class AnonymousObjectTransformer { ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); - extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, invocation); + List additionalFakeParams = + extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, invocation); InlineResult result = InlineResult.create(); for (MethodNode next : methodsToTransform) { @@ -156,7 +157,7 @@ public class AnonymousObjectTransformer { } InlineResult constructorResult = - generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, invocation, parentRemapper); + generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, invocation, parentRemapper, additionalFakeParams); result.addAllClassesToRemove(constructorResult); @@ -194,7 +195,8 @@ public class AnonymousObjectTransformer { @NotNull ParametersBuilder allCapturedBuilder, @NotNull ParametersBuilder constructorInlineBuilder, @NotNull ConstructorInvocation invocation, - @NotNull FieldRemapper parentRemapper + @NotNull FieldRemapper parentRemapper, + @NotNull List constructorAdditionalFakeParams ) { List descTypes = new ArrayList(); @@ -242,6 +244,23 @@ public class AnonymousObjectTransformer { } //then transform constructor + //HACK: in inlinining into constructor we access original captured fields with field access not local var + //but this fields added to general params (this assumes local var access) not captured one, + //so we need to add them to captured params + for (CapturedParamInfo info : constructorAdditionalFakeParams) { + CapturedParamInfo fake = constructorInlineBuilder.addCapturedParamCopy(info); + + if (fake.getLambda() != null) { + //set remap value to skip this fake (captured with lambda already skipped) + StackValue composed = StackValue.composed(StackValue.local(0, oldObjectType), + StackValue.field(fake.getType(), + oldObjectType, + fake.getNewFieldName(), false) + ); + fake.setRemapValue(composed); + } + } + Parameters constructorParameters = constructorInlineBuilder.buildParameters(); RegeneratedLambdaFieldRemapper remapper = @@ -291,7 +310,7 @@ public class AnonymousObjectTransformer { ); } - private void extractParametersMappingAndPatchConstructor( + private List extractParametersMappingAndPatchConstructor( @NotNull MethodNode constructor, @NotNull ParametersBuilder capturedParamBuilder, @NotNull ParametersBuilder constructorParamBuilder, @@ -306,7 +325,7 @@ public class AnonymousObjectTransformer { }; List capturedLambdas = new ArrayList(); //captured var of inlined parameter - List capturedToInline = new ArrayList(); + List constructorAdditionalFakeParams = new ArrayList(); Map indexToLambda = invocation.getLambdasToInline(); Set capturedParams = new HashSet(); @@ -330,8 +349,8 @@ public class AnonymousObjectTransformer { if (lambdaInfo != null) { info.setLambda(lambdaInfo); capturedLambdas.add(lambdaInfo); - capturedToInline.add(info); } + constructorAdditionalFakeParams.add(info); capturedParams.add(varIndex); constructor.instructions.remove(previous.getPrevious()); @@ -381,14 +400,12 @@ public class AnonymousObjectTransformer { capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info); } - //HACK: in inlinining into constructor we access inlined lambda with field access not local var but this lambda added no general params not captured one, - //so we need to add them to captured params - for (CapturedParamInfo info : capturedToInline) { - constructorParamBuilder.addCapturedParamCopy(info); - } + invocation.setAllRecapturedParameters(allRecapturedParameters); invocation.setCapturedLambdasToInline(capturedLambdasToInline); + + return constructorAdditionalFakeParams; } @NotNull diff --git a/compiler/testData/codegen/boxInline/anonymousObjectOnCallSite/1.kt b/compiler/testData/codegen/boxInline/anonymousObjectOnCallSite/1.kt index d99a9080e83..277fbf785a9 100644 --- a/compiler/testData/codegen/boxInline/anonymousObjectOnCallSite/1.kt +++ b/compiler/testData/codegen/boxInline/anonymousObjectOnCallSite/1.kt @@ -2,9 +2,13 @@ import test.* fun box() : String { val o = "O" - return doWork { + val p = "GOOD" + val result = doWork { val k = "K" val s = object : A() { + + val param = p; + override fun getO(): String { return o; } @@ -14,7 +18,11 @@ fun box() : String { } } - s.getO() + s.getK() + s.getO() + s.getK() + s.param } + + if (result != "OKGOOD") return "fail $result" + + return "OK" } diff --git a/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/1.kt b/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/1.kt index 901a56aaab4..0b2754c9115 100644 --- a/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/1.kt +++ b/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/1.kt @@ -3,9 +3,9 @@ import test.* fun test1(): String { val o = "O" - val result = doWork ({o}, {"K"}) + val result = doWork ({o}, {"K"}, "GOOD") - return result.getO() + result.getK() + return result.getO() + result.getK() + result.getParam() } fun test2() : String { @@ -13,17 +13,17 @@ fun test2() : String { val o1 = "O" val k1 = "K" - val result = doWorkInConstructor ({o1}, {k1}) + val result = doWorkInConstructor ({o1}, {k1}, "GOOD") - return result.getO() + result.getK() + return result.getO() + result.getK() + result.getParam() } fun box() : String { val result1 = test1(); - if (result1 != "OK") return "fail1 $result1" + if (result1 != "OKGOOD") return "fail1 $result1" val result2 = test2(); - if (result2 != "OK") return "fail2 $result2" + if (result2 != "OKGOOD") return "fail2 $result2" return "OK" } diff --git a/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/2.kt b/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/2.kt index ea41a21fac8..9a811742b29 100644 --- a/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/2.kt +++ b/compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite/2.kt @@ -4,9 +4,11 @@ abstract class A { abstract fun getO() : R abstract fun getK() : R + + abstract fun getParam() : R } -inline fun doWork(jobO: ()-> R, jobK: ()-> R) : A { +inline fun doWork(jobO: ()-> R, jobK: ()-> R, param: R) : A { val s = object : A() { override fun getO(): R { @@ -15,12 +17,19 @@ inline fun doWork(jobO: ()-> R, jobK: ()-> R) : A { override fun getK(): R { return jobK() } + + override fun getParam(): R { + return param + } } return s; } -inline fun doWorkInConstructor(jobO: ()-> R, jobK: ()-> R) : A { +inline fun doWorkInConstructor(jobO: ()-> R, jobK: ()-> R, param: R) : A { val s = object : A() { + + val p = param; + val o1 = jobO() val k1 = jobK() @@ -31,6 +40,10 @@ inline fun doWorkInConstructor(jobO: ()-> R, jobK: ()-> R) : A { override fun getK(): R { return k1 } + + override fun getParam(): R { + return p + } } return s; } \ No newline at end of file