diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index c5853937e3a..428c3ee2e3a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -2209,17 +2209,22 @@ public class ExpressionCodegen extends JetVisitor implem @Nullable private StackValue genSamInterfaceValue( - @NotNull final JetExpression expression, + @NotNull JetExpression probablyParenthesizedExpression, @NotNull final JetVisitor visitor ) { - final SamType samType = bindingContext.get(SAM_VALUE, expression); - if (samType == null) return null; + final JetExpression expression = JetPsiUtil.deparenthesize(probablyParenthesizedExpression); + final SamType samType = bindingContext.get(SAM_VALUE, probablyParenthesizedExpression); + if (samType == null || expression == null) return null; if (expression instanceof JetFunctionLiteralExpression) { return genClosure(((JetFunctionLiteralExpression) expression).getFunctionLiteral(), samType, KotlinSyntheticClass.Kind.SAM_LAMBDA); } + if (expression instanceof JetNamedFunction) { + return genClosure((JetNamedFunction) expression, samType, KotlinSyntheticClass.Kind.SAM_LAMBDA); + } + final Type asmType = state.getSamWrapperClasses().getSamWrapperClass(samType, expression.getContainingJetFile(), getParentCodegen()); diff --git a/compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/Test.java b/compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/Test.java new file mode 100644 index 00000000000..aeff3d5115c --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/Test.java @@ -0,0 +1,15 @@ +import java.lang.Runnable; + +class Test { + public static Class apply(Runnable x) { + return x.getClass(); + } + + public static interface ABC { + void apply(String x1, String x2); + } + + public static Class applyABC(ABC x) { + return x.getClass(); + } +} diff --git a/compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/annotatedSamFunExpression.kt b/compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/annotatedSamFunExpression.kt new file mode 100644 index 00000000000..798e6a86839 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/annotatedSamFunExpression.kt @@ -0,0 +1,29 @@ +import java.lang.annotation.* +import java.lang.reflect.Method +import kotlin.reflect.jvm.java +import kotlin.test.assertEquals + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val x: String) + +fun testMethod(method: Method, name: String) { + assertEquals("OK", method.getAnnotation(javaClass()).x, "On method of test named `$name`") + + for ((index, annotations) in method.getParameterAnnotations().withIndex()) { + val ann = annotations.filterIsInstance().single() + assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`") + } +} + +fun testClass(clazz: Class<*>, name: String) { + val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() } + testMethod(invokes, name) +} + +fun box(): String { + testClass(Test.apply(@Ann("OK") fun(){}), "1") + + testClass(Test.applyABC(@Ann("OK") fun(@Ann("OK0") x: String, @Ann("OK1") y: String){}), "2") + + return "OK" +} diff --git a/compiler/testData/codegen/boxWithJava/annotatedSamLambda/Test.java b/compiler/testData/codegen/boxWithJava/annotatedSamLambda/Test.java new file mode 100644 index 00000000000..b3e5d731ed2 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/annotatedSamLambda/Test.java @@ -0,0 +1,7 @@ +import java.lang.Runnable; + +class Test { + public static Class apply(Runnable x) { + return x.getClass(); + } +} diff --git a/compiler/testData/codegen/boxWithJava/annotatedSamLambda/annotatedSamLambda.kt b/compiler/testData/codegen/boxWithJava/annotatedSamLambda/annotatedSamLambda.kt new file mode 100644 index 00000000000..1b43fadddd4 --- /dev/null +++ b/compiler/testData/codegen/boxWithJava/annotatedSamLambda/annotatedSamLambda.kt @@ -0,0 +1,27 @@ +import java.lang.annotation.* +import java.lang.reflect.Method +import kotlin.reflect.jvm.java +import kotlin.test.assertEquals + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val x: String) + +fun testMethod(method: Method, name: String) { + assertEquals("OK", method.getAnnotation(javaClass()).x, "On method of test named `$name`") + + for ((index, annotations) in method.getParameterAnnotations().withIndex()) { + val ann = annotations.filterIsInstance().single() + assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`") + } +} + +fun testClass(clazz: Class<*>, name: String) { + val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() } + testMethod(invokes, name) +} + +fun box(): String { + testClass(Test.apply(@Ann("OK") {}), "1") + testClass(Test.apply @Ann("OK") {}, "2") + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/funExpression.kt b/compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/funExpression.kt new file mode 100644 index 00000000000..e1a35abe22b --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/funExpression.kt @@ -0,0 +1,30 @@ +import java.lang.annotation.* +import java.lang.reflect.Method +import kotlin.reflect.jvm.java +import kotlin.test.assertEquals + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val x: String) + +fun foo0(block: () -> Unit) = block.javaClass +fun foo1(block: (String) -> Unit) = block.javaClass + +fun testMethod(method: Method, name: String) { + assertEquals("OK", method.getAnnotation(javaClass()).x, "On method of test named `$name`") + + for ((index, annotations) in method.getParameterAnnotations().withIndex()) { + val ann = annotations.filterIsInstance().single() + assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`") + } +} + +fun testClass(clazz: Class<*>, name: String) { + val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() } + testMethod(invokes, name) +} + +fun box(): String { + testClass(foo0( @Ann("OK") fun() {} ), "1") + testClass(foo1( @Ann("OK") fun(@Ann("OK0") x: String) {} ), "2") + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/lambda.kt b/compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/lambda.kt new file mode 100644 index 00000000000..882242a90ee --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/lambda.kt @@ -0,0 +1,31 @@ +import java.lang.annotation.* +import java.lang.reflect.Method +import kotlin.reflect.jvm.java +import kotlin.test.assertEquals + +Retention(RetentionPolicy.RUNTIME) +annotation class Ann(val x: String) + +fun foo0(block: () -> Unit) = block.javaClass + +fun testMethod(method: Method, name: String) { + assertEquals("OK", method.getAnnotation(javaClass()).x, "On method of test named `$name`") + + for ((index, annotations) in method.getParameterAnnotations().withIndex()) { + val ann = annotations.filterIsInstance().single() + assertEquals("OK$index", ann.x, "On parameter $index of test named `$name`") + } +} + +fun testClass(clazz: Class<*>, name: String) { + val invokes = clazz.getDeclaredMethods().single() { !it.isBridge() } + testMethod(invokes, name) +} + +fun box(): String { + testClass(foo0([Ann("OK")] { }), "1") + testClass(foo0( @Ann("OK") { }), "2") + + testClass(foo0() @Ann("OK") { }, "3") + return "OK" +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java index 579b41c3121..72dd17b4f5b 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithJavaCodegenTestGenerated.java @@ -35,6 +35,18 @@ public class BlackBoxWithJavaCodegenTestGenerated extends AbstractBlackBoxCodege JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithJava"), Pattern.compile("^([^\\.]+)$"), true); } + @TestMetadata("annotatedSamFunExpression") + public void testAnnotatedSamFunExpression() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/annotatedSamFunExpression/"); + doTestWithJava(fileName); + } + + @TestMetadata("annotatedSamLambda") + public void testAnnotatedSamLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/annotatedSamLambda/"); + doTestWithJava(fileName); + } + @TestMetadata("classObjectAccessor") public void testClassObjectAccessor() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithJava/classObjectAccessor/"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index 94602274ac0..b8144eae990 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -102,6 +102,27 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/varargInAnnotationParameter.kt"); doTestWithStdlib(fileName); } + + @TestMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda") + @TestDataPath("$PROJECT_ROOT") + @RunWith(JUnit3RunnerWithInners.class) + public static class AnnotatedLambda extends AbstractBlackBoxCodegenTest { + public void testAllFilesPresentInAnnotatedLambda() throws Exception { + JetTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda"), Pattern.compile("^(.+)\\.kt$"), true); + } + + @TestMetadata("funExpression.kt") + public void testFunExpression() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/funExpression.kt"); + doTestWithStdlib(fileName); + } + + @TestMetadata("lambda.kt") + public void testLambda() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/annotations/annotatedLambda/lambda.kt"); + doTestWithStdlib(fileName); + } + } } @TestMetadata("compiler/testData/codegen/boxWithStdlib/arrays")