support extension function safe calls and extension literal safe call
This commit is contained in:
@@ -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");
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user