mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-03-10 08:31:29 +00:00
IR: Allow references to script constructor in module
aso add test checking (somewhat confusing) semantic of script nested classes.
This commit is contained in:
@@ -40111,6 +40111,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("scripInstance.kt")
|
||||
public void testScripInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scripInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("scriptNestedClassInstance.kt")
|
||||
public void testScriptNestedClassInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scriptNestedClassInstance.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -111,6 +111,7 @@ val IrType.erasedUpperBound: IrClass
|
||||
get() = when (val classifier = classifierOrNull) {
|
||||
is IrClassSymbol -> classifier.owner
|
||||
is IrTypeParameterSymbol -> classifier.owner.erasedUpperBound
|
||||
is IrScriptSymbol -> classifier.owner.targetClass!!.owner
|
||||
else -> error(render())
|
||||
}
|
||||
|
||||
|
||||
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
internal val scriptsToClassesPhase = makeCustomPhase<JvmBackendContext, IrModuleFragment>(
|
||||
name = "ScriptsToClasses",
|
||||
@@ -98,44 +99,20 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
|
||||
|
||||
irScriptClass.thisReceiver = irScript.thisReceiver.transform(scriptTransformer, null)
|
||||
|
||||
irScriptClass.addConstructor {
|
||||
isPrimary = true
|
||||
}.also { irConstructor ->
|
||||
|
||||
fun addConstructorParameter(valueParameter: IrValueParameter, createCorrespondingProperty: Boolean): IrValueParameter {
|
||||
val newValueParameter = valueParameter.patchForClass() as IrValueParameter
|
||||
irConstructor.valueParameters = irConstructor.valueParameters + newValueParameter
|
||||
if (createCorrespondingProperty) {
|
||||
irScriptClass.addSimplePropertyFrom(
|
||||
newValueParameter,
|
||||
IrExpressionBodyImpl(
|
||||
IrGetValueImpl(
|
||||
newValueParameter.startOffset, newValueParameter.endOffset,
|
||||
newValueParameter.type,
|
||||
newValueParameter.symbol,
|
||||
IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER
|
||||
)
|
||||
)
|
||||
)
|
||||
}
|
||||
return newValueParameter
|
||||
}
|
||||
|
||||
irScript.earlierScriptsParameter?.let { earlierScriptdParameter ->
|
||||
addConstructorParameter(earlierScriptdParameter, false)
|
||||
}
|
||||
val copiedExplicitParameters = irScript.explicitCallParameters.map { addConstructorParameter(it, false) }
|
||||
irScript.implicitReceiversParameters.forEach { addConstructorParameter(it, false) }
|
||||
irScript.providedProperties.forEach { addConstructorParameter(it.first, false) }
|
||||
|
||||
irConstructor.body = context.createIrBuilder(irConstructor.symbol).irBlockBody {
|
||||
irScript.constructor?.patchForClass()?.safeAs<IrConstructor>()!!.also { constructor ->
|
||||
val explicitParamsStartIndex = if (irScript.earlierScriptsParameter == null) 0 else 1
|
||||
val explicitParameters = constructor.valueParameters.subList(
|
||||
explicitParamsStartIndex,
|
||||
irScript.explicitCallParameters.size + explicitParamsStartIndex
|
||||
)
|
||||
constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody {
|
||||
val baseClassCtor = irScript.baseClass.classOrNull?.owner?.constructors?.firstOrNull()
|
||||
// TODO: process situation with multiple constructors (should probably be an error)
|
||||
if (baseClassCtor == null) {
|
||||
+irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single())
|
||||
} else {
|
||||
+irDelegatingConstructorCall(baseClassCtor).also {
|
||||
copiedExplicitParameters.forEachIndexed { idx, valueParameter ->
|
||||
explicitParameters.forEachIndexed { idx, valueParameter ->
|
||||
it.putValueArgument(
|
||||
idx,
|
||||
IrGetValueImpl(
|
||||
@@ -153,7 +130,10 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
|
||||
context.irBuiltIns.unitType
|
||||
)
|
||||
}
|
||||
irScriptClass.declarations.add(constructor)
|
||||
constructor.parent = irScriptClass
|
||||
}
|
||||
|
||||
var hasMain = false
|
||||
irScript.statements.forEach { scriptStatement ->
|
||||
when (scriptStatement) {
|
||||
|
||||
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ParameterDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ScriptDescriptor
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.assertCast
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.DescriptorMetadataSource
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
@@ -20,26 +21,25 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.toArrayOrPrimitiveArrayType
|
||||
import org.jetbrains.kotlin.ir.util.indexOrMinusOne
|
||||
import org.jetbrains.kotlin.ir.util.isCrossinline
|
||||
import org.jetbrains.kotlin.ir.util.isNoinline
|
||||
import org.jetbrains.kotlin.ir.util.varargElementType
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.name.SpecialNames
|
||||
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
|
||||
import org.jetbrains.kotlin.psi.KtScript
|
||||
import org.jetbrains.kotlin.psi.KtScriptInitializer
|
||||
import org.jetbrains.kotlin.psi.psiUtil.endOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.pureEndOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.pureStartOffset
|
||||
import org.jetbrains.kotlin.psi.psiUtil.startOffsetSkippingComments
|
||||
import org.jetbrains.kotlin.psi2ir.deparenthesize
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.createTemporaryVariableInBlock
|
||||
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
|
||||
import org.jetbrains.kotlin.resolve.BindingContext
|
||||
import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
|
||||
class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationGeneratorExtension(declarationGenerator) {
|
||||
@OptIn(ExperimentalStdlibApi::class)
|
||||
fun generateScriptDeclaration(ktScript: KtScript): IrDeclaration? {
|
||||
val descriptor = getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktScript) as ScriptDescriptor
|
||||
|
||||
@@ -66,7 +66,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
|
||||
descriptor.isCrossinline, descriptor.isNoinline,
|
||||
isHidden = false, isAssignable = false
|
||||
)
|
||||
} .also { it.parent = irScript }
|
||||
}.also { it.parent = irScript }
|
||||
}
|
||||
|
||||
irScript.thisReceiver = makeParameter(descriptor.thisAsReceiverParameter, IrDeclarationOrigin.INSTANCE_RECEIVER)
|
||||
@@ -140,6 +140,28 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
|
||||
valueParameter to irProperty.symbol
|
||||
}
|
||||
|
||||
irScript.constructor = with(IrFunctionBuilder().apply {
|
||||
isPrimary = true
|
||||
returnType = irScript.thisReceiver.type as IrSimpleType
|
||||
}) {
|
||||
irScript.factory.createConstructor(
|
||||
startOffset, endOffset, origin,
|
||||
context.symbolTable.referenceConstructor(descriptor.unsubstitutedPrimaryConstructor),
|
||||
SpecialNames.INIT,
|
||||
visibility, returnType,
|
||||
isInline = isInline, isExternal = isExternal, isPrimary = isPrimary, isExpect = isExpect,
|
||||
containerSource = containerSource
|
||||
)
|
||||
}.also { irConstructor ->
|
||||
irConstructor.valueParameters = buildList {
|
||||
addIfNotNull(irScript.earlierScriptsParameter)
|
||||
addAll(irScript.explicitCallParameters)
|
||||
addAll(irScript.implicitReceiversParameters)
|
||||
irScript.providedProperties.forEach { add(it.first) }
|
||||
}
|
||||
irConstructor.parent = irScript
|
||||
}
|
||||
|
||||
for (d in ktScript.declarations) {
|
||||
when (d) {
|
||||
is KtScriptInitializer -> {
|
||||
|
||||
@@ -38,4 +38,6 @@ abstract class IrScript :
|
||||
abstract var earlierScripts: List<IrScriptSymbol>?
|
||||
|
||||
abstract var targetClass: IrClassSymbol?
|
||||
|
||||
abstract var constructor: IrConstructor?
|
||||
}
|
||||
|
||||
@@ -56,6 +56,7 @@ class IrScriptImpl(
|
||||
override var earlierScriptsParameter: IrValueParameter? = null
|
||||
override var earlierScripts: List<IrScriptSymbol>? = null
|
||||
override var targetClass: IrClassSymbol? = null
|
||||
override var constructor: IrConstructor? = null
|
||||
|
||||
@ObsoleteDescriptorBasedAPI
|
||||
override val descriptor: ScriptDescriptor
|
||||
|
||||
@@ -14,6 +14,7 @@ import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.types.impl.*
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
@@ -77,7 +78,12 @@ val IrType.classifierOrNull: IrClassifierSymbol?
|
||||
get() = safeAs<IrSimpleType>()?.classifier
|
||||
|
||||
val IrType.classOrNull: IrClassSymbol?
|
||||
get() = classifierOrNull as? IrClassSymbol
|
||||
get() =
|
||||
when (val classifier = classifierOrNull) {
|
||||
is IrClassSymbol -> classifier
|
||||
is IrScriptSymbol -> classifier.owner.targetClass
|
||||
else -> null
|
||||
}
|
||||
|
||||
val IrType.classFqName: FqName?
|
||||
get() = classOrNull?.owner?.fqNameWhenAvailable
|
||||
|
||||
12
compiler/testData/codegen/box/script/scripInstance.kt
vendored
Normal file
12
compiler/testData/codegen/box/script/scripInstance.kt
vendored
Normal file
@@ -0,0 +1,12 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// FILE: test.kt
|
||||
|
||||
fun box(): String =
|
||||
Script(emptyArray<String>()).x
|
||||
|
||||
// FILE: script.kts
|
||||
|
||||
val x = "OK"
|
||||
14
compiler/testData/codegen/box/script/scriptNestedClassInstance.kt
vendored
Normal file
14
compiler/testData/codegen/box/script/scriptNestedClassInstance.kt
vendored
Normal file
@@ -0,0 +1,14 @@
|
||||
// TARGET_BACKEND: JVM
|
||||
// IGNORE_BACKEND_FIR: JVM_IR
|
||||
// IGNORE_LIGHT_ANALYSIS
|
||||
// WITH_RUNTIME
|
||||
// FILE: test.kt
|
||||
|
||||
fun box(): String =
|
||||
Script.Nested().x
|
||||
|
||||
// FILE: script.kts
|
||||
|
||||
class Nested {
|
||||
val x = "OK"
|
||||
}
|
||||
@@ -39937,6 +39937,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("scripInstance.kt")
|
||||
public void testScripInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scripInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("scriptNestedClassInstance.kt")
|
||||
public void testScriptNestedClassInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scriptNestedClassInstance.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -40111,6 +40111,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("scripInstance.kt")
|
||||
public void testScripInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scripInstance.kt");
|
||||
}
|
||||
|
||||
@Test
|
||||
@TestMetadata("scriptNestedClassInstance.kt")
|
||||
public void testScriptNestedClassInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scriptNestedClassInstance.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@Nested
|
||||
|
||||
@@ -32005,6 +32005,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
|
||||
public void testClassReference() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/classReference.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("scripInstance.kt")
|
||||
public void testScripInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scripInstance.kt");
|
||||
}
|
||||
|
||||
@TestMetadata("scriptNestedClassInstance.kt")
|
||||
public void testScriptNestedClassInstance() throws Exception {
|
||||
runTest("compiler/testData/codegen/box/script/scriptNestedClassInstance.kt");
|
||||
}
|
||||
}
|
||||
|
||||
@TestMetadata("compiler/testData/codegen/box/sealed")
|
||||
|
||||
Reference in New Issue
Block a user