JVM_IR: resolve inline fake overrides before codegen
See KT-33054 and KT-29242.
This commit is contained in:
@@ -298,6 +298,7 @@ private val jvmFilePhases =
|
|||||||
additionalClassAnnotationPhase then
|
additionalClassAnnotationPhase then
|
||||||
typeOperatorLowering then
|
typeOperatorLowering then
|
||||||
replaceKFunctionInvokeWithFunctionInvokePhase then
|
replaceKFunctionInvokeWithFunctionInvokePhase then
|
||||||
|
resolveInlineCallsPhase then
|
||||||
|
|
||||||
checkLocalNamesWithOldBackendPhase then
|
checkLocalNamesWithOldBackendPhase then
|
||||||
|
|
||||||
|
|||||||
+2
-5
@@ -965,9 +965,8 @@ class ExpressionCodegen(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
val original = (callee as? IrSimpleFunction)?.resolveFakeOverride() ?: irFunction
|
|
||||||
val methodOwner = callee.parent.safeAs<IrClass>()?.let(typeMapper::mapClass) ?: MethodSignatureMapper.FAKE_OWNER_TYPE
|
val methodOwner = callee.parent.safeAs<IrClass>()?.let(typeMapper::mapClass) ?: MethodSignatureMapper.FAKE_OWNER_TYPE
|
||||||
val sourceCompiler = IrSourceCompilerForInline(state, element, original, this, data)
|
val sourceCompiler = IrSourceCompilerForInline(state, element, callee, this, data)
|
||||||
|
|
||||||
val reifiedTypeInliner = ReifiedTypeInliner(mappings, object : ReifiedTypeInliner.IntrinsicsSupport<IrType> {
|
val reifiedTypeInliner = ReifiedTypeInliner(mappings, object : ReifiedTypeInliner.IntrinsicsSupport<IrType> {
|
||||||
override fun putClassInstance(v: InstructionAdapter, type: IrType) {
|
override fun putClassInstance(v: InstructionAdapter, type: IrType) {
|
||||||
@@ -977,9 +976,7 @@ class ExpressionCodegen(
|
|||||||
override fun toKotlinType(type: IrType): KotlinType = type.toKotlinType()
|
override fun toKotlinType(type: IrType): KotlinType = type.toKotlinType()
|
||||||
}, IrTypeCheckerContext(context.irBuiltIns), state.languageVersionSettings)
|
}, IrTypeCheckerContext(context.irBuiltIns), state.languageVersionSettings)
|
||||||
|
|
||||||
return IrInlineCodegen(
|
return IrInlineCodegen(this, state, callee.descriptor, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner)
|
||||||
this, state, original.descriptor, methodOwner, signature, mappings, sourceCompiler, reifiedTypeInliner
|
|
||||||
)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) {
|
override fun consumeReifiedOperationMarker(typeParameter: TypeParameterMarker) {
|
||||||
|
|||||||
+43
@@ -0,0 +1,43 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2019 JetBrains s.r.o. and Kotlin Programming Language contributors.
|
||||||
|
* 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.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||||
|
import org.jetbrains.kotlin.backend.jvm.codegen.isInlineFunctionCall
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||||
|
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||||
|
import org.jetbrains.kotlin.ir.util.copyTypeAndValueArgumentsFrom
|
||||||
|
import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
|
||||||
|
internal val resolveInlineCallsPhase = makeIrFilePhase(
|
||||||
|
::ResolveInlineCalls,
|
||||||
|
name = "ResolveInlineCalls",
|
||||||
|
description = "Statically resolve calls to inline methods to particular implementations"
|
||||||
|
)
|
||||||
|
|
||||||
|
class ResolveInlineCalls(val context: JvmBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||||
|
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall): IrExpression {
|
||||||
|
if (!expression.symbol.owner.isInlineFunctionCall(context))
|
||||||
|
return super.visitCall(expression)
|
||||||
|
val maybeFakeOverride = expression.symbol.owner as? IrSimpleFunction
|
||||||
|
?: return super.visitCall(expression)
|
||||||
|
val resolved = maybeFakeOverride.resolveFakeOverride()
|
||||||
|
?: return super.visitCall(expression)
|
||||||
|
return super.visitCall(with(expression) {
|
||||||
|
IrCallImpl(startOffset, endOffset, type, resolved.symbol, superQualifierSymbol).apply {
|
||||||
|
copyTypeAndValueArgumentsFrom(expression)
|
||||||
|
}
|
||||||
|
})
|
||||||
|
}
|
||||||
|
}
|
||||||
+24
@@ -0,0 +1,24 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// IGNORE_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
// See also kt33054.kt
|
||||||
|
|
||||||
|
fun causesVerifyErrorSample(): Sample<Boolean> = Sample
|
||||||
|
.Success(true)
|
||||||
|
.flatMap { Sample.Failure(RuntimeException()) }
|
||||||
|
|
||||||
|
sealed class Sample<out T> {
|
||||||
|
inline fun <R> flatMap(f: (T) -> Sample<R>): Sample<R> =
|
||||||
|
when (this) {
|
||||||
|
is Failure -> this
|
||||||
|
is Success -> f(this.value)
|
||||||
|
}
|
||||||
|
|
||||||
|
data class Failure(val exception: Throwable): Sample<Nothing>()
|
||||||
|
data class Success<out T>(val value: T): Sample<T>()
|
||||||
|
}
|
||||||
|
|
||||||
|
fun box(): String {
|
||||||
|
causesVerifyErrorSample()
|
||||||
|
return "OK"
|
||||||
|
}
|
||||||
+19
@@ -0,0 +1,19 @@
|
|||||||
|
// TARGET_BACKEND: JVM
|
||||||
|
// IGNORE_BACKEND: JVM
|
||||||
|
// JVM_TARGET: 1.8
|
||||||
|
|
||||||
|
open class A(val x: String) {
|
||||||
|
inline fun f() = if (this is C) this else A("O")
|
||||||
|
|
||||||
|
val y
|
||||||
|
inline get() = if (this is C) this else A("K")
|
||||||
|
}
|
||||||
|
|
||||||
|
class B : A("unused")
|
||||||
|
class C : A("unused")
|
||||||
|
|
||||||
|
// If the receiver is not CHECKCASTed to A when inlining, asm will infer Object
|
||||||
|
// for the result of `if` in `f` instead of A when generating stack maps because
|
||||||
|
// one branch has type A while the other has type B (a subtype of A, but asm
|
||||||
|
// does not know that). This would cause a JVM validation error.
|
||||||
|
fun box() = B().f().x + B().y.x
|
||||||
+10
@@ -14519,6 +14519,16 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
|||||||
runTest("compiler/testData/codegen/box/jvm8/kt16588.kt");
|
runTest("compiler/testData/codegen/box/jvm8/kt16588.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt29242.kt")
|
||||||
|
public void testKt29242() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/jvm8/kt29242.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt33054.kt")
|
||||||
|
public void testKt33054() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/jvm8/kt33054.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt6301.kt")
|
@TestMetadata("kt6301.kt")
|
||||||
public void testKt6301() throws Exception {
|
public void testKt6301() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/jvm8/kt6301.kt");
|
runTest("compiler/testData/codegen/box/jvm8/kt6301.kt");
|
||||||
|
|||||||
+10
@@ -14446,6 +14446,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
|||||||
@TestDataPath("$PROJECT_ROOT")
|
@TestDataPath("$PROJECT_ROOT")
|
||||||
@RunWith(JUnit3RunnerWithInners.class)
|
@RunWith(JUnit3RunnerWithInners.class)
|
||||||
public static class Jvm8 extends AbstractLightAnalysisModeTest {
|
public static class Jvm8 extends AbstractLightAnalysisModeTest {
|
||||||
|
@TestMetadata("kt29242.kt")
|
||||||
|
public void ignoreKt29242() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/jvm8/kt29242.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt33054.kt")
|
||||||
|
public void ignoreKt33054() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/jvm8/kt33054.kt");
|
||||||
|
}
|
||||||
|
|
||||||
private void runTest(String testDataFilePath) throws Exception {
|
private void runTest(String testDataFilePath) throws Exception {
|
||||||
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM, testDataFilePath);
|
||||||
}
|
}
|
||||||
|
|||||||
+10
@@ -13404,6 +13404,16 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
|||||||
runTest("compiler/testData/codegen/box/jvm8/kt16588.kt");
|
runTest("compiler/testData/codegen/box/jvm8/kt16588.kt");
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt29242.kt")
|
||||||
|
public void testKt29242() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/jvm8/kt29242.kt");
|
||||||
|
}
|
||||||
|
|
||||||
|
@TestMetadata("kt33054.kt")
|
||||||
|
public void testKt33054() throws Exception {
|
||||||
|
runTest("compiler/testData/codegen/box/jvm8/kt33054.kt");
|
||||||
|
}
|
||||||
|
|
||||||
@TestMetadata("kt6301.kt")
|
@TestMetadata("kt6301.kt")
|
||||||
public void testKt6301() throws Exception {
|
public void testKt6301() throws Exception {
|
||||||
runTest("compiler/testData/codegen/box/jvm8/kt6301.kt");
|
runTest("compiler/testData/codegen/box/jvm8/kt6301.kt");
|
||||||
|
|||||||
Reference in New Issue
Block a user