diff --git a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt index e23fefd48c8..de011536058 100644 --- a/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt +++ b/compiler/backend/src/org/jetbrains/kotlin/codegen/state/GenerationState.kt @@ -242,6 +242,7 @@ class GenerationState private constructor( var earlierScriptsForReplInterpreter: List? = null // and the rest is an output from the codegen var resultFieldName: String? = null + var resultTypeString: String? = null var resultType: KotlinType? = null } diff --git a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt index 6228bb33514..a3e7696bcb4 100644 --- a/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt +++ b/compiler/cli/src/org/jetbrains/kotlin/cli/jvm/compiler/KotlinToJVMBytecodeCompiler.kt @@ -37,7 +37,8 @@ import org.jetbrains.kotlin.cli.common.CLIConfigurationKeys import org.jetbrains.kotlin.cli.common.checkKotlinPackageUsage import org.jetbrains.kotlin.cli.common.config.addKotlinSourceRoot import org.jetbrains.kotlin.cli.common.messages.AnalyzerWithCompilerReport -import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.* +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.OUTPUT +import org.jetbrains.kotlin.cli.common.messages.CompilerMessageSeverity.WARNING import org.jetbrains.kotlin.cli.common.messages.MessageCollector import org.jetbrains.kotlin.cli.common.messages.OutputMessageUtil import org.jetbrains.kotlin.cli.common.output.writeAll @@ -616,17 +617,8 @@ object KotlinToJVMBytecodeCompiler { sourceFiles: List, module: Module? ): GenerationState { - // The IR backend does not handle .kts files yet. - var isIR = (configuration.getBoolean(JVMConfigurationKeys.IR) || + val isIR = (configuration.getBoolean(JVMConfigurationKeys.IR) || configuration.getBoolean(CommonConfigurationKeys.USE_FIR)) - val anyKts = sourceFiles.any { it.isScript() } - if (isIR && anyKts) { - environment.messageCollector.report( - STRONG_WARNING, - "IR backend does not support .kts scripts, switching to old JVM backend" - ) - isIR = false - } val generationState = GenerationState.Builder( environment.project, ClassBuilderFactories.BINARIES, diff --git a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CreateScriptFunctionsPhase.kt b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CreateScriptFunctionsPhase.kt index 7aaedc68a59..5279d00f6a4 100644 --- a/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CreateScriptFunctionsPhase.kt +++ b/compiler/ir/backend.js/src/org/jetbrains/kotlin/ir/backend/js/lower/CreateScriptFunctionsPhase.kt @@ -48,7 +48,10 @@ class CreateScriptFunctionsPhase(val context: CommonBackendContext) : FileLoweri it.body = it.factory.createBlockBody( startOffset, endOffset, - initializeStatements.map { (field, expression) -> createIrSetField(field, expression) } + initializeStatements.let { + if (irScript.resultProperty == null || initializeStatements.lastOrNull()?.first?.correspondingPropertySymbol != irScript.resultProperty) it + else it.dropLast(1) + }.map { (field, expression) -> createIrSetField(field, expression) } ) } @@ -56,7 +59,16 @@ class CreateScriptFunctionsPhase(val context: CommonBackendContext) : FileLoweri it.body = it.factory.createBlockBody( startOffset, endOffset, - irScript.statements.filter { it !is IrDeclaration }.prepareForEvaluateScriptFunction(it) + irScript.statements.filter { it !is IrDeclaration } + .let { + val lastInitializer = initializeStatements.lastOrNull() + if (lastInitializer == null || irScript.resultProperty == null + || lastInitializer.first.correspondingPropertySymbol != irScript.resultProperty) { + it + } else { + it + lastInitializer.second + } + }.prepareForEvaluateScriptFunction(it) ) } diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt index a439309d96c..5d00ef63d2e 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/JvmLower.kt @@ -389,6 +389,7 @@ val jvmPhases = NamedCompilerPhase( lower = validateIrBeforeLowering then processOptionalAnnotationsPhase then expectDeclarationsRemovingPhase then + scriptToClassPhase then fileClassPhase then performByIrFile(lower = jvmFilePhases) then generateMultifileFacadesPhase then diff --git a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt index c5044cb907b..020956c48a5 100644 --- a/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/FileClassLowering.kt @@ -50,7 +50,7 @@ internal val fileClassPhase = makeIrModulePhase( stickyPostconditions = setOf(::checkAllFileLevelDeclarationsAreClasses) ) -private fun checkAllFileLevelDeclarationsAreClasses(irModuleFragment: IrModuleFragment) { +internal fun checkAllFileLevelDeclarationsAreClasses(irModuleFragment: IrModuleFragment) { assert(irModuleFragment.files.all { irFile -> irFile.declarations.all { it is IrClass } }) @@ -62,10 +62,11 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa val fileClassMembers = ArrayList() irFile.declarations.forEach { - if (it is IrClass) - classes.add(it) - else - fileClassMembers.add(it) + when (it) { + is IrScript -> {} + is IrClass -> classes.add(it) + else -> fileClassMembers.add(it) + } } // TODO FirMetadataSource.File 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 new file mode 100644 index 00000000000..ad5dc5817fb --- /dev/null +++ b/compiler/ir/backend.jvm/src/org/jetbrains/kotlin/backend/jvm/lower/ScriptLowering.kt @@ -0,0 +1,386 @@ +/* + * Copyright 2010-2020 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.FileLoweringPass +import org.jetbrains.kotlin.backend.common.ir.copyTo +import org.jetbrains.kotlin.backend.common.ir.createImplicitParameterDeclarationWithWrappedDescriptor +import org.jetbrains.kotlin.backend.common.lower.createIrBuilder +import org.jetbrains.kotlin.backend.common.phaser.makeIrModulePhase +import org.jetbrains.kotlin.backend.jvm.JvmBackendContext +import org.jetbrains.kotlin.descriptors.ClassKind +import org.jetbrains.kotlin.descriptors.DescriptorVisibilities +import org.jetbrains.kotlin.descriptors.Modality +import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.IrStatement +import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET +import org.jetbrains.kotlin.ir.builders.declarations.* +import org.jetbrains.kotlin.ir.builders.irBlockBody +import org.jetbrains.kotlin.ir.builders.irDelegatingConstructorCall +import org.jetbrains.kotlin.ir.declarations.* +import org.jetbrains.kotlin.ir.declarations.impl.* +import org.jetbrains.kotlin.ir.descriptors.WrappedClassDescriptor +import org.jetbrains.kotlin.ir.expressions.* +import org.jetbrains.kotlin.ir.expressions.impl.* +import org.jetbrains.kotlin.ir.symbols.* +import org.jetbrains.kotlin.ir.symbols.impl.IrAnonymousInitializerSymbolImpl +import org.jetbrains.kotlin.ir.transformStatement +import org.jetbrains.kotlin.ir.types.* +import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl +import org.jetbrains.kotlin.ir.types.impl.IrTypeAbbreviationImpl +import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection +import org.jetbrains.kotlin.ir.util.* +import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid + +internal val scriptToClassPhase = makeIrModulePhase( + ::ScriptToClassLowering, + name = "ScriptToClass", + description = "Put script declarations into a class", + stickyPostconditions = setOf(::checkAllFileLevelDeclarationsAreClasses) +) + +private class ScriptToClassLowering(val context: JvmBackendContext) : FileLoweringPass { + + override fun lower(irFile: IrFile) { + irFile.declarations.replaceAll { declaration -> + if (declaration is IrScript) makeScriptClass(irFile, declaration) + else declaration + } + } + + private fun makeScriptClass(irFile: IrFile, irScript: IrScript): IrClass { + val fileEntry = irFile.fileEntry + return context.irFactory.buildClass { + startOffset = 0 + endOffset = fileEntry.maxOffset + origin = IrDeclarationOrigin.SCRIPT_CLASS + name = irScript.name + kind = ClassKind.CLASS + visibility = DescriptorVisibilities.PUBLIC + modality = Modality.FINAL + }.also { irScriptClass -> + irScriptClass.superTypes += context.irBuiltIns.anyType + irScriptClass.parent = irFile + irScriptClass.createImplicitParameterDeclarationWithWrappedDescriptor() + val symbolRemapper = ScriptToClassSymbolRemapper(irScript.symbol, irScriptClass.symbol) + val typeRemapper = ScriptTypeRemapper(symbolRemapper) + val scriptTransformer = ScriptToClassTransformer(irScript, irScriptClass, symbolRemapper, typeRemapper) + irScriptClass.thisReceiver = irScript.thisReceiver.run { + transform(scriptTransformer, null) + } + irScriptClass.addConstructor { + isPrimary = true + }.also { irConstructor -> + irScript.explicitCallParameters.forEach { scriptCallParameter -> + val callParameter = irConstructor.addValueParameter { + updateFrom(scriptCallParameter) + name = scriptCallParameter.name + } + irScriptClass.addSimplePropertyFrom( + callParameter, + IrExpressionBodyImpl( + IrGetValueImpl( + callParameter.startOffset, callParameter.endOffset, + callParameter.type, + callParameter.symbol, + IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER + ) + ) + ) + } + + irConstructor.body = context.createIrBuilder(irConstructor.symbol).irBlockBody { + +irDelegatingConstructorCall(context.irBuiltIns.anyClass.owner.constructors.single()) + +IrInstanceInitializerCallImpl( + irScript.startOffset, irScript.endOffset, + irScriptClass.symbol, + context.irBuiltIns.unitType + ) + } + } + irScript.statements.forEach { scriptStatement -> + when (scriptStatement) { + is IrVariable -> irScriptClass.addSimplePropertyFrom(scriptStatement) + is IrDeclaration -> { + val copy = scriptStatement.transform(scriptTransformer, null) as IrDeclaration + irScriptClass.declarations.add(copy) + } + else -> { + val transformedStatement = scriptStatement.transformStatement(scriptTransformer) + irScriptClass.addAnonymousInitializer().also { irInitializer -> + irInitializer.body = + context.createIrBuilder(irInitializer.symbol).irBlockBody { + if (transformedStatement is IrComposite) { + for (statement in transformedStatement.statements) + +statement + } else { + +transformedStatement + } + } + } + } + } + } + irScriptClass.annotations += irFile.annotations + irScriptClass.metadata = irFile.metadata + + irScript.resultProperty?.owner?.let { irResultProperty -> + context.state.scriptSpecific.resultFieldName = irResultProperty.name.identifier + context.state.scriptSpecific.resultTypeString = irResultProperty.backingField?.type?.render() + } + } + } + + private fun IrClass.addSimplePropertyFrom( + from: IrValueDeclaration, + initializer: IrExpressionBodyImpl? = null + ) { + addProperty { + updateFrom(from) + name = from.name + }.also { property -> + property.backingField = context.irFactory.buildField { + name = from.name + type = from.type + visibility = DescriptorVisibilities.PROTECTED + }.also { field -> + field.parent = this + if (initializer != null) { + field.initializer = initializer + } + + property.addSimpleFieldGetter(from.type, this, field) + } + } + } + + private fun IrProperty.addSimpleFieldGetter(type: IrType, irScriptClass: IrClass, field: IrField) = + addGetter { + returnType = type + }.apply { + dispatchReceiverParameter = irScriptClass.thisReceiver!!.copyTo(this) + body = IrBlockBodyImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, listOf( + IrReturnImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + context.irBuiltIns.nothingType, + symbol, + IrGetFieldImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + field.symbol, + type, + IrGetValueImpl( + UNDEFINED_OFFSET, UNDEFINED_OFFSET, + dispatchReceiverParameter!!.type, + dispatchReceiverParameter!!.symbol + ) + ) + ) + ) + ) + } +} + +private class ScriptToClassTransformer( + val irScript: IrScript, + val irScriptClass: IrClass, + val symbolRemapper: SymbolRemapper = ScriptToClassSymbolRemapper(irScript.symbol, irScriptClass.symbol), + val typeRemapper: TypeRemapper = ScriptTypeRemapper(symbolRemapper) +) : IrElementTransformerVoid() { + + private fun IrType.remapType() = typeRemapper.remapType(this) + + private fun IrDeclaration.transformParent() { + if (parent == irScript) { + parent = irScriptClass + } + } + + private fun IrMutableAnnotationContainer.transformAnnotations() { + annotations = annotations.transform() + } + + private inline fun T.transform() = + transform(this@ScriptToClassTransformer, null) as T + + private inline fun List.transform() = + map { it.transform() } + + private fun T.transformFunctionChildren(): T = + apply { + transformAnnotations() + typeRemapper.withinScope(this) { + dispatchReceiverParameter = dispatchReceiverParameter?.transform() + extensionReceiverParameter = extensionReceiverParameter?.transform() + returnType = returnType.remapType() + valueParameters = valueParameters.transform() + body = body?.transform() + } + } + + private fun IrTypeParameter.remapSuperTypes(): IrTypeParameter = apply { + superTypes = superTypes.map { it.remapType() } + } + + private fun unexpectedElement(element: IrElement): Nothing = + throw IllegalArgumentException("Unsupported element type: $element") + + override fun visitElement(element: IrElement): IrElement = unexpectedElement(element) + + override fun visitModuleFragment(declaration: IrModuleFragment): IrModuleFragment = unexpectedElement(declaration) + override fun visitExternalPackageFragment(declaration: IrExternalPackageFragment) = unexpectedElement(declaration) + override fun visitFile(declaration: IrFile): IrFile = unexpectedElement(declaration) + override fun visitScript(declaration: IrScript): IrStatement = unexpectedElement(declaration) + + override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement = declaration.apply { + transformParent() + transformAnnotations() + transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitClass(declaration: IrClass): IrClass = declaration.apply { + superTypes = superTypes.map { + it.remapType() + } + visitDeclaration(declaration) + } + + override fun visitSimpleFunction(declaration: IrSimpleFunction): IrSimpleFunction = declaration.apply { + transformParent() + transformFunctionChildren() +// transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitConstructor(declaration: IrConstructor): IrConstructor = declaration.apply { + transformParent() + transformFunctionChildren() + } + + override fun visitVariable(declaration: IrVariable): IrVariable = declaration.apply { + type = type.remapType() + visitDeclaration(declaration) + } + + override fun visitTypeParameter(declaration: IrTypeParameter): IrTypeParameter = declaration.apply { + remapSuperTypes() + visitDeclaration(declaration) + } + + override fun visitValueParameter(declaration: IrValueParameter): IrValueParameter = declaration.apply { + type = type.remapType() + varargElementType = varargElementType?.remapType() + visitDeclaration(declaration) + } + + override fun visitTypeAlias(declaration: IrTypeAlias): IrTypeAlias = declaration.apply { + expandedType = expandedType.remapType() + visitDeclaration(declaration) + } + + override fun visitVararg(expression: IrVararg): IrVararg = expression.apply { + type = type.remapType() + varargElementType = varargElementType.remapType() + transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitSpreadElement(spread: IrSpreadElement): IrSpreadElement = spread.apply { + transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitExpression(expression: IrExpression): IrExpression = expression.apply { + type = type.remapType() + transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitClassReference(expression: IrClassReference): IrClassReference = expression.apply { + type = type.remapType() + classType = classType.remapType() + transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitTypeOperator(expression: IrTypeOperatorCall): IrTypeOperatorCall = expression.apply { + type = type.remapType() + typeOperand = typeOperand.remapType() + transformChildren(this@ScriptToClassTransformer, null) + } + + override fun visitMemberAccess(expression: IrMemberAccessExpression<*>): IrExpression = expression.apply { + for (i in 0 until typeArgumentsCount) { + putTypeArgument(i, getTypeArgument(i)?.remapType()) + } + visitExpression(expression) + } +} + +private class ScriptToClassSymbolRemapper( + val irScriptSymbol: IrScriptSymbol, + val irScriptClassSymbol: IrClassSymbol +) : SymbolRemapper.Empty() { + override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol = + if (symbol != irScriptSymbol) symbol + else irScriptClassSymbol +} + +class ScriptTypeRemapper( + private val symbolRemapper: SymbolRemapper +) : TypeRemapper { + + override fun enterScope(irTypeParametersContainer: IrTypeParametersContainer) { + // TODO + } + + override fun leaveScope() { + // TODO + } + + override fun remapType(type: IrType): IrType = + if (type !is IrSimpleType) + type + else { + val symbol = symbolRemapper.getReferencedClassifier(type.classifier) + val arguments = type.arguments.map { remapTypeArgument(it) } + if (symbol == type.classifier && arguments == type.arguments) + type + else { + IrSimpleTypeImpl( + null, + symbol, + type.hasQuestionMark, + arguments, + type.annotations, + type.abbreviation?.remapTypeAbbreviation() + ) + } + } + + private fun remapTypeArgument(typeArgument: IrTypeArgument): IrTypeArgument = + if (typeArgument is IrTypeProjection) + makeTypeProjection(this.remapType(typeArgument.type), typeArgument.variance) + else + typeArgument + + private fun IrTypeAbbreviation.remapTypeAbbreviation() = + IrTypeAbbreviationImpl( + symbolRemapper.getReferencedTypeAlias(typeAlias), + hasQuestionMark, + arguments.map { remapTypeArgument(it) }, + annotations + ) +} + +private inline fun IrClass.addAnonymousInitializer(builder: IrFunctionBuilder.() -> Unit = {}): IrAnonymousInitializer = + IrFunctionBuilder().run { + builder() + returnType = defaultType + IrAnonymousInitializerImpl( + startOffset, endOffset, origin, + IrAnonymousInitializerSymbolImpl(WrappedClassDescriptor()) + ) + }.also { anonymousInitializer -> + declarations.add(anonymousInitializer) + anonymousInitializer.parent = this@addAnonymousInitializer + } + diff --git a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt index 341cb71a613..e0df9df2b03 100644 --- a/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt +++ b/compiler/ir/ir.psi2ir/src/org/jetbrains/kotlin/psi2ir/generators/PropertyGenerator.kt @@ -69,26 +69,32 @@ class PropertyGenerator(declarationGenerator: DeclarationGenerator) : Declaratio irValueParameter: IrValueParameter?, generateSyntheticAccessors: Boolean = false ): IrProperty { val irPropertyType = propertyDescriptor.type.toIrType() + return generateSyntheticPropertyWithInitializer(ktDeclarationContainer, propertyDescriptor, generateSyntheticAccessors) { + if (irValueParameter == null) null + else { + context.irFactory.createExpressionBody( + IrGetValueImpl( + ktDeclarationContainer.startOffsetSkippingComments, ktDeclarationContainer.endOffset, + irPropertyType, + irValueParameter.symbol, + IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER + ) + ) + } + } + } + + fun generateSyntheticPropertyWithInitializer( + ktDeclarationContainer: KtElement, propertyDescriptor: PropertyDescriptor, + generateSyntheticAccessors: Boolean, generateInitializer: (IrField) -> IrExpressionBody? + ): IrProperty { return context.symbolTable.declareProperty( ktDeclarationContainer.startOffsetSkippingComments, ktDeclarationContainer.endOffset, IrDeclarationOrigin.DEFINED, propertyDescriptor, isDelegated = false ).also { irProperty -> - irProperty.backingField = - generatePropertyBackingField(ktDeclarationContainer, propertyDescriptor) { - if (irValueParameter == null) null - else { - context.irFactory.createExpressionBody( - IrGetValueImpl( - ktDeclarationContainer.startOffsetSkippingComments, ktDeclarationContainer.endOffset, - irPropertyType, - irValueParameter.symbol, - IrStatementOrigin.INITIALIZE_PROPERTY_FROM_PARAMETER - ) - ) - } - } + irProperty.backingField = generatePropertyBackingField(ktDeclarationContainer, propertyDescriptor, generateInitializer) val getter = propertyDescriptor.getter ?: if (generateSyntheticAccessors) 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 b4277521399..2e5f995a1c0 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 @@ -5,24 +5,17 @@ package org.jetbrains.kotlin.psi2ir.generators -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.ParameterDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.ScriptDescriptor +import org.jetbrains.kotlin.descriptors.* import org.jetbrains.kotlin.ir.assertCast -import org.jetbrains.kotlin.ir.builders.declarations.IrFunctionBuilder -import org.jetbrains.kotlin.ir.declarations.* -import org.jetbrains.kotlin.ir.declarations.lazy.IrLazyFunction -import org.jetbrains.kotlin.ir.descriptors.WrappedFunctionDescriptorWithContainerSource -import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor +import org.jetbrains.kotlin.ir.declarations.IrDeclaration +import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin +import org.jetbrains.kotlin.ir.declarations.IrValueParameter import org.jetbrains.kotlin.ir.expressions.IrExpression import org.jetbrains.kotlin.ir.expressions.IrStatementOrigin 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.IrSimpleFunctionSymbolImpl import org.jetbrains.kotlin.ir.util.varargElementType -import org.jetbrains.kotlin.name.Name import org.jetbrains.kotlin.psi.KtDestructuringDeclaration import org.jetbrains.kotlin.psi.KtScript import org.jetbrains.kotlin.psi.KtScriptInitializer @@ -46,7 +39,11 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG // TODO: since script could reference instances of previous one their receivers have to be enlisted in its scope // Remove this code once script is no longer represented by Class - existedScripts.forEach { context.symbolTable.introduceValueParameter(it.owner.thisReceiver) } + existedScripts.forEach { + if (it.owner != irScript) { + context.symbolTable.introduceValueParameter(it.owner.thisReceiver) + } + } val startOffset = ktScript.pureStartOffset val endOffset = ktScript.pureEndOffset @@ -63,13 +60,33 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG irScript.thisReceiver = makeReceiver(descriptor) + irScript.baseClass = descriptor.typeConstructor.supertypes.single().toIrType() + irScript.implicitReceivers = descriptor.implicitReceivers.map(::makeReceiver) + + for (d in ktScript.declarations) { when (d) { is KtScriptInitializer -> { - irScript.statements += BodyGenerator( + val irExpressionBody = BodyGenerator( irScript.symbol, context - ).generateExpressionBody(d.body!!).expression + ).generateExpressionBody(d.body!!) + if (d == ktScript.declarations.last() && descriptor.resultValue != null) { + descriptor.resultValue!!.let { resultDescriptor -> + PropertyGenerator(declarationGenerator) + .generateSyntheticPropertyWithInitializer(ktScript, resultDescriptor, generateSyntheticAccessors = true) { + // TODO: check if this is a correct place to do it + it.visibility = DescriptorVisibilities.PUBLIC + irExpressionBody + }.also { + it.origin = IrDeclarationOrigin.SCRIPT_RESULT_PROPERTY + irScript.statements += it + irScript.resultProperty = it.symbol + } + } + } else { + irScript.statements += irExpressionBody.expression + } } is KtDestructuringDeclaration -> { // copied with modifications from StatementGenerator.visitDestructuringDeclaration @@ -130,14 +147,17 @@ class ScriptGenerator(declarationGenerator: DeclarationGenerator) : DeclarationG } } - descriptor.resultValue?.let { resultDescriptor -> + irScript.explicitCallParameters = descriptor.unsubstitutedPrimaryConstructor.valueParameters.map { valueParameterDescriptor -> + valueParameterDescriptor.toIrValueParameter(startOffset, endOffset, IrDeclarationOrigin.SCRIPT_CALL_PARAMETER) + } + + irScript.providedProperties = descriptor.scriptProvidedProperties.map { providedProperty -> // TODO: initializer - // TODO: do not keet direct link - val resultProperty = - PropertyGenerator(declarationGenerator) - .generateSyntheticProperty(ktScript, resultDescriptor, null, generateSyntheticAccessors = true) - resultProperty.origin = IrDeclarationOrigin.SCRIPT_RESULT_PROPERTY - irScript.statements += resultProperty + // TODO: do not keep direct links + val irProperty = PropertyGenerator(declarationGenerator).generateSyntheticProperty(ktScript, providedProperty, null) + irProperty.origin = IrDeclarationOrigin.SCRIPT_PROVIDED_PROPERTY + irScript.statements += irProperty + irProperty.symbol } } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt index 992c0ba4e97..a4fdbd47acf 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/declarations/IrDeclarationOrigin.kt @@ -38,6 +38,12 @@ interface IrDeclarationOrigin { object FILE_CLASS : IrDeclarationOriginImpl("FILE_CLASS") object SYNTHETIC_FILE_CLASS : IrDeclarationOriginImpl("SYNTHETIC_FILE_CLASS", isSynthetic = true) + object SCRIPT_CLASS : IrDeclarationOriginImpl("SCRIPT_CLASS") + object SCRIPT_STATEMENT : IrDeclarationOriginImpl("SCRIPT_STATEMENT") + object SCRIPT_CALL_PARAMETER : IrDeclarationOriginImpl("SCRIPT_CALL_PARAMETER") + object SCRIPT_IMPLICIT_RECEIVER : IrDeclarationOriginImpl("SCRIPT_IMPLICIT_RECEIVER") + object SCRIPT_PROVIDED_PROPERTY : IrDeclarationOriginImpl("SCRIPT_PROVIDED_PROPERTY") + object SCRIPT_RESULT_PROPERTY : IrDeclarationOriginImpl("SCRIPT_RESULT_PROPERTY") object GENERATED_DATA_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_DATA_CLASS_MEMBER") object GENERATED_INLINE_CLASS_MEMBER : IrDeclarationOriginImpl("GENERATED_INLINE_CLASS_MEMBER") object LOCAL_FUNCTION_FOR_LAMBDA : IrDeclarationOriginImpl("LOCAL_FUNCTION_FOR_LAMBDA") 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 ec3b4c08c40..57ad5aa23b7 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 @@ -6,7 +6,9 @@ package org.jetbrains.kotlin.ir.declarations import org.jetbrains.kotlin.ir.expressions.IrStatementContainer +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol +import org.jetbrains.kotlin.ir.types.IrType //TODO: make IrScript as IrPackageFragment, because script is used as a file, not as a class //NOTE: declarations and statements stored separately @@ -15,5 +17,16 @@ abstract class IrScript : IrDeclarationParent, IrStatementContainer { // NOTE: is the result of the FE conversion, because there script interpreted as a class and has receiver + // TODO: consider removing from here and handle appropriately in the lowering abstract var thisReceiver: IrValueParameter + + abstract var baseClass: IrType + + abstract var explicitCallParameters: List + + abstract var implicitReceivers: List + + abstract var providedProperties: List + + abstract var resultProperty: IrPropertySymbol? } 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 9d8ff5558d6..ab589b026a3 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 @@ -11,7 +11,9 @@ import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.IrConstructorCall +import org.jetbrains.kotlin.ir.symbols.IrPropertySymbol import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol +import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.util.transformInPlace import org.jetbrains.kotlin.ir.visitors.IrElementTransformer import org.jetbrains.kotlin.ir.visitors.IrElementVisitor @@ -42,6 +44,12 @@ class IrScriptImpl( override lateinit var thisReceiver: IrValueParameter + override lateinit var baseClass: IrType + override lateinit var explicitCallParameters: List + override lateinit var implicitReceivers: List + override lateinit var providedProperties: List + override var resultProperty: IrPropertySymbol? = null + @ObsoleteDescriptorBasedAPI override val descriptor: ScriptDescriptor get() = symbol.descriptor diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/WrappedDescriptors.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/WrappedDescriptors.kt index 3d5fced9fa4..40d28553d01 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/WrappedDescriptors.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/descriptors/WrappedDescriptors.kt @@ -10,8 +10,8 @@ import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptor import org.jetbrains.kotlin.descriptors.annotations.AnnotationDescriptorImpl import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.descriptors.impl.TypeAliasConstructorDescriptor -import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.IrElement +import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.declarations.* import org.jetbrains.kotlin.ir.expressions.* import org.jetbrains.kotlin.ir.types.classifierOrFail @@ -644,6 +644,110 @@ open class WrappedClassDescriptor : ClassDescriptor, WrappedDeclarationDescripto } } +@OptIn(ObsoleteDescriptorBasedAPI::class) +open class WrappedScriptDescriptor : ScriptDescriptor, WrappedDeclarationDescriptor() { + override fun getName() = owner.name + + override fun getMemberScope(typeArguments: MutableList) = MemberScope.Empty + + override fun getMemberScope(typeSubstitution: TypeSubstitution) = MemberScope.Empty + + override fun getUnsubstitutedMemberScope() = MemberScope.Empty + + override fun getUnsubstitutedInnerClassesScope() = MemberScope.Empty + + override fun getStaticScope() = MemberScope.Empty + + override fun getSource(): SourceElement = SourceElement.NO_SOURCE + + override fun getConstructors() = + owner.statements.filterIsInstance().filter { !it.origin.isSynthetic }.map { it.descriptor }.toList() + + override fun getContainingDeclaration() = (owner.parent as IrSymbolOwner).symbol.descriptor + + private val _defaultType: SimpleType by lazy { + TypeUtils.makeUnsubstitutedType(this, unsubstitutedMemberScope, KotlinTypeFactory.EMPTY_REFINED_TYPE_FACTORY) + } + + override fun getDefaultType(): SimpleType = _defaultType + + override fun getKind() = TODO() + + override fun getModality() = TODO() + + override fun getCompanionObjectDescriptor() = owner.statements.filterIsInstance().firstOrNull { it.isCompanion }?.descriptor + + override fun getVisibility() = TODO() + + override fun isCompanionObject() = false + + override fun isData() = false + + override fun isInline() = false + + override fun isFun() = false + + override fun getThisAsReceiverParameter() = owner.thisReceiver.descriptor as ReceiverParameterDescriptor + + override fun getUnsubstitutedPrimaryConstructor() = TODO() + + override fun getDeclaredTypeParameters() = TODO() + + override fun getSealedSubclasses(): Collection { + TODO("not implemented") + } + + override fun getOriginal() = this + + override fun isExpect() = false + + override fun substitute(substitutor: TypeSubstitutor): ClassifierDescriptorWithTypeParameters = + throw UnsupportedOperationException("Wrapped descriptors SHOULD NOT be substituted") + + override fun isInner(): Boolean { + TODO("Not yet implemented") + } + + override fun isActual() = false + + override fun isExternal(): Boolean { + TODO("Not yet implemented") + } + + override fun getTypeConstructor(): TypeConstructor = TODO() + + override fun accept(visitor: DeclarationDescriptorVisitor?, data: D): R = + visitor!!.visitClassDescriptor(this, data) + + override fun acceptVoid(visitor: DeclarationDescriptorVisitor?) { + visitor!!.visitClassDescriptor(this, null) + } + + override fun getDefaultFunctionTypeForSamInterface(): SimpleType? { + TODO("not implemented") + } + + override fun isDefinitelyNotSamInterface(): Boolean { + TODO("Not yet implemented") + } + + override fun getPriority(): Int { + TODO("Not yet implemented") + } + + override fun getImplicitReceivers(): MutableList { + TODO("Not yet implemented") + } + + override fun getScriptProvidedProperties(): MutableList { + TODO("Not yet implemented") + } + + override fun getResultValue(): PropertyDescriptor? { + TODO("Not yet implemented") + } +} + class LazyTypeConstructor( val classDescriptor: ClassDescriptor, val parametersBuilder: () -> List, diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt index d9cf941740f..d11dfe3230b 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/symbols/IrSymbol.kt @@ -69,7 +69,7 @@ interface IrClassifierSymbol : IrSymbol, TypeConstructorMarker { interface IrClassSymbol : IrClassifierSymbol, IrBindableSymbol -interface IrScriptSymbol : IrSymbol, IrBindableSymbol +interface IrScriptSymbol : IrClassifierSymbol, IrBindableSymbol interface IrTypeParameterSymbol : IrClassifierSymbol, IrBindableSymbol, TypeParameterMarker diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt index 59dcd417ef4..851d547fb0f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopyIrTreeWithSymbols.kt @@ -114,8 +114,7 @@ open class DeepCopyIrTreeWithSymbols( override fun visitScript(declaration: IrScript): IrStatement { return IrScriptImpl( - //TODO: something may go wrong, because expected using symbolRemapper - IrScriptSymbolImpl(declaration.descriptor as ScriptDescriptor), + symbolRemapper.getDeclaredScript(declaration.symbol), declaration.name ).also { scriptCopy -> scriptCopy.thisReceiver = declaration.thisReceiver.transform() diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySymbolRemapper.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySymbolRemapper.kt index 1684ffb2b49..f37a0ad690a 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySymbolRemapper.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DeepCopySymbolRemapper.kt @@ -33,6 +33,7 @@ open class DeepCopySymbolRemapper( ) : IrElementVisitorVoid, SymbolRemapper { private val classes = hashMapOf() + private val scripts = hashMapOf() private val constructors = hashMapOf() private val enumEntries = hashMapOf() private val externalPackageFragments = hashMapOf() @@ -64,6 +65,13 @@ open class DeepCopySymbolRemapper( declaration.acceptChildrenVoid(this) } + override fun visitScript(declaration: IrScript) { + remapSymbol(scripts, declaration) { + IrScriptSymbolImpl(descriptorsRemapper.remapDeclaredScript(it.descriptor)) + } + declaration.acceptChildrenVoid(this) + } + override fun visitConstructor(declaration: IrConstructor) { remapSymbol(constructors, declaration) { IrConstructorSymbolImpl(descriptorsRemapper.remapDeclaredConstructor(it.descriptor)) @@ -166,6 +174,7 @@ open class DeepCopySymbolRemapper( getOrElse(symbol) { symbol } override fun getDeclaredClass(symbol: IrClassSymbol): IrClassSymbol = classes.getDeclared(symbol) + override fun getDeclaredScript(symbol: IrScriptSymbol): IrScriptSymbol = scripts.getDeclared(symbol) override fun getDeclaredFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol = functions.getDeclared(symbol) override fun getDeclaredProperty(symbol: IrPropertySymbol): IrPropertySymbol = properties.getDeclared(symbol) override fun getDeclaredField(symbol: IrFieldSymbol): IrFieldSymbol = fields.getDeclared(symbol) @@ -184,6 +193,7 @@ open class DeepCopySymbolRemapper( override fun getDeclaredTypeAlias(symbol: IrTypeAliasSymbol): IrTypeAliasSymbol = typeAliases.getDeclared(symbol) override fun getReferencedClass(symbol: IrClassSymbol): IrClassSymbol = classes.getReferenced(symbol) + override fun getReferencedScript(symbol: IrScriptSymbol): IrScriptSymbol = scripts.getReferenced(symbol) override fun getReferencedClassOrNull(symbol: IrClassSymbol?): IrClassSymbol? = symbol?.let { classes.getReferenced(it) } override fun getReferencedEnumEntry(symbol: IrEnumEntrySymbol): IrEnumEntrySymbol = enumEntries.getReferenced(symbol) override fun getReferencedVariable(symbol: IrVariableSymbol): IrVariableSymbol = variables.getReferenced(symbol) @@ -214,6 +224,7 @@ open class DeepCopySymbolRemapper( override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol = when (symbol) { is IrClassSymbol -> classes.getReferenced(symbol) + is IrScriptSymbol -> scripts.getReferenced(symbol) is IrTypeParameterSymbol -> typeParameters.getReferenced(symbol) else -> throw IllegalArgumentException("Unexpected symbol $symbol") } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DescriptorsRemapper.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DescriptorsRemapper.kt index 6be2012e176..68c121e3e86 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DescriptorsRemapper.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/DescriptorsRemapper.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.descriptors.* interface DescriptorsRemapper { fun remapDeclaredClass(descriptor: ClassDescriptor): ClassDescriptor = descriptor + fun remapDeclaredScript(descriptor: ScriptDescriptor): ScriptDescriptor = descriptor fun remapDeclaredConstructor(descriptor: ClassConstructorDescriptor): ClassConstructorDescriptor = descriptor fun remapDeclaredEnumEntry(descriptor: ClassDescriptor): ClassDescriptor = descriptor fun remapDeclaredExternalPackageFragment(descriptor: PackageFragmentDescriptor): PackageFragmentDescriptor = descriptor diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt index aa68c6acf8d..9452afa3261 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/InlineClasses.kt @@ -10,6 +10,7 @@ import org.jetbrains.kotlin.ir.declarations.IrConstructor import org.jetbrains.kotlin.ir.declarations.IrField import org.jetbrains.kotlin.ir.declarations.IrProperty import org.jetbrains.kotlin.ir.symbols.IrClassSymbol +import org.jetbrains.kotlin.ir.symbols.IrScriptSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.types.IrSimpleType import org.jetbrains.kotlin.ir.types.IrType diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt index f8ac4d8ed9a..cc6d908565d 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/RenderIrElement.kt @@ -743,6 +743,7 @@ internal fun IrClassifierSymbol.renderClassifierFqn(): String = if (isBound) when (val owner = owner) { is IrClass -> owner.renderClassFqn() + is IrScript -> owner.renderScriptFqn() is IrTypeParameter -> owner.renderTypeParameterFqn() else -> "`unexpected classifier: ${owner.render()}`" } @@ -758,6 +759,9 @@ internal fun IrTypeAliasSymbol.renderTypeAliasFqn(): String = internal fun IrClass.renderClassFqn(): String = StringBuilder().also { renderDeclarationFqn(it) }.toString() +internal fun IrScript.renderScriptFqn(): String = + StringBuilder().also { renderDeclarationFqn(it) }.toString() + internal fun IrTypeParameter.renderTypeParameterFqn(): String = StringBuilder().also { sb -> sb.append(name.asString()) diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolRemapper.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolRemapper.kt index 2f57081ef81..a2763a0f36f 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolRemapper.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolRemapper.kt @@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.symbols.* interface SymbolRemapper { fun getDeclaredClass(symbol: IrClassSymbol): IrClassSymbol + fun getDeclaredScript(symbol: IrScriptSymbol): IrScriptSymbol fun getDeclaredFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol fun getDeclaredProperty(symbol: IrPropertySymbol): IrPropertySymbol fun getDeclaredField(symbol: IrFieldSymbol): IrFieldSymbol @@ -34,6 +35,7 @@ interface SymbolRemapper { fun getDeclaredTypeAlias(symbol: IrTypeAliasSymbol): IrTypeAliasSymbol fun getReferencedClass(symbol: IrClassSymbol): IrClassSymbol + fun getReferencedScript(symbol: IrScriptSymbol): IrScriptSymbol fun getReferencedClassOrNull(symbol: IrClassSymbol?): IrClassSymbol? fun getReferencedEnumEntry(symbol: IrEnumEntrySymbol): IrEnumEntrySymbol fun getReferencedVariable(symbol: IrVariableSymbol): IrVariableSymbol @@ -47,4 +49,65 @@ interface SymbolRemapper { fun getReferencedReturnableBlock(symbol: IrReturnableBlockSymbol): IrReturnableBlockSymbol fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol fun getReferencedTypeAlias(symbol: IrTypeAliasSymbol): IrTypeAliasSymbol + + open class Empty : SymbolRemapper { + override fun getDeclaredClass(symbol: IrClassSymbol): IrClassSymbol = symbol + + override fun getDeclaredScript(symbol: IrScriptSymbol): IrScriptSymbol = symbol + + override fun getDeclaredFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol = symbol + + override fun getDeclaredProperty(symbol: IrPropertySymbol): IrPropertySymbol = symbol + + override fun getDeclaredField(symbol: IrFieldSymbol): IrFieldSymbol = symbol + + override fun getDeclaredFile(symbol: IrFileSymbol): IrFileSymbol = symbol + + override fun getDeclaredConstructor(symbol: IrConstructorSymbol): IrConstructorSymbol = symbol + + override fun getDeclaredEnumEntry(symbol: IrEnumEntrySymbol): IrEnumEntrySymbol = symbol + + override fun getDeclaredExternalPackageFragment(symbol: IrExternalPackageFragmentSymbol): IrExternalPackageFragmentSymbol = symbol + + override fun getDeclaredVariable(symbol: IrVariableSymbol): IrVariableSymbol = symbol + + override fun getDeclaredLocalDelegatedProperty(symbol: IrLocalDelegatedPropertySymbol): IrLocalDelegatedPropertySymbol = symbol + + override fun getDeclaredTypeParameter(symbol: IrTypeParameterSymbol): IrTypeParameterSymbol = symbol + + override fun getDeclaredValueParameter(symbol: IrValueParameterSymbol): IrValueParameterSymbol = symbol + + override fun getDeclaredTypeAlias(symbol: IrTypeAliasSymbol): IrTypeAliasSymbol = symbol + + override fun getReferencedClass(symbol: IrClassSymbol): IrClassSymbol = symbol + + override fun getReferencedScript(symbol: IrScriptSymbol): IrScriptSymbol = symbol + + override fun getReferencedClassOrNull(symbol: IrClassSymbol?): IrClassSymbol? = symbol + + override fun getReferencedEnumEntry(symbol: IrEnumEntrySymbol): IrEnumEntrySymbol = symbol + + override fun getReferencedVariable(symbol: IrVariableSymbol): IrVariableSymbol = symbol + + override fun getReferencedLocalDelegatedProperty(symbol: IrLocalDelegatedPropertySymbol): IrLocalDelegatedPropertySymbol = symbol + + override fun getReferencedField(symbol: IrFieldSymbol): IrFieldSymbol = symbol + + override fun getReferencedConstructor(symbol: IrConstructorSymbol): IrConstructorSymbol = symbol + + override fun getReferencedValue(symbol: IrValueSymbol): IrValueSymbol = symbol + + override fun getReferencedFunction(symbol: IrFunctionSymbol): IrFunctionSymbol = symbol + + override fun getReferencedProperty(symbol: IrPropertySymbol): IrPropertySymbol = symbol + + override fun getReferencedSimpleFunction(symbol: IrSimpleFunctionSymbol): IrSimpleFunctionSymbol = symbol + + override fun getReferencedReturnableBlock(symbol: IrReturnableBlockSymbol): IrReturnableBlockSymbol = symbol + + override fun getReferencedClassifier(symbol: IrClassifierSymbol): IrClassifierSymbol = symbol + + override fun getReferencedTypeAlias(symbol: IrTypeAliasSymbol): IrTypeAliasSymbol = symbol + } + } \ No newline at end of file diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt index 6e90cca0ef1..4e58d7b3ef5 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/SymbolTable.kt @@ -37,6 +37,8 @@ import org.jetbrains.kotlin.serialization.deserialization.descriptors.Descriptor interface ReferenceSymbolTable { fun referenceClass(descriptor: ClassDescriptor): IrClassSymbol + fun referenceScript(descriptor: ScriptDescriptor): IrScriptSymbol + fun referenceConstructor(descriptor: ClassConstructorDescriptor): IrConstructorSymbol fun referenceEnumEntry(descriptor: ClassDescriptor): IrEnumEntrySymbol @@ -397,7 +399,19 @@ class SymbolTable( ) } - fun referenceScript(descriptor: ScriptDescriptor): IrScriptSymbol { + fun declareScript( + sig: IdSignature, + symbolFactory: () -> IrScriptSymbol, + classFactory: (IrScriptSymbol) -> IrScript + ): IrScript { + return scriptSymbolTable.declare( + sig, + symbolFactory, + classFactory + ) + } + + override fun referenceScript(descriptor: ScriptDescriptor): IrScriptSymbol { return scriptSymbolTable.referenced(descriptor) { IrScriptSymbolImpl(descriptor) } } diff --git a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt index c09848f00f5..4a7e673a1fc 100644 --- a/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt +++ b/compiler/ir/ir.tree/src/org/jetbrains/kotlin/ir/util/TypeTranslator.kt @@ -8,10 +8,8 @@ package org.jetbrains.kotlin.ir.util import org.jetbrains.kotlin.builtins.KotlinBuiltIns import org.jetbrains.kotlin.config.LanguageFeature import org.jetbrains.kotlin.config.LanguageVersionSettings -import org.jetbrains.kotlin.descriptors.ClassDescriptor -import org.jetbrains.kotlin.descriptors.PropertyDescriptor -import org.jetbrains.kotlin.descriptors.TypeAliasDescriptor -import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor +import org.jetbrains.kotlin.descriptors.* +import org.jetbrains.kotlin.descriptors.annotations.Annotations import org.jetbrains.kotlin.ir.ObsoleteDescriptorBasedAPI import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET import org.jetbrains.kotlin.ir.declarations.IrConstructor @@ -119,6 +117,9 @@ class TypeTranslator( annotations = translateTypeAnnotations(upperType, approximatedType) } + is ScriptDescriptor -> { + classifier = symbolTable.referenceScript(upperTypeDescriptor) + } is ClassDescriptor -> { // Types such as 'java.util.Collection' are treated as // '( kotlin.collections.MutableCollection diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractFirScriptCodegenTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractFirScriptCodegenTest.kt new file mode 100644 index 00000000000..23f8f90413d --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractFirScriptCodegenTest.kt @@ -0,0 +1,18 @@ +/* + * Copyright 2010-2020 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.codegen.ir + +import org.jetbrains.kotlin.config.CommonConfigurationKeys +import org.jetbrains.kotlin.config.CompilerConfiguration +import org.jetbrains.kotlin.config.JVMConfigurationKeys + +abstract class AbstractFirScriptCodegenTest : AbstractIrScriptCodegenTest() { + override fun updateConfiguration(configuration: CompilerConfiguration) { + super.updateConfiguration(configuration) + configuration.put(CommonConfigurationKeys.USE_FIR, true) + configuration.put(JVMConfigurationKeys.IR, true) + } +} diff --git a/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrScriptCodegenTest.kt b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrScriptCodegenTest.kt new file mode 100644 index 00000000000..0d6e149b5b0 --- /dev/null +++ b/compiler/tests-common/tests/org/jetbrains/kotlin/codegen/ir/AbstractIrScriptCodegenTest.kt @@ -0,0 +1,13 @@ +/* + * Copyright 2010-2020 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.codegen.ir + +import org.jetbrains.kotlin.codegen.AbstractScriptCodegenTest +import org.jetbrains.kotlin.test.TargetBackend + +abstract class AbstractIrScriptCodegenTest : AbstractScriptCodegenTest() { + override val backend = TargetBackend.JVM_IR +} diff --git a/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java new file mode 100644 index 00000000000..005803d5dd9 --- /dev/null +++ b/compiler/tests/org/jetbrains/kotlin/codegen/ir/IrScriptCodegenTestGenerated.java @@ -0,0 +1,176 @@ +/* + * Copyright 2010-2020 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.codegen.ir; + +import com.intellij.testFramework.TestDataPath; +import org.jetbrains.kotlin.test.JUnit3RunnerWithInners; +import org.jetbrains.kotlin.test.KotlinTestUtils; +import org.jetbrains.kotlin.test.TargetBackend; +import org.jetbrains.kotlin.test.TestMetadata; +import org.junit.runner.RunWith; + +import java.io.File; +import java.util.regex.Pattern; + +/** This class is generated by {@link org.jetbrains.kotlin.generators.tests.TestsPackage}. DO NOT MODIFY MANUALLY */ +@SuppressWarnings("all") +@TestMetadata("compiler/testData/codegen/script") +@TestDataPath("$PROJECT_ROOT") +@RunWith(JUnit3RunnerWithInners.class) +public class IrScriptCodegenTestGenerated extends AbstractIrScriptCodegenTest { + private void runTest(String testDataFilePath) throws Exception { + KotlinTestUtils.runTest(this::doTest, TargetBackend.JVM_IR, testDataFilePath); + } + + @TestMetadata("adder.kts") + public void testAdder() throws Exception { + runTest("compiler/testData/codegen/script/adder.kts"); + } + + public void testAllFilesPresentInScript() throws Exception { + KotlinTestUtils.assertAllTestsPresentByMetadataWithExcluded(this.getClass(), new File("compiler/testData/codegen/script"), Pattern.compile("^(.+)\\.kts$"), null, TargetBackend.JVM_IR, true); + } + + @TestMetadata("classLiteralInsideFunction.kts") + public void testClassLiteralInsideFunction() throws Exception { + runTest("compiler/testData/codegen/script/classLiteralInsideFunction.kts"); + } + + @TestMetadata("destructuringDeclaration.kts") + public void testDestructuringDeclaration() throws Exception { + runTest("compiler/testData/codegen/script/destructuringDeclaration.kts"); + } + + @TestMetadata("destructuringDeclarationUnderscore.kts") + public void testDestructuringDeclarationUnderscore() throws Exception { + runTest("compiler/testData/codegen/script/destructuringDeclarationUnderscore.kts"); + } + + @TestMetadata("empty.kts") + public void testEmpty() throws Exception { + runTest("compiler/testData/codegen/script/empty.kts"); + } + + @TestMetadata("helloWorld.kts") + public void testHelloWorld() throws Exception { + runTest("compiler/testData/codegen/script/helloWorld.kts"); + } + + @TestMetadata("inline.kts") + public void testInline() throws Exception { + runTest("compiler/testData/codegen/script/inline.kts"); + } + + @TestMetadata("kt20707.kts") + public void testKt20707() throws Exception { + runTest("compiler/testData/codegen/script/kt20707.kts"); + } + + @TestMetadata("kt22029.kts") + public void testKt22029() throws Exception { + runTest("compiler/testData/codegen/script/kt22029.kts"); + } + + @TestMetadata("localDelegatedProperty.kts") + public void testLocalDelegatedProperty() throws Exception { + runTest("compiler/testData/codegen/script/localDelegatedProperty.kts"); + } + + @TestMetadata("localDelegatedPropertyNoExplicitType.kts") + public void testLocalDelegatedPropertyNoExplicitType() throws Exception { + runTest("compiler/testData/codegen/script/localDelegatedPropertyNoExplicitType.kts"); + } + + @TestMetadata("localFunction.kts") + public void testLocalFunction() throws Exception { + runTest("compiler/testData/codegen/script/localFunction.kts"); + } + + @TestMetadata("outerCapture.kts") + public void testOuterCapture() throws Exception { + runTest("compiler/testData/codegen/script/outerCapture.kts"); + } + + @TestMetadata("parameter.kts") + public void testParameter() throws Exception { + runTest("compiler/testData/codegen/script/parameter.kts"); + } + + @TestMetadata("parameterArray.kts") + public void testParameterArray() throws Exception { + runTest("compiler/testData/codegen/script/parameterArray.kts"); + } + + @TestMetadata("parameterClosure.kts") + public void testParameterClosure() throws Exception { + runTest("compiler/testData/codegen/script/parameterClosure.kts"); + } + + @TestMetadata("parameterLong.kts") + public void testParameterLong() throws Exception { + runTest("compiler/testData/codegen/script/parameterLong.kts"); + } + + @TestMetadata("secondLevelFunction.kts") + public void testSecondLevelFunction() throws Exception { + runTest("compiler/testData/codegen/script/secondLevelFunction.kts"); + } + + @TestMetadata("secondLevelFunctionClosure.kts") + public void testSecondLevelFunctionClosure() throws Exception { + runTest("compiler/testData/codegen/script/secondLevelFunctionClosure.kts"); + } + + @TestMetadata("secondLevelVal.kts") + public void testSecondLevelVal() throws Exception { + runTest("compiler/testData/codegen/script/secondLevelVal.kts"); + } + + @TestMetadata("simpleClass.kts") + public void testSimpleClass() throws Exception { + runTest("compiler/testData/codegen/script/simpleClass.kts"); + } + + @TestMetadata("string.kts") + public void testString() throws Exception { + runTest("compiler/testData/codegen/script/string.kts"); + } + + @TestMetadata("topLevelFunction.kts") + public void testTopLevelFunction() throws Exception { + runTest("compiler/testData/codegen/script/topLevelFunction.kts"); + } + + @TestMetadata("topLevelFunctionClosure.kts") + public void testTopLevelFunctionClosure() throws Exception { + runTest("compiler/testData/codegen/script/topLevelFunctionClosure.kts"); + } + + @TestMetadata("topLevelLocalDelegatedProperty.kts") + public void testTopLevelLocalDelegatedProperty() throws Exception { + runTest("compiler/testData/codegen/script/topLevelLocalDelegatedProperty.kts"); + } + + @TestMetadata("topLevelPropertiesWithGetSet.kts") + public void testTopLevelPropertiesWithGetSet() throws Exception { + runTest("compiler/testData/codegen/script/topLevelPropertiesWithGetSet.kts"); + } + + @TestMetadata("topLevelProperty.kts") + public void testTopLevelProperty() throws Exception { + runTest("compiler/testData/codegen/script/topLevelProperty.kts"); + } + + @TestMetadata("topLevelPropertyWithProvideDelegate.kts") + public void testTopLevelPropertyWithProvideDelegate() throws Exception { + runTest("compiler/testData/codegen/script/topLevelPropertyWithProvideDelegate.kts"); + } + + @TestMetadata("topLevelTypealias.kts") + public void testTopLevelTypealias() throws Exception { + runTest("compiler/testData/codegen/script/topLevelTypealias.kts"); + } +} diff --git a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt index 57828febba9..fde36f70db5 100644 --- a/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt +++ b/compiler/tests/org/jetbrains/kotlin/generators/tests/GenerateCompilerTests.kt @@ -526,6 +526,10 @@ fun main(args: Array) { testClass { model("codegen/asmLike", targetBackend = TargetBackend.JVM_IR) } + + testClass { + model("codegen/script", extension = "kts", targetBackend = TargetBackend.JVM_IR) + } } testGroup( @@ -537,6 +541,10 @@ fun main(args: Array) { model("codegen/box", targetBackend = TargetBackend.JVM_IR, excludeDirs = listOf("oldLanguageVersions")) } + testClass { + model("codegen/script", extension = "kts", targetBackend = TargetBackend.JVM_IR, excludeDirs = listOf("oldLanguageVersions")) + } + testClass { model("codegen/boxInline", targetBackend = TargetBackend.JVM_IR, excludeDirs = listOf("oldLanguageVersions")) } diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/jvmCompilationUtil.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/jvmCompilationUtil.kt index 61a668b1d23..30e6950791f 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/jvmCompilationUtil.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/impl/jvmCompilationUtil.kt @@ -150,8 +150,8 @@ internal fun makeCompiledScript( val module = makeCompiledModule(generationState) val resultField = with(generationState.scriptSpecific) { - if (resultType == null || resultFieldName == null) null - else resultFieldName!! to KotlinType(DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(resultType!!)) + if (resultFieldName == null) null + else resultFieldName!! to KotlinType(resultTypeString ?: DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(resultType!!)) } return KJvmCompiledScript( diff --git a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/GenericReplCompiler.kt b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/GenericReplCompiler.kt index 868f0ffb87a..8e82ecd71ac 100644 --- a/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/GenericReplCompiler.kt +++ b/plugins/scripting/scripting-compiler/src/org/jetbrains/kotlin/scripting/compiler/plugin/repl/GenericReplCompiler.kt @@ -119,7 +119,7 @@ open class GenericReplCompiler( classes, generationState.scriptSpecific.resultFieldName != null, classpathAddendum ?: emptyList(), - generationState.scriptSpecific.resultType?.let { + generationState.scriptSpecific.resultTypeString ?: generationState.scriptSpecific.resultType?.let { DescriptorRenderer.FQ_NAMES_IN_TYPES.renderType(it) }, null