JVM IR: Support parameterless main methods
This commit: - introduces tests explicating what is and isn't considered a proper main method on the JVM backends. - implements support for parameterless main methods on the JVM IR backend - See KT-34338 for more tests.
This commit is contained in:
committed by
Alexander Udalov
parent
4b77db8979
commit
28b6913a25
@@ -43,4 +43,5 @@ interface JvmLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||
object SYNTHETIC_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("SYNTHETIC_INLINE_CLASS_MEMBER", isSynthetic = true)
|
||||
object INLINE_CLASS_GENERATED_IMPL_METHOD : IrDeclarationOriginImpl("INLINE_CLASS_GENERATED_IMPL_METHOD")
|
||||
object GENERATED_ASSERTION_ENABLED_FIELD : IrDeclarationOriginImpl("GENERATED_ASSERTION_ENABLED_FIELD", isSynthetic = true)
|
||||
object GENERATED_MAIN_FOR_PARAMETERLESS_MAIN_METHOD : IrDeclarationOriginImpl("GENERATED_MAIN_FOR_PARAMETERLESS_MAIN_METHOD", isSynthetic = true)
|
||||
}
|
||||
|
||||
@@ -172,8 +172,15 @@ private val syntheticAccessorPhase = makeIrFilePhase(
|
||||
prerequisite = setOf(objectClassPhase, staticDefaultFunctionPhase, interfacePhase)
|
||||
)
|
||||
|
||||
private val mainMethodGenerationPhase = makeIrFilePhase(
|
||||
::MainMethodGenerationLowering,
|
||||
name = "MainMethodGeneration",
|
||||
description = "Identify parameterless main methods and generate bridge main-methods"
|
||||
)
|
||||
|
||||
@Suppress("Reformat")
|
||||
private val jvmFilePhases =
|
||||
mainMethodGenerationPhase then
|
||||
typeAliasAnnotationMethodsPhase then
|
||||
stripTypeAliasDeclarationsPhase then
|
||||
provisionalFunctionExpressionPhase then
|
||||
|
||||
+1
-5
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.backend.common.lower.allOverridden
|
||||
import org.jetbrains.kotlin.backend.common.lower.parentsWithSelf
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.hasJvmDefault
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.propertyIfAccessor
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
@@ -122,11 +123,6 @@ class MethodSignatureMapper(private val context: JvmBackendContext) {
|
||||
getJvmModuleNameForDeserializedDescriptor(function.descriptor)
|
||||
else null) ?: context.state.moduleName
|
||||
|
||||
private fun IrDeclaration.getJvmNameFromAnnotation(): String? {
|
||||
val const = getAnnotation(DescriptorUtils.JVM_NAME)?.getValueArgument(0) as? IrConst<*>
|
||||
return const?.value as? String
|
||||
}
|
||||
|
||||
private fun IrFunction.isPublishedApi(): Boolean =
|
||||
propertyIfAccessor.annotations.hasAnnotation(KotlinBuiltIns.FQ_NAMES.publishedApi)
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@ import org.jetbrains.kotlin.ir.builders.Scope
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
@@ -25,6 +26,7 @@ import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrStarProjectionImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.resolve.jvm.annotations.JVM_DEFAULT_FQ_NAME
|
||||
|
||||
/**
|
||||
@@ -82,6 +84,12 @@ val IrType.erasedUpperBound: IrClass
|
||||
else -> throw IllegalStateException()
|
||||
}
|
||||
|
||||
|
||||
fun IrDeclaration.getJvmNameFromAnnotation(): String? {
|
||||
val const = getAnnotation(DescriptorUtils.JVM_NAME)?.getValueArgument(0) as? IrConst<*>
|
||||
return const?.value as? String
|
||||
}
|
||||
|
||||
val IrFunction.propertyIfAccessor: IrDeclaration
|
||||
get() = (this as? IrSimpleFunction)?.correspondingPropertySymbol?.owner ?: this
|
||||
|
||||
|
||||
+84
@@ -0,0 +1,84 @@
|
||||
/*
|
||||
* 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.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.allParameters
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getJvmNameFromAnnotation
|
||||
import org.jetbrains.kotlin.config.LanguageFeature
|
||||
import org.jetbrains.kotlin.config.languageVersionSettings
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addFunction
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.irBlockBody
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.builders.irReturn
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.getAnnotation
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.resolve.DescriptorUtils
|
||||
import org.jetbrains.kotlin.types.Variance
|
||||
|
||||
internal class MainMethodGenerationLowering(val context: JvmBackendContext) : ClassLoweringPass {
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (!context.configuration.languageVersionSettings.supportsFeature(LanguageFeature.ExtendedMainConvention)) return
|
||||
if (irClass.origin != IrDeclarationOrigin.FILE_CLASS) return
|
||||
|
||||
val parameterlessMain = irClass.functions.find { it.isParameterlessMainMethod() } ?: return
|
||||
|
||||
if (irClass.functions.any { it.isMainMethod() }) return
|
||||
|
||||
generateMainMethod(irClass, parameterlessMain)
|
||||
}
|
||||
|
||||
private fun generateMainMethod(irClass: IrClass, parameterlessMain: IrSimpleFunction) {
|
||||
irClass.addFunction {
|
||||
name = Name.identifier("main")
|
||||
visibility = Visibilities.PUBLIC
|
||||
returnType = context.irBuiltIns.unitType
|
||||
modality = Modality.FINAL
|
||||
origin = JvmLoweredDeclarationOrigin.GENERATED_MAIN_FOR_PARAMETERLESS_MAIN_METHOD
|
||||
}.apply {
|
||||
addValueParameter {
|
||||
name = Name.identifier("args")
|
||||
type = context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.stringType)
|
||||
}
|
||||
body = context.createIrBuilder(this.symbol).irBlockBody {
|
||||
+irReturn(this.irCall(parameterlessMain))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.isParameterlessMainMethod(): Boolean =
|
||||
typeParameters.isEmpty() && valueParameters.isEmpty() && returnType.isUnit() && name.asString() == "main"
|
||||
|
||||
|
||||
private fun IrSimpleFunction.isMainMethod(): Boolean {
|
||||
if (getJvmNameFromAnnotation() ?: name.asString() != "main") return false
|
||||
if (!returnType.isUnit()) return false
|
||||
|
||||
val parameter = allParameters.singleOrNull() ?: return false
|
||||
if (!parameter.type.isArray() && !parameter.type.isNullableArray()) return false
|
||||
|
||||
val argType = (parameter.type as IrSimpleType).arguments.first()
|
||||
return when (argType) {
|
||||
is IrTypeProjection -> {
|
||||
(argType.variance != Variance.IN_VARIANCE) && argType.type.isStringClassType()
|
||||
}
|
||||
else -> false
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user