[JVM IR] Fix JvmOverloads+Parameterless Main

Resolves the interaction of @JvmOverloads annotations and
parameterless main methods.

In the following code, both mechanisms generate methods that
ultimately produce the signature `public static void main(String[] args)`
of which there can be only one (true in general of any signature).

```
fun main() { }

@JvmOverloads
fun main(Array<String> args, x: Int = 42) { }
```

This PR simply shuffles the lowerings around, letting parameterless
main methods detect the presence of the default overload produced by
the annotation.

Additionally, this PR improves the testing of parameterless main
methods by actual bytecode patterns, and not simple check for
successful compilation (as @sfs and I discovered, there are issues in
flagging an error on duplicate signatures on the IR backend).
This commit is contained in:
Kristoffer Andersen
2019-11-11 13:25:26 +01:00
committed by Alexander Udalov
parent b4185c9d47
commit 4973baae4e
10 changed files with 62 additions and 11 deletions
@@ -210,15 +210,8 @@ private val syntheticAccessorPhase = makeIrFilePhase(
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase) prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase)
) )
private val mainMethodGenerationPhase = makeIrFilePhase(
::MainMethodGenerationLowering,
name = "MainMethodGeneration",
description = "Identify parameterless main methods and generate bridge main-methods"
)
@Suppress("Reformat") @Suppress("Reformat")
private val jvmFilePhases = private val jvmFilePhases =
mainMethodGenerationPhase then
typeAliasAnnotationMethodsPhase then typeAliasAnnotationMethodsPhase then
stripTypeAliasDeclarationsPhase then stripTypeAliasDeclarationsPhase then
provisionalFunctionExpressionPhase then provisionalFunctionExpressionPhase then
@@ -299,6 +292,8 @@ private val jvmFilePhases =
checkLocalNamesWithOldBackendPhase then checkLocalNamesWithOldBackendPhase then
mainMethodGenerationPhase then
// should be last transformation // should be last transformation
removeDeclarationsThatWouldBeInlined then removeDeclarationsThatWouldBeInlined then
makePatchParentsPhase(3) makePatchParentsPhase(3)
@@ -8,6 +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.ir.allParameters import org.jetbrains.kotlin.backend.common.ir.allParameters
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
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.getJvmNameFromAnnotation import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
@@ -28,6 +29,13 @@ import org.jetbrains.kotlin.ir.util.functions
import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.types.Variance import org.jetbrains.kotlin.types.Variance
internal val mainMethodGenerationPhase = makeIrFilePhase(
::MainMethodGenerationLowering,
name = "MainMethodGeneration",
description = "Identify parameterless main methods and generate bridge main-methods",
prerequisite = setOf(jvmOverloadsAnnotationPhase)
)
internal class MainMethodGenerationLowering(val context: JvmBackendContext) : ClassLoweringPass { internal class MainMethodGenerationLowering(val context: JvmBackendContext) : ClassLoweringPass {
override fun lower(irClass: IrClass) { override fun lower(irClass: IrClass) {
@@ -5,4 +5,6 @@ fun main() {
@JvmName("main") @JvmName("main")
fun foo(args: Array<String>) { fun foo(args: Array<String>) {
} }
// 0 INVOKESTATIC DontGenerateOnJvmNameMainKt\.main ()V
@@ -0,0 +1,11 @@
// IGNORE_BACKEND: JVM
fun main() {
println("FAIL")
}
@JvmOverloads
fun Array<String>.main(x: Int = 4, y: String = "Test") {
println("OK")
}
// 0 INVOKESTATIC DontGenerateOnJvmOverloadsKt\.main ()V
@@ -4,4 +4,6 @@ fun main() {
fun main(args: Array<String>) { fun main(args: Array<String>) {
} }
// 0 INVOKESTATIC DontGenerateOnMainKt\.main ()V
@@ -4,4 +4,6 @@ fun main() {
fun Array<String>.main() { fun Array<String>.main() {
} }
// 0 INVOKESTATIC DontGenerateOnMainExtensionKt\.main ()V
@@ -4,4 +4,6 @@ fun main() {
fun main(args: Array<String>?) { fun main(args: Array<String>?) {
} }
// 0 INVOKESTATIC DontGenerateOnNullableArrayKt\.main ()V
@@ -0,0 +1,9 @@
fun main() {
}
fun main(vararg args: String) {
}
// 0 INVOKESTATIC DontGenerateOnVarargsStringKt\.main ()V
@@ -3545,6 +3545,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnJvmNameMain.kt"); runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnJvmNameMain.kt");
} }
@TestMetadata("dontGenerateOnJvmOverloads.kt")
public void testDontGenerateOnJvmOverloads() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnJvmOverloads.kt");
}
@TestMetadata("dontGenerateOnMain.kt") @TestMetadata("dontGenerateOnMain.kt")
public void testDontGenerateOnMain() throws Exception { public void testDontGenerateOnMain() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnMain.kt"); runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnMain.kt");
@@ -3559,6 +3564,11 @@ public class BytecodeTextTestGenerated extends AbstractBytecodeTextTest {
public void testDontGenerateOnNullableArray() throws Exception { public void testDontGenerateOnNullableArray() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnNullableArray.kt"); runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnNullableArray.kt");
} }
@TestMetadata("dontGenerateOnVarargsString.kt")
public void testDontGenerateOnVarargsString() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnVarargsString.kt");
}
} }
@TestMetadata("compiler/testData/codegen/bytecodeText/properties") @TestMetadata("compiler/testData/codegen/bytecodeText/properties")
@@ -3463,6 +3463,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnJvmNameMain.kt"); runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnJvmNameMain.kt");
} }
@TestMetadata("dontGenerateOnJvmOverloads.kt")
public void testDontGenerateOnJvmOverloads() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnJvmOverloads.kt");
}
@TestMetadata("dontGenerateOnMain.kt") @TestMetadata("dontGenerateOnMain.kt")
public void testDontGenerateOnMain() throws Exception { public void testDontGenerateOnMain() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnMain.kt"); runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnMain.kt");
@@ -3477,6 +3482,11 @@ public class IrBytecodeTextTestGenerated extends AbstractIrBytecodeTextTest {
public void testDontGenerateOnNullableArray() throws Exception { public void testDontGenerateOnNullableArray() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnNullableArray.kt"); runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnNullableArray.kt");
} }
@TestMetadata("dontGenerateOnVarargsString.kt")
public void testDontGenerateOnVarargsString() throws Exception {
runTest("compiler/testData/codegen/bytecodeText/parameterlessMain/dontGenerateOnVarargsString.kt");
}
} }
@TestMetadata("compiler/testData/codegen/bytecodeText/properties") @TestMetadata("compiler/testData/codegen/bytecodeText/properties")