Implement correct is check for SuspendFunction
Let callable references implement SuspendFunction Do not generate CHECKCAST SuspendFunction when LV is 1.2 #KT-25825: Fixed
This commit is contained in:
@@ -4658,7 +4658,7 @@ The "returned" value of try expression with no finally is either the last expres
|
||||
return null;
|
||||
}
|
||||
|
||||
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type);
|
||||
CodegenUtilKt.generateIsCheck(v, rhsKotlinType, type, state.getLanguageVersionSettings().supportsFeature(LanguageFeature.ReleaseCoroutines));
|
||||
return null;
|
||||
});
|
||||
}
|
||||
|
||||
@@ -57,6 +57,12 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
|
||||
createCoroutineSuperClass("RestrictedSuspendLambda")
|
||||
}
|
||||
|
||||
private val suspendFunctionInterface by lazy {
|
||||
if (languageVersionSettings.isReleaseCoroutines())
|
||||
createClass(kotlinCoroutinesJvmInternalPackage, "SuspendFunction", ClassKind.INTERFACE)
|
||||
else null
|
||||
}
|
||||
|
||||
private fun createCoroutineSuperClass(className: String): ClassDescriptor {
|
||||
return if (languageVersionSettings.isReleaseCoroutines())
|
||||
createClass(kotlinCoroutinesJvmInternalPackage, className)
|
||||
@@ -145,7 +151,8 @@ class JvmRuntimeTypes(module: ModuleDescriptor, private val languageVersionSetti
|
||||
referencedFunction.isSuspend
|
||||
)
|
||||
|
||||
return listOf(functionReference.defaultType, functionType)
|
||||
val suspendFunctionType = if (referencedFunction.isSuspend) suspendFunctionInterface?.defaultType else null
|
||||
return listOfNotNull(functionReference.defaultType, functionType, suspendFunctionType)
|
||||
}
|
||||
|
||||
fun getSupertypeForPropertyReference(descriptor: VariableDescriptorWithAccessors, isMutable: Boolean, isBound: Boolean): KotlinType {
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
/*
|
||||
* Copyright 2000-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* Copyright 2010-2018 JetBrains s.r.o. Use of this source code is governed by the Apache 2.0 license
|
||||
* that can be found in the license/LICENSE.txt file.
|
||||
*/
|
||||
|
||||
@@ -59,10 +59,12 @@ import java.io.PrintWriter
|
||||
import java.io.StringWriter
|
||||
import java.util.*
|
||||
|
||||
@JvmOverloads
|
||||
fun generateIsCheck(
|
||||
v: InstructionAdapter,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type
|
||||
asmType: Type,
|
||||
isReleaseCoroutines: Boolean = false
|
||||
) {
|
||||
if (TypeUtils.isNullableType(kotlinType)) {
|
||||
val nope = Label()
|
||||
@@ -73,7 +75,7 @@ fun generateIsCheck(
|
||||
|
||||
ifnull(nope)
|
||||
|
||||
TypeIntrinsics.instanceOf(this, kotlinType, asmType)
|
||||
TypeIntrinsics.instanceOf(this, kotlinType, asmType, isReleaseCoroutines)
|
||||
|
||||
goTo(end)
|
||||
|
||||
@@ -84,15 +86,17 @@ fun generateIsCheck(
|
||||
mark(end)
|
||||
}
|
||||
} else {
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
|
||||
}
|
||||
}
|
||||
|
||||
@JvmOverloads
|
||||
fun generateAsCast(
|
||||
v: InstructionAdapter,
|
||||
kotlinType: KotlinType,
|
||||
asmType: Type,
|
||||
isSafe: Boolean
|
||||
isSafe: Boolean,
|
||||
isReleaseCoroutines: Boolean = false
|
||||
) {
|
||||
if (!isSafe) {
|
||||
if (!TypeUtils.isNullableType(kotlinType)) {
|
||||
@@ -101,7 +105,7 @@ fun generateAsCast(
|
||||
} else {
|
||||
with(v) {
|
||||
dup()
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType)
|
||||
TypeIntrinsics.instanceOf(v, kotlinType, asmType, isReleaseCoroutines)
|
||||
val ok = Label()
|
||||
ifne(ok)
|
||||
pop()
|
||||
|
||||
@@ -1,17 +1,6 @@
|
||||
/*
|
||||
* Copyright 2010-2015 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.
|
||||
* Copyright 2010-2018 JetBrains s.r.o. 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.codegen.intrinsics
|
||||
@@ -19,8 +8,10 @@ package org.jetbrains.kotlin.codegen.intrinsics
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns.FQ_NAMES
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.AsmTypes
|
||||
import org.jetbrains.kotlin.types.KotlinType
|
||||
import org.jetbrains.kotlin.types.TypeUtils
|
||||
import org.jetbrains.org.objectweb.asm.Label
|
||||
import org.jetbrains.org.objectweb.asm.Opcodes
|
||||
import org.jetbrains.org.objectweb.asm.Type
|
||||
import org.jetbrains.org.objectweb.asm.commons.InstructionAdapter
|
||||
@@ -28,7 +19,8 @@ import org.jetbrains.org.objectweb.asm.tree.*
|
||||
import kotlin.text.Regex
|
||||
|
||||
object TypeIntrinsics {
|
||||
@JvmStatic fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type) {
|
||||
@JvmStatic
|
||||
fun instanceOf(v: InstructionAdapter, jetType: KotlinType, boxedAsmType: Type, isReleaseCoroutines: Boolean) {
|
||||
val functionTypeArity = getFunctionTypeArity(jetType)
|
||||
if (functionTypeArity >= 0) {
|
||||
v.iconst(functionTypeArity)
|
||||
@@ -36,6 +28,30 @@ object TypeIntrinsics {
|
||||
return
|
||||
}
|
||||
|
||||
if (isReleaseCoroutines) {
|
||||
val suspendFunctionTypeArity = getSuspendFunctionTypeArity(jetType)
|
||||
if (suspendFunctionTypeArity >= 0) {
|
||||
val notSuspendLambda = Label()
|
||||
val end = Label()
|
||||
|
||||
with(v) {
|
||||
dup()
|
||||
instanceOf(AsmTypes.SUSPEND_FUNCTION_TYPE)
|
||||
ifeq(notSuspendLambda)
|
||||
iconst(suspendFunctionTypeArity + 1)
|
||||
typeIntrinsic(IS_FUNCTON_OF_ARITY_METHOD_NAME, IS_FUNCTON_OF_ARITY_DESCRIPTOR)
|
||||
goTo(end)
|
||||
|
||||
mark(notSuspendLambda)
|
||||
pop()
|
||||
iconst(0)
|
||||
|
||||
mark(end)
|
||||
}
|
||||
return
|
||||
}
|
||||
}
|
||||
|
||||
val isMutableCollectionMethodName = getIsMutableCollectionMethodName(jetType)
|
||||
if (isMutableCollectionMethodName != null) {
|
||||
v.typeIntrinsic(isMutableCollectionMethodName, IS_MUTABLE_COLLECTION_METHOD_DESCRIPTOR)
|
||||
@@ -148,16 +164,26 @@ object TypeIntrinsics {
|
||||
}
|
||||
|
||||
private val KOTLIN_FUNCTION_INTERFACE_REGEX = Regex("^kotlin\\.Function([0-9]+)$")
|
||||
// TODO: move to correct package
|
||||
private val KOTLIN_SUSPEND_FUNCTION_INTERFACE_REGEX = Regex("^kotlin\\.SuspendFunction([0-9]+)$")
|
||||
|
||||
/**
|
||||
* @return function type arity (non-negative), or -1 if the given type is not a function type
|
||||
*/
|
||||
private fun getFunctionTypeArity(jetType: KotlinType): Int {
|
||||
val classFqName = getClassFqName(jetType) ?: return -1
|
||||
val match = KOTLIN_FUNCTION_INTERFACE_REGEX.find(classFqName.asString()) ?: return -1
|
||||
private fun getFunctionTypeArity(kotlinType: KotlinType): Int = getFunctionTypeArityByRegex(kotlinType, KOTLIN_FUNCTION_INTERFACE_REGEX)
|
||||
|
||||
private fun getFunctionTypeArityByRegex(kotlinType: KotlinType, regex: Regex): Int {
|
||||
val classFqName = getClassFqName(kotlinType) ?: return -1
|
||||
val match = regex.find(classFqName.asString()) ?: return -1
|
||||
return Integer.valueOf(match.groups[1]!!.value)
|
||||
}
|
||||
|
||||
/**
|
||||
* @return function type arity (non-negative, counting continuation), or -1 if the given type is not a function type
|
||||
*/
|
||||
private fun getSuspendFunctionTypeArity(kotlinType: KotlinType): Int =
|
||||
getFunctionTypeArityByRegex(kotlinType, KOTLIN_SUSPEND_FUNCTION_INTERFACE_REGEX)
|
||||
|
||||
private fun typeIntrinsicNode(methodName: String, methodDescriptor: String): MethodInsnNode =
|
||||
MethodInsnNode(Opcodes.INVOKESTATIC, INTRINSICS_CLASS, methodName, methodDescriptor, false)
|
||||
|
||||
|
||||
Reference in New Issue
Block a user