diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenStatementVisitor.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenStatementVisitor.java index 7240288c716..f6a0be5626c 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenStatementVisitor.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/CodegenStatementVisitor.java @@ -41,6 +41,11 @@ public class CodegenStatementVisitor extends JetVisitor return codegen.generateTryExpression(expression, true); } + @Override + public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data) { + return codegen.visitNamedFunction(function, data, true); + } + @Override public StackValue visitWhenExpression(@NotNull JetWhenExpression expression, StackValue data) { return codegen.generateWhenExpression(expression, true); diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java index fc907090a7c..72daa45a10a 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/ExpressionCodegen.java @@ -1346,6 +1346,10 @@ public class ExpressionCodegen extends JetVisitor implem @Override public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data) { + return visitNamedFunction(function, data, false); + } + + public StackValue visitNamedFunction(@NotNull JetNamedFunction function, StackValue data, boolean isStatement) { assert data == StackValue.none(); if (JetPsiUtil.isScriptDeclaration(function)) { @@ -1353,11 +1357,16 @@ public class ExpressionCodegen extends JetVisitor implem } StackValue closure = genClosure(function, null, KotlinSyntheticClass.Kind.LOCAL_FUNCTION); - DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); - int index = lookupLocalIndex(descriptor); - closure.put(OBJECT_TYPE, v); - v.store(index, OBJECT_TYPE); - return StackValue.none(); + if (isStatement) { + DeclarationDescriptor descriptor = bindingContext.get(DECLARATION_TO_DESCRIPTOR, function); + int index = lookupLocalIndex(descriptor); + closure.put(OBJECT_TYPE, v); + v.store(index, OBJECT_TYPE); + return StackValue.none(); + } + else { + return closure; + } } @Override diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java index eec22104791..4e2c9560b80 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/JetTypeMapper.java @@ -621,9 +621,6 @@ public class JetTypeMapper { return isAccessor ? "access$" + accessorName : accessorName; } - else if (isLocalNamedFun(descriptor)) { - return "invoke"; - } else if (descriptor instanceof AnonymousFunctionDescriptor) { PsiElement element = DescriptorToSourceUtils.getSourceFromDescriptor(descriptor); if (element instanceof JetFunctionLiteral) { @@ -638,6 +635,9 @@ public class JetTypeMapper { return "invoke"; } + else if (isLocalFunOrLambda(descriptor)) { + return "invoke"; + } else { return descriptor.getName().asString(); } diff --git a/compiler/testData/codegen/box/functions/functionExpression.kt b/compiler/testData/codegen/box/functions/functionExpression.kt index aaeadaf0c56..d40bdd72916 100644 --- a/compiler/testData/codegen/box/functions/functionExpression.kt +++ b/compiler/testData/codegen/box/functions/functionExpression.kt @@ -1,25 +1,32 @@ -fun Any.foo1() : ()-> String { - return { "239" + this } +val foo1 = fun Any.(): String { +return "239" + this } -fun Int.foo2() : (i : Int) -> Int { - return { x -> x + this } -} +val foo2 = fun Int.(i : Int) : Int = this + i -fun fooT1(t : T) = { t.toString() } +fun fooT1() = fun (t : T) = t.toString() -fun fooT2(t: T) = { (x:T) -> t.toString() + x.toString() } +annotation class A fun box() : String { - if( (10.foo1())() != "23910") return "foo1 fail" - if( (10.foo2())(1) != 11 ) return "foo2 fail" + if(10.foo1() != "23910") return "foo1 fail" + if(10.foo2(1) != 11) return "foo2 fail" - if(1.{Int.() -> this + 1}() != 2) return "test 3 failed"; - if( {1}() != 1) return "test 4 failed"; - if( {(x : Int) -> x}(1) != 1) return "test 5 failed"; - if( 1.{Int.(x : Int) -> x + this}(1) != 2) return "test 6 failed"; - if( 1.({Int.() -> this})() != 1) return "test 7 failed"; - if( (fooT1("mama"))() != "mama") return "test 8 failed"; - if( (fooT2("mama"))("papa") != "mamapapa") return "test 9 failed"; - return "OK" + if(1.(fun Int.() = this + 1)() != 2) return "test 3 failed"; + if( (fun () = 1)() != 1) return "test 4 failed"; + if( (fun (i: Int) = i)(1) != 1) return "test 5 failed"; + if( 1.(fun Int.(i: Int) = i + this)(1) != 2) return "test 6 failed"; + if( (fooT1()("mama")) != "mama") return "test 7 failed"; + + val a = [A] fun Int.() = this + 1 // + if (1.a() != 2) return "test 8 failed" + val b = ( fun Int.() = this + 1) + if (1.a() != 2) return "test 9 failed" + val c = (@c fun Int.() = this + 1) + if (1.a() != 2) return "test 10 failed" + + val d = @d fun (): Int { return@d 4} + if (d() != 4) return "test 11 failed" + + return "OK" } diff --git a/compiler/testData/codegen/box/functions/functionExpressionWithName.kt b/compiler/testData/codegen/box/functions/functionExpressionWithName.kt new file mode 100644 index 00000000000..13d61b76b80 --- /dev/null +++ b/compiler/testData/codegen/box/functions/functionExpressionWithName.kt @@ -0,0 +1,32 @@ +val foo1 = fun Any.name(): String { +return "239" + this +} + +val foo2 = fun Int.name(i : Int) : Int = this + i + +fun fooT1() = fun name(t : T) = t.toString() + +annotation class A + +fun box() : String { + if(10.foo1() != "23910") return "foo1 fail" + if(10.foo2(1) != 11) return "foo2 fail" + + if(1.(fun Int.name() = this + 1)() != 2) return "test 3 failed"; + if( (fun name() = 1)() != 1) return "test 4 failed"; + if( (fun name(i: Int) = i)(1) != 1) return "test 5 failed"; + if( 1.(fun Int.name(i: Int) = i + this)(1) != 2) return "test 6 failed"; + if( (fooT1()("mama")) != "mama") return "test 7 failed"; + + val a = [A] fun Int.name() = this + 1 // name + if (1.a() != 2) return "test 8 failed" + val b = ( fun Int.name() = this + 1) + if (1.a() != 2) return "test 9 failed" + val c = (@c fun Int.name() = this + 1) + if (1.a() != 2) return "test 10 failed" + + val d = fun name(): Int { return@name 4} + if (d() != 4) return "test 11 failed" + + return "OK" +} diff --git a/compiler/testData/codegen/box/functions/functionLiteralExpression.kt b/compiler/testData/codegen/box/functions/functionLiteralExpression.kt new file mode 100644 index 00000000000..aaeadaf0c56 --- /dev/null +++ b/compiler/testData/codegen/box/functions/functionLiteralExpression.kt @@ -0,0 +1,25 @@ +fun Any.foo1() : ()-> String { + return { "239" + this } +} + +fun Int.foo2() : (i : Int) -> Int { + return { x -> x + this } +} + +fun fooT1(t : T) = { t.toString() } + +fun fooT2(t: T) = { (x:T) -> t.toString() + x.toString() } + +fun box() : String { + if( (10.foo1())() != "23910") return "foo1 fail" + if( (10.foo2())(1) != 11 ) return "foo2 fail" + + if(1.{Int.() -> this + 1}() != 2) return "test 3 failed"; + if( {1}() != 1) return "test 4 failed"; + if( {(x : Int) -> x}(1) != 1) return "test 5 failed"; + if( 1.{Int.(x : Int) -> x + this}(1) != 2) return "test 6 failed"; + if( 1.({Int.() -> this})() != 1) return "test 7 failed"; + if( (fooT1("mama"))() != "mama") return "test 8 failed"; + if( (fooT2("mama"))("papa") != "mamapapa") return "test 9 failed"; + return "OK" +} diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/functionExpressionInProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/functionExpressionInProperty.kt new file mode 100644 index 00000000000..24c71def982 --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/functionExpressionInProperty.kt @@ -0,0 +1,16 @@ +val property = fun () {} + +fun box(): String { + val javaClass = property.javaClass + + val enclosingMethod = javaClass.getEnclosingMethod() + if (enclosingMethod != null) return "method: $enclosingMethod" + + val enclosingClass = javaClass.getEnclosingClass()!!.getName() + if (!enclosingClass.startsWith("_DefaultPackage") || !enclosingClass.contains("functionExpressionInProperty")) return "enclosing class: $enclosingClass" + + val declaringClass = javaClass.getDeclaringClass() + if (declaringClass != null) return "anonymous function has a declaring class: $declaringClass" + + return "OK" +} \ No newline at end of file diff --git a/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/namedFunctionExpressionInProperty.kt b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/namedFunctionExpressionInProperty.kt new file mode 100644 index 00000000000..5e7c69be8cd --- /dev/null +++ b/compiler/testData/codegen/boxWithStdlib/reflection/enclosing/namedFunctionExpressionInProperty.kt @@ -0,0 +1,16 @@ +val property = fun name() {} + +fun box(): String { + val javaClass = property.javaClass + + val enclosingMethod = javaClass.getEnclosingMethod() + if (enclosingMethod != null) return "method: $enclosingMethod" + + val enclosingClass = javaClass.getEnclosingClass()!!.getName() + if (!enclosingClass.startsWith("_DefaultPackage") || !enclosingClass.contains("namedFunctionExpressionInProperty")) return "enclosing class: $enclosingClass" + + val declaringClass = javaClass.getDeclaringClass() + if (declaringClass != null) return "anonymous function has a declaring class: $declaringClass" + + return "OK" +} \ No newline at end of file diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java index 18c9596182e..546d1f80422 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -3698,6 +3698,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest(fileName); } + @TestMetadata("functionExpressionWithName.kt") + public void testFunctionExpressionWithName() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionExpressionWithName.kt"); + doTest(fileName); + } + + @TestMetadata("functionLiteralExpression.kt") + public void testFunctionLiteralExpression() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionLiteralExpression.kt"); + doTest(fileName); + } + @TestMetadata("functionNtoString.kt") public void testFunctionNtoString() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/box/functions/functionNtoString.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java index cac4b05dd2d..7799c367896 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/generated/BlackBoxWithStdlibCodegenTestGenerated.java @@ -2590,6 +2590,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("functionExpressionInProperty.kt") + public void testFunctionExpressionInProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/functionExpressionInProperty.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("kt6368.kt") public void testKt6368() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/kt6368.kt"); @@ -2704,6 +2710,12 @@ public class BlackBoxWithStdlibCodegenTestGenerated extends AbstractBlackBoxCode doTestWithStdlib(fileName); } + @TestMetadata("namedFunctionExpressionInProperty.kt") + public void testNamedFunctionExpressionInProperty() throws Exception { + String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/namedFunctionExpressionInProperty.kt"); + doTestWithStdlib(fileName); + } + @TestMetadata("objectInLambda.kt") public void testObjectInLambda() throws Exception { String fileName = JetTestUtils.navigationMetadata("compiler/testData/codegen/boxWithStdlib/reflection/enclosing/objectInLambda.kt");