From 9e3001215bcadb4a699386fb000b279593fc56f4 Mon Sep 17 00:00:00 2001 From: Pavel Talanov Date: Sun, 12 Feb 2012 18:37:50 +0400 Subject: [PATCH] support extension function safe calls and extension literal safe call --- .../translate/reference/CallTranslator.java | 51 ++++++++++++++----- .../cases/extensionLiteralSafeCall.kt | 14 +++++ .../cases/safeExtensionFunctionCall.kt | 36 +++++++++++++ .../k2js/test/PropertyAccessTest.java | 9 ++++ 4 files changed, 98 insertions(+), 12 deletions(-) create mode 100644 translator/testFiles/propertyAccess/cases/extensionLiteralSafeCall.kt create mode 100644 translator/testFiles/propertyAccess/cases/safeExtensionFunctionCall.kt diff --git a/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java b/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java index abb2986e476..df28e271329 100644 --- a/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java +++ b/translator/src/org/jetbrains/k2js/translate/reference/CallTranslator.java @@ -41,6 +41,7 @@ public final class CallTranslator extends AbstractTranslator { public /*var*/ JsExpression functionReference; } + //NOTE: receiver may mean this object as well @Nullable private /*var*/ JsExpression receiver; @@ -130,14 +131,26 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private JsExpression extensionFunctionLiteralCall() { - //TODO: call type - receiver = getExtensionFunctionCallReceiver(); - List callArguments = generateExtensionCallArgumentList(); + JsExpression realReceiver = getExtensionFunctionCallReceiver(); + return callType.constructCall(realReceiver, new CallType.CallConstructor() { + @NotNull + @Override + public JsExpression construct(@Nullable JsExpression receiver) { + assert receiver != null : "Could not be null for extensions"; + return constructExtensionLiteralCall(receiver); + } + }, context()); + } + + @NotNull + private JsExpression constructExtensionLiteralCall(@NotNull JsExpression realReceiver) { + List callArguments = generateExtensionCallArgumentList(realReceiver); JsInvocation callMethodInvocation = generateCallMethodInvocation(); callMethodInvocation.setArguments(callArguments); return callMethodInvocation; } + @NotNull private JsInvocation generateCallMethodInvocation() { JsNameRef callMethodNameRef = AstUtil.newQualifiedNameRef("call"); JsInvocation callMethodInvocation = new JsInvocation(); @@ -154,17 +167,24 @@ public final class CallTranslator extends AbstractTranslator { @NotNull private JsExpression extensionFunctionCall() { - receiver = getExtensionFunctionCallReceiver(); - List argumentList = generateExtensionCallArgumentList(); - JsExpression functionReference = callParameters().functionReference; - AstUtil.setQualifier(functionReference, callParameters().receiver); - return AstUtil.newInvocation(functionReference, argumentList); + JsExpression realReceiver = getExtensionFunctionCallReceiver(); + return callType.constructCall(realReceiver, new CallType.CallConstructor() { + @NotNull + @Override + public JsExpression construct(@Nullable JsExpression receiver) { + assert receiver != null : "Could not be null for extensions"; + return constructExtensionFunctionCall(receiver); + } + }, context()); } @NotNull private JsExpression getExtensionFunctionCallReceiver() { if (receiver != null) { - return receiver; + JsExpression result = receiver; + //Now the rest of the code can work as if it was simple method invocation + receiver = null; + return result; } DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor); assert expectedReceiverDescriptor != null; @@ -172,12 +192,19 @@ public final class CallTranslator extends AbstractTranslator { } @NotNull - private List generateExtensionCallArgumentList() { + private JsExpression constructExtensionFunctionCall(@NotNull JsExpression receiver) { + List argumentList = generateExtensionCallArgumentList(receiver); + JsExpression functionReference = callParameters().functionReference; + AstUtil.setQualifier(functionReference, callParameters().receiver); + return AstUtil.newInvocation(functionReference, argumentList); + } + + @NotNull + private List generateExtensionCallArgumentList(@NotNull JsExpression receiver) { List argumentList = new ArrayList(); + assert this.receiver == null : "Should be null at that point"; argumentList.add(receiver); argumentList.addAll(arguments); - //Now the rest of the code can work as if it was simple method invocation - receiver = null; return argumentList; } diff --git a/translator/testFiles/propertyAccess/cases/extensionLiteralSafeCall.kt b/translator/testFiles/propertyAccess/cases/extensionLiteralSafeCall.kt new file mode 100644 index 00000000000..c811204e80d --- /dev/null +++ b/translator/testFiles/propertyAccess/cases/extensionLiteralSafeCall.kt @@ -0,0 +1,14 @@ +package foo + +fun f(a : Int?, b : Int.(Int)->Int) = a?.b(2) + +fun box() : Boolean { + val c1 = f (null) { + it + this + } != null + if (c1) return false; + if (f(3) { + it + this + } != 5) return false + return true; +} diff --git a/translator/testFiles/propertyAccess/cases/safeExtensionFunctionCall.kt b/translator/testFiles/propertyAccess/cases/safeExtensionFunctionCall.kt new file mode 100644 index 00000000000..f37ce75f76f --- /dev/null +++ b/translator/testFiles/propertyAccess/cases/safeExtensionFunctionCall.kt @@ -0,0 +1,36 @@ +package foo + +class A() { + var c = 3 +} + +fun A.i() : Int { + c = c + 1 + return c +} + +fun box() : String { + var a1 : A? = A() + var a2 : A? = null + if (a1?.i() != 4) { + return "1"; + } + if (a1?.c != 4) { + return "2"; + } + if (a2?.c != null) { + return "3"; + } + a2?.i() + if (a1?.c != 4) { + return "4"; + } + a2 = a1 + if (a2?.i() != 5) { + return "5"; + } + if ((a2?.i() != 6) || (a1?.c != 6)) { + return "6" + } + return "OK" +} \ No newline at end of file diff --git a/translatorTests/test/org/jetbrains/k2js/test/PropertyAccessTest.java b/translatorTests/test/org/jetbrains/k2js/test/PropertyAccessTest.java index 9c8619811a1..1d616789e77 100644 --- a/translatorTests/test/org/jetbrains/k2js/test/PropertyAccessTest.java +++ b/translatorTests/test/org/jetbrains/k2js/test/PropertyAccessTest.java @@ -43,6 +43,7 @@ public final class PropertyAccessTest extends TranslationTest { } + //TODO: place safecalls under distinkt category public void testSafeCallReturnsNullIfFails() throws Exception { testFooBoxIsTrue("safeCallReturnsNullIfFails.kt"); } @@ -71,4 +72,12 @@ public final class PropertyAccessTest extends TranslationTest { testFooBoxIsTrue("safeAccess.kt"); } + public void testSafeExtensionFunctionCall() throws Exception { + testFooBoxIsOk("safeExtensionFunctionCall.kt"); + } + + public void testExtensionLiteralSafeCall() throws Exception { + testFooBoxIsTrue("extensionLiteralSafeCall.kt"); + } + }