JVM IR: add isInlineClassType, use it instead of isInlined

This commit is contained in:
Alexander Udalov
2021-03-24 22:31:12 +01:00
parent 770401801b
commit c17b6c59f8
18 changed files with 83 additions and 19 deletions
@@ -18018,6 +18018,12 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@Test
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@Test
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
@@ -22,6 +22,7 @@ import org.jetbrains.kotlin.backend.common.ir.ir2string
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.JvmSymbols
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.AsmUtil
import org.jetbrains.kotlin.codegen.TypeAnnotationCollector
@@ -275,7 +276,7 @@ abstract class AnnotationCodegen(
is IrClassReference -> {
var classType = value.classType
classType.classOrNull?.owner?.let(innerClassConsumer::addInnerClassInfoFromAnnotation)
if (classType.isInlined()) {
if (classType.isInlineClassType()) {
classType = classType.makeNullable()
}
annotationVisitor.visit(name, typeMapper.mapType(classType))
@@ -13,10 +13,12 @@ import org.jetbrains.kotlin.backend.jvm.intrinsics.IrIntrinsicMethods
import org.jetbrains.kotlin.backend.jvm.intrinsics.JavaClassProperty
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isFromJava
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.backend.jvm.lower.MultifileFacadeFileEntry
import org.jetbrains.kotlin.backend.jvm.lower.constantValue
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isInlineCallableReference
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.isMappedToPrimitive
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.requiresMangling
import org.jetbrains.kotlin.backend.jvm.lower.inlineclasses.unboxInlineClass
import org.jetbrains.kotlin.backend.jvm.lower.isMultifileBridge
import org.jetbrains.kotlin.backend.jvm.lower.suspendFunctionOriginal
@@ -633,7 +635,7 @@ class ExpressionCodegen(
// it generates them as normal functions and not objects.
// Thus, we need to unbox inline class argument with reference underlying type.
private fun unboxInlineClassArgumentOfInlineCallableReference(arg: IrGetValue) {
if (!arg.type.erasedUpperBound.isInline) return
if (!arg.type.isInlineClassType()) return
if (arg.type.isMappedToPrimitive) return
if (!irFunction.isInlineCallableReference) return
if (irFunction.extensionReceiverParameter?.symbol == arg.symbol) return
@@ -670,9 +672,7 @@ class ExpressionCodegen(
private fun IrClass.isSamAdapter(): Boolean = this.superTypes.any { it.getClass()?.isFun == true }
private fun onlyResultInlineClassParameters(): Boolean = irFunction.valueParameters.all {
!it.type.erasedUpperBound.isInline || it.type.erasedUpperBound.fqNameWhenAvailable == StandardNames.RESULT_FQ_NAME
}
private fun onlyResultInlineClassParameters(): Boolean = irFunction.valueParameters.all { !it.type.requiresMangling }
private fun hasBridge(): Boolean = irFunction.parentAsClass.declarations.any { function ->
function is IrFunction && function != irFunction &&
@@ -699,7 +699,7 @@ class ExpressionCodegen(
?: receiverType ?: typeMapper.mapClass(callee.parentAsClass)
val ownerName = ownerType.internalName
val fieldName = callee.name.asString()
val calleeIrType = if (callee.isFromJava() && callee.type.isInlined()) callee.type.makeNullable() else callee.type
val calleeIrType = if (callee.isFromJava() && callee.type.isInlineClassType()) callee.type.makeNullable() else callee.type
val fieldType = calleeIrType.asmType
return if (expression is IrSetField) {
val value = expression.value.accept(this, data)
@@ -203,7 +203,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
isBoxMethodForInlineClass(function) ||
forceFoxedReturnTypeOnOverride(function) ||
forceBoxedReturnTypeOnDefaultImplFun(function) ||
function.isFromJava() && function.returnType.isInlined()
function.isFromJava() && function.returnType.isInlineClassType()
private fun forceFoxedReturnTypeOnOverride(function: IrFunction) =
function is IrSimpleFunction &&
@@ -225,7 +225,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
if (isBoundReceiver) return false
if (function !is IrSimpleFunction) return false
if (!function.isInlineCallableReference) return false
return type.erasedUpperBound.isInline && !type.isMappedToPrimitive
return type.isInlineClassType() && !type.isMappedToPrimitive
}
fun mapSignatureSkipGeneric(function: IrFunction): JvmMethodSignature =
@@ -341,7 +341,7 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
private fun writeParameterType(sw: JvmSignatureWriter, type: IrType, declaration: IrDeclaration, isReceiver: Boolean) {
if (sw.skipGenericSignature()) {
if (type.isInlined() &&
if (type.isInlineClassType() &&
(declaration.isFromJava() || forceBoxedInlineClassParametersForInliner(declaration, type, isReceiver))
) {
typeMapper.mapType(type, TypeMappingMode.GENERIC_ARGUMENT, sw)
@@ -400,3 +400,6 @@ fun IrClass.getSingleAbstractMethod(): IrSimpleFunction? =
fun IrFile.getKtFile(): KtFile? =
(fileEntry as? PsiIrFileEntry)?.psiFile as KtFile?
fun IrType.isInlineClassType(): Boolean =
erasedUpperBound.isInline
@@ -558,7 +558,9 @@ internal class FunctionReferenceLowering(private val context: JvmBackendContext)
functionReferenceClass.addFunction {
setSourceRange(if (isLambda) callee else irFunctionReference)
name =
if (samSuperType == null && callee.returnType.erasedUpperBound.isInline && context.state.functionsWithInlineClassReturnTypesMangled) {
if (samSuperType == null && callee.returnType.isInlineClassType() &&
context.state.functionsWithInlineClassReturnTypesMangled
) {
// For functions with inline class return type we need to mangle the invoke method.
// Otherwise, bridge lowering may fail to generate bridges for inline class types erasing to Any.
val suffix = InlineClassAbi.hashReturnSuffix(callee)
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.backend.jvm.codegen.fileParent
import org.jetbrains.kotlin.backend.jvm.ir.createJvmIrBuilder
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.getKtFile
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.builders.*
@@ -29,7 +30,6 @@ import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.util.dump
import org.jetbrains.kotlin.ir.util.isInlined
import org.jetbrains.kotlin.ir.util.render
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
@@ -383,7 +383,7 @@ private class TypeOperatorLowering(private val context: JvmBackendContext) : Fil
irType = context.irBuiltIns.anyNType
) { valueSymbol ->
val thenPart =
if (valueSymbol.owner.type.isInlined())
if (valueSymbol.owner.type.isInlineClassType())
lowerCast(irGet(valueSymbol.owner), expression.typeOperand)
else
irGet(valueSymbol.owner)
@@ -6,6 +6,7 @@
package org.jetbrains.kotlin.backend.jvm.lower.inlineclasses
import org.jetbrains.kotlin.backend.jvm.ir.erasedUpperBound
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.backend.jvm.lower.STUB_FOR_INLINING
import org.jetbrains.kotlin.builtins.StandardNames
import org.jetbrains.kotlin.codegen.state.InfoForMangling
@@ -131,7 +132,7 @@ object InlineClassAbi {
private fun IrType.asInfoForMangling(): InfoForMangling =
InfoForMangling(
erasedUpperBound.fqNameWhenAvailable!!.toUnsafe(),
isInline = erasedUpperBound.isInline,
isInline = isInlineClassType(),
isNullable = isNullable()
)
@@ -154,7 +155,7 @@ internal val IrFunction.hasMangledParameters: Boolean
(this is IrConstructor && constructedClass.isInline)
internal val IrFunction.hasMangledReturnType: Boolean
get() = returnType.erasedUpperBound.isInline && parentClassOrNull?.isFileClass != true
get() = returnType.isInlineClassType() && parentClassOrNull?.isFileClass != true
private val IrClass.singlePrimaryConstructorParameter: IrValueParameter
get() {
@@ -178,6 +179,6 @@ val IrFunction.isInlineCallableReference: Boolean
get() = origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA && name.asString().contains("\$$STUB_FOR_INLINING")
val IrType.isMappedToPrimitive: Boolean
get() = erasedUpperBound.isInline &&
get() = isInlineClassType() &&
!(isNullable() && makeNotNull().unboxInlineClass().isNullable()) &&
makeNotNull().unboxInlineClass().isPrimitiveType()
@@ -17,12 +17,11 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.classifierOrFail
import org.jetbrains.kotlin.ir.types.isMarkedNullable
/**
* Returns inline class for given class or null of type is not inlined
* TODO: Make this configurable for different backends (currently implements logic of JS BE)
*/
fun IrType.getInlinedClass(): IrClass? {
private fun IrType.getInlinedClass(): IrClass? {
if (this is IrSimpleType) {
val erased = erase(this) ?: return null
if (erased.isInline) {
@@ -45,6 +44,13 @@ fun IrType.getInlinedClass(): IrClass? {
return null
}
/**
* Do not use this function in the JVM backend! Use `isInlineClassType` instead.
*
* This function has slightly different semantics for generic type parameters with inline class bounds.
*
* TODO: examine remaining usages in Native and preferably remove this function.
*/
fun IrType.isInlined(): Boolean = this.getInlinedClass() != null
private tailrec fun erase(type: IrType): IrClass? {
@@ -0,0 +1,8 @@
// IGNORE_BACKEND: JVM
interface X
inline class Z(val value: Int) : X
fun <T> test(t: T) where T : X, T : Z = t as? Int
fun box(): String = if (test(Z(42)) != null) "fail" else "OK"
@@ -18018,6 +18018,12 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@Test
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@Test
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
@@ -18018,6 +18018,12 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@Test
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@Test
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
@@ -24,6 +24,7 @@ import com.intellij.mock.MockProject
import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.backend.common.extensions.IrGenerationExtension
import org.jetbrains.kotlin.backend.common.extensions.IrPluginContext
import org.jetbrains.kotlin.backend.jvm.ir.isInlineClassType
import org.jetbrains.kotlin.compiler.plugin.ComponentRegistrar
import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.IrStatement
@@ -41,7 +42,6 @@ import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.types.makeNullable
import org.jetbrains.kotlin.ir.util.hasDefaultValue
import org.jetbrains.kotlin.ir.util.isInlined
import org.jetbrains.kotlin.ir.util.statements
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -207,7 +207,7 @@ class ComposeLikeDefaultArgumentRewriter(
val type = param.type
return when {
type.isPrimitiveType() -> type
type.isInlined() -> type
type.isInlineClassType() -> type
else -> type.makeNullable()
}
}
@@ -14941,6 +14941,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/secondaryConstructorWithVararg.kt");
@@ -13120,6 +13120,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/secondaryConstructorWithVararg.kt");
@@ -12541,6 +12541,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/secondaryConstructorWithVararg.kt");
@@ -12606,6 +12606,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest {
runTest("compiler/testData/codegen/box/inlineClasses/resultRunCatchingOrElse.kt");
}
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/secondaryConstructorWithVararg.kt");
@@ -6867,6 +6867,11 @@ public class IrCodegenBoxWasmTestGenerated extends AbstractIrCodegenBoxWasmTest
runTest("compiler/testData/codegen/box/inlineClasses/resultInlining.kt");
}
@TestMetadata("safeAsOfTypeParameterWithInlineClassBound.kt")
public void testSafeAsOfTypeParameterWithInlineClassBound() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/safeAsOfTypeParameterWithInlineClassBound.kt");
}
@TestMetadata("secondaryConstructorWithVararg.kt")
public void testSecondaryConstructorWithVararg() throws Exception {
runTest("compiler/testData/codegen/box/inlineClasses/secondaryConstructorWithVararg.kt");