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.
This commit is contained in:
Generated
+5
@@ -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");
|
||||
|
||||
@@ -80,7 +80,7 @@ fun IrType.substitute(params: List<IrTypeParameter>, arguments: List<IrType>): I
|
||||
substitute(params.map { it.symbol }.zip(arguments).toMap())
|
||||
|
||||
fun IrType.substitute(substitutionMap: Map<IrTypeParameterSymbol, IrType>): IrType {
|
||||
if (this !is IrSimpleType) return this
|
||||
if (this !is IrSimpleType || substitutionMap.isEmpty()) return this
|
||||
|
||||
val newAnnotations = annotations.map { it.deepCopyWithSymbols() }
|
||||
|
||||
|
||||
+13
-8
@@ -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<IrCall>()?.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) =
|
||||
|
||||
@@ -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<IrTypeParameter>
|
||||
else
|
||||
typeParameters
|
||||
|
||||
fun IrMemberAccessExpression<*>.getTypeSubstitutionMap(irFunction: IrFunction): Map<IrTypeParameterSymbol, IrType> =
|
||||
irFunction.allTypeParameters.withIndex().associate {
|
||||
fun IrMemberAccessExpression<*>.getTypeSubstitutionMap(irFunction: IrFunction): Map<IrTypeParameterSymbol, IrType> {
|
||||
val typeParameters = irFunction.allTypeParameters
|
||||
return if (typeParameters.isEmpty()) emptyMap() else typeParameters.withIndex().associate {
|
||||
it.value.symbol to getTypeArgument(it.index)!!
|
||||
}
|
||||
}
|
||||
|
||||
val IrFunctionReference.typeSubstitutionMap: Map<IrTypeParameterSymbol, IrType>
|
||||
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
|
||||
get() = attributeOwnerId as? IrProperty ?: this
|
||||
|
||||
@@ -0,0 +1,9 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
|
||||
fun <T> foo(a: IC): T = a.value as T
|
||||
|
||||
inline class IC(val value: String)
|
||||
|
||||
fun box(): String {
|
||||
return foo<String>(IC("O")) + "K"
|
||||
}
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
fun <T> 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"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
fun <T> 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"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-3
@@ -1,6 +1,4 @@
|
||||
// !LANGUAGE: +InlineClasses
|
||||
// IGNORE_BACKEND: JVM_IR
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
|
||||
fun <T> underlying(a: IC): T = bar(a, object : IFace<IC, T> {
|
||||
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"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-5
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
+1
-5
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-5
@@ -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"
|
||||
}
|
||||
}
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
Generated
+5
@@ -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");
|
||||
|
||||
+5
@@ -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");
|
||||
|
||||
Reference in New Issue
Block a user