From 571adf3acca80897f599f8a6f194740c631a4b7d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Thu, 19 Dec 2013 19:08:19 +0400 Subject: [PATCH] Support references to local extensions in codegen --- .../jet/codegen/ExpressionCodegen.java | 15 +++++++++----- .../box/callableReference/local/extension.kt | 6 ++++++ .../local/extensionToLocalClass.kt | 5 +++++ .../local/extensionToPrimitive.kt | 4 ++++ .../local/extensionWithClosure.kt | 11 ++++++++++ .../BlackBoxCodegenTestGenerated.java | 20 +++++++++++++++++++ 6 files changed, 56 insertions(+), 5 deletions(-) create mode 100644 compiler/testData/codegen/box/callableReference/local/extension.kt create mode 100644 compiler/testData/codegen/box/callableReference/local/extensionToLocalClass.kt create mode 100644 compiler/testData/codegen/box/callableReference/local/extensionToPrimitive.kt create mode 100644 compiler/testData/codegen/box/callableReference/local/extensionWithClosure.kt diff --git a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java index 0f60952c3ec..8ff82852f4a 100644 --- a/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java +++ b/compiler/backend/src/org/jetbrains/jet/codegen/ExpressionCodegen.java @@ -2507,6 +2507,9 @@ public class ExpressionCodegen extends JetVisitor implem Call call = CallMaker.makeCall(fakeExpression, NO_RECEIVER, null, fakeExpression, fakeArguments); Callable callable = codegen.resolveToCallable(codegen.accessibleFunctionDescriptor(referencedFunction), false); StackValue receiver = generateCallee(codegen, callable); + if (extensionReceiver.exists()) { + receiver = StackValue.composed(receiver, receiverParameterStackValue(signature)); + } result = codegen.invokeFunctionWithCalleeOnStack(call, receiver, fakeResolvedCall, callable); } @@ -2574,13 +2577,15 @@ public class ExpressionCodegen extends JetVisitor implem if (receiver == null) return NO_RECEIVER; JetExpression receiverExpression = JetPsiFactory.createExpression(state.getProject(), "callableReferenceFakeReceiver"); - - Type firstParameterType = signature.getAsmMethod().getArgumentTypes()[0]; - // 0 is this (the closure class), 1 is the method's first parameter - codegen.tempVariables.put(receiverExpression, StackValue.local(1, firstParameterType)); - + codegen.tempVariables.put(receiverExpression, receiverParameterStackValue(signature)); return new ExpressionReceiver(receiverExpression, receiver.getType()); } + + @NotNull + private static StackValue.Local receiverParameterStackValue(@NotNull JvmMethodSignature signature) { + // 0 is this (the callable reference class), 1 is the invoke() method's first parameter + return StackValue.local(1, signature.getAsmMethod().getArgumentTypes()[0]); + } } @Override diff --git a/compiler/testData/codegen/box/callableReference/local/extension.kt b/compiler/testData/codegen/box/callableReference/local/extension.kt new file mode 100644 index 00000000000..c0ce1217d94 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/local/extension.kt @@ -0,0 +1,6 @@ +class A + +fun box(): String { + fun A.foo() = "OK" + return A().(A::foo)() +} diff --git a/compiler/testData/codegen/box/callableReference/local/extensionToLocalClass.kt b/compiler/testData/codegen/box/callableReference/local/extensionToLocalClass.kt new file mode 100644 index 00000000000..781d8096ea0 --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/local/extensionToLocalClass.kt @@ -0,0 +1,5 @@ +fun box(): String { + class A + fun A.foo() = "OK" + return (::A)().(A::foo)() +} diff --git a/compiler/testData/codegen/box/callableReference/local/extensionToPrimitive.kt b/compiler/testData/codegen/box/callableReference/local/extensionToPrimitive.kt new file mode 100644 index 00000000000..f8db384261a --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/local/extensionToPrimitive.kt @@ -0,0 +1,4 @@ +fun box(): String { + fun Int.is42With(that: Int) = this + 2 * that == 42 + return if (16.(Int::is42With)(13)) "OK" else "Fail" +} diff --git a/compiler/testData/codegen/box/callableReference/local/extensionWithClosure.kt b/compiler/testData/codegen/box/callableReference/local/extensionWithClosure.kt new file mode 100644 index 00000000000..a3e02eef8de --- /dev/null +++ b/compiler/testData/codegen/box/callableReference/local/extensionWithClosure.kt @@ -0,0 +1,11 @@ +class A + +fun box(): String { + var result = "Fail" + + fun A.ext() { result = "OK" } + + val f = A::ext + A().f() + return result +} diff --git a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java index c0fc4c43f90..d7704d1c0a1 100644 --- a/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/jet/codegen/generated/BlackBoxCodegenTestGenerated.java @@ -767,6 +767,26 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { doTest("compiler/testData/codegen/box/callableReference/local/enumExtendsTrait.kt"); } + @TestMetadata("extension.kt") + public void testExtension() throws Exception { + doTest("compiler/testData/codegen/box/callableReference/local/extension.kt"); + } + + @TestMetadata("extensionToLocalClass.kt") + public void testExtensionToLocalClass() throws Exception { + doTest("compiler/testData/codegen/box/callableReference/local/extensionToLocalClass.kt"); + } + + @TestMetadata("extensionToPrimitive.kt") + public void testExtensionToPrimitive() throws Exception { + doTest("compiler/testData/codegen/box/callableReference/local/extensionToPrimitive.kt"); + } + + @TestMetadata("extensionWithClosure.kt") + public void testExtensionWithClosure() throws Exception { + doTest("compiler/testData/codegen/box/callableReference/local/extensionWithClosure.kt"); + } + @TestMetadata("genericMember.kt") public void testGenericMember() throws Exception { doTest("compiler/testData/codegen/box/callableReference/local/genericMember.kt");