JS: add support of interceptResume function in coroutine controller

This commit is contained in:
Alexey Andreev
2016-12-05 15:30:04 +03:00
committed by Alexey Andreev
parent 9eff193ea4
commit 060f08a8dd
11 changed files with 132 additions and 18 deletions
@@ -18,9 +18,12 @@ package org.jetbrains.kotlin.backend.common
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
import org.jetbrains.kotlin.types.KotlinType
import org.jetbrains.kotlin.util.OperatorNameConventions
val SUSPEND_WITH_CURRENT_CONTINUATION_NAME = Name.identifier("suspendWithCurrentContinuation")
@@ -30,4 +33,7 @@ fun FunctionDescriptor.getBuiltInSuspendWithCurrentContinuation() =
?.getContributedFunctions(SUSPEND_WITH_CURRENT_CONTINUATION_NAME, NoLookupLocation.FROM_BACKEND)
?.singleOrNull()
fun KotlinType.findInterceptResume() = findOperatorInController(this, OperatorNameConventions.COROUTINE_INTERCEPT_RESUME)
fun findOperatorInController(controllerType: KotlinType, name: Name): SimpleFunctionDescriptor? =
controllerType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).singleOrNull { it.isOperator }
@@ -16,6 +16,7 @@
package org.jetbrains.kotlin.codegen.coroutines
import org.jetbrains.kotlin.backend.common.findOperatorInController
import org.jetbrains.kotlin.codegen.*
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
import org.jetbrains.kotlin.codegen.context.ClosureContext
@@ -29,7 +29,6 @@ import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
import org.jetbrains.kotlin.descriptors.SourceElement
import org.jetbrains.kotlin.descriptors.annotations.Annotations
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.psi.*
import org.jetbrains.kotlin.resolve.*
@@ -240,14 +239,9 @@ private fun FunctionDescriptor.getContinuationParameterTypeOfSuspendFunction() =
val KotlinBuiltIns.continuationClassDescriptor get() = getBuiltInClassByFqName(DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME)
fun KotlinType.hasInlineInterceptResume() =
findOperatorInController(this, OperatorNameConventions.COROUTINE_INTERCEPT_RESUME)?.isInline == true
fun KotlinType.hasInlineInterceptResume() = findInterceptResume()?.isInline == true
fun KotlinType.hasNoinlineInterceptResume() =
findOperatorInController(this, OperatorNameConventions.COROUTINE_INTERCEPT_RESUME)?.isInline == false
fun findOperatorInController(controllerType: KotlinType, name: Name): SimpleFunctionDescriptor? =
controllerType.memberScope.getContributedFunctions(name, NoLookupLocation.FROM_BACKEND).singleOrNull { it.isOperator }
fun KotlinType.hasNoinlineInterceptResume() = findInterceptResume()?.isInline == false
fun FunctionDescriptor.isBuiltInSuspendWithCurrentContinuation(): Boolean {
if (name != SUSPEND_WITH_CURRENT_CONTINUATION_NAME) return false
@@ -0,0 +1,53 @@
// NO_INTERCEPT_RESUME_TESTS
class Controller {
var log = ""
var resumeIndex = 0
suspend fun <T> suspendWithValue(value: T): T = suspendWithCurrentContinuation { continuation ->
log += "suspend($value);"
continuation.resume(value)
Suspend
}
suspend fun suspendWithException(value: String): Unit = suspendWithCurrentContinuation { continuation ->
log += "error($value);"
continuation.resumeWithException(RuntimeException(value))
Suspend
}
operator fun interceptResume(block: () -> Unit) {
var id = resumeIndex++
log += "before $id;"
block()
log += "after $id;"
}
}
fun test(coroutine c: Controller.() -> Continuation<Unit>): String {
val controller = Controller()
c(controller).resume(Unit)
return controller.log
}
fun box(): String {
var result = test {
val o = suspendWithValue("O")
val k = suspendWithValue("K")
log += "$o$k;"
}
if (result != "before 0;suspend(O);before 1;suspend(K);before 2;OK;after 2;after 1;after 0;") return "fail1: $result"
result = test {
try {
suspendWithException("OK")
log += "ignore;"
}
catch (e: RuntimeException) {
log += "${e.message};"
}
}
if (result != "before 0;error(OK);before 1;OK;after 1;after 0;") return "fail2: $result"
return "OK"
}
@@ -4595,6 +4595,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
doTest(fileName);
}
@TestMetadata("interceptResume.kt")
public void testInterceptResume() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/interceptResume.kt");
doTest(fileName);
}
@TestMetadata("iterateOverArray.kt")
public void testIterateOverArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");
@@ -4595,6 +4595,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
doTest(fileName);
}
@TestMetadata("interceptResume.kt")
public void testInterceptResume() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/interceptResume.kt");
doTest(fileName);
}
@TestMetadata("iterateOverArray.kt")
public void testIterateOverArray() throws Exception {
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/iterateOverArray.kt");