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
committed by TeamCityServer
parent e7cbc9a0fb
commit 47ea5330ff
12 changed files with 124 additions and 40 deletions
@@ -40141,6 +40141,18 @@ public class FirBlackBoxCodegenTestGenerated extends AbstractFirBlackBoxCodegenT
public void testLocalCaptureTests() throws Exception { public void testLocalCaptureTests() throws Exception {
runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); 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 @Nested
@@ -111,6 +111,7 @@ val IrType.erasedUpperBound: IrClass
get() = when (val classifier = classifierOrNull) { get() = when (val classifier = classifierOrNull) {
is IrClassSymbol -> classifier.owner is IrClassSymbol -> classifier.owner
is IrTypeParameterSymbol -> classifier.owner.erasedUpperBound is IrTypeParameterSymbol -> classifier.owner.erasedUpperBound
is IrScriptSymbol -> classifier.owner.targetClass!!.owner
else -> error(render()) else -> error(render())
} }
@@ -36,6 +36,7 @@ import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.util.OperatorNameConventions import org.jetbrains.kotlin.util.OperatorNameConventions
import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull import org.jetbrains.kotlin.utils.addToStdlib.firstIsInstanceOrNull
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
internal val scriptsToClassesPhase = makeCustomPhase<JvmBackendContext, IrModuleFragment>( internal val scriptsToClassesPhase = makeCustomPhase<JvmBackendContext, IrModuleFragment>(
name = "ScriptsToClasses", name = "ScriptsToClasses",
@@ -98,44 +99,20 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
irScriptClass.thisReceiver = irScript.thisReceiver.transform(scriptTransformer, null) irScriptClass.thisReceiver = irScript.thisReceiver.transform(scriptTransformer, null)
irScriptClass.addConstructor { irScript.constructor?.patchForClass()?.safeAs<IrConstructor>()!!.also { constructor ->
isPrimary = true val explicitParamsStartIndex = if (irScript.earlierScriptsParameter == null) 0 else 1
}.also { irConstructor -> val explicitParameters = constructor.valueParameters.subList(
explicitParamsStartIndex,
fun addConstructorParameter(valueParameter: IrValueParameter, createCorrespondingProperty: Boolean): IrValueParameter { irScript.explicitCallParameters.size + explicitParamsStartIndex
val newValueParameter = valueParameter.patchForClass() as IrValueParameter )
irConstructor.valueParameters = irConstructor.valueParameters + newValueParameter constructor.body = context.createIrBuilder(constructor.symbol).irBlockBody {
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 {
val baseClassCtor = irScript.baseClass.classOrNull?.owner?.constructors?.firstOrNull() val baseClassCtor = irScript.baseClass.classOrNull?.owner?.constructors?.firstOrNull()
// TODO: process situation with multiple constructors (should probably be an error) // TODO: process situation with multiple constructors (should probably be an error)
if (baseClassCtor == null) { if (baseClassCtor == null) {
+irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single()) +irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single())
} else { } else {
+irDelegatingConstructorCall(baseClassCtor).also { +irDelegatingConstructorCall(baseClassCtor).also {
copiedExplicitParameters.forEachIndexed { idx, valueParameter -> explicitParameters.forEachIndexed { idx, valueParameter ->
it.putValueArgument( it.putValueArgument(
idx, idx,
IrGetValueImpl( IrGetValueImpl(
@@ -153,7 +130,10 @@ private class ScriptsToClassesLowering(val context: JvmBackendContext) {
context.irBuiltIns.unitType context.irBuiltIns.unitType
) )
} }
irScriptClass.declarations.add(constructor)
constructor.parent = irScriptClass
} }
var hasMain = false var hasMain = false
irScript.statements.forEach { scriptStatement -> irScript.statements.forEach { scriptStatement ->
when (scriptStatement) { when (scriptStatement) {
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.ParameterDescriptor
import org.jetbrains.kotlin.descriptors.ScriptDescriptor import org.jetbrains.kotlin.descriptors.ScriptDescriptor
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
import org.jetbrains.kotlin.ir.assertCast 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.DescriptorMetadataSource
import org.jetbrains.kotlin.ir.declarations.IrDeclaration import org.jetbrains.kotlin.ir.declarations.IrDeclaration
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin 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.IrGetValueImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl 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.types.toArrayOrPrimitiveArrayType
import org.jetbrains.kotlin.ir.util.indexOrMinusOne import org.jetbrains.kotlin.ir.util.*
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.name.Name import org.jetbrains.kotlin.name.Name
import org.jetbrains.kotlin.name.SpecialNames
import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtDestructuringDeclaration
import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.psi.KtScript
import org.jetbrains.kotlin.psi.KtScriptInitializer import org.jetbrains.kotlin.psi.KtScriptInitializer
import org.jetbrains.kotlin.psi.psiUtil.endOffset 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.psi.psiUtil.startOffsetSkippingComments
import org.jetbrains.kotlin.psi2ir.deparenthesize import org.jetbrains.kotlin.psi2ir.deparenthesize
import org.jetbrains.kotlin.psi2ir.intermediate.createTemporaryVariableInBlock import org.jetbrains.kotlin.psi2ir.intermediate.createTemporaryVariableInBlock
import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue import org.jetbrains.kotlin.psi2ir.intermediate.setExplicitReceiverValue
import org.jetbrains.kotlin.resolve.BindingContext import org.jetbrains.kotlin.resolve.BindingContext
import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore import org.jetbrains.kotlin.resolve.calls.util.isSingleUnderscore
import org.jetbrains.kotlin.utils.addIfNotNull
class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationGeneratorExtension(declarationGenerator) { class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationGeneratorExtension(declarationGenerator) {
@OptIn(ExperimentalStdlibApi::class)
fun generateScriptDeclaration(ktScript: KtScript): IrDeclaration? { fun generateScriptDeclaration(ktScript: KtScript): IrDeclaration? {
val descriptor = getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktScript) as ScriptDescriptor val descriptor = getOrFail(BindingContext.DECLARATION_TO_DESCRIPTOR, ktScript) as ScriptDescriptor
@@ -66,7 +66,7 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
descriptor.isCrossinline, descriptor.isNoinline, descriptor.isCrossinline, descriptor.isNoinline,
isHidden = false, isAssignable = false isHidden = false, isAssignable = false
) )
} .also { it.parent = irScript } }.also { it.parent = irScript }
} }
irScript.thisReceiver = makeParameter(descriptor.thisAsReceiverParameter, IrDeclarationOrigin.INSTANCE_RECEIVER) irScript.thisReceiver = makeParameter(descriptor.thisAsReceiverParameter, IrDeclarationOrigin.INSTANCE_RECEIVER)
@@ -140,6 +140,28 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG
valueParameter to irProperty.symbol 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) { for (d in ktScript.declarations) {
when (d) { when (d) {
is KtScriptInitializer -> { is KtScriptInitializer -> {
@@ -38,4 +38,6 @@ abstract class IrScript :
abstract var earlierScripts: List<IrScriptSymbol>? abstract var earlierScripts: List<IrScriptSymbol>?
abstract var targetClass: IrClassSymbol? abstract var targetClass: IrClassSymbol?
abstract var constructor: IrConstructor?
} }
@@ -56,6 +56,7 @@ class IrScriptImpl(
override var earlierScriptsParameter: IrValueParameter? = null override var earlierScriptsParameter: IrValueParameter? = null
override var earlierScripts: List<IrScriptSymbol>? = null override var earlierScripts: List<IrScriptSymbol>? = null
override var targetClass: IrClassSymbol? = null override var targetClass: IrClassSymbol? = null
override var constructor: IrConstructor? = null
@ObsoleteDescriptorBasedAPI @ObsoleteDescriptorBasedAPI
override val descriptor: ScriptDescriptor 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.expressions.IrConstructorCall
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol 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.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.impl.* import org.jetbrains.kotlin.ir.types.impl.*
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
@@ -77,7 +78,12 @@ val IrType.classifierOrNull: IrClassifierSymbol?
get() = safeAs<IrSimpleType>()?.classifier get() = safeAs<IrSimpleType>()?.classifier
val IrType.classOrNull: IrClassSymbol? 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? val IrType.classFqName: FqName?
get() = classOrNull?.owner?.fqNameWhenAvailable get() = classOrNull?.owner?.fqNameWhenAvailable
+12
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"
@@ -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"
}
@@ -39967,6 +39967,18 @@ public class BlackBoxCodegenTestGenerated extends AbstractBlackBoxCodegenTest {
public void testLocalCaptureTests() throws Exception { public void testLocalCaptureTests() throws Exception {
runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); 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 @Nested
@@ -40141,6 +40141,18 @@ public class IrBlackBoxCodegenTestGenerated extends AbstractIrBlackBoxCodegenTes
public void testLocalCaptureTests() throws Exception { public void testLocalCaptureTests() throws Exception {
runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); 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 @Nested
@@ -32030,6 +32030,16 @@ public class LightAnalysisModeTestGenerated extends AbstractLightAnalysisModeTes
public void testLocalCaptureTests() throws Exception { public void testLocalCaptureTests() throws Exception {
runTest("compiler/testData/codegen/box/script/localCaptureTests.kt"); 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") @TestMetadata("compiler/testData/codegen/box/sealed")