Forbid old coroutineContext deserialization. Fix suspend function deserialization

This commit is contained in:
Ilmir Usmanov
2018-07-06 16:46:50 +03:00
parent d13e2ef32e
commit 524cc3ffe4
6 changed files with 42 additions and 6 deletions
@@ -37,6 +37,12 @@ import org.jetbrains.kotlin.utils.addToStdlib.safeAs
val COROUTINE_CONTEXT_1_2_20_FQ_NAME =
DescriptorUtils.COROUTINES_INTRINSICS_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext"))
val COROUTINE_CONTEXT_1_2_30_FQ_NAME =
DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_EXPERIMENTAL.child(Name.identifier("coroutineContext"))
val COROUTINE_CONTEXT_1_3_FQ_NAME =
DescriptorUtils.COROUTINES_PACKAGE_FQ_NAME_RELEASE.child(Name.identifier("coroutineContext"))
fun FunctionDescriptor.isBuiltInCoroutineContext(languageVersionSettings: LanguageVersionSettings) =
(this as? PropertyGetterDescriptor)?.correspondingProperty?.fqNameSafe?.isBuiltInCoroutineContext(languageVersionSettings) == true
@@ -50,8 +56,11 @@ object CoroutineSuspendCallChecker : CallChecker {
val descriptor = resolvedCall.candidateDescriptor
when (descriptor) {
is FunctionDescriptor -> if (!descriptor.isSuspend) return
is PropertyDescriptor ->
if (descriptor.fqNameSafe != COROUTINE_CONTEXT_1_2_20_FQ_NAME && !descriptor.isBuiltInCoroutineContext(context.languageVersionSettings)) return
is PropertyDescriptor -> when (descriptor.fqNameSafe) {
COROUTINE_CONTEXT_1_2_20_FQ_NAME, COROUTINE_CONTEXT_1_2_30_FQ_NAME, COROUTINE_CONTEXT_1_3_FQ_NAME -> {
}
else -> return
}
else -> return
}
@@ -71,6 +80,17 @@ object CoroutineSuspendCallChecker : CallChecker {
context.trace.report(Errors.UNSUPPORTED.on(reportOn, "suspend function calls in a context of default parameter value"))
}
if ((descriptor.fqNameSafe == COROUTINE_CONTEXT_1_2_20_FQ_NAME || descriptor.fqNameSafe == COROUTINE_CONTEXT_1_2_30_FQ_NAME) &&
context.languageVersionSettings.supportsFeature(LanguageFeature.ReleaseCoroutines)
) {
context.trace.report(
Errors.UNSUPPORTED.on(
reportOn,
"experimental coroutineContext of release coroutine: use kotlin.coroutines.coroutineContext instead"
)
)
}
context.trace.record(
BindingContext.ENCLOSING_SUSPEND_FUNCTION_FOR_SUSPEND_FUNCTION_CALL,
resolvedCall.call,
@@ -4,5 +4,5 @@
import kotlin.coroutines.experimental.coroutineContext
suspend fun test() {
coroutineContext
<!UNSUPPORTED!>coroutineContext<!>
}
@@ -0,0 +1,6 @@
// !LANGUAGE: +ReleaseCoroutines
// SKIP_TXT
suspend fun test() {
suspend {}
}
@@ -1871,6 +1871,11 @@ public class DiagnosticsTestWithStdLibGenerated extends AbstractDiagnosticsTestW
public void testCoroutineContext() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/release/coroutineContext.kt");
}
@TestMetadata("suspend.kt")
public void testSuspend() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/release/suspend.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension")
@@ -1871,6 +1871,11 @@ public class DiagnosticsTestWithStdLibUsingJavacGenerated extends AbstractDiagno
public void testCoroutineContext() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/release/coroutineContext.kt");
}
@TestMetadata("suspend.kt")
public void testSuspend() throws Exception {
runTest("compiler/testData/diagnostics/testsWithStdLib/coroutines/release/suspend.kt");
}
}
@TestMetadata("compiler/testData/diagnostics/testsWithStdLib/coroutines/restrictSuspension")
@@ -167,14 +167,14 @@ class TypeDeserializer(
val functionType = KotlinTypeFactory.simpleType(annotations, functionTypeConstructor, arguments, nullable)
if (!functionType.isFunctionType) return null
transformRuntimeFunctionTypeToSuspendFunction(functionType, isReleaseCoroutines)?.let { return it }
// kotlin.suspend is still built with LV=1.2, thus it references old Continuation
// And otherwise, once stdlib is compiled with 1.3 one may want to stay at LV=1.2
if (c.containingDeclaration.safeAs<CallableDescriptor>()?.fqNameOrNull() == KOTLIN_SUSPEND_BUILT_IN_FUNCTION_FQ_NAME) {
transformRuntimeFunctionTypeToSuspendFunction(functionType, !isReleaseCoroutines)?.let { return it }
transformRuntimeFunctionTypeToSuspendFunction(functionType, false)?.let { return it }
}
transformRuntimeFunctionTypeToSuspendFunction(functionType, isReleaseCoroutines)?.let { return it }
return null
}