Support anonymous object constructor transformation and inline

This commit is contained in:
Mikhael Bogdanov
2014-04-24 16:14:17 +04:00
parent 9181302ce4
commit c5e9ea0d29
14 changed files with 350 additions and 87 deletions
@@ -16,6 +16,7 @@
package org.jetbrains.jet.codegen.inline; package org.jetbrains.jet.codegen.inline;
import org.jetbrains.annotations.NotNull;
import org.jetbrains.org.objectweb.asm.Type; import org.jetbrains.org.objectweb.asm.Type;
import java.util.List; import java.util.List;
@@ -25,6 +26,8 @@ public class ConstructorInvocation {
private final String ownerInternalName; private final String ownerInternalName;
private final String desc;
private final Map<Integer, LambdaInfo> lambdasToInline; private final Map<Integer, LambdaInfo> lambdasToInline;
private final boolean isSameModule; private final boolean isSameModule;
@@ -37,15 +40,17 @@ public class ConstructorInvocation {
private Map<String, LambdaInfo> capturedLambdasToInline; private Map<String, LambdaInfo> capturedLambdasToInline;
private boolean capturedOuterRegenerated; private final boolean capturedOuterRegenerated;
ConstructorInvocation( ConstructorInvocation(
String ownerInternalName, @NotNull String ownerInternalName,
Map<Integer, LambdaInfo> lambdasToInline, @NotNull String desc,
@NotNull Map<Integer, LambdaInfo> lambdasToInline,
boolean isSameModule, boolean isSameModule,
boolean capturedOuterRegenerated boolean capturedOuterRegenerated
) { ) {
this.ownerInternalName = ownerInternalName; this.ownerInternalName = ownerInternalName;
this.desc = desc;
this.lambdasToInline = lambdasToInline; this.lambdasToInline = lambdasToInline;
this.isSameModule = isSameModule; this.isSameModule = isSameModule;
this.capturedOuterRegenerated = capturedOuterRegenerated; this.capturedOuterRegenerated = capturedOuterRegenerated;
@@ -95,4 +100,7 @@ public class ConstructorInvocation {
this.capturedLambdasToInline = capturedLambdasToInline; this.capturedLambdasToInline = capturedLambdasToInline;
} }
public String getDesc() {
return desc;
}
} }
@@ -18,20 +18,22 @@ package org.jetbrains.jet.codegen.inline;
import com.intellij.openapi.util.Pair; import com.intellij.openapi.util.Pair;
import com.intellij.openapi.vfs.VirtualFile; import com.intellij.openapi.vfs.VirtualFile;
import com.intellij.util.ArrayUtil;
import org.jetbrains.annotations.NotNull; import org.jetbrains.annotations.NotNull;
import org.jetbrains.jet.OutputFile; import org.jetbrains.jet.OutputFile;
import org.jetbrains.jet.codegen.*; import org.jetbrains.jet.codegen.AsmUtil;
import org.jetbrains.jet.codegen.ClassBuilder;
import org.jetbrains.jet.codegen.FieldInfo;
import org.jetbrains.jet.codegen.StackValue;
import org.jetbrains.jet.codegen.state.GenerationState; import org.jetbrains.jet.codegen.state.GenerationState;
import org.jetbrains.jet.codegen.state.JetTypeMapper; import org.jetbrains.jet.codegen.state.JetTypeMapper;
import org.jetbrains.org.objectweb.asm.*; import org.jetbrains.org.objectweb.asm.*;
import org.jetbrains.org.objectweb.asm.commons.Method; import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter;
import org.jetbrains.org.objectweb.asm.tree.*; import org.jetbrains.org.objectweb.asm.tree.*;
import java.io.IOException; import java.io.IOException;
import java.util.*; import java.util.*;
import static org.jetbrains.org.objectweb.asm.Opcodes.V1_6;
public class LambdaTransformer { public class LambdaTransformer {
protected final GenerationState state; protected final GenerationState state;
@@ -48,8 +50,6 @@ public class LambdaTransformer {
private final ClassReader reader; private final ClassReader reader;
private String superName;
private final boolean isSameModule; private final boolean isSameModule;
private final Map<String, List<String>> fieldNames = new HashMap<String, List<String>>(); private final Map<String, List<String>> fieldNames = new HashMap<String, List<String>>();
@@ -91,28 +91,13 @@ public class LambdaTransformer {
@NotNull @NotNull
public InlineResult doTransform(@NotNull ConstructorInvocation invocation, @NotNull FieldRemapper parentRemapper) { public InlineResult doTransform(@NotNull ConstructorInvocation invocation, @NotNull FieldRemapper parentRemapper) {
final ClassBuilder classBuilder = createClassBuilder(); ClassBuilder classBuilder = createClassBuilder();
final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>(); final List<MethodNode> methodsToTransform = new ArrayList<MethodNode>();
final List<FieldNode> fieldToAdd = new ArrayList<FieldNode>();
reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) { reader.accept(new ClassVisitor(InlineCodegenUtil.API, classBuilder.getVisitor()) {
@Override
public void visit(int version, int access, String name, String signature, String superName, String[] interfaces) {
//TODO: public visibility for inline function
LambdaTransformer.this.superName = superName;
classBuilder.defineClass(null,
V1_6,
access,
newLambdaType.getInternalName(),
signature,
superName,
interfaces
);
}
@Override @Override
public MethodVisitor visitMethod( public MethodVisitor visitMethod(
int access, String name, String desc, String signature, String[] exceptions int access, @NotNull String name, @NotNull String desc, String signature, String[] exceptions
) { ) {
MethodNode node = new MethodNode(access, name, desc, signature, exceptions); MethodNode node = new MethodNode(access, name, desc, signature, exceptions);
if (name.equals("<init>")){ if (name.equals("<init>")){
@@ -128,26 +113,32 @@ public class LambdaTransformer {
@Override @Override
public FieldVisitor visitField( public FieldVisitor visitField(
int access, String name, String desc, String signature, Object value int access, @NotNull String name, @NotNull String desc, String signature, Object value
) { ) {
addUniqueField(name); addUniqueField(name);
FieldNode fieldNode = new FieldNode(access, name, desc, signature, value); if (InlineCodegenUtil.isCapturedFieldName(name)) {
fieldToAdd.add(fieldNode); return null;
return fieldNode; } else {
return super.visitField(access, name, desc, signature, value);
}
} }
}, ClassReader.SKIP_FRAMES); }, ClassReader.SKIP_FRAMES);
ParametersBuilder capturedBuilder = ParametersBuilder.newBuilder(); ParametersBuilder allCapturedParamBuilder = ParametersBuilder.newBuilder();
extractParametersMappingAndPatchConstructor(constructor, capturedBuilder, invocation); ParametersBuilder constructorParamBuilder = ParametersBuilder.newBuilder();
extractParametersMappingAndPatchConstructor(constructor, allCapturedParamBuilder, constructorParamBuilder, invocation);
InlineResult result = InlineResult.create(); InlineResult result = InlineResult.create();
for (MethodNode next : methodsToTransform) { for (MethodNode next : methodsToTransform) {
MethodVisitor visitor = newMethod(classBuilder, next); MethodVisitor visitor = newMethod(classBuilder, next);
InlineResult funResult = inlineMethod(invocation, parentRemapper, visitor, next, capturedBuilder); InlineResult funResult = inlineMethod(invocation, parentRemapper, visitor, next, allCapturedParamBuilder);
result.addAllClassesToRemove(funResult); result.addAllClassesToRemove(funResult);
} }
generateConstructorAndFields(classBuilder, capturedBuilder, invocation); InlineResult constructorResult =
generateConstructorAndFields(classBuilder, allCapturedParamBuilder, constructorParamBuilder, invocation, parentRemapper);
result.addAllClassesToRemove(constructorResult);
classBuilder.done(); classBuilder.done();
@@ -178,22 +169,82 @@ public class LambdaTransformer {
return result; return result;
} }
private void generateConstructorAndFields(@NotNull ClassBuilder classBuilder, @NotNull ParametersBuilder builder, @NotNull ConstructorInvocation invocation) { private InlineResult generateConstructorAndFields(
List<CapturedParamInfo> infos = builder.buildCaptured(); @NotNull ClassBuilder classBuilder,
List<Pair<String, Type>> newConstructorSignature = new ArrayList<Pair<String, Type>>(); @NotNull ParametersBuilder allCapturedBuilder,
for (CapturedParamInfo capturedParamInfo : infos) { @NotNull ParametersBuilder constructorInlineBuilder,
if (capturedParamInfo.getLambda() == null) { //not inlined @NotNull ConstructorInvocation invocation,
newConstructorSignature.add(new Pair<String, Type>(capturedParamInfo.getNewFieldName(), capturedParamInfo.getType())); @NotNull FieldRemapper parentRemapper
) {
List<Type> descTypes = new ArrayList<Type>();
Parameters constructorParams = constructorInlineBuilder.buildParameters();
final int [] capturedIndexes = new int [constructorParams.totalSize()];
int index = 0;
int size = 0;
//complex processing cause it could have super constructor call params
for (ParameterInfo info : constructorParams) {
if (!info.isSkipped()) { //not inlined
if (info.isCaptured() || info instanceof CapturedParamInfo) {
capturedIndexes[index] = size;
index++;
}
if (size != 0) { //skip this
descTypes.add(info.getType());
}
size += info.getType().getSize();
} }
} }
List<FieldInfo> fields = AsmUtil.transformCapturedParams(newConstructorSignature, newLambdaType); final List<Pair<String, Type>> capturedFieldsToGenerate = new ArrayList<Pair<String, Type>>();
for (CapturedParamInfo capturedParamInfo : allCapturedBuilder.listCaptured()) {
if (capturedParamInfo.getLambda() == null) { //not inlined
capturedFieldsToGenerate.add(new Pair<String, Type>(capturedParamInfo.getNewFieldName(), capturedParamInfo.getType()));
}
}
AsmUtil.genClosureFields(newConstructorSignature, classBuilder); String constructorDescriptor = Type.getMethodDescriptor(Type.VOID_TYPE, descTypes.toArray(new Type[descTypes.size()]));
MethodVisitor constructorVisitor = classBuilder.newMethod(null,
AsmUtil.NO_FLAG_PACKAGE_PRIVATE,
"<init>", constructorDescriptor,
null, ArrayUtil.EMPTY_STRING_ARRAY);
MethodVisitor capturedFieldInitializer = new InstructionAdapter(InlineCodegenUtil.API, constructorVisitor) {
private boolean superCallProcessed;
@Override
public void visitMethodInsn(int opcode, String owner, String name, String desc, boolean itf) {
super.visitMethodInsn(opcode, owner, name, desc, itf);
if (!superCallProcessed && "<init>".equals(name)) {
superCallProcessed = true;
List<FieldInfo> fields = AsmUtil.transformCapturedParams(capturedFieldsToGenerate, newLambdaType);
int paramIndex = 0;
for (FieldInfo fieldInfo : fields) {
AsmUtil.genAssignInstanceFieldFromParam(fieldInfo, capturedIndexes[paramIndex], this);
paramIndex++;
}
}
}
};
Parameters constructorParameters = constructorInlineBuilder.buildParameters();
RegeneratedLambdaFieldRemapper remapper =
new RegeneratedLambdaFieldRemapper(oldObjectType.getInternalName(), newLambdaType.getInternalName(),
constructorParameters, invocation.getCapturedLambdasToInline(),
parentRemapper);
MethodInliner inliner = new MethodInliner(constructor, constructorParameters, inliningContext.subInline(inliningContext.nameGenerator.subGenerator("lambda")),
remapper, isSameModule, "Transformer for constructor of " + invocation.getOwnerInternalName());
InlineResult result = inliner.doInline(capturedFieldInitializer, new LocalVarRemapper(constructorParameters, 0), false);
constructorVisitor.visitMaxs(-1, -1);
AsmUtil.genClosureFields(capturedFieldsToGenerate, classBuilder);
//TODO for inline method make public class //TODO for inline method make public class
Method newConstructor = ClosureCodegen.generateConstructor(classBuilder, fields, null, Type.getObjectType(superName), state, AsmUtil.NO_FLAG_PACKAGE_PRIVATE); invocation.setNewConstructorDescriptor(constructorDescriptor);
invocation.setNewConstructorDescriptor(newConstructor.getDescriptor()); return result;
} }
@NotNull @NotNull
@@ -203,7 +254,7 @@ public class LambdaTransformer {
) { ) {
ParametersBuilder builder = ParametersBuilder.newBuilder(); ParametersBuilder builder = ParametersBuilder.newBuilder();
buildInvokeParamsFor(builder, sourceNode); buildInvokeParamsFor(builder, sourceNode);
for (CapturedParamInfo param : capturedBuilder.getCapturedParams()) { for (CapturedParamInfo param : capturedBuilder.listCaptured()) {
builder.addCapturedParamCopy(param); builder.addCapturedParamCopy(param);
} }
return builder.buildParameters(); return builder.buildParameters();
@@ -229,11 +280,11 @@ public class LambdaTransformer {
private void extractParametersMappingAndPatchConstructor( private void extractParametersMappingAndPatchConstructor(
@NotNull MethodNode constructor, @NotNull MethodNode constructor,
@NotNull ParametersBuilder builder, @NotNull ParametersBuilder capturedParamBuilder,
@NotNull ParametersBuilder constructorParamBuilder,
@NotNull final ConstructorInvocation invocation @NotNull final ConstructorInvocation invocation
) { ) {
Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
List<LambdaInfo> capturedLambdas = new ArrayList<LambdaInfo>(); //captured var of inlined parameter
CapturedParamOwner owner = new CapturedParamOwner() { CapturedParamOwner owner = new CapturedParamOwner() {
@Override @Override
public Type getType() { public Type getType() {
@@ -241,24 +292,41 @@ public class LambdaTransformer {
} }
}; };
AbstractInsnNode cur = constructor.instructions.getFirst(); List<LambdaInfo> capturedLambdas = new ArrayList<LambdaInfo>(); //captured var of inlined parameter
//load captured parameters (NB: there is also could be object fields) List<CapturedParamInfo> capturedToInline = new ArrayList<CapturedParamInfo>();
while (cur != null) { Map<Integer, LambdaInfo> indexToLambda = invocation.getLambdasToInline();
if (cur instanceof FieldInsnNode && cur.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(((FieldInsnNode) cur).name)) { Set<Integer> capturedParams = new HashSet<Integer>();
FieldInsnNode fieldNode = (FieldInsnNode) cur;
CapturedParamInfo info = builder.addCapturedParam(owner, fieldNode.name, Type.getType(fieldNode.desc), false, null);
boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode; //load captured parameters and patch instruction list (NB: there is also could be object fields)
boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode; AbstractInsnNode cur = constructor.instructions.getFirst();
if (isPrevPrevVarNode) { while (cur != null) {
VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious(); if (cur instanceof FieldInsnNode) {
if (node.var == 0) { FieldInsnNode fieldNode = (FieldInsnNode) cur;
VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious(); if (fieldNode.getOpcode() == Opcodes.PUTFIELD && InlineCodegenUtil.isCapturedFieldName(fieldNode.name)) {
int varIndex = previous.var;
LambdaInfo lambdaInfo = indexToLambda.get(varIndex); boolean isPrevVarNode = fieldNode.getPrevious() instanceof VarInsnNode;
if (lambdaInfo != null) { boolean isPrevPrevVarNode = isPrevVarNode && fieldNode.getPrevious().getPrevious() instanceof VarInsnNode;
info.setLambda(lambdaInfo);
capturedLambdas.add(lambdaInfo); if (isPrevPrevVarNode) {
VarInsnNode node = (VarInsnNode) fieldNode.getPrevious().getPrevious();
if (node.var == 0) {
VarInsnNode previous = (VarInsnNode) fieldNode.getPrevious();
int varIndex = previous.var;
LambdaInfo lambdaInfo = indexToLambda.get(varIndex);
CapturedParamInfo info = capturedParamBuilder.addCapturedParam(owner, fieldNode.name, Type.getType(fieldNode.desc), lambdaInfo != null, null);
if (lambdaInfo != null) {
info.setLambda(lambdaInfo);
capturedLambdas.add(lambdaInfo);
capturedToInline.add(info);
}
capturedParams.add(varIndex);
constructor.instructions.remove(previous.getPrevious());
constructor.instructions.remove(previous);
AbstractInsnNode temp = cur;
cur = cur.getNext();
constructor.instructions.remove(temp);
continue;
} }
} }
} }
@@ -266,13 +334,27 @@ public class LambdaTransformer {
cur = cur.getNext(); cur = cur.getNext();
} }
constructorParamBuilder.addThis(oldObjectType, false);
Type [] types = Type.getArgumentTypes(invocation.getDesc());
for (Type type : types) {
LambdaInfo info = indexToLambda.get(constructorParamBuilder.getNextValueParameterIndex());
ParameterInfo parameterInfo = constructorParamBuilder.addNextParameter(type, info != null, null);
parameterInfo.setLambda(info);
if (capturedParams.contains(parameterInfo.getIndex())) {
parameterInfo.setCaptured(true);
} else {
//otherwise it's super constructor parameter
}
}
//For all inlined lambdas add their captured parameters //For all inlined lambdas add their captured parameters
//TODO: some of such parameters could be skipped - we should perform additional analysis //TODO: some of such parameters could be skipped - we should perform additional analysis
Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>(); //captured var of inlined parameter Map<String, LambdaInfo> capturedLambdasToInline = new HashMap<String, LambdaInfo>(); //captured var of inlined parameter
List<CapturedParamInfo> allRecapturedParameters = new ArrayList<CapturedParamInfo>(); List<CapturedParamInfo> allRecapturedParameters = new ArrayList<CapturedParamInfo>();
for (LambdaInfo info : capturedLambdas) { for (LambdaInfo info : capturedLambdas) {
for (CapturedParamInfo var : info.getCapturedVars()) { for (CapturedParamInfo var : info.getCapturedVars()) {
CapturedParamInfo recapturedParamInfo = builder.addCapturedParam(var, getNewFieldName(var.getOriginalFieldName())); CapturedParamInfo recapturedParamInfo = capturedParamBuilder.addCapturedParam(var,
getNewFieldName(var.getOriginalFieldName()));
StackValue composed = StackValue.composed(StackValue.local(0, oldObjectType), StackValue composed = StackValue.composed(StackValue.local(0, oldObjectType),
StackValue.field(var.getType(), StackValue.field(var.getType(),
oldObjectType, /*TODO owner type*/ oldObjectType, /*TODO owner type*/
@@ -280,10 +362,18 @@ public class LambdaTransformer {
); );
recapturedParamInfo.setRemapValue(composed); recapturedParamInfo.setRemapValue(composed);
allRecapturedParameters.add(var); allRecapturedParameters.add(var);
constructorParamBuilder.addCapturedParam(var, recapturedParamInfo.getNewFieldName()).setRemapValue(composed);
} }
capturedLambdasToInline.put(info.getLambdaClassType().getInternalName(), info); 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.setAllRecapturedParameters(allRecapturedParameters);
invocation.setCapturedLambdasToInline(capturedLambdasToInline); invocation.setCapturedLambdasToInline(capturedLambdasToInline);
} }
@@ -352,7 +352,7 @@ public class MethodInliner {
} }
} }
constructorInvocations.add(new ConstructorInvocation(owner, lambdaMapping, isSameModule, inliningContext.classRegeneration)); constructorInvocations.add(new ConstructorInvocation(owner, desc, lambdaMapping, isSameModule, inliningContext.classRegeneration));
} }
} }
} }
@@ -28,6 +28,8 @@ class ParameterInfo {
protected final int index; protected final int index;
private boolean isCaptured;
public final Type type; public final Type type;
//for skipped parameter: e.g. inlined lambda //for skipped parameter: e.g. inlined lambda
@@ -87,4 +89,12 @@ class ParameterInfo {
public void setRemapValue(StackValue remapValue) { public void setRemapValue(StackValue remapValue) {
this.remapValue = remapValue; this.remapValue = remapValue;
} }
public boolean isCaptured() {
return isCaptured;
}
public void setCaptured(boolean isCaptured) {
this.isCaptured = isCaptured;
}
} }
@@ -88,10 +88,10 @@ public class Parameters implements Iterable<ParameterInfo> {
ArrayList<Type> result = new ArrayList<Type>(); ArrayList<Type> result = new ArrayList<Type>();
for (CapturedParamInfo info : captured) { for (CapturedParamInfo info : captured) {
if(info != CapturedParamInfo.STUB) { if(info != CapturedParamInfo.STUB) {
Type type = info.getType(); result.add(info.getType());
result.add(type);
} }
} }
return result; return result;
} }
} }
@@ -43,9 +43,8 @@ public class ParametersBuilder {
} }
@NotNull @NotNull
public ParametersBuilder addNextParameter(@NotNull Type type, boolean skipped, @Nullable ParameterInfo original) { public ParameterInfo addNextParameter(@NotNull Type type, boolean skipped, @Nullable ParameterInfo original) {
addParameter(new ParameterInfo(type, skipped, nextIndex, original != null ? original.getIndex() : -1)); return addParameter(new ParameterInfo(type, skipped, nextIndex, original != null ? original.getIndex() : -1));
return this;
} }
@NotNull @NotNull
@@ -83,9 +82,10 @@ public class ParametersBuilder {
return addCapturedParameter(info); return addCapturedParameter(info);
} }
private void addParameter(ParameterInfo info) { private ParameterInfo addParameter(ParameterInfo info) {
params.add(info); params.add(info);
nextIndex += info.getType().getSize(); nextIndex += info.getType().getSize();
return info;
} }
private CapturedParamInfo addCapturedParameter(CapturedParamInfo info) { private CapturedParamInfo addCapturedParameter(CapturedParamInfo info) {
@@ -94,27 +94,30 @@ public class ParametersBuilder {
return info; return info;
} }
public List<ParameterInfo> build() { @NotNull
public List<ParameterInfo> listNotCaptured() {
return Collections.unmodifiableList(params); return Collections.unmodifiableList(params);
} }
public List<CapturedParamInfo> buildCaptured() { @NotNull
public List<CapturedParamInfo> listCaptured() {
return Collections.unmodifiableList(capturedParams); return Collections.unmodifiableList(capturedParams);
} }
public List<ParameterInfo> buildWithStubs() { @NotNull
return Parameters.addStubs(build()); private List<ParameterInfo> buildWithStubs() {
return Parameters.addStubs(listNotCaptured());
} }
public List<CapturedParamInfo> buildCapturedWithStubs() { private List<CapturedParamInfo> buildCapturedWithStubs() {
return Parameters.shiftAndAddStubs(buildCaptured(), nextIndex); return Parameters.shiftAndAddStubs(listCaptured(), nextIndex);
} }
public Parameters buildParameters() { public Parameters buildParameters() {
return new Parameters(buildWithStubs(), buildCapturedWithStubs()); return new Parameters(buildWithStubs(), buildCapturedWithStubs());
} }
public List<CapturedParamInfo> getCapturedParams() { public int getNextValueParameterIndex() {
return capturedParams; return nextIndex;
} }
} }
@@ -0,0 +1,30 @@
import test.*
fun test1(): String {
val o = "O"
val result = doWork ({o}, {"K"})
return result.getO() + result.getK()
}
fun test2() : String {
//same names as in object
val o1 = "O"
val k1 = "K"
val result = doWorkInConstructor ({o1}, {k1})
return result.getO() + result.getK()
}
fun box() : String {
val result1 = test1();
if (result1 != "OK") return "fail1 $result1"
val result2 = test2();
if (result2 != "OK") return "fail2 $result2"
return "OK"
}
@@ -0,0 +1,36 @@
package test
abstract class A<R> {
abstract fun getO() : R
abstract fun getK() : R
}
inline fun <R> doWork(jobO: ()-> R, jobK: ()-> R) : A<R> {
val s = object : A<R>() {
override fun getO(): R {
return jobO()
}
override fun getK(): R {
return jobK()
}
}
return s;
}
inline fun <R> doWorkInConstructor(jobO: ()-> R, jobK: ()-> R) : A<R> {
val s = object : A<R>() {
val o1 = jobO()
val k1 = jobK()
override fun getO(): R {
return o1
}
override fun getK(): R {
return k1
}
}
return s;
}
@@ -0,0 +1,30 @@
import test.*
fun test1(): String {
val o = "O"
val result = doWork ({o}, {"K"}, "11")
return result.getO() + result.getK() + result.param
}
fun test2() : String {
//same names as in object
val o1 = "O"
val k1 = "K"
val param = "11"
val result = doWorkInConstructor ({o1}, {k1}, {param})
return result.getO() + result.getK() + result.param
}
fun box() : String {
val result1 = test1();
if (result1 != "OK11") return "fail1 $result1"
val result2 = test2();
if (result2 != "OK11") return "fail2 $result2"
return "OK"
}
@@ -0,0 +1,36 @@
package test
abstract class A<R>(val param : R) {
abstract fun getO() : R
abstract fun getK() : R
}
inline fun <R> doWork(jobO: ()-> R, jobK: ()-> R, param: R) : A<R> {
val s = object : A<R>(param) {
override fun getO(): R {
return jobO()
}
override fun getK(): R {
return jobK()
}
}
return s;
}
inline fun <R> doWorkInConstructor(jobO: ()-> R, jobK: ()-> R, param: () -> R) : A<R> {
val s = object : A<R>(param()) {
val o1 = jobO()
val k1 = jobK()
override fun getO(): R {
return o1
}
override fun getK(): R {
return k1
}
}
return s;
}
@@ -41,9 +41,19 @@ public class BlackBoxInlineCodegenTestGenerated extends AbstractBlackBoxCodegenT
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite"); doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite");
} }
@TestMetadata("anonymousObjectSuperParams") @TestMetadata("anonymousObjectOnCallSiteSuperParams")
public void testAnonymousObjectSuperParams() throws Exception { public void testAnonymousObjectOnCallSiteSuperParams() throws Exception {
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectSuperParams"); doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSiteSuperParams");
}
@TestMetadata("anonymousObjectOnDeclarationSite")
public void testAnonymousObjectOnDeclarationSite() throws Exception {
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite");
}
@TestMetadata("anonymousObjectOnDeclarationSiteSuperParams")
public void testAnonymousObjectOnDeclarationSiteSuperParams() throws Exception {
doTestMultiFileWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSiteSuperParams");
} }
@TestMetadata("builders") @TestMetadata("builders")
@@ -41,9 +41,19 @@ public class CompileKotlinAgainstInlineKotlinTestGenerated extends AbstractCompi
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite"); doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSite");
} }
@TestMetadata("anonymousObjectSuperParams") @TestMetadata("anonymousObjectOnCallSiteSuperParams")
public void testAnonymousObjectSuperParams() throws Exception { public void testAnonymousObjectOnCallSiteSuperParams() throws Exception {
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectSuperParams"); doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnCallSiteSuperParams");
}
@TestMetadata("anonymousObjectOnDeclarationSite")
public void testAnonymousObjectOnDeclarationSite() throws Exception {
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSite");
}
@TestMetadata("anonymousObjectOnDeclarationSiteSuperParams")
public void testAnonymousObjectOnDeclarationSiteSuperParams() throws Exception {
doBoxTestWithInlineCheck("compiler/testData/codegen/boxInline/anonymousObjectOnDeclarationSiteSuperParams");
} }
@TestMetadata("builders") @TestMetadata("builders")