Supported functional interfaces with generic parameters in codegen.
This commit is contained in:
@@ -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<ValueParameterDescriptor> 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;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1888,7 +1888,7 @@ public class ExpressionCodegen extends JetVisitor<StackValue, StackValue> 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()
|
||||
|
||||
@@ -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()
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
|
||||
|
||||
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user