diff --git a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java index 5da73bc9d5a..b02a2a2fd93 100644 --- a/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java +++ b/compiler/fir/fir2ir/tests-gen/org/jetbrains/kotlin/test/runners/codegen/FirBlackBoxCodegenTestGenerated.java @@ -40141,6 +40141,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT public void testLocalCaptureTests() throws Exception { runTest("compiler/testData/codegen/box/script/localCaptureTests.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 diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt index ca82e2b809e..6031d0dd5f9 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/ir/IrUtils.kt @@ -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()) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt index 8b9e928aa56..b6c3c819b01 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt @@ -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( 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()!!.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) { diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt index 9eb3d75d1d3..a346972335e 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/ScriptGenerator.kt @@ -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 -> { diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt index 8395cc1e674..b840a86a111 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrScript.kt @@ -38,4 +38,6 @@ abstract class IrScript : abstract var earlierScripts: List? abstract var targetClass: IrClassSymbol? + + abstract var constructor: IrConstructor? } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt index ef69238f608..3240e112183 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/impl/IrScriptImpl.kt @@ -56,6 +56,7 @@ class IrScriptImpl( override var earlierScriptsParameter: IrValueParameter? = null override var earlierScripts: List? = null override var targetClass: IrClassSymbol? = null + override var constructor: IrConstructor? = null @ObsoleteDescriptorBasedAPI override val descriptor: ScriptDescriptor diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt index 50298b854d5..03e0e67f4bc 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/types/irTypes.kt @@ -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()?.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 diff --git a/compiler/testData/codegen/box/script/scripInstance.kt b/compiler/testData/codegen/box/script/scripInstance.kt new file mode 100644 index 00000000000..a3d79d17b6b --- /dev/null +++ b/compiler/testData/codegen/box/script/scripInstance.kt @@ -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()).x + +// FILE: script.kts + +val x = "OK" diff --git a/compiler/testData/codegen/box/script/scriptNestedClassInstance.kt b/compiler/testData/codegen/box/script/scriptNestedClassInstance.kt new file mode 100644 index 00000000000..ad03bf5096d --- /dev/null +++ b/compiler/testData/codegen/box/script/scriptNestedClassInstance.kt @@ -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" +} diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java index be5ceb5f7a2..d721fbd2d59 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/BlackBoxCodegenTestGenerated.java @@ -39967,6 +39967,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest { public void testLocalCaptureTests() throws Exception { runTest("compiler/testData/codegen/box/script/localCaptureTests.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 diff --git a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java index a8cc0147f59..7d067df7456 100644 --- a/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java +++ b/compiler/tests-common-new/tests-gen/org/jetbrains/kotlin/test/runners/codegen/IrBlackBoxCodegenTestGenerated.java @@ -40141,6 +40141,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes public void testLocalCaptureTests() throws Exception { runTest("compiler/testData/codegen/box/script/localCaptureTests.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 diff --git a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java index 28aad6aeb42..82911423836 100644 --- a/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java +++ b/compiler/tests-gen/org/jetbrains/kotlin/codegen/LightAnalysisModeTestGenerated.java @@ -32030,6 +32030,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes public void testLocalCaptureTests() throws Exception { runTest("compiler/testData/codegen/box/script/localCaptureTests.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")