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;
|
public /*var*/ JsExpression functionReference;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
//NOTE: receiver may mean this object as well
|
||||||
@Nullable
|
@Nullable
|
||||||
private /*var*/ JsExpression receiver;
|
private /*var*/ JsExpression receiver;
|
||||||
|
|
||||||
@@ -130,14 +131,26 @@ public final class CallTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression extensionFunctionLiteralCall() {
|
private JsExpression extensionFunctionLiteralCall() {
|
||||||
//TODO: call type
|
JsExpression realReceiver = getExtensionFunctionCallReceiver();
|
||||||
receiver = getExtensionFunctionCallReceiver();
|
return callType.constructCall(realReceiver, new CallType.CallConstructor() {
|
||||||
List<JsExpression> callArguments = generateExtensionCallArgumentList();
|
@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();
|
JsInvocation callMethodInvocation = generateCallMethodInvocation();
|
||||||
callMethodInvocation.setArguments(callArguments);
|
callMethodInvocation.setArguments(callArguments);
|
||||||
return callMethodInvocation;
|
return callMethodInvocation;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@NotNull
|
||||||
private JsInvocation generateCallMethodInvocation() {
|
private JsInvocation generateCallMethodInvocation() {
|
||||||
JsNameRef callMethodNameRef = AstUtil.newQualifiedNameRef("call");
|
JsNameRef callMethodNameRef = AstUtil.newQualifiedNameRef("call");
|
||||||
JsInvocation callMethodInvocation = new JsInvocation();
|
JsInvocation callMethodInvocation = new JsInvocation();
|
||||||
@@ -154,17 +167,24 @@ public final class CallTranslator extends AbstractTranslator {
|
|||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression extensionFunctionCall() {
|
private JsExpression extensionFunctionCall() {
|
||||||
receiver = getExtensionFunctionCallReceiver();
|
JsExpression realReceiver = getExtensionFunctionCallReceiver();
|
||||||
List<JsExpression> argumentList = generateExtensionCallArgumentList();
|
return callType.constructCall(realReceiver, new CallType.CallConstructor() {
|
||||||
JsExpression functionReference = callParameters().functionReference;
|
@NotNull
|
||||||
AstUtil.setQualifier(functionReference, callParameters().receiver);
|
@Override
|
||||||
return AstUtil.newInvocation(functionReference, argumentList);
|
public JsExpression construct(@Nullable JsExpression receiver) {
|
||||||
|
assert receiver != null : "Could not be null for extensions";
|
||||||
|
return constructExtensionFunctionCall(receiver);
|
||||||
|
}
|
||||||
|
}, context());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private JsExpression getExtensionFunctionCallReceiver() {
|
private JsExpression getExtensionFunctionCallReceiver() {
|
||||||
if (receiver != null) {
|
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);
|
DeclarationDescriptor expectedReceiverDescriptor = getExpectedReceiverDescriptor(descriptor);
|
||||||
assert expectedReceiverDescriptor != null;
|
assert expectedReceiverDescriptor != null;
|
||||||
@@ -172,12 +192,19 @@ public final class CallTranslator extends AbstractTranslator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@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>();
|
List<JsExpression> argumentList = new ArrayList<JsExpression>();
|
||||||
|
assert this.receiver == null : "Should be null at that point";
|
||||||
argumentList.add(receiver);
|
argumentList.add(receiver);
|
||||||
argumentList.addAll(arguments);
|
argumentList.addAll(arguments);
|
||||||
//Now the rest of the code can work as if it was simple method invocation
|
|
||||||
receiver = null;
|
|
||||||
return argumentList;
|
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 {
|
public void testSafeCallReturnsNullIfFails() throws Exception {
|
||||||
testFooBoxIsTrue("safeCallReturnsNullIfFails.kt");
|
testFooBoxIsTrue("safeCallReturnsNullIfFails.kt");
|
||||||
}
|
}
|
||||||
@@ -71,4 +72,12 @@ public final class PropertyAccessTest extends TranslationTest {
|
|||||||
testFooBoxIsTrue("safeAccess.kt");
|
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