Report suspension point in monitor error on crossinline lambdas
#KT-27258: Fixed
This commit is contained in:
+2
-2
@@ -63,7 +63,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
private val languageVersionSettings: LanguageVersionSettings,
|
private val languageVersionSettings: LanguageVersionSettings,
|
||||||
private val sourceFile: String,
|
private val sourceFile: String,
|
||||||
// These two are needed to report diagnostics about suspension points inside critical section
|
// These two are needed to report diagnostics about suspension points inside critical section
|
||||||
private val element: KtElement?,
|
private val element: KtElement,
|
||||||
private val diagnostics: DiagnosticSink,
|
private val diagnostics: DiagnosticSink,
|
||||||
// It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls
|
// It's only matters for named functions, may differ from '!isStatic(access)' in case of DefaultImpls
|
||||||
private val needDispatchReceiver: Boolean = false,
|
private val needDispatchReceiver: Boolean = false,
|
||||||
@@ -231,7 +231,7 @@ class CoroutineTransformerMethodVisitor(
|
|||||||
sourceFile,
|
sourceFile,
|
||||||
findSuspensionPointLineNumber(suspensionPoint)?.line ?: -1
|
findSuspensionPointLineNumber(suspensionPoint)?.line ?: -1
|
||||||
)
|
)
|
||||||
element?.let { diagnostics.report(ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR.on(it, "$stackTraceElement")) }
|
diagnostics.report(ErrorsJvm.SUSPENSION_POINT_INSIDE_MONITOR.on(element, "$stackTraceElement"))
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+25
-12
@@ -21,8 +21,10 @@ import org.jetbrains.kotlin.metadata.jvm.JvmProtoBuf
|
|||||||
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
import org.jetbrains.kotlin.metadata.jvm.deserialization.JvmProtoBufUtil
|
||||||
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
|
import org.jetbrains.kotlin.metadata.jvm.serialization.JvmStringTable
|
||||||
import org.jetbrains.kotlin.protobuf.MessageLite
|
import org.jetbrains.kotlin.protobuf.MessageLite
|
||||||
|
import org.jetbrains.kotlin.psi.KtExpression
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin
|
||||||
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
import org.jetbrains.kotlin.resolve.jvm.diagnostics.JvmDeclarationOrigin.Companion.NO_ORIGIN
|
||||||
|
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||||
import org.jetbrains.org.objectweb.asm.*
|
import org.jetbrains.org.objectweb.asm.*
|
||||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||||
import org.jetbrains.org.objectweb.asm.tree.*
|
import org.jetbrains.org.objectweb.asm.tree.*
|
||||||
@@ -131,10 +133,9 @@ class AnonymousObjectTransformer(
|
|||||||
constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper
|
constructor!!, allCapturedParamBuilder, constructorParamBuilder,transformationInfo, parentRemapper
|
||||||
)
|
)
|
||||||
|
|
||||||
|
val crossinlineSuspendElement = capturedCrossinlineSuspendElement()
|
||||||
val capturesCrossinlineSuspend = (!inliningContext.isInliningLambda || inliningContext.isContinuation) &&
|
val capturesCrossinlineSuspend = (!inliningContext.isInliningLambda || inliningContext.isContinuation) &&
|
||||||
inliningContext.expressionMap.values.any { lambda ->
|
crossinlineSuspendElement != null
|
||||||
lambda is PsiExpressionLambda && lambda.isCrossInline && lambda.invokeMethodDescriptor.isSuspend
|
|
||||||
}
|
|
||||||
|
|
||||||
val deferringMethods = ArrayList<DeferredMethodVisitor>()
|
val deferringMethods = ArrayList<DeferredMethodVisitor>()
|
||||||
|
|
||||||
@@ -158,11 +159,18 @@ class AnonymousObjectTransformer(
|
|||||||
capturesCrossinlineSuspend && !inliningContext.isContinuation && continuationClassName != null
|
capturesCrossinlineSuspend && !inliningContext.isContinuation && continuationClassName != null
|
||||||
|
|
||||||
val deferringVisitor =
|
val deferringVisitor =
|
||||||
when {
|
if (crossinlineSuspendElement != null) {
|
||||||
generateStateMachineForLambda -> newStateMachineForLambda(classBuilder, next)
|
when {
|
||||||
generateStateMachineForNamedFunction -> newStateMachineForNamedFunction(classBuilder, next, continuationClassName!!)
|
generateStateMachineForLambda -> newStateMachineForLambda(classBuilder, next, crossinlineSuspendElement)
|
||||||
else -> newMethod(classBuilder, next)
|
generateStateMachineForNamedFunction -> newStateMachineForNamedFunction(
|
||||||
}
|
classBuilder,
|
||||||
|
next,
|
||||||
|
continuationClassName!!,
|
||||||
|
crossinlineSuspendElement
|
||||||
|
)
|
||||||
|
else -> newMethod(classBuilder, next)
|
||||||
|
}
|
||||||
|
} else newMethod(classBuilder, next)
|
||||||
val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false)
|
val funResult = inlineMethodAndUpdateGlobalResult(parentRemapper, deferringVisitor, next, allCapturedParamBuilder, false)
|
||||||
|
|
||||||
val returnType = Type.getReturnType(next.desc)
|
val returnType = Type.getReturnType(next.desc)
|
||||||
@@ -227,6 +235,10 @@ class AnonymousObjectTransformer(
|
|||||||
return transformationResult
|
return transformationResult
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private fun capturedCrossinlineSuspendElement(): KtExpression? = inliningContext.expressionMap.values.find { lambda ->
|
||||||
|
lambda is PsiExpressionLambda && lambda.isCrossInline && lambda.invokeMethodDescriptor.isSuspend
|
||||||
|
}?.cast<PsiExpressionLambda>()?.functionWithBodyOrCallableReference
|
||||||
|
|
||||||
private fun writeTransformedMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) {
|
private fun writeTransformedMetadata(header: KotlinClassHeader, classBuilder: ClassBuilder) {
|
||||||
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) action@ { av ->
|
writeKotlinMetadata(classBuilder, state, header.kind, header.extraInt) action@ { av ->
|
||||||
val (newProto, newStringTable) = transformMetadata(header) ?: run {
|
val (newProto, newStringTable) = transformMetadata(header) ?: run {
|
||||||
@@ -435,7 +447,7 @@ class AnonymousObjectTransformer(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
private fun newStateMachineForLambda(builder: ClassBuilder, original: MethodNode): DeferredMethodVisitor {
|
private fun newStateMachineForLambda(builder: ClassBuilder, original: MethodNode, element: KtExpression): DeferredMethodVisitor {
|
||||||
return DeferredMethodVisitor(
|
return DeferredMethodVisitor(
|
||||||
MethodNode(
|
MethodNode(
|
||||||
original.access, original.name, original.desc, original.signature,
|
original.access, original.name, original.desc, original.signature,
|
||||||
@@ -448,7 +460,7 @@ class AnonymousObjectTransformer(
|
|||||||
ArrayUtil.toStringArray(original.exceptions)
|
ArrayUtil.toStringArray(original.exceptions)
|
||||||
), original.access, original.name, original.desc, null, null,
|
), original.access, original.name, original.desc, null, null,
|
||||||
obtainClassBuilderForCoroutineState = { builder },
|
obtainClassBuilderForCoroutineState = { builder },
|
||||||
element = null,
|
element = element,
|
||||||
diagnostics = state.diagnostics,
|
diagnostics = state.diagnostics,
|
||||||
languageVersionSettings = languageVersionSettings,
|
languageVersionSettings = languageVersionSettings,
|
||||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||||
@@ -463,7 +475,8 @@ class AnonymousObjectTransformer(
|
|||||||
private fun newStateMachineForNamedFunction(
|
private fun newStateMachineForNamedFunction(
|
||||||
builder: ClassBuilder,
|
builder: ClassBuilder,
|
||||||
original: MethodNode,
|
original: MethodNode,
|
||||||
continuationClassName: String
|
continuationClassName: String,
|
||||||
|
element: KtExpression
|
||||||
): DeferredMethodVisitor {
|
): DeferredMethodVisitor {
|
||||||
assert(inliningContext is RegeneratedClassContext)
|
assert(inliningContext is RegeneratedClassContext)
|
||||||
return DeferredMethodVisitor(
|
return DeferredMethodVisitor(
|
||||||
@@ -478,7 +491,7 @@ class AnonymousObjectTransformer(
|
|||||||
ArrayUtil.toStringArray(original.exceptions)
|
ArrayUtil.toStringArray(original.exceptions)
|
||||||
), original.access, original.name, original.desc, null, null,
|
), original.access, original.name, original.desc, null, null,
|
||||||
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
|
obtainClassBuilderForCoroutineState = { (inliningContext as RegeneratedClassContext).continuationBuilders[continuationClassName]!! },
|
||||||
element = null,
|
element = element,
|
||||||
diagnostics = state.diagnostics,
|
diagnostics = state.diagnostics,
|
||||||
languageVersionSettings = languageVersionSettings,
|
languageVersionSettings = languageVersionSettings,
|
||||||
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
shouldPreserveClassInitialization = state.constructorCallNormalizationMode.shouldPreserveClassInitialization,
|
||||||
|
|||||||
+9
@@ -15,3 +15,12 @@ inline fun monitorInFinally(a: () -> Unit, b: () -> Unit) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
inline fun withCrossinline(crossinline a: suspend () -> Unit): suspend () -> Unit {
|
||||||
|
val c : suspend () -> Unit = {
|
||||||
|
inlineMe {
|
||||||
|
a()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return c
|
||||||
|
}
|
||||||
+3
@@ -4,4 +4,7 @@ compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/so
|
|||||||
compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:14:13: error: a suspension point at SourceKt$test$2.invokeSuspend(source.kt:17) is inside a critical section
|
compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:14:13: error: a suspension point at SourceKt$test$2.invokeSuspend(source.kt:17) is inside a critical section
|
||||||
builder {
|
builder {
|
||||||
^
|
^
|
||||||
|
compiler/testData/compileKotlinAgainstCustomBinaries/suspensionPointInMonitor/source.kt:24:25: error: a suspension point at SourceKt$test$3$invokeSuspend$$inlined$withCrossinline$2.invokeSuspend(a.kt:31) is inside a critical section
|
||||||
|
withCrossinline {
|
||||||
|
^
|
||||||
COMPILATION_ERROR
|
COMPILATION_ERROR
|
||||||
|
|||||||
+8
@@ -18,6 +18,14 @@ fun test() {
|
|||||||
)
|
)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
builder {
|
||||||
|
withCrossinline {}
|
||||||
|
|
||||||
|
withCrossinline {
|
||||||
|
suspensionPoint()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
synchronized(lock) {
|
synchronized(lock) {
|
||||||
builder {
|
builder {
|
||||||
suspensionPoint()
|
suspensionPoint()
|
||||||
|
|||||||
Reference in New Issue
Block a user