JS: support cross-module inlining of suspend functions
See KT-18063
This commit is contained in:
+42
-4
@@ -211,6 +211,22 @@ public final class DebugJsAstProtoBuf {
|
|||||||
* <code>UNBOX_CHAR = 4;</code>
|
* <code>UNBOX_CHAR = 4;</code>
|
||||||
*/
|
*/
|
||||||
UNBOX_CHAR(3, 4),
|
UNBOX_CHAR(3, 4),
|
||||||
|
/**
|
||||||
|
* <code>SUSPEND_CALL = 5;</code>
|
||||||
|
*/
|
||||||
|
SUSPEND_CALL(4, 5),
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RESULT = 6;</code>
|
||||||
|
*/
|
||||||
|
COROUTINE_RESULT(5, 6),
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_CONTROLLER = 7;</code>
|
||||||
|
*/
|
||||||
|
COROUTINE_CONTROLLER(6, 7),
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RECEIVER = 8;</code>
|
||||||
|
*/
|
||||||
|
COROUTINE_RECEIVER(7, 8),
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -229,6 +245,22 @@ public final class DebugJsAstProtoBuf {
|
|||||||
* <code>UNBOX_CHAR = 4;</code>
|
* <code>UNBOX_CHAR = 4;</code>
|
||||||
*/
|
*/
|
||||||
public static final int UNBOX_CHAR_VALUE = 4;
|
public static final int UNBOX_CHAR_VALUE = 4;
|
||||||
|
/**
|
||||||
|
* <code>SUSPEND_CALL = 5;</code>
|
||||||
|
*/
|
||||||
|
public static final int SUSPEND_CALL_VALUE = 5;
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RESULT = 6;</code>
|
||||||
|
*/
|
||||||
|
public static final int COROUTINE_RESULT_VALUE = 6;
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_CONTROLLER = 7;</code>
|
||||||
|
*/
|
||||||
|
public static final int COROUTINE_CONTROLLER_VALUE = 7;
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RECEIVER = 8;</code>
|
||||||
|
*/
|
||||||
|
public static final int COROUTINE_RECEIVER_VALUE = 8;
|
||||||
|
|
||||||
|
|
||||||
public final int getNumber() { return value; }
|
public final int getNumber() { return value; }
|
||||||
@@ -239,6 +271,10 @@ public final class DebugJsAstProtoBuf {
|
|||||||
case 2: return WRAP_FUNCTION;
|
case 2: return WRAP_FUNCTION;
|
||||||
case 3: return TO_BOXED_CHAR;
|
case 3: return TO_BOXED_CHAR;
|
||||||
case 4: return UNBOX_CHAR;
|
case 4: return UNBOX_CHAR;
|
||||||
|
case 5: return SUSPEND_CALL;
|
||||||
|
case 6: return COROUTINE_RESULT;
|
||||||
|
case 7: return COROUTINE_CONTROLLER;
|
||||||
|
case 8: return COROUTINE_RECEIVER;
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -49361,10 +49397,12 @@ public final class DebugJsAstProtoBuf {
|
|||||||
"t.Fragment*@\n\013SideEffects\022\021\n\rAFFECTS_STA" +
|
"t.Fragment*@\n\013SideEffects\022\021\n\rAFFECTS_STA" +
|
||||||
"TE\020\001\022\024\n\020DEPENDS_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016" +
|
"TE\020\001\022\024\n\020DEPENDS_ON_STATE\020\002\022\010\n\004PURE\020\003*?\n\016" +
|
||||||
"InlineStrategy\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PL" +
|
"InlineStrategy\022\017\n\013AS_FUNCTION\020\000\022\014\n\010IN_PL" +
|
||||||
"ACE\020\001\022\016\n\nNOT_INLINE\020\002*c\n\017SpecialFunction" +
|
"ACE\020\001\022\016\n\nNOT_INLINE\020\002*\275\001\n\017SpecialFunctio" +
|
||||||
"\022\032\n\026DEFINE_INLINE_FUNCTION\020\001\022\021\n\rWRAP_FUN" +
|
"n\022\032\n\026DEFINE_INLINE_FUNCTION\020\001\022\021\n\rWRAP_FU" +
|
||||||
"CTION\020\002\022\021\n\rTO_BOXED_CHAR\020\003\022\016\n\nUNBOX_CHAR" +
|
"NCTION\020\002\022\021\n\rTO_BOXED_CHAR\020\003\022\016\n\nUNBOX_CHA" +
|
||||||
"\020\004B\024B\022DebugJsAstProtoBuf"
|
"R\020\004\022\020\n\014SUSPEND_CALL\020\005\022\024\n\020COROUTINE_RESUL" +
|
||||||
|
"T\020\006\022\030\n\024COROUTINE_CONTROLLER\020\007\022\026\n\022COROUTI" +
|
||||||
|
"NE_RECEIVER\020\010B\024B\022DebugJsAstProtoBuf"
|
||||||
};
|
};
|
||||||
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor.InternalDescriptorAssigner assigner =
|
||||||
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
new org.jetbrains.kotlin.protobuf.Descriptors.FileDescriptor. InternalDescriptorAssigner() {
|
||||||
|
|||||||
@@ -0,0 +1,69 @@
|
|||||||
|
// IGNORE_BACKEND: NATIVE
|
||||||
|
// WITH_COROUTINES
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
// MODULE: lib(support)
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
import helpers.*
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
var continuation: () -> Unit = { }
|
||||||
|
var log = ""
|
||||||
|
var finished = false
|
||||||
|
|
||||||
|
suspend fun <T> foo(v: T): T = suspendCoroutineOrReturn { x ->
|
||||||
|
continuation = {
|
||||||
|
x.resume(v)
|
||||||
|
}
|
||||||
|
log += "foo($v);"
|
||||||
|
COROUTINE_SUSPENDED
|
||||||
|
}
|
||||||
|
|
||||||
|
inline suspend fun bar(v: String) {
|
||||||
|
log += "before bar($v);"
|
||||||
|
foo("1:$v")
|
||||||
|
log += "inside bar($v);"
|
||||||
|
foo("2:$v")
|
||||||
|
log += "after bar($v);"
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(c: suspend () -> Unit) {
|
||||||
|
c.startCoroutine(handleResultContinuation {
|
||||||
|
continuation = { }
|
||||||
|
finished = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
suspend fun baz() {
|
||||||
|
bar("A")
|
||||||
|
log += "between bar;"
|
||||||
|
bar("B")
|
||||||
|
}
|
||||||
|
|
||||||
|
val expectedString =
|
||||||
|
"before bar(A);foo(1:A);@;inside bar(A);foo(2:A);@;after bar(A);" +
|
||||||
|
"between bar;" +
|
||||||
|
"before bar(B);foo(1:B);@;inside bar(B);foo(2:B);@;after bar(B);"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
builder {
|
||||||
|
baz()
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!finished) {
|
||||||
|
log += "@;"
|
||||||
|
continuation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log != expectedString) return "fail: $log"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+80
@@ -0,0 +1,80 @@
|
|||||||
|
// IGNORE_BACKEND: NATIVE
|
||||||
|
// IGNORE_BACKEND: JVM
|
||||||
|
// WITH_COROUTINES
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
// MODULE: lib(support)
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
import helpers.*
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
var continuation: () -> Unit = { }
|
||||||
|
var log = ""
|
||||||
|
var finished = false
|
||||||
|
|
||||||
|
suspend fun <T> foo(v: T): T = suspendCoroutineOrReturn { x ->
|
||||||
|
continuation = {
|
||||||
|
x.resume(v)
|
||||||
|
}
|
||||||
|
log += "foo($v);"
|
||||||
|
COROUTINE_SUSPENDED
|
||||||
|
}
|
||||||
|
|
||||||
|
interface I {
|
||||||
|
suspend fun bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
class A(val v: String) : I {
|
||||||
|
override inline suspend fun bar() {
|
||||||
|
log += "before bar($v);"
|
||||||
|
foo("1:$v")
|
||||||
|
log += "inside bar($v);"
|
||||||
|
foo("2:$v")
|
||||||
|
log += "after bar($v);"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fun builder(c: suspend () -> Unit) {
|
||||||
|
c.startCoroutine(handleResultContinuation {
|
||||||
|
continuation = { }
|
||||||
|
finished = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
suspend fun baz() {
|
||||||
|
val a = A("A")
|
||||||
|
a.bar()
|
||||||
|
|
||||||
|
log += "between bar;"
|
||||||
|
|
||||||
|
val b: I = A("B")
|
||||||
|
b.bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
val expectedString =
|
||||||
|
"before bar(A);foo(1:A);@;inside bar(A);foo(2:A);@;after bar(A);" +
|
||||||
|
"between bar;" +
|
||||||
|
"before bar(B);foo(1:B);@;inside bar(B);foo(2:B);@;after bar(B);"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
builder {
|
||||||
|
baz()
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!finished) {
|
||||||
|
log += "@;"
|
||||||
|
continuation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log != expectedString) return "fail: $log"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+77
@@ -0,0 +1,77 @@
|
|||||||
|
// IGNORE_BACKEND: NATIVE
|
||||||
|
// WITH_COROUTINES
|
||||||
|
// WITH_RUNTIME
|
||||||
|
|
||||||
|
// MODULE: lib(support)
|
||||||
|
// FILE: lib.kt
|
||||||
|
|
||||||
|
import helpers.*
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
var continuation: () -> Unit = { }
|
||||||
|
var log = ""
|
||||||
|
var finished = false
|
||||||
|
|
||||||
|
class C {
|
||||||
|
var v: String = ""
|
||||||
|
|
||||||
|
inline suspend fun bar() {
|
||||||
|
log += "before bar($v);"
|
||||||
|
foo("1:$v")
|
||||||
|
log += "inside bar($v);"
|
||||||
|
foo("2:$v")
|
||||||
|
log += "after bar($v);"
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
suspend fun <T> foo(v: T): T = suspendCoroutineOrReturn { x ->
|
||||||
|
continuation = {
|
||||||
|
x.resume(v)
|
||||||
|
}
|
||||||
|
log += "foo($v);"
|
||||||
|
COROUTINE_SUSPENDED
|
||||||
|
}
|
||||||
|
|
||||||
|
fun C.builder(c: suspend C.() -> Unit) {
|
||||||
|
c.startCoroutine(this, handleResultContinuation {
|
||||||
|
continuation = { }
|
||||||
|
finished = true
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
|
// MODULE: main(lib)
|
||||||
|
// FILE: main.kt
|
||||||
|
|
||||||
|
import kotlin.coroutines.experimental.*
|
||||||
|
import kotlin.coroutines.experimental.intrinsics.*
|
||||||
|
|
||||||
|
suspend fun C.baz() {
|
||||||
|
v = "A"
|
||||||
|
bar()
|
||||||
|
log += "between bar;"
|
||||||
|
v = "B"
|
||||||
|
bar()
|
||||||
|
}
|
||||||
|
|
||||||
|
val expectedString =
|
||||||
|
"before bar(A);foo(1:A);@;inside bar(A);foo(2:A);@;after bar(A);" +
|
||||||
|
"between bar;" +
|
||||||
|
"before bar(B);foo(1:B);@;inside bar(B);foo(2:B);@;after bar(B);"
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
var c = C()
|
||||||
|
|
||||||
|
c.builder {
|
||||||
|
baz()
|
||||||
|
}
|
||||||
|
|
||||||
|
while (!finished) {
|
||||||
|
log += "@;"
|
||||||
|
continuation()
|
||||||
|
}
|
||||||
|
|
||||||
|
if (log != expectedString) return "fail: $log"
|
||||||
|
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+24
@@ -5788,6 +5788,30 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModule.kt")
|
||||||
|
public void testInlineMultiModule() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModule.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleOverride.kt")
|
||||||
|
public void testInlineMultiModuleOverride() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
|
||||||
|
try {
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleWithController.kt")
|
||||||
|
public void testInlineMultiModuleWithController() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleWithController.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
||||||
|
|||||||
@@ -5788,6 +5788,30 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModule.kt")
|
||||||
|
public void testInlineMultiModule() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModule.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleOverride.kt")
|
||||||
|
public void testInlineMultiModuleOverride() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
|
||||||
|
try {
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleWithController.kt")
|
||||||
|
public void testInlineMultiModuleWithController() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleWithController.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
||||||
|
|||||||
@@ -5778,6 +5778,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class MultiModule extends AbstractLightAnalysisModeTest {
|
public static class MultiModule extends AbstractLightAnalysisModeTest {
|
||||||
|
@TestMetadata("inlineMultiModuleOverride.kt")
|
||||||
|
public void ignoreInlineMultiModuleOverride() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
|
||||||
|
try {
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
catch (Throwable ignore) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive for that.");
|
||||||
|
}
|
||||||
|
|
||||||
public void testAllFilesPresentInMultiModule() throws Exception {
|
public void testAllFilesPresentInMultiModule() throws Exception {
|
||||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/multiModule"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/multiModule"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||||
}
|
}
|
||||||
@@ -5788,6 +5800,18 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModule.kt")
|
||||||
|
public void testInlineMultiModule() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModule.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleWithController.kt")
|
||||||
|
public void testInlineMultiModuleWithController() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleWithController.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
||||||
|
|||||||
@@ -59,19 +59,26 @@ public abstract class JsVisitorWithContext {
|
|||||||
doAcceptStatementList(statements);
|
doAcceptStatementList(statements);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public void endVisit(@NotNull JsExpression x, @NotNull JsContext ctx) {
|
||||||
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsArrayAccess x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsArrayAccess x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsArrayLiteral x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsArrayLiteral x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsBinaryOperation x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsBinaryOperation x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsBlock x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsBlock x, @NotNull JsContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsBooleanLiteral x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsBooleanLiteral x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsBreak x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsBreak x, @NotNull JsContext ctx) {
|
||||||
@@ -84,6 +91,7 @@ public abstract class JsVisitorWithContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsConditional x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsConditional x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsContinue x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsContinue x, @NotNull JsContext ctx) {
|
||||||
@@ -111,12 +119,14 @@ public abstract class JsVisitorWithContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsFunction x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsFunction x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsIf x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsIf x, @NotNull JsContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsInvocation x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsInvocation x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsLabel x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsLabel x, @NotNull JsContext ctx) {
|
||||||
@@ -126,27 +136,33 @@ public abstract class JsVisitorWithContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsNameRef x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsNameRef x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsNew x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsNew x, @NotNull JsContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsNullLiteral x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsNullLiteral x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsNumberLiteral x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsNumberLiteral x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsObjectLiteral x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsObjectLiteral x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsParameter x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsParameter x, @NotNull JsContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsPostfixOperation x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsPostfixOperation x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsPrefixOperation x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsPrefixOperation x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsProgram x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsProgram x, @NotNull JsContext ctx) {
|
||||||
@@ -156,18 +172,21 @@ public abstract class JsVisitorWithContext {
|
|||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsRegExp x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsRegExp x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsReturn x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsReturn x, @NotNull JsContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsStringLiteral x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsStringLiteral x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsSwitch x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsSwitch x, @NotNull JsContext ctx) {
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsThisRef x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsThisRef x, @NotNull JsContext ctx) {
|
||||||
|
endVisit((JsExpression) x, ctx);
|
||||||
}
|
}
|
||||||
|
|
||||||
public void endVisit(@NotNull JsThrow x, @NotNull JsContext ctx) {
|
public void endVisit(@NotNull JsThrow x, @NotNull JsContext ctx) {
|
||||||
|
|||||||
@@ -147,6 +147,10 @@ enum class SpecialFunction(val suggestedName: String) {
|
|||||||
WRAP_FUNCTION("wrapFunction"),
|
WRAP_FUNCTION("wrapFunction"),
|
||||||
TO_BOXED_CHAR("toBoxedChar"),
|
TO_BOXED_CHAR("toBoxedChar"),
|
||||||
UNBOX_CHAR("unboxChar"),
|
UNBOX_CHAR("unboxChar"),
|
||||||
|
SUSPEND_CALL("suspendCall"),
|
||||||
|
COROUTINE_RESULT("coroutineResult"),
|
||||||
|
COROUTINE_CONTROLLER("coroutineController"),
|
||||||
|
COROUTINE_RECEIVER("coroutineReceiver")
|
||||||
}
|
}
|
||||||
|
|
||||||
enum class BoxingKind {
|
enum class BoxingKind {
|
||||||
|
|||||||
@@ -49,7 +49,10 @@ private val JS_IDENTIFIER_PART = "$JS_IDENTIFIER_START\\p{Pc}\\p{Mc}\\p{Mn}\\d"
|
|||||||
private val JS_IDENTIFIER="[$JS_IDENTIFIER_START][$JS_IDENTIFIER_PART]*"
|
private val JS_IDENTIFIER="[$JS_IDENTIFIER_START][$JS_IDENTIFIER_PART]*"
|
||||||
private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern()
|
private val DEFINE_MODULE_PATTERN = ("($JS_IDENTIFIER)\\.defineModule\\(\\s*(['\"])([^'\"]+)\\2\\s*,\\s*(\\w+)\\s*\\)").toRegex().toPattern()
|
||||||
private val DEFINE_MODULE_FIND_PATTERN = ".defineModule("
|
private val DEFINE_MODULE_FIND_PATTERN = ".defineModule("
|
||||||
private val WRAP_FUNCTION_PATTERN = Regex("var\\s+($JS_IDENTIFIER)\\s*=\\s*($JS_IDENTIFIER)\\.wrapFunction\\s*;").toPattern()
|
|
||||||
|
private val specialFunctions = enumValues<SpecialFunction>().joinToString("|") { it.suggestedName }
|
||||||
|
private val specialFunctionsByName = enumValues<SpecialFunction>().associateBy { it.suggestedName }
|
||||||
|
private val SPECIAL_FUNCTION_PATTERN = Regex("var\\s+($JS_IDENTIFIER)\\s*=\\s*($JS_IDENTIFIER)\\.($specialFunctions)\\s*;").toPattern()
|
||||||
|
|
||||||
class FunctionReader(
|
class FunctionReader(
|
||||||
private val reporter: JsConfig.Reporter,
|
private val reporter: JsConfig.Reporter,
|
||||||
@@ -72,13 +75,15 @@ class FunctionReader(
|
|||||||
val fileContent: String,
|
val fileContent: String,
|
||||||
val moduleVariable: String,
|
val moduleVariable: String,
|
||||||
val kotlinVariable: String,
|
val kotlinVariable: String,
|
||||||
val wrapFunctionVariable: String?,
|
val specialFunctions: Map<String, SpecialFunction>,
|
||||||
offsetToSourceMappingProvider: () -> OffsetToSourceMapping,
|
offsetToSourceMappingProvider: () -> OffsetToSourceMapping,
|
||||||
val sourceMap: SourceMap?
|
val sourceMap: SourceMap?
|
||||||
) {
|
) {
|
||||||
val offsetToSourceMapping by lazy(offsetToSourceMappingProvider)
|
val offsetToSourceMapping by lazy(offsetToSourceMappingProvider)
|
||||||
|
|
||||||
val wrapFunctionRegex = wrapFunctionVariable?.let { Regex("\\s*$it\\s*\\(\\s*").toPattern() }
|
val wrapFunctionRegex = specialFunctions.entries
|
||||||
|
.singleOrNull { (_, v) -> v == SpecialFunction.WRAP_FUNCTION }?.key
|
||||||
|
?.let { Regex("\\s*$it\\s*\\(\\s*").toPattern() }
|
||||||
}
|
}
|
||||||
|
|
||||||
private val moduleNameToInfo by lazy {
|
private val moduleNameToInfo by lazy {
|
||||||
@@ -100,8 +105,12 @@ class FunctionReader(
|
|||||||
val moduleVariable = preciseMatcher.group(4)
|
val moduleVariable = preciseMatcher.group(4)
|
||||||
val kotlinVariable = preciseMatcher.group(1)
|
val kotlinVariable = preciseMatcher.group(1)
|
||||||
|
|
||||||
val wrapFunctionVariable = WRAP_FUNCTION_PATTERN.matcher(content).let { matcher ->
|
val matcher = SPECIAL_FUNCTION_PATTERN.matcher(content)
|
||||||
if (matcher.find() && matcher.group(2) == kotlinVariable) matcher.group(1) else null
|
val specialFunctions = mutableMapOf<String, SpecialFunction>()
|
||||||
|
while (matcher.find()) {
|
||||||
|
if (matcher.group(2) == kotlinVariable) {
|
||||||
|
specialFunctions[matcher.group(1)] = specialFunctionsByName[matcher.group(3)]!!
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val sourceMap = sourceMapContent?.let {
|
val sourceMap = sourceMapContent?.let {
|
||||||
@@ -120,7 +129,7 @@ class FunctionReader(
|
|||||||
fileContent = content,
|
fileContent = content,
|
||||||
moduleVariable = moduleVariable,
|
moduleVariable = moduleVariable,
|
||||||
kotlinVariable = kotlinVariable,
|
kotlinVariable = kotlinVariable,
|
||||||
wrapFunctionVariable = wrapFunctionVariable,
|
specialFunctions = specialFunctions,
|
||||||
offsetToSourceMappingProvider = { OffsetToSourceMapping(content) },
|
offsetToSourceMappingProvider = { OffsetToSourceMapping(content) },
|
||||||
sourceMap = sourceMap
|
sourceMap = sourceMap
|
||||||
)
|
)
|
||||||
@@ -246,9 +255,9 @@ class FunctionReader(
|
|||||||
function.markInlineArguments(descriptor)
|
function.markInlineArguments(descriptor)
|
||||||
markDefaultParams(function)
|
markDefaultParams(function)
|
||||||
|
|
||||||
info.wrapFunctionVariable.let { wrapFunction ->
|
for (externalName in (collectReferencedNames(function) - allDefinedNames)) {
|
||||||
for (externalName in (collectReferencedNames(function) - allDefinedNames).filter { it.ident == wrapFunction }) {
|
info.specialFunctions[externalName.ident]?.let {
|
||||||
externalName.specialFunction = SpecialFunction.WRAP_FUNCTION
|
externalName.specialFunction = it
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -43,6 +43,7 @@ import java.util.stream.Collectors;
|
|||||||
import java.util.stream.Stream;
|
import java.util.stream.Stream;
|
||||||
|
|
||||||
import static org.jetbrains.kotlin.js.inline.util.CollectUtilsKt.getImportTag;
|
import static org.jetbrains.kotlin.js.inline.util.CollectUtilsKt.getImportTag;
|
||||||
|
import static org.jetbrains.kotlin.js.translate.declaration.InlineCoroutineUtilKt.transformSpecialFunctionsToCoroutineMetadata;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.flattenStatement;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.flattenStatement;
|
||||||
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
import static org.jetbrains.kotlin.js.translate.utils.JsAstUtils.pureFqn;
|
||||||
|
|
||||||
@@ -348,6 +349,7 @@ public class JsInliner extends JsVisitorWithContextImpl {
|
|||||||
}
|
}
|
||||||
|
|
||||||
JsFunction function = functionWithWrapper.getFunction().deepCopy();
|
JsFunction function = functionWithWrapper.getFunction().deepCopy();
|
||||||
|
function.setBody(transformSpecialFunctionsToCoroutineMetadata(function.getBody()));
|
||||||
if (functionWithWrapper.getWrapperBody() != null) {
|
if (functionWithWrapper.getWrapperBody() != null) {
|
||||||
applyWrapper(functionWithWrapper.getWrapperBody(), function, functionWithWrapper.getFunction(), inliningContext);
|
applyWrapper(functionWithWrapper.getWrapperBody(), function, functionWithWrapper.getFunction(), inliningContext);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -61,3 +61,16 @@ Kotlin.andPredicate = function (a, b) {
|
|||||||
|
|
||||||
Kotlin.kotlinModuleMetadata = function (abiVersion, moduleName, data) {
|
Kotlin.kotlinModuleMetadata = function (abiVersion, moduleName, data) {
|
||||||
};
|
};
|
||||||
|
|
||||||
|
Kotlin.suspendCall = function(value) {
|
||||||
|
return value;
|
||||||
|
};
|
||||||
|
|
||||||
|
Kotlin.coroutineResult = function(qualifier) {
|
||||||
|
};
|
||||||
|
|
||||||
|
Kotlin.coroutineController = function(qualifier) {
|
||||||
|
};
|
||||||
|
|
||||||
|
Kotlin.coroutineReceiver = function(qualifier) {
|
||||||
|
};
|
||||||
@@ -435,6 +435,10 @@ enum SpecialFunction {
|
|||||||
WRAP_FUNCTION = 2;
|
WRAP_FUNCTION = 2;
|
||||||
TO_BOXED_CHAR = 3;
|
TO_BOXED_CHAR = 3;
|
||||||
UNBOX_CHAR = 4;
|
UNBOX_CHAR = 4;
|
||||||
|
SUSPEND_CALL = 5;
|
||||||
|
COROUTINE_RESULT = 6;
|
||||||
|
COROUTINE_CONTROLLER = 7;
|
||||||
|
COROUTINE_RECEIVER = 8;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -522,6 +522,10 @@ class JsAstDeserializer(program: JsProgram, private val sourceRoots: Iterable<Fi
|
|||||||
JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION -> SpecialFunction.WRAP_FUNCTION
|
JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION -> SpecialFunction.WRAP_FUNCTION
|
||||||
JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR -> SpecialFunction.TO_BOXED_CHAR
|
JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR -> SpecialFunction.TO_BOXED_CHAR
|
||||||
JsAstProtoBuf.SpecialFunction.UNBOX_CHAR -> SpecialFunction.UNBOX_CHAR
|
JsAstProtoBuf.SpecialFunction.UNBOX_CHAR -> SpecialFunction.UNBOX_CHAR
|
||||||
|
JsAstProtoBuf.SpecialFunction.SUSPEND_CALL -> SpecialFunction.SUSPEND_CALL
|
||||||
|
JsAstProtoBuf.SpecialFunction.COROUTINE_RESULT -> SpecialFunction.COROUTINE_RESULT
|
||||||
|
JsAstProtoBuf.SpecialFunction.COROUTINE_CONTROLLER -> SpecialFunction.COROUTINE_CONTROLLER
|
||||||
|
JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER -> SpecialFunction.COROUTINE_RECEIVER
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun <T : JsNode> withLocation(fileId: Int?, location: Location?, action: () -> T): T {
|
private fun <T : JsNode> withLocation(fileId: Int?, location: Location?, action: () -> T): T {
|
||||||
|
|||||||
@@ -159,6 +159,22 @@ public final class JsAstProtoBuf {
|
|||||||
* <code>UNBOX_CHAR = 4;</code>
|
* <code>UNBOX_CHAR = 4;</code>
|
||||||
*/
|
*/
|
||||||
UNBOX_CHAR(3, 4),
|
UNBOX_CHAR(3, 4),
|
||||||
|
/**
|
||||||
|
* <code>SUSPEND_CALL = 5;</code>
|
||||||
|
*/
|
||||||
|
SUSPEND_CALL(4, 5),
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RESULT = 6;</code>
|
||||||
|
*/
|
||||||
|
COROUTINE_RESULT(5, 6),
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_CONTROLLER = 7;</code>
|
||||||
|
*/
|
||||||
|
COROUTINE_CONTROLLER(6, 7),
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RECEIVER = 8;</code>
|
||||||
|
*/
|
||||||
|
COROUTINE_RECEIVER(7, 8),
|
||||||
;
|
;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -177,6 +193,22 @@ public final class JsAstProtoBuf {
|
|||||||
* <code>UNBOX_CHAR = 4;</code>
|
* <code>UNBOX_CHAR = 4;</code>
|
||||||
*/
|
*/
|
||||||
public static final int UNBOX_CHAR_VALUE = 4;
|
public static final int UNBOX_CHAR_VALUE = 4;
|
||||||
|
/**
|
||||||
|
* <code>SUSPEND_CALL = 5;</code>
|
||||||
|
*/
|
||||||
|
public static final int SUSPEND_CALL_VALUE = 5;
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RESULT = 6;</code>
|
||||||
|
*/
|
||||||
|
public static final int COROUTINE_RESULT_VALUE = 6;
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_CONTROLLER = 7;</code>
|
||||||
|
*/
|
||||||
|
public static final int COROUTINE_CONTROLLER_VALUE = 7;
|
||||||
|
/**
|
||||||
|
* <code>COROUTINE_RECEIVER = 8;</code>
|
||||||
|
*/
|
||||||
|
public static final int COROUTINE_RECEIVER_VALUE = 8;
|
||||||
|
|
||||||
|
|
||||||
public final int getNumber() { return value; }
|
public final int getNumber() { return value; }
|
||||||
@@ -187,6 +219,10 @@ public final class JsAstProtoBuf {
|
|||||||
case 2: return WRAP_FUNCTION;
|
case 2: return WRAP_FUNCTION;
|
||||||
case 3: return TO_BOXED_CHAR;
|
case 3: return TO_BOXED_CHAR;
|
||||||
case 4: return UNBOX_CHAR;
|
case 4: return UNBOX_CHAR;
|
||||||
|
case 5: return SUSPEND_CALL;
|
||||||
|
case 6: return COROUTINE_RESULT;
|
||||||
|
case 7: return COROUTINE_CONTROLLER;
|
||||||
|
case 8: return COROUTINE_RECEIVER;
|
||||||
default: return null;
|
default: return null;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -558,6 +558,10 @@ class JsAstSerializer(private val pathResolver: (File) -> String) {
|
|||||||
SpecialFunction.WRAP_FUNCTION -> JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION
|
SpecialFunction.WRAP_FUNCTION -> JsAstProtoBuf.SpecialFunction.WRAP_FUNCTION
|
||||||
SpecialFunction.TO_BOXED_CHAR -> JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR
|
SpecialFunction.TO_BOXED_CHAR -> JsAstProtoBuf.SpecialFunction.TO_BOXED_CHAR
|
||||||
SpecialFunction.UNBOX_CHAR -> JsAstProtoBuf.SpecialFunction.UNBOX_CHAR
|
SpecialFunction.UNBOX_CHAR -> JsAstProtoBuf.SpecialFunction.UNBOX_CHAR
|
||||||
|
SpecialFunction.SUSPEND_CALL -> JsAstProtoBuf.SpecialFunction.SUSPEND_CALL
|
||||||
|
SpecialFunction.COROUTINE_RESULT -> JsAstProtoBuf.SpecialFunction.COROUTINE_RESULT
|
||||||
|
SpecialFunction.COROUTINE_CONTROLLER -> JsAstProtoBuf.SpecialFunction.COROUTINE_CONTROLLER
|
||||||
|
SpecialFunction.COROUTINE_RECEIVER -> JsAstProtoBuf.SpecialFunction.COROUTINE_RECEIVER
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
|
private fun serialize(name: JsName): Int = nameMap.getOrPut(name) {
|
||||||
|
|||||||
+18
@@ -6424,6 +6424,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
|||||||
doTest(fileName);
|
doTest(fileName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModule.kt")
|
||||||
|
public void testInlineMultiModule() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModule.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleOverride.kt")
|
||||||
|
public void testInlineMultiModuleOverride() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleOverride.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("inlineMultiModuleWithController.kt")
|
||||||
|
public void testInlineMultiModuleWithController() throws Exception {
|
||||||
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/inlineMultiModuleWithController.kt");
|
||||||
|
doTest(fileName);
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("simple.kt")
|
@TestMetadata("simple.kt")
|
||||||
public void testSimple() throws Exception {
|
public void testSimple() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/multiModule/simple.kt");
|
||||||
|
|||||||
@@ -95,7 +95,6 @@ public final class Namer {
|
|||||||
|
|
||||||
public static final JsNameRef IS_ARRAY_FUN_REF = new JsNameRef("isArray", "Array");
|
public static final JsNameRef IS_ARRAY_FUN_REF = new JsNameRef("isArray", "Array");
|
||||||
public static final String DEFINE_INLINE_FUNCTION = "defineInlineFunction";
|
public static final String DEFINE_INLINE_FUNCTION = "defineInlineFunction";
|
||||||
private static final String WRAP_FUNCTION = "wrapFunction";
|
|
||||||
public static final String DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX = "$default";
|
public static final String DEFAULT_PARAMETER_IMPLEMENTOR_SUFFIX = "$default";
|
||||||
|
|
||||||
private static final JsNameRef JS_OBJECT = new JsNameRef("Object");
|
private static final JsNameRef JS_OBJECT = new JsNameRef("Object");
|
||||||
@@ -324,30 +323,9 @@ public final class Namer {
|
|||||||
return pureFqn("Long", kotlinObject());
|
return pureFqn("Long", kotlinObject());
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static JsNameRef createInlineFunction() {
|
|
||||||
return pureFqn(DEFINE_INLINE_FUNCTION, kotlinObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
|
||||||
private static JsNameRef wrapFunction() {
|
|
||||||
return pureFqn(WRAP_FUNCTION, kotlinObject());
|
|
||||||
}
|
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
public static JsExpression createSpecialFunction(@NotNull SpecialFunction specialFunction) {
|
public static JsExpression createSpecialFunction(@NotNull SpecialFunction specialFunction) {
|
||||||
switch (specialFunction) {
|
return pureFqn(specialFunction.getSuggestedName(), kotlinObject());
|
||||||
case DEFINE_INLINE_FUNCTION:
|
|
||||||
return createInlineFunction();
|
|
||||||
case WRAP_FUNCTION:
|
|
||||||
return wrapFunction();
|
|
||||||
case TO_BOXED_CHAR:
|
|
||||||
return pureFqn("toBoxedChar", kotlinObject());
|
|
||||||
case UNBOX_CHAR:
|
|
||||||
return pureFqn("unboxChar", kotlinObject());
|
|
||||||
default:
|
|
||||||
throw new IllegalArgumentException("Unknown function: " + specialFunction);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
|
|||||||
+33
-9
@@ -21,15 +21,17 @@ import org.jetbrains.kotlin.descriptors.Modality
|
|||||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||||
import org.jetbrains.kotlin.descriptors.isOverridable
|
import org.jetbrains.kotlin.descriptors.isOverridable
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.JsFunction
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsName
|
import org.jetbrains.kotlin.js.backend.ast.JsName
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.coroutineMetadata
|
||||||
|
import org.jetbrains.kotlin.js.descriptorUtils.shouldBeExported
|
||||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
import org.jetbrains.kotlin.js.translate.expression.translateAndAliasParameters
|
import org.jetbrains.kotlin.js.translate.expression.*
|
||||||
import org.jetbrains.kotlin.js.translate.expression.translateFunction
|
|
||||||
import org.jetbrains.kotlin.js.translate.expression.wrapWithInlineMetadata
|
|
||||||
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor
|
import org.jetbrains.kotlin.js.translate.general.TranslatorVisitor
|
||||||
import org.jetbrains.kotlin.js.translate.utils.*
|
import org.jetbrains.kotlin.js.translate.utils.*
|
||||||
import org.jetbrains.kotlin.psi.*
|
import org.jetbrains.kotlin.psi.*
|
||||||
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
import org.jetbrains.kotlin.resolve.descriptorUtil.isExtensionProperty
|
||||||
|
import org.jetbrains.kotlin.resolve.source.getPsi
|
||||||
|
|
||||||
abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
||||||
override fun emptyResult(context: TranslationContext) { }
|
override fun emptyResult(context: TranslationContext) { }
|
||||||
@@ -52,7 +54,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
|||||||
val defaultTranslator = DefaultPropertyTranslator(descriptor, context, getBackingFieldReference(descriptor))
|
val defaultTranslator = DefaultPropertyTranslator(descriptor, context, getBackingFieldReference(descriptor))
|
||||||
val getter = descriptor.getter!!
|
val getter = descriptor.getter!!
|
||||||
val getterExpr = if (expression.hasCustomGetter()) {
|
val getterExpr = if (expression.hasCustomGetter()) {
|
||||||
translateFunction(getter, expression.getter!!, propertyContext)
|
translateFunction(getter, expression.getter!!, propertyContext).first
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val function = context.getFunctionObject(getter)
|
val function = context.getFunctionObject(getter)
|
||||||
@@ -64,7 +66,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
|||||||
val setterExpr = if (descriptor.isVar) {
|
val setterExpr = if (descriptor.isVar) {
|
||||||
val setter = descriptor.setter!!
|
val setter = descriptor.setter!!
|
||||||
if (expression.hasCustomSetter()) {
|
if (expression.hasCustomSetter()) {
|
||||||
translateFunction(setter, expression.setter!!, propertyContext)
|
translateFunction(setter, expression.setter!!, propertyContext).first
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
val function = context.getFunctionObject(setter)
|
val function = context.getFunctionObject(setter)
|
||||||
@@ -88,8 +90,23 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
|||||||
|
|
||||||
override fun visitNamedFunction(expression: KtNamedFunction, context: TranslationContext) {
|
override fun visitNamedFunction(expression: KtNamedFunction, context: TranslationContext) {
|
||||||
val descriptor = BindingUtils.getFunctionDescriptor(context.bindingContext(), expression)
|
val descriptor = BindingUtils.getFunctionDescriptor(context.bindingContext(), expression)
|
||||||
val jsFunction = if (descriptor.modality != Modality.ABSTRACT) translateFunction(descriptor, expression, context) else null
|
val functionAndContext = if (descriptor.modality != Modality.ABSTRACT) {
|
||||||
addFunction(descriptor, jsFunction, expression)
|
translateFunction(descriptor, expression, context)
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
null
|
||||||
|
}
|
||||||
|
addFunction(descriptor, functionAndContext?.first, expression)
|
||||||
|
|
||||||
|
if (descriptor.isSuspend && descriptor.isInline && descriptor.shouldBeExported(context.config) && functionAndContext != null) {
|
||||||
|
val innerContext = functionAndContext.second
|
||||||
|
val inlineFunction = transformCoroutineMetadataToSpecialFunctions(context, functionAndContext.first.deepCopy() as JsFunction)
|
||||||
|
inlineFunction.name = null
|
||||||
|
inlineFunction.coroutineMetadata = null
|
||||||
|
val metadata = InlineMetadata.compose(inlineFunction, descriptor, innerContext)
|
||||||
|
val functionWithMetadata = metadata.functionWithMetadata(context, descriptor.source.getPsi())
|
||||||
|
context.addDeclarationStatement(functionWithMetadata.makeStmt())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitTypeAlias(typeAlias: KtTypeAlias, data: TranslationContext?) {}
|
override fun visitTypeAlias(typeAlias: KtTypeAlias, data: TranslationContext?) {}
|
||||||
@@ -98,7 +115,7 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
|||||||
descriptor: FunctionDescriptor,
|
descriptor: FunctionDescriptor,
|
||||||
expression: KtDeclarationWithBody,
|
expression: KtDeclarationWithBody,
|
||||||
context: TranslationContext
|
context: TranslationContext
|
||||||
): JsExpression {
|
): Pair<JsExpression, TranslationContext> {
|
||||||
val function = context.getFunctionObject(descriptor)
|
val function = context.getFunctionObject(descriptor)
|
||||||
function.source = expression.finalElement
|
function.source = expression.finalElement
|
||||||
val innerContext = context.newDeclaration(descriptor).translateAndAliasParameters(descriptor, function.parameters)
|
val innerContext = context.newDeclaration(descriptor).translateAndAliasParameters(descriptor, function.parameters)
|
||||||
@@ -113,7 +130,14 @@ abstract class AbstractDeclarationVisitor : TranslatorVisitor<Unit>() {
|
|||||||
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
|
function.body.statements += FunctionBodyTranslator.setDefaultValueForArguments(descriptor, innerContext)
|
||||||
}
|
}
|
||||||
innerContext.translateFunction(expression, function)
|
innerContext.translateFunction(expression, function)
|
||||||
return innerContext.wrapWithInlineMetadata(context, function, descriptor)
|
val result = if (descriptor.isSuspend && descriptor.shouldBeExported(context.config)) {
|
||||||
|
function
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
innerContext.wrapWithInlineMetadata(context, function, descriptor)
|
||||||
|
}
|
||||||
|
|
||||||
|
return Pair(result, innerContext)
|
||||||
}
|
}
|
||||||
|
|
||||||
// used from kotlinx.serialization
|
// used from kotlinx.serialization
|
||||||
|
|||||||
+101
@@ -0,0 +1,101 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Copyright 2010-2017 JetBrains s.r.o.
|
||||||
|
*
|
||||||
|
* Licensed under the Apache License, Version 2.0 (the "License");
|
||||||
|
* you may not use this file except in compliance with the License.
|
||||||
|
* You may obtain a copy of the License at
|
||||||
|
*
|
||||||
|
* http://www.apache.org/licenses/LICENSE-2.0
|
||||||
|
*
|
||||||
|
* Unless required by applicable law or agreed to in writing, software
|
||||||
|
* distributed under the License is distributed on an "AS IS" BASIS,
|
||||||
|
* WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||||||
|
* See the License for the specific language governing permissions and
|
||||||
|
* limitations under the License.
|
||||||
|
*/
|
||||||
|
|
||||||
|
package org.jetbrains.kotlin.js.translate.declaration
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.backend.ast.metadata.*
|
||||||
|
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.TranslationUtils
|
||||||
|
import org.jetbrains.kotlin.js.translate.utils.name
|
||||||
|
|
||||||
|
fun <T : JsNode> transformCoroutineMetadataToSpecialFunctions(context: TranslationContext, node: T): T {
|
||||||
|
val visitor = object : JsVisitorWithContextImpl() {
|
||||||
|
override fun endVisit(x: JsNameRef, ctx: JsContext<in JsExpression>) {
|
||||||
|
val specialFunction = when {
|
||||||
|
x.coroutineController -> SpecialFunction.COROUTINE_CONTROLLER
|
||||||
|
x.coroutineReceiver -> SpecialFunction.COROUTINE_RECEIVER
|
||||||
|
x.coroutineResult -> SpecialFunction.COROUTINE_RESULT
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
if (specialFunction != null) {
|
||||||
|
val arguments = listOfNotNull(x.qualifier).toTypedArray()
|
||||||
|
ctx.replaceMe(TranslationUtils.invokeSpecialFunction(context, specialFunction, *arguments).source(x.source))
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
super.endVisit(x, ctx)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun endVisit(x: JsExpression, ctx: JsContext<in JsExpression>) {
|
||||||
|
if (x.isSuspend) {
|
||||||
|
x.isSuspend = false
|
||||||
|
ctx.replaceMe(TranslationUtils.invokeSpecialFunction(context, SpecialFunction.SUSPEND_CALL, x).source(x.source))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visitor.accept(node)
|
||||||
|
}
|
||||||
|
|
||||||
|
fun <T : JsNode> transformSpecialFunctionsToCoroutineMetadata(node: T): T {
|
||||||
|
val visitor = object : JsVisitorWithContextImpl() {
|
||||||
|
override fun endVisit(x: JsInvocation, ctx: JsContext<in JsExpression>) {
|
||||||
|
x.qualifier.name?.specialFunction?.let { specialFunction ->
|
||||||
|
val replacement = when (specialFunction) {
|
||||||
|
SpecialFunction.COROUTINE_CONTROLLER -> {
|
||||||
|
JsNameRef("\$\$controller\$\$", x.arguments.getOrNull(0)).apply {
|
||||||
|
coroutineController = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpecialFunction.COROUTINE_RECEIVER -> {
|
||||||
|
JsNameRef("\$this\$", x.arguments.getOrNull(0)).apply {
|
||||||
|
coroutineReceiver = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpecialFunction.COROUTINE_RESULT -> {
|
||||||
|
JsNameRef("\$result\$", x.arguments.getOrNull(0)).apply {
|
||||||
|
coroutineResult = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
SpecialFunction.SUSPEND_CALL -> {
|
||||||
|
x.arguments[0].apply {
|
||||||
|
isSuspend = true
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else -> null
|
||||||
|
}
|
||||||
|
replacement?.let { ctx.replaceMe(it) }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return visitor.accept(node)
|
||||||
|
}
|
||||||
+1
-1
@@ -112,7 +112,7 @@ fun TranslationContext.wrapWithInlineMetadata(
|
|||||||
if (descriptor.shouldBeExported(config)) {
|
if (descriptor.shouldBeExported(config)) {
|
||||||
val metadata = InlineMetadata.compose(function, descriptor, this)
|
val metadata = InlineMetadata.compose(function, descriptor, this)
|
||||||
val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo)
|
val functionWithMetadata = metadata.functionWithMetadata(outerContext, sourceInfo)
|
||||||
config.configuration[JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER]?.apply {
|
config.configuration[JSConfigurationKeys.INCREMENTAL_RESULTS_CONSUMER]?.apply {
|
||||||
val psiFile = (descriptor.source.containingFile as? PsiSourceFile)?.psiFile ?: return@apply
|
val psiFile = (descriptor.source.containingFile as? PsiSourceFile)?.psiFile ?: return@apply
|
||||||
val file = VfsUtilCore.virtualToIoFile(psiFile.virtualFile)
|
val file = VfsUtilCore.virtualToIoFile(psiFile.virtualFile)
|
||||||
|
|
||||||
|
|||||||
@@ -526,7 +526,7 @@ public final class TranslationUtils {
|
|||||||
}
|
}
|
||||||
|
|
||||||
@NotNull
|
@NotNull
|
||||||
private static JsInvocation invokeSpecialFunction(
|
public static JsInvocation invokeSpecialFunction(
|
||||||
@NotNull TranslationContext context,
|
@NotNull TranslationContext context,
|
||||||
@NotNull SpecialFunction function, @NotNull JsExpression... arguments
|
@NotNull SpecialFunction function, @NotNull JsExpression... arguments
|
||||||
) {
|
) {
|
||||||
|
|||||||
Reference in New Issue
Block a user