JVM_IR: Support is/as SuspendFunction operators

This commit is contained in:
Ilmir Usmanov
2019-10-10 20:46:02 +03:00
parent 6f47699796
commit 5eeb2958f7
7 changed files with 34 additions and 30 deletions
@@ -40,6 +40,7 @@ class JvmSymbols(
private val storageManager = LockBasedStorageManager(this::class.java.simpleName) private val storageManager = LockBasedStorageManager(this::class.java.simpleName)
private val kotlinPackage: IrPackageFragment = createPackage(FqName("kotlin")) private val kotlinPackage: IrPackageFragment = createPackage(FqName("kotlin"))
private val kotlinCoroutinesPackage: IrPackageFragment = createPackage(FqName("kotlin.coroutines")) private val kotlinCoroutinesPackage: IrPackageFragment = createPackage(FqName("kotlin.coroutines"))
private val kotlinCoroutinesJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.coroutines.jvm.internal"))
private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm")) private val kotlinJvmPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm"))
private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal")) private val kotlinJvmInternalPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.internal"))
private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions")) private val kotlinJvmFunctionsPackage: IrPackageFragment = createPackage(FqName("kotlin.jvm.functions"))
@@ -81,6 +82,7 @@ class JvmSymbols(
parent = when (fqName.parent().asString()) { parent = when (fqName.parent().asString()) {
"kotlin" -> kotlinPackage "kotlin" -> kotlinPackage
"kotlin.coroutines" -> kotlinCoroutinesPackage "kotlin.coroutines" -> kotlinCoroutinesPackage
"kotlin.coroutines.jvm.internal" -> kotlinCoroutinesJvmInternalPackage
"kotlin.jvm.internal" -> kotlinJvmInternalPackage "kotlin.jvm.internal" -> kotlinJvmInternalPackage
"kotlin.jvm.functions" -> kotlinJvmFunctionsPackage "kotlin.jvm.functions" -> kotlinJvmFunctionsPackage
"java.lang" -> javaLangPackage "java.lang" -> javaLangPackage
@@ -169,6 +171,8 @@ class JvmSymbols(
klass.addTypeParameter("T", irBuiltIns.anyNType, Variance.IN_VARIANCE) klass.addTypeParameter("T", irBuiltIns.anyNType, Variance.IN_VARIANCE)
} }
val suspendFunctionInterface: IrClassSymbol = createClass(FqName("kotlin.coroutines.jvm.internal.SuspendFunction"), ClassKind.INTERFACE)
val lambdaClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.Lambda")) { klass -> val lambdaClass: IrClassSymbol = createClass(FqName("kotlin.jvm.internal.Lambda")) { klass ->
klass.addConstructor().apply { klass.addConstructor().apply {
addValueParameter("arity", irBuiltIns.intType) addValueParameter("arity", irBuiltIns.intType)
@@ -103,14 +103,12 @@ internal fun IrFunction.isInvokeOfSuspendLambda(context: JvmBackendContext): Boo
internal fun IrFunction.isInvokeSuspendOfContinuation(context: JvmBackendContext): Boolean = internal fun IrFunction.isInvokeSuspendOfContinuation(context: JvmBackendContext): Boolean =
name.asString() == INVOKE_SUSPEND_METHOD_NAME && parentAsClass in context.suspendFunctionContinuations.values name.asString() == INVOKE_SUSPEND_METHOD_NAME && parentAsClass in context.suspendFunctionContinuations.values
internal fun IrFunction.isInvokeOfCallableReference(): Boolean = isSuspend && name.asString() == "invoke" && (parent as? IrClass)?.let { internal fun IrFunction.isInvokeOfSuspendCallableReference(): Boolean = isSuspend && name.asString() == "invoke" &&
// TODO: Should we use different origin for lowered callable references? (parent as? IrClass)?.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL
it.origin == JvmLoweredDeclarationOrigin.FUNCTION_REFERENCE_IMPL && it.functions.any { it.name.asString() == "getSignature" }
} == true
internal fun IrFunction.isKnownToBeTailCall(): Boolean = internal fun IrFunction.isKnownToBeTailCall(): Boolean =
origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR || origin == IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || origin == JvmLoweredDeclarationOrigin.SYNTHETIC_ACCESSOR ||
isInvokeOfCallableReference() isInvokeOfSuspendCallableReference()
internal fun IrFunction.shouldNotContainSuspendMarkers(context: JvmBackendContext): Boolean = internal fun IrFunction.shouldNotContainSuspendMarkers(context: JvmBackendContext): Boolean =
isInvokeSuspendOfContinuation(context) || isKnownToBeTailCall() isInvokeSuspendOfContinuation(context) || isKnownToBeTailCall()
@@ -1,6 +1,6 @@
/* /*
* Copyright 2010-2019 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license * Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
* that can be found in the license/LICENSE.txt file. * Use of this source code is governed by the Apache 2.0 license that can be found in the license/LICENSE.txt file.
*/ */
package org.jetbrains.kotlin.backend.jvm.codegen package org.jetbrains.kotlin.backend.jvm.codegen
@@ -35,6 +35,8 @@ import org.jetbrains.org.objectweb.asm.Type
class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase() { class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBase() {
internal val typeSystem = IrTypeCheckerContext(context.irBuiltIns) internal val typeSystem = IrTypeCheckerContext(context.irBuiltIns)
private val IrTypeArgument.adjustedType
get() = (this as? IrTypeProjection)?.type ?: context.irBuiltIns.anyNType
override fun mapClass(classifier: ClassifierDescriptor): Type = override fun mapClass(classifier: ClassifierDescriptor): Type =
when (classifier) { when (classifier) {
@@ -99,8 +101,8 @@ class IrTypeMapper(private val context: JvmBackendContext) : KotlinTypeMapperBas
if (type.isSuspendFunction()) { if (type.isSuspendFunction()) {
val arguments = val arguments =
type.arguments.dropLast(1).map { (it as IrTypeProjection).type } + type.arguments.dropLast(1).map { it.adjustedType } +
context.ir.symbols.continuationClass.typeWith((type.arguments.last() as IrTypeProjection).type) + context.ir.symbols.continuationClass.typeWith(type.arguments.last().adjustedType) +
context.irBuiltIns.anyNType context.irBuiltIns.anyNType
val runtimeFunctionType = context.referenceClass(context.builtIns.getFunction(arguments.size - 1)).typeWith(arguments) val runtimeFunctionType = context.referenceClass(context.builtIns.getFunction(arguments.size - 1)).typeWith(arguments)
return mapType(runtimeFunctionType, mode, sw) return mapType(runtimeFunctionType, mode, sw)
@@ -18,7 +18,7 @@ import org.jetbrains.kotlin.backend.common.pop
import org.jetbrains.kotlin.backend.common.push import org.jetbrains.kotlin.backend.common.push
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrBlock import org.jetbrains.kotlin.backend.jvm.codegen.isInlineIrBlock
import org.jetbrains.kotlin.backend.jvm.codegen.isInvokeOfCallableReference import org.jetbrains.kotlin.backend.jvm.codegen.isInvokeOfSuspendCallableReference
import org.jetbrains.kotlin.codegen.coroutines.* import org.jetbrains.kotlin.codegen.coroutines.*
import org.jetbrains.kotlin.config.coroutinesPackageFqName import org.jetbrains.kotlin.config.coroutinesPackageFqName
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
@@ -433,7 +433,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
override fun visitFunction(declaration: IrFunction) { override fun visitFunction(declaration: IrFunction) {
super.visitFunction(declaration) super.visitFunction(declaration)
if (declaration.isSuspend && declaration !in suspendLambdas && !declaration.isInline && if (declaration.isSuspend && declaration !in suspendLambdas && !declaration.isInline &&
!declaration.isInvokeOfCallableReference() !declaration.isInvokeOfSuspendCallableReference()
) { ) {
result.add(declaration) result.add(declaration)
} }
@@ -188,6 +188,7 @@ internal class CallableReferenceLowering(private val context: JvmBackendContext)
superTypes += superType superTypes += superType
if (samSuperType == null) if (samSuperType == null)
superTypes += functionSuperClass.typeWith(parameterTypes) superTypes += functionSuperClass.typeWith(parameterTypes)
if (irFunctionReference.isSuspend) superTypes += context.ir.symbols.suspendFunctionInterface.typeWith()
createImplicitParameterDeclarationWithWrappedDescriptor() createImplicitParameterDeclarationWithWrappedDescriptor()
copyAttributes(irFunctionReference) copyAttributes(irFunctionReference)
} }
@@ -17,26 +17,26 @@ fun test(f: Function<*>, arity: Int) {
} }
suspend fun foo(s: String, i: Int) {} suspend fun foo(s: String, i: Int) {}
//class A { class A {
// suspend fun bar(s: String, i: Int) {} suspend fun bar(s: String, i: Int) {}
//} }
//
//suspend fun Double.baz(s: String, i: Int) {} suspend fun Double.baz(s: String, i: Int) {}
fun box(): String { fun box(): String {
test(::foo, 2 + 1) test(::foo, 2 + 1)
// test(A::bar, 3 + 1) test(A::bar, 3 + 1)
// test(Double::baz, 3 + 1) test(Double::baz, 3 + 1)
//
// test(::box, 0) test(::box, 0)
//
// suspend fun local(x: Int) {} suspend fun local(x: Int) {}
// test(::local, 1 + 1) test(::local, 1 + 1)
//
// // TODO: Uncomment when `suspend fun` will be supported // TODO: Uncomment when `suspend fun` will be supported
// // test(suspend fun(s: String) = s, 1) // test(suspend fun(s: String) = s, 1)
// // test(suspend fun(){}, 0) // test(suspend fun(){}, 0)
// test(suspend {}, 1) test(suspend {}, 1)
return "OK" return "OK"
} }
@@ -1,6 +1,5 @@
// IGNORE_BACKEND: NATIVE // IGNORE_BACKEND: NATIVE
// IGNORE_BACKEND: JS_IR, JS // IGNORE_BACKEND: JS_IR, JS
// IGNORE_BACKEND: JVM_IR
// WITH_RUNTIME // WITH_RUNTIME
// WITH_COROUTINES // WITH_COROUTINES