From ad5b6da273f8d14ed196b9ad0fd54d042450038d Mon Sep 17 00:00:00 2001 From: Alexander Udalov Date: Mon, 26 Oct 2020 19:08:00 +0100 Subject: [PATCH] JVM IR: substitute generic type for inline class replacement function calls The main change here is in `JvmInlineClassLowering.visitFunctionAccess`, where we now store the substituted return type of the function as the type of the call expression. Without it, the call could have a meaningless type, e.g. some `T` which is inaccessible at that place, and that could backfire in subsequent lowerings in codegen. For example, in the `stringPlus.kt` test, it would prevent the code in `FlattenStringConcatenationLowering.isStringPlusCall` from recognizing and replacing the `String.plus` call, leading to a codegen exception. Other changes are mostly cosmetics to make the code similar to `visitFunctionReference`, and preventive optimizations for the case when the substitution map is empty. --- .../ir/FirBlackBoxCodegenTestGenerated.java | 5 +++++ .../jetbrains/kotlin/ir/util/IrTypeUtils.kt | 2 +- .../jvm/lower/JvmInlineClassLowering.kt | 21 ++++++++++++------- .../org/jetbrains/kotlin/ir/util/IrUtils.kt | 13 ++++++++---- .../codegen/box/inlineClasses/stringPlus.kt | 9 ++++++++ .../funInterface/string.kt | 4 +--- .../unboxGenericParameter/lambda/string.kt | 4 +--- .../objectLiteral/string.kt | 4 +--- .../funInterface/string.kt | 6 +----- .../unboxGenericParameter/lambda/string.kt | 6 +----- .../objectLiteral/string.kt | 6 +----- .../codegen/BlackBoxCodegenTestGenerated.java | 5 +++++ .../LightAnalysisModeTestGenerated.java | 5 +++++ .../ir/IrBlackBoxCodegenTestGenerated.java | 5 +++++ .../IrJsCodegenBoxES6TestGenerated.java | 5 +++++ .../IrJsCodegenBoxTestGenerated.java | 5 +++++ .../semantics/JsCodegenBoxTestGenerated.java | 5 +++++ 17 files changed, 73 insertions(+), 37 deletions(-) create mode 100644 compiler/testData/codegen/box/inlineClasses/stringPlus.kt diff --git a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java index 4038fbeb5c4..aa7402b0887 100644 --- a/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests/org/jetbrains/kotlin/codegen/ir/FirBlackBoxCodegenTestGenerated.java @@ -14117,6 +14117,11 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt"); diff --git a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt index 7a2a75d9ebc..94958d2ccbf 100644 --- a/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt +++ b/compiler/ir/backend.common/src/org/jetbrains/kotlin/ir/util/IrTypeUtils.kt @@ -80,7 +80,7 @@ fun IrType.substitute(params: List, arguments: List): I substitute(params.map { it.symbol }.zip(arguments).toMap()) fun IrType.substitute(substitutionMap: Map): IrType { - if (this !is IrSimpleType) return this + if (this !is IrSimpleType || substitutionMap.isEmpty()) return this val newAnnotations = annotations.map { it.deepCopyWithSymbols() } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt index a06311f4e95..3ff1811d2f7 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/JvmInlineClassLowering.kt @@ -277,15 +277,16 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F if (expression.origin == InlineClassAbi.UNMANGLED_FUNCTION_REFERENCE) return super.visitFunctionReference(expression) - val function = context.inlineClassReplacements.getReplacementFunction(expression.symbol.owner) + val function = expression.symbol.owner + val replacement = context.inlineClassReplacements.getReplacementFunction(function) ?: return super.visitFunctionReference(expression) return IrFunctionReferenceImpl( expression.startOffset, expression.endOffset, expression.type, - function.symbol, function.typeParameters.size, - function.valueParameters.size, expression.reflectionTarget, expression.origin + replacement.symbol, replacement.typeParameters.size, + replacement.valueParameters.size, expression.reflectionTarget, expression.origin ).apply { - buildReplacement(expression.symbol.owner, expression, function) + buildReplacement(function, expression, replacement) }.copyAttributes(expression) } @@ -293,10 +294,14 @@ private class JvmInlineClassLowering(private val context: JvmBackendContext) : F val function = expression.symbol.owner val replacement = context.inlineClassReplacements.getReplacementFunction(function) ?: return super.visitFunctionAccess(expression) - return context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol, expression.startOffset, expression.endOffset) - .irCall(replacement, expression.origin, expression.safeAs()?.superQualifierSymbol).apply { - buildReplacement(function, expression, replacement) - } + + return IrCallImpl( + expression.startOffset, expression.endOffset, function.returnType.substitute(expression.typeSubstitutionMap), + replacement.symbol, replacement.typeParameters.size, replacement.valueParameters.size, + expression.origin, (expression as? IrCall)?.superQualifierSymbol + ).apply { + buildReplacement(function, expression, replacement) + } } private fun coerceInlineClasses(argument: IrExpression, from: IrType, to: IrType) = diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt index cb63dd7e753..2a292d4b02d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/IrUtils.kt @@ -16,7 +16,10 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl import org.jetbrains.kotlin.ir.symbols.* -import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.IrSimpleType +import org.jetbrains.kotlin.ir.types.IrType +import org.jetbrains.kotlin.ir.types.isAny +import org.jetbrains.kotlin.ir.types.isSubtypeOf import org.jetbrains.kotlin.name.FqName import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.utils.DFS @@ -512,10 +515,12 @@ val IrFunction.allTypeParameters: List else typeParameters -fun IrMemberAccessExpression<*>.getTypeSubstitutionMap(irFunction: IrFunction): Map = - irFunction.allTypeParameters.withIndex().associate { +fun IrMemberAccessExpression<*>.getTypeSubstitutionMap(irFunction: IrFunction): Map { + val typeParameters = irFunction.allTypeParameters + return if (typeParameters.isEmpty()) emptyMap() else typeParameters.withIndex().associate { it.value.symbol to getTypeArgument(it.index)!! } +} val IrFunctionReference.typeSubstitutionMap: Map get() = getTypeSubstitutionMap(symbol.owner) @@ -536,4 +541,4 @@ val IrFunction.originalFunction: IrFunction get() = (this as? IrAttributeContainer)?.attributeOwnerId as? IrFunction ?: this val IrProperty.originalProperty: IrProperty - get() = attributeOwnerId as? IrProperty ?: this \ No newline at end of file + get() = attributeOwnerId as? IrProperty ?: this diff --git a/compiler/testData/codegen/box/inlineClasses/stringPlus.kt b/compiler/testData/codegen/box/inlineClasses/stringPlus.kt new file mode 100644 index 00000000000..37fd5117c83 --- /dev/null +++ b/compiler/testData/codegen/box/inlineClasses/stringPlus.kt @@ -0,0 +1,9 @@ +// !LANGUAGE: +InlineClasses + +fun foo(a: IC): T = a.value as T + +inline class IC(val value: String) + +fun box(): String { + return foo(IC("O")) + "K" +} diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt index fda16c3a330..9d84cf1a01c 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/funInterface/string.kt @@ -1,6 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR fun underlying(a: IC): T = bar(a) { it.value as T @@ -48,4 +46,4 @@ fun box(): String { if (res != "OK") return "FAIL 3: $res" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/lambda/string.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/lambda/string.kt index c8ec62c787c..0922f4ef605 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/lambda/string.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/lambda/string.kt @@ -1,6 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR fun underlying(a: IC): T = bar(a) { it.value as T @@ -44,4 +42,4 @@ fun box(): String { if (res != "OK") return "FAIL 3: $res" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/objectLiteral/string.kt b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/objectLiteral/string.kt index a44ea4108e5..2a911bc1760 100644 --- a/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/objectLiteral/string.kt +++ b/compiler/testData/codegen/box/inlineClasses/unboxGenericParameter/objectLiteral/string.kt @@ -1,6 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR fun underlying(a: IC): T = bar(a, object : IFace { override fun call(ic: IC): T = ic.value as T @@ -48,4 +46,4 @@ fun box(): String { if (res != "OK") return "FAIL 3: $res" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/funInterface/string.kt b/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/funInterface/string.kt index cbe2a024d65..7cb7cea35e1 100644 --- a/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/funInterface/string.kt +++ b/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/funInterface/string.kt @@ -1,8 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR, JVM_MULTI_MODULE_IR_AGAINST_OLD - // FILE: inline.kt inline class IC(val value: String) { @@ -47,4 +43,4 @@ fun box(): String { if (res != "OK") return "FAIL 3: $res" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/lambda/string.kt b/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/lambda/string.kt index 3c5cf7bed69..0072106d1cc 100644 --- a/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/lambda/string.kt +++ b/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/lambda/string.kt @@ -1,8 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR, JVM_MULTI_MODULE_IR_AGAINST_OLD - // FILE: inline.kt inline class IC(val value: String) { @@ -43,4 +39,4 @@ fun box(): String { if (res != "OK") return "FAIL 3: $res" return "OK" -} \ No newline at end of file +} diff --git a/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/objectLiteral/string.kt b/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/objectLiteral/string.kt index f8293ece19c..bdf6307c30c 100644 --- a/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/objectLiteral/string.kt +++ b/compiler/testData/codegen/boxInline/inlineClasses/unboxGenericParameter/objectLiteral/string.kt @@ -1,8 +1,4 @@ // !LANGUAGE: +InlineClasses -// IGNORE_BACKEND: JVM_IR -// IGNORE_BACKEND_FIR: JVM_IR -// IGNORE_BACKEND_MULTI_MODULE: JVM_IR, JVM_MULTI_MODULE_IR_AGAINST_OLD - // FILE: inline.kt inline class IC(val value: String) { @@ -47,4 +43,4 @@ fun box(): String { if (res != "OK") return "FAIL 3: $res" return "OK" -} \ No newline at end of file +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java index 8c27483ec16..00157a261f5 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/BlackBoxCodegenTestGenerated.java @@ -15517,6 +15517,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 78065a1b245..1f2fc652b38 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -15522,6 +15522,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt"); diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java index 23a26d18b43..cd98efd9952 100644 --- a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrBlackBoxCodegenTestGenerated.java @@ -14117,6 +14117,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java index aba203116e1..08459ac10cf 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/es6/semantics/IrJsCodegenBoxES6TestGenerated.java @@ -12122,6 +12122,11 @@ public class IrJsCodegenBoxES6TestGenerated extends AbstractIrJsCodegenBoxES6Tes runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java index a9114f89e89..ffe5f59dd02 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/ir/semantics/IrJsCodegenBoxTestGenerated.java @@ -12122,6 +12122,11 @@ public class IrJsCodegenBoxTestGenerated extends AbstractIrJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt"); diff --git a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java index c947e3968e9..94a0680eaae 100644 --- a/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java +++ b/js/js.tests/test/org/jetbrains/kotlin/js/test/semantics/JsCodegenBoxTestGenerated.java @@ -12187,6 +12187,11 @@ public class JsCodegenBoxTestGenerated extends AbstractJsCodegenBoxTest { runTest("compiler/testData/codegen/box/inlineClasses/smartCastOnThisOfInlineClassType.kt"); } + @TestMetadata("stringPlus.kt") + public void testStringPlus() throws Exception { + runTest("compiler/testData/codegen/box/inlineClasses/stringPlus.kt"); + } + @TestMetadata("toStringCallingPrivateFun.kt") public void testToStringCallingPrivateFun() throws Exception { runTest("compiler/testData/codegen/box/inlineClasses/toStringCallingPrivateFun.kt");