support extension function safe calls and extension literal safe call

This commit is contained in:
Pavel Talanov
2012-02-12 18:37:50 +04:00
parent f98c24c6aa
commit 9e3001215b
4 changed files with 98 additions and 12 deletions
@@ -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<JsExpression> 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<JsExpression> 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<JsExpression> 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<JsExpression> generateExtensionCallArgumentList() {
private JsExpression constructExtensionFunctionCall(@NotNull JsExpression receiver) {
List<JsExpression> argumentList = generateExtensionCallArgumentList(receiver);
JsExpression functionReference = callParameters().functionReference;
AstUtil.setQualifier(functionReference, callParameters().receiver);
return AstUtil.newInvocation(functionReference, argumentList);
}
@NotNull
private List<JsExpression> generateExtensionCallArgumentList(@NotNull JsExpression receiver) {
List<JsExpression> argumentList = new ArrayList<JsExpression>();
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;
}
@@ -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;
}
@@ -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"
}
@@ -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");
}
}