Implement coroutineContext intrinsic
This intrinsic allows coroutine to access its context without suspention and, furthermore, disabling tail-call optimization. KT-17609: Fixed
This commit is contained in:
+7
@@ -17,16 +17,19 @@
|
||||
package org.jetbrains.kotlin.backend.common
|
||||
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyGetterDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorEquivalenceForOverrides
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.module
|
||||
|
||||
val SUSPEND_COROUTINE_OR_RETURN_NAME = Name.identifier("suspendCoroutineOrReturn")
|
||||
val COROUTINE_SUSPENDED_NAME = Name.identifier("COROUTINE_SUSPENDED")
|
||||
|
||||
val COROUTINES_INTRINSICS_PACKAGE_FQ_NAME = DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("intrinsics"))
|
||||
val COROUTINE_CONTEXT_FQ_NAME = COROUTINES_INTRINSICS_PACKAGE_FQ_NAME.child(Name.identifier("coroutineContext"))
|
||||
|
||||
fun FunctionDescriptor.isBuiltInSuspendCoroutineOrReturn(): Boolean {
|
||||
if (name != SUSPEND_COROUTINE_OR_RETURN_NAME) return false
|
||||
@@ -42,3 +45,7 @@ fun FunctionDescriptor.getBuiltInSuspendCoroutineOrReturn() =
|
||||
module.getPackage(COROUTINES_INTRINSICS_PACKAGE_FQ_NAME).memberScope
|
||||
.getContributedFunctions(SUSPEND_COROUTINE_OR_RETURN_NAME, NoLookupLocation.FROM_BACKEND)
|
||||
.singleOrNull()
|
||||
|
||||
fun FunctionDescriptor.isBuiltInCoroutineContext() =
|
||||
(this as? PropertyGetterDescriptor)?.correspondingProperty?.fqNameSafe == COROUTINE_CONTEXT_FQ_NAME
|
||||
|
||||
|
||||
@@ -1236,7 +1236,7 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
}
|
||||
|
||||
@Nullable
|
||||
private StackValue genCoroutineInstanceForSuspendLambda(@NotNull FunctionDescriptor suspendFunction) {
|
||||
public StackValue genCoroutineInstanceForSuspendLambda(@NotNull FunctionDescriptor suspendFunction) {
|
||||
if (!(suspendFunction instanceof AnonymousFunctionDescriptor)) return null;
|
||||
|
||||
ClassDescriptor suspendLambdaClassDescriptor = bindingContext.get(CodegenBinding.CLASS_FOR_CALLABLE, suspendFunction);
|
||||
@@ -2209,6 +2209,11 @@ public class ExpressionCodegen extends KtVisitor<StackValue, StackValue> impleme
|
||||
|
||||
assert enclosingSuspendFunctionJvmView != null : "No JVM view function found for " + enclosingSuspendFunction;
|
||||
|
||||
return getContinuationParameterFromEnclosingSuspendFunctionDescriptor(enclosingSuspendFunctionJvmView);
|
||||
}
|
||||
|
||||
@Nullable
|
||||
public StackValue getContinuationParameterFromEnclosingSuspendFunctionDescriptor(@NotNull FunctionDescriptor enclosingSuspendFunctionJvmView) {
|
||||
ValueParameterDescriptor continuationParameter =
|
||||
enclosingSuspendFunctionJvmView.getValueParameters()
|
||||
.get(enclosingSuspendFunctionJvmView.getValueParameters().size() - 1);
|
||||
|
||||
+34
-3
@@ -17,9 +17,7 @@
|
||||
package org.jetbrains.kotlin.codegen.coroutines
|
||||
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.backend.common.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME
|
||||
import org.jetbrains.kotlin.backend.common.COROUTINE_SUSPENDED_NAME
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInSuspendCoroutineOrReturn
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.builtins.isBuiltinFunctionalType
|
||||
import org.jetbrains.kotlin.codegen.StackValue
|
||||
import org.jetbrains.kotlin.codegen.binding.CodegenBinding
|
||||
@@ -66,6 +64,9 @@ val COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME =
|
||||
@JvmField
|
||||
val CONTINUATION_ASM_TYPE = DescriptorUtils.CONTINUATION_INTERFACE_FQ_NAME.topLevelClassAsmType()
|
||||
|
||||
@JvmField
|
||||
val COROUTINE_CONTEXT_ASM_TYPE = DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineContext")).topLevelClassAsmType()
|
||||
|
||||
@JvmField
|
||||
val COROUTINE_IMPL_ASM_TYPE = COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineImpl")).topLevelClassAsmType()
|
||||
|
||||
@@ -76,6 +77,7 @@ private val INTERNAL_COROUTINE_INTRINSICS_OWNER_INTERNAL_NAME =
|
||||
COROUTINES_JVM_INTERNAL_PACKAGE_FQ_NAME.child(Name.identifier("CoroutineIntrinsics")).topLevelClassInternalName()
|
||||
|
||||
private val NORMALIZE_CONTINUATION_METHOD_NAME = "normalizeContinuation"
|
||||
private val GET_CONTEXT_METHOD_NAME = "getContext"
|
||||
|
||||
data class ResolvedCallWithRealDescriptor(val resolvedCall: ResolvedCall<*>, val fakeContinuationExpression: KtExpression)
|
||||
|
||||
@@ -287,6 +289,35 @@ fun createMethodNodeForSuspendCoroutineOrReturn(
|
||||
return node
|
||||
}
|
||||
|
||||
fun createMethodNodeForCoroutineContext(functionDescriptor: FunctionDescriptor): MethodNode {
|
||||
assert(functionDescriptor.isBuiltInCoroutineContext()) {
|
||||
"functionDescriptor must be kotlin.coroutines.intrinsics.coroutineContext property getter"
|
||||
}
|
||||
|
||||
val node =
|
||||
MethodNode(
|
||||
Opcodes.ASM5,
|
||||
Opcodes.ACC_STATIC,
|
||||
"fake",
|
||||
Type.getMethodDescriptor(COROUTINE_CONTEXT_ASM_TYPE, CONTINUATION_ASM_TYPE),
|
||||
null, null
|
||||
)
|
||||
|
||||
node.visitVarInsn(Opcodes.ALOAD, 0)
|
||||
|
||||
node.visitMethodInsn(
|
||||
Opcodes.INVOKEINTERFACE,
|
||||
CONTINUATION_ASM_TYPE.internalName,
|
||||
GET_CONTEXT_METHOD_NAME,
|
||||
Type.getMethodDescriptor(COROUTINE_CONTEXT_ASM_TYPE),
|
||||
true
|
||||
)
|
||||
node.visitInsn(Opcodes.ARETURN)
|
||||
node.visitMaxs(1, 1)
|
||||
|
||||
return node
|
||||
}
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <D : CallableDescriptor?> D.unwrapInitialDescriptorForSuspendFunction(): D =
|
||||
this.safeAs<SimpleFunctionDescriptor>()?.getUserData(INITIAL_DESCRIPTOR_FOR_SUSPEND_FUNCTION) as D ?: this
|
||||
|
||||
@@ -18,12 +18,13 @@ package org.jetbrains.kotlin.codegen.inline
|
||||
|
||||
import com.intellij.psi.PsiElement
|
||||
import com.intellij.util.ArrayUtil
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInCoroutineContext
|
||||
import org.jetbrains.kotlin.builtins.BuiltInsPackageFragment
|
||||
import org.jetbrains.kotlin.codegen.*
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.getMethodAsmFlags
|
||||
import org.jetbrains.kotlin.codegen.AsmUtil.isPrimitive
|
||||
import org.jetbrains.kotlin.codegen.coroutines.createMethodNodeForSuspendCoroutineOrReturn
|
||||
import org.jetbrains.kotlin.codegen.coroutines.isBuiltInSuspendCoroutineOrReturnInJvm
|
||||
import org.jetbrains.kotlin.codegen.context.ClosureContext
|
||||
import org.jetbrains.kotlin.codegen.coroutines.*
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.bytecode
|
||||
import org.jetbrains.kotlin.codegen.intrinsics.classId
|
||||
import org.jetbrains.kotlin.codegen.state.GenerationState
|
||||
@@ -50,8 +51,6 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Deserializ
|
||||
import org.jetbrains.kotlin.types.expressions.DoubleColonLHS
|
||||
import org.jetbrains.kotlin.types.expressions.ExpressionTypingUtils.isFunctionLiteral
|
||||
import org.jetbrains.kotlin.types.expressions.LabelResolver
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
@@ -225,6 +224,19 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
||||
return true
|
||||
}
|
||||
|
||||
private fun continuationValue(): StackValue {
|
||||
assert(codegen is ExpressionCodegen) { "Expected ExpressionCodegen in coroutineContext inlining" }
|
||||
codegen as ExpressionCodegen
|
||||
|
||||
val parentContext = codegen.context.parentContext
|
||||
return if (parentContext is ClosureContext) {
|
||||
val originalSuspendLambdaDescriptor = parentContext.originalSuspendLambdaDescriptor ?: error("No original lambda descriptor found")
|
||||
codegen.genCoroutineInstanceForSuspendLambda(originalSuspendLambdaDescriptor) ?: error("No stack value for coroutine instance of lambda found")
|
||||
}
|
||||
else
|
||||
codegen.getContinuationParameterFromEnclosingSuspendFunctionDescriptor(codegen.context.functionDescriptor) ?: error("No stack value for continuation parameter of suspend function")
|
||||
}
|
||||
|
||||
protected fun inlineCall(nodeAndSmap: SMAPAndMethodNode, callDefault: Boolean): InlineResult {
|
||||
assert(delayedHiddenWriting == null) { "'putHiddenParamsIntoLocals' should be called after 'processAndPutHiddenParameters(true)'" }
|
||||
defaultSourceMapper.callSiteMarker = CallSiteMarker(codegen.lastLineNumber)
|
||||
@@ -252,6 +264,9 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
||||
addInlineMarker(codegen.v, true)
|
||||
}
|
||||
|
||||
if (functionDescriptor.isBuiltInCoroutineContext())
|
||||
invocationParamBuilder.addNextValueParameter(CONTINUATION_ASM_TYPE, false, continuationValue(), 0)
|
||||
|
||||
val parameters = invocationParamBuilder.buildParameters()
|
||||
|
||||
val info = RootInliningContext(
|
||||
@@ -458,24 +473,28 @@ abstract class InlineCodegen<out T: BaseExpressionCodegen>(
|
||||
state: GenerationState,
|
||||
sourceCompilerForInline: SourceCompilerForInline
|
||||
): SMAPAndMethodNode {
|
||||
if (isSpecialEnumMethod(functionDescriptor)) {
|
||||
val arguments = resolvedCall!!.typeArguments
|
||||
when {
|
||||
isSpecialEnumMethod(functionDescriptor) -> {
|
||||
val arguments = resolvedCall!!.typeArguments
|
||||
|
||||
val node = createSpecialEnumMethodBody(
|
||||
codegen,
|
||||
functionDescriptor.name.asString(),
|
||||
arguments.keys.single().defaultType,
|
||||
state.typeMapper
|
||||
)
|
||||
return SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1))
|
||||
}
|
||||
else if (functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm()) {
|
||||
return SMAPAndMethodNode(
|
||||
createMethodNodeForSuspendCoroutineOrReturn(
|
||||
functionDescriptor, state.typeMapper
|
||||
),
|
||||
val node = createSpecialEnumMethodBody(
|
||||
codegen,
|
||||
functionDescriptor.name.asString(),
|
||||
arguments.keys.single().defaultType,
|
||||
state.typeMapper
|
||||
)
|
||||
return SMAPAndMethodNode(node, SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1))
|
||||
}
|
||||
functionDescriptor.isBuiltInSuspendCoroutineOrReturnInJvm() ->
|
||||
return SMAPAndMethodNode(
|
||||
createMethodNodeForSuspendCoroutineOrReturn(functionDescriptor, state.typeMapper),
|
||||
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
|
||||
)
|
||||
)
|
||||
functionDescriptor.isBuiltInCoroutineContext() ->
|
||||
return SMAPAndMethodNode(
|
||||
createMethodNodeForCoroutineContext(functionDescriptor),
|
||||
SMAPParser.parseOrCreateDefault(null, null, "fake", -1, -1)
|
||||
)
|
||||
}
|
||||
|
||||
val asmMethod = if (callDefault)
|
||||
|
||||
@@ -981,6 +981,7 @@ public interface Errors {
|
||||
|
||||
DiagnosticFactory0<PsiElement> NON_LOCAL_SUSPENSION_POINT = DiagnosticFactory0.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> ILLEGAL_SUSPEND_FUNCTION_CALL = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory1<PsiElement, CallableDescriptor> ILLEGAL_SUSPEND_PROPERTY_ACCESS = DiagnosticFactory1.create(ERROR);
|
||||
DiagnosticFactory0<PsiElement> ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL = DiagnosticFactory0.create(ERROR);
|
||||
|
||||
DiagnosticFactory1<PsiElement, RenderedDiagnostic<?>> PLUGIN_ERROR = DiagnosticFactory1.create(ERROR);
|
||||
|
||||
+1
-1
@@ -25,7 +25,6 @@ import org.jetbrains.kotlin.config.LanguageVersion;
|
||||
import org.jetbrains.kotlin.diagnostics.Diagnostic;
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticFactory;
|
||||
import org.jetbrains.kotlin.diagnostics.Errors;
|
||||
import org.jetbrains.kotlin.diagnostics.RenderedDiagnostic;
|
||||
import org.jetbrains.kotlin.resolve.VarianceConflictDiagnosticData;
|
||||
import org.jetbrains.kotlin.serialization.deserialization.descriptors.VersionRequirement;
|
||||
import org.jetbrains.kotlin.types.KotlinTypeKt;
|
||||
@@ -870,6 +869,7 @@ public class DefaultErrorMessages {
|
||||
MAP.put(NON_LOCAL_RETURN_IN_DISABLED_INLINE, "Non-local returns are not allowed with inlining disabled");
|
||||
MAP.put(NON_LOCAL_SUSPENSION_POINT, "Suspension functions can be called only within coroutine body");
|
||||
MAP.put(ILLEGAL_SUSPEND_FUNCTION_CALL, "Suspend function ''{0}'' should be called only from a coroutine or another suspend function", NAME);
|
||||
MAP.put(ILLEGAL_SUSPEND_PROPERTY_ACCESS, "Suspend property ''{0}'' should be accessed only from a coroutine or suspend function", NAME);
|
||||
MAP.put(ILLEGAL_RESTRICTED_SUSPENDING_FUNCTION_CALL, "Restricted suspending functions can only invoke member or extension suspending functions on their restricted coroutine scope");
|
||||
|
||||
MAP.put(PLUGIN_ERROR, "{0}", (d, c) -> d.getText());
|
||||
|
||||
+19
-9
@@ -22,12 +22,15 @@ import org.jetbrains.kotlin.config.LanguageVersionSettings
|
||||
import org.jetbrains.kotlin.coroutines.hasSuspendFunctionType
|
||||
import org.jetbrains.kotlin.descriptors.CallableDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.diagnostics.DiagnosticSink
|
||||
import org.jetbrains.kotlin.diagnostics.Errors
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtExpression
|
||||
import org.jetbrains.kotlin.psi.KtThisExpression
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.model.ResolvedCall
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.fqNameSafe
|
||||
import org.jetbrains.kotlin.resolve.descriptorUtil.hasRestrictsSuspensionAnnotation
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineUtil
|
||||
import org.jetbrains.kotlin.resolve.scopes.HierarchicalScope
|
||||
@@ -42,17 +45,21 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
object CoroutineSuspendCallChecker : CallChecker {
|
||||
private val ALLOWED_SCOPE_KINDS = setOf(LexicalScopeKind.FUNCTION_INNER_SCOPE, LexicalScopeKind.FUNCTION_HEADER_FOR_DESTRUCTURING)
|
||||
private val COROUTINE_CONTEXT_FQ_NAME = FqName("kotlin.coroutines.experimental.intrinsics.coroutineContext")
|
||||
|
||||
override fun check(resolvedCall: ResolvedCall<*>, reportOn: PsiElement, context: CallCheckerContext) {
|
||||
val descriptor = resolvedCall.candidateDescriptor as? FunctionDescriptor ?: return
|
||||
if (!descriptor.isSuspend) return
|
||||
val descriptor = resolvedCall.candidateDescriptor
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> if (!descriptor.isSuspend) return
|
||||
is PropertyDescriptor -> if (descriptor.fqNameSafe != COROUTINE_CONTEXT_FQ_NAME) return
|
||||
else -> return
|
||||
}
|
||||
|
||||
val enclosingSuspendFunction =
|
||||
context.scope
|
||||
.parentsWithSelf.firstOrNull {
|
||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
||||
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
|
||||
val enclosingSuspendFunction = context.scope
|
||||
.parentsWithSelf.firstOrNull {
|
||||
it is LexicalScope && it.kind in ALLOWED_SCOPE_KINDS &&
|
||||
it.ownerDescriptor.safeAs<FunctionDescriptor>()?.isSuspend == true
|
||||
}?.cast<LexicalScope>()?.ownerDescriptor?.cast<FunctionDescriptor>()
|
||||
|
||||
when {
|
||||
enclosingSuspendFunction != null -> {
|
||||
@@ -70,7 +77,10 @@ object CoroutineSuspendCallChecker : CallChecker {
|
||||
checkRestrictsSuspension(enclosingSuspendFunction, resolvedCall, reportOn, context)
|
||||
}
|
||||
else -> {
|
||||
context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn, resolvedCall.candidateDescriptor))
|
||||
when (descriptor) {
|
||||
is FunctionDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_FUNCTION_CALL.on(reportOn, resolvedCall.candidateDescriptor))
|
||||
is PropertyDescriptor -> context.trace.report(Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS.on(reportOn, resolvedCall.candidateDescriptor))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+42
@@ -0,0 +1,42 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
suspend fun suspendHere() = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
|
||||
|
||||
suspend fun multipleArgs(a: Any, b: Any, c: Any) = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
|
||||
|
||||
fun builder(c: suspend () -> String): String {
|
||||
var fromSuspension: String? = null
|
||||
|
||||
val continuation = object: Continuation<String> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
fromSuspension = "Exception: ${exception}"
|
||||
}
|
||||
|
||||
override fun resume(value: String) {
|
||||
fromSuspension = value
|
||||
}
|
||||
}
|
||||
|
||||
c.startCoroutine(continuation)
|
||||
|
||||
return fromSuspension as String
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
var res = builder { suspendHere() }
|
||||
if (res != "OK") { return "fail 1 $res"}
|
||||
res = builder { multipleArgs(1,1,1) }
|
||||
if (res != "OK") { return "fail 2 $res"}
|
||||
res = builder { if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK" }
|
||||
if (res != "OK") { return "fail 3 $res"}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
+43
@@ -0,0 +1,43 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class Controller {
|
||||
suspend fun controllerSuspendHere() = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
|
||||
|
||||
suspend fun controllerMultipleArgs(a: Any, b: Any, c: Any) = if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK"
|
||||
|
||||
fun builder(c: suspend Controller.() -> String): String {
|
||||
var fromSuspension: String? = null
|
||||
|
||||
c.startCoroutine(this, object: Continuation<String> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
fromSuspension = "Exception: " + exception.message!!
|
||||
}
|
||||
|
||||
override fun resume(value: String) {
|
||||
fromSuspension = value
|
||||
}
|
||||
})
|
||||
|
||||
return fromSuspension as String
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val c = Controller()
|
||||
var res = c.builder { controllerSuspendHere() }
|
||||
if (res != "OK") { return "fail 1 $res"}
|
||||
res = c.builder { controllerMultipleArgs(1,1,1) }
|
||||
if (res != "OK") { return "fail 2 $res"}
|
||||
res = c.builder { if(coroutineContext != EmptyCoroutineContext) "$coroutineContext != $EmptyCoroutineContext" else "OK" }
|
||||
if (res != "OK") { return "fail 3 $res"}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
Vendored
+59
@@ -0,0 +1,59 @@
|
||||
// WITH_RUNTIME
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
class Controller {
|
||||
val coroutineContext = object : CoroutineContext {
|
||||
public override fun <E : CoroutineContext.Element> get(key: CoroutineContext.Key<E>): E? = null
|
||||
public override fun <R> fold(initial: R, operation: (R, CoroutineContext.Element) -> R): R = initial
|
||||
public override fun plus(context: CoroutineContext): CoroutineContext = context
|
||||
public override fun minusKey(key: CoroutineContext.Key<*>): CoroutineContext = this
|
||||
public override fun hashCode(): Int = 0
|
||||
public override fun toString(): String = "AnotherEmptyCoroutineContext"
|
||||
}
|
||||
|
||||
suspend fun controllerSuspendHere() = if(coroutineContext == EmptyCoroutineContext) "$coroutineContext == $EmptyCoroutineContext" else "OK"
|
||||
|
||||
suspend fun controllerSuspendHereIntrinsic() = if(kotlin.coroutines.experimental.intrinsics.coroutineContext != EmptyCoroutineContext)
|
||||
"${kotlin.coroutines.experimental.intrinsics.coroutineContext} != $EmptyCoroutineContext"
|
||||
else
|
||||
"OK"
|
||||
|
||||
suspend fun controllerMultipleArgs(a: Any, b: Any, c: Any) = if(coroutineContext == EmptyCoroutineContext) "$coroutineContext == $EmptyCoroutineContext" else "OK"
|
||||
|
||||
fun builder(c: suspend Controller.() -> String): String {
|
||||
var fromSuspension: String? = null
|
||||
|
||||
c.startCoroutine(this, object: Continuation<String> {
|
||||
override val context: CoroutineContext
|
||||
get() = EmptyCoroutineContext
|
||||
|
||||
override fun resumeWithException(exception: Throwable) {
|
||||
fromSuspension = "Exception: " + exception.message!!
|
||||
}
|
||||
|
||||
override fun resume(value: String) {
|
||||
fromSuspension = value
|
||||
}
|
||||
})
|
||||
|
||||
return fromSuspension as String
|
||||
}
|
||||
}
|
||||
|
||||
fun box(): String {
|
||||
val v = Controller()
|
||||
var res = v.builder { controllerMultipleArgs(1,1,1) }
|
||||
if (res != "OK") { return "fail 1 $res"}
|
||||
res = v.builder { if(coroutineContext == EmptyCoroutineContext) "$coroutineContext == $EmptyCoroutineContext" else "OK" }
|
||||
if (res != "OK") { return "fail 2 $res"}
|
||||
res = v.builder { controllerSuspendHereIntrinsic() }
|
||||
if (res != "OK") { return "fail 3 $res"}
|
||||
res = v.builder { controllerSuspendHere() }
|
||||
if (res != "OK") { return "fail 4 $res"}
|
||||
|
||||
return "OK"
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
// WITH_RUNTIME
|
||||
import kotlin.coroutines.experimental.*
|
||||
import kotlin.coroutines.experimental.intrinsics.*
|
||||
|
||||
suspend fun suspendHere(ctx: CoroutineContext) = suspendCoroutineOrReturn<String> { x ->
|
||||
if (x.context == ctx) x.resume("OK") else x.resume("FAIL")
|
||||
}
|
||||
|
||||
suspend fun mustBeTailCall(): String {
|
||||
return suspendHere(coroutineContext)
|
||||
}
|
||||
|
||||
suspend fun retrieveCoroutineContext(): CoroutineContext =
|
||||
suspendCoroutineOrReturn { cont -> cont.context }
|
||||
|
||||
suspend fun notTailCall(): String {
|
||||
return suspendHere(retrieveCoroutineContext())
|
||||
}
|
||||
@@ -0,0 +1,19 @@
|
||||
@kotlin.Metadata
|
||||
final class CoroutineContextIntrinsicKt$notTailCall$1 {
|
||||
synthetic field data: java.lang.Object
|
||||
synthetic field exception: java.lang.Throwable
|
||||
inner class CoroutineContextIntrinsicKt$notTailCall$1
|
||||
method <init>(p0: kotlin.coroutines.experimental.Continuation): void
|
||||
public final @org.jetbrains.annotations.Nullable method doResume(@org.jetbrains.annotations.Nullable p0: java.lang.Object, @org.jetbrains.annotations.Nullable p1: java.lang.Throwable): java.lang.Object
|
||||
synthetic final method getLabel(): int
|
||||
synthetic final method setLabel(p0: int): void
|
||||
}
|
||||
|
||||
@kotlin.Metadata
|
||||
public final class CoroutineContextIntrinsicKt {
|
||||
inner class CoroutineContextIntrinsicKt$notTailCall$1
|
||||
public final static @org.jetbrains.annotations.Nullable method mustBeTailCall(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method notTailCall(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method retrieveCoroutineContext(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
public final static @org.jetbrains.annotations.Nullable method suspendHere(@org.jetbrains.annotations.NotNull p0: kotlin.coroutines.experimental.CoroutineContext, @org.jetbrains.annotations.NotNull p1: kotlin.coroutines.experimental.Continuation): java.lang.Object
|
||||
}
|
||||
@@ -0,0 +1,43 @@
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
|
||||
import kotlin.coroutines.experimental.intrinsics.coroutineContext
|
||||
import kotlin.coroutines.experimental.CoroutineContext
|
||||
|
||||
fun ordinal() {
|
||||
<!ILLEGAL_SUSPEND_PROPERTY_ACCESS!>coroutineContext<!>
|
||||
}
|
||||
|
||||
suspend fun named() {
|
||||
coroutineContext
|
||||
}
|
||||
|
||||
class A {
|
||||
val coroutineContext = kotlin.coroutines.experimental.intrinsics.<!ILLEGAL_SUSPEND_PROPERTY_ACCESS!>coroutineContext<!>
|
||||
}
|
||||
|
||||
class Controller {
|
||||
fun ordinal() {
|
||||
<!ILLEGAL_SUSPEND_PROPERTY_ACCESS!>coroutineContext<!>
|
||||
}
|
||||
|
||||
suspend fun named() {
|
||||
coroutineContext
|
||||
}
|
||||
|
||||
suspend fun severalArgs(s: String, a: Any) {
|
||||
coroutineContext
|
||||
}
|
||||
}
|
||||
|
||||
fun builder(c: () -> CoroutineContext) = {}
|
||||
fun builderSuspend(c: suspend () -> CoroutineContext) = {}
|
||||
|
||||
fun builderSeveralArgs(c: (Int, Int, Int) -> CoroutineContext) = {}
|
||||
fun builderSuspendSeveralArgs(c: suspend (Int, Int, Int) -> CoroutineContext) = {}
|
||||
|
||||
fun test() {
|
||||
builder { <!ILLEGAL_SUSPEND_PROPERTY_ACCESS!>coroutineContext<!> }
|
||||
builderSuspend { coroutineContext }
|
||||
builderSeveralArgs {_, _,_ -> <!ILLEGAL_SUSPEND_PROPERTY_ACCESS!>coroutineContext<!> }
|
||||
builderSuspendSeveralArgs {_, _,_ -> coroutineContext}
|
||||
}
|
||||
+27
@@ -0,0 +1,27 @@
|
||||
package
|
||||
|
||||
public fun builder(/*0*/ c: () -> kotlin.coroutines.experimental.CoroutineContext): () -> kotlin.Unit
|
||||
public fun builderSeveralArgs(/*0*/ c: (kotlin.Int, kotlin.Int, kotlin.Int) -> kotlin.coroutines.experimental.CoroutineContext): () -> kotlin.Unit
|
||||
public fun builderSuspend(/*0*/ c: suspend () -> kotlin.coroutines.experimental.CoroutineContext): () -> kotlin.Unit
|
||||
public fun builderSuspendSeveralArgs(/*0*/ c: suspend (kotlin.Int, kotlin.Int, kotlin.Int) -> kotlin.coroutines.experimental.CoroutineContext): () -> kotlin.Unit
|
||||
public suspend fun named(): kotlin.Unit
|
||||
public fun ordinal(): kotlin.Unit
|
||||
public fun test(): kotlin.Unit
|
||||
|
||||
public final class A {
|
||||
public constructor A()
|
||||
public final val coroutineContext: kotlin.coroutines.experimental.CoroutineContext
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
|
||||
public final class Controller {
|
||||
public constructor Controller()
|
||||
public open override /*1*/ /*fake_override*/ fun equals(/*0*/ other: kotlin.Any?): kotlin.Boolean
|
||||
public open override /*1*/ /*fake_override*/ fun hashCode(): kotlin.Int
|
||||
public final suspend fun named(): kotlin.Unit
|
||||
public final fun ordinal(): kotlin.Unit
|
||||
public final suspend fun severalArgs(/*0*/ s: kotlin.String, /*1*/ a: kotlin.Any): kotlin.Unit
|
||||
public open override /*1*/ /*fake_override*/ fun toString(): kotlin.String
|
||||
}
|
||||
+18
@@ -5833,6 +5833,24 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/intrinsicSemantics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContext.kt")
|
||||
public void testCoroutineContext() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContext.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiver.kt")
|
||||
public void testCoroutineContextReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiverNotIntrinsic.kt")
|
||||
public void testCoroutineContextReceiverNotIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiverNotIntrinsic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("startCoroutine.kt")
|
||||
public void testStartCoroutine() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
|
||||
|
||||
@@ -1271,6 +1271,12 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContext.kt")
|
||||
public void testCoroutineContext() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/coroutineContext.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutinesDisabled.kt")
|
||||
public void testCoroutinesDisabled() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/coroutinesDisabled.kt");
|
||||
|
||||
+6
@@ -1271,6 +1271,12 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContext.kt")
|
||||
public void testCoroutineContext() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/coroutineContext.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutinesDisabled.kt")
|
||||
public void testCoroutinesDisabled() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/coroutinesDisabled.kt");
|
||||
|
||||
@@ -5833,6 +5833,24 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/intrinsicSemantics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContext.kt")
|
||||
public void testCoroutineContext() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContext.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiver.kt")
|
||||
public void testCoroutineContextReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiverNotIntrinsic.kt")
|
||||
public void testCoroutineContextReceiverNotIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiverNotIntrinsic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("startCoroutine.kt")
|
||||
public void testStartCoroutine() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
|
||||
|
||||
@@ -42,6 +42,12 @@ public class BytecodeListingTestGenerated extends AbstractBytecodeListingTest {
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextIntrinsic.kt")
|
||||
public void testCoroutineContextIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/coroutineContextIntrinsic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineFields.kt")
|
||||
public void testCoroutineFields() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/bytecodeListing/coroutineFields.kt");
|
||||
|
||||
@@ -5833,6 +5833,24 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/intrinsicSemantics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JVM, true);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContext.kt")
|
||||
public void testCoroutineContext() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContext.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiver.kt")
|
||||
public void testCoroutineContextReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiverNotIntrinsic.kt")
|
||||
public void testCoroutineContextReceiverNotIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiverNotIntrinsic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("startCoroutine.kt")
|
||||
public void testStartCoroutine() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
|
||||
|
||||
+1
-1
@@ -716,7 +716,7 @@ fun ExtractionData.performAnalysis(): AnalysisResult {
|
||||
ExtractionGeneratorOptions(inTempFile = true, allowExpressionBody = false)
|
||||
).generateDeclaration().declaration.getGeneratedBody()
|
||||
val virtualContext = body.analyzeFully()
|
||||
if (virtualContext.diagnostics.all().any { it.factory == Errors.ILLEGAL_SUSPEND_FUNCTION_CALL }) {
|
||||
if (virtualContext.diagnostics.all().any { it.factory == Errors.ILLEGAL_SUSPEND_FUNCTION_CALL || it.factory == Errors.ILLEGAL_SUSPEND_PROPERTY_ACCESS }) {
|
||||
descriptor = descriptor.copy(modifiers = listOf(KtTokens.SUSPEND_KEYWORD))
|
||||
}
|
||||
|
||||
|
||||
+18
@@ -6391,6 +6391,24 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
|
||||
KotlinTestUtils.assertAllTestsPresentByMetadata(this.getClass(), new File("compiler/testData/codegen/box/coroutines/intrinsicSemantics"), Pattern.compile("^(.+)\\.kt$"), TargetBackend.JS, true);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContext.kt")
|
||||
public void testCoroutineContext() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContext.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiver.kt")
|
||||
public void testCoroutineContextReceiver() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiver.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("coroutineContextReceiverNotIntrinsic.kt")
|
||||
public void testCoroutineContextReceiverNotIntrinsic() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/coroutineContextReceiverNotIntrinsic.kt");
|
||||
doTest(fileName);
|
||||
}
|
||||
|
||||
@TestMetadata("startCoroutine.kt")
|
||||
public void testStartCoroutine() throws Exception {
|
||||
String fileName = KotlinTestUtils.navigationMetadata("compiler/testData/codegen/box/coroutines/intrinsicSemantics/startCoroutine.kt");
|
||||
|
||||
+1
@@ -51,6 +51,7 @@ public final class FunctionIntrinsics {
|
||||
register(ThrowableConstructorIntrinsicFactory.INSTANCE);
|
||||
register(ExceptionPropertyIntrinsicFactory.INSTANCE);
|
||||
register(AsDynamicFIF.INSTANCE);
|
||||
register(CoroutineContextFIF.INSTANCE);
|
||||
}
|
||||
|
||||
private void register(@NotNull FunctionIntrinsicFactory instance) {
|
||||
|
||||
+54
@@ -0,0 +1,54 @@
|
||||
/*
|
||||
* 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.intrinsic.functions.factories
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.isBuiltInCoroutineContext
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.FunctionDescriptor
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsExpression
|
||||
import org.jetbrains.kotlin.js.backend.ast.JsNameRef
|
||||
import org.jetbrains.kotlin.js.backend.ast.metadata.inlineStrategy
|
||||
import org.jetbrains.kotlin.js.descriptorUtils.isCoroutineLambda
|
||||
import org.jetbrains.kotlin.js.translate.callTranslator.CallInfo
|
||||
import org.jetbrains.kotlin.js.translate.context.TranslationContext
|
||||
import org.jetbrains.kotlin.js.translate.intrinsic.functions.basic.FunctionIntrinsic
|
||||
import org.jetbrains.kotlin.js.translate.utils.JsAstUtils
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.inline.InlineStrategy
|
||||
|
||||
object CoroutineContextFIF : FunctionIntrinsicFactory {
|
||||
override fun getIntrinsic(descriptor: FunctionDescriptor): FunctionIntrinsic? {
|
||||
if (!descriptor.isBuiltInCoroutineContext()) return null
|
||||
return Intrinsic
|
||||
}
|
||||
|
||||
object Intrinsic : FunctionIntrinsic() {
|
||||
override fun apply(callInfo: CallInfo, arguments: List<JsExpression>, context: TranslationContext): JsExpression {
|
||||
val continuation = context.continuationParameterDescriptor ?: error("coroutineContext called from outside of coroutine")
|
||||
val continuationDescriptor = continuation.type.constructor.declarationDescriptor as? ClassDescriptor ?: error("Continuation is not a class")
|
||||
val contContext = DescriptorUtils.getPropertyByName(continuationDescriptor.unsubstitutedMemberScope, Name.identifier("context"))
|
||||
val res = JsNameRef(
|
||||
context.getNameForDescriptor(contContext),
|
||||
if (context.declarationDescriptor?.isCoroutineLambda == true) JsAstUtils.stateMachineReceiver()
|
||||
else context.getNameForDescriptor(continuation).makeRef()
|
||||
)
|
||||
res.inlineStrategy = InlineStrategy.NOT_INLINE
|
||||
return res
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -81,6 +81,7 @@ fun setInlineCallMetadata(
|
||||
descriptor: CallableDescriptor,
|
||||
context: TranslationContext
|
||||
) {
|
||||
if (nameRef.inlineStrategy != null) return
|
||||
nameRef.descriptor = descriptor
|
||||
nameRef.inlineStrategy = InlineStrategy.IN_PLACE
|
||||
nameRef.psiElement = psiElement
|
||||
|
||||
@@ -45,6 +45,19 @@ import kotlin.coroutines.experimental.processBareContinuationResume
|
||||
public inline suspend fun <T> suspendCoroutineOrReturn(crossinline block: (Continuation<T>) -> Any?): T =
|
||||
throw NotImplementedError("Implementation is intrinsic")
|
||||
|
||||
/**
|
||||
* Continuation context of current coroutine.
|
||||
*
|
||||
* This allows the user code to not pass an extra [CoroutineContext] parameter in basic coroutine builders like [launch] and [async],
|
||||
* but still provide easy access to coroutine context.
|
||||
*/
|
||||
@SinceKotlin("1.2")
|
||||
@Suppress("WRONG_MODIFIER_TARGET")
|
||||
public inline suspend val coroutineContext: CoroutineContext
|
||||
get() {
|
||||
throw NotImplementedError("Implemented as intrinsic")
|
||||
}
|
||||
|
||||
/**
|
||||
* This value is used as a return value of [suspendCoroutineOrReturn] `block` argument to state that
|
||||
* the execution was suspended and will not return any result immediately.
|
||||
|
||||
+1
@@ -2057,6 +2057,7 @@ public final class kotlin/coroutines/experimental/intrinsics/IntrinsicsKt {
|
||||
public static final fun createCoroutineUnchecked (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/experimental/Continuation;)Lkotlin/coroutines/experimental/Continuation;
|
||||
public static final fun createCoroutineUnchecked (Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/experimental/Continuation;)Lkotlin/coroutines/experimental/Continuation;
|
||||
public static final fun getCOROUTINE_SUSPENDED ()Ljava/lang/Object;
|
||||
public static final fun getCoroutineContext ()Lkotlin/coroutines/experimental/CoroutineContext;
|
||||
}
|
||||
|
||||
public abstract class kotlin/coroutines/experimental/jvm/internal/CoroutineImpl : kotlin/jvm/internal/Lambda, kotlin/coroutines/experimental/Continuation {
|
||||
|
||||
@@ -1876,6 +1876,7 @@ public final class kotlin/coroutines/experimental/intrinsics/IntrinsicsKt {
|
||||
public static final fun createCoroutineUnchecked (Lkotlin/jvm/functions/Function1;Lkotlin/coroutines/experimental/Continuation;)Lkotlin/coroutines/experimental/Continuation;
|
||||
public static final fun createCoroutineUnchecked (Lkotlin/jvm/functions/Function2;Ljava/lang/Object;Lkotlin/coroutines/experimental/Continuation;)Lkotlin/coroutines/experimental/Continuation;
|
||||
public static final fun getCOROUTINE_SUSPENDED ()Ljava/lang/Object;
|
||||
public static final fun getCoroutineContext ()Lkotlin/coroutines/experimental/CoroutineContext;
|
||||
}
|
||||
|
||||
public abstract class kotlin/coroutines/experimental/jvm/internal/CoroutineImpl : kotlin/jvm/internal/Lambda, kotlin/coroutines/experimental/Continuation {
|
||||
|
||||
Reference in New Issue
Block a user