diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index b5e105cad92..986525b38d7 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -56,6 +56,7 @@ import org.jetbrains.jet.lang.resolve.java.AsmTypeConstants; import org.jetbrains.jet.lang.resolve.java.JvmAbi; import org.jetbrains.jet.lang.resolve.java.JvmClassName; import org.jetbrains.jet.lang.resolve.java.JvmPrimitiveType; +import org.jetbrains.jet.lang.resolve.java.sam.SingleAbstractMethodUtils; import org.jetbrains.jet.lang.resolve.name.Name; import org.jetbrains.jet.lang.resolve.scopes.receivers.*; import org.jetbrains.jet.lang.types.JetType; @@ -1790,6 +1791,15 @@ public class ExpressionCodegen extends JetVisitor implem } } + @Nullable + private SimpleFunctionDescriptor getOriginalIfSamAdapter(@NotNull CallableDescriptor fun) { + if (!(fun instanceof SimpleFunctionDescriptor)) { + return null; + } + SimpleFunctionDescriptor original = ((SimpleFunctionDescriptor) fun).getOriginal(); + return bindingContext.get(SAM_ADAPTER_FUNCTION_TO_ORIGINAL, original); + } + private StackValue invokeSamConstructor( JetCallExpression expression, ResolvedCall resolvedCall, @@ -1967,7 +1977,8 @@ public class ExpressionCodegen extends JetVisitor implem callableMethod = typeMapper.asCallableMethod(invoke); } else { - callableMethod = typeMapper.mapToCallableMethod(fd, superCall, + SimpleFunctionDescriptor originalOfSamAdapter = getOriginalIfSamAdapter(fd); + callableMethod = typeMapper.mapToCallableMethod(originalOfSamAdapter != null ? originalOfSamAdapter : fd, superCall, isCallInsideSameClassAsDeclared(fd, context), isCallInsideSameModuleAsDeclared(fd, context), OwnerKind.IMPLEMENTATION); @@ -2214,12 +2225,27 @@ public class ExpressionCodegen extends JetVisitor implem int mask = 0; + SimpleFunctionDescriptor originalOfSamAdapter = getOriginalIfSamAdapter(fd); + for (ValueParameterDescriptor valueParameter : fd.getValueParameters()) { ResolvedValueArgument resolvedValueArgument = valueArguments.get(valueParameter.getIndex()); if (resolvedValueArgument instanceof ExpressionValueArgument) { - ExpressionValueArgument valueArgument = (ExpressionValueArgument) resolvedValueArgument; - //noinspection ConstantConditions - gen(valueArgument.getValueArgument().getArgumentExpression(), valueParameterTypes.get(valueParameter.getIndex())); + ValueArgument valueArgument = ((ExpressionValueArgument) resolvedValueArgument).getValueArgument(); + assert valueArgument != null; + JetExpression argumentExpression = valueArgument.getArgumentExpression(); + assert argumentExpression != null : valueArgument.asElement().getText(); + + if (originalOfSamAdapter != null) { + JetType samAdapterType = originalOfSamAdapter.getValueParameters().get(valueParameter.getIndex()).getType(); + if (SingleAbstractMethodUtils.isSamType(samAdapterType)) { + ClassDescriptor samInterface = (ClassDescriptor) samAdapterType.getConstructor().getDeclarationDescriptor(); + + // TODO support not literals + genClosure(((JetFunctionLiteralExpression) argumentExpression).getFunctionLiteral(), samInterface); + continue; + } + } + gen(argumentExpression, valueParameterTypes.get(valueParameter.getIndex())); } else if (resolvedValueArgument instanceof DefaultValueArgument) { Type type = valueParameterTypes.get(valueParameter.getIndex()); diff --git a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java index f9eeb2d488a..ac2e63af270 100644 --- a/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java +++ b/compiler/frontend.java/src/org/jetbrains/jet/lang/resolve/java/sam/SingleAbstractMethodUtils.java @@ -134,7 +134,7 @@ public class SingleAbstractMethodUtils { return result; } - private static boolean isSamType(@NotNull JetType type) { + public static boolean isSamType(@NotNull JetType type) { ClassifierDescriptor classifier = type.getConstructor().getDeclarationDescriptor(); return classifier instanceof ClassDescriptorFromJvmBytecode && ((ClassDescriptorFromJvmBytecode) classifier).isSamInterface() && diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/comparator.java b/compiler/testData/codegen/boxWithJava/samAdapters/comparator.java new file mode 100644 index 00000000000..1d6843c1a82 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/comparator.java @@ -0,0 +1,7 @@ +import java.util.*; + +class JavaClass { + public static void sortIntList(List list, Comparator comparator) { + Collections.sort(list, comparator); + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/comparator.kt b/compiler/testData/codegen/boxWithJava/samAdapters/comparator.kt new file mode 100644 index 00000000000..57932c64f29 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/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)) + JavaClass.sortIntList(list, { a, b -> b - a }) + return if (list == expected) "OK" else list.toString() +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.java b/compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.java new file mode 100644 index 00000000000..b0f6a35b314 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.java @@ -0,0 +1,7 @@ +import java.io.*; + +class JavaClass { + public static String invokeFilter(FileFilter f, File file1, File file2) { + return f.accept(file1) + " " + f.accept(file2); + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.kt b/compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.kt new file mode 100644 index 00000000000..08f4a5d21ff --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.kt @@ -0,0 +1,11 @@ +import java.io.* + +fun box(): String { + val ACCEPT_NAME = "test" + val WRONG_NAME = "wrong" + + val result = JavaClass.invokeFilter({ file -> ACCEPT_NAME == file?.getName() }, File(ACCEPT_NAME), File(WRONG_NAME)) + + if (result != "true false") return "Wrong result: $result" + return "OK" +} diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/simplest.java b/compiler/testData/codegen/boxWithJava/samAdapters/simplest.java new file mode 100644 index 00000000000..3860797a795 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/simplest.java @@ -0,0 +1,5 @@ +class JavaClass { + public static void run(Runnable r) { + r.run(); + } +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithJava/samAdapters/simplest.kt b/compiler/testData/codegen/boxWithJava/samAdapters/simplest.kt new file mode 100644 index 00000000000..d0b28745431 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/samAdapters/simplest.kt @@ -0,0 +1,5 @@ +fun box(): String { + var v = "FAIL" + JavaClass.run { v = "OK" } + return v +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 200983a5150..cd20a9b84d8 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -31,7 +31,7 @@ import org.jetbrains.jet.codegen.generated.AbstractBlackBoxCodegenTest; /** This class is generated by {@link org.jetbrains.jet.generators.tests.GenerateTests}. DO NOT MODIFY MANUALLY */ @SuppressWarnings("all") @TestMetadata("compiler/testData/codegen/boxWithJava") -@InnerTestClasses({BlackBoxWithJavaCodegenTestGenerated.Enum.class, BlackBoxWithJavaCodegenTestGenerated.Functions.class, BlackBoxWithJavaCodegenTestGenerated.Property.class, BlackBoxWithJavaCodegenTestGenerated.StaticFun.class, BlackBoxWithJavaCodegenTestGenerated.Visibility.class}) +@InnerTestClasses({BlackBoxWithJavaCodegenTestGenerated.Enum.class, BlackBoxWithJavaCodegenTestGenerated.Functions.class, BlackBoxWithJavaCodegenTestGenerated.Property.class, BlackBoxWithJavaCodegenTestGenerated.SamAdapters.class, BlackBoxWithJavaCodegenTestGenerated.StaticFun.class, BlackBoxWithJavaCodegenTestGenerated.Visibility.class}) public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInBoxWithJava() throws Exception { JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithJava"), Pattern.compile("^(.+)\\.kt$"), true); @@ -111,6 +111,29 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege } + @TestMetadata("compiler/testData/codegen/boxWithJava/samAdapters") + public static class SamAdapters extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInSamAdapters() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), "org.jetbrains.jet.generators.tests.GenerateTests", new File("compiler/testData/codegen/boxWithJava/samAdapters"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("comparator.kt") + public void testComparator() throws Exception { + doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/comparator.kt"); + } + + @TestMetadata("fileFilter.kt") + public void testFileFilter() throws Exception { + doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/fileFilter.kt"); + } + + @TestMetadata("simplest.kt") + public void testSimplest() throws Exception { + doTestWithJava("compiler/testData/codegen/boxWithJava/samAdapters/simplest.kt"); + } + + } + @TestMetadata("compiler/testData/codegen/boxWithJava/staticFun") public static class StaticFun extends AbstractBlackBoxCodegenTest { public void testAllFilesPresentInStaticFun() throws Exception { @@ -271,6 +294,7 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege suite.addTestSuite(Enum.class); suite.addTestSuite(Functions.class); suite.addTestSuite(Property.class); + suite.addTestSuite(SamAdapters.class); suite.addTestSuite(StaticFun.class); suite.addTest(Visibility.innerSuite()); return suite;