JVM_IR: set dispatchReceiverParameter of imported JvmStatic object methods to null

This commit is contained in:
Georgy Bronnikov
2019-09-12 19:50:03 +03:00
parent c7904b273f
commit 4920d71d70
8 changed files with 75 additions and 11 deletions
@@ -21,10 +21,7 @@ import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.* import org.jetbrains.kotlin.ir.types.*
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.*
import org.jetbrains.kotlin.ir.util.hasAnnotation
import org.jetbrains.kotlin.ir.util.isFunction
import org.jetbrains.kotlin.ir.util.isSuspendFunctionTypeOrSubtype
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME
/** /**
@@ -120,3 +117,7 @@ fun JvmBackendContext.createJvmIrBuilder(
startOffset: Int = UNDEFINED_OFFSET, startOffset: Int = UNDEFINED_OFFSET,
endOffset: Int = UNDEFINED_OFFSET endOffset: Int = UNDEFINED_OFFSET
) = JvmIrBuilder(this, symbol, startOffset, endOffset) ) = JvmIrBuilder(this, symbol, startOffset, endOffset)
fun IrDeclaration.isInCurrentModule(): Boolean =
getPackageFragment() is IrFile
@@ -8,9 +8,7 @@ package org.jetbrains.kotlin.backend.jvm.lower
import org.jetbrains.kotlin.backend.common.ClassLoweringPass import org.jetbrains.kotlin.backend.common.ClassLoweringPass
import org.jetbrains.kotlin.backend.common.FileLoweringPass import org.jetbrains.kotlin.backend.common.FileLoweringPass
import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor import org.jetbrains.kotlin.backend.common.descriptors.WrappedSimpleFunctionDescriptor
import org.jetbrains.kotlin.backend.common.ir.copyTo import org.jetbrains.kotlin.backend.common.ir.*
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
import org.jetbrains.kotlin.backend.common.ir.passTypeArgumentsFrom
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.lower.irBlock import org.jetbrains.kotlin.backend.common.lower.irBlock
import org.jetbrains.kotlin.backend.common.lower.replaceThisByStaticReference import org.jetbrains.kotlin.backend.common.lower.replaceThisByStaticReference
@@ -18,6 +16,7 @@ import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
import org.jetbrains.kotlin.backend.common.runOnFilePostfix import org.jetbrains.kotlin.backend.common.runOnFilePostfix
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
import org.jetbrains.kotlin.backend.jvm.ir.isInCurrentModule
import org.jetbrains.kotlin.descriptors.Modality import org.jetbrains.kotlin.descriptors.Modality
import org.jetbrains.kotlin.descriptors.Visibilities import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.descriptors.Visibility import org.jetbrains.kotlin.descriptors.Visibility
@@ -192,6 +191,14 @@ private class MakeCallsStatic(
) : IrElementTransformerVoid() { ) : IrElementTransformerVoid() {
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) { if (expression.symbol.owner.isJvmStaticInSingleton() && expression.dispatchReceiver != null) {
// Imported functions do not have their receiver parameter nulled by SingletonObjectJvmStaticLowering,
// so we have to do it here.
// TODO: would be better handled by lowering imported declarations.
val callee = expression.symbol.owner as IrSimpleFunction
val newCallee = if (!callee.isInCurrentModule()) {
callee.copyRemovingDispatchReceiver() // TODO: cache these
} else callee
return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) { return context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset).irBlock(expression) {
// OldReceiver has to be evaluated for its side effects. // OldReceiver has to be evaluated for its side effects.
val oldReceiver = super.visitExpression(expression.dispatchReceiver!!) val oldReceiver = super.visitExpression(expression.dispatchReceiver!!)
@@ -205,15 +212,34 @@ private class MakeCallsStatic(
) )
+super.visitExpression(oldReceiverVoid) +super.visitExpression(oldReceiverVoid)
expression.dispatchReceiver = null +super.visitCall(
+super.visitCall(expression) irCall(expression, newFunction = newCallee).apply { dispatchReceiver = null }
)
} }
} }
return super.visitCall(expression) return super.visitCall(expression)
} }
private fun IrSimpleFunction.copyRemovingDispatchReceiver(): IrSimpleFunction {
val newDescriptor = WrappedSimpleFunctionDescriptor(descriptor)
return IrFunctionImpl(
startOffset, endOffset, origin,
IrSimpleFunctionSymbolImpl(newDescriptor),
name,
visibility, modality, returnType, isInline, isExternal, isTailrec, isSuspend
).also {
newDescriptor.bind(it)
it.parent = parent
it.correspondingPropertySymbol = correspondingPropertySymbol
it.annotations.addAll(annotations)
it.copyParameterDeclarationsFrom(this)
it.dispatchReceiverParameter = null
}
}
} }
private fun isJvmStaticFunction(declaration: IrDeclaration): Boolean = private fun isJvmStaticFunction(declaration: IrDeclaration): Boolean =
declaration is IrSimpleFunction && declaration is IrSimpleFunction &&
(declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) || (declaration.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) ||
declaration.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true) declaration.correspondingPropertySymbol?.owner?.hasAnnotation(JVM_STATIC_ANNOTATION_FQ_NAME) == true)
@@ -94,7 +94,9 @@ private class StaticDefaultCallLowering(
override fun visitCall(expression: IrCall): IrExpression { override fun visitCall(expression: IrCall): IrExpression {
val callee = expression.symbol.owner val callee = expression.symbol.owner
if (callee.origin !== IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER || callee.dispatchReceiverParameter == null) { if (callee.origin !== IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER ||
expression.dispatchReceiver == null
) {
return super.visitCall(expression) return super.visitCall(expression)
} }
@@ -0,0 +1,21 @@
// TARGET_BACKEND: JVM
// WITH_RUNTIME
// FILE: 1.kt
fun box(): String {
if (A.test() != "OK") return "fail 1"
return "OK"
}
// FILE: 2.kt
object A {
@JvmStatic fun test(b: String = "OK") : String {
return b
}
}
@@ -1,4 +1,3 @@
// IGNORE_BACKEND: JVM_IR
// TARGET_BACKEND: JVM // TARGET_BACKEND: JVM
// FILE: A.kt // FILE: A.kt
@@ -15240,6 +15240,11 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
runTest("compiler/testData/codegen/box/jvmStatic/default.kt"); runTest("compiler/testData/codegen/box/jvmStatic/default.kt");
} }
@TestMetadata("defaultCrossFile.kt")
public void testDefaultCrossFile() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/defaultCrossFile.kt");
}
@TestMetadata("enumCompanion.kt") @TestMetadata("enumCompanion.kt")
public void testEnumCompanion() throws Exception { public void testEnumCompanion() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/enumCompanion.kt"); runTest("compiler/testData/codegen/box/jvmStatic/enumCompanion.kt");
@@ -15240,6 +15240,11 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
runTest("compiler/testData/codegen/box/jvmStatic/default.kt"); runTest("compiler/testData/codegen/box/jvmStatic/default.kt");
} }
@TestMetadata("defaultCrossFile.kt")
public void testDefaultCrossFile() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/defaultCrossFile.kt");
}
@TestMetadata("enumCompanion.kt") @TestMetadata("enumCompanion.kt")
public void testEnumCompanion() throws Exception { public void testEnumCompanion() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/enumCompanion.kt"); runTest("compiler/testData/codegen/box/jvmStatic/enumCompanion.kt");
@@ -14125,6 +14125,11 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
runTest("compiler/testData/codegen/box/jvmStatic/default.kt"); runTest("compiler/testData/codegen/box/jvmStatic/default.kt");
} }
@TestMetadata("defaultCrossFile.kt")
public void testDefaultCrossFile() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/defaultCrossFile.kt");
}
@TestMetadata("enumCompanion.kt") @TestMetadata("enumCompanion.kt")
public void testEnumCompanion() throws Exception { public void testEnumCompanion() throws Exception {
runTest("compiler/testData/codegen/box/jvmStatic/enumCompanion.kt"); runTest("compiler/testData/codegen/box/jvmStatic/enumCompanion.kt");