From 91282b992dd3a50aa6c293312481fded23ad0bf5 Mon Sep 17 00:00:00 2001 From: Evgeny Gerashchenko Date: Mon, 18 Mar 2013 21:01:27 +0400 Subject: [PATCH] Supported functional interfaces with generic parameters in codegen. --- .../jetbrains/jet/codegen/ClosureCodegen.java | 49 ++++++++++++------- .../jet/codegen/ExpressionCodegen.java | 2 +- .../testData/codegen/box/sam/comparator.kt | 8 +++ .../AbstractBlackBoxCodegenTest.java | 2 +- .../BlackBoxCodegenTestGenerated.java | 5 ++ 5 files changed, 45 insertions(+), 21 deletions(-) create mode 100644 compiler/testData/codegen/box/sam/comparator.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java index fb8b0cd58cb..1d19a950bdb 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ClosureCodegen.java @@ -42,6 +42,7 @@ import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.types.JetType; +import org.jetbrains.jet.lang.types.lang.KotlinBuiltIns; import java.util.List; @@ -74,12 +75,12 @@ public class ClosureCodegen extends GenerationStateAware { FunctionDescriptor funDescriptor = bindingContext.get(BindingContext.FUNCTION, fun); assert funDescriptor != null; - Name interfaceFunctionName; + FunctionDescriptor interfaceFunction; if (samInterface == null) { - interfaceFunctionName = Name.identifier("invoke"); + interfaceFunction = getInvokeFunction(funDescriptor); } else { - interfaceFunctionName = SingleAbstractMethodUtils.getAbstractMethodOfFunctionalInterface(samInterface).getName(); + interfaceFunction = SingleAbstractMethodUtils.getAbstractMethodOfFunctionalInterface(samInterface); } SignatureWriter signatureWriter = new SignatureWriter(); @@ -109,10 +110,8 @@ public class ClosureCodegen extends GenerationStateAware { cv.visitSource(fun.getContainingFile().getName(), null); - if (samInterface == null) { // TODO temporary: if SAM interface is generic, we'll need bridge - generateBridge(interfaceFunctionName, name.getInternalName(), funDescriptor, fun, cv); - } - generateBody(interfaceFunctionName, funDescriptor, cv, fun, context, expressionCodegen); + generateBridge(interfaceFunction, name.getInternalName(), funDescriptor, fun, cv); + generateBody(interfaceFunction.getName(), funDescriptor, cv, fun, context, expressionCodegen); constructor = generateConstructor(funClass, fun, cv, closure); @@ -161,22 +160,23 @@ public class ClosureCodegen extends GenerationStateAware { } private void generateBridge( - Name interfaceFunctionName, + FunctionDescriptor interfaceFunction, String className, FunctionDescriptor funDescriptor, JetExpression fun, ClassBuilder cv ) { - JvmMethodSignature bridge = erasedInvokeSignature(funDescriptor); - Method delegate = typeMapper.mapSignature(interfaceFunctionName, funDescriptor).getAsmMethod(); + Method bridge = typeMapper.mapSignature(interfaceFunction.getName(), interfaceFunction).getAsmMethod(); - if (bridge.getAsmMethod().getDescriptor().equals(delegate.getDescriptor())) { + Method delegate = typeMapper.mapSignature(interfaceFunction.getName(), funDescriptor).getAsmMethod(); + + if (bridge.getDescriptor().equals(delegate.getDescriptor())) { return; } - MethodVisitor mv = - cv.newMethod(fun, ACC_PUBLIC | ACC_BRIDGE | ACC_VOLATILE, "invoke", bridge.getAsmMethod().getDescriptor(), null, - new String[0]); + MethodVisitor mv = cv.newMethod( + fun, ACC_PUBLIC | ACC_BRIDGE | ACC_VOLATILE, interfaceFunction.getName().getName(), + bridge.getDescriptor(), null, new String[0]); if (state.getClassBuilderMode() == ClassBuilderMode.STUBS) { genStubCode(mv); } @@ -190,20 +190,20 @@ public class ClosureCodegen extends GenerationStateAware { ReceiverParameterDescriptor receiver = funDescriptor.getReceiverParameter(); int count = 1; if (receiver != null) { - StackValue.local(count, OBJECT_TYPE).put(typeMapper.mapType(receiver.getType()), iv); + StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(receiver.getType()), iv); count++; } List params = funDescriptor.getValueParameters(); for (ValueParameterDescriptor param : params) { - StackValue.local(count, OBJECT_TYPE).put(typeMapper.mapType(param.getType()), iv); + StackValue.local(count, bridge.getArgumentTypes()[count - 1]).put(typeMapper.mapType(param.getType()), iv); count++; } - iv.invokevirtual(className, "invoke", delegate.getDescriptor()); - StackValue.onStack(delegate.getReturnType()).put(OBJECT_TYPE, iv); + iv.invokevirtual(className, interfaceFunction.getName().getName(), delegate.getDescriptor()); + StackValue.onStack(delegate.getReturnType()).put(bridge.getReturnType(), iv); - iv.areturn(OBJECT_TYPE); + iv.areturn(bridge.getReturnType()); FunctionCodegen.endVisit(mv, "bridge", fun); } @@ -306,4 +306,15 @@ public class ClosureCodegen extends GenerationStateAware { signatureWriter.visitClassType(rawRetType.getInternalName()); signatureWriter.visitEnd(); } + + private static FunctionDescriptor getInvokeFunction(FunctionDescriptor funDescriptor) { + FunctionDescriptor interfaceFunction; + int paramCount = funDescriptor.getValueParameters().size(); + KotlinBuiltIns builtIns = KotlinBuiltIns.getInstance(); + ClassDescriptor funClass = funDescriptor.getReceiverParameter() == null + ? builtIns.getFunction(paramCount) + : builtIns.getExtensionFunction(paramCount); + interfaceFunction = funClass.getDefaultType().getMemberScope().getFunctions(Name.identifier("invoke")).iterator().next(); + return interfaceFunction; + } } diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 38c877d5490..08d5b296a55 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -1888,7 +1888,7 @@ public class ExpressionCodegen extends JetVisitor implem else { if (funDescriptor instanceof SimpleFunctionDescriptor) { ClassDescriptor samTrait = bindingContext.get( - BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, (SimpleFunctionDescriptor) funDescriptor); + BindingContext.SAM_CONSTRUCTOR_TO_TRAIT, ((SimpleFunctionDescriptor) funDescriptor).getOriginal()); if (samTrait != null) { JetFunctionLiteralExpression argumentExpression = (JetFunctionLiteralExpression) ((ExpressionValueArgument) resolvedCall.getValueArgumentsByIndex().get(0)).getValueArgument() diff --git a/compiler/testData/codegen/box/sam/comparator.kt b/compiler/testData/codegen/box/sam/comparator.kt new file mode 100644 index 00000000000..d791fa72d1f --- /dev/null +++ b/compiler/testData/codegen/box/sam/comparator.kt @@ -0,0 +1,8 @@ +import java.util.* + +fun box(): String { + val list = ArrayList(Arrays.asList(3, 2, 4, 8, 1, 5)) + val expected = ArrayList(Arrays.asList(8, 5, 4, 3, 2, 1)) + Collections.sort(list, Comparator { a, b -> b - a }) + return if (list == expected) "OK" else list.toString() +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java b/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java index 20ced0bdf39..39bebafa62d 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/AbstractBlackBoxCodegenTest.java @@ -41,7 +41,7 @@ import static org.jetbrains.jet.codegen.CodegenTestUtil.compileJava; public abstract class AbstractBlackBoxCodegenTest extends CodegenTestCase { public void doTest(@NotNull String filename) { - createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_ONLY); + createEnvironmentWithMockJdkAndIdeaAnnotations(ConfigurationKind.JDK_AND_ANNOTATIONS); blackBoxFileByFullPath(filename); } diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index e4b641687ba..3def89030d7 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -3159,6 +3159,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/box/sam"), Pattern.compile("^(.+)\\.kt$"), true); } + @TestMetadata("comparator.kt") + public void testComparator() throws Exception { + doTest("compiler/testData/codegen/box/sam/comparator.kt"); + } + @TestMetadata("filenameFilter.kt") public void testFilenameFilter() throws Exception { doTest("compiler/testData/codegen/box/sam/filenameFilter.kt");