Simple stage layers + enforce model

This commit is contained in:
Anton Bannykh
2020-01-17 19:07:37 +03:00
parent f437da8ee5
commit f07fb91e9d
20 changed files with 293 additions and 133 deletions
@@ -112,7 +112,7 @@ fun DeclarationContainerLoweringPass.runOnFilePostfix(irFile: IrFile) {
this.lower(irFile as IrDeclarationContainer) this.lower(irFile as IrDeclarationContainer)
} }
fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile, withLocalDeclarations: Boolean = false) { fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile, withLocalDeclarations: Boolean = false, allowDeclarationModification: Boolean = false) {
ArrayList(irFile.declarations).forEach { ArrayList(irFile.declarations).forEach {
it.accept(object : IrElementVisitor<Unit, IrDeclaration?> { it.accept(object : IrElementVisitor<Unit, IrDeclaration?> {
override fun visitElement(element: IrElement, data: IrDeclaration?) { override fun visitElement(element: IrElement, data: IrDeclaration?) {
@@ -131,8 +131,13 @@ fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile, withLocalDeclarations: Boo
override fun visitBody(body: IrBody, data: IrDeclaration?) { override fun visitBody(body: IrBody, data: IrDeclaration?) {
if (withLocalDeclarations) body.acceptChildren(this, null) if (withLocalDeclarations) body.acceptChildren(this, null)
if (allowDeclarationModification) {
lower(body, data!!) lower(body, data!!)
} else {
stageController.bodyLowering {
lower(body, data!!)
}
}
} }
}, null) }, null)
} }
@@ -160,7 +165,9 @@ interface DeclarationTransformer: FileLoweringPass {
} }
fun DeclarationTransformer.transformFlatRestricted(declaration: IrDeclaration): List<IrDeclaration>? { fun DeclarationTransformer.transformFlatRestricted(declaration: IrDeclaration): List<IrDeclaration>? {
return transformFlat(declaration) return stageController.restrictTo(declaration) {
transformFlat(declaration)
}
} }
fun DeclarationTransformer.toFileLoweringPass(): FileLoweringPass { fun DeclarationTransformer.toFileLoweringPass(): FileLoweringPass {
@@ -366,7 +366,9 @@ fun IrType.remapTypeParameters(
/* Copied from K/N */ /* Copied from K/N */
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) { fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
this.declarations += declaration stageController.unrestrictDeclarationListsAccess {
this.declarations += declaration
}
declaration.accept(SetDeclarationsParentVisitor, this) declaration.accept(SetDeclarationsParentVisitor, this)
} }
@@ -443,6 +445,7 @@ fun IrClass.simpleFunctions() = declarations.flatMap {
} }
} }
fun IrClass.createParameterDeclarations() { fun IrClass.createParameterDeclarations() {
assert(thisReceiver == null) assert(thisReceiver == null)
@@ -64,7 +64,8 @@ open class InitializersLowering(context: CommonBackendContext) : InitializersLow
abstract class InitializersLoweringBase(open val context: CommonBackendContext) { abstract class InitializersLoweringBase(open val context: CommonBackendContext) {
protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) = protected fun extractInitializers(irClass: IrClass, filter: (IrDeclaration) -> Boolean) =
irClass.declarations.filter(filter).mapNotNull { // TODO What about fields that were added by lowerings? e.g. captured outer class or locals?
ArrayList(irClass.declarations).mapNotNull { if (it is IrProperty) it.backingField else it }.filter(filter).mapNotNull {
when (it) { when (it) {
is IrField -> handleField(irClass, it) is IrField -> handleField(irClass, it)
is IrAnonymousInitializer -> handleAnonymousInitializer(it) is IrAnonymousInitializer -> handleAnonymousInitializer(it)
@@ -34,7 +34,9 @@ class InnerClassesLowering(val context: BackendContext) : DeclarationTransformer
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration is IrClass && declaration.isInner) { if (declaration is IrClass && declaration.isInner) {
declaration.declarations += context.declarationFactory.getOuterThisField(declaration) stageController.unrestrictDeclarationListsAccess {
declaration.declarations += context.declarationFactory.getOuterThisField(declaration)
}
} else if (declaration is IrConstructor) { } else if (declaration is IrConstructor) {
val irClass = declaration.parentAsClass val irClass = declaration.parentAsClass
if (!irClass.isInner) return null if (!irClass.isInner) return null
@@ -15,7 +15,7 @@ import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
//This lower takes part of old LocalDeclarationLowering job to pop up local classes from functions //This lower takes part of old LocalDeclarationLowering job to pop up local classes from functions
open class LocalClassPopupLowering(val context: BackendContext) : BodyLoweringPass { open class LocalClassPopupLowering(val context: BackendContext) : BodyLoweringPass {
override fun lower(irFile: IrFile) { override fun lower(irFile: IrFile) {
runOnFilePostfix(irFile, withLocalDeclarations = true) runOnFilePostfix(irFile, withLocalDeclarations = true, allowDeclarationModification = true)
} }
override fun lower(irBody: IrBody, container: IrDeclaration) { override fun lower(irBody: IrBody, container: IrDeclaration) {
@@ -95,6 +95,10 @@ class LocalDeclarationsLowering(
) : ) :
BodyLoweringPass { BodyLoweringPass {
override fun lower(irFile: IrFile) {
runOnFilePostfix(irFile, allowDeclarationModification = true)
}
object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE : object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE", isSynthetic = true) IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE", isSynthetic = true)
@@ -194,12 +194,12 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
val anyConstructorSymbol = anyClassSymbol.constructors.single() val anyConstructorSymbol = anyClassSymbol.constructors.single()
val jsObjectClassSymbol = getInternalClassWithoutPackage("kotlin.js.JsObject") val jsObjectClassSymbol = getInternalClassWithoutPackage("kotlin.js.JsObject")
val jsObjectConstructorSymbol by lazy { jsObjectClassSymbol.constructors.single() } val jsObjectConstructorSymbol by lazy2 { jsObjectClassSymbol.constructors.single() }
val uByteClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.UByte") } val uByteClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.UByte") }
val uShortClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.UShort") } val uShortClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.UShort") }
val uIntClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.UInt") } val uIntClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.UInt") }
val uLongClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.ULong") } val uLongClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.ULong") }
val unreachable = defineUnreachableIntrinsic() val unreachable = defineUnreachableIntrinsic()
@@ -274,16 +274,16 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
// TODO move CharSequence-related stiff to IntrinsifyCallsLowering // TODO move CharSequence-related stiff to IntrinsifyCallsLowering
val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence"))) val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence")))
val charSequenceLengthPropertyGetterSymbol by lazy { val charSequenceLengthPropertyGetterSymbol by lazy2 {
with(charSequenceClassSymbol.owner.declarations) { with(charSequenceClassSymbol.owner.declarations) {
filterIsInstance<IrProperty>().firstOrNull { it.name.asString() == "length" }?.getter ?: filterIsInstance<IrProperty>().firstOrNull { it.name.asString() == "length" }?.getter ?:
filterIsInstance<IrFunction>().first { it.name.asString() == "<get-length>" } filterIsInstance<IrFunction>().first { it.name.asString() == "<get-length>" }
}.symbol }.symbol
} }
val charSequenceGetFunctionSymbol by lazy { val charSequenceGetFunctionSymbol by lazy2 {
charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "get" }.symbol charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "get" }.symbol
} }
val charSequenceSubSequenceFunctionSymbol by lazy { val charSequenceSubSequenceFunctionSymbol by lazy2 {
charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence" }.symbol charSequenceClassSymbol.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "subSequence" }.symbol
} }
@@ -87,7 +87,7 @@ class JsIrBackendContext(
val declarationLevelJsModules = mutableListOf<IrDeclarationWithName>() val declarationLevelJsModules = mutableListOf<IrDeclarationWithName>()
val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal")) val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))
val implicitDeclarationFile by lazy { val implicitDeclarationFile by lazy2 {
IrFileImpl(object : SourceManager.FileEntry { IrFileImpl(object : SourceManager.FileEntry {
override val name = "<implicitDeclarations>" override val name = "<implicitDeclarations>"
override val maxOffset = UNDEFINED_OFFSET override val maxOffset = UNDEFINED_OFFSET
@@ -281,27 +281,27 @@ class JsIrBackendContext(
val suiteFun = getFunctions(FqName("kotlin.test.suite")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) } val suiteFun = getFunctions(FqName("kotlin.test.suite")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) }
val testFun = getFunctions(FqName("kotlin.test.test")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) } val testFun = getFunctions(FqName("kotlin.test.test")).singleOrNull()?.let { symbolTable.referenceSimpleFunction(it) }
val coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner } val coroutineImplLabelPropertyGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner } val coroutineImplLabelPropertySetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
val coroutineImplResultSymbolGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner } val coroutineImplResultSymbolGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner }
val coroutineImplResultSymbolSetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("result")!!.owner } val coroutineImplResultSymbolSetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("result")!!.owner }
val coroutineImplExceptionPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exception")!!.owner } val coroutineImplExceptionPropertyGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("exception")!!.owner }
val coroutineImplExceptionPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exception")!!.owner } val coroutineImplExceptionPropertySetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("exception")!!.owner }
val coroutineImplExceptionStatePropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exceptionState")!!.owner } val coroutineImplExceptionStatePropertyGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("exceptionState")!!.owner }
val coroutineImplExceptionStatePropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exceptionState")!!.owner } val coroutineImplExceptionStatePropertySetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("exceptionState")!!.owner }
val primitiveClassProperties by lazy { val primitiveClassProperties by lazy2 {
primitiveClassesObject.owner.declarations.filterIsInstance<IrProperty>() primitiveClassesObject.owner.declarations.filterIsInstance<IrProperty>()
} }
val primitiveClassFunctionClass by lazy { val primitiveClassFunctionClass by lazy2 {
primitiveClassesObject.owner.declarations primitiveClassesObject.owner.declarations
.filterIsInstance<IrSimpleFunction>() .filterIsInstance<IrSimpleFunction>()
.find { it.name == Name.identifier("functionClass") }!! .find { it.name == Name.identifier("functionClass") }!!
} }
val throwableConstructors by lazy { throwableClass.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol } } val throwableConstructors by lazy2 { throwableClass.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol } }
val defaultThrowableCtor by lazy { throwableConstructors.single { !it.owner.isPrimary && it.owner.valueParameters.size == 0 } } val defaultThrowableCtor by lazy2 { throwableConstructors.single { !it.owner.isPrimary && it.owner.valueParameters.size == 0 } }
private fun referenceOperators(): Map<Name, MutableMap<IrClassifierSymbol, IrSimpleFunctionSymbol>> { private fun referenceOperators(): Map<Name, MutableMap<IrClassifierSymbol, IrSimpleFunctionSymbol>> {
val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol } val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol }
@@ -352,3 +352,5 @@ class JsIrBackendContext(
print(message) print(message)
} }
} }
fun <T> lazy2(fn: () -> T) = lazy { stageController.withInitialIr(fn) }
@@ -498,77 +498,82 @@ private val objectUsageLoweringPhase = makeJsModulePhase(
description = "Transform IrGetObjectValue into instance generator call" description = "Transform IrGetObjectValue into instance generator call"
) )
val phaseList: List<CompilerPhase<JsIrBackendContext, IrModuleFragment, IrModuleFragment>> = listOf(
scriptRemoveReceiverLowering,
validateIrBeforeLowering,
testGenerationPhase,
expectDeclarationsRemovingPhase,
stripTypeAliasDeclarationsPhase,
arrayConstructorPhase,
functionInliningPhase,
copyInlineFunctionBodyLoweringPhase,
createScriptFunctionsPhase,
provisionalFunctionExpressionPhase,
lateinitNullableFieldsPhase,
lateinitDeclarationLoweringPhase,
lateinitUsageLoweringPhase,
tailrecLoweringPhase,
enumClassConstructorLoweringPhase,
enumClassConstructorBodyLoweringPhase,
sharedVariablesLoweringPhase,
localDelegatedPropertiesLoweringPhase,
localDeclarationsLoweringPhase,
localClassExtractionPhase,
innerClassesLoweringPhase,
innerClassesMemberBodyLoweringPhase,
innerClassConstructorCallsLoweringPhase,
propertiesLoweringPhase,
primaryConstructorLoweringPhase,
delegateToPrimaryConstructorLoweringPhase,
annotationConstructorLowering,
initializersLoweringPhase,
initializersCleanupLoweringPhase,
// Common prefix ends
enumEntryInstancesLoweringPhase,
enumEntryInstancesBodyLoweringPhase,
enumClassCreateInitializerLoweringPhase,
enumEntryCreateGetInstancesFunsLoweringPhase,
enumSyntheticFunsLoweringPhase,
enumUsageLoweringPhase,
enumEntryRemovalLoweringPhase,
suspendFunctionsLoweringPhase,
suspendLambdasRemovalLoweringPhase,
returnableBlockLoweringPhase,
forLoopsLoweringPhase,
primitiveCompanionLoweringPhase,
propertyAccessorInlinerLoweringPhase,
foldConstantLoweringPhase,
privateMembersLoweringPhase,
privateMemberUsagesLoweringPhase,
callableReferenceLoweringPhase,
defaultArgumentStubGeneratorPhase,
defaultArgumentPatchOverridesPhase,
defaultParameterInjectorPhase,
defaultParameterCleanerPhase,
jsDefaultCallbackGeneratorPhase,
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase,
throwableSuccessorsLoweringPhase,
varargLoweringPhase,
multipleCatchesLoweringPhase,
bridgesConstructionPhase,
typeOperatorLoweringPhase,
secondaryConstructorLoweringPhase,
secondaryFactoryInjectorLoweringPhase,
classReferenceLoweringPhase,
inlineClassDeclarationLoweringPhase,
inlineClassUsageLoweringPhase,
autoboxingTransformerPhase,
blockDecomposerLoweringPhase,
constLoweringPhase,
objectDeclarationLoweringPhase,
objectUsageLoweringPhase,
callsLoweringPhase,
validateIrAfterLowering
)
val jsPhases = namedIrModulePhase( val jsPhases = namedIrModulePhase(
name = "IrModuleLowering", name = "IrModuleLowering",
description = "IR module lowering", description = "IR module lowering",
lower = scriptRemoveReceiverLowering then lower = phaseList.drop(1).fold(phaseList[0]) { acc: CompilerPhase<JsIrBackendContext, IrModuleFragment, IrModuleFragment>, phase ->
validateIrBeforeLowering then acc.then(phase)
testGenerationPhase then })
expectDeclarationsRemovingPhase then
stripTypeAliasDeclarationsPhase then
arrayConstructorPhase then
functionInliningPhase then
copyInlineFunctionBodyLoweringPhase then
createScriptFunctionsPhase then
provisionalFunctionExpressionPhase then
lateinitNullableFieldsPhase then
lateinitDeclarationLoweringPhase then
lateinitUsageLoweringPhase then
tailrecLoweringPhase then
enumClassConstructorLoweringPhase then
enumClassConstructorBodyLoweringPhase then
sharedVariablesLoweringPhase then
localDelegatedPropertiesLoweringPhase then
localDeclarationsLoweringPhase then
localClassExtractionPhase then
innerClassesLoweringPhase then
innerClassesMemberBodyLoweringPhase then
innerClassConstructorCallsLoweringPhase then
propertiesLoweringPhase then
primaryConstructorLoweringPhase then
delegateToPrimaryConstructorLoweringPhase then
annotationConstructorLowering then
initializersLoweringPhase then
initializersCleanupLoweringPhase then
// Common prefix ends
enumEntryInstancesLoweringPhase then
enumEntryInstancesBodyLoweringPhase then
enumClassCreateInitializerLoweringPhase then
enumEntryCreateGetInstancesFunsLoweringPhase then
enumSyntheticFunsLoweringPhase then
enumUsageLoweringPhase then
enumEntryRemovalLoweringPhase then
suspendFunctionsLoweringPhase then
suspendLambdasRemovalLoweringPhase then
returnableBlockLoweringPhase then
forLoopsLoweringPhase then
primitiveCompanionLoweringPhase then
propertyAccessorInlinerLoweringPhase then
foldConstantLoweringPhase then
privateMembersLoweringPhase then
privateMemberUsagesLoweringPhase then
callableReferenceLoweringPhase then
defaultArgumentStubGeneratorPhase then
defaultArgumentPatchOverridesPhase then
defaultParameterInjectorPhase then
defaultParameterCleanerPhase then
jsDefaultCallbackGeneratorPhase then
removeInlineFunctionsWithReifiedTypeParametersLoweringPhase then
throwableSuccessorsLoweringPhase then
varargLoweringPhase then
multipleCatchesLoweringPhase then
bridgesConstructionPhase then
typeOperatorLoweringPhase then
secondaryConstructorLoweringPhase then
secondaryFactoryInjectorLoweringPhase then
classReferenceLoweringPhase then
inlineClassDeclarationLoweringPhase then
inlineClassUsageLoweringPhase then
autoboxingTransformerPhase then
blockDecomposerLoweringPhase then
constLoweringPhase then
objectDeclarationLoweringPhase then
objectUsageLoweringPhase then
callsLoweringPhase then
validateIrAfterLowering
)
@@ -0,0 +1,91 @@
/*
* 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.ir.backend.js
import org.jetbrains.kotlin.descriptors.Visibilities
import org.jetbrains.kotlin.ir.IrElement
import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.impl.IrPersistingElementBase
open class MutableController(override var currentStage: Int = 0) : StageController {
override var bodiesEnabled: Boolean = true
override fun <T> withStage(stage: Int, fn: () -> T): T {
val prevStage = currentStage
currentStage = stage
try {
return fn()
} finally {
currentStage = prevStage
}
}
override fun <T> withInitialIr(block: () -> T): T = restrictionImpl(null) { withStage(0, block) }
override fun <T> withInitialStateOf(declaration: IrDeclaration, block: () -> T): T = withStage((declaration as? IrPersistingElementBase<*>)?.createdOn ?: 0, block)
private var restricted: Boolean = false
private var restrictedToDeclaration: IrDeclaration? = null
override fun <T> restrictTo(declaration: IrDeclaration, fn: () -> T): T = restrictionImpl(declaration, fn)
private fun <T> restrictionImpl(declaration: IrDeclaration?, fn: () -> T): T {
val prev = restrictedToDeclaration
restrictedToDeclaration = declaration
val wereBodiesEnabled = bodiesEnabled
bodiesEnabled = false
val wasRestricted = restricted
restricted = true
val wereDeclarationListsRestricted = declarationListsRestricted
declarationListsRestricted = true
try {
return fn()
} finally {
restrictedToDeclaration = prev
bodiesEnabled = wereBodiesEnabled
restricted = wasRestricted
declarationListsRestricted = wereDeclarationListsRestricted
}
}
override fun <T> bodyLowering(fn: () -> T): T {
val wereBodiesEnabled = bodiesEnabled
bodiesEnabled = true
val wasRestricted = restricted
restricted = true
val wereDeclarationListsRestricted = declarationListsRestricted
declarationListsRestricted = true
try {
return fn()
} finally {
bodiesEnabled = wereBodiesEnabled
restricted = wasRestricted
declarationListsRestricted = wereDeclarationListsRestricted
}
}
override fun canModify(element: IrElement): Boolean {
return !restricted || restrictedToDeclaration === element || element is IrPersistingElementBase<*> && element.createdOn == currentStage
}
private var declarationListsRestricted = false
override fun <T> unrestrictDeclarationListsAccess(fn: () -> T): T {
val wereDeclarationListsRestricted = declarationListsRestricted
declarationListsRestricted = false
try {
return fn()
} finally {
declarationListsRestricted = wereDeclarationListsRestricted
}
}
override fun canAccessDeclarationsOf(irClass: IrClass): Boolean {
return !declarationListsRestricted || irClass.visibility == Visibilities.LOCAL /*|| currentStage == (irClass as? IrPersistingElementBase<*>)?.createdOn ?: 0*/
}
}
@@ -8,6 +8,7 @@ package org.jetbrains.kotlin.ir.backend.js
import com.intellij.openapi.project.Project import com.intellij.openapi.project.Project
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
import org.jetbrains.kotlin.backend.common.phaser.PhaserState
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
import org.jetbrains.kotlin.config.CompilerConfiguration import org.jetbrains.kotlin.config.CompilerConfiguration
import org.jetbrains.kotlin.ir.backend.js.export.isExported import org.jetbrains.kotlin.ir.backend.js.export.isExported
@@ -16,10 +17,7 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransf
import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector import org.jetbrains.kotlin.ir.backend.js.utils.JsMainFunctionDetector
import org.jetbrains.kotlin.ir.backend.js.utils.NameTables import org.jetbrains.kotlin.ir.backend.js.utils.NameTables
import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport import org.jetbrains.kotlin.ir.backend.js.utils.isJsExport
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName import org.jetbrains.kotlin.ir.declarations.*
import org.jetbrains.kotlin.ir.declarations.IrField
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
@@ -59,6 +57,8 @@ fun compile(
generateFullJs: Boolean = true, generateFullJs: Boolean = true,
generateDceJs: Boolean = false generateDceJs: Boolean = false
): CompilerResult { ): CompilerResult {
stageController = object : StageController {}
val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) = val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
loadIr(project, mainModule, analyzer, configuration, allDependencies, friendDependencies) loadIr(project, mainModule, analyzer, configuration, allDependencies, friendDependencies)
@@ -93,7 +93,14 @@ fun compile(
moveBodilessDeclarationsToSeparatePlace(context, moduleFragment) moveBodilessDeclarationsToSeparatePlace(context, moduleFragment)
jsPhases.invokeToplevel(phaseConfig, context, moduleFragment) val controller = MutableController()
stageController = controller
val phaserState = PhaserState<IrModuleFragment>()
phaseList.forEachIndexed { index, phase ->
controller.currentStage = index + 1
phase.invoke(phaseConfig, phaserState, context, moduleFragment)
}
val transformer = IrModuleToJsTransformer(context, mainFunction, mainArguments) val transformer = IrModuleToJsTransformer(context, mainFunction, mainArguments)
return transformer.generateModule(moduleFragment, generateFullJs, generateDceJs) return transformer.generateModule(moduleFragment, generateFullJs, generateDceJs)
@@ -68,7 +68,9 @@ abstract class AbstractBlockDecomposerLowering(
val lastStatement = newBody.statements.last() val lastStatement = newBody.statements.last()
val actualParent = if (newBody.statements.size > 1 || lastStatement !is IrReturn || lastStatement.value != expression) { val actualParent = if (newBody.statements.size > 1 || lastStatement !is IrReturn || lastStatement.value != expression) {
expression = JsIrBuilder.buildCall(initFunction.symbol, expression.type) expression = JsIrBuilder.buildCall(initFunction.symbol, expression.type)
(container.parent as IrDeclarationContainer).declarations += initFunction stageController.unrestrictDeclarationListsAccess {
(container.parent as IrDeclarationContainer).declarations += initFunction
}
initFunction initFunction
} else { } else {
container container
@@ -74,7 +74,11 @@ class EnumUsageLowering(val context: JsIrBackendContext) : BodyLoweringPass {
).also { ).also {
descriptor.bind(it) descriptor.bind(it)
it.parent = irClass it.parent = irClass
irClass.declarations += it
// TODO need a way to emerge local declarations from BodyLoweringPass
stageController.unrestrictDeclarationListsAccess {
irClass.declarations += it
}
} }
} }
} }
@@ -268,7 +272,7 @@ class EnumClassConstructorBodyTransformer(val context: JsCommonBackendContext) :
) : ) :
IrElementTransformerVoid() { IrElementTransformerVoid() {
private val enumEntries = irClass.declarations.filterIsInstance<IrEnumEntry>() private val enumEntries = irClass.enumEntries
private val builder = context.createIrBuilder(irClass.symbol) private val builder = context.createIrBuilder(irClass.symbol)
@@ -384,8 +388,11 @@ class EnumClassCreateInitializerLowering(val context: JsIrBackendContext) : Decl
declaration.initEntryInstancesFun = initEntryInstancesFun declaration.initEntryInstancesFun = initEntryInstancesFun
// TODO Why not move to upper level? // TODO Why not move to upper level?
declaration.declarations += entryInstancesInitializedVar // TODO Also doesn't fit the transformFlat-ish API
declaration.declarations += initEntryInstancesFun stageController.unrestrictDeclarationListsAccess {
declaration.declarations += entryInstancesInitializedVar
declaration.declarations += initEntryInstancesFun
}
return null return null
} }
@@ -411,7 +418,7 @@ class EnumClassCreateInitializerLowering(val context: JsIrBackendContext) : Decl
+irIfThen(irGetField(null, entryInstancesInitializedField), irReturnUnit()) +irIfThen(irGetField(null, entryInstancesInitializedField), irReturnUnit())
+irSetField(null, entryInstancesInitializedField, irBoolean(true)) +irSetField(null, entryInstancesInitializedField, irBoolean(true))
irClass.declarations.filterIsInstance<IrEnumEntry>().forEach { entry -> irClass.enumEntries.forEach { entry ->
entry.correspondingField?.let { instanceField -> entry.correspondingField?.let { instanceField ->
+irSetField(null, instanceField, entry.initializerExpression!!.expression) +irSetField(null, instanceField, entry.initializerExpression!!.expression)
} }
@@ -444,9 +451,11 @@ class EnumEntryCreateGetInstancesFunsLowering(val context: JsIrBackendContext):
// TODO prettify // TODO prettify
entryGetInstanceFun.parent = irClass.parent entryGetInstanceFun.parent = irClass.parent
(irClass.parent as IrDeclarationContainer).declarations += entryGetInstanceFun stageController.unrestrictDeclarationListsAccess {
(irClass.parent as IrDeclarationContainer).declarations += entryGetInstanceFun
}
return listOf(declaration) return listOf(declaration) // TODO not null?
} }
} }
@@ -492,10 +501,6 @@ class EnumSyntheticFunctionsLowering(val context: JsIrBackendContext): Declarati
private val throwISESymbol = context.throwISEsymbol private val throwISESymbol = context.throwISEsymbol
// TODO cache
private val IrClass.enumEntries: List<IrEnumEntry>
get() = declarations.filterIsInstance<IrEnumEntry>()
private fun createEnumValueOfBody(valueOfFun: IrFunction, irClass: IrClass): IrBlockBody { private fun createEnumValueOfBody(valueOfFun: IrFunction, irClass: IrClass): IrBlockBody {
val nameParameter = valueOfFun.valueParameters[0] val nameParameter = valueOfFun.valueParameters[0]
@@ -536,6 +541,9 @@ class EnumSyntheticFunctionsLowering(val context: JsIrBackendContext): Declarati
} }
} }
private val IrClass.enumEntries: List<IrEnumEntry>
get() = declarations.filterIsInstance<IrEnumEntry>()
// Should be applied recursively // Should be applied recursively
class EnumClassRemoveEntriesLowering(val context: JsIrBackendContext) : DeclarationTransformer { class EnumClassRemoveEntriesLowering(val context: JsIrBackendContext) : DeclarationTransformer {
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
@@ -37,6 +37,7 @@ class ObjectDeclarationLowering(
) : DeclarationTransformer { ) : DeclarationTransformer {
private var IrClass.instanceField by context.mapping.objectToInstanceField private var IrClass.instanceField by context.mapping.objectToInstanceField
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal()) if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
@@ -55,7 +56,7 @@ class ObjectDeclarationLowering(
declaration.instanceField = instanceField declaration.instanceField = instanceField
val primaryConstructor = declaration.primaryConstructor!! // TODO find a way to trigger this correctly val primaryConstructor = declaration.primaryConstructor ?: declaration.syntheticPrimaryConstructor!!
getInstanceFun.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) { getInstanceFun.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
statements += context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) { statements += context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) {
@@ -16,6 +16,7 @@ import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
import org.jetbrains.kotlin.ir.util.constructors
import org.jetbrains.kotlin.ir.util.parentAsClass import org.jetbrains.kotlin.ir.util.parentAsClass
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -27,7 +28,7 @@ class PrimaryConstructorLowering(context: JsCommonBackendContext) : DeclarationT
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? { override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
if (declaration is IrClass) { if (declaration is IrClass) {
val constructors = declaration.declarations.filterIsInstance<IrConstructor>() val constructors = declaration.constructors
if (constructors.any { it.isPrimary }) return null if (constructors.any { it.isPrimary }) return null
@@ -42,10 +43,13 @@ class PrimaryConstructorLowering(context: JsCommonBackendContext) : DeclarationT
private val unitType = context.irBuiltIns.unitType private val unitType = context.irBuiltIns.unitType
private fun createPrimaryConstructor(irClass: IrClass): IrConstructor { private fun createPrimaryConstructor(irClass: IrClass): IrConstructor {
val declaration = irClass.addConstructor { // TODO better API for declaration creation. This case doesn't fit the usual transformFlat-like API.
origin = SYNTHETIC_PRIMARY_CONSTRUCTOR val declaration = stageController.unrestrictDeclarationListsAccess {
isPrimary = true irClass.addConstructor {
visibility = Visibilities.PRIVATE origin = SYNTHETIC_PRIMARY_CONSTRUCTOR
isPrimary = true
visibility = Visibilities.PRIVATE
}
} }
declaration.body = irClass.run { declaration.body = irClass.run {
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.ir.types.isPrimitiveType
import org.jetbrains.kotlin.ir.types.isString import org.jetbrains.kotlin.ir.types.isString
import org.jetbrains.kotlin.ir.util.defaultType import org.jetbrains.kotlin.ir.util.defaultType
import org.jetbrains.kotlin.ir.util.irCall import org.jetbrains.kotlin.ir.util.irCall
import org.jetbrains.kotlin.ir.util.properties
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
@@ -51,9 +52,12 @@ class PrimitiveCompanionLowering(val context: JsIrBackendContext) : BodyLowering
val actualCompanion = getActualPrimitiveCompanion(companion) val actualCompanion = getActualPrimitiveCompanion(companion)
?: return null ?: return null
return actualCompanion.declarations for (p in actualCompanion.properties) {
.filterIsInstance<IrSimpleFunction>() p.getter?.let { if (it.name == function.name) return it }
.single { it.name == function.name } p.setter?.let { if (it.name == function.name) return it }
}
error("Accessor not found")
} }
override fun lower(irBody: IrBody, container: IrDeclaration) { override fun lower(irBody: IrBody, container: IrDeclaration) {
@@ -23,9 +23,21 @@ interface StageController {
val bodiesEnabled: Boolean get() = true val bodiesEnabled: Boolean get() = true
fun <T> withInitialIr(block: () -> T): T = block()
fun <T> withInitialStateOf(declaration: IrDeclaration, block: () -> T): T = block()
fun <T> restrictTo(declaration: IrDeclaration, fn: () -> T): T = fn()
fun <T> bodyLowering(fn: () -> T): T = fn() fun <T> bodyLowering(fn: () -> T): T = fn()
fun canModify(element: IrElement): Boolean = true fun canModify(element: IrElement): Boolean = true
fun canAccessDeclarationsOf(declaration: IrClass): Boolean = true fun <T> unrestrictDeclarationListsAccess(fn: () -> T): T = fn()
fun canAccessDeclarationsOf(irClass: IrClass): Boolean = true
}
inline fun <T> withInitialIr(noinline fn: () -> T): T {
return stageController.withInitialIr(fn)
} }
@@ -10,6 +10,7 @@ import org.jetbrains.kotlin.descriptors.Visibility
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrTypeAlias import org.jetbrains.kotlin.ir.declarations.IrTypeAlias
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.declarations.withInitialIr
import org.jetbrains.kotlin.ir.symbols.IrTypeAliasSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeAliasSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
@@ -47,8 +48,10 @@ class IrLazyTypeAlias(
} }
override val expandedType: IrType by lazy { override val expandedType: IrType by lazy {
typeTranslator.buildWithScope(this) { withInitialIr {
descriptor.expandedType.toIrType() typeTranslator.buildWithScope(this) {
descriptor.expandedType.toIrType()
}
} }
} }
@@ -9,6 +9,7 @@ import org.jetbrains.kotlin.descriptors.TypeParameterDescriptor
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer import org.jetbrains.kotlin.ir.declarations.IrTypeParametersContainer
import org.jetbrains.kotlin.ir.declarations.withInitialIr
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
import org.jetbrains.kotlin.ir.types.IrType import org.jetbrains.kotlin.ir.types.IrType
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
@@ -57,9 +58,11 @@ class IrLazyTypeParameter(
} }
override val superTypes: MutableList<IrType> by lazy { override val superTypes: MutableList<IrType> by lazy {
typeTranslator.buildWithScope(this.parent as IrTypeParametersContainer) { withInitialIr {
val descriptor = symbol.descriptor typeTranslator.buildWithScope(this.parent as IrTypeParametersContainer) {
descriptor.upperBounds.mapTo(arrayListOf()) { it.toIrType() } val descriptor = symbol.descriptor
descriptor.upperBounds.mapTo(arrayListOf()) { it.toIrType() }
}
} }
} }
@@ -5,6 +5,7 @@
package org.jetbrains.kotlin.ir.declarations.lazy package org.jetbrains.kotlin.ir.declarations.lazy
import org.jetbrains.kotlin.ir.declarations.withInitialIr
import kotlin.reflect.KProperty import kotlin.reflect.KProperty
internal fun <T> lazyVar(initializer: () -> T): UnsafeLazyVar<T> = UnsafeLazyVar(initializer) internal fun <T> lazyVar(initializer: () -> T): UnsafeLazyVar<T> = UnsafeLazyVar(initializer)
@@ -17,7 +18,7 @@ internal class UnsafeLazyVar<T>(initializer: () -> T) {
private val value: T private val value: T
get() { get() {
if (!isInitialized) { if (!isInitialized) {
_value = initializer!!() withInitialIr { _value = initializer!!() }
isInitialized = true isInitialized = true
initializer = null initializer = null
} }