IR: Allow references to script constructor in module

aso add test checking (somewhat confusing) semantic of
script nested classes.
This commit is contained in:
Ilya Chernikov
2021-08-13 19:18:34 +02:00
parent 7fb0db39a8
commit 55e56e397b
12 changed files with 124 additions and 40 deletions

View File

@@ -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

View File

@@ -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())
}

View File

@@ -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) {

View File

@@ -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 -> {

View File

@@ -38,4 +38,6 @@ abstract class IrScript :
abstract var earlierScripts: List<IrScriptSymbol>?
abstract var targetClass: IrClassSymbol?
abstract var constructor: IrConstructor?
}

View File

@@ -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

View File

@@ -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

View 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"

View 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"
}

View File

@@ -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

View File

@@ -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

View File

@@ -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")