From 21699e17530db4b98ebcd65f7d0ac111b72609fe Mon Sep 17 00:00:00 2001 From: Denis Zharkov Date: Mon, 13 Oct 2014 19:01:41 +0400 Subject: [PATCH] Supported reification for anonymous objects and lambdas --- ...on.java => AnonymousObjectGeneration.java} | 49 ++++-- .../inline/AnonymousObjectTransformer.java | 59 +++++--- .../jet/codegen/inline/InlineCodegen.java | 2 +- .../jet/codegen/inline/InlineCodegenUtil.java | 4 + .../jet/codegen/inline/InlineResult.java | 9 ++ .../jet/codegen/inline/InliningContext.java | 11 +- .../jet/codegen/inline/MethodInliner.java | 141 +++++++++++++----- .../codegen/inline/RegenetedClassContext.java | 11 +- .../codegen/inline/RootInliningContext.java | 5 +- .../localFunInLambda/definedWithinLambda.kt | 14 ++ .../definedWithinLambdaInnerUsage1.kt | 14 ++ .../definedWithinLambdaInnerUsage2.kt | 15 ++ .../boxWithStdlib/localFunInLambda/simple.kt | 13 ++ .../boxWithStdlib/reified/anonymousObject.kt | 19 +++ .../anonymousObjectReifiedSupertype.kt | 20 +++ .../reified/innerAnonymousObject.kt | 27 ++++ .../nonInlineableLambdaInReifiedFunction.kt | 17 +++ .../reified/recursiveInnerAnonymousObject.kt | 35 +++++ .../reified/recursiveNonInlineableLambda.kt | 22 +++ ...lackBoxWithStdlibCodegenTestGenerated.java | 71 ++++++++- 20 files changed, 476 insertions(+), 82 deletions(-) rename compiler/backend/src/org/jetbrains/jet/codegen/inline/{ConstructorInvocation.java => AnonymousObjectGeneration.java} (65%) create mode 100644 compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambda.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage1.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage2.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/localFunInLambda/simple.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reified/anonymousObject.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reified/innerAnonymousObject.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reified/nonInlineableLambdaInReifiedFunction.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reified/recursiveInnerAnonymousObject.kt create mode 100644 compiler/testData/codegen/boxWithStdlib/reified/recursiveNonInlineableLambda.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectGeneration.java similarity index 65% rename from compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java rename to compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectGeneration.java index 71fb72cbd85..8fa4f665dc8 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/ConstructorInvocation.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectGeneration.java @@ -17,16 +17,18 @@ package org.jetbrains.jet.codegen.inline; import org.jetbrains.annotations.NotNull; +import org.jetbrains.annotations.Nullable; import org.jetbrains.org.objectweb.asm.Type; +import java.util.HashMap; import java.util.List; import java.util.Map; -public class ConstructorInvocation { +public class AnonymousObjectGeneration { private final String ownerInternalName; - private final String desc; + private final String constructorDesc; private final Map lambdasToInline; @@ -41,19 +43,39 @@ public class ConstructorInvocation { private Map capturedLambdasToInline; private final boolean capturedOuterRegenerated; + private final boolean needReification; + private final boolean alreadyRegenerated; + private final boolean isStaticOrigin; - ConstructorInvocation( + AnonymousObjectGeneration( @NotNull String ownerInternalName, - @NotNull String desc, - @NotNull Map lambdasToInline, + boolean needReification, boolean isSameModule, - boolean capturedOuterRegenerated + @NotNull Map lambdasToInline, + boolean capturedOuterRegenerated, + boolean alreadyRegenerated, + @Nullable String constructorDesc, + boolean isStaticOrigin ) { this.ownerInternalName = ownerInternalName; - this.desc = desc; + this.constructorDesc = constructorDesc; this.lambdasToInline = lambdasToInline; this.isSameModule = isSameModule; this.capturedOuterRegenerated = capturedOuterRegenerated; + this.needReification = needReification; + this.alreadyRegenerated = alreadyRegenerated; + this.isStaticOrigin = isStaticOrigin; + } + + public AnonymousObjectGeneration( + @NotNull String ownerInternalName, boolean isSameModule, boolean needReification, + boolean alreadyRegenerated, + boolean isStaticOrigin + ) { + this( + ownerInternalName, isSameModule, needReification, + new HashMap(), false, alreadyRegenerated, null, isStaticOrigin + ); } public String getOwnerInternalName() { @@ -61,7 +83,9 @@ public class ConstructorInvocation { } public boolean shouldRegenerate() { - return !lambdasToInline.isEmpty() || !isSameModule || capturedOuterRegenerated; + return !alreadyRegenerated && ( + !lambdasToInline.isEmpty() || !isSameModule || capturedOuterRegenerated || needReification + ); } public Map getLambdasToInline() { @@ -100,7 +124,12 @@ public class ConstructorInvocation { this.capturedLambdasToInline = capturedLambdasToInline; } - public String getDesc() { - return desc; + @Nullable + public String getConstructorDesc() { + return constructorDesc; + } + + public boolean isStaticOrigin() { + return isStaticOrigin; } } 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 71e19c9bca0..da772498533 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectTransformer.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/AnonymousObjectTransformer.java @@ -79,10 +79,21 @@ public class AnonymousObjectTransformer { } @NotNull - public InlineResult doTransform(@NotNull ConstructorInvocation invocation, @NotNull FieldRemapper parentRemapper) { + public InlineResult doTransform(@NotNull final AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper) { ClassBuilder classBuilder = createClassBuilder(); final List methodsToTransform = new ArrayList(); + + final InlineResult result = InlineResult.create(); reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { + @Override + public void visit(int version, int access, @NotNull String name, String signature, String superName, String[] interfaces) { + if (signature != null) { + ReifiedTypeInliner.SignatureReificationResult signatureResult = inliningContext.reifedTypeInliner.reifySignature(signature); + signature = signatureResult.getNewSignature(); + result.markAsNeededFurtherReificationIf(signatureResult.getNeedFurtherReification()); + } + super.visit(version, access, name, signature, superName, interfaces); + } @Override public void visitOuterClass(@NotNull String owner, String name, String desc) { @@ -131,46 +142,47 @@ public class AnonymousObjectTransformer { ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder(); ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder(); List additionalFakeParams = - extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, invocation); + extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen); - InlineResult result = InlineResult.create(); for (MethodNode next : methodsToTransform) { MethodVisitor visitor = newMethod(classBuilder, next); - InlineResult funResult = inlineMethod(invocation, parentRemapper, visitor, next, allCapturedParamBuilder); + InlineResult funResult = inlineMethod(anonymousObjectGen, parentRemapper, visitor, next, allCapturedParamBuilder); result.addAllClassesToRemove(funResult); + result.markAsNeededFurtherReificationIf(funResult.needFurtherReification()); } InlineResult constructorResult = - generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, invocation, parentRemapper, additionalFakeParams); + generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, anonymousObjectGen, parentRemapper, additionalFakeParams); result.addAllClassesToRemove(constructorResult); classBuilder.done(); - invocation.setNewLambdaType(newLambdaType); + anonymousObjectGen.setNewLambdaType(newLambdaType); return result; } @NotNull private InlineResult inlineMethod( - @NotNull ConstructorInvocation invocation, + @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper, @NotNull MethodVisitor resultVisitor, @NotNull MethodNode sourceNode, @NotNull ParametersBuilder capturedBuilder ) { - + boolean neededFurtherReification = inliningContext.reifedTypeInliner.reifyInstructions(sourceNode.instructions); Parameters parameters = getMethodParametersWithCaptured(capturedBuilder, sourceNode); RegeneratedLambdaFieldRemapper remapper = new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(), - parameters, invocation.getCapturedLambdasToInline(), + parameters, anonymousObjectGen.getCapturedLambdasToInline(), parentRemapper); MethodInliner inliner = new MethodInliner(sourceNode, parameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), - remapper, isSameModule, "Transformer for " + invocation.getOwnerInternalName()); + remapper, isSameModule, "Transformer for " + anonymousObjectGen.getOwnerInternalName()); InlineResult result = inliner.doInline(resultVisitor, new LocalVarRemapper(parameters, 0), false, LabelOwner.NOT_APPLICABLE); + result.markAsNeededFurtherReificationIf(neededFurtherReification); resultVisitor.visitMaxs(-1, -1); resultVisitor.visitEnd(); return result; @@ -180,7 +192,7 @@ public class AnonymousObjectTransformer { @NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder allCapturedBuilder, @NotNull ParametersBuilder constructorInlineBuilder, - @NotNull ConstructorInvocation invocation, + @NotNull AnonymousObjectGeneration anonymousObjectGen, @NotNull FieldRemapper parentRemapper, @NotNull List constructorAdditionalFakeParams ) { @@ -251,11 +263,11 @@ public class AnonymousObjectTransformer { RegeneratedLambdaFieldRemapper remapper = new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(), - constructorParameters, invocation.getCapturedLambdasToInline(), + constructorParameters, anonymousObjectGen.getCapturedLambdasToInline(), parentRemapper); MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")), - remapper, isSameModule, "Transformer for constructor of " + invocation.getOwnerInternalName()); + remapper, isSameModule, "Transformer for constructor of " + anonymousObjectGen.getOwnerInternalName()); InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false, LabelOwner.NOT_APPLICABLE); constructorVisitor.visitMaxs(-1, -1); @@ -263,7 +275,7 @@ public class AnonymousObjectTransformer { AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder); //TODO for inline method make public class - invocation.setNewConstructorDescriptor(constructorDescriptor); + anonymousObjectGen.setNewConstructorDescriptor(constructorDescriptor); return result; } @@ -302,19 +314,19 @@ public class AnonymousObjectTransformer { @NotNull MethodNode constructor, @NotNull ParametersBuilder capturedParamBuilder, @NotNull ParametersBuilder constructorParamBuilder, - @NotNull final ConstructorInvocation invocation + @NotNull final AnonymousObjectGeneration anonymousObjectGen ) { CapturedParamOwner owner = new CapturedParamOwner() { @Override public Type getType() { - return Type.getObjectType(invocation.getOwnerInternalName()); + return Type.getObjectType(anonymousObjectGen.getOwnerInternalName()); } }; List capturedLambdas = new ArrayList(); //captured var of inlined parameter List constructorAdditionalFakeParams = new ArrayList(); - Map indexToLambda = invocation.getLambdasToInline(); + Map indexToLambda = anonymousObjectGen.getLambdasToInline(); Set capturedParams = new HashSet(); //load captured parameters and patch instruction list (NB: there is also could be object fields) @@ -355,7 +367,14 @@ public class AnonymousObjectTransformer { } constructorParamBuilder.addThis(oldObjectType, false); - Type [] types = Type.getArgumentTypes(invocation.getDesc()); + String constructorDesc = anonymousObjectGen.getConstructorDesc(); + + if (constructorDesc == null) { + // in case of anonymous object with empty closure + constructorDesc = Type.getMethodDescriptor(Type.VOID_TYPE); + } + + Type [] types = Type.getArgumentTypes(constructorDesc); for (Type type : types) { LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex()); ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null, null); @@ -389,8 +408,8 @@ public class AnonymousObjectTransformer { - invocation.setAllRecapturedParameters(allRecapturedParameters); - invocation.setCapturedLambdasToInline(capturedLambdasToInline); + anonymousObjectGen.setAllRecapturedParameters(allRecapturedParameters); + anonymousObjectGen.setCapturedLambdasToInline(capturedLambdasToInline); return constructorAdditionalFakeParams; } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java index fc45fc5ca28..e1dbcc63161 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegen.java @@ -222,7 +222,7 @@ public class InlineCodegen implements CallGenerator { .subGenerator(functionDescriptor.getName().asString()), codegen.getContext(), callElement, - codegen.getParentCodegen().getClassName()); + codegen.getParentCodegen().getClassName(), reifiedTypeInliner); MethodInliner inliner = new MethodInliner(node, parameters, info, new FieldRemapper(null, null, parameters), isSameModule, "Method inlining " + callElement.getText()); //with captured diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java index b2fee10ba97..756ba852b80 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineCodegenUtil.java @@ -232,6 +232,10 @@ public class InlineCodegenUtil { return "".equals(methodName) && isAnonymousClass(internalName); } + public static boolean isAnonymousSingletonLoad(@NotNull String internalName, @NotNull String fieldName) { + return JvmAbi.INSTANCE_FIELD.equals(fieldName) && isAnonymousClass(internalName); + } + public static boolean isAnonymousClass(String internalName) { String shortName = getLastNamePart(internalName); int index = shortName.lastIndexOf("$"); diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java index f2a73522043..8a671d5f209 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InlineResult.java @@ -24,6 +24,7 @@ import java.util.Set; public class InlineResult { private final Set classesToRemove = new HashSet(); + private boolean needFurtherReification = false; private InlineResult() { @@ -48,4 +49,12 @@ public class InlineResult { public Set getClassesToRemove() { return classesToRemove; } + + public boolean needFurtherReification() { + return needFurtherReification; + } + + public void markAsNeededFurtherReificationIf(boolean condtition) { + this.needFurtherReification |= condtition; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java index ef85eaf942a..18723d58dc7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/InliningContext.java @@ -37,6 +37,8 @@ public class InliningContext { public final Map typeMapping; + public final ReifiedTypeInliner reifedTypeInliner; + public final boolean isInliningLambda; public final boolean classRegeneration; @@ -47,6 +49,7 @@ public class InliningContext { @NotNull GenerationState state, @NotNull NameGenerator nameGenerator, @NotNull Map typeMapping, + @NotNull ReifiedTypeInliner reifedTypeInliner, boolean isInliningLambda, boolean classRegeneration ) { @@ -55,6 +58,7 @@ public class InliningContext { this.state = state; this.nameGenerator = nameGenerator; this.typeMapping = typeMapping; + this.reifedTypeInliner = reifedTypeInliner; this.isInliningLambda = isInliningLambda; this.classRegeneration = classRegeneration; } @@ -75,11 +79,12 @@ public class InliningContext { public InliningContext subInlineWithClassRegeneration(@NotNull NameGenerator generator, @NotNull Map additionalTypeMappings, - @NotNull ConstructorInvocation constructorInvocation) { + @NotNull AnonymousObjectGeneration anonymousObjectGeneration + ) { Map newTypeMappings = new HashMap(typeMapping); newTypeMappings.putAll(additionalTypeMappings); return new RegenetedClassContext(this, expressionMap, state, generator, - newTypeMappings, isInliningLambda, constructorInvocation); + newTypeMappings, reifedTypeInliner, isInliningLambda, anonymousObjectGeneration); } @@ -96,7 +101,7 @@ public class InliningContext { Map newTypeMappings = new HashMap(typeMapping); newTypeMappings.putAll(additionalTypeMappings); return new InliningContext(this, expressionMap, state, generator, - newTypeMappings, isInliningLambda, isRegeneration); + newTypeMappings, reifedTypeInliner, isInliningLambda, isRegeneration); } public boolean isRoot() { diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java index bc03fbded57..99511c688e4 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/MethodInliner.java @@ -29,10 +29,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.PackageClassUtils; import org.jetbrains.jet.lang.resolve.kotlin.KotlinBinaryClassCache; import org.jetbrains.jet.lang.resolve.kotlin.KotlinJvmBinaryClass; -import org.jetbrains.org.objectweb.asm.Label; -import org.jetbrains.org.objectweb.asm.MethodVisitor; -import org.jetbrains.org.objectweb.asm.Opcodes; -import org.jetbrains.org.objectweb.asm.Type; +import org.jetbrains.org.objectweb.asm.*; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter; import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.commons.RemappingMethodAdapter; @@ -62,7 +59,7 @@ public class MethodInliner { private final List invokeCalls = new ArrayList(); //keeps order - private final List constructorInvocations = new ArrayList(); + private final List anonymousObjectGenerations = new ArrayList(); //current state private final Map currentTypeMapping = new HashMap(); @@ -140,44 +137,55 @@ public class MethodInliner { final MethodNode resultNode = new MethodNode(node.access, node.name, node.desc, node.signature, null); - final Iterator iterator = constructorInvocations.iterator(); + final Iterator iterator = anonymousObjectGenerations.iterator(); RemappingMethodAdapter remappingMethodAdapter = new RemappingMethodAdapter(resultNode.access, resultNode.desc, resultNode, new TypeRemapper(currentTypeMapping)); InlineAdapter lambdaInliner = new InlineAdapter(remappingMethodAdapter, parameters.totalSize()) { - private ConstructorInvocation invocation; + private AnonymousObjectGeneration anonymousObjectGen; + private void handleAnonymousObjectGeneration() { + anonymousObjectGen = iterator.next(); + + if (anonymousObjectGen.shouldRegenerate()) { + //TODO: need poping of type but what to do with local funs??? + Type newLambdaType = Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName()); + currentTypeMapping.put(anonymousObjectGen.getOwnerInternalName(), newLambdaType.getInternalName()); + AnonymousObjectTransformer transformer = + new AnonymousObjectTransformer(anonymousObjectGen.getOwnerInternalName(), + inliningContext + .subInlineWithClassRegeneration( + inliningContext.nameGenerator, + currentTypeMapping, + anonymousObjectGen), + isSameModule, newLambdaType + ); + + InlineResult transformResult = transformer.doTransform(anonymousObjectGen, nodeRemapper); + result.addAllClassesToRemove(transformResult); + + if (inliningContext.isInliningLambda && !anonymousObjectGen.isStaticOrigin()) { + // this class is transformed and original not used so we should remove original one after inlining + // Note: It is unsafe to remove anonymous class that is referenced by GETSTATIC within lambda + // because it can be local function from outer scope + result.addClassToRemove(anonymousObjectGen.getOwnerInternalName()); + } + + if (transformResult.needFurtherReification()) { + ReifiedTypeInliner.putNeedClassReificationMarker(mv); + result.markAsNeededFurtherReificationIf(true); + } + } + } + @Override public void anew(@NotNull Type type) { if (isAnonymousConstructorCall(type.getInternalName(), "")) { - invocation = iterator.next(); - - if (invocation.shouldRegenerate()) { - //TODO: need poping of type but what to do with local funs??? - Type newLambdaType = Type.getObjectType(inliningContext.nameGenerator.genLambdaClassName()); - currentTypeMapping.put(invocation.getOwnerInternalName(), newLambdaType.getInternalName()); - AnonymousObjectTransformer transformer = - new AnonymousObjectTransformer(invocation.getOwnerInternalName(), - inliningContext - .subInlineWithClassRegeneration( - inliningContext.nameGenerator, - currentTypeMapping, - invocation), - isSameModule, newLambdaType - ); - - InlineResult transformResult = transformer.doTransform(invocation, nodeRemapper); - result.addAllClassesToRemove(transformResult); - - if (inliningContext.isInliningLambda) { - //this class is transformed and original not used so we should remove original one after inlining - result.addClassToRemove(invocation.getOwnerInternalName()); - } - } + handleAnonymousObjectGeneration(); } - //in case of regenerated invocation type would be remapped to new one via remappingMethodAdapter + //in case of regenerated anonymousObjectGen type would be remapped to new one via remappingMethodAdapter super.anew(type); } @@ -222,24 +230,35 @@ public class MethodInliner { addInlineMarker(this, false); } else if (isAnonymousConstructorCall(owner, name)) { //TODO add method - assert invocation != null : " call not corresponds to new call" + owner + " " + name; - if (invocation.shouldRegenerate()) { + assert anonymousObjectGen != null : " call not corresponds to new call" + owner + " " + name; + if (anonymousObjectGen.shouldRegenerate()) { //put additional captured parameters on stack - for (CapturedParamDesc capturedParamDesc : invocation.getAllRecapturedParameters()) { + for (CapturedParamDesc capturedParamDesc : anonymousObjectGen.getAllRecapturedParameters()) { visitFieldInsn(Opcodes.GETSTATIC, capturedParamDesc.getContainingLambdaName(), "$$$" + capturedParamDesc.getFieldName(), capturedParamDesc.getType().getDescriptor()); } - super.visitMethodInsn(opcode, invocation.getNewLambdaType().getInternalName(), name, invocation.getNewConstructorDescriptor(), itf); - invocation = null; + super.visitMethodInsn(opcode, anonymousObjectGen.getNewLambdaType().getInternalName(), name, anonymousObjectGen.getNewConstructorDescriptor(), itf); + anonymousObjectGen = null; } else { super.visitMethodInsn(opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf); } } + else if (ReifiedTypeInliner.isNeedClassReificationMarker(new MethodInsnNode(opcode, owner, name, desc, false))) { + // we will put it if needed in anew processing + } else { super.visitMethodInsn(opcode, changeOwnerForExternalPackage(owner, opcode), name, desc, itf); } } + @Override + public void visitFieldInsn(int opcode, @NotNull String owner, @NotNull String name, @NotNull String desc) { + if (opcode == Opcodes.GETSTATIC && isAnonymousSingletonLoad(owner, name)) { + handleAnonymousObjectGeneration(); + } + super.visitFieldInsn(opcode, owner, name, desc); + } + @Override public void visitMaxs(int stack, int locals) { lambdasFinallyBlocks = resultNode.tryCatchBlocks.size(); @@ -358,11 +377,17 @@ public class MethodInliner { AbstractInsnNode cur = node.instructions.getFirst(); int index = 0; + boolean awaitClassReification = false; + Set possibleDeadLabels = new HashSet(); + while (cur != null) { Frame frame = sources[index]; if (frame != null) { - if (cur.getType() == AbstractInsnNode.METHOD_INSN) { + if (ReifiedTypeInliner.isNeedClassReificationMarker(cur)) { + awaitClassReification = true; + } + else if (cur.getType() == AbstractInsnNode.METHOD_INSN) { MethodInsnNode methodInsnNode = (MethodInsnNode) cur; String owner = methodInsnNode.owner; String desc = methodInsnNode.desc; @@ -403,11 +428,27 @@ public class MethodInliner { } } - constructorInvocations.add(new ConstructorInvocation(owner, desc, lambdaMapping, isSameModule, inliningContext.classRegeneration)); + anonymousObjectGenerations.add( + buildConstructorInvocation( + owner, desc, lambdaMapping, awaitClassReification + ) + ); + awaitClassReification = false; + } + } + else if (cur.getOpcode() == Opcodes.GETSTATIC) { + FieldInsnNode fieldInsnNode = (FieldInsnNode) cur; + String owner = fieldInsnNode.owner; + if (isAnonymousSingletonLoad(owner, fieldInsnNode.name)) { + anonymousObjectGenerations.add( + new AnonymousObjectGeneration( + owner, isSameModule, awaitClassReification, isAlreadyRegenerated(owner), true + ) + ); + awaitClassReification = false; } } } - AbstractInsnNode prevNode = cur; cur = cur.getNext(); index++; @@ -446,6 +487,26 @@ public class MethodInliner { return start == end; } + @NotNull + private AnonymousObjectGeneration buildConstructorInvocation( + @NotNull String owner, + @NotNull String desc, + @NotNull Map lambdaMapping, + boolean needReification + ) { + return new AnonymousObjectGeneration( + owner, needReification, isSameModule, lambdaMapping, + inliningContext.classRegeneration, + isAlreadyRegenerated(owner), + desc, + false + ); + } + + private boolean isAlreadyRegenerated(@NotNull String owner) { + return inliningContext.typeMapping.containsKey(owner); + } + public LambdaInfo getLambdaIfExists(AbstractInsnNode insnNode) { if (insnNode.getOpcode() == Opcodes.ALOAD) { int varIndex = ((VarInsnNode) insnNode).var; diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java index 98c231a9e08..e5c6f1af58c 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RegenetedClassContext.java @@ -25,7 +25,7 @@ import java.util.Map; public class RegenetedClassContext extends InliningContext { @NotNull - private final ConstructorInvocation constructorInvocation; + private final AnonymousObjectGeneration anonymousObjectGeneration; protected RegenetedClassContext( @Nullable InliningContext parent, @@ -33,15 +33,16 @@ public class RegenetedClassContext extends InliningContext { @NotNull GenerationState state, @NotNull NameGenerator nameGenerator, @NotNull Map typeMapping, + @NotNull ReifiedTypeInliner reifiedTypeInliner, boolean isInliningLambda, - @NotNull ConstructorInvocation constructorInvocation + @NotNull AnonymousObjectGeneration anonymousObjectGeneration ) { - super(parent, map, state, nameGenerator, typeMapping, isInliningLambda, true); - this.constructorInvocation = constructorInvocation; + super(parent, map, state, nameGenerator, typeMapping, reifiedTypeInliner, isInliningLambda, true); + this.anonymousObjectGeneration = anonymousObjectGeneration; } @Override public String getClassNameToInline() { - return constructorInvocation.getOwnerInternalName(); + return anonymousObjectGeneration.getOwnerInternalName(); } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java index fcac9379c92..100fcc86b58 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/inline/RootInliningContext.java @@ -38,9 +38,10 @@ public class RootInliningContext extends InliningContext { @NotNull NameGenerator nameGenerator, @NotNull CodegenContext startContext, @NotNull JetElement callElement, - @NotNull String classNameToInline + @NotNull String classNameToInline, + @NotNull ReifiedTypeInliner inliner ) { - super(null, map, state, nameGenerator, Collections.emptyMap(), false, false); + super(null, map, state, nameGenerator, Collections.emptyMap(), inliner, false, false); this.callElement = callElement; this.startContext = startContext; this.classNameToInline = classNameToInline; diff --git a/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambda.kt b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambda.kt new file mode 100644 index 00000000000..41ccf0f2efd --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambda.kt @@ -0,0 +1,14 @@ +import kotlin.test.assertEquals + +inline fun foo(x: String, block: (String) -> String) = block(x) + +fun box(): String { + val res = foo("abc") { + fun bar(y: String) = y + "cde" + bar(it) + } + + assertEquals("abccde", res) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage1.kt b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage1.kt new file mode 100644 index 00000000000..edb963dd8b5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage1.kt @@ -0,0 +1,14 @@ +import kotlin.test.assertEquals + +inline fun foo(x: String, block: (String) -> String) = block(x) + +fun box(): String { + val res = foo("abc") { + fun bar(y: String) = y + "cde" + foo(it) { bar(it) } + } + + assertEquals("abccde", res) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage2.kt b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage2.kt new file mode 100644 index 00000000000..b97f93fd8b5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage2.kt @@ -0,0 +1,15 @@ +import kotlin.test.assertEquals + +inline fun foo(x: String, block: (String) -> String) = block(x) +fun noInlineFoo(x: String, block: (String) -> String) = block(x) + +fun box(): String { + val res = foo("abc") { + fun bar(y: String) = y + "cde" + noInlineFoo(it) { bar(it) } + } + + assertEquals("abccde", res) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/localFunInLambda/simple.kt b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/simple.kt new file mode 100644 index 00000000000..8f86cc3c384 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/localFunInLambda/simple.kt @@ -0,0 +1,13 @@ +import kotlin.test.assertEquals + +inline fun foo(x: String, block: (String) -> String) = block(x) + +fun box(): String { + fun bar(y: String) = y + "cde" + + val res = foo("abc") { bar(it) } + + assertEquals("abccde", res) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/anonymousObject.kt b/compiler/testData/codegen/boxWithStdlib/reified/anonymousObject.kt new file mode 100644 index 00000000000..0b36c0ed49f --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reified/anonymousObject.kt @@ -0,0 +1,19 @@ +import kotlin.test.assertEquals + +abstract class A { + abstract fun f(): String +} + +inline fun foo(): A { + return object : A() { + override fun f(): String { + return javaClass().getName() + } + } +} + +fun box(): String { + val y = foo(); + assertEquals("java.lang.String", y.f()) + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt b/compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt new file mode 100644 index 00000000000..80b0fc20b68 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt @@ -0,0 +1,20 @@ +import kotlin.test.assertEquals + +abstract class A { + abstract fun f(): String +} + +inline fun foo(): A { + return object : A() { + override fun f(): String { + return "OK" + } + } +} + +fun box(): String { + val y = foo(); + assertEquals("OK", y.f()) + assertEquals("A", y.javaClass.getGenericSuperclass()?.toString()) + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/innerAnonymousObject.kt b/compiler/testData/codegen/boxWithStdlib/reified/innerAnonymousObject.kt new file mode 100644 index 00000000000..aaafb952e31 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reified/innerAnonymousObject.kt @@ -0,0 +1,27 @@ +import kotlin.test.assertEquals + +abstract class A { + abstract fun f(): String + override fun toString() = f() +} + +abstract class G { + abstract fun bar(): Any +} + +inline fun foo(): G { + return object : G() { + override fun bar(): Any { + return object : A() { + override fun f(): String = "OK" + } + } + } +} + +fun box(): String { + val y = foo().bar(); + assertEquals("OK", y.toString()) + assertEquals("A", y.javaClass.getGenericSuperclass()?.toString()) + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/nonInlineableLambdaInReifiedFunction.kt b/compiler/testData/codegen/boxWithStdlib/reified/nonInlineableLambdaInReifiedFunction.kt new file mode 100644 index 00000000000..72baad4ecc5 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reified/nonInlineableLambdaInReifiedFunction.kt @@ -0,0 +1,17 @@ +import kotlin.test.assertEquals + +fun foo(block: () -> String) = block() +inline fun bar1(x: T): String = foo() { + javaClass().getName() +} +inline fun bar2(x: T, y: String): String = foo() { + javaClass().getName() + "#" + y +} + +fun box(): String { + + assertEquals("java.lang.Integer", bar1(1)) + assertEquals("java.lang.String#OK", bar2("abc", "OK")) + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/recursiveInnerAnonymousObject.kt b/compiler/testData/codegen/boxWithStdlib/reified/recursiveInnerAnonymousObject.kt new file mode 100644 index 00000000000..c6499a5e810 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reified/recursiveInnerAnonymousObject.kt @@ -0,0 +1,35 @@ +import kotlin.test.assertEquals + +abstract class A { + abstract fun f(): String + override fun toString() = f() +} + +abstract class G { + abstract fun bar(): Any +} + +inline fun baz(): G { + return object : G() { + override fun bar(): Any { + return object : A() { + override fun f(): String = "OK" + } + } + } +} + +inline fun foo(): Pair { + return Pair(baz(), baz()) +} + +fun box(): String { + val res = foo(); + val x1 = res.first.bar() + val x2 = res.second.bar() + assertEquals("OK", x1.toString()) + assertEquals("OK", x2.toString()) + assertEquals("A", x1.javaClass.getGenericSuperclass()?.toString()) + assertEquals("A", x2.javaClass.getGenericSuperclass()?.toString()) + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reified/recursiveNonInlineableLambda.kt b/compiler/testData/codegen/boxWithStdlib/reified/recursiveNonInlineableLambda.kt new file mode 100644 index 00000000000..cc3d6934471 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reified/recursiveNonInlineableLambda.kt @@ -0,0 +1,22 @@ +import kotlin.test.assertEquals + +fun foo(block: () -> String) = block() + +inline fun bar1(): String = foo() { + javaClass().getName() +} +inline fun bar2(y: String): String = foo() { + javaClass().getName() + "#" + y +} + +inline fun bar3(y: String) = + Pair(bar1(), bar2(y)) + +fun box(): String { + val x = bar3("OK") + + assertEquals("java.lang.Integer", x.first) + assertEquals("java.lang.String#OK", x.second) + + return "OK" +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 14a65b5e9a4..e549915cbbb 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -30,7 +30,7 @@ import java.util.regex.Pattern; @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/boxWithStdlib") @TestDataPath("$PROJECT_ROOT") -@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.BoxingOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.DefaultArguments.class, BlackBoxWithStdlibCodegenTestGenerated.Enum.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.NonLocalReturns.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformStatic.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformTypes.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Reified.class, BlackBoxWithStdlibCodegenTestGenerated.StoreStackBeforeInline.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class, BlackBoxWithStdlibCodegenTestGenerated.WhenEnumOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.WhenStringOptimization.class}) +@InnerTestClasses({BlackBoxWithStdlibCodegenTestGenerated.Annotations.class, BlackBoxWithStdlibCodegenTestGenerated.Arrays.class, BlackBoxWithStdlibCodegenTestGenerated.BoxingOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.CallableReference.class, BlackBoxWithStdlibCodegenTestGenerated.Casts.class, BlackBoxWithStdlibCodegenTestGenerated.DataClasses.class, BlackBoxWithStdlibCodegenTestGenerated.DefaultArguments.class, BlackBoxWithStdlibCodegenTestGenerated.Enum.class, BlackBoxWithStdlibCodegenTestGenerated.Evaluate.class, BlackBoxWithStdlibCodegenTestGenerated.FullJdk.class, BlackBoxWithStdlibCodegenTestGenerated.HashPMap.class, BlackBoxWithStdlibCodegenTestGenerated.Intrinsics.class, BlackBoxWithStdlibCodegenTestGenerated.JdkAnnotations.class, BlackBoxWithStdlibCodegenTestGenerated.LocalFunInLambda.class, BlackBoxWithStdlibCodegenTestGenerated.NonLocalReturns.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformNames.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformStatic.class, BlackBoxWithStdlibCodegenTestGenerated.PlatformTypes.class, BlackBoxWithStdlibCodegenTestGenerated.Ranges.class, BlackBoxWithStdlibCodegenTestGenerated.Reflection.class, BlackBoxWithStdlibCodegenTestGenerated.Regressions.class, BlackBoxWithStdlibCodegenTestGenerated.Reified.class, BlackBoxWithStdlibCodegenTestGenerated.StoreStackBeforeInline.class, BlackBoxWithStdlibCodegenTestGenerated.Strings.class, BlackBoxWithStdlibCodegenTestGenerated.ToArray.class, BlackBoxWithStdlibCodegenTestGenerated.Vararg.class, BlackBoxWithStdlibCodegenTestGenerated.When.class, BlackBoxWithStdlibCodegenTestGenerated.WhenEnumOptimization.class, BlackBoxWithStdlibCodegenTestGenerated.WhenStringOptimization.class}) @RunWith(JUnit3RunnerWithInners.class) public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBoxWithStdlib() throws Exception { @@ -1452,6 +1452,39 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode } } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class LocalFunInLambda extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInLocalFunInLambda() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/localFunInLambda"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("definedWithinLambda.kt") + public void testDefinedWithinLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambda.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("definedWithinLambdaInnerUsage1.kt") + public void testDefinedWithinLambdaInnerUsage1() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage1.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("definedWithinLambdaInnerUsage2.kt") + public void testDefinedWithinLambdaInnerUsage2() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/definedWithinLambdaInnerUsage2.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("simple.kt") + public void testSimple() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/localFunInLambda/simple.kt"); + doTestWithStdlib(fileName); + } + } + @TestMetadata("compiler/testData/codegen/boxWithStdlib/nonLocalReturns") @TestDataPath("$PROJECT_ROOT") @RunWith(JUnit3RunnerWithInners.class) @@ -2420,6 +2453,18 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/reified"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("anonymousObject.kt") + public void testAnonymousObject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/anonymousObject.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("anonymousObjectReifiedSupertype.kt") + public void testAnonymousObjectReifiedSupertype() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/anonymousObjectReifiedSupertype.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("checkcast.kt") public void testCheckcast() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/checkcast.kt"); @@ -2438,6 +2483,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("innerAnonymousObject.kt") + public void testInnerAnonymousObject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/innerAnonymousObject.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("instanceof.kt") public void testInstanceof() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/instanceof.kt"); @@ -2456,12 +2507,30 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("nonInlineableLambdaInReifiedFunction.kt") + public void testNonInlineableLambdaInReifiedFunction() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/nonInlineableLambdaInReifiedFunction.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("recursiveInnerAnonymousObject.kt") + public void testRecursiveInnerAnonymousObject() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/recursiveInnerAnonymousObject.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("recursiveNewArray.kt") public void testRecursiveNewArray() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/recursiveNewArray.kt"); doTestWithStdlib(fileName); } + @TestMetadata("recursiveNonInlineableLambda.kt") + public void testRecursiveNonInlineableLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/recursiveNonInlineableLambda.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("safecast.kt") public void testSafecast() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reified/safecast.kt");