mirror of
https://github.com/jlengrand/kotlin.git
synced 2026-05-11 00:21:29 +00:00
Compare commits
54 Commits
rr/perf/no
...
rr/abannyk
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
bdc0f904f1 | ||
|
|
242119fba2 | ||
|
|
d1d9d41825 | ||
|
|
48116532f9 | ||
|
|
f6f70b7fb0 | ||
|
|
c0470e3cae | ||
|
|
c72b563178 | ||
|
|
78bb5670b2 | ||
|
|
3307aecb2b | ||
|
|
ed086c9114 | ||
|
|
355963e324 | ||
|
|
c575397b6d | ||
|
|
15aaed0837 | ||
|
|
bbdc221a1b | ||
|
|
e958d6b915 | ||
|
|
f978aa637a | ||
|
|
0624296f0c | ||
|
|
4df935a4ac | ||
|
|
13158de050 | ||
|
|
2ac169fa41 | ||
|
|
ccdf5eb908 | ||
|
|
ab9bb748d0 | ||
|
|
2251b0c681 | ||
|
|
67548f85b3 | ||
|
|
5e2152e4ec | ||
|
|
1c336a2f1f | ||
|
|
133a3f2592 | ||
|
|
c44d37395e | ||
|
|
0c37a5317d | ||
|
|
dacb4bdb29 | ||
|
|
d75aa32f0b | ||
|
|
db233abd0b | ||
|
|
a0d97884f0 | ||
|
|
7474f771b4 | ||
|
|
83cfe9abbd | ||
|
|
08d5dfa628 | ||
|
|
a5e7a5d019 | ||
|
|
dafd78f476 | ||
|
|
bd1d6db743 | ||
|
|
8efc6663d7 | ||
|
|
e9e65272b8 | ||
|
|
76e4bfe814 | ||
|
|
3b1bdadfb5 | ||
|
|
9bd8779df1 | ||
|
|
f5d7f823c7 | ||
|
|
4bcecb53dc | ||
|
|
d88dfabec7 | ||
|
|
fc114cff41 | ||
|
|
a65bb5d361 | ||
|
|
103ca9f827 | ||
|
|
712c2e865f | ||
|
|
62d39aed66 | ||
|
|
57bd633be7 | ||
|
|
d38318a546 |
1
.gitignore
vendored
1
.gitignore
vendored
@@ -18,6 +18,7 @@ workspace.xml
|
||||
/jps-plugin/testData/kannotator
|
||||
/js/js.translator/testData/out/
|
||||
/js/js.translator/testData/out-min/
|
||||
/js/js.translator/testData/out-pir/
|
||||
.gradle/
|
||||
build/
|
||||
!**/src/**/build
|
||||
|
||||
@@ -125,6 +125,9 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
@Argument(value = "-Xir-dce", description = "Perform experimental dead code elimination")
|
||||
var irDce: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-Xir-dce-driven", description = "Perform a more experimental faster dead code elimination")
|
||||
var irDceDriven: Boolean by FreezableVar(false)
|
||||
|
||||
@Argument(value = "-Xir-only", description = "Disables pre-IR backend")
|
||||
var irOnly: Boolean by FreezableVar(false)
|
||||
|
||||
|
||||
@@ -228,13 +228,14 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
friendDependencies = friendDependencies,
|
||||
mainArguments = mainCallArguments,
|
||||
generateFullJs = !arguments.irDce,
|
||||
generateDceJs = arguments.irDce
|
||||
generateDceJs = arguments.irDce,
|
||||
dceDriven = arguments.irDceDriven
|
||||
)
|
||||
} catch (e: JsIrCompilationError) {
|
||||
return COMPILATION_ERROR
|
||||
}
|
||||
|
||||
val jsCode = if (arguments.irDce) compiledModule.dceJsCode!! else compiledModule.jsCode!!
|
||||
val jsCode = if (arguments.irDce && !arguments.irDceDriven) compiledModule.dceJsCode!! else compiledModule.jsCode!!
|
||||
outputFile.writeText(jsCode)
|
||||
if (arguments.generateDts) {
|
||||
val dtsFile = outputFile.withReplacedExtensionOrNull(outputFile.extension, "d.ts")!!
|
||||
|
||||
@@ -587,7 +587,7 @@ class Fir2IrDeclarationStorage(
|
||||
this.correspondingClass = klass
|
||||
} else if (irParent != null) {
|
||||
this.initializerExpression =
|
||||
IrEnumConstructorCallImpl(startOffset, endOffset, irType, irParent.constructors.first().symbol)
|
||||
IrExpressionBodyImpl(IrEnumConstructorCallImpl(startOffset, endOffset, irType, irParent.constructors.first().symbol))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@ import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.SharedVariablesManager
|
||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
@@ -35,4 +36,5 @@ interface BackendContext {
|
||||
val internalPackageFqn: FqName
|
||||
val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
||||
val lateinitNullableFields: MutableMap<IrField, IrField>
|
||||
val extractedLocalClasses: MutableSet<IrClass>
|
||||
}
|
||||
|
||||
@@ -33,4 +33,6 @@ interface CommonBackendContext : BackendContext, LoggingContext {
|
||||
putValueArgument(0, builder.irString(name))
|
||||
}
|
||||
}
|
||||
|
||||
val mapping: Mapping
|
||||
}
|
||||
|
||||
@@ -68,6 +68,20 @@ abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid()
|
||||
return result
|
||||
}
|
||||
|
||||
final override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement {
|
||||
scopeStack.push(createScope(declaration))
|
||||
val result = visitAnonymousInitializerNew(declaration)
|
||||
scopeStack.pop()
|
||||
return result
|
||||
}
|
||||
|
||||
final override fun visitValueParameter(declaration: IrValueParameter): IrStatement {
|
||||
scopeStack.push(createScope(declaration))
|
||||
val result = visitValueParameterNew(declaration)
|
||||
scopeStack.pop()
|
||||
return result
|
||||
}
|
||||
|
||||
final override fun visitScript(declaration: IrScript): IrStatement {
|
||||
scopeStack.push(createScope(declaration))
|
||||
val result = visitScriptNew(declaration)
|
||||
@@ -80,6 +94,8 @@ abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid()
|
||||
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrClassSymbol }
|
||||
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrFunctionSymbol }
|
||||
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrPropertySymbol }
|
||||
protected val currentAnonymousInitializer get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrAnonymousInitializer }
|
||||
protected val currentValueParameter get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrValueParameter }
|
||||
protected val currentScope get() = scopeStack.peek()
|
||||
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
|
||||
protected val allScopes get() = scopeStack
|
||||
@@ -109,6 +125,14 @@ abstract class IrElementTransformerVoidWithContext : IrElementTransformerVoid()
|
||||
return super.visitField(declaration)
|
||||
}
|
||||
|
||||
open fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer): IrStatement {
|
||||
return super.visitAnonymousInitializer(declaration)
|
||||
}
|
||||
|
||||
open fun visitValueParameterNew(declaration: IrValueParameter): IrStatement {
|
||||
return super.visitValueParameter(declaration)
|
||||
}
|
||||
|
||||
open fun visitScriptNew(declaration: IrScript): IrStatement {
|
||||
return super.visitScript(declaration)
|
||||
}
|
||||
@@ -152,10 +176,24 @@ abstract class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
|
||||
scopeStack.pop()
|
||||
}
|
||||
|
||||
final override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
|
||||
scopeStack.push(createScope(declaration))
|
||||
visitAnonymousInitializerNew(declaration)
|
||||
scopeStack.pop()
|
||||
}
|
||||
|
||||
final override fun visitValueParameter(declaration: IrValueParameter) {
|
||||
scopeStack.push(createScope(declaration))
|
||||
visitValueParameterNew(declaration)
|
||||
scopeStack.pop()
|
||||
}
|
||||
|
||||
protected val currentFile get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrFileSymbol }
|
||||
protected val currentClass get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrClassSymbol }
|
||||
protected val currentFunction get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrFunctionSymbol }
|
||||
protected val currentProperty get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrPropertySymbol }
|
||||
protected val currentAnonymousInitializer get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrAnonymousInitializer }
|
||||
protected val currentValueParameter get() = scopeStack.lastOrNull { it.scope.scopeOwnerSymbol is IrValueParameter }
|
||||
protected val currentScope get() = scopeStack.peek()
|
||||
protected val parentScope get() = if (scopeStack.size < 2) null else scopeStack[scopeStack.size - 2]
|
||||
protected val allScopes get() = scopeStack
|
||||
@@ -183,4 +221,12 @@ abstract class IrElementVisitorVoidWithContext : IrElementVisitorVoid {
|
||||
open fun visitFieldNew(declaration: IrField) {
|
||||
super.visitField(declaration)
|
||||
}
|
||||
|
||||
open fun visitAnonymousInitializerNew(declaration: IrAnonymousInitializer) {
|
||||
super.visitAnonymousInitializer(declaration)
|
||||
}
|
||||
|
||||
open fun visitValueParameterNew(declaration: IrValueParameter) {
|
||||
super.visitValueParameter(declaration)
|
||||
}
|
||||
}
|
||||
@@ -19,6 +19,8 @@ package org.jetbrains.kotlin.backend.common
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
@@ -58,7 +60,7 @@ interface FunctionLoweringPass : FileLoweringPass {
|
||||
}
|
||||
|
||||
interface BodyLoweringPass : FileLoweringPass {
|
||||
fun lower(irBody: IrBody)
|
||||
fun lower(irBody: IrBody, container: IrDeclaration)
|
||||
|
||||
override fun lower(irFile: IrFile) = runOnFilePostfix(irFile)
|
||||
}
|
||||
@@ -110,17 +112,35 @@ fun DeclarationContainerLoweringPass.runOnFilePostfix(irFile: IrFile) {
|
||||
this.lower(irFile as IrDeclarationContainer)
|
||||
}
|
||||
|
||||
fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile) {
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
fun BodyLoweringPass.runOnFilePostfix(irFile: IrFile, withLocalDeclarations: Boolean = false, allowDeclarationModification: Boolean = false) {
|
||||
ArrayList(irFile.declarations).forEach {
|
||||
it.accept(object : IrElementVisitor<Unit, IrDeclaration?> {
|
||||
override fun visitElement(element: IrElement, data: IrDeclaration?) {
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
override fun visitBody(body: IrBody) {
|
||||
body.acceptChildrenVoid(this)
|
||||
lower(body)
|
||||
}
|
||||
})
|
||||
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclaration?) {
|
||||
declaration.acceptChildren(this, declaration)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: IrDeclaration?) {
|
||||
declaration.thisReceiver?.accept(this, declaration)
|
||||
declaration.typeParameters.forEach { it.accept(this, declaration) }
|
||||
ArrayList(declaration.declarations).forEach { it.accept(this, declaration) }
|
||||
}
|
||||
|
||||
override fun visitBody(body: IrBody, data: IrDeclaration?) {
|
||||
if (withLocalDeclarations) body.acceptChildren(this, null)
|
||||
if (allowDeclarationModification) {
|
||||
lower(body, data!!)
|
||||
} else {
|
||||
stageController.bodyLowering {
|
||||
lower(body, data!!)
|
||||
}
|
||||
}
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
|
||||
fun FunctionLoweringPass.runOnFilePostfix(irFile: IrFile) {
|
||||
@@ -134,4 +154,94 @@ fun FunctionLoweringPass.runOnFilePostfix(irFile: IrFile) {
|
||||
lower(declaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
interface DeclarationTransformer: FileLoweringPass {
|
||||
fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>?
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
runPostfix().toFileLoweringPass().lower(irFile)
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationTransformer.transformFlatRestricted(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return stageController.restrictTo(declaration) {
|
||||
transformFlat(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationTransformer.toFileLoweringPass(): FileLoweringPass {
|
||||
return object : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.declarations.transformFlat(this@toFileLoweringPass::transformFlat)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun DeclarationTransformer.runPostfix(withLocalDeclarations: Boolean = false): DeclarationTransformer {
|
||||
return object : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
declaration.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitBody(body: IrBody) {
|
||||
if (withLocalDeclarations) {
|
||||
super.visitBody(body)
|
||||
}
|
||||
// else stop
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
|
||||
for (v in declaration.valueParameters) {
|
||||
val result = this@runPostfix.transformFlatRestricted(v)
|
||||
if (result != null) error("Don't know how to add value parameters")
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitProperty(declaration: IrProperty) {
|
||||
// TODO This is a hack to allow lowering a getter separately from the enclosing property
|
||||
|
||||
val visitor = this
|
||||
|
||||
fun IrDeclaration.transform() {
|
||||
|
||||
acceptVoid(visitor)
|
||||
|
||||
val result = this@runPostfix.transformFlatRestricted(this)
|
||||
if (result != null) {
|
||||
(parent as? IrDeclarationContainer)?.let {
|
||||
var index = it.declarations.indexOf(this)
|
||||
if (index == -1) {
|
||||
index = it.declarations.indexOf(declaration)
|
||||
} else {
|
||||
it.declarations.removeAt(index)
|
||||
--index
|
||||
}
|
||||
|
||||
it.declarations.addAll(index + 1, result)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
declaration.backingField?.transform()
|
||||
declaration.getter?.transform()
|
||||
declaration.setter?.transform()
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
declaration.thisReceiver?.accept(this, null)
|
||||
declaration.typeParameters.forEach { it.accept(this, null) }
|
||||
ArrayList(declaration.declarations).forEach { it.accept(this, null) }
|
||||
|
||||
declaration.declarations.transformFlat(this@runPostfix::transformFlatRestricted)
|
||||
}
|
||||
})
|
||||
|
||||
return this@runPostfix.transformFlatRestricted(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,63 @@
|
||||
/*
|
||||
* 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.common
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import kotlin.reflect.KMutableProperty0
|
||||
import kotlin.reflect.KProperty
|
||||
|
||||
interface Mapping {
|
||||
val defaultArgumentsDispatchFunction: Delegate<IrFunction, IrFunction>
|
||||
val defaultArgumentsOriginalFunction: Delegate<IrFunction, IrFunction>
|
||||
val suspendFunctionToCoroutineConstructor: Delegate<IrFunction, IrConstructor>
|
||||
val lateInitFieldToNullableField: Delegate<IrField, IrField>
|
||||
val inlineClassMemberToStatic: Delegate<IrFunction, IrSimpleFunction>
|
||||
|
||||
abstract class Delegate<K : IrDeclaration, V> {
|
||||
abstract operator fun get(key: K): V?
|
||||
|
||||
abstract operator fun set(key: K, value: V?)
|
||||
|
||||
operator fun getValue(thisRef: K, desc: KProperty<*>): V? = get(thisRef)
|
||||
|
||||
operator fun setValue(thisRef: K, desc: KProperty<*>, value: V?) {
|
||||
set(thisRef, value)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
open class DefaultMapping : Mapping {
|
||||
|
||||
override val defaultArgumentsDispatchFunction: Mapping.Delegate<IrFunction, IrFunction> = newMapping()
|
||||
override val defaultArgumentsOriginalFunction: Mapping.Delegate<IrFunction, IrFunction> = newMapping()
|
||||
override val suspendFunctionToCoroutineConstructor: Mapping.Delegate<IrFunction, IrConstructor> = newMapping()
|
||||
override val lateInitFieldToNullableField: Mapping.Delegate<IrField, IrField> = newMapping()
|
||||
override val inlineClassMemberToStatic: Mapping.Delegate<IrFunction, IrSimpleFunction> = newMapping()
|
||||
|
||||
protected open fun <K : IrDeclaration, V> newMapping() = object : Mapping.Delegate<K, V>() {
|
||||
private val map: MutableMap<K, V> = mutableMapOf()
|
||||
|
||||
override operator fun get(key: K): V? {
|
||||
return map[key]
|
||||
}
|
||||
|
||||
override operator fun set(key: K, value: V?) {
|
||||
if (value == null) {
|
||||
map.remove(key)
|
||||
} else {
|
||||
map[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun <V : Any> KMutableProperty0<V?>.getOrPut(fn: () -> V) = this.get() ?: fn().also {
|
||||
this.set(it)
|
||||
}
|
||||
|
||||
fun <K : IrDeclaration, V> Mapping.Delegate<K, V>.getOrPut(key: K, fn: () -> V) = this[key] ?: fn().also {
|
||||
this[key] = it
|
||||
}
|
||||
@@ -14,5 +14,6 @@ interface DeclarationFactory {
|
||||
fun getFieldForEnumEntry(enumEntry: IrEnumEntry): IrField
|
||||
fun getOuterThisField(innerClass: IrClass): IrField
|
||||
fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructor
|
||||
fun getInnerClassOriginalPrimaryConstructorOrNull(innerClass: IrClass): IrConstructor?
|
||||
fun getFieldForObjectInstance(singleton: IrClass): IrField
|
||||
}
|
||||
@@ -78,7 +78,7 @@ fun IrClass.addSimpleDelegatingConstructor(
|
||||
constructor.parent = this
|
||||
declarations += constructor
|
||||
|
||||
superConstructor.valueParameters.mapIndexedTo(constructor.valueParameters) { index, parameter ->
|
||||
constructor.valueParameters = superConstructor.valueParameters.mapIndexed { index, parameter ->
|
||||
parameter.copyTo(constructor, index = index)
|
||||
}
|
||||
|
||||
@@ -154,8 +154,13 @@ fun IrValueParameter.copyTo(
|
||||
WrappedValueParameterDescriptor(this.descriptor.annotations, this.descriptor.source)
|
||||
}
|
||||
val symbol = IrValueParameterSymbolImpl(descriptor)
|
||||
val defaultValueCopy = defaultValue?.deepCopyWithVariables()
|
||||
defaultValueCopy?.patchDeclarationParents(irFunction)
|
||||
val defaultValueCopy = defaultValue?.let { originalDefault ->
|
||||
IrExpressionBodyImpl(originalDefault.startOffset, originalDefault.endOffset) {
|
||||
expression = originalDefault.expression.deepCopyWithVariables().also {
|
||||
it.patchDeclarationParents(irFunction)
|
||||
}
|
||||
}
|
||||
}
|
||||
return IrValueParameterImpl(
|
||||
startOffset, endOffset, origin, symbol,
|
||||
name, index, type, varargElementType, isCrossinline, isNoinline
|
||||
@@ -163,7 +168,7 @@ fun IrValueParameter.copyTo(
|
||||
descriptor.bind(it)
|
||||
it.parent = irFunction
|
||||
it.defaultValue = defaultValueCopy
|
||||
it.annotations.addAll(annotations.map { it.deepCopyWithSymbols() })
|
||||
it.annotations = annotations.map { it.deepCopyWithSymbols() }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,7 +210,7 @@ fun IrFunction.copyValueParametersInsertingContinuationFrom(from: IrFunction, in
|
||||
insertContinuation()
|
||||
additionalShift = 1
|
||||
}
|
||||
valueParameters.add(it.copyTo(this, index = it.index + shift + additionalShift))
|
||||
valueParameters += it.copyTo(this, index = it.index + shift + additionalShift)
|
||||
}
|
||||
// If there was no default argument mask and handler, the continuation goes last.
|
||||
if (additionalShift == 0) insertContinuation()
|
||||
@@ -231,7 +236,7 @@ fun IrTypeParametersContainer.copyTypeParameters(
|
||||
oldToNewParameterMap[sourceParameter] = it
|
||||
}
|
||||
}
|
||||
typeParameters.addAll(newTypeParameters)
|
||||
typeParameters += newTypeParameters
|
||||
srcTypeParameters.zip(newTypeParameters).forEach { (srcParameter, dstParameter) ->
|
||||
dstParameter.copySuperTypesFrom(srcParameter, oldToNewParameterMap)
|
||||
}
|
||||
@@ -273,35 +278,29 @@ fun IrFunction.copyValueParametersToStatic(
|
||||
target.classIfConstructor
|
||||
)
|
||||
|
||||
target.valueParameters.add(
|
||||
originalDispatchReceiver.copyTo(
|
||||
target,
|
||||
origin = originalDispatchReceiver.origin,
|
||||
index = shift++,
|
||||
type = type,
|
||||
name = Name.identifier("\$this")
|
||||
)
|
||||
target.valueParameters += originalDispatchReceiver.copyTo(
|
||||
target,
|
||||
origin = originalDispatchReceiver.origin,
|
||||
index = shift++,
|
||||
type = type,
|
||||
name = Name.identifier("\$this")
|
||||
)
|
||||
}
|
||||
source.extensionReceiverParameter?.let { originalExtensionReceiver ->
|
||||
target.valueParameters.add(
|
||||
originalExtensionReceiver.copyTo(
|
||||
target,
|
||||
origin = originalExtensionReceiver.origin,
|
||||
index = shift++,
|
||||
name = Name.identifier("\$receiver")
|
||||
)
|
||||
target.valueParameters += originalExtensionReceiver.copyTo(
|
||||
target,
|
||||
origin = originalExtensionReceiver.origin,
|
||||
index = shift++,
|
||||
name = Name.identifier("\$receiver")
|
||||
)
|
||||
}
|
||||
|
||||
for (oldValueParameter in source.valueParameters) {
|
||||
if (oldValueParameter.index >= numValueParametersToCopy) break
|
||||
target.valueParameters.add(
|
||||
oldValueParameter.copyTo(
|
||||
target,
|
||||
origin = origin,
|
||||
index = oldValueParameter.index + shift
|
||||
)
|
||||
target.valueParameters += oldValueParameter.copyTo(
|
||||
target,
|
||||
origin = origin,
|
||||
index = oldValueParameter.index + shift
|
||||
)
|
||||
}
|
||||
}
|
||||
@@ -367,7 +366,9 @@ fun IrType.remapTypeParameters(
|
||||
|
||||
/* Copied from K/N */
|
||||
fun IrDeclarationContainer.addChild(declaration: IrDeclaration) {
|
||||
this.declarations += declaration
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
this.declarations += declaration
|
||||
}
|
||||
declaration.accept(SetDeclarationsParentVisitor, this)
|
||||
}
|
||||
|
||||
@@ -444,6 +445,7 @@ fun IrClass.simpleFunctions() = declarations.flatMap {
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
fun IrClass.createParameterDeclarations() {
|
||||
assert(thisReceiver == null)
|
||||
|
||||
@@ -601,7 +603,7 @@ fun createStaticFunctionWithReceivers(
|
||||
|
||||
typeParameters.forEach { it.superTypes.replaceAll { remap(it) } }
|
||||
|
||||
annotations.addAll(oldFunction.annotations)
|
||||
annotations = oldFunction.annotations
|
||||
|
||||
var offset = 0
|
||||
val dispatchReceiver = oldFunction.dispatchReceiverParameter?.copyTo(
|
||||
@@ -618,7 +620,7 @@ fun createStaticFunctionWithReceivers(
|
||||
origin = IrDeclarationOrigin.MOVED_EXTENSION_RECEIVER,
|
||||
remapTypeMap = typeParameterMap
|
||||
)
|
||||
valueParameters.addAll(listOfNotNull(dispatchReceiver, extensionReceiver) +
|
||||
valueParameters = listOfNotNull(dispatchReceiver, extensionReceiver) +
|
||||
oldFunction.valueParameters.map {
|
||||
it.copyTo(
|
||||
this,
|
||||
@@ -626,7 +628,6 @@ fun createStaticFunctionWithReceivers(
|
||||
remapTypeMap = typeParameterMap
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
if (copyMetadata) metadata = oldFunction.metadata
|
||||
}
|
||||
@@ -670,10 +671,11 @@ private fun IrSimpleFunction.copyAndRenameConflictingTypeParametersFrom(
|
||||
it.parent = this
|
||||
}
|
||||
|
||||
typeParameters.add(newTypeParameter)
|
||||
newParameters.add(newTypeParameter)
|
||||
}
|
||||
|
||||
typeParameters = typeParameters + newParameters
|
||||
|
||||
return newParameters
|
||||
}
|
||||
|
||||
|
||||
@@ -38,7 +38,9 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val context: C) : FileLoweringPass {
|
||||
abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val context: C) : BodyLoweringPass {
|
||||
|
||||
private var IrFunction.coroutineConstructor by context.mapping.suspendFunctionToCoroutineConstructor
|
||||
|
||||
protected object STATEMENT_ORIGIN_COROUTINE_IMPL : IrStatementOriginImpl("COROUTINE_IMPL")
|
||||
protected object DECLARATION_ORIGIN_COROUTINE_IMPL : IrDeclarationOriginImpl("COROUTINE_IMPL")
|
||||
@@ -61,53 +63,38 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
delegatingCall
|
||||
|
||||
private val builtCoroutines = mutableMapOf<IrFunction, BuiltCoroutine>()
|
||||
private val suspendLambdas = mutableMapOf<IrFunction, IrFunctionReference>()
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
markSuspendLambdas(irFile)
|
||||
buildCoroutines(irFile)
|
||||
transformCallableReferencesToSuspendLambdas(irFile)
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
transformCallableReferencesToSuspendLambdas(irBody)
|
||||
|
||||
if (container.isLambda) return
|
||||
|
||||
tryTransformSuspendFunction(container, null)
|
||||
}
|
||||
|
||||
private fun buildCoroutines(irFile: IrFile) {
|
||||
irFile.transformDeclarationsFlat(::tryTransformSuspendFunction)
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
declaration.transformDeclarationsFlat(::tryTransformSuspendFunction)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
|
||||
// Suppress since it is used in native
|
||||
@Suppress("MemberVisibilityCanBePrivate")
|
||||
protected fun IrCall.isReturnIfSuspendedCall() =
|
||||
symbol.owner.run { fqNameWhenAvailable == context.internalPackageFqn.child(Name.identifier("returnIfSuspended")) }
|
||||
|
||||
private fun tryTransformSuspendFunction(element: IrElement) =
|
||||
if (element is IrSimpleFunction && element.isSuspend && element.modality != Modality.ABSTRACT)
|
||||
transformSuspendFunction(element, suspendLambdas[element])
|
||||
else null
|
||||
private fun tryTransformSuspendFunction(element: IrElement, functionReference: IrFunctionReference?) {
|
||||
if (element is IrSimpleFunction && element.isSuspend && element.modality != Modality.ABSTRACT) {
|
||||
|
||||
private fun markSuspendLambdas(irElement: IrElement) {
|
||||
irElement.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
transformCallableReferencesToSuspendLambdas(element)
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||
expression.acceptChildrenVoid(this)
|
||||
transformSuspendFunction(element, functionReference)?.let { result ->
|
||||
result.forEach { declaration ->
|
||||
if (declaration !== element) {
|
||||
// TODO Use proper means to emerge declarations
|
||||
element.file.declarations += declaration
|
||||
declaration.parent = element.file
|
||||
|
||||
if (expression.isSuspend) {
|
||||
suspendLambdas[expression.symbol.owner] = expression
|
||||
// TODO investigate IrJsCodegenBoxTestGenerated$Coroutines$ControlFlow.testBreakFinally_1_3
|
||||
declaration.patchDeclarationParents(declaration.parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformCallableReferencesToSuspendLambdas(irElement: IrElement) {
|
||||
@@ -118,16 +105,33 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
|
||||
if (!expression.isSuspend)
|
||||
return expression
|
||||
val coroutine = builtCoroutines[expression.symbol.owner]
|
||||
?: throw Error("Non-local callable reference to suspend lambda: $expression")
|
||||
val constructorParameters = coroutine.coroutineConstructor.valueParameters
|
||||
|
||||
val coroutineConstructor = if (expression.symbol.owner.isLambda) {
|
||||
if (expression.symbol.owner in builtCoroutines) {
|
||||
error("Lambda revisiting?")
|
||||
}
|
||||
|
||||
tryTransformSuspendFunction(expression.symbol.owner, expression)
|
||||
|
||||
builtCoroutines[expression.symbol.owner]?.coroutineConstructor
|
||||
?: throw Error("Non-local callable reference to suspend lambda: $expression")
|
||||
} else {
|
||||
expression.symbol.owner.coroutineConstructor ?: run {
|
||||
|
||||
tryTransformSuspendFunction(expression.symbol.owner, expression)
|
||||
|
||||
builtCoroutines[expression.symbol.owner]!!.coroutineConstructor
|
||||
}
|
||||
}
|
||||
|
||||
val constructorParameters = coroutineConstructor.valueParameters
|
||||
val expressionArguments = expression.getArguments().map { it.second }
|
||||
assert(constructorParameters.size == expressionArguments.size) {
|
||||
"Inconsistency between callable reference to suspend lambda and the corresponding coroutine"
|
||||
}
|
||||
val irBuilder = context.createIrBuilder(expression.symbol, expression.startOffset, expression.endOffset)
|
||||
irBuilder.run {
|
||||
return irCall(coroutine.coroutineConstructor.symbol).apply {
|
||||
return irCall(coroutineConstructor.symbol).apply {
|
||||
expressionArguments.forEachIndexed { index, argument ->
|
||||
putValueArgument(index, argument)
|
||||
}
|
||||
@@ -144,7 +148,7 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
}
|
||||
|
||||
private fun transformSuspendFunction(irFunction: IrSimpleFunction, functionReference: IrFunctionReference?) =
|
||||
when (val suspendFunctionKind = getSuspendFunctionKind(irFunction)) {
|
||||
when (val suspendFunctionKind = getSuspendFunctionKind(irFunction, functionReference)) {
|
||||
is SuspendFunctionKind.NO_SUSPEND_CALLS -> {
|
||||
null // No suspend function calls - just an ordinary function.
|
||||
}
|
||||
@@ -156,15 +160,15 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
|
||||
is SuspendFunctionKind.NEEDS_STATE_MACHINE -> {
|
||||
val coroutine = buildCoroutine(irFunction, functionReference) // Coroutine implementation.
|
||||
if (irFunction in suspendLambdas) // Suspend lambdas are called through factory method <create>,
|
||||
if (irFunction.isLambda) // Suspend lambdas are called through factory method <create>,
|
||||
listOf(coroutine) // thus we can eliminate original body.
|
||||
else
|
||||
listOf<IrDeclaration>(coroutine, irFunction)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuspendFunctionKind(irFunction: IrSimpleFunction): SuspendFunctionKind {
|
||||
if (irFunction in suspendLambdas)
|
||||
private fun getSuspendFunctionKind(irFunction: IrSimpleFunction, functionReference: IrFunctionReference?): SuspendFunctionKind {
|
||||
if (irFunction.isLambda || functionReference != null)
|
||||
return SuspendFunctionKind.NEEDS_STATE_MACHINE // Suspend lambdas always need coroutine implementation.
|
||||
|
||||
val body = irFunction.body ?: return SuspendFunctionKind.NO_SUSPEND_CALLS
|
||||
@@ -237,29 +241,33 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
private fun buildCoroutine(irFunction: IrSimpleFunction, functionReference: IrFunctionReference?): IrClass {
|
||||
val coroutine = CoroutineBuilder(irFunction, functionReference).build()
|
||||
builtCoroutines[irFunction] = coroutine
|
||||
irFunction.coroutineConstructor = coroutine.coroutineConstructor
|
||||
|
||||
if (functionReference == null) {
|
||||
if (!irFunction.isLambda && functionReference == null) {
|
||||
// It is not a lambda - replace original function with a call to constructor of the built coroutine.
|
||||
val irBuilder = context.createIrBuilder(irFunction.symbol, irFunction.startOffset, irFunction.endOffset)
|
||||
irFunction.body = irBuilder.irBlockBody(irFunction) {
|
||||
val constructor = coroutine.coroutineConstructor
|
||||
generateCoroutineStart(coroutine.stateMachineFunction,
|
||||
irCallConstructor(constructor.symbol, irFunction.typeParameters.map {
|
||||
IrSimpleTypeImpl(it.symbol, true, emptyList(), emptyList())
|
||||
}).apply {
|
||||
val functionParameters = irFunction.explicitParameters
|
||||
functionParameters.forEachIndexed { index, argument ->
|
||||
putValueArgument(index, irGet(argument))
|
||||
}
|
||||
putValueArgument(
|
||||
functionParameters.size,
|
||||
irCall(
|
||||
getContinuationSymbol,
|
||||
getContinuationSymbol.owner.returnType,
|
||||
listOf(irFunction.returnType)
|
||||
(irFunction.body as IrBlockBody).statements.let {
|
||||
it.clear()
|
||||
it += irBuilder.irBlockBody(irFunction) {
|
||||
val constructor = coroutine.coroutineConstructor
|
||||
generateCoroutineStart(coroutine.stateMachineFunction,
|
||||
irCallConstructor(constructor.symbol, irFunction.typeParameters.map {
|
||||
IrSimpleTypeImpl(it.symbol, true, emptyList(), emptyList())
|
||||
}).apply {
|
||||
val functionParameters = irFunction.explicitParameters
|
||||
functionParameters.forEachIndexed { index, argument ->
|
||||
putValueArgument(index, irGet(argument))
|
||||
}
|
||||
putValueArgument(
|
||||
functionParameters.size,
|
||||
irCall(
|
||||
getContinuationSymbol,
|
||||
getContinuationSymbol.owner.returnType,
|
||||
listOf(irFunction.returnType)
|
||||
)
|
||||
)
|
||||
)
|
||||
})
|
||||
})
|
||||
}.statements
|
||||
}
|
||||
}
|
||||
|
||||
@@ -300,7 +308,7 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
d.bind(this)
|
||||
parent = irFunction.parent
|
||||
createParameterDeclarations()
|
||||
irFunction.typeParameters.mapTo(typeParameters) { typeParam ->
|
||||
typeParameters = irFunction.typeParameters.map { typeParam ->
|
||||
typeParam.copyToWithoutSuperTypes(this).apply { superTypes += typeParam.superTypes }
|
||||
}
|
||||
}
|
||||
@@ -403,13 +411,15 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
coroutineClass.declarations += this
|
||||
coroutineConstructors += this
|
||||
|
||||
functionParameters.mapIndexedTo(valueParameters) { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
valueParameters = functionParameters.mapIndexed { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index, defaultValue = null)
|
||||
}
|
||||
val continuationParameter = coroutineBaseClassConstructor.valueParameters[0]
|
||||
valueParameters += continuationParameter.copyTo(
|
||||
this, DECLARATION_ORIGIN_COROUTINE_IMPL,
|
||||
index = valueParameters.size, type = continuationType
|
||||
index = valueParameters.size,
|
||||
type = continuationType,
|
||||
defaultValue = null
|
||||
)
|
||||
|
||||
val irBuilder = context.createIrBuilder(symbol, startOffset, endOffset)
|
||||
@@ -449,7 +459,7 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
coroutineClass.declarations += this
|
||||
coroutineConstructors += this
|
||||
|
||||
boundParams.mapIndexedTo(valueParameters) { index, parameter ->
|
||||
valueParameters = boundParams.mapIndexed { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
}
|
||||
|
||||
@@ -498,15 +508,14 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
parent = coroutineClass
|
||||
coroutineClass.declarations += this
|
||||
|
||||
irFunction.typeParameters.mapTo(typeParameters) { parameter ->
|
||||
typeParameters = irFunction.typeParameters.map { parameter ->
|
||||
parameter.copyToWithoutSuperTypes(this, origin = DECLARATION_ORIGIN_COROUTINE_IMPL)
|
||||
.apply { superTypes += parameter.superTypes }
|
||||
}
|
||||
|
||||
(unboundArgs + create1CompletionParameter)
|
||||
.mapIndexedTo(valueParameters) { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
}
|
||||
valueParameters = (unboundArgs + create1CompletionParameter).mapIndexed { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
}
|
||||
|
||||
this.createDispatchReceiverParameter()
|
||||
|
||||
@@ -566,15 +575,15 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
parent = coroutineClass
|
||||
coroutineClass.declarations += this
|
||||
|
||||
irFunction.typeParameters.mapTo(typeParameters) { parameter ->
|
||||
typeParameters = irFunction.typeParameters.map { parameter ->
|
||||
parameter.copyToWithoutSuperTypes(this, origin = DECLARATION_ORIGIN_COROUTINE_IMPL)
|
||||
.apply { superTypes += parameter.superTypes }
|
||||
}
|
||||
|
||||
createFunction.valueParameters
|
||||
valueParameters = createFunction.valueParameters
|
||||
// Skip completion - invoke() already has it implicitly as a suspend function.
|
||||
.take(createFunction.valueParameters.size - 1)
|
||||
.mapIndexedTo(valueParameters) { index, parameter ->
|
||||
.mapIndexed { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
}
|
||||
|
||||
@@ -626,12 +635,12 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
parent = coroutineClass
|
||||
coroutineClass.declarations += this
|
||||
|
||||
stateMachineFunction.typeParameters.mapTo(typeParameters) { parameter ->
|
||||
typeParameters = stateMachineFunction.typeParameters.map { parameter ->
|
||||
parameter.copyToWithoutSuperTypes(this, origin = DECLARATION_ORIGIN_COROUTINE_IMPL)
|
||||
.apply { superTypes += parameter.superTypes }
|
||||
}
|
||||
|
||||
stateMachineFunction.valueParameters.mapIndexedTo(valueParameters) { index, parameter ->
|
||||
valueParameters = stateMachineFunction.valueParameters.mapIndexed { index, parameter ->
|
||||
parameter.copyTo(this, DECLARATION_ORIGIN_COROUTINE_IMPL, index)
|
||||
}
|
||||
|
||||
@@ -696,3 +705,13 @@ abstract class AbstractSuspendFunctionsLowering<C : CommonBackendContext>(val co
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IrDeclaration.isLambda
|
||||
get() = origin == IrDeclarationOrigin.LOCAL_FUNCTION_FOR_LAMBDA
|
||||
|
||||
class RemoveSuspendLambdas() : DeclarationTransformer {
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return if (declaration.isLambda && declaration is IrFunction && declaration.isSuspend) emptyList() else null
|
||||
}
|
||||
}
|
||||
@@ -5,31 +5,38 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.asSimpleLambda
|
||||
import org.jetbrains.kotlin.backend.common.ir.inline
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.copyTypeArgumentsFrom
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
import org.jetbrains.kotlin.ir.types.getClass
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.constructors
|
||||
import org.jetbrains.kotlin.ir.util.functions
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTransformerVoidWithContext(), FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTransformerVoidWithContext(), BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(ArrayConstructorTransformer(context, container as IrSymbolOwner))
|
||||
}
|
||||
}
|
||||
|
||||
private class ArrayConstructorTransformer(
|
||||
val context: CommonBackendContext,
|
||||
val container: IrSymbolOwner
|
||||
) : IrElementTransformerVoidWithContext() {
|
||||
|
||||
// Array(size, init) -> Array(size)
|
||||
private fun arrayInlineToSizeConstructor(irConstructor: IrConstructor): IrFunctionSymbol? {
|
||||
@@ -64,7 +71,7 @@ class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTra
|
||||
// (and similar for primitive arrays)
|
||||
val size = expression.getValueArgument(0)!!.transform(this, null)
|
||||
val invokable = expression.getValueArgument(1)!!.transform(this, null)
|
||||
val scope = currentScope!!.scope
|
||||
val scope = (currentScope ?: createScope(container)).scope
|
||||
return context.createIrBuilder(scope.scopeOwnerSymbol).irBlock(expression.startOffset, expression.endOffset) {
|
||||
val index = irTemporaryVar(irInt(0))
|
||||
val sizeVar = irTemporary(size)
|
||||
@@ -83,7 +90,7 @@ class ArrayConstructorLowering(val context: CommonBackendContext) : IrElementTra
|
||||
}
|
||||
body = irBlock {
|
||||
val tempIndex = irTemporary(irGet(index))
|
||||
val value = lambda?.inline(parent, listOf(tempIndex)) ?: irCallOp(
|
||||
val value = lambda?.inline(parent, listOf(tempIndex))?.patchDeclarationParents(scope.getLocalDeclarationParent()) ?: irCallOp(
|
||||
invoke.symbol,
|
||||
invoke.returnType,
|
||||
irGet(invokableVar!!),
|
||||
|
||||
@@ -17,9 +17,6 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ir.ir2string
|
||||
import org.jetbrains.kotlin.backend.common.peek
|
||||
import org.jetbrains.kotlin.backend.common.pop
|
||||
import org.jetbrains.kotlin.backend.common.push
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -29,19 +26,21 @@ import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrSimpleType
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.isLocal
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import kotlin.collections.set
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
data class Closure(val capturedValues: List<IrValueSymbol>, val capturedTypeParameters: List<IrTypeParameter>)
|
||||
|
||||
class ClosureAnnotator(irFile: IrFile) {
|
||||
class ClosureAnnotator(body: IrBody, declaration: IrDeclaration) {
|
||||
private val closureBuilders = mutableMapOf<IrDeclaration, ClosureBuilder>()
|
||||
|
||||
init {
|
||||
// Collect all closures for classes and functions. Collect call graph
|
||||
irFile.acceptChildrenVoid(ClosureCollectorVisitor())
|
||||
if (declaration is IrSimpleFunction && declaration.name.asString() == "arrayIterator") {
|
||||
1
|
||||
}
|
||||
body.accept(ClosureCollectorVisitor(), declaration.closureBuilderOrNull ?: declaration.parentClosureBuilder)
|
||||
}
|
||||
|
||||
fun getFunctionClosure(declaration: IrFunction) = getClosure(declaration)
|
||||
@@ -126,129 +125,150 @@ class ClosureAnnotator(irFile: IrFile) {
|
||||
}
|
||||
}
|
||||
|
||||
private inner class ClosureCollectorVisitor : IrElementVisitorVoid {
|
||||
|
||||
val closuresStack = mutableListOf<ClosureBuilder>()
|
||||
|
||||
fun includeInParent(builder: ClosureBuilder) {
|
||||
// We don't include functions or classes in a parent function when they are declared.
|
||||
// Instead we will include them when are is used (use = call for a function or constructor call for a class).
|
||||
val parentBuilder = closuresStack.peek()
|
||||
if (parentBuilder != null && parentBuilder.owner !is IrFunction) {
|
||||
parentBuilder.include(builder)
|
||||
}
|
||||
private fun includeInParent(builder: ClosureBuilder) {
|
||||
// We don't include functions or classes in a parent function when they are declared.
|
||||
// Instead we will include them when are is used (use = call for a function or constructor call for a class).
|
||||
val parentBuilder = builder.owner.parentClosureBuilder
|
||||
if (parentBuilder != null && parentBuilder.owner !is IrFunction) {
|
||||
parentBuilder.include(builder)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
val closureBuilder = ClosureBuilder(declaration)
|
||||
closureBuilders[declaration] = closureBuilder
|
||||
private val IrClass.closureBuilder: ClosureBuilder
|
||||
get() = closureBuilders.getOrPut(this) {
|
||||
val closureBuilder = ClosureBuilder(this)
|
||||
|
||||
collectPotentiallyCapturedTypeParameters(closureBuilder)
|
||||
|
||||
closureBuilder.declareVariable(declaration.thisReceiver)
|
||||
if (declaration.isInner) {
|
||||
closureBuilder.declareVariable((declaration.parent as IrClass).thisReceiver)
|
||||
closureBuilder.declareVariable(this.thisReceiver)
|
||||
if (this.isInner) {
|
||||
closureBuilder.declareVariable((this.parent as IrClass).thisReceiver)
|
||||
includeInParent(closureBuilder)
|
||||
}
|
||||
|
||||
declaration.declarations.firstOrNull { it is IrConstructor && it.isPrimary }?.let {
|
||||
this.declarations.firstOrNull { it is IrConstructor && it.isPrimary }?.let {
|
||||
val constructor = it as IrConstructor
|
||||
constructor.valueParameters.forEach { v -> closureBuilder.declareVariable(v) }
|
||||
}
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
closuresStack.pop()
|
||||
closureBuilder
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
val closureBuilder = ClosureBuilder(declaration)
|
||||
closureBuilders[declaration] = closureBuilder
|
||||
private val IrFunction.closureBuilder: ClosureBuilder
|
||||
get() = closureBuilders.getOrPut(this) {
|
||||
val closureBuilder = ClosureBuilder(this)
|
||||
|
||||
collectPotentiallyCapturedTypeParameters(closureBuilder)
|
||||
|
||||
declaration.valueParameters.forEach { closureBuilder.declareVariable(it) }
|
||||
closureBuilder.declareVariable(declaration.dispatchReceiverParameter)
|
||||
closureBuilder.declareVariable(declaration.extensionReceiverParameter)
|
||||
this.valueParameters.forEach { closureBuilder.declareVariable(it) }
|
||||
closureBuilder.declareVariable(this.dispatchReceiverParameter)
|
||||
closureBuilder.declareVariable(this.extensionReceiverParameter)
|
||||
|
||||
if (declaration is IrConstructor) {
|
||||
val constructedClass = (declaration.parent as IrClass)
|
||||
if (this is IrConstructor) {
|
||||
val constructedClass = (this.parent as IrClass)
|
||||
closureBuilder.declareVariable(constructedClass.thisReceiver)
|
||||
|
||||
// Include closure of the class in the constructor closure.
|
||||
val classBuilder = closuresStack.peek()
|
||||
classBuilder?.let {
|
||||
assert(classBuilder.owner == constructedClass)
|
||||
closureBuilder.include(classBuilder)
|
||||
}
|
||||
val classBuilder = constructedClass.closureBuilder
|
||||
closureBuilder.include(classBuilder)
|
||||
}
|
||||
|
||||
closuresStack.push(closureBuilder)
|
||||
declaration.acceptChildrenVoid(this)
|
||||
closuresStack.pop()
|
||||
closureBuilder
|
||||
}
|
||||
|
||||
private fun collectPotentiallyCapturedTypeParameters(closureBuilder: ClosureBuilder) {
|
||||
|
||||
fun ClosureBuilder.doCollect() {
|
||||
if (owner !is IrClass) {
|
||||
(owner as? IrTypeParametersContainer)?.let { container ->
|
||||
for (tp in container.typeParameters) {
|
||||
closureBuilder.addPotentiallyCapturedTypeParameter(tp)
|
||||
}
|
||||
}
|
||||
|
||||
owner.parentClosureBuilder?.doCollect()
|
||||
}
|
||||
}
|
||||
|
||||
closureBuilder.owner.parentClosureBuilder?.doCollect()
|
||||
}
|
||||
|
||||
private val IrDeclaration.parentClosureBuilder: ClosureBuilder?
|
||||
get() = when (val p = parent) {
|
||||
is IrClass -> p.closureBuilder
|
||||
is IrFunction -> p.closureBuilder
|
||||
is IrDeclaration -> p.parentClosureBuilder
|
||||
else -> null
|
||||
}
|
||||
|
||||
private val IrDeclaration.closureBuilderOrNull: ClosureBuilder?
|
||||
get() = when (this) {
|
||||
is IrClass -> closureBuilder
|
||||
is IrFunction -> closureBuilder
|
||||
else -> null
|
||||
}
|
||||
|
||||
private inner class ClosureCollectorVisitor() : IrElementVisitor<Unit, ClosureBuilder?> {
|
||||
|
||||
override fun visitElement(element: IrElement, data: ClosureBuilder?) {
|
||||
element.acceptChildren(this, data)
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: ClosureBuilder?) {
|
||||
declaration.acceptChildren(this, declaration.closureBuilder)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction, data: ClosureBuilder?) {
|
||||
val closureBuilder = declaration.closureBuilder
|
||||
|
||||
declaration.acceptChildren(this, closureBuilder)
|
||||
|
||||
includeInParent(closureBuilder)
|
||||
}
|
||||
|
||||
override fun visitVariableAccess(expression: IrValueAccessExpression) {
|
||||
closuresStack.peek()?.seeVariable(expression.symbol)
|
||||
super.visitVariableAccess(expression)
|
||||
override fun visitValueAccess(expression: IrValueAccessExpression, data: ClosureBuilder?) {
|
||||
data?.seeVariable(expression.symbol)
|
||||
super.visitValueAccess(expression, data)
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable) {
|
||||
closuresStack.peek()?.declareVariable(declaration)
|
||||
super.visitVariable(declaration)
|
||||
override fun visitVariable(declaration: IrVariable, data: ClosureBuilder?) {
|
||||
data?.declareVariable(declaration)
|
||||
super.visitVariable(declaration, data)
|
||||
}
|
||||
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression) {
|
||||
super.visitFunctionAccess(expression)
|
||||
processMemberAccess(expression.symbol.owner)
|
||||
override fun visitFunctionAccess(expression: IrFunctionAccessExpression, data: ClosureBuilder?) {
|
||||
super.visitFunctionAccess(expression, data)
|
||||
processMemberAccess(expression.symbol.owner, data)
|
||||
}
|
||||
|
||||
override fun visitFunctionReference(expression: IrFunctionReference) {
|
||||
super.visitFunctionReference(expression)
|
||||
processMemberAccess(expression.symbol.owner)
|
||||
override fun visitFunctionReference(expression: IrFunctionReference, data: ClosureBuilder?) {
|
||||
super.visitFunctionReference(expression, data)
|
||||
processMemberAccess(expression.symbol.owner, data)
|
||||
}
|
||||
|
||||
override fun visitPropertyReference(expression: IrPropertyReference) {
|
||||
super.visitPropertyReference(expression)
|
||||
expression.getter?.let { processMemberAccess(it.owner) }
|
||||
expression.setter?.let { processMemberAccess(it.owner) }
|
||||
override fun visitPropertyReference(expression: IrPropertyReference, data: ClosureBuilder?) {
|
||||
super.visitPropertyReference(expression, data)
|
||||
expression.getter?.let { processMemberAccess(it.owner, data) }
|
||||
expression.setter?.let { processMemberAccess(it.owner, data) }
|
||||
}
|
||||
|
||||
override fun visitExpression(expression: IrExpression) {
|
||||
super.visitExpression(expression)
|
||||
val typeParameterContainerScopeBuilder = closuresStack.peek()?.let {
|
||||
if (it.owner is IrConstructor) {
|
||||
closuresStack[closuresStack.size - 2]
|
||||
} else it
|
||||
override fun visitExpression(expression: IrExpression, data: ClosureBuilder?) {
|
||||
super.visitExpression(expression, data)
|
||||
val typeParameterContainerScopeBuilder = data?.let {
|
||||
(it.owner as? IrConstructor)?.closureBuilder ?: it
|
||||
}
|
||||
typeParameterContainerScopeBuilder?.seeType(expression.type)
|
||||
}
|
||||
|
||||
private fun processMemberAccess(declaration: IrDeclaration) {
|
||||
private fun processMemberAccess(declaration: IrDeclaration, parentClosure: ClosureBuilder?) {
|
||||
if (declaration.isLocal) {
|
||||
if (declaration is IrSimpleFunction && declaration.visibility != Visibilities.LOCAL) {
|
||||
return
|
||||
}
|
||||
|
||||
val builder = closureBuilders[declaration]
|
||||
val builder = declaration.closureBuilderOrNull
|
||||
builder?.let {
|
||||
closuresStack.peek()?.include(builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun collectPotentiallyCapturedTypeParameters(closureBuilder: ClosureBuilder) {
|
||||
closuresStack.takeLastWhile { it.owner !is IrClass }.forEach {
|
||||
(it.owner as? IrTypeParametersContainer)?.let { container ->
|
||||
for (tp in container.typeParameters) {
|
||||
closureBuilder.addPotentiallyCapturedTypeParameter(tp)
|
||||
}
|
||||
parentClosure?.include(builder)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,22 +36,26 @@ import org.jetbrains.kotlin.name.Name
|
||||
open class DefaultArgumentStubGenerator(
|
||||
open val context: CommonBackendContext,
|
||||
private val skipInlineMethods: Boolean = true,
|
||||
private val skipExternalMethods: Boolean = false
|
||||
) : DeclarationContainerLoweringPass {
|
||||
private val skipExternalMethods: Boolean = false,
|
||||
private val forceSetOverrideSymbols: Boolean = true
|
||||
) : DeclarationTransformer {
|
||||
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.transformDeclarationsFlat { memberDeclaration ->
|
||||
if (memberDeclaration is IrFunction)
|
||||
lower(memberDeclaration)
|
||||
else
|
||||
null
|
||||
}
|
||||
override fun lower(irFile: IrFile) {
|
||||
runPostfix(true).toFileLoweringPass().lower(irFile)
|
||||
}
|
||||
|
||||
private fun lower(irFunction: IrFunction): List<IrFunction> {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrFunction) {
|
||||
return lower(declaration)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun lower(irFunction: IrFunction): List<IrFunction>? {
|
||||
val visibility = defaultArgumentStubVisibility(irFunction)
|
||||
val newIrFunction = irFunction.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods, visibility)
|
||||
?: return listOf(irFunction)
|
||||
val newIrFunction = irFunction.generateDefaultsFunction(context, skipInlineMethods, skipExternalMethods, forceSetOverrideSymbols, visibility)
|
||||
?: return null
|
||||
if (newIrFunction.origin == IrDeclarationOrigin.FAKE_OVERRIDE) {
|
||||
return listOf(irFunction, newIrFunction)
|
||||
}
|
||||
@@ -59,80 +63,77 @@ open class DefaultArgumentStubGenerator(
|
||||
log { "$irFunction -> $newIrFunction" }
|
||||
val builder = context.createIrBuilder(newIrFunction.symbol)
|
||||
|
||||
newIrFunction.body = builder.irBlockBody(newIrFunction) {
|
||||
val params = mutableListOf<IrValueDeclaration>()
|
||||
val variables = mutableMapOf<IrValueDeclaration, IrValueDeclaration>()
|
||||
newIrFunction.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += builder.irBlockBody(newIrFunction) {
|
||||
val params = mutableListOf<IrValueDeclaration>()
|
||||
val variables = mutableMapOf<IrValueDeclaration, IrValueDeclaration>()
|
||||
|
||||
irFunction.dispatchReceiverParameter?.let {
|
||||
variables[it] = newIrFunction.dispatchReceiverParameter!!
|
||||
}
|
||||
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
variables[it] = newIrFunction.extensionReceiverParameter!!
|
||||
}
|
||||
|
||||
// In order to deal with forward references in default value lambdas,
|
||||
// accesses to the parameter before it has been determined if there is
|
||||
// a default value or not is redirected to the actual parameter of the
|
||||
// $default function. This is to ensure that examples such as:
|
||||
//
|
||||
// fun f(f1: () -> String = { f2() },
|
||||
// f2: () -> String = { "OK" }) = f1()
|
||||
//
|
||||
// works correctly so that `f() { "OK" }` returns "OK" and
|
||||
// `f()` throws a NullPointerException.
|
||||
irFunction.valueParameters.associateWithTo(variables) {
|
||||
newIrFunction.valueParameters[it.index]
|
||||
}
|
||||
|
||||
var sourceParameterIndex = -1
|
||||
for (valueParameter in irFunction.valueParameters) {
|
||||
if (!valueParameter.isMovedReceiver()) {
|
||||
++sourceParameterIndex
|
||||
irFunction.dispatchReceiverParameter?.let {
|
||||
variables[it] = newIrFunction.dispatchReceiverParameter!!
|
||||
}
|
||||
val parameter = newIrFunction.valueParameters[valueParameter.index]
|
||||
val remapped = if (valueParameter.defaultValue != null) {
|
||||
val mask = irGet(newIrFunction.valueParameters[irFunction.valueParameters.size + valueParameter.index / 32])
|
||||
val bit = irInt(1 shl (sourceParameterIndex % 32))
|
||||
val defaultFlag = irCallOp(this@DefaultArgumentStubGenerator.context.ir.symbols.intAnd, context.irBuiltIns.intType, mask, bit)
|
||||
|
||||
val expressionBody = valueParameter.defaultValue!!
|
||||
expressionBody.patchDeclarationParents(newIrFunction)
|
||||
expressionBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
log { "GetValue: ${expression.symbol.owner}" }
|
||||
val valueSymbol = variables[expression.symbol.owner] ?: return expression
|
||||
return irGet(valueSymbol)
|
||||
}
|
||||
})
|
||||
|
||||
selectArgumentOrDefault(defaultFlag, parameter, expressionBody.expression)
|
||||
} else {
|
||||
parameter
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
variables[it] = newIrFunction.extensionReceiverParameter!!
|
||||
}
|
||||
params.add(remapped)
|
||||
variables[valueParameter] = remapped
|
||||
}
|
||||
|
||||
when (irFunction) {
|
||||
is IrConstructor -> +irDelegatingConstructorCall(irFunction).apply {
|
||||
passTypeArgumentsFrom(newIrFunction.parentAsClass)
|
||||
// This is for Kotlin/Native, which differs from the other backends in that constructors
|
||||
// apparently do have dispatch receivers (though *probably* not type arguments, but copy
|
||||
// those as well just in case):
|
||||
passTypeArgumentsFrom(newIrFunction, offset = newIrFunction.parentAsClass.typeParameters.size)
|
||||
dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) }
|
||||
params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
|
||||
// In order to deal with forward references in default value lambdas,
|
||||
// accesses to the parameter before it has been determined if there is
|
||||
// a default value or not is redirected to the actual parameter of the
|
||||
// $default function. This is to ensure that examples such as:
|
||||
//
|
||||
// fun f(f1: () -> String = { f2() },
|
||||
// f2: () -> String = { "OK" }) = f1()
|
||||
//
|
||||
// works correctly so that `f() { "OK" }` returns "OK" and
|
||||
// `f()` throws a NullPointerException.
|
||||
irFunction.valueParameters.associateWithTo(variables) {
|
||||
newIrFunction.valueParameters[it.index]
|
||||
}
|
||||
is IrSimpleFunction -> +irReturn(dispatchToImplementation(irFunction, newIrFunction, params))
|
||||
else -> error("Unknown function declaration")
|
||||
}
|
||||
}
|
||||
// Remove default argument initializers.
|
||||
irFunction.valueParameters.forEach {
|
||||
if (it.defaultValue != null) {
|
||||
it.defaultValue = IrExpressionBodyImpl(IrErrorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, it.type, "Default Stub"))
|
||||
}
|
||||
|
||||
var sourceParameterIndex = -1
|
||||
for (valueParameter in irFunction.valueParameters) {
|
||||
if (!valueParameter.isMovedReceiver()) {
|
||||
++sourceParameterIndex
|
||||
}
|
||||
val parameter = newIrFunction.valueParameters[valueParameter.index]
|
||||
val remapped = if (valueParameter.defaultValue != null) {
|
||||
val mask = irGet(newIrFunction.valueParameters[irFunction.valueParameters.size + valueParameter.index / 32])
|
||||
val bit = irInt(1 shl (sourceParameterIndex % 32))
|
||||
val defaultFlag =
|
||||
irCallOp(this@DefaultArgumentStubGenerator.context.ir.symbols.intAnd, context.irBuiltIns.intType, mask, bit)
|
||||
|
||||
val expressionBody = valueParameter.defaultValue!!
|
||||
expressionBody.patchDeclarationParents(newIrFunction)
|
||||
expressionBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
log { "GetValue: ${expression.symbol.owner}" }
|
||||
val valueSymbol = variables[expression.symbol.owner] ?: return expression
|
||||
return irGet(valueSymbol)
|
||||
}
|
||||
})
|
||||
|
||||
selectArgumentOrDefault(defaultFlag, parameter, expressionBody.expression)
|
||||
} else {
|
||||
parameter
|
||||
}
|
||||
params.add(remapped)
|
||||
variables[valueParameter] = remapped
|
||||
}
|
||||
|
||||
when (irFunction) {
|
||||
is IrConstructor -> +irDelegatingConstructorCall(irFunction).apply {
|
||||
passTypeArgumentsFrom(newIrFunction.parentAsClass)
|
||||
// This is for Kotlin/Native, which differs from the other backends in that constructors
|
||||
// apparently do have dispatch receivers (though *probably* not type arguments, but copy
|
||||
// those as well just in case):
|
||||
passTypeArgumentsFrom(newIrFunction, offset = newIrFunction.parentAsClass.typeParameters.size)
|
||||
dispatchReceiver = newIrFunction.dispatchReceiverParameter?.let { irGet(it) }
|
||||
params.forEachIndexed { i, variable -> putValueArgument(i, irGet(variable)) }
|
||||
}
|
||||
is IrSimpleFunction -> +irReturn(dispatchToImplementation(irFunction, newIrFunction, params))
|
||||
else -> error("Unknown function declaration")
|
||||
}
|
||||
}.statements
|
||||
}
|
||||
return listOf(irFunction, newIrFunction)
|
||||
}
|
||||
@@ -195,19 +196,41 @@ open class DefaultArgumentStubGenerator(
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-REPLACER: ${msg()}" }
|
||||
}
|
||||
|
||||
private fun IrFunction.findBaseFunctionWithDefaultArguments(skipInlineMethods: Boolean, skipExternalMethods: Boolean): IrFunction? {
|
||||
|
||||
val visited = mutableSetOf<IrFunction>()
|
||||
|
||||
fun IrFunction.dfsImpl(): IrFunction? {
|
||||
visited += this
|
||||
|
||||
if (isInline && skipInlineMethods) return null
|
||||
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||
|
||||
if (this is IrSimpleFunction) {
|
||||
overriddenSymbols.forEach {
|
||||
val base = it.owner
|
||||
if (base !in visited) base.dfsImpl()?.let { return it }
|
||||
}
|
||||
}
|
||||
|
||||
if (valueParameters.any { it.defaultValue != null }) return this
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return dfsImpl()
|
||||
}
|
||||
|
||||
val DEFAULT_DISPATCH_CALL = object : IrStatementOriginImpl("DEFAULT_DISPATCH_CALL") {}
|
||||
|
||||
open class DefaultParameterInjector(
|
||||
open val context: CommonBackendContext,
|
||||
private val skipInline: Boolean = true,
|
||||
private val skipExternalMethods: Boolean = false
|
||||
) : IrElementTransformerVoid(), BodyLoweringPass, FileLoweringPass {
|
||||
private val skipExternalMethods: Boolean = false,
|
||||
private val forceSetOverrideSymbols: Boolean = true
|
||||
) : IrElementTransformerVoid(), BodyLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun lower(irBody: IrBody) {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
@@ -279,12 +302,15 @@ open class DefaultParameterInjector(
|
||||
val endOffset = expression.endOffset
|
||||
val declaration = expression.symbol.owner
|
||||
val visibility = defaultArgumentStubVisibility(declaration)
|
||||
val stubOverride = declaration.generateDefaultsFunction(context, skipInline, skipExternalMethods, visibility) ?: return null
|
||||
// We *have* to resolve the fake override here since on the JVM, a default stub for a function implemented
|
||||
|
||||
// We *have* to find the actual function here since on the JVM, a default stub for a function implemented
|
||||
// in an interface does not leave an abstract method after being moved to DefaultImpls (see InterfaceLowering).
|
||||
// Calling the fake override on an implementation of that interface would then result in a call to a method
|
||||
// that does not actually exist as DefaultImpls is not part of the inheritance hierarchy.
|
||||
val stubFunction = if (stubOverride is IrSimpleFunction) stubOverride.resolveFakeOverride()!! else stubOverride
|
||||
val stubFunction = declaration.findBaseFunctionWithDefaultArguments(skipInline, skipExternalMethods)
|
||||
?.generateDefaultsFunction(context, skipInline, skipExternalMethods, forceSetOverrideSymbols, visibility)
|
||||
?: return null
|
||||
|
||||
log { "$declaration -> $stubFunction" }
|
||||
|
||||
val realArgumentsNumber = declaration.valueParameters.size
|
||||
@@ -335,11 +361,44 @@ open class DefaultParameterInjector(
|
||||
private fun log(msg: () -> String) = context.log { "DEFAULT-INJECTOR: ${msg()}" }
|
||||
}
|
||||
|
||||
class DefaultParameterCleaner constructor(val context: CommonBackendContext) : FunctionLoweringPass {
|
||||
override fun lower(irFunction: IrFunction) {
|
||||
if (!context.scriptMode) {
|
||||
irFunction.valueParameters.forEach { it.defaultValue = null }
|
||||
// Remove default argument initializers.
|
||||
class DefaultParameterCleaner(
|
||||
val context: CommonBackendContext,
|
||||
val replaceDefaultValuesWithStubs: Boolean = false
|
||||
) : DeclarationTransformer {
|
||||
override fun lower(irFile: IrFile) {
|
||||
runPostfix(true).toFileLoweringPass().lower(irFile)
|
||||
}
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrValueParameter && !context.scriptMode && declaration.defaultValue != null) {
|
||||
if (replaceDefaultValuesWithStubs) {
|
||||
if (context.mapping.defaultArgumentsOriginalFunction[declaration.parent as IrFunction] == null) {
|
||||
declaration.defaultValue =
|
||||
IrExpressionBodyImpl(IrErrorExpressionImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, declaration.type, "Default Stub"))
|
||||
}
|
||||
} else {
|
||||
declaration.defaultValue = null
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// Sets overriden symbols. Should be used in case `forceSetOverrideSymbols = false`
|
||||
class DefaultParameterPatchOverridenSymbolsLowering(
|
||||
val context: CommonBackendContext
|
||||
) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrSimpleFunction) {
|
||||
(context.mapping.defaultArgumentsOriginalFunction[declaration] as? IrSimpleFunction)?.run {
|
||||
declaration.overriddenSymbols += overriddenSymbols.mapNotNull {
|
||||
(context.mapping.defaultArgumentsDispatchFunction[it.owner] as? IrSimpleFunction)?.symbol
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@@ -347,27 +406,32 @@ private fun IrFunction.generateDefaultsFunction(
|
||||
context: CommonBackendContext,
|
||||
skipInlineMethods: Boolean,
|
||||
skipExternalMethods: Boolean,
|
||||
forceSetOverrideSymbols: Boolean,
|
||||
visibility: Visibility
|
||||
): IrFunction? {
|
||||
if (skipInlineMethods && isInline) return null
|
||||
if (skipExternalMethods && isExternalOrInheritedFromExternal()) return null
|
||||
context.ir.defaultParameterDeclarationsCache[this]?.let { return it }
|
||||
if (context.mapping.defaultArgumentsOriginalFunction[this] != null) return null
|
||||
context.mapping.defaultArgumentsDispatchFunction[this]?.let { return it }
|
||||
if (this is IrSimpleFunction) {
|
||||
// If this is an override of a function with default arguments, produce a fake override of a default stub.
|
||||
val overriddenStubs = overriddenSymbols.mapNotNull {
|
||||
it.owner.generateDefaultsFunction(
|
||||
context,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
visibility
|
||||
)?.symbol as IrSimpleFunctionSymbol?
|
||||
}
|
||||
if (overriddenStubs.isNotEmpty()) {
|
||||
if (overriddenSymbols.any { it.owner.findBaseFunctionWithDefaultArguments(skipInlineMethods, skipExternalMethods) != null })
|
||||
return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FAKE_OVERRIDE, visibility).also {
|
||||
(it as IrSimpleFunction).overriddenSymbols.addAll(overriddenStubs)
|
||||
context.ir.defaultParameterDeclarationsCache[this] = it
|
||||
context.mapping.defaultArgumentsDispatchFunction[this] = it
|
||||
context.mapping.defaultArgumentsOriginalFunction[it] = this
|
||||
|
||||
if (forceSetOverrideSymbols) {
|
||||
(it as IrSimpleFunction).overriddenSymbols += overriddenSymbols.mapNotNull {
|
||||
it.owner.generateDefaultsFunction(
|
||||
context,
|
||||
skipInlineMethods,
|
||||
skipExternalMethods,
|
||||
forceSetOverrideSymbols,
|
||||
visibility
|
||||
)?.symbol as IrSimpleFunctionSymbol?
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// Note: this is intentionally done *after* checking for overrides. While normally `override fun`s
|
||||
// have no default parameters, there is an exception in case of interface delegation:
|
||||
@@ -381,7 +445,8 @@ private fun IrFunction.generateDefaultsFunction(
|
||||
// binaries, it's way too late to fix it. Hence the workaround.
|
||||
if (valueParameters.any { it.defaultValue != null }) {
|
||||
return generateDefaultsFunctionImpl(context, IrDeclarationOrigin.FUNCTION_FOR_DEFAULT_PARAMETER, visibility).also {
|
||||
context.ir.defaultParameterDeclarationsCache[this] = it
|
||||
context.mapping.defaultArgumentsDispatchFunction[this] = it
|
||||
context.mapping.defaultArgumentsOriginalFunction[it] = this
|
||||
}
|
||||
}
|
||||
return null
|
||||
@@ -420,7 +485,7 @@ private fun IrFunction.generateDefaultsFunctionImpl(
|
||||
newFunction.dispatchReceiverParameter = dispatchReceiverParameter?.copyTo(newFunction)
|
||||
newFunction.extensionReceiverParameter = extensionReceiverParameter?.copyTo(newFunction)
|
||||
|
||||
valueParameters.mapTo(newFunction.valueParameters) {
|
||||
newFunction.valueParameters = valueParameters.map {
|
||||
val newType = it.type.remapTypeParameters(classIfConstructor, newFunction.classIfConstructor)
|
||||
val makeNullable = it.defaultValue != null &&
|
||||
(context.ir.unfoldInlineClassType(it.type) ?: it.type) !in context.irBuiltIns.primitiveIrTypes
|
||||
@@ -445,7 +510,7 @@ private fun IrFunction.generateDefaultsFunctionImpl(
|
||||
}
|
||||
|
||||
// TODO some annotations are needed (e.g. @JvmStatic), others need different values (e.g. @JvmName), the rest are redundant.
|
||||
annotations.mapTo(newFunction.annotations) { it.deepCopyWithSymbols() }
|
||||
newFunction.annotations = annotations.map { it.deepCopyWithSymbols() }
|
||||
return newFunction
|
||||
}
|
||||
|
||||
|
||||
@@ -6,20 +6,22 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.util.ExpectDeclarationRemover
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
/**
|
||||
* This pass removes all declarations with `isExpect == true`.
|
||||
*/
|
||||
class ExpectDeclarationsRemoveLowering(val context: BackendContext, keepOptionalAnnotations: Boolean = false) : FileLoweringPass {
|
||||
class ExpectDeclarationsRemoveLowering(context: BackendContext, keepOptionalAnnotations: Boolean = false) : DeclarationTransformer {
|
||||
|
||||
val visitor = ExpectDeclarationRemover(context.ir.symbols.externalSymbolTable, doRemove = true, keepOptionalAnnotations)
|
||||
private val remover = ExpectDeclarationRemover(
|
||||
symbolTable = context.ir.symbols.externalSymbolTable,
|
||||
doRemove = true,
|
||||
keepOptionalAnnotations = keepOptionalAnnotations
|
||||
)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptVoid(visitor)
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return remover.transformFlat(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,67 +5,81 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrStatementOriginImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
|
||||
object SYNTHESIZED_INIT_BLOCK : IrStatementOriginImpl("SYNTHESIZED_INIT_BLOCK")
|
||||
|
||||
open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context) {
|
||||
override fun lower(irClass: IrClass) {
|
||||
open class InitializersLowering(context: CommonBackendContext) : InitializersLoweringBase(context), BodyLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile, true)
|
||||
}
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container !is IrConstructor) return
|
||||
|
||||
val irClass = container.constructedClass
|
||||
|
||||
val instanceInitializerStatements = extractInitializers(irClass) {
|
||||
(it is IrField && !it.isStatic) || (it is IrAnonymousInitializer && !it.isStatic)
|
||||
}
|
||||
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
// Only transform constructors of current class.
|
||||
override fun visitClassNew(declaration: IrClass) = declaration
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) = declaration
|
||||
container.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression {
|
||||
return IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
|
||||
.deepCopyWithSymbols(container).also {
|
||||
// Handle declarations, copied from initializers
|
||||
// Otherwise local classes inside them won't get processed.
|
||||
// Yes, there are such cases - see testData/codegen/box/properties/complexPropertyInitializer.kt
|
||||
it.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall): IrExpression =
|
||||
IrBlockImpl(irClass.startOffset, irClass.endOffset, context.irBuiltIns.unitType, null, instanceInitializerStatements)
|
||||
.deepCopyWithSymbols(currentScope!!.scope.getLocalDeclarationParent())
|
||||
override fun visitConstructor(declaration: IrConstructor) {
|
||||
super.visitConstructor(declaration)
|
||||
|
||||
declaration.body?.let { lower(it, declaration) }
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
abstract class InitializersLoweringBase(open val context: CommonBackendContext) : ClassLoweringPass {
|
||||
abstract class InitializersLoweringBase(open val context: CommonBackendContext) {
|
||||
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) {
|
||||
is IrField -> handleField(irClass, it)
|
||||
is IrAnonymousInitializer -> handleAnonymousInitializer(it)
|
||||
else -> null
|
||||
}
|
||||
}.also {
|
||||
irClass.declarations.removeAll { it is IrAnonymousInitializer && filter(it) }
|
||||
}
|
||||
|
||||
protected open fun shouldEraseFieldInitializer(irField: IrField): Boolean = irField.correspondingPropertySymbol?.owner?.isConst != true
|
||||
|
||||
private fun handleField(irClass: IrClass, declaration: IrField): IrStatement? =
|
||||
declaration.initializer?.run {
|
||||
val receiver = if (!declaration.isStatic) // TODO isStaticField
|
||||
IrGetValueImpl(startOffset, endOffset, irClass.thisReceiver!!.type, irClass.thisReceiver!!.symbol)
|
||||
else
|
||||
null
|
||||
val value = if (shouldEraseFieldInitializer(declaration)) {
|
||||
declaration.initializer = null
|
||||
expression
|
||||
} else {
|
||||
expression.deepCopyWithSymbols()
|
||||
}
|
||||
IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, value, context.irBuiltIns.unitType)
|
||||
IrSetFieldImpl(startOffset, endOffset, declaration.symbol, receiver, expression, context.irBuiltIns.unitType)
|
||||
}
|
||||
|
||||
private fun handleAnonymousInitializer(declaration: IrAnonymousInitializer): IrStatement =
|
||||
@@ -73,3 +87,31 @@ abstract class InitializersLoweringBase(open val context: CommonBackendContext)
|
||||
IrBlockImpl(startOffset, endOffset, context.irBuiltIns.unitType, SYNTHESIZED_INIT_BLOCK, body.statements)
|
||||
}
|
||||
}
|
||||
|
||||
// Remove anonymous initializers and set field initializers to `null`
|
||||
class InitializersCleanupLowering(
|
||||
val context: CommonBackendContext,
|
||||
private val shouldEraseFieldInitializer: (IrField) -> Boolean = { it.correspondingPropertySymbol?.owner?.isConst != true }
|
||||
) : DeclarationTransformer {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
runPostfix(withLocalDeclarations = true).toFileLoweringPass().lower(irFile)
|
||||
}
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrAnonymousInitializer) return emptyList()
|
||||
|
||||
if (declaration is IrField && declaration.parent is IrClass) {
|
||||
if (shouldEraseFieldInitializer(declaration)) {
|
||||
declaration.initializer = null
|
||||
} else {
|
||||
declaration.initializer?.let {
|
||||
declaration.initializer =
|
||||
IrExpressionBodyImpl(it.startOffset, it.endOffset) { expression = it.expression.deepCopyWithSymbols() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -5,14 +5,17 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.ir.createStaticFunctionWithReceivers
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
@@ -21,164 +24,190 @@ import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private const val INLINE_CLASS_IMPL_SUFFIX = "-impl"
|
||||
|
||||
// TODO: Support incremental compilation
|
||||
class InlineClassLowering(val context: CommonBackendContext) {
|
||||
private val transformedFunction = if (context.scriptMode) context.transformedFunction else mutableMapOf()
|
||||
private val transformedFunction = context.mapping.inlineClassMemberToStatic
|
||||
|
||||
val inlineClassDeclarationLowering = object : ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (!irClass.isInline) return
|
||||
val inlineClassDeclarationLowering = object : DeclarationTransformer {
|
||||
|
||||
irClass.transformDeclarationsFlat { declaration ->
|
||||
when (declaration) {
|
||||
is IrConstructor -> listOf(transformConstructor(declaration))
|
||||
is IrSimpleFunction -> transformMethodFlat(declaration)
|
||||
is IrProperty -> listOf(declaration) // Getters and setters should be flattened
|
||||
is IrField -> listOf(declaration)
|
||||
is IrClass -> listOf(declaration)
|
||||
else -> error("Unexpected declaration: $declaration")
|
||||
}
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
val irClass = declaration.parent as? IrClass ?: return null
|
||||
if (!irClass.isInline) return null
|
||||
|
||||
return when (declaration) {
|
||||
is IrConstructor -> transformConstructor(declaration)
|
||||
is IrSimpleFunction -> transformMethodFlat(declaration)
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformConstructor(irConstructor: IrConstructor): IrDeclaration {
|
||||
if (irConstructor.isPrimary) return irConstructor
|
||||
private fun transformConstructor(irConstructor: IrConstructor): List<IrDeclaration>? {
|
||||
if (irConstructor.isPrimary) return null
|
||||
|
||||
// Secondary constructors are lowered into static function
|
||||
val result = transformedFunction.getOrPut(irConstructor.symbol) { createStaticBodilessMethod(irConstructor).symbol }.owner
|
||||
val irClass = irConstructor.parentAsClass
|
||||
val result = getOrCreateStaticMethod(irConstructor)
|
||||
|
||||
// Copied and adapted from Kotlin/Native InlineClassTransformer
|
||||
result.body = context.createIrBuilder(result.symbol).irBlockBody(result) {
|
||||
transformConstructorBody(irConstructor, result)
|
||||
|
||||
// Secondary ctors of inline class must delegate to some other constructors.
|
||||
// Use these delegating call later to initialize this variable.
|
||||
lateinit var thisVar: IrVariable
|
||||
val parameterMapping = result.valueParameters.associateBy {
|
||||
irConstructor.valueParameters[it.index].symbol
|
||||
}
|
||||
|
||||
(irConstructor.body as IrBlockBody).statements.forEach { statement ->
|
||||
+statement.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
return irBlock(expression) {
|
||||
thisVar = createTmpVariable(
|
||||
expression,
|
||||
irType = irClass.defaultType
|
||||
)
|
||||
thisVar.parent = result
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
if (expression.symbol == irClass.thisReceiver?.symbol) {
|
||||
return irGet(thisVar)
|
||||
}
|
||||
|
||||
parameterMapping[expression.symbol]?.let { return irGet(it) }
|
||||
return expression
|
||||
}
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.parent == irConstructor)
|
||||
declaration.parent = result
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
if (expression.returnTargetSymbol == irConstructor.symbol) {
|
||||
return irReturn(irBlock(expression.startOffset, expression.endOffset) {
|
||||
+expression.value
|
||||
+irGet(thisVar)
|
||||
})
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
}, null)
|
||||
}
|
||||
+irReturn(irGet(thisVar))
|
||||
}
|
||||
|
||||
return result
|
||||
return listOf(result)
|
||||
}
|
||||
|
||||
|
||||
private fun transformMethodFlat(function: IrSimpleFunction): List<IrDeclaration> {
|
||||
private fun transformMethodFlat(function: IrSimpleFunction): List<IrDeclaration>? {
|
||||
// TODO: Support fake-overridden methods without boxing
|
||||
if (function.isStaticMethodOfClass || !function.isReal)
|
||||
return listOf(function)
|
||||
return null
|
||||
|
||||
val staticMethod = createStaticBodilessMethod(function)
|
||||
transformedFunction[function.symbol] = staticMethod.symbol
|
||||
val staticMethod = getOrCreateStaticMethod(function)
|
||||
|
||||
// Move function body to static method, transforming value parameters and nested declarations
|
||||
function.body!!.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.parent == function)
|
||||
declaration.parent = staticMethod
|
||||
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
|
||||
|
||||
return context.createIrBuilder(staticMethod.symbol).irGet(
|
||||
when (valueDeclaration) {
|
||||
function.dispatchReceiverParameter, function.parentAsClass.thisReceiver ->
|
||||
staticMethod.valueParameters[0]
|
||||
|
||||
function.extensionReceiverParameter ->
|
||||
staticMethod.valueParameters[1]
|
||||
|
||||
in function.valueParameters -> {
|
||||
val offset = if (function.extensionReceiverParameter != null) 2 else 1
|
||||
staticMethod.valueParameters[valueDeclaration.index + offset]
|
||||
}
|
||||
|
||||
else -> return expression
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
|
||||
staticMethod.body = function.body
|
||||
transformMethodBodyFlat(function, staticMethod)
|
||||
function.body = delegateToStaticMethod(function, staticMethod)
|
||||
|
||||
if (function.overriddenSymbols.isEmpty()) // Function is used only in unboxed context
|
||||
return listOf(staticMethod)
|
||||
|
||||
// Delegate original function to static implementation
|
||||
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(staticMethod).apply {
|
||||
val parameters =
|
||||
listOfNotNull(
|
||||
function.dispatchReceiverParameter!!,
|
||||
function.extensionReceiverParameter
|
||||
) + function.valueParameters
|
||||
|
||||
for ((index, valueParameter) in parameters.withIndex()) {
|
||||
putValueArgument(index, irGet(valueParameter))
|
||||
}
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
return listOf(function, staticMethod)
|
||||
}
|
||||
|
||||
private fun transformConstructorBody(irConstructor: IrConstructor, staticMethod: IrSimpleFunction) {
|
||||
if (irConstructor.isPrimary) return // TODO error() maybe?
|
||||
|
||||
val irClass = irConstructor.parentAsClass
|
||||
|
||||
// Copied and adapted from Kotlin/Native InlineClassTransformer
|
||||
staticMethod.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += context.createIrBuilder(staticMethod.symbol).irBlockBody(staticMethod) {
|
||||
|
||||
// Secondary ctors of inline class must delegate to some other constructors.
|
||||
// Use these delegating call later to initialize this variable.
|
||||
lateinit var thisVar: IrVariable
|
||||
val parameterMapping = staticMethod.valueParameters.associateBy {
|
||||
irConstructor.valueParameters[it.index].symbol
|
||||
}
|
||||
|
||||
(irConstructor.body as IrBlockBody).statements.forEach { statement ->
|
||||
+statement.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
return irBlock(expression) {
|
||||
thisVar = createTmpVariable(
|
||||
expression,
|
||||
irType = irClass.defaultType
|
||||
)
|
||||
thisVar.parent = staticMethod
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
if (expression.symbol == irClass.thisReceiver?.symbol) {
|
||||
return irGet(thisVar)
|
||||
}
|
||||
|
||||
parameterMapping[expression.symbol]?.let { return irGet(it) }
|
||||
return expression
|
||||
}
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.parent == irConstructor)
|
||||
declaration.parent = staticMethod
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
if (expression.returnTargetSymbol == irConstructor.symbol) {
|
||||
return irReturn(irBlock(expression.startOffset, expression.endOffset) {
|
||||
+expression.value
|
||||
+irGet(thisVar)
|
||||
})
|
||||
}
|
||||
|
||||
return expression
|
||||
}
|
||||
|
||||
}, null)
|
||||
}
|
||||
+irReturn(irGet(thisVar))
|
||||
}.statements
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformMethodBodyFlat(function: IrSimpleFunction, staticMethod: IrSimpleFunction) {
|
||||
// TODO: Support fake-overridden methods without boxing
|
||||
if (function.isStaticMethodOfClass || !function.isReal) return // TODO error()
|
||||
|
||||
val functionBody = function.body
|
||||
|
||||
// Move function body to static method, transforming value parameters and nested declarations
|
||||
staticMethod.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements.addAll((functionBody as IrBlockBody).statements)
|
||||
|
||||
transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitDeclaration(declaration: IrDeclaration): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.parent == function)
|
||||
declaration.parent = staticMethod
|
||||
|
||||
return declaration
|
||||
}
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val valueDeclaration = expression.symbol.owner as? IrValueParameter ?: return super.visitGetValue(expression)
|
||||
|
||||
return context.createIrBuilder(staticMethod.symbol).irGet(
|
||||
when (valueDeclaration) {
|
||||
function.dispatchReceiverParameter, function.parentAsClass.thisReceiver ->
|
||||
staticMethod.valueParameters[0]
|
||||
|
||||
function.extensionReceiverParameter ->
|
||||
staticMethod.valueParameters[1]
|
||||
|
||||
in function.valueParameters -> {
|
||||
val offset = if (function.extensionReceiverParameter != null) 2 else 1
|
||||
staticMethod.valueParameters[valueDeclaration.index + offset]
|
||||
}
|
||||
|
||||
else -> return expression
|
||||
}
|
||||
)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun delegateToStaticMethod(function: IrSimpleFunction, staticMethod: IrSimpleFunction): IrBlockBody {
|
||||
// Delegate original function to static implementation
|
||||
return IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += context.createIrBuilder(function.symbol).irBlockBody {
|
||||
+irReturn(
|
||||
irCall(staticMethod).apply {
|
||||
val parameters =
|
||||
listOfNotNull(
|
||||
function.dispatchReceiverParameter!!,
|
||||
function.extensionReceiverParameter
|
||||
) + function.valueParameters
|
||||
|
||||
for ((index, valueParameter) in parameters.withIndex()) {
|
||||
putValueArgument(index, irGet(valueParameter))
|
||||
}
|
||||
}
|
||||
)
|
||||
}.statements
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
val inlineClassUsageLowering = object : FileLoweringPass {
|
||||
private fun getOrCreateStaticMethod(function: IrFunction): IrSimpleFunction =
|
||||
transformedFunction.getOrPut(function) {
|
||||
createStaticBodilessMethod(function)
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
val inlineClassUsageLowering = object : BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
@@ -219,13 +248,6 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
||||
else -> irCall(expression, getOrCreateStaticMethod(function))
|
||||
}
|
||||
}
|
||||
|
||||
private fun getOrCreateStaticMethod(function: IrFunction): IrSimpleFunctionSymbol =
|
||||
transformedFunction.getOrPut(function.symbol) {
|
||||
createStaticBodilessMethod(function).also {
|
||||
function.parentAsClass.declarations.add(it)
|
||||
}.symbol
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,15 +17,97 @@ import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.cast
|
||||
|
||||
class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
class InnerClassesLowering(val context: BackendContext) : DeclarationTransformer {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
runPostfix(true).toFileLoweringPass().lower(irFile)
|
||||
}
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
|
||||
if (declaration is IrClass && declaration.isInner) {
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
declaration.declarations += context.declarationFactory.getOuterThisField(declaration)
|
||||
}
|
||||
} else if (declaration is IrConstructor) {
|
||||
val irClass = declaration.parentAsClass
|
||||
if (!irClass.isInner) return null
|
||||
|
||||
val newConstructor = lowerConstructor(declaration)
|
||||
val oldConstructorParameterToNew = context.primaryConstructorParameterMap(declaration)
|
||||
for ((oldParam, newParam) in oldConstructorParameterToNew.entries) {
|
||||
newParam.defaultValue = oldParam.defaultValue?.let { oldDefault ->
|
||||
IrExpressionBodyImpl(oldDefault.startOffset, oldDefault.endOffset) {
|
||||
expression = oldDefault.expression.patchDeclarationParents(newConstructor)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return listOf(newConstructor)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun lowerConstructor(irConstructor: IrConstructor): IrConstructor {
|
||||
val loweredConstructor = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(irConstructor)
|
||||
val outerThisParameter = loweredConstructor.valueParameters[0]
|
||||
|
||||
val irClass = irConstructor.parentAsClass
|
||||
val parentThisField = context.declarationFactory.getOuterThisField(irClass)
|
||||
|
||||
val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
|
||||
|
||||
loweredConstructor.body = IrBlockBodyImpl(blockBody.startOffset, blockBody.endOffset) {
|
||||
context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply {
|
||||
statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter)))
|
||||
}
|
||||
|
||||
statements.addAll(blockBody.statements)
|
||||
|
||||
if (statements.find { it is IrInstanceInitializerCall } == null) {
|
||||
val delegatingConstructorCall =
|
||||
statements.find { it is IrDelegatingConstructorCall } as IrDelegatingConstructorCall?
|
||||
?: throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
|
||||
delegatingConstructorCall.apply { dispatchReceiver = IrGetValueImpl(startOffset, endOffset, outerThisParameter.symbol) }
|
||||
}
|
||||
patchDeclarationParents(loweredConstructor)
|
||||
|
||||
val oldConstructorParameterToNew = context.primaryConstructorParameterMap(irConstructor)
|
||||
transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
|
||||
}
|
||||
|
||||
return loweredConstructor
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
private fun BackendContext.primaryConstructorParameterMap(originalConstructor: IrConstructor): Map<IrValueParameter, IrValueParameter> {
|
||||
val oldConstructorParameterToNew = HashMap<IrValueParameter, IrValueParameter>()
|
||||
|
||||
val loweredConstructor = declarationFactory.getInnerClassConstructorWithOuterThisParameter(originalConstructor)
|
||||
|
||||
originalConstructor.valueParameters.forEach { old ->
|
||||
oldConstructorParameterToNew[old] = loweredConstructor.valueParameters[old.index + 1]
|
||||
}
|
||||
|
||||
return oldConstructorParameterToNew
|
||||
}
|
||||
|
||||
|
||||
class InnerClassesMemberBodyLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile, true)
|
||||
}
|
||||
|
||||
private val IrValueSymbol.classForImplicitThis: IrClass?
|
||||
// TODO: is this the correct way to get the class?
|
||||
get() =
|
||||
@@ -37,40 +119,31 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
} else
|
||||
null
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
val irClass = container.parent as? IrClass ?: return
|
||||
|
||||
if (!irClass.isInner) return
|
||||
|
||||
val parentThisField = context.declarationFactory.getOuterThisField(irClass)
|
||||
val oldConstructorParameterToNew = HashMap<IrValueParameter, IrValueParameter>()
|
||||
|
||||
fun lowerConstructor(irConstructor: IrConstructor): IrConstructor {
|
||||
val loweredConstructor = context.declarationFactory.getInnerClassConstructorWithOuterThisParameter(irConstructor)
|
||||
val outerThisParameter = loweredConstructor.valueParameters[0]
|
||||
|
||||
irConstructor.valueParameters.forEach { old ->
|
||||
oldConstructorParameterToNew[old] = loweredConstructor.valueParameters[old.index + 1]
|
||||
if (container is IrField || container is IrAnonymousInitializer || container is IrValueParameter) {
|
||||
val primaryConstructor = context.declarationFactory.getInnerClassOriginalPrimaryConstructorOrNull(irClass)
|
||||
if (primaryConstructor != null) {
|
||||
val oldConstructorParameterToNew = context.primaryConstructorParameterMap(primaryConstructor)
|
||||
irBody.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
|
||||
}
|
||||
|
||||
val blockBody = irConstructor.body as? IrBlockBody ?: throw AssertionError("Unexpected constructor body: ${irConstructor.body}")
|
||||
context.createIrBuilder(irConstructor.symbol, irConstructor.startOffset, irConstructor.endOffset).apply {
|
||||
blockBody.statements.add(0, irSetField(irGet(irClass.thisReceiver!!), parentThisField, irGet(outerThisParameter)))
|
||||
}
|
||||
if (blockBody.statements.find { it is IrInstanceInitializerCall } == null) {
|
||||
val delegatingConstructorCall =
|
||||
blockBody.statements.find { it is IrDelegatingConstructorCall } as IrDelegatingConstructorCall?
|
||||
?: throw AssertionError("Delegating constructor call expected: ${irConstructor.dump()}")
|
||||
delegatingConstructorCall.apply { dispatchReceiver = IrGetValueImpl(startOffset, endOffset, outerThisParameter.symbol) }
|
||||
}
|
||||
blockBody.patchDeclarationParents(loweredConstructor)
|
||||
loweredConstructor.body = blockBody
|
||||
return loweredConstructor
|
||||
}
|
||||
|
||||
irClass.declarations += parentThisField
|
||||
irClass.transformDeclarationsFlat { irMember -> (irMember as? IrConstructor)?.let { listOf(lowerConstructor(it)) } }
|
||||
irClass.transformChildrenVoid(VariableRemapper(oldConstructorParameterToNew))
|
||||
irBody.fixThisReference(irClass, container)
|
||||
}
|
||||
|
||||
irClass.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
fun IrBody.fixThisReference(irClass: IrClass, container: IrDeclaration) {
|
||||
val enclosingFunction: IrDeclaration? = run {
|
||||
var current: IrDeclaration? = container
|
||||
while (current != null && current !is IrFunction) {
|
||||
current = current.parent as? IrDeclaration
|
||||
}
|
||||
current
|
||||
}
|
||||
transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitClassNew(declaration: IrClass): IrStatement =
|
||||
declaration
|
||||
|
||||
@@ -83,7 +156,7 @@ class InnerClassesLowering(val context: BackendContext) : ClassLoweringPass {
|
||||
val startOffset = expression.startOffset
|
||||
val endOffset = expression.endOffset
|
||||
val origin = expression.origin
|
||||
val function = currentFunction?.irElement as? IrFunction
|
||||
val function = (currentFunction?.irElement ?: enclosingFunction) as? IrFunction
|
||||
val enclosingThisReceiver = function?.dispatchReceiverParameter ?: irClass.thisReceiver!!
|
||||
|
||||
var irThis: IrExpression = IrGetValueImpl(startOffset, endOffset, enclosingThisReceiver.symbol, origin)
|
||||
@@ -117,9 +190,9 @@ val innerClassConstructorCallsPhase = makeIrFilePhase(
|
||||
description = "Handle constructor calls for inner classes"
|
||||
)
|
||||
|
||||
class InnerClassConstructorCallsLowering(val context: BackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
class InnerClassConstructorCallsLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
|
||||
@@ -16,8 +16,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
@@ -35,43 +34,77 @@ import org.jetbrains.kotlin.ir.util.resolveFakeOverride
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class LateinitLowering(val backendContext: CommonBackendContext) : FileLoweringPass {
|
||||
class NullableFieldsForLateinitCreationLowering(val backendContext: CommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private val nullableFields = backendContext.lateinitNullableFields
|
||||
private fun buildOrGetNullableField(originalField: IrField): IrField {
|
||||
if (originalField.type.isMarkedNullable()) return originalField
|
||||
return nullableFields.getOrPut(originalField) {
|
||||
buildField {
|
||||
updateFrom(originalField)
|
||||
type = originalField.type.makeNullable()
|
||||
name = originalField.name
|
||||
}.apply {
|
||||
parent = originalField.parent
|
||||
correspondingPropertySymbol = originalField.correspondingPropertySymbol
|
||||
annotations += originalField.annotations
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrField) {
|
||||
declaration.correspondingPropertySymbol?.owner?.let { property ->
|
||||
if (property.isRealLateinit) {
|
||||
val newField = backendContext.buildOrGetNullableField(declaration)
|
||||
if (declaration != newField && declaration.parent != property.parent) return listOf(newField)
|
||||
}
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
// Transform declarations
|
||||
class NullableFieldsDeclarationLowering(val backendContext: CommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
when (declaration) {
|
||||
is IrProperty -> {
|
||||
if (declaration.isRealLateinit) {
|
||||
declaration.backingField = backendContext.buildOrGetNullableField(declaration.backingField!!)
|
||||
}
|
||||
}
|
||||
|
||||
is IrSimpleFunction -> {
|
||||
declaration.correspondingPropertySymbol?.owner?.let { property ->
|
||||
if (declaration == property.getter && property.isRealLateinit) {
|
||||
// f = buildOrGetNullableField is idempotent, i.e. f(f(x)) == f(x)
|
||||
transformGetter(backendContext.buildOrGetNullableField(property.backingField!!), declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun transformGetter(backingField: IrField, getter: IrFunction) {
|
||||
val type = backingField.type
|
||||
assert(!type.isPrimitiveType()) { "'lateinit' modifier is not allowed on primitive types" }
|
||||
val startOffset = getter.startOffset
|
||||
val endOffset = getter.endOffset
|
||||
getter.body = IrBlockBodyImpl(startOffset, endOffset) {
|
||||
val irBuilder = backendContext.createIrBuilder(getter.symbol, startOffset, endOffset)
|
||||
irBuilder.run {
|
||||
val resultVar = scope.createTemporaryVariable(
|
||||
irGetField(getter.dispatchReceiverParameter?.let { irGet(it) }, backingField)
|
||||
)
|
||||
resultVar.parent = getter
|
||||
statements.add(resultVar)
|
||||
val throwIfNull = irIfThenElse(
|
||||
context.irBuiltIns.nothingType,
|
||||
irNotEquals(irGet(resultVar), irNull()),
|
||||
irReturn(irGet(resultVar)),
|
||||
backendContext.throwUninitializedPropertyAccessException(this, backingField.name.asString())
|
||||
)
|
||||
statements.add(throwIfNull)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
// Transform usages
|
||||
class LateinitUsageLowering(val backendContext: CommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
val nullableVariables = mutableMapOf<IrVariable, IrVariable>()
|
||||
|
||||
// Transform declarations
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitProperty(declaration: IrProperty): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
if (declaration.isLateinit && declaration.origin != IrDeclarationOrigin.FAKE_OVERRIDE) {
|
||||
val oldField = declaration.backingField!!
|
||||
val newField = buildOrGetNullableField(oldField)
|
||||
|
||||
declaration.backingField = newField
|
||||
|
||||
transformGetter(newField, declaration.getter!!)
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitVariable(declaration: IrVariable): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
|
||||
@@ -92,41 +125,17 @@ class LateinitLowering(val backendContext: CommonBackendContext) : FileLoweringP
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = declaration.parent
|
||||
it.initializer = IrConstImpl.constNull(declaration.startOffset, declaration.endOffset, backendContext.irBuiltIns.nothingNType)
|
||||
it.initializer =
|
||||
IrConstImpl.constNull(declaration.startOffset, declaration.endOffset, backendContext.irBuiltIns.nothingNType)
|
||||
}
|
||||
|
||||
nullableVariables[declaration] = newVar
|
||||
|
||||
return newVar
|
||||
}
|
||||
|
||||
private fun transformGetter(backingField: IrField, getter: IrFunction) {
|
||||
val type = backingField.type
|
||||
assert(!type.isPrimitiveType()) { "'lateinit' modifier is not allowed on primitive types" }
|
||||
val startOffset = getter.startOffset
|
||||
val endOffset = getter.endOffset
|
||||
val irBuilder = backendContext.createIrBuilder(getter.symbol, startOffset, endOffset)
|
||||
irBuilder.run {
|
||||
val body = IrBlockBodyImpl(startOffset, endOffset)
|
||||
val resultVar = scope.createTemporaryVariable(
|
||||
irGetField(getter.dispatchReceiverParameter?.let { irGet(it) }, backingField)
|
||||
)
|
||||
resultVar.parent = getter
|
||||
body.statements.add(resultVar)
|
||||
val throwIfNull = irIfThenElse(
|
||||
context.irBuiltIns.nothingType,
|
||||
irNotEquals(irGet(resultVar), irNull()),
|
||||
irReturn(irGet(resultVar)),
|
||||
backendContext.throwUninitializedPropertyAccessException(this, backingField.name.asString())
|
||||
)
|
||||
body.statements.add(throwIfNull)
|
||||
getter.body = body
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
// Transform usages
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val irVar = nullableVariables[expression.symbol.owner] ?: return expression
|
||||
|
||||
@@ -152,7 +161,7 @@ class LateinitLowering(val backendContext: CommonBackendContext) : FileLoweringP
|
||||
|
||||
override fun visitGetField(expression: IrGetField): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val newField = nullableFields[expression.symbol.owner] ?: return expression
|
||||
val newField = backendContext.mapping.lateInitFieldToNullableField[expression.symbol.owner] ?: return expression
|
||||
return with(expression) {
|
||||
IrGetFieldImpl(startOffset, endOffset, newField.symbol, newField.type, receiver, origin, superQualifierSymbol)
|
||||
}
|
||||
@@ -160,7 +169,7 @@ class LateinitLowering(val backendContext: CommonBackendContext) : FileLoweringP
|
||||
|
||||
override fun visitSetField(expression: IrSetField): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
val newField = nullableFields[expression.symbol.owner] ?: return expression
|
||||
val newField = backendContext.mapping.lateInitFieldToNullableField[expression.symbol.owner] ?: return expression
|
||||
return with(expression) {
|
||||
IrSetFieldImpl(startOffset, endOffset, newField.symbol, receiver, value, type, origin, superQualifierSymbol)
|
||||
}
|
||||
@@ -177,7 +186,9 @@ class LateinitLowering(val backendContext: CommonBackendContext) : FileLoweringP
|
||||
receiver.getter?.owner?.resolveFakeOverride()?.correspondingPropertySymbol!!.owner.also { assert(it.isLateinit) }
|
||||
|
||||
val nullableField =
|
||||
buildOrGetNullableField(property.backingField ?: error("Lateinit property is supposed to have backing field"))
|
||||
backendContext.buildOrGetNullableField(
|
||||
property.backingField ?: error("Lateinit property is supposed to have backing field")
|
||||
)
|
||||
|
||||
return expression.run { backendContext.createIrBuilder(symbol, startOffset, endOffset) }.run {
|
||||
irNotEquals(irGetField(receiver.dispatchReceiver, nullableField), irNull())
|
||||
@@ -186,3 +197,20 @@ class LateinitLowering(val backendContext: CommonBackendContext) : FileLoweringP
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun CommonBackendContext.buildOrGetNullableField(originalField: IrField): IrField {
|
||||
if (originalField.type.isMarkedNullable()) return originalField
|
||||
return mapping.lateInitFieldToNullableField.getOrPut(originalField) {
|
||||
buildField {
|
||||
updateFrom(originalField)
|
||||
type = originalField.type.makeNullable()
|
||||
name = originalField.name
|
||||
}.apply {
|
||||
parent = originalField.parent
|
||||
correspondingPropertySymbol = originalField.correspondingPropertySymbol
|
||||
annotations += originalField.annotations
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private val IrProperty.isRealLateinit get() = isLateinit && origin != IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
@@ -5,44 +5,46 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.ir.addChild
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrScript
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
|
||||
//This lower takes part of old LocalDeclarationLowering job to pop up local classes from functions
|
||||
open class LocalClassPopupLowering(val context: BackendContext) : FileLoweringPass {
|
||||
open class LocalClassPopupLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile, withLocalDeclarations = true, allowDeclarationModification = true)
|
||||
}
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
val extractedLocalClasses = arrayListOf<Pair<IrClass, IrDeclarationContainer>>()
|
||||
|
||||
irFile.transform(object : IrElementTransformerVoidWithContext() {
|
||||
irBody.transform(object : IrElementTransformerVoidWithContext() {
|
||||
|
||||
override fun visitClassNew(declaration: IrClass): IrStatement {
|
||||
val newDeclaration = super.visitClassNew(declaration)
|
||||
if (newDeclaration !is IrClass) return newDeclaration
|
||||
val currentScope =
|
||||
if (allScopes.size > 1) allScopes[allScopes.lastIndex - 1] else createScope(container as IrSymbolOwner)
|
||||
if (!shouldPopUp(declaration, currentScope)) return declaration
|
||||
|
||||
val currentScope = allScopes[allScopes.lastIndex - 1]
|
||||
if (!shouldPopUp(declaration, currentScope)) return newDeclaration
|
||||
val newContainer = run {
|
||||
var currentParent = declaration.parent
|
||||
while (currentParent is IrDeclaration && currentParent !is IrClass && currentParent !is IrScript) {
|
||||
currentParent = currentParent.parent
|
||||
}
|
||||
|
||||
val newContainer = allScopes.asReversed().drop(1/*skip self*/).firstOrNull {
|
||||
//find first class local or not;
|
||||
// to reproduce original LocalDeclarationLowering behaviour add: '&& !it.irElement.isLocal' condition
|
||||
it.irElement is IrClass || it.irElement is IrScript
|
||||
}?.irElement?.let { it as? IrClass ?: it as? IrScript } ?: currentFile
|
||||
extractedLocalClasses.add(newDeclaration to newContainer)
|
||||
currentParent as IrDeclarationContainer // IrClass or IrScript or IrPackageFragment
|
||||
}
|
||||
|
||||
extractedLocalClasses.add(declaration to newContainer)
|
||||
return IrCompositeImpl(declaration.startOffset, declaration.endOffset, context.irBuiltIns.unitType)
|
||||
}
|
||||
}, null)
|
||||
|
||||
for ((local, newContainer) in extractedLocalClasses) {
|
||||
newContainer.addChild(local)
|
||||
context.extractedLocalClasses += local
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -5,10 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementVisitorVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ScopeWithIr
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.backend.common.descriptors.synthesizedName
|
||||
import org.jetbrains.kotlin.backend.common.ir.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
@@ -43,6 +40,7 @@ import org.jetbrains.kotlin.ir.types.impl.IrUninitializedType
|
||||
import org.jetbrains.kotlin.ir.types.impl.makeTypeProjection
|
||||
import org.jetbrains.kotlin.ir.util.constructedClass
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
@@ -95,7 +93,11 @@ class LocalDeclarationsLowering(
|
||||
val localNameProvider: LocalNameProvider = LocalNameProvider.DEFAULT,
|
||||
val visibilityPolicy: VisibilityPolicy = VisibilityPolicy.DEFAULT
|
||||
) :
|
||||
FileLoweringPass {
|
||||
BodyLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
runOnFilePostfix(irFile, allowDeclarationModification = true)
|
||||
}
|
||||
|
||||
object DECLARATION_ORIGIN_FIELD_FOR_CAPTURED_VALUE :
|
||||
IrDeclarationOriginImpl("FIELD_FOR_CAPTURED_VALUE", isSynthetic = true)
|
||||
@@ -106,10 +108,23 @@ class LocalDeclarationsLowering(
|
||||
private object STATEMENT_ORIGIN_INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE :
|
||||
IrStatementOriginImpl("INITIALIZER_OF_FIELD_FOR_CAPTURED_VALUE")
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
LocalDeclarationsTransformer(irFile).lowerLocalDeclarations()
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
LocalDeclarationsTransformer(irBody, container).lowerLocalDeclarations()
|
||||
}
|
||||
|
||||
private class ScopeWithCounter(scope: Scope, irElement: IrElement) : ScopeWithIr(scope, irElement) {
|
||||
// Continuous numbering across all declarations in the container.
|
||||
var counter: Int = 0
|
||||
}
|
||||
|
||||
private val scopeMap: MutableMap<IrSymbolOwner, ScopeWithCounter> = mutableMapOf()
|
||||
// Need to keep LocalFunctionContext.index
|
||||
private val IrSymbolOwner.scopeWithCounter: ScopeWithCounter
|
||||
get() = scopeMap.getOrPut(this) {
|
||||
ScopeWithCounter(Scope(symbol), this)
|
||||
}
|
||||
|
||||
|
||||
private abstract class LocalContext {
|
||||
val capturedTypeParameterToTypeParameter: MutableMap<IrTypeParameter, IrTypeParameter> = mutableMapOf()
|
||||
|
||||
@@ -203,7 +218,7 @@ class LocalDeclarationsLowering(
|
||||
abbreviation.annotations
|
||||
)
|
||||
|
||||
private inner class LocalDeclarationsTransformer(val irFile: IrFile) {
|
||||
private inner class LocalDeclarationsTransformer(val irBody: IrBody, val container: IrDeclaration) {
|
||||
val localFunctions: MutableMap<IrFunction, LocalFunctionContext> = LinkedHashMap()
|
||||
val localClasses: MutableMap<IrClass, LocalClassContext> = LinkedHashMap()
|
||||
val localClassConstructors: MutableMap<IrConstructor, LocalClassConstructorContext> = LinkedHashMap()
|
||||
@@ -481,7 +496,7 @@ class LocalDeclarationsLowering(
|
||||
rewriteClassMembers(it.declaration, it)
|
||||
}
|
||||
|
||||
rewriteFunctionBody(irFile, null)
|
||||
rewriteFunctionBody(container, null)
|
||||
}
|
||||
|
||||
private fun createNewCall(oldCall: IrCall, newCallee: IrFunction) =
|
||||
@@ -613,7 +628,7 @@ class LocalDeclarationsLowering(
|
||||
)
|
||||
newDeclaration.recordTransformedValueParameters(localFunctionContext)
|
||||
|
||||
newDeclaration.annotations.addAll(oldDeclaration.annotations)
|
||||
newDeclaration.annotations = oldDeclaration.annotations
|
||||
|
||||
transformedDeclarations[oldDeclaration] = newDeclaration
|
||||
}
|
||||
@@ -794,7 +809,7 @@ class LocalDeclarationsLowering(
|
||||
|
||||
private fun collectClosureForLocalDeclarations() {
|
||||
//TODO: maybe use for granular declarations
|
||||
val annotator = ClosureAnnotator(irFile)
|
||||
val annotator = ClosureAnnotator(irBody, container)
|
||||
|
||||
localFunctions.forEach { (declaration, context) ->
|
||||
context.closure = annotator.getFunctionClosure(declaration)
|
||||
@@ -806,19 +821,25 @@ class LocalDeclarationsLowering(
|
||||
}
|
||||
|
||||
private fun collectLocalDeclarations() {
|
||||
class ScopeWithCounter(scope: Scope, irElement: IrElement) : ScopeWithIr(scope, irElement) {
|
||||
// Continuous numbering across all declarations in the container.
|
||||
var counter: Int = 0
|
||||
}
|
||||
val enclosingFileScope = container.file.scopeWithCounter
|
||||
|
||||
irFile.acceptVoid(object : IrElementVisitorVoidWithContext() {
|
||||
val enclosingClassScope = run {
|
||||
var currentParent = container as? IrClass ?: container.parent
|
||||
while (currentParent is IrDeclaration && currentParent !is IrClass) {
|
||||
currentParent = currentParent.parent
|
||||
}
|
||||
|
||||
currentParent as? IrClass
|
||||
}?.scopeWithCounter
|
||||
|
||||
irBody.acceptVoid(object : IrElementVisitorVoidWithContext() {
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun createScope(declaration: IrSymbolOwner): ScopeWithIr {
|
||||
return ScopeWithCounter(Scope(declaration.symbol), declaration)
|
||||
return ScopeWithCounter(Scope(declaration.symbol), declaration) // Don't cache local declarations
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
@@ -826,7 +847,7 @@ class LocalDeclarationsLowering(
|
||||
|
||||
if (declaration.visibility == Visibilities.LOCAL) {
|
||||
val scopeWithIr =
|
||||
(currentClass ?: currentFile /*file is required for K/N cause file declarations are not split by classes*/
|
||||
(currentClass ?: enclosingClassScope ?: enclosingFileScope /*file is required for K/N cause file declarations are not split by classes*/
|
||||
?: error("No scope for ${declaration.dump()}"))
|
||||
localFunctions[declaration] =
|
||||
LocalFunctionContext(
|
||||
@@ -858,7 +879,8 @@ class LocalDeclarationsLowering(
|
||||
}
|
||||
|
||||
private val inInlineFunctionScope: Boolean
|
||||
get() = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false }
|
||||
get() = allScopes.any { scope -> (scope.irElement as? IrFunction)?.isInline ?: false } ||
|
||||
generateSequence(container) { it.parent as? IrDeclaration }.any { it is IrFunction && it.isInline }
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,43 +5,46 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.*
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
|
||||
class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
|
||||
class PropertiesLowering : DeclarationTransformer {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.accept(this, null)
|
||||
runPostfix(true).toFileLoweringPass().lower(irFile)
|
||||
}
|
||||
|
||||
override fun visitFile(declaration: IrFile): IrFile {
|
||||
declaration.transformChildrenVoid(this)
|
||||
declaration.transformDeclarationsFlat { lowerProperty(it) }
|
||||
return declaration
|
||||
}
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
when (declaration) {
|
||||
is IrSimpleFunction -> {
|
||||
declaration.correspondingPropertySymbol?.owner?.let { property ->
|
||||
if (!property.isEffectivelyExternal()) {
|
||||
return listOf(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
is IrField -> {
|
||||
declaration.correspondingPropertySymbol?.owner?.let { property ->
|
||||
if (!property.isEffectivelyExternal()) {
|
||||
return listOf(declaration)
|
||||
}
|
||||
}
|
||||
}
|
||||
is IrProperty -> {
|
||||
if (!declaration.isEffectivelyExternal()) {
|
||||
return listOf()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
declaration.transformDeclarationsFlat { lowerProperty(it) }
|
||||
return declaration
|
||||
return null
|
||||
}
|
||||
|
||||
override fun visitScript(declaration: IrScript): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
declaration.transformDeclarationsFlat { lowerProperty(it) }
|
||||
return declaration
|
||||
}
|
||||
|
||||
private fun lowerProperty(declaration: IrDeclaration): List<IrDeclaration>? =
|
||||
if (declaration is IrProperty && !declaration.isEffectivelyExternal())
|
||||
listOfNotNull(declaration.backingField, declaration.getter, declaration.setter)
|
||||
else null
|
||||
|
||||
companion object {
|
||||
fun checkNoProperties(irFile: IrFile) {
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
@@ -57,9 +60,10 @@ class PropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
|
||||
}
|
||||
}
|
||||
|
||||
class LocalDelegatedPropertiesLowering : IrElementTransformerVoid(), FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.accept(this, null)
|
||||
class LocalDelegatedPropertiesLowering : IrElementTransformerVoid(), BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.accept(this, null)
|
||||
}
|
||||
|
||||
override fun visitLocalDelegatedProperty(declaration: IrLocalDelegatedProperty): IrStatement {
|
||||
|
||||
@@ -5,8 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
@@ -16,10 +19,10 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class ProvisionalFunctionExpressionLowering :
|
||||
IrElementTransformerVoid(),
|
||||
FileLoweringPass {
|
||||
BodyLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(this)
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunctionExpression(expression: IrFunctionExpression): IrExpression {
|
||||
|
||||
@@ -5,22 +5,18 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.ir.builders.irBoolean
|
||||
import org.jetbrains.kotlin.ir.builders.irBreak
|
||||
import org.jetbrains.kotlin.ir.builders.irGet
|
||||
import org.jetbrains.kotlin.ir.builders.irSetVar
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturnableBlock
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSymbolOwner
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDoWhileLoopImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||
|
||||
/**
|
||||
* Replaces returnable blocks and `return`'s with loops and `break`'s correspondingly.
|
||||
@@ -69,13 +65,13 @@ import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||
* }
|
||||
*
|
||||
*/
|
||||
class ReturnableBlockLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transform(ReturnableBlockTransformer(context), null)
|
||||
class ReturnableBlockLowering(val context: CommonBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
container.transform(ReturnableBlockTransformer(context, (container as IrSymbolOwner).symbol), null)
|
||||
}
|
||||
}
|
||||
|
||||
class ReturnableBlockTransformer(val context: CommonBackendContext) : IrElementTransformerVoidWithContext() {
|
||||
class ReturnableBlockTransformer(val context: CommonBackendContext, val containerSymbol: IrSymbol? = null) : IrElementTransformerVoidWithContext() {
|
||||
private var labelCnt = 0
|
||||
private val returnMap = mutableMapOf<IrReturnableBlockSymbol, (IrReturn) -> IrExpression>()
|
||||
|
||||
@@ -87,7 +83,8 @@ class ReturnableBlockTransformer(val context: CommonBackendContext) : IrElementT
|
||||
override fun visitContainerExpression(expression: IrContainerExpression): IrExpression {
|
||||
if (expression !is IrReturnableBlock) return super.visitContainerExpression(expression)
|
||||
|
||||
val builder = context.createIrBuilder(currentScope!!.scope.scopeOwnerSymbol)
|
||||
val scopeSymbol = currentScope?.scope?.scopeOwnerSymbol ?: containerSymbol
|
||||
val builder = context.createIrBuilder(scopeSymbol!!)
|
||||
val variable by lazy {
|
||||
builder.scope.createTemporaryVariableDeclaration(expression.type, "tmp\$ret\$${labelCnt++}", true)
|
||||
}
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
@@ -26,7 +26,9 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.ir.visitors.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
val sharedVariablesPhase = makeIrFilePhase(
|
||||
::SharedVariablesLowering,
|
||||
@@ -36,35 +38,16 @@ val sharedVariablesPhase = makeIrFilePhase(
|
||||
|
||||
object CoroutineIntrinsicLambdaOrigin : IrStatementOriginImpl("Coroutine intrinsic lambda")
|
||||
|
||||
class SharedVariablesLowering(val context: BackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
class SharedVariablesLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
|
||||
SharedVariablesTransformer(declaration).lowerSharedVariables()
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
|
||||
SharedVariablesTransformer(declaration).lowerSharedVariables()
|
||||
}
|
||||
|
||||
override fun visitAnonymousInitializer(declaration: IrAnonymousInitializer) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
|
||||
SharedVariablesTransformer(declaration).lowerSharedVariables()
|
||||
}
|
||||
})
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
// TODO remove this condition
|
||||
if (container is IrFunction || container is IrField || container is IrAnonymousInitializer) {
|
||||
SharedVariablesTransformer(irBody, container).lowerSharedVariables()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private inner class SharedVariablesTransformer(val irDeclaration: IrDeclaration) {
|
||||
private inner class SharedVariablesTransformer(val irBody: IrBody, val irDeclaration: IrDeclaration) {
|
||||
private val sharedVariables = HashSet<IrVariable>()
|
||||
|
||||
fun lowerSharedVariables() {
|
||||
@@ -75,7 +58,7 @@ class SharedVariablesLowering(val context: BackendContext) : FileLoweringPass {
|
||||
}
|
||||
|
||||
private fun collectSharedVariables() {
|
||||
irDeclaration.accept(object : IrElementVisitor<Unit, IrDeclarationParent?> {
|
||||
irBody.accept(object : IrElementVisitor<Unit, IrDeclarationParent?> {
|
||||
val relevantVars = HashSet<IrVariable>()
|
||||
val relevantVals = HashSet<IrVariable>()
|
||||
|
||||
@@ -134,7 +117,7 @@ class SharedVariablesLowering(val context: BackendContext) : FileLoweringPass {
|
||||
private fun rewriteSharedVariables() {
|
||||
val transformedSymbols = HashMap<IrValueSymbol, IrVariableSymbol>()
|
||||
|
||||
irDeclaration.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitVariable(declaration: IrVariable): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
|
||||
@@ -148,7 +131,7 @@ class SharedVariablesLowering(val context: BackendContext) : FileLoweringPass {
|
||||
}
|
||||
})
|
||||
|
||||
irDeclaration.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
|
||||
@@ -196,7 +196,7 @@ abstract class SingleAbstractMethodLowering(val context: CommonBackendContext) :
|
||||
}.apply {
|
||||
overriddenSymbols += superMethod.symbol
|
||||
dispatchReceiverParameter = subclass.thisReceiver!!.copyTo(this)
|
||||
superMethod.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
|
||||
valueParameters = superMethod.valueParameters.map { it.copyTo(this) }
|
||||
body = context.createIrBuilder(symbol).irBlockBody {
|
||||
+irReturn(irCall(wrappedFunctionClass.functions.single { it.name == OperatorNameConventions.INVOKE }).apply {
|
||||
dispatchReceiver = irGetField(irGet(dispatchReceiverParameter!!), field)
|
||||
|
||||
@@ -5,40 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeAlias
|
||||
import org.jetbrains.kotlin.ir.expressions.IrContainerExpression
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
|
||||
class StripTypeAliasDeclarationsLowering :
|
||||
IrElementVisitorVoid,
|
||||
FileLoweringPass {
|
||||
class StripTypeAliasDeclarationsLowering : DeclarationTransformer {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.acceptVoid(this)
|
||||
}
|
||||
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFile(declaration: IrFile) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
declaration.declarations.removeAll { it is IrTypeAlias }
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
declaration.declarations.removeAll { it is IrTypeAlias }
|
||||
}
|
||||
|
||||
override fun visitContainerExpression(expression: IrContainerExpression) {
|
||||
expression.acceptChildrenVoid(this)
|
||||
expression.statements.removeAll { it is IrTypeAlias }
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return if (declaration is IrTypeAlias) listOf() else null
|
||||
}
|
||||
}
|
||||
@@ -17,20 +17,20 @@
|
||||
package org.jetbrains.kotlin.backend.common.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FunctionLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.collectTailRecursionCalls
|
||||
import org.jetbrains.kotlin.backend.common.deepCopyWithVariables
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.util.explicitParameters
|
||||
import org.jetbrains.kotlin.ir.util.getArgumentsWithIr
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
/**
|
||||
@@ -39,9 +39,24 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
* Note: it currently can't handle local functions and classes declared in default arguments.
|
||||
* See [deepCopyWithVariables].
|
||||
*/
|
||||
open class TailrecLowering(val context: BackendContext) : FunctionLoweringPass {
|
||||
override fun lower(irFunction: IrFunction) {
|
||||
lowerTailRecursionCalls(context, irFunction, useProperComputationOrderOfTailrecDefaultParameters())
|
||||
open class TailrecLowering(val context: BackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container is IrFunction) {
|
||||
// TODO Shouldn't this be done after local declarations lowering?
|
||||
// Lower local declarations
|
||||
irBody.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitFunction(declaration: IrFunction) {
|
||||
declaration.acceptChildrenVoid(this)
|
||||
lowerTailRecursionCalls(context, declaration, useProperComputationOrderOfTailrecDefaultParameters())
|
||||
}
|
||||
})
|
||||
|
||||
lowerTailRecursionCalls(context, container, useProperComputationOrderOfTailrecDefaultParameters())
|
||||
}
|
||||
}
|
||||
|
||||
open fun useProperComputationOrderOfTailrecDefaultParameters() = true
|
||||
@@ -54,11 +69,13 @@ private fun lowerTailRecursionCalls(context: BackendContext, irFunction: IrFunct
|
||||
}
|
||||
|
||||
val oldBody = irFunction.body as IrBlockBody
|
||||
val oldBodyStatements = ArrayList(oldBody.statements)
|
||||
val builder = context.createIrBuilder(irFunction.symbol).at(oldBody)
|
||||
|
||||
val parameters = irFunction.explicitParameters
|
||||
|
||||
irFunction.body = builder.irBlockBody {
|
||||
oldBody.statements.clear()
|
||||
oldBody.statements += builder.irBlockBody {
|
||||
// Define variables containing current values of parameters:
|
||||
val parameterToVariable = parameters.associate {
|
||||
it to createTmpVariable(irGet(it), nameHint = it.symbol.suggestVariableName(), isMutable = true)
|
||||
@@ -82,14 +99,14 @@ private fun lowerTailRecursionCalls(context: BackendContext, irFunction: IrFunct
|
||||
properComputationOrderOfTailrecDefaultParameters
|
||||
)
|
||||
|
||||
oldBody.statements.forEach {
|
||||
oldBodyStatements.forEach {
|
||||
+it.transform(transformer, null)
|
||||
}
|
||||
|
||||
+irBreak(loop)
|
||||
}
|
||||
}
|
||||
}
|
||||
}.statements
|
||||
}
|
||||
|
||||
private class BodyTransformer(
|
||||
|
||||
@@ -31,7 +31,18 @@ import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.util.OperatorNameConventions
|
||||
|
||||
class FunctionInlining(val context: CommonBackendContext) : IrElementTransformerVoidWithContext() {
|
||||
class FunctionInlining(val context: CommonBackendContext) : IrElementTransformerVoidWithContext(), BodyLoweringPass {
|
||||
|
||||
private var containerScope: ScopeWithIr? = null
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
// TODO container: IrSymbolDeclaration
|
||||
containerScope = createScope(container as IrSymbolOwner)
|
||||
irBody.accept(this, null)
|
||||
containerScope = null
|
||||
|
||||
irBody.patchDeclarationParents(container as? IrDeclarationParent ?: container.parent)
|
||||
}
|
||||
|
||||
fun inline(irModule: IrModuleFragment) = irModule.accept(this, data = null)
|
||||
|
||||
@@ -52,8 +63,11 @@ class FunctionInlining(val context: CommonBackendContext) : IrElementTransformer
|
||||
val actualCallee = getFunctionDeclaration(callee.symbol)
|
||||
|
||||
val parent = allScopes.map { it.irElement }.filterIsInstance<IrDeclarationParent>().lastOrNull()
|
||||
?: allScopes.map { it.irElement }.filterIsInstance<IrDeclaration>().lastOrNull()?.parent
|
||||
?: containerScope?.irElement as? IrDeclarationParent
|
||||
?: (containerScope?.irElement as? IrDeclaration)?.parent
|
||||
|
||||
val inliner = Inliner(expression, actualCallee, currentScope!!, parent, context)
|
||||
val inliner = Inliner(expression, actualCallee, currentScope ?: containerScope!!, parent, context)
|
||||
return inliner.inline()
|
||||
}
|
||||
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower.loops
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
@@ -12,9 +13,7 @@ import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
@@ -96,15 +95,15 @@ val forLoopsPhase = makeIrFilePhase(
|
||||
* }
|
||||
* ```
|
||||
*/
|
||||
class ForLoopsLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
class ForLoopsLowering(val context: CommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
val oldLoopToNewLoop = mutableMapOf<IrLoop, IrLoop>()
|
||||
val transformer = RangeLoopTransformer(context, oldLoopToNewLoop)
|
||||
irFile.transformChildrenVoid(transformer)
|
||||
val transformer = RangeLoopTransformer(context, container as IrSymbolOwner, oldLoopToNewLoop)
|
||||
irBody.transformChildrenVoid(transformer)
|
||||
|
||||
// Update references in break/continue.
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitBreakContinue(jump: IrBreakContinue): IrExpression {
|
||||
oldLoopToNewLoop[jump.loop]?.let { jump.loop = it }
|
||||
return jump
|
||||
@@ -115,6 +114,7 @@ class ForLoopsLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
|
||||
private class RangeLoopTransformer(
|
||||
val context: CommonBackendContext,
|
||||
val container: IrSymbolOwner,
|
||||
val oldLoopToNewLoop: MutableMap<IrLoop, IrLoop>
|
||||
) : IrElementTransformerVoidWithContext() {
|
||||
|
||||
@@ -122,7 +122,7 @@ private class RangeLoopTransformer(
|
||||
private val headerInfoBuilder = DefaultHeaderInfoBuilder(context, this::getScopeOwnerSymbol)
|
||||
private val headerProcessor = HeaderProcessor(context, headerInfoBuilder, this::getScopeOwnerSymbol)
|
||||
|
||||
fun getScopeOwnerSymbol() = currentScope!!.scope.scopeOwnerSymbol
|
||||
fun getScopeOwnerSymbol() = currentScope?.scope?.scopeOwnerSymbol ?: container.symbol
|
||||
|
||||
override fun visitBlock(expression: IrBlock): IrExpression {
|
||||
// LoopExpressionGenerator in psi2ir lowers `for (loopVar in <someIterable>) { // Loop body }` into an IrBlock with origin FOR_LOOP.
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower.optimizations
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.phaser.makeIrFilePhase
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
@@ -39,7 +39,7 @@ val foldConstantLoweringPhase = makeIrFilePhase(
|
||||
class FoldConstantLowering(
|
||||
private val context: CommonBackendContext,
|
||||
// In K/JS Float and Double are the same so Float constant should be fold similar to Double
|
||||
private val floatSpecial: Boolean = false) : IrElementTransformerVoid(), FileLoweringPass {
|
||||
private val floatSpecial: Boolean = false) : IrElementTransformerVoid(), BodyLoweringPass {
|
||||
/**
|
||||
* ID of an binary operator / method.
|
||||
*
|
||||
@@ -243,8 +243,8 @@ class FoldConstantLowering(
|
||||
}
|
||||
|
||||
@ExperimentalUnsignedTypes
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
expression.transformChildrenVoid(this)
|
||||
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.common.lower.optimizations
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.isTopLevel
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
@@ -15,13 +15,11 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrSetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
class PropertyAccessorInlineLowering(private val context: CommonBackendContext) : FileLoweringPass {
|
||||
class PropertyAccessorInlineLowering(private val context: CommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
private val IrProperty.isSafeToInline: Boolean get() = isTopLevel || (modality === Modality.FINAL || visibility == Visibilities.PRIVATE) || (parent as IrClass).modality === Modality.FINAL
|
||||
|
||||
@@ -128,7 +126,7 @@ class PropertyAccessorInlineLowering(private val context: CommonBackendContext)
|
||||
}
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(AccessorInliner())
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(AccessorInliner())
|
||||
}
|
||||
}
|
||||
@@ -234,7 +234,7 @@ inline fun IrFunction.addValueParameter(builder: IrValueParameterBuilder.() -> U
|
||||
index = valueParameters.size
|
||||
}
|
||||
build().also { valueParameter ->
|
||||
valueParameters.add(valueParameter)
|
||||
valueParameters += valueParameter
|
||||
valueParameter.parent = this@addValueParameter
|
||||
}
|
||||
}
|
||||
@@ -293,7 +293,7 @@ inline fun IrTypeParametersContainer.addTypeParameter(builder: IrTypeParameterBu
|
||||
index = typeParameters.size
|
||||
}
|
||||
build().also { typeParameter ->
|
||||
typeParameters.add(typeParameter)
|
||||
typeParameters += typeParameter
|
||||
typeParameter.parent = this@addTypeParameter
|
||||
}
|
||||
}
|
||||
|
||||
@@ -6,14 +6,11 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.classOrNull
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrFail
|
||||
@@ -28,11 +25,13 @@ fun eliminateDeadDeclarations(
|
||||
mainFunction: IrSimpleFunction?
|
||||
) {
|
||||
|
||||
val allRoots = buildRoots(module, context, mainFunction)
|
||||
val allRoots = stageController.withInitialIr { buildRoots(module, context, mainFunction) }
|
||||
|
||||
val usefulDeclarations = usefulDeclarations(allRoots, context)
|
||||
|
||||
removeUselessDeclarations(module, usefulDeclarations)
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
removeUselessDeclarations(module, usefulDeclarations)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrField.isConstant(): Boolean {
|
||||
@@ -42,13 +41,14 @@ private fun IrField.isConstant(): Boolean {
|
||||
private fun buildRoots(module: IrModuleFragment, context: JsIrBackendContext, mainFunction: IrSimpleFunction?): Iterable<IrDeclaration> {
|
||||
val rootDeclarations =
|
||||
(module.files + context.packageLevelJsModules + context.externalPackageFragment.values).flatMapTo(mutableListOf()) { file ->
|
||||
file.declarations.filter {
|
||||
it is IrField && it.initializer != null && it.fqNameWhenAvailable?.asString()?.startsWith("kotlin") != true
|
||||
|| it.isExported(context)
|
||||
|| it.isEffectivelyExternal()
|
||||
|| it is IrField && it.correspondingPropertySymbol?.owner?.isExported(context) == true
|
||||
|| it is IrSimpleFunction && it.correspondingPropertySymbol?.owner?.isExported(context) == true
|
||||
}.filter { !(it is IrField && it.isConstant() && !it.isExported(context)) }
|
||||
file.declarations.flatMap { if (it is IrProperty) listOfNotNull(it.backingField, it.getter, it.setter) else listOf(it) }
|
||||
.filter {
|
||||
it is IrField && it.initializer != null && it.fqNameWhenAvailable?.asString()?.startsWith("kotlin") != true
|
||||
|| it.isExported(context)
|
||||
|| it.isEffectivelyExternal()
|
||||
|| it is IrField && it.correspondingPropertySymbol?.owner?.isExported(context) == true
|
||||
|| it is IrSimpleFunction && it.correspondingPropertySymbol?.owner?.isExported(context) == true
|
||||
}.filter { !(it is IrField && it.isConstant() && !it.isExported(context)) }
|
||||
}
|
||||
|
||||
if (context.hasTests) rootDeclarations += context.testContainer
|
||||
@@ -78,16 +78,11 @@ private fun removeUselessDeclarations(module: IrModuleFragment, usefulDeclaratio
|
||||
process(declaration)
|
||||
}
|
||||
|
||||
override fun visitConstructor(declaration: IrConstructor) {
|
||||
if (declaration !in usefulDeclarations) {
|
||||
// Keep the constructor declaration without body in order to declare the JS constructor function
|
||||
declaration.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, emptyList())
|
||||
}
|
||||
}
|
||||
// TODO bring back the primary constructor fix
|
||||
|
||||
private fun process(container: IrDeclarationContainer) {
|
||||
container.declarations.transformFlat { member ->
|
||||
if (member !in usefulDeclarations && member !is IrConstructor) {
|
||||
if (member !in usefulDeclarations) {
|
||||
emptyList()
|
||||
} else {
|
||||
member.acceptVoid(this)
|
||||
@@ -128,14 +123,16 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
val constructedClasses = hashSetOf<IrClass>()
|
||||
|
||||
fun IrDeclaration.enqueue() {
|
||||
if (this !in result) {
|
||||
if ((this !is IrProperty || this.isExternal) && this !in result) {
|
||||
result.add(this)
|
||||
queue.addLast(this)
|
||||
}
|
||||
}
|
||||
|
||||
// Add roots, including nested declarations
|
||||
roots.withNested().forEach { it.enqueue() }
|
||||
stageController.withInitialIr {
|
||||
roots.withNested().forEach { it.enqueue() }
|
||||
}
|
||||
|
||||
val toStringMethod =
|
||||
context.irBuiltIns.anyClass.owner.declarations.filterIsInstance<IrFunction>().single { it.name.asString() == "toString" }
|
||||
@@ -148,6 +145,9 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
while (queue.isNotEmpty()) {
|
||||
val declaration = queue.pollFirst()
|
||||
|
||||
// TODO remove?
|
||||
stageController.lazyLower(declaration)
|
||||
|
||||
if (declaration is IrClass) {
|
||||
declaration.superTypes.forEach {
|
||||
(it.classifierOrNull as? IrClassSymbol)?.owner?.enqueue()
|
||||
@@ -191,6 +191,9 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
else -> null
|
||||
}
|
||||
|
||||
// TODO remove?
|
||||
(body as? IrBody)?.let { stageController.lazyLower(it) }
|
||||
|
||||
body?.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
@@ -265,7 +268,8 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
}
|
||||
|
||||
for (klass in constructedClasses) {
|
||||
for (declaration in klass.declarations) {
|
||||
// TODO a better way to support inverse overrides.
|
||||
for (declaration in ArrayList(klass.declarations)) {
|
||||
if (declaration in result) continue
|
||||
|
||||
if (declaration is IrOverridableDeclaration<*> && declaration.overridesUsefulFunction()) {
|
||||
@@ -284,6 +288,34 @@ fun usefulDeclarations(roots: Iterable<IrDeclaration>, context: JsIrBackendConte
|
||||
declaration.enqueue()
|
||||
}
|
||||
}
|
||||
|
||||
// TODO is this needed?
|
||||
for (declaration in ArrayList(klass.declarations)) {
|
||||
// TODO this is a hack.
|
||||
if (declaration is IrProperty) {
|
||||
declaration.getter?.let { if (it.overridesUsefulFunction()) it.enqueue() }
|
||||
declaration.setter?.let { if (it.overridesUsefulFunction()) it.enqueue() }
|
||||
}
|
||||
}
|
||||
|
||||
// TODO deduplicate
|
||||
// Special hack for `IntrinsicsJs.kt` support
|
||||
if (klass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }) {
|
||||
ArrayList(klass.declarations).forEach {
|
||||
if (it is IrSimpleFunction && it.name.asString().startsWith("invoke")) {
|
||||
it.enqueue()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// TODO find out how `doResume` gets removed
|
||||
if (klass.symbol == context.ir.symbols.coroutineImpl) {
|
||||
ArrayList(klass.declarations).forEach {
|
||||
if (it is IrSimpleFunction && it.name.asString() == "doResume") {
|
||||
it.enqueue()
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,12 @@
|
||||
/*
|
||||
* 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.backend.common.CommonBackendContext
|
||||
|
||||
interface JsCommonBackendContext : CommonBackendContext {
|
||||
override val mapping: JsMapping
|
||||
}
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.ir.DeclarationFactory
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||
@@ -12,6 +13,7 @@ import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsMapping
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -25,12 +27,12 @@ import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.dump
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import java.util.*
|
||||
|
||||
class JsDeclarationFactory : DeclarationFactory {
|
||||
private val singletonFieldDescriptors = HashMap<IrClass, IrField>()
|
||||
private val outerThisFieldSymbols = HashMap<IrClass, IrField>()
|
||||
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
|
||||
class JsDeclarationFactory(mapping: JsMapping) : DeclarationFactory {
|
||||
private val singletonFieldDescriptors = mapping.singletonFieldDescriptors
|
||||
private val outerThisFieldSymbols = mapping.outerThisFieldSymbols
|
||||
private val innerClassConstructors = mapping.innerClassConstructors
|
||||
private val originalInnerClassPrimaryConstructorByClass = mapping.originalInnerClassPrimaryConstructorByClass
|
||||
|
||||
override fun getFieldForEnumEntry(enumEntry: IrEnumEntry): IrField = TODO()
|
||||
|
||||
@@ -79,9 +81,19 @@ class JsDeclarationFactory : DeclarationFactory {
|
||||
|
||||
return innerClassConstructors.getOrPut(innerClassConstructor) {
|
||||
createInnerClassConstructorWithOuterThisParameter(innerClassConstructor)
|
||||
}.also {
|
||||
if (innerClassConstructor.isPrimary) {
|
||||
originalInnerClassPrimaryConstructorByClass[innerClass] = innerClassConstructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInnerClassOriginalPrimaryConstructorOrNull(innerClass: IrClass): IrConstructor? {
|
||||
assert(innerClass.isInner) { "Class is not inner: $innerClass" }
|
||||
|
||||
return originalInnerClassPrimaryConstructorByClass[innerClass]
|
||||
}
|
||||
|
||||
private fun createInnerClassConstructorWithOuterThisParameter(oldConstructor: IrConstructor): IrConstructor {
|
||||
val irClass = oldConstructor.parent as IrClass
|
||||
val outerThisType = (irClass.parent as IrClass).defaultType
|
||||
|
||||
@@ -194,12 +194,12 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val anyConstructorSymbol = anyClassSymbol.constructors.single()
|
||||
|
||||
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 uShortClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.UShort") }
|
||||
val uIntClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.UInt") }
|
||||
val uLongClassSymbol by lazy { getInternalClassWithoutPackage("kotlin.ULong") }
|
||||
val uByteClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.UByte") }
|
||||
val uShortClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.UShort") }
|
||||
val uIntClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.UInt") }
|
||||
val uLongClassSymbol by lazy2 { getInternalClassWithoutPackage("kotlin.ULong") }
|
||||
|
||||
val unreachable = defineUnreachableIntrinsic()
|
||||
|
||||
@@ -274,16 +274,16 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
// TODO move CharSequence-related stiff to IntrinsifyCallsLowering
|
||||
val charSequenceClassSymbol = context.symbolTable.referenceClass(context.getClass(FqName("kotlin.CharSequence")))
|
||||
val charSequenceLengthPropertyGetterSymbol by lazy {
|
||||
val charSequenceLengthPropertyGetterSymbol by lazy2 {
|
||||
with(charSequenceClassSymbol.owner.declarations) {
|
||||
filterIsInstance<IrProperty>().firstOrNull { it.name.asString() == "length" }?.getter ?:
|
||||
filterIsInstance<IrFunction>().first { it.name.asString() == "<get-length>" }
|
||||
}.symbol
|
||||
}
|
||||
val charSequenceGetFunctionSymbol by lazy {
|
||||
val charSequenceGetFunctionSymbol by lazy2 {
|
||||
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
|
||||
}
|
||||
|
||||
|
||||
@@ -5,17 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.atMostOne
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.js.JsDeclarationFactory
|
||||
import org.jetbrains.kotlin.builtins.PrimitiveType
|
||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PropertyDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.SimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.*
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -24,9 +20,9 @@ import org.jetbrains.kotlin.ir.SourceRangeInfo
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.CallableReferenceKey
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ConstructorPair
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.OperatorNames
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -47,11 +43,14 @@ class JsIrBackendContext(
|
||||
val additionalExportedDeclarations: Set<FqName>,
|
||||
override val configuration: CompilerConfiguration, // TODO: remove configuration from backend context
|
||||
override val scriptMode: Boolean = false
|
||||
) : CommonBackendContext {
|
||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||
) : JsCommonBackendContext {
|
||||
override val transformedFunction
|
||||
get() = error("Use Mapping.inlineClassMemberToStatic instead")
|
||||
|
||||
val memberMap = mutableMapOf<IrSimpleFunctionSymbol, IrSimpleFunction>()
|
||||
override val lateinitNullableFields
|
||||
get() = error("Use Mapping.lateInitFieldToNullableField instead")
|
||||
|
||||
override val extractedLocalClasses: MutableSet<IrClass> = hashSetOf()
|
||||
|
||||
override val builtIns = module.builtIns
|
||||
|
||||
@@ -59,15 +58,39 @@ class JsIrBackendContext(
|
||||
|
||||
val devMode = configuration[JSConfigurationKeys.DEVELOPER_MODE] ?: false
|
||||
|
||||
var externalPackageFragment = mutableMapOf<IrFileSymbol, IrFile>()
|
||||
lateinit var bodilessBuiltInsPackageFragment: IrPackageFragment
|
||||
val externalPackageFragment = mutableMapOf<IrFileSymbol, IrFile>()
|
||||
val externalDeclarations = hashSetOf<IrDeclaration>()
|
||||
val bodilessBuiltInsPackageFragment: IrPackageFragment = run {
|
||||
|
||||
val externalNestedClasses = mutableListOf<IrClass>()
|
||||
val packageLevelJsModules = mutableListOf<IrFile>()
|
||||
class DescriptorlessExternalPackageFragmentSymbol : IrExternalPackageFragmentSymbol {
|
||||
override val descriptor: PackageFragmentDescriptor
|
||||
get() = error("Operation is unsupported")
|
||||
|
||||
private var _owner: IrExternalPackageFragment? = null
|
||||
override val owner get() = _owner!!
|
||||
|
||||
override var uniqId: UniqId
|
||||
get() = error("Operation is unsupported")
|
||||
set(value) { error("Operation is unsupported") }
|
||||
|
||||
override val isBound get() = _owner != null
|
||||
|
||||
override fun bind(owner: IrExternalPackageFragment) {
|
||||
_owner = owner
|
||||
}
|
||||
}
|
||||
|
||||
IrExternalPackageFragmentImpl(
|
||||
DescriptorlessExternalPackageFragmentSymbol(),
|
||||
FqName("kotlin")
|
||||
)
|
||||
}
|
||||
|
||||
val packageLevelJsModules = mutableSetOf<IrFile>()
|
||||
val declarationLevelJsModules = mutableListOf<IrDeclarationWithName>()
|
||||
|
||||
val internalPackageFragmentDescriptor = EmptyPackageFragmentDescriptor(builtIns.builtInsModule, FqName("kotlin.js.internal"))
|
||||
val implicitDeclarationFile by lazy {
|
||||
val implicitDeclarationFile by lazy2 {
|
||||
IrFileImpl(object : SourceManager.FileEntry {
|
||||
override val name = "<implicitDeclarations>"
|
||||
override val maxOffset = UNDEFINED_OFFSET
|
||||
@@ -102,7 +125,9 @@ class JsIrBackendContext(
|
||||
}
|
||||
|
||||
override val sharedVariablesManager = JsSharedVariablesManager(irBuiltIns, implicitDeclarationFile)
|
||||
override val declarationFactory = JsDeclarationFactory()
|
||||
|
||||
override val mapping = JsMapping()
|
||||
override val declarationFactory = JsDeclarationFactory(mapping)
|
||||
|
||||
companion object {
|
||||
val KOTLIN_PACKAGE_FQN = FqName.fromSegments(listOf("kotlin"))
|
||||
@@ -136,11 +161,7 @@ class JsIrBackendContext(
|
||||
private val coroutinePackage = module.getPackage(COROUTINE_PACKAGE_FQNAME)
|
||||
private val coroutineIntrinsicsPackage = module.getPackage(COROUTINE_INTRINSICS_PACKAGE_FQNAME)
|
||||
|
||||
val enumEntryToGetInstanceFunction = mutableMapOf<IrEnumEntrySymbol, IrSimpleFunction>()
|
||||
val objectToGetInstanceFunction = mutableMapOf<IrClassSymbol, IrSimpleFunction>()
|
||||
val enumEntryExternalToInstanceField = mutableMapOf<IrEnumEntrySymbol, IrField>()
|
||||
val callableReferencesCache = mutableMapOf<CallableReferenceKey, IrSimpleFunction>()
|
||||
val secondaryConstructorToFactoryCache = mutableMapOf<IrConstructor, ConstructorPair>()
|
||||
|
||||
val intrinsics = JsIntrinsics(irBuiltIns, this)
|
||||
|
||||
@@ -263,27 +284,27 @@ class JsIrBackendContext(
|
||||
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 coroutineImplLabelPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
|
||||
val coroutineImplLabelPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
|
||||
val coroutineImplResultSymbolGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner }
|
||||
val coroutineImplResultSymbolSetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("result")!!.owner }
|
||||
val coroutineImplExceptionPropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exception")!!.owner }
|
||||
val coroutineImplExceptionPropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exception")!!.owner }
|
||||
val coroutineImplExceptionStatePropertyGetter by lazy { ir.symbols.coroutineImpl.getPropertyGetter("exceptionState")!!.owner }
|
||||
val coroutineImplExceptionStatePropertySetter by lazy { ir.symbols.coroutineImpl.getPropertySetter("exceptionState")!!.owner }
|
||||
val coroutineImplLabelPropertyGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("state")!!.owner }
|
||||
val coroutineImplLabelPropertySetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("state")!!.owner }
|
||||
val coroutineImplResultSymbolGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("result")!!.owner }
|
||||
val coroutineImplResultSymbolSetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("result")!!.owner }
|
||||
val coroutineImplExceptionPropertyGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("exception")!!.owner }
|
||||
val coroutineImplExceptionPropertySetter by lazy2 { ir.symbols.coroutineImpl.getPropertySetter("exception")!!.owner }
|
||||
val coroutineImplExceptionStatePropertyGetter by lazy2 { ir.symbols.coroutineImpl.getPropertyGetter("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>()
|
||||
}
|
||||
|
||||
val primitiveClassFunctionClass by lazy {
|
||||
val primitiveClassFunctionClass by lazy2 {
|
||||
primitiveClassesObject.owner.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.find { it.name == Name.identifier("functionClass") }!!
|
||||
}
|
||||
|
||||
val throwableConstructors by lazy { throwableClass.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol } }
|
||||
val defaultThrowableCtor by lazy { throwableConstructors.single { !it.owner.isPrimary && it.owner.valueParameters.size == 0 } }
|
||||
val throwableConstructors by lazy2 { throwableClass.owner.declarations.filterIsInstance<IrConstructor>().map { it.symbol } }
|
||||
val defaultThrowableCtor by lazy2 { throwableConstructors.single { !it.owner.isPrimary && it.owner.valueParameters.size == 0 } }
|
||||
|
||||
private fun referenceOperators(): Map<Name, MutableMap<IrClassifierSymbol, IrSimpleFunctionSymbol>> {
|
||||
val primitiveIrSymbols = irBuiltIns.primitiveIrTypes.map { it.classifierOrFail as IrClassSymbol }
|
||||
@@ -334,3 +355,6 @@ class JsIrBackendContext(
|
||||
print(message)
|
||||
}
|
||||
}
|
||||
|
||||
// TODO: investigate if it could be removed
|
||||
fun <T> lazy2(fn: () -> T) = lazy { stageController.withInitialIr(fn) }
|
||||
@@ -15,10 +15,10 @@ import org.jetbrains.kotlin.backend.common.phaser.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.calls.CallsLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.coroutines.JsSuspendFunctionsLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.inline.CopyInlineFunctionBodyLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.inline.RemoveInlineFunctionsWithReifiedTypeParametersLowering
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
|
||||
private fun DeclarationContainerLoweringPass.runOnFilesPostfix(files: Iterable<IrFile>) = files.forEach { runOnFilePostfix(it) }
|
||||
|
||||
@@ -55,175 +55,322 @@ private fun makeCustomJsModulePhase(
|
||||
}
|
||||
)
|
||||
|
||||
sealed class Lowering(val name: String) {
|
||||
|
||||
abstract val modulePhase: SameTypeNamedPhaseWrapper<JsIrBackendContext, IrModuleFragment>
|
||||
}
|
||||
|
||||
class DeclarationLowering(
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<AnyNamedPhase> = emptySet(),
|
||||
private val factory: (JsIrBackendContext) -> DeclarationTransformer
|
||||
) : Lowering(name) {
|
||||
fun declarationTransformer(context: JsIrBackendContext): DeclarationTransformer {
|
||||
return factory(context)
|
||||
}
|
||||
|
||||
override val modulePhase = makeJsModulePhase(factory, name, description, prerequisite)
|
||||
}
|
||||
|
||||
class BodyLowering(
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<AnyNamedPhase> = emptySet(),
|
||||
private val factory: (JsIrBackendContext) -> BodyLoweringPass
|
||||
) : Lowering(name) {
|
||||
fun bodyLowering(context: JsIrBackendContext): BodyLoweringPass {
|
||||
return factory(context)
|
||||
}
|
||||
|
||||
override val modulePhase = makeJsModulePhase(factory, name, description, prerequisite)
|
||||
}
|
||||
|
||||
class ModuleLowering(
|
||||
name: String,
|
||||
override val modulePhase: SameTypeNamedPhaseWrapper<JsIrBackendContext, IrModuleFragment>
|
||||
) : Lowering(name)
|
||||
|
||||
private fun makeDeclarationTransformerPhase(
|
||||
lowering: (JsIrBackendContext) -> DeclarationTransformer,
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<Lowering> = emptySet()
|
||||
) = DeclarationLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering)
|
||||
|
||||
private fun makeBodyLoweringPhase(
|
||||
lowering: (JsIrBackendContext) -> BodyLoweringPass,
|
||||
name: String,
|
||||
description: String,
|
||||
prerequisite: Set<Lowering> = emptySet()
|
||||
) = BodyLowering(name, description, prerequisite.map { it.modulePhase }.toSet(), lowering)
|
||||
|
||||
fun SameTypeNamedPhaseWrapper<JsIrBackendContext, IrModuleFragment>.toModuleLowering() = ModuleLowering(this.name, this)
|
||||
|
||||
private val validateIrBeforeLowering = makeCustomJsModulePhase(
|
||||
{ context, module -> validationCallback(context, module) },
|
||||
name = "ValidateIrBeforeLowering",
|
||||
description = "Validate IR before lowering"
|
||||
)
|
||||
).toModuleLowering()
|
||||
|
||||
private val validateIrAfterLowering = makeCustomJsModulePhase(
|
||||
{ context, module -> validationCallback(context, module) },
|
||||
name = "ValidateIrAfterLowering",
|
||||
description = "Validate IR after lowering"
|
||||
).toModuleLowering()
|
||||
|
||||
val scriptRemoveReceiverLowering = makeIrModulePhase(
|
||||
::ScriptRemoveReceiverLowering,
|
||||
name = "ScriptRemoveReceiver",
|
||||
description = "Remove receivers for declarations in script"
|
||||
).toModuleLowering()
|
||||
|
||||
val createScriptFunctionsPhase = makeJsModulePhase(
|
||||
::CreateScriptFunctionsPhase,
|
||||
name = "CreateScriptFunctionsPhase",
|
||||
description = "Create functions for initialize and evaluate script"
|
||||
).toModuleLowering()
|
||||
|
||||
private val moveBodilessDeclarationsToSeparatePlacePhase = makeDeclarationTransformerPhase(
|
||||
::MoveBodilessDeclarationsToSeparatePlaceLowering,
|
||||
name = "MoveBodilessDeclarationsToSeparatePlaceLowering",
|
||||
description = "Move bodiless declarations to a separate place"
|
||||
)
|
||||
|
||||
private val expectDeclarationsRemovingPhase = makeJsModulePhase(
|
||||
private val expectDeclarationsRemovingPhase = makeDeclarationTransformerPhase(
|
||||
::ExpectDeclarationsRemoveLowering,
|
||||
name = "ExpectDeclarationsRemoving",
|
||||
description = "Remove expect declaration from module fragment"
|
||||
)
|
||||
|
||||
private val lateinitLoweringPhase = makeJsModulePhase(
|
||||
::LateinitLowering,
|
||||
name = "LateinitLowering",
|
||||
private val lateinitNullableFieldsPhase = makeDeclarationTransformerPhase(
|
||||
::NullableFieldsForLateinitCreationLowering,
|
||||
name = "LateinitNullableFields",
|
||||
description = "Create nullable fields for lateinit properties"
|
||||
)
|
||||
|
||||
private val lateinitDeclarationLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::NullableFieldsDeclarationLowering,
|
||||
name = "LateinitDeclarations",
|
||||
description = "Reference nullable fields from properties and getters + insert checks"
|
||||
)
|
||||
|
||||
private val lateinitUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
::LateinitUsageLowering,
|
||||
name = "LateinitUsage",
|
||||
description = "Insert checks for lateinit field references"
|
||||
)
|
||||
|
||||
private val stripTypeAliasDeclarationsPhase = makeJsModulePhase(
|
||||
private val stripTypeAliasDeclarationsPhase = makeDeclarationTransformerPhase(
|
||||
{ StripTypeAliasDeclarationsLowering() },
|
||||
name = "StripTypeAliasDeclarations",
|
||||
description = "Strip typealias declarations"
|
||||
)
|
||||
|
||||
// TODO make all lambda-related stuff work with IrFunctionExpression and drop this phase
|
||||
private val provisionalFunctionExpressionPhase = makeJsModulePhase(
|
||||
private val provisionalFunctionExpressionPhase = makeBodyLoweringPhase(
|
||||
{ ProvisionalFunctionExpressionLowering() },
|
||||
name = "FunctionExpression",
|
||||
description = "Transform IrFunctionExpression to a local function reference"
|
||||
)
|
||||
|
||||
private val arrayConstructorPhase = makeJsModulePhase(
|
||||
private val arrayConstructorPhase = makeBodyLoweringPhase(
|
||||
::ArrayConstructorLowering,
|
||||
name = "ArrayConstructor",
|
||||
description = "Transform `Array(size) { index -> value }` into a loop"
|
||||
)
|
||||
|
||||
private val functionInliningPhase = makeCustomJsModulePhase(
|
||||
{ context, module ->
|
||||
FunctionInlining(context).inline(module)
|
||||
module.patchDeclarationParents()
|
||||
},
|
||||
private val functionInliningPhase = makeBodyLoweringPhase(
|
||||
::FunctionInlining,
|
||||
name = "FunctionInliningPhase",
|
||||
description = "Perform function inlining",
|
||||
prerequisite = setOf(expectDeclarationsRemovingPhase)
|
||||
)
|
||||
|
||||
private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeJsModulePhase(
|
||||
private val copyInlineFunctionBodyLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::CopyInlineFunctionBodyLowering,
|
||||
name = "CopyInlineFunctionBody",
|
||||
description = "Copy inline function body",
|
||||
prerequisite = setOf(functionInliningPhase)
|
||||
)
|
||||
|
||||
private val removeInlineFunctionsWithReifiedTypeParametersLoweringPhase = makeDeclarationTransformerPhase(
|
||||
{ RemoveInlineFunctionsWithReifiedTypeParametersLowering() },
|
||||
name = "RemoveInlineFunctionsWithReifiedTypeParametersLowering",
|
||||
description = "Remove Inline functions with reified parameters from context",
|
||||
prerequisite = setOf(functionInliningPhase)
|
||||
)
|
||||
|
||||
private val throwableSuccessorsLoweringPhase = makeJsModulePhase(
|
||||
private val throwableSuccessorsLoweringPhase = makeBodyLoweringPhase(
|
||||
::ThrowableLowering,
|
||||
name = "ThrowableLowering",
|
||||
description = "Link kotlin.Throwable and JavaScript Error together to provide proper interop between language and platform exceptions"
|
||||
)
|
||||
|
||||
private val tailrecLoweringPhase = makeJsModulePhase(
|
||||
private val tailrecLoweringPhase = makeBodyLoweringPhase(
|
||||
::TailrecLowering,
|
||||
name = "TailrecLowering",
|
||||
description = "Replace `tailrec` callsites with equivalent loop"
|
||||
)
|
||||
|
||||
private val enumClassConstructorLoweringPhase = makeJsModulePhase(
|
||||
private val enumClassConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumClassConstructorLowering,
|
||||
name = "EnumClassConstructorLowering",
|
||||
description = "Transform Enum Class into regular Class"
|
||||
)
|
||||
|
||||
private val enumClassLoweringPhase = makeJsModulePhase(
|
||||
::EnumClassLowering,
|
||||
name = "EnumClassLowering",
|
||||
description = "Transform Enum Class into regular Class",
|
||||
private val enumClassConstructorBodyLoweringPhase = makeBodyLoweringPhase(
|
||||
::EnumClassConstructorBodyTransformer,
|
||||
name = "EnumClassConstructorBodyLowering",
|
||||
description = "Transform Enum Class into regular Class"
|
||||
)
|
||||
|
||||
|
||||
private val enumEntryInstancesLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumEntryInstancesLowering,
|
||||
name = "EnumEntryInstancesLowering",
|
||||
description = "Create instance variable for each enum entry initialized with `null`",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumUsageLoweringPhase = makeJsModulePhase(
|
||||
private val enumEntryInstancesBodyLoweringPhase = makeBodyLoweringPhase(
|
||||
::EnumEntryInstancesBodyLowering,
|
||||
name = "EnumEntryInstancesBodyLowering",
|
||||
description = "Insert enum entry field initialization into correxposnding class constructors",
|
||||
prerequisite = setOf(enumEntryInstancesLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumClassCreateInitializerLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumClassCreateInitializerLowering,
|
||||
name = "EnumClassCreateInitializerLowering",
|
||||
description = "Create initializer for enum entries",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumEntryCreateGetInstancesFunsLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumEntryCreateGetInstancesFunsLowering,
|
||||
name = "EnumEntryCreateGetInstancesFunsLowering",
|
||||
description = "Create enumEntry_getInstance functions",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumSyntheticFunsLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumSyntheticFunctionsLowering,
|
||||
name = "EnumSyntheticFunctionsLowering",
|
||||
description = "Implement `valueOf` and `values`",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val enumUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
::EnumUsageLowering,
|
||||
name = "EnumUsageLowering",
|
||||
description = "Replace enum access with invocation of corresponding function",
|
||||
prerequisite = setOf(enumClassLoweringPhase)
|
||||
prerequisite = setOf(enumEntryCreateGetInstancesFunsLoweringPhase)
|
||||
)
|
||||
|
||||
private val sharedVariablesLoweringPhase = makeJsModulePhase(
|
||||
private val enumEntryRemovalLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::EnumClassRemoveEntriesLowering,
|
||||
name = "EnumEntryRemovalLowering",
|
||||
description = "Replace enum entry with corresponding class",
|
||||
prerequisite = setOf(enumUsageLoweringPhase)
|
||||
)
|
||||
|
||||
private val sharedVariablesLoweringPhase = makeBodyLoweringPhase(
|
||||
::SharedVariablesLowering,
|
||||
name = "SharedVariablesLowering",
|
||||
description = "Box captured mutable variables"
|
||||
)
|
||||
|
||||
private val returnableBlockLoweringPhase = makeJsModulePhase(
|
||||
private val returnableBlockLoweringPhase = makeBodyLoweringPhase(
|
||||
::ReturnableBlockLowering,
|
||||
name = "ReturnableBlockLowering",
|
||||
description = "Replace returnable block with do-while loop",
|
||||
prerequisite = setOf(functionInliningPhase)
|
||||
)
|
||||
|
||||
private val forLoopsLoweringPhase = makeJsModulePhase(
|
||||
private val forLoopsLoweringPhase = makeBodyLoweringPhase(
|
||||
::ForLoopsLowering,
|
||||
name = "ForLoopsLowering",
|
||||
description = "[Optimization] For loops lowering"
|
||||
)
|
||||
|
||||
private val propertyAccessorInlinerLoweringPhase = makeJsModulePhase(
|
||||
private val propertyAccessorInlinerLoweringPhase = makeBodyLoweringPhase(
|
||||
::PropertyAccessorInlineLowering,
|
||||
name = "PropertyAccessorInlineLowering",
|
||||
description = "[Optimization] Inline property accessors"
|
||||
)
|
||||
|
||||
private val foldConstantLoweringPhase = makeJsModulePhase(
|
||||
private val foldConstantLoweringPhase = makeBodyLoweringPhase(
|
||||
{ FoldConstantLowering(it, true) },
|
||||
name = "FoldConstantLowering",
|
||||
description = "[Optimization] Constant Folding",
|
||||
prerequisite = setOf(propertyAccessorInlinerLoweringPhase)
|
||||
)
|
||||
|
||||
private val localDelegatedPropertiesLoweringPhase = makeJsModulePhase(
|
||||
private val localDelegatedPropertiesLoweringPhase = makeBodyLoweringPhase(
|
||||
{ LocalDelegatedPropertiesLowering() },
|
||||
name = "LocalDelegatedPropertiesLowering",
|
||||
description = "Transform Local Delegated properties"
|
||||
)
|
||||
|
||||
private val localDeclarationsLoweringPhase = makeJsModulePhase(
|
||||
private val localDeclarationsLoweringPhase = makeBodyLoweringPhase(
|
||||
::LocalDeclarationsLowering,
|
||||
name = "LocalDeclarationsLowering",
|
||||
description = "Move local declarations into nearest declaration container",
|
||||
prerequisite = setOf(sharedVariablesLoweringPhase, localDelegatedPropertiesLoweringPhase)
|
||||
)
|
||||
|
||||
private val localClassExtractionPhase = makeJsModulePhase(
|
||||
private val localClassExtractionPhase = makeBodyLoweringPhase(
|
||||
::LocalClassPopupLowering,
|
||||
name = "LocalClassExtractionPhase",
|
||||
description = "Move local declarations into nearest declaration container",
|
||||
prerequisite = setOf(localDeclarationsLoweringPhase)
|
||||
)
|
||||
|
||||
private val innerClassesLoweringPhase = makeJsModulePhase(
|
||||
private val innerClassesLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::InnerClassesLowering,
|
||||
name = "InnerClassesLowering",
|
||||
description = "Capture outer this reference to inner class"
|
||||
)
|
||||
|
||||
private val innerClassConstructorCallsLoweringPhase = makeJsModulePhase(
|
||||
private val innerClassesMemberBodyLoweringPhase = makeBodyLoweringPhase(
|
||||
::InnerClassesMemberBodyLowering,
|
||||
name = "InnerClassesMemberBody",
|
||||
description = "Replace `this` with 'outer this' field references",
|
||||
prerequisite = setOf(innerClassesLoweringPhase)
|
||||
)
|
||||
|
||||
private val innerClassConstructorCallsLoweringPhase = makeBodyLoweringPhase(
|
||||
::InnerClassConstructorCallsLowering,
|
||||
name = "InnerClassConstructorCallsLowering",
|
||||
description = "Replace inner class constructor invocation"
|
||||
)
|
||||
|
||||
private val suspendFunctionsLoweringPhase = makeJsModulePhase(
|
||||
private val suspendFunctionsLoweringPhase = makeBodyLoweringPhase(
|
||||
::JsSuspendFunctionsLowering,
|
||||
name = "SuspendFunctionsLowering",
|
||||
description = "Transform suspend functions into CoroutineImpl instance and build state machine"
|
||||
)
|
||||
|
||||
private val privateMembersLoweringPhase = makeJsModulePhase(
|
||||
private val suspendLambdasRemovalLoweringPhase = makeDeclarationTransformerPhase(
|
||||
{ RemoveSuspendLambdas() },
|
||||
name = "RemoveSuspendLambdas",
|
||||
description = "Remove suspend lambdas"
|
||||
)
|
||||
|
||||
private val privateMembersLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::PrivateMembersLowering,
|
||||
name = "PrivateMembersLowering",
|
||||
description = "Extract private members from classes"
|
||||
)
|
||||
|
||||
private val callableReferenceLoweringPhase = makeJsModulePhase(
|
||||
private val privateMemberUsagesLoweringPhase = makeBodyLoweringPhase(
|
||||
::PrivateMemberBodiesLowering,
|
||||
name = "PrivateMemberUsagesLowering",
|
||||
description = "Rewrite the private member usages"
|
||||
)
|
||||
|
||||
private val callableReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
::CallableReferenceLowering,
|
||||
name = "CallableReferenceLowering",
|
||||
description = "Handle callable references",
|
||||
@@ -235,144 +382,163 @@ private val callableReferenceLoweringPhase = makeJsModulePhase(
|
||||
)
|
||||
)
|
||||
|
||||
private val defaultArgumentStubGeneratorPhase = makeJsModulePhase(
|
||||
private val defaultArgumentStubGeneratorPhase = makeDeclarationTransformerPhase(
|
||||
::JsDefaultArgumentStubGenerator,
|
||||
name = "DefaultArgumentStubGenerator",
|
||||
description = "Generate synthetic stubs for functions with default parameter values"
|
||||
)
|
||||
|
||||
private val defaultParameterInjectorPhase = makeJsModulePhase(
|
||||
{ context -> DefaultParameterInjector(context, skipExternalMethods = true) },
|
||||
private val defaultArgumentPatchOverridesPhase = makeDeclarationTransformerPhase(
|
||||
::DefaultParameterPatchOverridenSymbolsLowering,
|
||||
name = "DefaultArgumentsPatchOverrides",
|
||||
description = "Patch overrides for fake override dispatch functions",
|
||||
prerequisite = setOf(defaultArgumentStubGeneratorPhase)
|
||||
)
|
||||
|
||||
private val defaultParameterInjectorPhase = makeBodyLoweringPhase(
|
||||
{ context -> DefaultParameterInjector(context, skipExternalMethods = true, forceSetOverrideSymbols = false) },
|
||||
name = "DefaultParameterInjector",
|
||||
description = "Replace callsite with default parameters with corresponding stub function",
|
||||
prerequisite = setOf(callableReferenceLoweringPhase, innerClassesLoweringPhase)
|
||||
)
|
||||
|
||||
private val defaultParameterCleanerPhase = makeJsModulePhase(
|
||||
private val defaultParameterCleanerPhase = makeDeclarationTransformerPhase(
|
||||
::DefaultParameterCleaner,
|
||||
name = "DefaultParameterCleaner",
|
||||
description = "Clean default parameters up"
|
||||
)
|
||||
|
||||
private val jsDefaultCallbackGeneratorPhase = makeJsModulePhase(
|
||||
private val jsDefaultCallbackGeneratorPhase = makeBodyLoweringPhase(
|
||||
::JsDefaultCallbackGenerator,
|
||||
name = "JsDefaultCallbackGenerator",
|
||||
description = "Build binding for super calls with default parameters"
|
||||
)
|
||||
|
||||
private val varargLoweringPhase = makeJsModulePhase(
|
||||
private val varargLoweringPhase = makeBodyLoweringPhase(
|
||||
::VarargLowering,
|
||||
name = "VarargLowering",
|
||||
description = "Lower vararg arguments",
|
||||
prerequisite = setOf(callableReferenceLoweringPhase)
|
||||
)
|
||||
|
||||
private val propertiesLoweringPhase = makeJsModulePhase(
|
||||
private val propertiesLoweringPhase = makeDeclarationTransformerPhase(
|
||||
{ PropertiesLowering() },
|
||||
name = "PropertiesLowering",
|
||||
description = "Move fields and accessors out from its property"
|
||||
)
|
||||
|
||||
private val primaryConstructorLoweringPhase = makeJsModulePhase(
|
||||
private val primaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::PrimaryConstructorLowering,
|
||||
name = "PrimaryConstructorLowering",
|
||||
description = "Creates primary constructor if it doesn't exist",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val annotationConstructorLowering = makeJsModulePhase(
|
||||
private val delegateToPrimaryConstructorLoweringPhase = makeBodyLoweringPhase(
|
||||
::DelegateToSyntheticPrimaryConstructor,
|
||||
name = "DelegateToSyntheticPrimaryConstructor",
|
||||
description = "Delegates to synthetic primary constructor",
|
||||
prerequisite = setOf(primaryConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val annotationConstructorLowering = makeDeclarationTransformerPhase(
|
||||
::AnnotationConstructorLowering,
|
||||
name = "AnnotationConstructorLowering",
|
||||
description = "Generate annotation constructor body"
|
||||
)
|
||||
|
||||
private val initializersLoweringPhase = makeJsModulePhase(
|
||||
private val initializersLoweringPhase = makeBodyLoweringPhase(
|
||||
::InitializersLowering,
|
||||
name = "InitializersLowering",
|
||||
description = "Merge init block and field initializers into [primary] constructor",
|
||||
prerequisite = setOf(enumClassConstructorLoweringPhase, primaryConstructorLoweringPhase, annotationConstructorLowering)
|
||||
)
|
||||
|
||||
private val multipleCatchesLoweringPhase = makeJsModulePhase(
|
||||
private val initializersCleanupLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::InitializersCleanupLowering,
|
||||
name = "InitializersCleanupLowering",
|
||||
description = "Remove non-static anonymous initializers and field init expressions",
|
||||
prerequisite = setOf(initializersLoweringPhase)
|
||||
)
|
||||
|
||||
private val multipleCatchesLoweringPhase = makeBodyLoweringPhase(
|
||||
::MultipleCatchesLowering,
|
||||
name = "MultipleCatchesLowering",
|
||||
description = "Replace multiple catches with single one"
|
||||
)
|
||||
|
||||
private val bridgesConstructionPhase = makeJsModulePhase(
|
||||
private val bridgesConstructionPhase = makeDeclarationTransformerPhase(
|
||||
::BridgesConstruction,
|
||||
name = "BridgesConstruction",
|
||||
description = "Generate bridges",
|
||||
prerequisite = setOf(suspendFunctionsLoweringPhase)
|
||||
)
|
||||
|
||||
private val typeOperatorLoweringPhase = makeJsModulePhase(
|
||||
private val typeOperatorLoweringPhase = makeBodyLoweringPhase(
|
||||
::TypeOperatorLowering,
|
||||
name = "TypeOperatorLowering",
|
||||
description = "Lower IrTypeOperator with corresponding logic",
|
||||
prerequisite = setOf(bridgesConstructionPhase, removeInlineFunctionsWithReifiedTypeParametersLoweringPhase)
|
||||
)
|
||||
|
||||
private val secondaryConstructorLoweringPhase = makeJsModulePhase(
|
||||
private val secondaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::SecondaryConstructorLowering,
|
||||
name = "SecondaryConstructorLoweringPhase",
|
||||
description = "Generate static functions for each secondary constructor",
|
||||
prerequisite = setOf(innerClassesLoweringPhase)
|
||||
)
|
||||
|
||||
private val secondaryFactoryInjectorLoweringPhase = makeJsModulePhase(
|
||||
private val secondaryFactoryInjectorLoweringPhase = makeBodyLoweringPhase(
|
||||
::SecondaryFactoryInjectorLowering,
|
||||
name = "SecondaryFactoryInjectorLoweringPhase",
|
||||
description = "Replace usage of secondary constructor with corresponding static function",
|
||||
prerequisite = setOf(innerClassesLoweringPhase)
|
||||
)
|
||||
|
||||
private val inlineClassLoweringPhase = makeCustomJsModulePhase(
|
||||
{ context, module ->
|
||||
InlineClassLowering(context).run {
|
||||
inlineClassDeclarationLowering.runOnFilesPostfix(module)
|
||||
inlineClassUsageLowering.lower(module)
|
||||
}
|
||||
},
|
||||
name = "InlineClassLowering",
|
||||
description = "Handle inline classes"
|
||||
private val inlineClassDeclarationLoweringPhase = makeDeclarationTransformerPhase(
|
||||
{ InlineClassLowering(it).inlineClassDeclarationLowering },
|
||||
name = "InlineClassDeclarationLowering",
|
||||
description = "Handle inline class declarations"
|
||||
)
|
||||
|
||||
private val autoboxingTransformerPhase = makeJsModulePhase(
|
||||
private val inlineClassUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
{ InlineClassLowering(it).inlineClassUsageLowering },
|
||||
name = "InlineClassUsageLowering",
|
||||
description = "Handle inline class usages"
|
||||
)
|
||||
|
||||
private val autoboxingTransformerPhase = makeBodyLoweringPhase(
|
||||
::AutoboxingTransformer,
|
||||
name = "AutoboxingTransformer",
|
||||
description = "Insert box/unbox intrinsics"
|
||||
)
|
||||
|
||||
private val blockDecomposerLoweringPhase = makeCustomJsModulePhase(
|
||||
{ context, module ->
|
||||
JsBlockDecomposerLowering(context).lower(module)
|
||||
module.patchDeclarationParents()
|
||||
},
|
||||
private val blockDecomposerLoweringPhase = makeBodyLoweringPhase(
|
||||
::JsBlockDecomposerLowering,
|
||||
name = "BlockDecomposerLowering",
|
||||
description = "Transform statement-like-expression nodes into pure-statement to make it easily transform into JS",
|
||||
prerequisite = setOf(typeOperatorLoweringPhase, suspendFunctionsLoweringPhase)
|
||||
)
|
||||
|
||||
private val classReferenceLoweringPhase = makeJsModulePhase(
|
||||
private val classReferenceLoweringPhase = makeBodyLoweringPhase(
|
||||
::ClassReferenceLowering,
|
||||
name = "ClassReferenceLowering",
|
||||
description = "Handle class references"
|
||||
)
|
||||
|
||||
private val primitiveCompanionLoweringPhase = makeJsModulePhase(
|
||||
private val primitiveCompanionLoweringPhase = makeBodyLoweringPhase(
|
||||
::PrimitiveCompanionLowering,
|
||||
name = "PrimitiveCompanionLowering",
|
||||
description = "Replace common companion object access with platform one"
|
||||
)
|
||||
|
||||
private val constLoweringPhase = makeJsModulePhase(
|
||||
private val constLoweringPhase = makeBodyLoweringPhase(
|
||||
::ConstLowering,
|
||||
name = "ConstLowering",
|
||||
description = "Wrap Long and Char constants into constructor invocation"
|
||||
)
|
||||
|
||||
private val callsLoweringPhase = makeJsModulePhase(
|
||||
private val callsLoweringPhase = makeBodyLoweringPhase(
|
||||
::CallsLowering,
|
||||
name = "CallsLowering",
|
||||
description = "Handle intrinsics"
|
||||
@@ -382,81 +548,107 @@ private val testGenerationPhase = makeJsModulePhase(
|
||||
::TestGenerator,
|
||||
name = "TestGenerationLowering",
|
||||
description = "Generate invocations to kotlin.test suite and test functions"
|
||||
)
|
||||
).toModuleLowering()
|
||||
|
||||
private val staticMembersLoweringPhase = makeJsModulePhase(
|
||||
private val staticMembersLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::StaticMembersLowering,
|
||||
name = "StaticMembersLowering",
|
||||
description = "Move static member declarations to top-level"
|
||||
)
|
||||
|
||||
private val objectDeclarationLoweringPhase = makeCustomJsModulePhase(
|
||||
{ context, module -> ObjectDeclarationLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
||||
private val objectDeclarationLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::ObjectDeclarationLowering,
|
||||
name = "ObjectDeclarationLowering",
|
||||
description = "Create lazy object instance generator functions"
|
||||
)
|
||||
|
||||
private val objectUsageLoweringPhase = makeCustomJsModulePhase(
|
||||
{ context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
||||
private val objectUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
::ObjectUsageLowering,
|
||||
name = "ObjectUsageLowering",
|
||||
description = "Transform IrGetObjectValue into instance generator call"
|
||||
)
|
||||
|
||||
val loweringList = listOf<Lowering>(
|
||||
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
|
||||
)
|
||||
|
||||
// TODO comment? Eliminate MouduleLowering's? Don't filter them here?
|
||||
val pirLowerings = loweringList.filter { it is DeclarationLowering || it is BodyLowering } + staticMembersLoweringPhase
|
||||
|
||||
// TODO `fold` -> `reduce`
|
||||
val jsPhases = namedIrModulePhase(
|
||||
name = "IrModuleLowering",
|
||||
description = "IR module lowering",
|
||||
lower = scriptRemoveReceiverLowering then
|
||||
validateIrBeforeLowering then
|
||||
testGenerationPhase then
|
||||
expectDeclarationsRemovingPhase then
|
||||
stripTypeAliasDeclarationsPhase then
|
||||
arrayConstructorPhase then
|
||||
functionInliningPhase then
|
||||
createScriptFunctionsPhase then
|
||||
provisionalFunctionExpressionPhase then
|
||||
lateinitLoweringPhase then
|
||||
tailrecLoweringPhase then
|
||||
enumClassConstructorLoweringPhase then
|
||||
sharedVariablesLoweringPhase then
|
||||
localDelegatedPropertiesLoweringPhase then
|
||||
localDeclarationsLoweringPhase then
|
||||
localClassExtractionPhase then
|
||||
innerClassesLoweringPhase then
|
||||
innerClassConstructorCallsLoweringPhase then
|
||||
propertiesLoweringPhase then
|
||||
primaryConstructorLoweringPhase then
|
||||
annotationConstructorLowering then
|
||||
initializersLoweringPhase then
|
||||
// Common prefix ends
|
||||
enumClassLoweringPhase then
|
||||
enumUsageLoweringPhase then
|
||||
suspendFunctionsLoweringPhase then
|
||||
returnableBlockLoweringPhase then
|
||||
forLoopsLoweringPhase then
|
||||
primitiveCompanionLoweringPhase then
|
||||
propertyAccessorInlinerLoweringPhase then
|
||||
foldConstantLoweringPhase then
|
||||
privateMembersLoweringPhase then
|
||||
callableReferenceLoweringPhase then
|
||||
defaultArgumentStubGeneratorPhase 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
|
||||
inlineClassLoweringPhase then
|
||||
autoboxingTransformerPhase then
|
||||
blockDecomposerLoweringPhase then
|
||||
constLoweringPhase then
|
||||
objectDeclarationLoweringPhase then
|
||||
objectUsageLoweringPhase then
|
||||
callsLoweringPhase then
|
||||
validateIrAfterLowering
|
||||
)
|
||||
lower = loweringList.drop(1).fold(loweringList[0].modulePhase) { acc: CompilerPhase<JsIrBackendContext, IrModuleFragment, IrModuleFragment>, lowering ->
|
||||
acc.then(lowering.modulePhase)
|
||||
}
|
||||
)
|
||||
@@ -0,0 +1,50 @@
|
||||
/*
|
||||
* 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.backend.common.DefaultMapping
|
||||
import org.jetbrains.kotlin.backend.common.Mapping
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
|
||||
class JsMapping : DefaultMapping() {
|
||||
val singletonFieldDescriptors = newMapping<IrClass, IrField>()
|
||||
val outerThisFieldSymbols = newMapping<IrClass, IrField>()
|
||||
val innerClassConstructors = newMapping<IrConstructor, IrConstructor>()
|
||||
val originalInnerClassPrimaryConstructorByClass = newMapping<IrClass, IrConstructor>()
|
||||
val secondaryConstructorToDelegate = newMapping<IrConstructor, IrSimpleFunction>()
|
||||
val secondaryConstructorToFactory = newMapping<IrConstructor, IrSimpleFunction>()
|
||||
val objectToGetInstanceFunction = newMapping<IrClass, IrSimpleFunction>()
|
||||
val objectToInstanceField = newMapping<IrClass, IrField>()
|
||||
val classToSyntheticPrimaryConstructor = newMapping<IrClass, IrConstructor>()
|
||||
val privateMemberToCorrespondingStatic = newMapping<IrFunction, IrSimpleFunction>()
|
||||
|
||||
val enumEntryToGetInstanceFun = newMapping<IrEnumEntry, IrSimpleFunction>()
|
||||
val enumEntryToInstanceField = newMapping<IrEnumEntry, IrField>()
|
||||
val enumConstructorToNewConstructor = newMapping<IrConstructor, IrConstructor>()
|
||||
val enumClassToCorrespondingEnumEntry = newMapping<IrClass, IrEnumEntry>()
|
||||
val enumConstructorOldToNewValueParameters = newMapping<IrValueDeclaration, IrValueParameter>()
|
||||
val enumEntryToCorrespondingField = newMapping<IrEnumEntry, IrField>()
|
||||
val enumClassToInitEntryInstancesFun = newMapping<IrClass, IrSimpleFunction>()
|
||||
|
||||
// Triggers `StageController.lazyLower` on access
|
||||
override fun <K : IrDeclaration, V> newMapping(): Mapping.Delegate<K, V> = object : Mapping.Delegate<K, V>() {
|
||||
private val map: MutableMap<K, V> = mutableMapOf()
|
||||
|
||||
override operator fun get(key: K): V? {
|
||||
stageController.lazyLower(key)
|
||||
return map[key]
|
||||
}
|
||||
|
||||
override operator fun set(key: K, value: V?) {
|
||||
stageController.lazyLower(key)
|
||||
if (value == null) {
|
||||
map.remove(key)
|
||||
} else {
|
||||
map[key] = value
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,187 @@
|
||||
/*
|
||||
* 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.IrBodyBase
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrDeclarationBase
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.util.isLocal
|
||||
|
||||
open class MutableController(val context: JsIrBackendContext, val lowerings: List<Lowering>) : StageController {
|
||||
|
||||
override var currentStage: Int = 0
|
||||
|
||||
override fun lazyLower(declaration: IrDeclaration) {
|
||||
if (declaration is IrDeclarationBase<*>) {
|
||||
while (declaration.loweredUpTo + 1 < currentStage) {
|
||||
val i = declaration.loweredUpTo + 1
|
||||
withStage(i) {
|
||||
// TODO a better way to skip declarations in external package fragments
|
||||
if (declaration.removedOn > i && declaration !in context.externalDeclarations) {
|
||||
|
||||
when (val lowering = lowerings[i - 1]) {
|
||||
is DeclarationLowering -> lowering.doApplyLoweringTo(declaration)
|
||||
is BodyLowering -> {
|
||||
// Handle local declarations in case they leak through types
|
||||
if (declaration.isLocal) {
|
||||
declaration.enclosingBody()?.let {
|
||||
withStage(i + 1) { lazyLower(it) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
declaration.loweredUpTo = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun lazyLower(body: IrBody) {
|
||||
if (body is IrBodyBase<*>) {
|
||||
for (i in (body.loweredUpTo + 1) until currentStage) {
|
||||
withStage(i) {
|
||||
if (body.container !in context.externalDeclarations) {
|
||||
val lowering = lowerings[i - 1]
|
||||
|
||||
if (lowering is BodyLowering) {
|
||||
bodyLowering {
|
||||
lowering.bodyLowering(context).lower(body, body.container)
|
||||
}
|
||||
}
|
||||
}
|
||||
body.loweredUpTo = i
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Launches a lowering and applies it's results
|
||||
private fun DeclarationLowering.doApplyLoweringTo(declaration: IrDeclarationBase<*>) {
|
||||
val parentBefore = declaration.parent
|
||||
val result = restrictTo(declaration) { this.declarationTransformer(context).transformFlat(declaration) }
|
||||
if (result != null) {
|
||||
result.forEach {
|
||||
// Some of our lowerings rely on transformDeclarationsFlat
|
||||
it.parent = parentBefore
|
||||
}
|
||||
|
||||
if (parentBefore is IrDeclarationContainer) {
|
||||
unrestrictDeclarationListsAccess {
|
||||
|
||||
// Field order matters for top level property initialization
|
||||
val correspondingProperty = when (declaration) {
|
||||
is IrSimpleFunction -> declaration.correspondingPropertySymbol?.owner
|
||||
is IrField -> declaration.correspondingPropertySymbol?.owner
|
||||
else -> null
|
||||
}
|
||||
|
||||
var index = -1
|
||||
parentBefore.declarations.forEachIndexed { i, v ->
|
||||
if (v == declaration || index == -1 && v == correspondingProperty) {
|
||||
index = i
|
||||
}
|
||||
}
|
||||
|
||||
if (index != -1 && declaration !is IrProperty) {
|
||||
if (parentBefore.declarations[index] == declaration) {
|
||||
parentBefore.declarations.removeAt(index)
|
||||
}
|
||||
parentBefore.declarations.addAll(index, result)
|
||||
} else {
|
||||
parentBefore.declarations.addAll(result)
|
||||
}
|
||||
|
||||
if (declaration.parent == parentBefore && declaration !in result) {
|
||||
declaration.removedOn = currentStage
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Finds outermost body, containing the declarations
|
||||
// Doesn't work in case of local declarations inside default arguments
|
||||
// That might be fine as those shouldn't leak
|
||||
private fun IrDeclaration.enclosingBody(): IrBody? {
|
||||
var lastBodyContainer: IrDeclaration? = null
|
||||
var parent = this.parent
|
||||
while (parent is IrDeclaration) {
|
||||
if (parent !is IrClass) {
|
||||
lastBodyContainer = parent
|
||||
}
|
||||
parent = parent.parent
|
||||
}
|
||||
return lastBodyContainer?.run {
|
||||
when (this) {
|
||||
is IrFunction -> body // TODO What about local declarations inside default arguments?
|
||||
is IrField -> initializer
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
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 = { withStage(0, block) }.withRestrictions(newRestrictedToDeclaration = null)
|
||||
|
||||
override fun <T> restrictTo(declaration: IrDeclaration, fn: () -> T): T = fn.withRestrictions(newRestrictedToDeclaration = declaration)
|
||||
|
||||
override fun <T> bodyLowering(fn: () -> T): T = fn.withRestrictions(newBodiesEnabled = true, newRestricted = true, newDeclarationListsRestricted = true)
|
||||
|
||||
override fun <T> unrestrictDeclarationListsAccess(fn: () -> T): T = fn.withRestrictions(newDeclarationListsRestricted = false)
|
||||
|
||||
override fun canModify(element: IrElement): Boolean {
|
||||
return true
|
||||
// TODO fix and enable
|
||||
// return !restricted || restrictedToDeclaration === element || element is IrPersistingElementBase<*> && element.createdOn == currentStage
|
||||
}
|
||||
|
||||
override fun canAccessDeclarationsOf(irClass: IrClass): Boolean {
|
||||
return !declarationListsRestricted || irClass.visibility == Visibilities.LOCAL && irClass !in context.extractedLocalClasses
|
||||
}
|
||||
|
||||
private var restrictedToDeclaration: IrDeclaration? = null
|
||||
// TODO flags?
|
||||
override var bodiesEnabled: Boolean = true
|
||||
private var restricted: Boolean = false
|
||||
private var declarationListsRestricted = false
|
||||
|
||||
private inline fun <T> (() -> T).withRestrictions(
|
||||
newRestrictedToDeclaration: IrDeclaration? = null,
|
||||
newBodiesEnabled: Boolean? = null,
|
||||
newRestricted: Boolean? = null,
|
||||
newDeclarationListsRestricted: Boolean? = null
|
||||
): T {
|
||||
val prev = restrictedToDeclaration
|
||||
restrictedToDeclaration = newRestrictedToDeclaration
|
||||
val wereBodiesEnabled = bodiesEnabled
|
||||
bodiesEnabled = newBodiesEnabled ?: bodiesEnabled
|
||||
val wasRestricted = restricted
|
||||
restricted = newRestricted ?: restricted
|
||||
val wereDeclarationListsRestricted = declarationListsRestricted
|
||||
declarationListsRestricted = newDeclarationListsRestricted ?: declarationListsRestricted
|
||||
try {
|
||||
return this.invoke()
|
||||
} finally {
|
||||
restrictedToDeclaration = prev
|
||||
bodiesEnabled = wereBodiesEnabled
|
||||
restricted = wasRestricted
|
||||
declarationListsRestricted = wereDeclarationListsRestricted
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -8,18 +8,16 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
import com.intellij.openapi.project.Project
|
||||
import org.jetbrains.kotlin.analyzer.AbstractAnalyzerWithCompilerReport
|
||||
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.config.CompilerConfiguration
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.generateTests
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.moveBodilessDeclarationsToSeparatePlace
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||
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.isJsExport
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationWithName
|
||||
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.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.generateTypicalIrProviderList
|
||||
@@ -29,16 +27,6 @@ import org.jetbrains.kotlin.library.KotlinLibrary
|
||||
import org.jetbrains.kotlin.library.resolver.KotlinLibraryResolveResult
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.psi.KtFile
|
||||
import org.jetbrains.kotlin.utils.DFS
|
||||
|
||||
fun sortDependencies(dependencies: Collection<IrModuleFragment>): Collection<IrModuleFragment> {
|
||||
val mapping = dependencies.map { it.descriptor to it }.toMap()
|
||||
|
||||
return DFS.topologicalOrder(dependencies) { m ->
|
||||
val descriptor = m.descriptor
|
||||
descriptor.allDependencyModules.filter { it != descriptor }.map { mapping[it] }
|
||||
}.reversed()
|
||||
}
|
||||
|
||||
class CompilerResult(
|
||||
val jsCode: String?,
|
||||
@@ -57,8 +45,11 @@ fun compile(
|
||||
mainArguments: List<String>?,
|
||||
exportedDeclarations: Set<FqName> = emptySet(),
|
||||
generateFullJs: Boolean = true,
|
||||
generateDceJs: Boolean = false
|
||||
generateDceJs: Boolean = false,
|
||||
dceDriven: Boolean = false
|
||||
): CompilerResult {
|
||||
stageController = object : StageController {}
|
||||
|
||||
val (moduleFragment: IrModuleFragment, dependencyModules, irBuiltIns, symbolTable, deserializer) =
|
||||
loadIr(project, mainModule, analyzer, configuration, allDependencies, friendDependencies)
|
||||
|
||||
@@ -93,10 +84,31 @@ fun compile(
|
||||
|
||||
moveBodilessDeclarationsToSeparatePlace(context, moduleFragment)
|
||||
|
||||
jsPhases.invokeToplevel(phaseConfig, context, moduleFragment)
|
||||
if (dceDriven) {
|
||||
|
||||
val transformer = IrModuleToJsTransformer(context, mainFunction, mainArguments)
|
||||
return transformer.generateModule(moduleFragment, generateFullJs, generateDceJs)
|
||||
// TODO we should only generate tests for the current module
|
||||
// TODO should be done incrementally
|
||||
generateTests(context, moduleFragment)
|
||||
|
||||
val controller = MutableController(context, pirLowerings)
|
||||
stageController = controller
|
||||
|
||||
controller.currentStage = controller.lowerings.size + 1
|
||||
|
||||
eliminateDeadDeclarations(moduleFragment, context, mainFunction)
|
||||
|
||||
// TODO investigate whether this is needed anymore
|
||||
stageController = object : StageController {
|
||||
override val currentStage: Int = controller.currentStage
|
||||
}
|
||||
|
||||
val transformer = IrModuleToJsTransformer(context, mainFunction, mainArguments)
|
||||
return transformer.generateModule(moduleFragment, fullJs = true, dceJs = false)
|
||||
} else {
|
||||
jsPhases.invokeToplevel(phaseConfig, context, moduleFragment)
|
||||
val transformer = IrModuleToJsTransformer(context, mainFunction, mainArguments)
|
||||
return transformer.generateModule(moduleFragment, generateFullJs, generateDceJs)
|
||||
}
|
||||
}
|
||||
|
||||
fun generateJsCode(
|
||||
|
||||
@@ -5,26 +5,32 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
|
||||
class AnnotationConstructorLowering(context: CommonBackendContext) : ClassLoweringPass {
|
||||
class AnnotationConstructorLowering(context: CommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (irClass.kind != ClassKind.ANNOTATION_CLASS) return
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrConstructor || !declaration.isPrimary) return null
|
||||
|
||||
val irClass = declaration.parentAsClass
|
||||
|
||||
if (irClass.kind != ClassKind.ANNOTATION_CLASS) return null
|
||||
|
||||
val constructor = irClass.declarations.filterIsInstance<IrConstructor>().single()
|
||||
assert(constructor.isPrimary)
|
||||
// put empty body to make sure proper initializer is generated
|
||||
constructor.body = IrBlockBodyImpl(constructor.startOffset, constructor.endOffset).apply {
|
||||
// TODO what about its previous body?
|
||||
declaration.body = IrBlockBodyImpl(declaration.startOffset, declaration.endOffset) {
|
||||
statements += IrInstanceInitializerCallImpl(startOffset, endOffset, irClass.symbol, unitType)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.AbstractValueUsageTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
@@ -18,12 +18,19 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
|
||||
// Copied and adapted from Kotlin/Native
|
||||
|
||||
class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsageTransformer(context.irBuiltIns), FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid()
|
||||
class AutoboxingTransformer(val context: JsIrBackendContext) : AbstractValueUsageTransformer(context.irBuiltIns), BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
// TODO workaround for callable references
|
||||
// Prevents from revisiting local
|
||||
if (container.parent is IrFunction) return
|
||||
|
||||
val replacement = container.transform(this, null) as IrDeclaration
|
||||
|
||||
if (container !== replacement) error("Declaration has changed: ${container}")
|
||||
|
||||
// TODO: Track & insert parents for temporary variables
|
||||
irFile.patchDeclarationParents()
|
||||
irBody.patchDeclarationParents(container as? IrDeclarationParent ?: container.parent)
|
||||
}
|
||||
|
||||
private tailrec fun IrExpression.isGetUnit(): Boolean =
|
||||
|
||||
@@ -5,8 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.isElseBranch
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
@@ -30,31 +32,56 @@ class JsBlockDecomposerLowering(val context: JsIrBackendContext) : AbstractBlock
|
||||
JsIrBuilder.buildCall(context.intrinsics.unreachable.symbol, context.irBuiltIns.nothingType)
|
||||
}
|
||||
|
||||
abstract class AbstractBlockDecomposerLowering(context: CommonBackendContext) : DeclarationContainerLoweringPass {
|
||||
abstract class AbstractBlockDecomposerLowering(
|
||||
context: CommonBackendContext
|
||||
) : BodyLoweringPass {
|
||||
|
||||
private val nothingType = context.irBuiltIns.nothingType
|
||||
|
||||
// Expression with Nothing type to be inserted in places of unreachable expression
|
||||
abstract fun unreachableExpression(): IrExpression
|
||||
|
||||
private val decomposerTransformer = BlockDecomposerTransformer(context, ::unreachableExpression)
|
||||
private val nothingType = context.irBuiltIns.nothingType
|
||||
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.transformDeclarationsFlat { declaration ->
|
||||
when (declaration) {
|
||||
is IrScript -> {
|
||||
lower(declaration)
|
||||
listOf(declaration)
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
when (container) {
|
||||
is IrFunction -> {
|
||||
container.accept(decomposerTransformer, null)
|
||||
irBody.patchDeclarationParents(container)
|
||||
}
|
||||
is IrField -> {
|
||||
container.initializer?.apply {
|
||||
|
||||
val initFunction = JsIrBuilder.buildFunction(
|
||||
container.name.asString() + "\$init\$",
|
||||
container.type,
|
||||
container.parent,
|
||||
Visibilities.PRIVATE
|
||||
)
|
||||
|
||||
val newBody = toBlockBody(initFunction)
|
||||
newBody.patchDeclarationParents(initFunction)
|
||||
initFunction.body = newBody
|
||||
|
||||
initFunction.accept(decomposerTransformer, null)
|
||||
|
||||
val lastStatement = newBody.statements.last()
|
||||
val actualParent = if (newBody.statements.size > 1 || lastStatement !is IrReturn || lastStatement.value != expression) {
|
||||
expression = JsIrBuilder.buildCall(initFunction.symbol, expression.type)
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
(container.parent as IrDeclarationContainer).declarations += initFunction
|
||||
}
|
||||
initFunction
|
||||
} else {
|
||||
container
|
||||
}
|
||||
|
||||
patchDeclarationParents(actualParent)
|
||||
}
|
||||
is IrFunction -> {
|
||||
lower(declaration)
|
||||
listOf(declaration)
|
||||
}
|
||||
is IrField -> lower(declaration, irDeclarationContainer)
|
||||
else -> listOf(declaration)
|
||||
}
|
||||
}
|
||||
|
||||
irDeclarationContainer.transformChildrenVoid(CodeCleaner())
|
||||
// irDeclarationContainer.transformChildrenVoid(CodeCleaner()) TODO
|
||||
}
|
||||
|
||||
private inner class CodeCleaner : IrElementTransformerVoid() {
|
||||
@@ -98,49 +125,13 @@ abstract class AbstractBlockDecomposerLowering(context: CommonBackendContext) :
|
||||
}
|
||||
}
|
||||
|
||||
fun lower(irScript: IrScript) {
|
||||
irScript.transform(decomposerTransformer, null)
|
||||
}
|
||||
|
||||
fun lower(irFunction: IrFunction) {
|
||||
(irFunction.body as? IrExpressionBody)?.apply {
|
||||
irFunction.body = toBlockBody(irFunction)
|
||||
}
|
||||
irFunction.accept(decomposerTransformer, null)
|
||||
}
|
||||
|
||||
private fun IrExpressionBody.toBlockBody(containingFunction: IrFunction): IrBlockBody {
|
||||
expression.patchDeclarationParents(containingFunction)
|
||||
val returnStatement = JsIrBuilder.buildReturn(containingFunction.symbol, expression, nothingType)
|
||||
return IrBlockBodyImpl(expression.startOffset, expression.endOffset).apply {
|
||||
return IrBlockBodyImpl(startOffset, endOffset) {
|
||||
expression.patchDeclarationParents(containingFunction)
|
||||
val returnStatement = JsIrBuilder.buildReturn(containingFunction.symbol, expression, nothingType)
|
||||
statements += returnStatement
|
||||
}
|
||||
}
|
||||
|
||||
fun lower(irField: IrField, container: IrDeclarationContainer): List<IrDeclaration> {
|
||||
irField.initializer?.apply {
|
||||
val initFunction = JsIrBuilder.buildFunction(
|
||||
irField.name.asString() + "\$init\$",
|
||||
expression.type,
|
||||
container,
|
||||
Visibilities.PRIVATE
|
||||
)
|
||||
|
||||
val newBody = toBlockBody(initFunction)
|
||||
newBody.patchDeclarationParents(initFunction)
|
||||
initFunction.body = newBody
|
||||
|
||||
lower(initFunction)
|
||||
|
||||
val lastStatement = newBody.statements.last()
|
||||
if (newBody.statements.size > 1 || lastStatement !is IrReturn || lastStatement.value != expression) {
|
||||
expression = JsIrBuilder.buildCall(initFunction.symbol, expression.type)
|
||||
return listOf(initFunction, irField)
|
||||
}
|
||||
}
|
||||
|
||||
return listOf(irField)
|
||||
}
|
||||
}
|
||||
|
||||
class BlockDecomposerTransformer(
|
||||
|
||||
@@ -5,8 +5,8 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.bridges.FunctionHandle
|
||||
import org.jetbrains.kotlin.backend.common.bridges.generateBridges
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
@@ -15,6 +15,7 @@ import org.jetbrains.kotlin.backend.common.ir.isMethodOfAny
|
||||
import org.jetbrains.kotlin.backend.common.ir.isSuspend
|
||||
import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.functionSignature
|
||||
@@ -23,6 +24,7 @@ import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
@@ -46,23 +48,20 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
// fun foo(t: Any?) = foo(t as Int) // Constructed bridge
|
||||
// }
|
||||
//
|
||||
class BridgesConstruction(val context: CommonBackendContext) : ClassLoweringPass {
|
||||
class BridgesConstruction(val context: CommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private val specialBridgeMethods = SpecialBridgeMethods(context)
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
irClass.declarations
|
||||
.asSequence()
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.filter { !it.isStaticMethodOfClass }
|
||||
.toList()
|
||||
.forEach { generateBridges(it, irClass) }
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrSimpleFunction || declaration.isStaticMethodOfClass || declaration.parent !is IrClass) return null
|
||||
|
||||
return generateBridges(declaration)?.let { listOf(declaration) + it }
|
||||
}
|
||||
|
||||
private fun generateBridges(function: IrSimpleFunction, irClass: IrClass) {
|
||||
private fun generateBridges(function: IrSimpleFunction): List<IrDeclaration>? {
|
||||
// equals(Any?), hashCode(), toString() never need bridges
|
||||
if (function.isMethodOfAny())
|
||||
return
|
||||
return null
|
||||
|
||||
val (specialOverride: IrSimpleFunction?, specialOverrideInfo) =
|
||||
specialBridgeMethods.findSpecialWithOverride(function) ?: Pair(null, null)
|
||||
@@ -74,6 +73,10 @@ class BridgesConstruction(val context: CommonBackendContext) : ClassLoweringPass
|
||||
signature = { FunctionAndSignature(it.function) }
|
||||
)
|
||||
|
||||
if (bridgesToGenerate.isEmpty()) return null
|
||||
|
||||
val result = mutableListOf<IrDeclaration>()
|
||||
|
||||
for ((from, to) in bridgesToGenerate) {
|
||||
if (!from.function.parentAsClass.isInterface &&
|
||||
from.function.isReal &&
|
||||
@@ -97,8 +100,10 @@ class BridgesConstruction(val context: CommonBackendContext) : ClassLoweringPass
|
||||
}
|
||||
|
||||
|
||||
irClass.declarations.add(bridge)
|
||||
result += bridge
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
// Ported from from jvm.lower.BridgeLowering
|
||||
@@ -137,36 +142,36 @@ class BridgesConstruction(val context: CommonBackendContext) : ClassLoweringPass
|
||||
extensionReceiverParameter = bridge.extensionReceiverParameter?.copyTo(this)
|
||||
valueParameters += bridge.valueParameters.map { p -> p.copyTo(this) }
|
||||
annotations += bridge.annotations
|
||||
overriddenSymbols.addAll(delegateTo.overriddenSymbols)
|
||||
overriddenSymbols.add(bridge.symbol)
|
||||
overriddenSymbols += delegateTo.overriddenSymbols
|
||||
overriddenSymbols += bridge.symbol
|
||||
}
|
||||
|
||||
context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) {
|
||||
if (specialMethodInfo != null) {
|
||||
irFunction.valueParameters.take(specialMethodInfo.argumentsToCheck).forEach {
|
||||
+irIfThen(
|
||||
context.irBuiltIns.unitType,
|
||||
irNot(irIs(irGet(it), delegateTo.valueParameters[it.index].type)),
|
||||
irReturn(specialMethodInfo.defaultValueGenerator(irFunction))
|
||||
)
|
||||
irFunction.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += context.createIrBuilder(irFunction.symbol).irBlockBody(irFunction) {
|
||||
if (specialMethodInfo != null) {
|
||||
irFunction.valueParameters.take(specialMethodInfo.argumentsToCheck).forEach {
|
||||
+irIfThen(
|
||||
context.irBuiltIns.unitType,
|
||||
irNot(irIs(irGet(it), delegateTo.valueParameters[it.index].type)),
|
||||
irReturn(specialMethodInfo.defaultValueGenerator(irFunction))
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
val call = irCall(delegateTo.symbol)
|
||||
call.dispatchReceiver = irGet(irFunction.dispatchReceiverParameter!!)
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = irCastIfNeeded(irGet(it), delegateTo.extensionReceiverParameter!!.type)
|
||||
}
|
||||
val call = irCall(delegateTo.symbol)
|
||||
call.dispatchReceiver = irGet(irFunction.dispatchReceiverParameter!!)
|
||||
irFunction.extensionReceiverParameter?.let {
|
||||
call.extensionReceiver = irCastIfNeeded(irGet(it), delegateTo.extensionReceiverParameter!!.type)
|
||||
}
|
||||
|
||||
val toTake = irFunction.valueParameters.size - if (call.isSuspend xor irFunction.isSuspend) 1 else 0
|
||||
val toTake = irFunction.valueParameters.size - if (call.isSuspend xor irFunction.isSuspend) 1 else 0
|
||||
|
||||
irFunction.valueParameters.subList(0, toTake).mapIndexed { i, valueParameter ->
|
||||
call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type))
|
||||
}
|
||||
irFunction.valueParameters.subList(0, toTake).mapIndexed { i, valueParameter ->
|
||||
call.putValueArgument(i, irCastIfNeeded(irGet(valueParameter), delegateTo.valueParameters[i].type))
|
||||
}
|
||||
|
||||
+irReturn(call)
|
||||
}.apply {
|
||||
irFunction.body = this
|
||||
+irReturn(call)
|
||||
}.statements
|
||||
}
|
||||
|
||||
return irFunction
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.BOUND_VALUE_PARAMETER
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
@@ -30,6 +30,7 @@ import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.IrTypeProjection
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.isInlined
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
@@ -42,14 +43,15 @@ data class CallableReferenceKey(
|
||||
)
|
||||
|
||||
// TODO: generate $metadata$ property and fill it with corresponding KFunction/KProperty interface
|
||||
class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class CallableReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val callableToFactoryFunction = context.callableReferencesCache
|
||||
private val newDeclarations = mutableListOf<IrDeclaration>()
|
||||
private val implicitDeclarationFile = context.implicitDeclarationFile
|
||||
private lateinit var implicitDeclarationFile: IrFile //= context.implicitDeclarationFile
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
newDeclarations.clear()
|
||||
irFile.transformChildrenVoid(CallableReferenceLowerTransformer())
|
||||
implicitDeclarationFile = container.file // TODO
|
||||
irBody.transformChildrenVoid(CallableReferenceLowerTransformer())
|
||||
implicitDeclarationFile.declarations += newDeclarations
|
||||
}
|
||||
|
||||
@@ -496,7 +498,7 @@ class CallableReferenceLowering(val context: JsIrBackendContext) : FileLoweringP
|
||||
|
||||
closureFunction.valueParameters += unboundParamDeclarations
|
||||
|
||||
val callTarget = context.ir.defaultParameterDeclarationsCache[declaration] ?: declaration
|
||||
val callTarget = declaration
|
||||
|
||||
val target = callTarget.symbol
|
||||
|
||||
|
||||
@@ -5,19 +5,14 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrTypeParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetClass
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
@@ -28,7 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.types.*
|
||||
|
||||
class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class ClassReferenceLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val intrinsics = context.intrinsics
|
||||
|
||||
private val primitiveClassesObject = context.primitiveClassesObject
|
||||
@@ -223,8 +218,8 @@ class ClassReferenceLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
)
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitGetClass(expression: IrGetClass) =
|
||||
callGetKClassFromExpression(
|
||||
returnType = expression.type,
|
||||
|
||||
@@ -5,10 +5,11 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstKind
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
@@ -70,8 +71,8 @@ class ConstTransformer(private val context: JsIrBackendContext) : IrElementTrans
|
||||
}
|
||||
}
|
||||
|
||||
class ConstLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(ConstTransformer(context))
|
||||
class ConstLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(ConstTransformer(context))
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -27,12 +27,6 @@ import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
val createScriptFunctionsPhase = makeIrModulePhase(
|
||||
::CreateScriptFunctionsPhase,
|
||||
name = "CreateScriptFunctionsPhase",
|
||||
description = "Create functions for initialize and evaluate script"
|
||||
)
|
||||
|
||||
private object SCRIPT_FUNCTION : IrDeclarationOriginImpl("SCRIPT_FUNCTION")
|
||||
|
||||
class CreateScriptFunctionsPhase(val context: CommonBackendContext) : FileLoweringPass {
|
||||
|
||||
@@ -5,16 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyParameterDeclarationsFrom
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.backend.common.lower.parents
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.toJsArrayLiteral
|
||||
@@ -26,11 +29,7 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrFieldImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedClassConstructorDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedFieldDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrInstanceInitializerCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrConstructorSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrFieldSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
@@ -40,11 +39,12 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import java.util.*
|
||||
|
||||
class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
class EnumUsageLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetEnumValue(expression: IrGetEnumValue): IrExpression {
|
||||
val enumEntry = expression.symbol.owner
|
||||
val klass = enumEntry.parent as IrClass
|
||||
@@ -54,7 +54,7 @@ class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
}
|
||||
|
||||
private fun lowerExternalEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) =
|
||||
context.enumEntryExternalToInstanceField.getOrPut(enumEntry.symbol) { createFieldForEntry(enumEntry, klass) }.let {
|
||||
context.mapping.enumEntryToInstanceField.getOrPut(enumEntry) { createFieldForEntry(enumEntry, klass) }.let {
|
||||
JsIrBuilder.buildGetField(it.symbol, classAsReceiver(klass), null, klass.defaultType)
|
||||
}
|
||||
|
||||
@@ -74,31 +74,17 @@ class EnumUsageLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = irClass
|
||||
irClass.declarations += it
|
||||
|
||||
// TODO need a way to emerge local declarations from BodyLoweringPass
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
irClass.declarations += it
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerEnumEntry(enumEntry: IrEnumEntry, klass: IrClass) =
|
||||
context.enumEntryToGetInstanceFunction.getOrPut(enumEntry.symbol) {
|
||||
JsIrBuilder.buildFunction(
|
||||
createEntryAccessorName(klass.name.identifier, enumEntry),
|
||||
returnType = enumEntry.getType(klass),
|
||||
parent = klass
|
||||
)
|
||||
}.run { JsIrBuilder.buildCall(symbol) }
|
||||
}
|
||||
|
||||
class EnumClassLowering(val context: JsIrBackendContext) : DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.transformDeclarationsFlat { declaration ->
|
||||
if (declaration is IrClass && declaration.isEnumClass &&
|
||||
!declaration.descriptor.isExpect && !declaration.isEffectivelyExternal()
|
||||
) {
|
||||
EnumClassTransformer(context, declaration).transform()
|
||||
} else null
|
||||
}
|
||||
}
|
||||
enumEntry.getInstanceFun!!.run { JsIrBuilder.buildCall(symbol) }
|
||||
}
|
||||
|
||||
|
||||
@@ -107,52 +93,30 @@ private fun createEntryAccessorName(enumName: String, enumEntry: IrEnumEntry) =
|
||||
|
||||
private fun IrEnumEntry.getType(irClass: IrClass) = (correspondingClass ?: irClass).defaultType
|
||||
|
||||
class EnumClassConstructorLowering(val context: CommonBackendContext) : DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.transformDeclarationsFlat { declaration ->
|
||||
if (declaration is IrClass && declaration.isEnumClass &&
|
||||
!declaration.descriptor.isExpect && !declaration.isEffectivelyExternal()
|
||||
) {
|
||||
EnumClassConstructorTransformer(context, declaration).transform()
|
||||
} else null
|
||||
}
|
||||
}
|
||||
}
|
||||
// Should be applied recursively
|
||||
class EnumClassConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
class EnumClassConstructorTransformer(val context: CommonBackendContext, private val irClass: IrClass) {
|
||||
private val builder = context.createIrBuilder(irClass.symbol)
|
||||
private val enumEntries = irClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||
private val loweredEnumConstructors = HashMap<IrConstructorSymbol, IrConstructor>()
|
||||
private var IrConstructor.newConstructor by context.mapping.enumConstructorToNewConstructor
|
||||
private var IrClass.correspondingEntry by context.mapping.enumClassToCorrespondingEnumEntry
|
||||
private var IrValueDeclaration.valueParameter by context.mapping.enumConstructorOldToNewValueParameters
|
||||
|
||||
fun transform(): List<IrDeclaration> {
|
||||
// Add `name` and `ordinal` parameters to enum class constructors
|
||||
lowerEnumConstructorsSignature()
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
(declaration.parent as? IrClass)?.let { irClass ->
|
||||
if (!irClass.isEnumClass || irClass.descriptor.isExpect || irClass.isEffectivelyExternal()) return null
|
||||
|
||||
// Pass these parameters to delegating constructor calls
|
||||
lowerEnumConstructorsBody()
|
||||
|
||||
// The first step creates a new `IrConstructor` with new `IrValueParameter`s so references to old `IrValueParameter`s must be replaced with new ones.
|
||||
fixReferencesToConstructorParameters()
|
||||
|
||||
// Lower `IrEnumConstructorCall`s inside of enum entry class constructors to corresponding `IrDelegatingConstructorCall`s.
|
||||
// Add `name` and `ordinal` parameters.
|
||||
lowerEnumEntryClassConstructors()
|
||||
|
||||
// Lower `IrEnumConstructorCall`s to corresponding `IrCall`s.
|
||||
// Add `name` and `ordinal` constant parameters only for calls to the "enum class" constructors ("enum entry class" constructors
|
||||
// already delegate these parameters)
|
||||
lowerEnumEntryInitializerExpression()
|
||||
|
||||
return listOf(irClass)
|
||||
}
|
||||
|
||||
private fun lowerEnumConstructorsSignature() {
|
||||
irClass.declarations.transform { declaration ->
|
||||
if (declaration is IrConstructor) {
|
||||
transformEnumConstructor(declaration, irClass)
|
||||
} else
|
||||
declaration
|
||||
// Add `name` and `ordinal` parameters to enum class constructors
|
||||
return listOf(transformEnumConstructor(declaration, irClass))
|
||||
}
|
||||
|
||||
if (declaration is IrEnumEntry) {
|
||||
declaration.correspondingClass?.let { klass ->
|
||||
klass.correspondingEntry = declaration
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun transformEnumConstructor(enumConstructor: IrConstructor, enumClass: IrClass): IrConstructor {
|
||||
@@ -177,17 +141,94 @@ class EnumClassConstructorTransformer(val context: CommonBackendContext, private
|
||||
valueParameters += JsIrBuilder.buildValueParameter("name", 0, context.irBuiltIns.stringType).also { it.parent = this }
|
||||
valueParameters += JsIrBuilder.buildValueParameter("ordinal", 1, context.irBuiltIns.intType).also { it.parent = this }
|
||||
copyParameterDeclarationsFrom(enumConstructor)
|
||||
body = enumConstructor.body
|
||||
loweredEnumConstructors[enumConstructor.symbol] = this
|
||||
|
||||
this.acceptVoid(PatchDeclarationParentsVisitor(enumClass))
|
||||
val newConstructor = this
|
||||
enumConstructor.newConstructor = this
|
||||
|
||||
enumConstructor.body?.let { oldBody ->
|
||||
body = IrBlockBodyImpl(oldBody.startOffset, oldBody.endOffset) {
|
||||
statements += (oldBody as IrBlockBody).statements
|
||||
|
||||
context.fixReferencesToConstructorParameters(enumClass, this)
|
||||
|
||||
acceptVoid(PatchDeclarationParentsVisitor(enumClass))
|
||||
|
||||
body = this
|
||||
}
|
||||
}
|
||||
|
||||
// TODO except for `fixReferencesToConstructorParameters` this code seems to be obsolete
|
||||
val oldParameters = enumConstructor.valueParameters
|
||||
val newParameters = valueParameters
|
||||
oldParameters.forEach { old ->
|
||||
// TODO Match by index?
|
||||
val new = newParameters.single { it.name == old.name }
|
||||
old.valueParameter = new
|
||||
|
||||
old.defaultValue?.let { default ->
|
||||
new.defaultValue = IrExpressionBodyImpl(default.startOffset, default.endOffset) {
|
||||
expression = default.expression
|
||||
expression.patchDeclarationParents(newConstructor)
|
||||
context.fixReferencesToConstructorParameters(enumClass, this)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// The first step creates a new `IrConstructor` with new `IrValueParameter`s so references to old `IrValueParameter`s must be replaced with new ones.
|
||||
private fun JsCommonBackendContext.fixReferencesToConstructorParameters(irClass: IrClass, body: IrBody) {
|
||||
body.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
private val builder = createIrBuilder(irClass.symbol)
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
mapping.enumConstructorOldToNewValueParameters[expression.symbol.owner]?.let {
|
||||
return builder.irGet(it)
|
||||
}
|
||||
|
||||
return super.visitGetValue(expression)
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
class EnumClassConstructorBodyTransformer(val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
private var IrConstructor.newConstructor by context.mapping.enumConstructorToNewConstructor
|
||||
private var IrClass.correspondingEntry by context.mapping.enumClassToCorrespondingEnumEntry
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
|
||||
(container.parent as? IrClass)?.let { irClass ->
|
||||
|
||||
// TODO Don't apply to everything
|
||||
context.fixReferencesToConstructorParameters(irClass, irBody)
|
||||
|
||||
if (container is IrConstructor) {
|
||||
|
||||
if (irClass.goodEnum) {
|
||||
// Pass new parameters to delegating constructor calls
|
||||
lowerEnumConstructorsBody(container)
|
||||
}
|
||||
|
||||
irClass.correspondingEntry?.let { enumEntry ->
|
||||
// Lower `IrEnumConstructorCall`s inside of enum entry class constructors to corresponding `IrDelegatingConstructorCall`s.
|
||||
// Add `name` and `ordinal` parameters.
|
||||
lowerEnumEntryClassConstructors(irClass, enumEntry, container)
|
||||
}
|
||||
}
|
||||
|
||||
if (container is IrEnumEntry) {
|
||||
// Lower `IrEnumConstructorCall`s to corresponding `IrCall`s.
|
||||
// Add `name` and `ordinal` constant parameters only for calls to the "enum class" constructors ("enum entry class" constructors
|
||||
// already delegate these parameters)
|
||||
lowerEnumEntryInitializerExpression(irClass, container)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerEnumConstructorsBody() {
|
||||
irClass.declarations.filterIsInstance<IrConstructor>().forEach {
|
||||
IrEnumClassConstructorTransformer(it).transformBody()
|
||||
}
|
||||
private fun lowerEnumConstructorsBody(constructor: IrConstructor) {
|
||||
IrEnumClassConstructorTransformer(constructor).transformBody()
|
||||
}
|
||||
|
||||
private inner class IrEnumClassConstructorTransformer(val constructor: IrConstructor) : IrElementTransformerVoid() {
|
||||
@@ -205,11 +246,7 @@ class EnumClassConstructorTransformer(val context: CommonBackendContext, private
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
var delegatingConstructor = expression.symbol.owner
|
||||
val constructorWasTransformed = delegatingConstructor.symbol in loweredEnumConstructors
|
||||
|
||||
if (constructorWasTransformed)
|
||||
delegatingConstructor = loweredEnumConstructors[delegatingConstructor.symbol]!!
|
||||
val delegatingConstructor = expression.symbol.owner. let { it.newConstructor ?: it }
|
||||
|
||||
return builder.irDelegatingConstructorCall(delegatingConstructor).apply {
|
||||
var valueArgIdx = 0
|
||||
@@ -223,41 +260,25 @@ class EnumClassConstructorTransformer(val context: CommonBackendContext, private
|
||||
}
|
||||
}
|
||||
|
||||
private fun fixReferencesToConstructorParameters() {
|
||||
val fromOldToNewParameter = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||
|
||||
loweredEnumConstructors.forEach { (oldCtorSymbol, newCtor) ->
|
||||
val oldParameters = oldCtorSymbol.owner.valueParameters
|
||||
val newParameters = newCtor.valueParameters
|
||||
|
||||
oldParameters.forEach { old ->
|
||||
fromOldToNewParameter[old.symbol] = newParameters.single { it.name == old.name }
|
||||
}
|
||||
}
|
||||
|
||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
fromOldToNewParameter[expression.symbol]?.let {
|
||||
return builder.irGet(it)
|
||||
}
|
||||
|
||||
return super.visitGetValue(expression)
|
||||
}
|
||||
})
|
||||
private fun lowerEnumEntryClassConstructors(irClass: IrClass, entry: IrEnumEntry, constructor: IrConstructor) {
|
||||
constructor.transformChildrenVoid(IrEnumEntryClassConstructorTransformer(irClass, entry, true))
|
||||
}
|
||||
|
||||
|
||||
private fun lowerEnumEntryClassConstructors() {
|
||||
for (entry in enumEntries) {
|
||||
entry.correspondingClass?.constructors?.forEach {
|
||||
it.transformChildrenVoid(IrEnumEntryClassConstructorTransformer(entry, true))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private inner class IrEnumEntryClassConstructorTransformer(val entry: IrEnumEntry, val isInsideConstructor: Boolean) :
|
||||
private inner class IrEnumEntryClassConstructorTransformer(
|
||||
val irClass: IrClass,
|
||||
val entry: IrEnumEntry,
|
||||
val isInsideConstructor: Boolean
|
||||
) :
|
||||
IrElementTransformerVoid() {
|
||||
|
||||
private val enumEntries = irClass.enumEntries
|
||||
|
||||
private val builder = context.createIrBuilder(irClass.symbol)
|
||||
|
||||
private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier)
|
||||
private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this))
|
||||
|
||||
private fun buildConstructorCall(constructor: IrConstructor) =
|
||||
if (isInsideConstructor)
|
||||
builder.irDelegatingConstructorCall(constructor)
|
||||
@@ -266,11 +287,11 @@ class EnumClassConstructorTransformer(val context: CommonBackendContext, private
|
||||
|
||||
override fun visitEnumConstructorCall(expression: IrEnumConstructorCall): IrExpression {
|
||||
var constructor = expression.symbol.owner
|
||||
val constructorWasTransformed = constructor.symbol in loweredEnumConstructors
|
||||
val constructorWasTransformed = constructor.newConstructor != null
|
||||
|
||||
// Enum entry class constructors are not transformed
|
||||
if (constructorWasTransformed)
|
||||
constructor = loweredEnumConstructors[constructor.symbol]!!
|
||||
constructor = constructor.newConstructor!!
|
||||
|
||||
return buildConstructorCall(constructor).apply {
|
||||
var valueArgIdx = 0
|
||||
@@ -287,64 +308,210 @@ class EnumClassConstructorTransformer(val context: CommonBackendContext, private
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerEnumEntryInitializerExpression() {
|
||||
for (entry in enumEntries) {
|
||||
entry.initializerExpression =
|
||||
entry.initializerExpression?.transform(IrEnumEntryClassConstructorTransformer(entry, false), null)
|
||||
}
|
||||
private fun lowerEnumEntryInitializerExpression(irClass: IrClass, entry: IrEnumEntry) {
|
||||
entry.initializerExpression =
|
||||
entry.initializerExpression?.transform(IrEnumEntryClassConstructorTransformer(irClass, entry, false), null)
|
||||
}
|
||||
|
||||
private fun IrEnumEntry.getNameExpression() = builder.irString(this.name.identifier)
|
||||
private fun IrEnumEntry.getOrdinalExpression() = builder.irInt(enumEntries.indexOf(this))
|
||||
}
|
||||
|
||||
//-------------------------------------------------------
|
||||
|
||||
private val IrClass.goodEnum: Boolean
|
||||
get() = isEnumClass && !descriptor.isExpect && !isEffectivelyExternal()
|
||||
|
||||
class EnumClassTransformer(val context: JsIrBackendContext, private val irClass: IrClass) {
|
||||
private val builder = context.createIrBuilder(irClass.symbol)
|
||||
private val enumEntries = irClass.declarations.filterIsInstance<IrEnumEntry>()
|
||||
private val enumName = irClass.name.identifier
|
||||
private val throwISESymbol = context.throwISEsymbol
|
||||
class EnumEntryInstancesLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
fun transform(): List<IrDeclaration> {
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
|
||||
// Create instance variable for each enum entry initialized with `null`
|
||||
val entryInstances = createEnumEntryInstanceVariables()
|
||||
|
||||
// Create boolean flag that indicates if entry instances were initialized.
|
||||
val entryInstancesInitializedVar = createEntryInstancesInitializedVar()
|
||||
|
||||
// Create function that initializes all enum entry instances using `IrEnumEntry.initializationExpression`.
|
||||
// It should be called on the first `IrGetEnumValue`, consecutive calls to this function will do nothing.
|
||||
val initEntryInstancesFun = createInitEntryInstancesFun(entryInstancesInitializedVar, entryInstances)
|
||||
|
||||
// Create entry instance getters. These are used to lower `IrGetEnumValue`.
|
||||
val entryGetInstanceFuns = createGetEntryInstanceFuns(initEntryInstancesFun, entryInstances)
|
||||
|
||||
// Create body for `values` and `valueOf` functions
|
||||
lowerSyntheticFunctions()
|
||||
|
||||
// Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them).
|
||||
replaceIrEntriesWithCorrespondingClasses()
|
||||
|
||||
return listOf(irClass) + entryInstances + listOf(entryInstancesInitializedVar, initEntryInstancesFun) + entryGetInstanceFuns
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrEnumEntry) {
|
||||
val irClass = declaration.parentAsClass
|
||||
if (irClass.goodEnum) {
|
||||
// Create instance variable for each enum entry initialized with `null`
|
||||
return listOf(declaration, createEnumEntryInstanceVariable(irClass, declaration))
|
||||
}
|
||||
}
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createEnumEntryInstanceVariable(irClass: IrClass, enumEntry: IrEnumEntry): IrField {
|
||||
val enumName = irClass.name.identifier
|
||||
|
||||
private fun createEnumValueOfBody(): IrBody {
|
||||
val valueOfFun = findFunctionDescriptorForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUEOF)
|
||||
val result = buildField {
|
||||
name = Name.identifier("${enumName}_${enumEntry.name.identifier}_instance")
|
||||
type = enumEntry.getType(irClass).makeNullable()
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = irClass
|
||||
val builder = context.createIrBuilder(irClass.symbol)
|
||||
initializer = builder.run { irExprBody(irImplicitCast(irNull(), type)) }
|
||||
}
|
||||
|
||||
enumEntry.correspondingField = result
|
||||
|
||||
return result
|
||||
}
|
||||
}
|
||||
|
||||
class EnumEntryInstancesBodyLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container is IrConstructor && container.constructedClass.kind == ClassKind.ENUM_ENTRY) {
|
||||
val entryClass = container.constructedClass
|
||||
val enum = entryClass.parentAsClass
|
||||
if (enum.goodEnum) {
|
||||
val entry = enum.declarations.filterIsInstance<IrEnumEntry>().find { it.correspondingClass === entryClass }!!
|
||||
(irBody as IrBlockBody).statements.add(0, context.createIrBuilder(container.symbol).run {
|
||||
irSetField(null, entry.correspondingField!!, irGet(entryClass.thisReceiver!!))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EnumClassCreateInitializerLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrClass && declaration.goodEnum) {
|
||||
// Create boolean flag that indicates if entry instances were initialized.
|
||||
val entryInstancesInitializedVar = createEntryInstancesInitializedVar(declaration)
|
||||
|
||||
// Create function that initializes all enum entry instances using `IrEnumEntry.initializationExpression`.
|
||||
// It should be called on the first `IrGetEnumValue`, consecutive calls to this function will do nothing.
|
||||
val initEntryInstancesFun = createInitEntryInstancesFun(declaration, entryInstancesInitializedVar)
|
||||
|
||||
declaration.initEntryInstancesFun = initEntryInstancesFun
|
||||
|
||||
// TODO Why not move to upper level?
|
||||
// TODO Also doesn't fit the transformFlat-ish API
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
declaration.declarations += entryInstancesInitializedVar
|
||||
declaration.declarations += initEntryInstancesFun
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createEntryInstancesInitializedVar(irClass: IrClass): IrField = buildField {
|
||||
val enumName = irClass.name.identifier
|
||||
name = Name.identifier("${enumName}_entriesInitialized")
|
||||
type = context.irBuiltIns.booleanType
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = irClass
|
||||
val builder = context.createIrBuilder(irClass.symbol)
|
||||
initializer = builder.run { irExprBody(irBoolean(false)) }
|
||||
}
|
||||
|
||||
private fun createInitEntryInstancesFun(irClass: IrClass, entryInstancesInitializedField: IrField): IrSimpleFunction =
|
||||
buildFunction(irClass, "${irClass.name.identifier}_initEntries", context.irBuiltIns.unitType).also {
|
||||
it.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += context.createIrBuilder(it.symbol).irBlockBody(it) {
|
||||
+irIfThen(irGetField(null, entryInstancesInitializedField), irReturnUnit())
|
||||
+irSetField(null, entryInstancesInitializedField, irBoolean(true))
|
||||
|
||||
irClass.enumEntries.forEach { entry ->
|
||||
entry.correspondingField?.let { instanceField ->
|
||||
+irSetField(null, instanceField, entry.initializerExpression!!.expression)
|
||||
}
|
||||
}
|
||||
}.also {
|
||||
// entry.initializerExpression can have local declarations
|
||||
it.acceptVoid(PatchDeclarationParentsVisitor(irClass))
|
||||
}.statements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildFunction(
|
||||
irClass: IrClass,
|
||||
name: String,
|
||||
returnType: IrType
|
||||
) = JsIrBuilder.buildFunction(name, returnType, irClass)
|
||||
|
||||
class EnumEntryCreateGetInstancesFunsLowering(val context: JsIrBackendContext): DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.correspondingField by context.mapping.enumEntryToCorrespondingField
|
||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrEnumEntry) {
|
||||
val irClass = declaration.parentAsClass
|
||||
if (irClass.goodEnum) {
|
||||
// Create entry instance getters. These are used to lower `IrGetEnumValue`.
|
||||
val entryGetInstanceFun = createGetEntryInstanceFun(irClass, declaration, irClass.initEntryInstancesFun!!)
|
||||
|
||||
// TODO prettify
|
||||
entryGetInstanceFun.parent = irClass.parent
|
||||
stageController.unrestrictDeclarationListsAccess {
|
||||
(irClass.parent as IrDeclarationContainer).declarations += entryGetInstanceFun
|
||||
}
|
||||
|
||||
return listOf(declaration) // TODO not null?
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun createGetEntryInstanceFun(irClass: IrClass, enumEntry: IrEnumEntry, initEntryInstancesFun: IrSimpleFunction): IrSimpleFunction {
|
||||
|
||||
return context.mapping.enumEntryToGetInstanceFun.getOrPut(enumEntry) { buildFunction(irClass, createEntryAccessorName(irClass.name.identifier, enumEntry), enumEntry.getType(irClass)) }
|
||||
.also {
|
||||
it.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += context.createIrBuilder(it.symbol).irBlockBody(it) {
|
||||
+irCall(initEntryInstancesFun)
|
||||
+irReturn(irGetField(null, enumEntry.correspondingField!!))
|
||||
}.statements
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class EnumSyntheticFunctionsLowering(val context: JsIrBackendContext): DeclarationTransformer {
|
||||
|
||||
private var IrEnumEntry.getInstanceFun by context.mapping.enumEntryToGetInstanceFun
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrSimpleFunction) {
|
||||
(declaration.body as? IrSyntheticBody)?.let { body ->
|
||||
val kind = body.kind
|
||||
|
||||
declaration.parents.filterIsInstance<IrClass>().firstOrNull { it.goodEnum }?.let { irClass ->
|
||||
declaration.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += when (kind) {
|
||||
IrSyntheticBodyKind.ENUM_VALUES -> createEnumValuesBody(declaration, irClass)
|
||||
IrSyntheticBodyKind.ENUM_VALUEOF -> createEnumValueOfBody(declaration, irClass)
|
||||
}.statements
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private val throwISESymbol = context.throwISEsymbol
|
||||
|
||||
private fun createEnumValueOfBody(valueOfFun: IrFunction, irClass: IrClass): IrBlockBody {
|
||||
val nameParameter = valueOfFun.valueParameters[0]
|
||||
val entryInstanceToFunction = context.enumEntryToGetInstanceFunction
|
||||
|
||||
return context.createIrBuilder(valueOfFun.symbol).run {
|
||||
irBlockBody {
|
||||
+irReturn(
|
||||
irWhen(
|
||||
irClass.defaultType,
|
||||
enumEntries.map {
|
||||
irClass.enumEntries.map {
|
||||
irBranch(
|
||||
irEquals(irString(it.name.identifier), irGet(nameParameter)), irCall(entryInstanceToFunction[it.symbol]!!)
|
||||
irEquals(irString(it.name.identifier), irGet(nameParameter)), irCall(it.getInstanceFun!!)
|
||||
)
|
||||
} + irElseBranch(irCall(throwISESymbol))
|
||||
)
|
||||
@@ -353,131 +520,38 @@ class EnumClassTransformer(val context: JsIrBackendContext, private val irClass:
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEnumValuesBody(): IrBody {
|
||||
val valuesFun = findFunctionDescriptorForMemberWithSyntheticBodyKind(IrSyntheticBodyKind.ENUM_VALUES)
|
||||
val entryInstanceToFunction = context.enumEntryToGetInstanceFunction
|
||||
private fun List<IrExpression>.toArrayLiteral(arrayType: IrType, elementType: IrType): IrExpression {
|
||||
val irVararg = IrVarargImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, elementType, this)
|
||||
|
||||
return IrCallImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, arrayType, context.intrinsics.arrayLiteral).apply {
|
||||
putValueArgument(0, irVararg)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEnumValuesBody(valuesFun: IrFunction, irClass: IrClass): IrBlockBody {
|
||||
val backendContext = context
|
||||
return context.createIrBuilder(valuesFun.symbol).run {
|
||||
irBlockBody {
|
||||
+irReturn(
|
||||
enumEntries.map { irCall(entryInstanceToFunction[it.symbol]!!) }
|
||||
irClass.enumEntries.map { irCall(it.getInstanceFun!!) }
|
||||
.toJsArrayLiteral(backendContext, valuesFun.returnType, irClass.defaultType)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
private fun lowerEnumEntryClassConstructors(entryInstances: List<IrVariable>) {
|
||||
for ((entry, instance) in enumEntries.zip(entryInstances)) {
|
||||
entry.correspondingClass?.constructors?.forEach {
|
||||
|
||||
// Initialize entry instance at the beginning of constructor so it can be used inside constructor body
|
||||
(it.body as? IrBlockBody)?.apply {
|
||||
statements.add(0, context.createIrBuilder(it.symbol).run {
|
||||
irSetVar(instance.symbol, irGet(entry.correspondingClass!!.thisReceiver!!))
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createEnumEntryInstanceVariables() = enumEntries.map { enumEntry ->
|
||||
val result = buildField {
|
||||
name = Name.identifier("${enumName}_${enumEntry.name.identifier}_instance")
|
||||
type = enumEntry.getType(irClass).makeNullable()
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = irClass
|
||||
initializer = builder.run { irExprBody(irImplicitCast(irNull(), type)) }
|
||||
}
|
||||
|
||||
enumEntry.correspondingClass?.constructors?.forEach {
|
||||
// Initialize entry instance at the beginning of constructor so it can be used inside constructor body
|
||||
(it.body as? IrBlockBody)?.apply {
|
||||
statements.add(0, context.createIrBuilder(it.symbol).run {
|
||||
irSetField(null, result, irGet(enumEntry.correspondingClass!!.thisReceiver!!))
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
result
|
||||
}
|
||||
|
||||
private fun replaceIrEntriesWithCorrespondingClasses() {
|
||||
irClass.transformDeclarationsFlat {
|
||||
listOfNotNull(if (it is IrEnumEntry) it.correspondingClass else it)
|
||||
}
|
||||
}
|
||||
|
||||
private fun lowerSyntheticFunctions() {
|
||||
irClass.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitSyntheticBody(body: IrSyntheticBody): IrBody {
|
||||
return when (body.kind) {
|
||||
IrSyntheticBodyKind.ENUM_VALUES -> createEnumValuesBody()
|
||||
IrSyntheticBodyKind.ENUM_VALUEOF -> createEnumValueOfBody()
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun createGetEntryInstanceFuns(
|
||||
initEntryInstancesFun: IrSimpleFunction,
|
||||
entryInstances: List<IrField>
|
||||
) = enumEntries.mapIndexed { index, enumEntry ->
|
||||
context.enumEntryToGetInstanceFunction.getOrPut(enumEntry.symbol) {
|
||||
buildFunction(createEntryAccessorName(enumName, enumEntry), enumEntry.getType(irClass))
|
||||
}.apply {
|
||||
body = context.createIrBuilder(symbol).irBlockBody(this) {
|
||||
+irCall(initEntryInstancesFun)
|
||||
+irReturn(irGetField(null, entryInstances[index]))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun createInitEntryInstancesFun(
|
||||
entryInstancesInitializedField: IrField,
|
||||
entryInstances: List<IrField>
|
||||
) = buildFunction("${enumName}_initEntries") {
|
||||
+irIfThen(irGetField(null, entryInstancesInitializedField), irReturnUnit())
|
||||
+irSetField(null, entryInstancesInitializedField, irBoolean(true))
|
||||
for ((entry, instanceField) in enumEntries.zip(entryInstances)) {
|
||||
+irSetField(null, instanceField, entry.initializerExpression!!)
|
||||
}
|
||||
}.also {
|
||||
// entry.initializerExpression can have local declarations
|
||||
it.acceptVoid(PatchDeclarationParentsVisitor(irClass))
|
||||
}
|
||||
|
||||
private fun createEntryInstancesInitializedVar(): IrField = buildField {
|
||||
name = Name.identifier("${enumName}_entriesInitialized")
|
||||
type = context.irBuiltIns.booleanType
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = irClass
|
||||
initializer = builder.run { irExprBody(irBoolean(false)) }
|
||||
}
|
||||
|
||||
|
||||
private fun findFunctionDescriptorForMemberWithSyntheticBodyKind(kind: IrSyntheticBodyKind): IrFunction =
|
||||
irClass.declarations.asSequence().filterIsInstance<IrFunction>()
|
||||
.first {
|
||||
it.body.let { body ->
|
||||
body is IrSyntheticBody && body.kind == kind
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildFunction(
|
||||
name: String,
|
||||
returnType: IrType = context.irBuiltIns.unitType
|
||||
) = JsIrBuilder.buildFunction(name, returnType, irClass)
|
||||
|
||||
private fun buildFunction(
|
||||
name: String,
|
||||
returnType: IrType = context.irBuiltIns.unitType,
|
||||
bodyBuilder: IrBlockBodyBuilder.() -> Unit
|
||||
) = JsIrBuilder.buildFunction(name, returnType, irClass).also {
|
||||
it.body = context.createIrBuilder(it.symbol).irBlockBody(it, bodyBuilder)
|
||||
}
|
||||
}
|
||||
|
||||
private val IrClass.enumEntries: List<IrEnumEntry>
|
||||
get() = declarations.filterIsInstance<IrEnumEntry>()
|
||||
|
||||
// Should be applied recursively
|
||||
class EnumClassRemoveEntriesLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
// Remove IrEnumEntry nodes from class declarations. Replace them with corresponding class declarations (if they have them).
|
||||
if (declaration is IrEnumEntry && !declaration.descriptor.isExpect && !declaration.isEffectivelyExternal()) {
|
||||
return listOfNotNull(declaration.correspondingClass)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -23,7 +23,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) : DefaultArgumentStubGenerator(context, true, true) {
|
||||
class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) : DefaultArgumentStubGenerator(context, true, true, false) {
|
||||
|
||||
override fun needSpecialDispatch(irFunction: IrSimpleFunction) = irFunction.isOverridableOrOverrides
|
||||
|
||||
@@ -54,7 +54,7 @@ class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) :
|
||||
val BIND_CALL = object : IrStatementOriginImpl("BIND_CALL") {}
|
||||
|
||||
class JsDefaultCallbackGenerator(val context: JsIrBackendContext): BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody) {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
super.visitCall(expression)
|
||||
@@ -71,7 +71,7 @@ class JsDefaultCallbackGenerator(val context: JsIrBackendContext): BodyLoweringP
|
||||
|
||||
private fun buildBoundSuperCall(irCall: IrCall): IrExpression {
|
||||
|
||||
val originalFunction = context.ir.defaultParameterDeclarationsCache.entries.first { it.value == irCall.symbol.owner }.key
|
||||
val originalFunction = context.mapping.defaultArgumentsOriginalFunction[irCall.symbol.owner]!!
|
||||
|
||||
val reference = irCall.run {
|
||||
IrFunctionReferenceImpl(
|
||||
|
||||
@@ -5,20 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.addChild
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsModule
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsQualifier
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrFileImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFileSymbol
|
||||
import org.jetbrains.kotlin.ir.util.UniqId
|
||||
import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
private val BODILESS_BUILTIN_CLASSES = listOf(
|
||||
@@ -43,24 +44,6 @@ private val BODILESS_BUILTIN_CLASSES = listOf(
|
||||
"kotlin.Function"
|
||||
).map { FqName(it) }.toSet()
|
||||
|
||||
private class DescriptorlessExternalPackageFragmentSymbol : IrExternalPackageFragmentSymbol {
|
||||
override val descriptor: PackageFragmentDescriptor
|
||||
get() = error("Operation is unsupported")
|
||||
|
||||
private var _owner: IrExternalPackageFragment? = null
|
||||
override val owner get() = _owner!!
|
||||
|
||||
override var uniqId: UniqId
|
||||
get() = error("Operation is unsupported")
|
||||
set(value) { error("Operation is unsupported") }
|
||||
|
||||
override val isBound get() = _owner != null
|
||||
|
||||
override fun bind(owner: IrExternalPackageFragment) {
|
||||
_owner = owner
|
||||
}
|
||||
}
|
||||
|
||||
private class DescriptorlessIrFileSymbol : IrFileSymbol {
|
||||
override fun bind(owner: IrFile) {
|
||||
_owner = owner
|
||||
@@ -79,33 +62,22 @@ private class DescriptorlessIrFileSymbol : IrFileSymbol {
|
||||
override val isBound get() = _owner != null
|
||||
}
|
||||
|
||||
private fun isBuiltInClass(declaration: IrDeclaration): Boolean =
|
||||
declaration is IrClass && declaration.fqNameWhenAvailable in BODILESS_BUILTIN_CLASSES
|
||||
|
||||
fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module: IrModuleFragment) {
|
||||
|
||||
val bodilessBuiltInsPackageFragment = IrExternalPackageFragmentImpl(
|
||||
DescriptorlessExternalPackageFragmentSymbol(),
|
||||
FqName("kotlin")
|
||||
)
|
||||
|
||||
context.bodilessBuiltInsPackageFragment = bodilessBuiltInsPackageFragment
|
||||
|
||||
fun isBuiltInClass(declaration: IrDeclaration): Boolean =
|
||||
declaration is IrClass && declaration.fqNameWhenAvailable in BODILESS_BUILTIN_CLASSES
|
||||
|
||||
fun collectExternalClasses(container: IrDeclarationContainer, includeCurrentLevel: Boolean): List<IrClass> {
|
||||
val externalClasses =
|
||||
container.declarations.filterIsInstance<IrClass>().filter { it.isEffectivelyExternal() }
|
||||
|
||||
val nestedExternalClasses =
|
||||
externalClasses.flatMap { collectExternalClasses(it, true) }
|
||||
|
||||
return if (includeCurrentLevel)
|
||||
externalClasses + nestedExternalClasses
|
||||
else
|
||||
nestedExternalClasses
|
||||
fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, moduleFragment: IrModuleFragment) {
|
||||
MoveBodilessDeclarationsToSeparatePlaceLowering(context).let { moveBodiless ->
|
||||
moduleFragment.files.forEach {
|
||||
moveBodiless.lower(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class MoveBodilessDeclarationsToSeparatePlaceLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
val irFile = declaration.parent as? IrFile ?: return null
|
||||
|
||||
fun lowerFile(irFile: IrFile): IrFile? {
|
||||
val externalPackageFragment by lazy {
|
||||
context.externalPackageFragment.getOrPut(irFile.symbol) {
|
||||
IrFileImpl(fileEntry = irFile.fileEntry, fqName = irFile.fqName, symbol = DescriptorlessIrFileSymbol()).also {
|
||||
@@ -114,33 +86,49 @@ fun moveBodilessDeclarationsToSeparatePlace(context: JsIrBackendContext, module:
|
||||
}
|
||||
}
|
||||
|
||||
context.externalNestedClasses += collectExternalClasses(irFile, includeCurrentLevel = false)
|
||||
|
||||
if (irFile.getJsModule() != null || irFile.getJsQualifier() != null) {
|
||||
context.packageLevelJsModules.add(irFile)
|
||||
return null
|
||||
}
|
||||
externalPackageFragment.declarations += declaration
|
||||
declaration.parent = externalPackageFragment
|
||||
|
||||
val it = irFile.declarations.iterator()
|
||||
context.packageLevelJsModules += externalPackageFragment
|
||||
|
||||
while (it.hasNext()) {
|
||||
val d = it.next() as? IrDeclarationWithName ?: continue
|
||||
declaration.collectAllExternalDeclarations()
|
||||
|
||||
return emptyList()
|
||||
} else {
|
||||
val d = declaration as? IrDeclarationWithName ?: return null
|
||||
|
||||
if (isBuiltInClass(d)) {
|
||||
it.remove()
|
||||
bodilessBuiltInsPackageFragment.addChild(d)
|
||||
context.bodilessBuiltInsPackageFragment.addChild(d)
|
||||
d.collectAllExternalDeclarations()
|
||||
|
||||
return emptyList()
|
||||
} else if (d.isEffectivelyExternal()) {
|
||||
if (d.getJsModule() != null)
|
||||
context.declarationLevelJsModules.add(d)
|
||||
|
||||
it.remove()
|
||||
externalPackageFragment.addChild(d)
|
||||
externalPackageFragment.declarations += d
|
||||
d.parent = externalPackageFragment
|
||||
|
||||
d.collectAllExternalDeclarations()
|
||||
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
return irFile
|
||||
}
|
||||
|
||||
module.files.transformFlat { irFile ->
|
||||
listOfNotNull(lowerFile(irFile))
|
||||
private fun IrDeclaration.collectAllExternalDeclarations() {
|
||||
this.accept(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
}
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclaration) {
|
||||
context.externalDeclarations.add(declaration)
|
||||
super.visitDeclaration(declaration)
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,13 +5,12 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBranchImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCatchImpl
|
||||
@@ -45,12 +44,12 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
* finally {}
|
||||
*/
|
||||
|
||||
class MultipleCatchesLowering(private val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class MultipleCatchesLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val litTrue get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, true)
|
||||
private val nothingType = context.irBuiltIns.nothingType
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transform(object : IrElementTransformer<IrDeclarationParent> {
|
||||
|
||||
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent): IrStatement {
|
||||
val parent = (declaration as? IrDeclarationParent) ?: data
|
||||
@@ -117,6 +116,6 @@ class MultipleCatchesLowering(private val context: JsIrBackendContext) : FileLow
|
||||
private fun buildImplicitCast(value: IrExpression, toType: IrType) =
|
||||
JsIrBuilder.buildTypeOperator(toType, IrTypeOperator.IMPLICIT_CAST, value, toType)
|
||||
|
||||
}, irFile)
|
||||
}, container as? IrDeclarationParent ?: container.parent)
|
||||
}
|
||||
}
|
||||
@@ -5,94 +5,104 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.backend.common.lower.irBlockBody
|
||||
import org.jetbrains.kotlin.backend.common.lower.irIfThen
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.primaryConstructor
|
||||
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class ObjectDeclarationLowering(
|
||||
val context: CommonBackendContext,
|
||||
val objectToGetInstanceFunction: MutableMap<IrClassSymbol, IrSimpleFunction>
|
||||
) : DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.transformDeclarationsFlat { declaration ->
|
||||
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
||||
return@transformDeclarationsFlat null
|
||||
val context: JsCommonBackendContext
|
||||
) : DeclarationTransformer {
|
||||
|
||||
val getInstanceFun = getOrCreateGetInstanceFunction(objectToGetInstanceFunction, declaration)
|
||||
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||
|
||||
val instanceField = buildField {
|
||||
name = Name.identifier(declaration.name.asString() + "_instance")
|
||||
type = declaration.defaultType.makeNullable()
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = declaration.parent
|
||||
initializer = null // Initialized with 'undefined'
|
||||
}
|
||||
val primaryConstructor = declaration.primaryConstructor!!
|
||||
val body = primaryConstructor.body as IrBlockBody
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
||||
return null
|
||||
|
||||
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
||||
val initInstanceField = context.createIrBuilder(primaryConstructor.symbol).buildStatement(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
irSetField(null, instanceField, irGet(declaration.thisReceiver!!))
|
||||
}
|
||||
body.statements.add(0, initInstanceField)
|
||||
val getInstanceFun = context.getOrCreateGetInstanceFunction(declaration)
|
||||
|
||||
getInstanceFun.body = context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) {
|
||||
val instanceField = buildField {
|
||||
name = Name.identifier(declaration.name.asString() + "_instance")
|
||||
type = declaration.defaultType.makeNullable()
|
||||
isStatic = true
|
||||
}.apply {
|
||||
parent = declaration.parent
|
||||
initializer = null // Initialized with 'undefined'
|
||||
}
|
||||
|
||||
declaration.instanceField = instanceField
|
||||
|
||||
val primaryConstructor = declaration.primaryConstructor ?: declaration.syntheticPrimaryConstructor!!
|
||||
|
||||
getInstanceFun.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += context.createIrBuilder(getInstanceFun.symbol).irBlockBody(getInstanceFun) {
|
||||
+irIfThen(
|
||||
irEqualsNull(irGetField(null, instanceField)),
|
||||
// Instance field initialized inside constructor
|
||||
irCallConstructor(primaryConstructor.symbol, emptyList())
|
||||
)
|
||||
+irReturn(irGetField(null, instanceField))
|
||||
}
|
||||
|
||||
listOf(declaration, instanceField, getInstanceFun)
|
||||
}.statements
|
||||
}
|
||||
|
||||
return listOf(declaration, instanceField, getInstanceFun)
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectUsageLowering(
|
||||
val context: CommonBackendContext,
|
||||
val objectToGetInstanceFunction: MutableMap<IrClassSymbol, IrSimpleFunction>
|
||||
) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
val context: JsCommonBackendContext
|
||||
) : BodyLoweringPass {
|
||||
|
||||
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container is IrConstructor && container.isPrimary) {
|
||||
val irClass = container.parentAsClass
|
||||
irClass.instanceField?.let { instanceField ->
|
||||
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
||||
val initInstanceField = context.createIrBuilder(container.symbol).buildStatement(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
irSetField(null, instanceField, irGet(irClass.thisReceiver!!))
|
||||
}
|
||||
(irBody as IrBlockBody).statements.add(0, initInstanceField)
|
||||
}
|
||||
}
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||
val obj: IrClass = expression.symbol.owner
|
||||
if (obj.isEffectivelyExternal()) return expression
|
||||
return JsIrBuilder.buildCall(getOrCreateGetInstanceFunction(objectToGetInstanceFunction, obj).symbol)
|
||||
return JsIrBuilder.buildCall(context.getOrCreateGetInstanceFunction(obj).symbol)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
fun getOrCreateGetInstanceFunction(objectToGetInstanceFunction: MutableMap<IrClassSymbol, IrSimpleFunction>, obj: IrClass) =
|
||||
objectToGetInstanceFunction.getOrPut(obj.symbol) {
|
||||
fun JsCommonBackendContext.getOrCreateGetInstanceFunction(obj: IrClass) =
|
||||
mapping.objectToGetInstanceFunction.getOrPut(obj) {
|
||||
JsIrBuilder.buildFunction(
|
||||
obj.name.asString() + "_getInstance",
|
||||
returnType = obj.defaultType,
|
||||
|
||||
@@ -5,52 +5,51 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
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.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
|
||||
// Create primary constructor if it doesn't exist
|
||||
class PrimaryConstructorLowering(context: CommonBackendContext) : ClassLoweringPass {
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
class PrimaryConstructorLowering(context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
val constructors = irClass.declarations.filterIsInstance<IrConstructor>()
|
||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||
|
||||
if (constructors.any { it.isPrimary }) return
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrClass) {
|
||||
val constructors = declaration.constructors
|
||||
|
||||
val primary = createPrimaryConstructor(irClass)
|
||||
if (constructors.any { it.isPrimary }) return null
|
||||
|
||||
val initializeTransformer = object : IrElementTransformerVoid() {
|
||||
override fun visitDeclaration(declaration: IrDeclaration) = declaration // optimize visiting
|
||||
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) = expression.run {
|
||||
IrDelegatingConstructorCallImpl(startOffset, endOffset, type, primary.symbol)
|
||||
}
|
||||
declaration.syntheticPrimaryConstructor = createPrimaryConstructor(declaration)
|
||||
}
|
||||
|
||||
constructors.forEach { it.transformChildrenVoid(initializeTransformer) }
|
||||
return null
|
||||
}
|
||||
|
||||
private object SYNTHETIC_PRIMARY_CONSTRUCTOR : IrDeclarationOriginImpl("SYNTHETIC_PRIMARY_CONSTRUCTOR")
|
||||
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
|
||||
private fun createPrimaryConstructor(irClass: IrClass): IrConstructor {
|
||||
val declaration = irClass.addConstructor {
|
||||
origin = SYNTHETIC_PRIMARY_CONSTRUCTOR
|
||||
isPrimary = true
|
||||
visibility = Visibilities.PRIVATE
|
||||
// TODO better API for declaration creation. This case doesn't fit the usual transformFlat-like API.
|
||||
val declaration = stageController.unrestrictDeclarationListsAccess {
|
||||
irClass.addConstructor {
|
||||
origin = SYNTHETIC_PRIMARY_CONSTRUCTOR
|
||||
isPrimary = true
|
||||
visibility = Visibilities.PRIVATE
|
||||
}
|
||||
}
|
||||
|
||||
declaration.body = irClass.run {
|
||||
@@ -59,4 +58,25 @@ class PrimaryConstructorLowering(context: CommonBackendContext) : ClassLoweringP
|
||||
|
||||
return declaration
|
||||
}
|
||||
}
|
||||
|
||||
class DelegateToSyntheticPrimaryConstructor(context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container is IrConstructor && !container.isPrimary) {
|
||||
container.parentAsClass.syntheticPrimaryConstructor?.let { primary ->
|
||||
val initializeTransformer = object : IrElementTransformerVoid() {
|
||||
override fun visitDeclaration(declaration: IrDeclaration) = declaration // optimize visiting
|
||||
|
||||
override fun visitInstanceInitializerCall(expression: IrInstanceInitializerCall) = expression.run {
|
||||
IrDelegatingConstructorCallImpl(startOffset, endOffset, type, primary.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
irBody.transformChildrenVoid(initializeTransformer)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -5,12 +5,13 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.descriptors.ClassDescriptor
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetObjectValue
|
||||
@@ -19,10 +20,11 @@ import org.jetbrains.kotlin.ir.types.isPrimitiveType
|
||||
import org.jetbrains.kotlin.ir.types.isString
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
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.transformChildrenVoid
|
||||
|
||||
class PrimitiveCompanionLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class PrimitiveCompanionLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
private fun getActualPrimitiveCompanion(irClass: IrClass): IrClass? {
|
||||
if (!irClass.isCompanion)
|
||||
@@ -50,13 +52,18 @@ class PrimitiveCompanionLowering(val context: JsIrBackendContext) : FileLowering
|
||||
val actualCompanion = getActualPrimitiveCompanion(companion)
|
||||
?: return null
|
||||
|
||||
for (p in actualCompanion.properties) {
|
||||
p.getter?.let { if (it.name == function.name) return it }
|
||||
p.setter?.let { if (it.name == function.name) return it }
|
||||
}
|
||||
|
||||
return actualCompanion.declarations
|
||||
.filterIsInstance<IrSimpleFunction>()
|
||||
.single { it.name == function.name }
|
||||
}
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitGetObjectValue(expression: IrGetObjectValue): IrExpression {
|
||||
val irClass = expression.symbol.owner
|
||||
val actualCompanion = getActualPrimitiveCompanion(irClass) ?: return expression
|
||||
|
||||
@@ -5,10 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -17,56 +17,143 @@ import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedSimpleFunctionDescriptor
|
||||
import org.jetbrains.kotlin.ir.descriptors.WrappedValueParameterDescriptor
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrPropertyReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrSimpleFunctionSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrValueParameterSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
private val STATIC_THIS_PARAMETER = object : IrDeclarationOriginImpl("STATIC_THIS_PARAMETER") {}
|
||||
|
||||
class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val memberMap = context.memberMap
|
||||
class PrivateMembersLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
transformPrivateDeclarations(irFile)
|
||||
transformPrivateUseSites(irFile)
|
||||
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
return when (declaration) {
|
||||
is IrSimpleFunction -> transformMemberToStaticFunction(declaration)?.let { staticFunction ->
|
||||
declaration.correspondingStatic = staticFunction
|
||||
listOf(staticFunction)
|
||||
}
|
||||
is IrProperty -> listOf(declaration.apply {
|
||||
// Detach old function from corresponding property
|
||||
this.getter = this.getter?.let { g -> transformAccessor(g) }
|
||||
this.setter = this.setter?.let { s -> transformAccessor(s) }
|
||||
})
|
||||
else -> null
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformPrivateDeclarations(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitClass(declaration: IrClass): IrStatement {
|
||||
declaration.transformChildrenVoid(this)
|
||||
declaration.declarations.transformFlat {
|
||||
when (it) {
|
||||
is IrSimpleFunction -> transformMemberToStaticFunction(it)?.let { staticFunction ->
|
||||
listOf(staticFunction)
|
||||
}
|
||||
is IrProperty -> listOf(it.apply {
|
||||
this.getter = this.getter?.let { g -> transformAccessor(g) }
|
||||
this.setter = this.setter?.let { s -> transformAccessor(s) }
|
||||
})
|
||||
else -> null
|
||||
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
|
||||
|
||||
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
|
||||
|
||||
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
|
||||
|
||||
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
|
||||
val staticFunction = function.run {
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, origin,
|
||||
symbol, name, visibility, modality,
|
||||
returnType,
|
||||
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
|
||||
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
|
||||
isOperator = isOperator
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = parent
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
}
|
||||
}
|
||||
|
||||
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
|
||||
|
||||
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
|
||||
val thisDesc = WrappedValueParameterDescriptor()
|
||||
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
|
||||
staticFunction.valueParameters += IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
STATIC_THIS_PARAMETER,
|
||||
thisSymbol,
|
||||
Name.identifier("\$this"),
|
||||
0,
|
||||
function.dispatchReceiverParameter!!.type,
|
||||
null,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).also {
|
||||
thisDesc.bind(it)
|
||||
it.parent = staticFunction
|
||||
}
|
||||
|
||||
function.correspondingStatic = staticFunction
|
||||
|
||||
staticFunction.valueParameters += function.valueParameters.map {
|
||||
// TODO better way to avoid copying default value
|
||||
it.copyTo(staticFunction, index = it.index + 1, defaultValue = null)
|
||||
}
|
||||
|
||||
val oldParameters =
|
||||
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
|
||||
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
|
||||
assert(oldParameters.size == newParameters.size)
|
||||
|
||||
val parameterMapping = oldParameters.zip(newParameters).toMap()
|
||||
|
||||
val parameterTransformer = object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
|
||||
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
|
||||
} ?: expression
|
||||
}
|
||||
|
||||
fun IrBody.copyWithParameters(): IrBody {
|
||||
return deepCopyWithSymbols(staticFunction).also {
|
||||
it.transform(parameterTransformer, null)
|
||||
}
|
||||
}
|
||||
|
||||
function.valueParameters.forEach {
|
||||
// TODO better way to avoid copying default value
|
||||
|
||||
parameterMapping[it]?.apply {
|
||||
it.defaultValue?.let { originalDefault ->
|
||||
defaultValue = IrExpressionBodyImpl(it.startOffset, it.endOffset) {
|
||||
expression = (originalDefault.copyWithParameters() as IrExpressionBody).expression
|
||||
}
|
||||
}
|
||||
return declaration
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun transformPrivateUseSites(irFile: IrFile) {
|
||||
irFile.transform(object : IrElementTransformerVoid() {
|
||||
function.body?.let {
|
||||
staticFunction.body = when (it) {
|
||||
is IrBlockBody -> IrBlockBodyImpl(it.startOffset, it.endOffset) {
|
||||
statements += (it.copyWithParameters() as IrBlockBody).statements
|
||||
}
|
||||
is IrExpressionBody -> IrExpressionBodyImpl(it.startOffset, it.endOffset) {
|
||||
expression = (it.copyWithParameters() as IrExpressionBody).expression
|
||||
}
|
||||
is IrSyntheticBody -> it
|
||||
else -> error("Unexpected body kind: ${it.javaClass}")
|
||||
}
|
||||
}
|
||||
|
||||
return staticFunction
|
||||
}
|
||||
}
|
||||
|
||||
class PrivateMemberBodiesLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
private var IrFunction.correspondingStatic by context.mapping.privateMemberToCorrespondingStatic
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
super.visitCall(expression)
|
||||
|
||||
return getOrPutStaticFunction(expression.symbol)?.let {
|
||||
return expression.symbol.owner.correspondingStatic?.let {
|
||||
transformPrivateToStaticCall(expression, it)
|
||||
} ?: expression
|
||||
}
|
||||
@@ -74,7 +161,7 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
override fun visitFunctionReference(expression: IrFunctionReference): IrExpression {
|
||||
super.visitFunctionReference(expression)
|
||||
|
||||
return getOrPutStaticFunction(expression.symbol)?.let {
|
||||
return expression.symbol.owner.correspondingStatic?.let {
|
||||
transformPrivateToStaticReference(expression) {
|
||||
IrFunctionReferenceImpl(
|
||||
expression.startOffset, expression.endOffset,
|
||||
@@ -89,8 +176,8 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
override fun visitPropertyReference(expression: IrPropertyReference): IrExpression {
|
||||
super.visitPropertyReference(expression)
|
||||
|
||||
val staticGetter = expression.getter?.let { getOrPutStaticFunction(it) }
|
||||
val staticSetter = expression.setter?.let { getOrPutStaticFunction(it) }
|
||||
val staticGetter = expression.getter?.owner?.correspondingStatic
|
||||
val staticSetter = expression.setter?.owner?.correspondingStatic
|
||||
|
||||
return if (staticGetter != null || staticSetter != null) {
|
||||
transformPrivateToStaticReference(expression) {
|
||||
@@ -147,88 +234,4 @@ class PrivateMembersLowering(val context: JsIrBackendContext) : FileLoweringPass
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun transformAccessor(accessor: IrSimpleFunction) = transformMemberToStaticFunction(accessor) ?: accessor
|
||||
|
||||
private fun transformMemberToStaticFunction(function: IrSimpleFunction): IrSimpleFunction? {
|
||||
|
||||
val staticFunction = getOrPutStaticFunction(function.symbol) ?: return null
|
||||
|
||||
// Detach old function from corresponding property
|
||||
val correspondingProperty = function.correspondingPropertySymbol?.owner
|
||||
if (correspondingProperty != null) {
|
||||
when (function) {
|
||||
correspondingProperty.getter -> correspondingProperty.getter = staticFunction
|
||||
correspondingProperty.setter -> correspondingProperty.setter = staticFunction
|
||||
}
|
||||
}
|
||||
|
||||
val oldParameters =
|
||||
listOfNotNull(function.extensionReceiverParameter, function.dispatchReceiverParameter) + function.valueParameters
|
||||
val newParameters = listOfNotNull(staticFunction.extensionReceiverParameter) + staticFunction.valueParameters
|
||||
assert(oldParameters.size == newParameters.size)
|
||||
|
||||
val parameterMapping = oldParameters.zip(newParameters).toMap()
|
||||
|
||||
staticFunction.body = function.body?.deepCopyWithSymbols(staticFunction)
|
||||
|
||||
staticFunction.transform(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue) = parameterMapping[expression.symbol.owner]?.let {
|
||||
expression.run { IrGetValueImpl(startOffset, endOffset, type, it.symbol, origin) }
|
||||
} ?: expression
|
||||
}, null)
|
||||
|
||||
return staticFunction
|
||||
}
|
||||
|
||||
private fun getOrPutStaticFunction(functionSymbol: IrFunctionSymbol): IrSimpleFunction? {
|
||||
val function = functionSymbol.owner
|
||||
if (function !is IrSimpleFunction) return null
|
||||
if (function.visibility != Visibilities.PRIVATE || function.dispatchReceiverParameter == null) return null
|
||||
|
||||
return memberMap.getOrPut(function.symbol) {
|
||||
val descriptor = WrappedSimpleFunctionDescriptor()
|
||||
val symbol = IrSimpleFunctionSymbolImpl(descriptor)
|
||||
val staticFunction = function.run {
|
||||
IrFunctionImpl(
|
||||
startOffset, endOffset, origin,
|
||||
symbol, name, visibility, modality,
|
||||
returnType,
|
||||
isInline = isInline, isExternal = isExternal, isTailrec = isTailrec, isSuspend = isSuspend, isExpect = isExpect,
|
||||
isFakeOverride = origin == IrDeclarationOrigin.FAKE_OVERRIDE,
|
||||
isOperator = isOperator
|
||||
).also {
|
||||
descriptor.bind(it)
|
||||
it.parent = parent
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
}
|
||||
}
|
||||
|
||||
staticFunction.typeParameters += function.typeParameters.map { it.deepCopyWithSymbols(staticFunction) }
|
||||
|
||||
staticFunction.extensionReceiverParameter = function.extensionReceiverParameter?.copyTo(staticFunction)
|
||||
val thisDesc = WrappedValueParameterDescriptor()
|
||||
val thisSymbol = IrValueParameterSymbolImpl(thisDesc)
|
||||
staticFunction.valueParameters += IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
STATIC_THIS_PARAMETER,
|
||||
thisSymbol,
|
||||
Name.identifier("\$this"),
|
||||
0,
|
||||
function.dispatchReceiverParameter!!.type,
|
||||
null,
|
||||
isCrossinline = false,
|
||||
isNoinline = false
|
||||
).also {
|
||||
thisDesc.bind(it)
|
||||
it.parent = staticFunction
|
||||
}
|
||||
|
||||
staticFunction.valueParameters += function.valueParameters.map { it.copyTo(staticFunction, index = it.index + 1) }
|
||||
|
||||
staticFunction
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
@@ -22,13 +22,7 @@ import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import java.lang.IllegalArgumentException
|
||||
|
||||
val scriptRemoveReceiverLowering = makeIrModulePhase(
|
||||
::ScriptRemoveReceiverLowering,
|
||||
name = "ScriptRemoveReceiver",
|
||||
description = "Remove receivers for declarations in script"
|
||||
)
|
||||
|
||||
private class ScriptRemoveReceiverLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
class ScriptRemoveReceiverLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
if (context.scriptMode) {
|
||||
irFile.declarations.transformFlat {
|
||||
|
||||
@@ -5,18 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTo
|
||||
import org.jetbrains.kotlin.backend.common.ir.copyTypeParametersFrom
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrReturnImpl
|
||||
@@ -26,38 +29,36 @@ import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.transformFlat
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
data class ConstructorPair(val delegate: IrSimpleFunction, val stub: IrSimpleFunction)
|
||||
class SecondaryConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
class SecondaryConstructorLowering(val context: JsIrBackendContext) : ClassLoweringPass {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
|
||||
private val oldCtorToNewMap = context.secondaryConstructorToFactoryCache
|
||||
if (declaration is IrConstructor && !declaration.isPrimary) {
|
||||
val irClass = declaration.parentAsClass
|
||||
|
||||
override fun lower(irClass: IrClass) {
|
||||
if (irClass.isInline) return
|
||||
if (irClass.isInline) return null
|
||||
|
||||
irClass.declarations.transformFlat {
|
||||
if (it is IrConstructor) {
|
||||
if (it.isPrimary) null else transformConstructor(it, irClass)
|
||||
} else null
|
||||
return transformConstructor(declaration, irClass)
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun transformConstructor(constructor: IrConstructor, irClass: IrClass): List<IrSimpleFunction> {
|
||||
val stubs = oldCtorToNewMap.getOrPut(constructor) {
|
||||
buildConstructorStubDeclarations(constructor, irClass)
|
||||
}
|
||||
val delegate = context.buildConstructorDelegate(constructor, irClass)
|
||||
|
||||
generateStubsBody(constructor, irClass, stubs)
|
||||
val factory = context.buildConstructorFactory(constructor, irClass)
|
||||
|
||||
return listOf(stubs.delegate, stubs.stub)
|
||||
generateStubsBody(constructor, irClass, delegate, factory)
|
||||
|
||||
return listOf(delegate, factory)
|
||||
}
|
||||
|
||||
private fun generateStubsBody(constructor: IrConstructor, irClass: IrClass, stubs: ConstructorPair) {
|
||||
private fun generateStubsBody(constructor: IrConstructor, irClass: IrClass, delegate: IrSimpleFunction, factory: IrSimpleFunction) {
|
||||
// We should split secondary constructor into two functions,
|
||||
// * Initializer which contains constructor's body and takes just created object as implicit param `$this`
|
||||
// ** This function is also delegation constructor
|
||||
@@ -76,41 +77,42 @@ class SecondaryConstructorLowering(val context: JsIrBackendContext) : ClassLower
|
||||
// val t = Object.create(Foo.prototype);
|
||||
// return Foo_init_$Init$(..., t)
|
||||
// }
|
||||
generateInitBody(constructor, irClass, stubs.delegate)
|
||||
generateFactoryBody(constructor, irClass, stubs.stub, stubs.delegate)
|
||||
generateInitBody(constructor, irClass, delegate)
|
||||
generateFactoryBody(constructor, irClass, factory, delegate)
|
||||
}
|
||||
|
||||
private fun generateFactoryBody(constructor: IrConstructor, irClass: IrClass, stub: IrSimpleFunction, delegate: IrSimpleFunction) {
|
||||
val type = irClass.defaultType
|
||||
val createFunctionIntrinsic = context.intrinsics.jsObjectCreate
|
||||
val irCreateCall = JsIrBuilder.buildCall(createFunctionIntrinsic.symbol, type, listOf(type))
|
||||
val irDelegateCall = JsIrBuilder.buildCall(delegate.symbol, type).also { call ->
|
||||
for (i in 0 until stub.typeParameters.size) {
|
||||
call.putTypeArgument(i, stub.typeParameters[i].toIrType())
|
||||
}
|
||||
stub.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
val type = irClass.defaultType
|
||||
val createFunctionIntrinsic = context.intrinsics.jsObjectCreate
|
||||
val irCreateCall = JsIrBuilder.buildCall(createFunctionIntrinsic.symbol, type, listOf(type))
|
||||
val irDelegateCall = JsIrBuilder.buildCall(delegate.symbol, type).also { call ->
|
||||
for (i in 0 until stub.typeParameters.size) {
|
||||
call.putTypeArgument(i, stub.typeParameters[i].toIrType())
|
||||
}
|
||||
|
||||
for (i in 0 until stub.valueParameters.size) {
|
||||
call.putValueArgument(i, JsIrBuilder.buildGetValue(stub.valueParameters[i].symbol))
|
||||
}
|
||||
for (i in 0 until stub.valueParameters.size) {
|
||||
call.putValueArgument(i, JsIrBuilder.buildGetValue(stub.valueParameters[i].symbol))
|
||||
}
|
||||
|
||||
call.putValueArgument(constructor.valueParameters.size, irCreateCall)
|
||||
call.putValueArgument(constructor.valueParameters.size, irCreateCall)
|
||||
}
|
||||
val irReturn = JsIrBuilder.buildReturn(stub.symbol, irDelegateCall, context.irBuiltIns.nothingType)
|
||||
|
||||
statements += irReturn
|
||||
}
|
||||
val irReturn = JsIrBuilder.buildReturn(stub.symbol, irDelegateCall, context.irBuiltIns.nothingType)
|
||||
|
||||
|
||||
stub.body = JsIrBuilder.buildBlockBody(listOf(irReturn))
|
||||
}
|
||||
|
||||
private fun generateInitBody(constructor: IrConstructor, irClass: IrClass, delegate: IrSimpleFunction) {
|
||||
val thisParam = delegate.valueParameters.last()
|
||||
val oldThisReceiver = irClass.thisReceiver!!
|
||||
val retStmt = JsIrBuilder.buildReturn(delegate.symbol, JsIrBuilder.buildGetValue(thisParam.symbol), context.irBuiltIns.nothingType)
|
||||
val statements = (constructor.body!!.deepCopyWithSymbols(delegate) as IrStatementContainer).statements
|
||||
|
||||
val constructorBody = constructor.body!!
|
||||
val oldValueParameters = constructor.valueParameters + oldThisReceiver
|
||||
|
||||
// TODO: replace parameters as well
|
||||
delegate.body = JsIrBuilder.buildBlockBody(statements + retStmt).apply {
|
||||
delegate.body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += (constructorBody.deepCopyWithSymbols(delegate) as IrStatementContainer).statements
|
||||
statements += JsIrBuilder.buildReturn(delegate.symbol, JsIrBuilder.buildGetValue(thisParam.symbol), context.irBuiltIns.nothingType)
|
||||
transformChildrenVoid(ThisUsageReplaceTransformer(delegate.symbol, oldValueParameters.zip(delegate.valueParameters).toMap()))
|
||||
}
|
||||
}
|
||||
@@ -155,7 +157,7 @@ private fun buildInitDeclaration(constructor: IrConstructor, irClass: IrClass):
|
||||
).also {
|
||||
it.copyTypeParametersFrom(constructor.parentAsClass)
|
||||
|
||||
constructor.valueParameters.mapTo(it.valueParameters) { p -> p.copyTo(it) }
|
||||
it.valueParameters = constructor.valueParameters.map { p -> p.copyTo(it) }
|
||||
it.valueParameters += JsIrBuilder.buildValueParameter("\$this", constructor.valueParameters.size, type).apply { parent = it }
|
||||
}
|
||||
}
|
||||
@@ -179,18 +181,40 @@ private fun buildFactoryDeclaration(constructor: IrConstructor, irClass: IrClass
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildConstructorStubDeclarations(constructor: IrConstructor, klass: IrClass) =
|
||||
ConstructorPair(buildInitDeclaration(constructor, klass), buildFactoryDeclaration(constructor, klass))
|
||||
|
||||
class SecondaryFactoryInjectorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.accept(CallsiteRedirectionTransformer(context), null)
|
||||
private fun JsIrBackendContext.buildConstructorDelegate(constructor: IrConstructor, klass: IrClass): IrSimpleFunction {
|
||||
return mapping.secondaryConstructorToDelegate.getOrPut(constructor) {
|
||||
buildInitDeclaration(constructor, klass)
|
||||
}
|
||||
}
|
||||
|
||||
private class CallsiteRedirectionTransformer(context: JsIrBackendContext) : IrElementTransformer<IrFunction?> {
|
||||
private fun JsIrBackendContext.buildConstructorFactory(constructor: IrConstructor, klass: IrClass): IrSimpleFunction {
|
||||
return mapping.secondaryConstructorToFactory.getOrPut(constructor) {
|
||||
buildFactoryDeclaration(constructor, klass)
|
||||
}
|
||||
}
|
||||
|
||||
class SecondaryFactoryInjectorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
// TODO Simplify? Is this needed at all?
|
||||
var parentFunction: IrFunction? = container as? IrFunction
|
||||
var declaration = container
|
||||
while (parentFunction == null) {
|
||||
val parent = declaration.parent
|
||||
|
||||
if (parent is IrFunction) {
|
||||
parentFunction = parent
|
||||
}
|
||||
|
||||
declaration = parent as? IrDeclaration ?: break
|
||||
}
|
||||
|
||||
irBody.accept(CallsiteRedirectionTransformer(context), parentFunction)
|
||||
}
|
||||
}
|
||||
|
||||
private class CallsiteRedirectionTransformer(private val context: JsIrBackendContext) : IrElementTransformer<IrFunction?> {
|
||||
|
||||
private val oldCtorToNewMap = context.secondaryConstructorToFactoryCache
|
||||
private val defaultThrowableConstructor = context.defaultThrowableCtor
|
||||
|
||||
private val IrConstructor.isSecondaryConstructorCall
|
||||
@@ -204,10 +228,8 @@ private class CallsiteRedirectionTransformer(context: JsIrBackendContext) : IrEl
|
||||
|
||||
val target = expression.symbol.owner
|
||||
return if (target.isSecondaryConstructorCall) {
|
||||
val ctor = oldCtorToNewMap.getOrPut(target) {
|
||||
buildConstructorStubDeclarations(target, target.parentAsClass)
|
||||
}
|
||||
replaceSecondaryConstructorWithFactoryFunction(expression, ctor.stub.symbol)
|
||||
val factory = context.buildConstructorFactory(target, target.parentAsClass)
|
||||
replaceSecondaryConstructorWithFactoryFunction(expression, factory.symbol)
|
||||
} else expression
|
||||
}
|
||||
|
||||
@@ -218,8 +240,8 @@ private class CallsiteRedirectionTransformer(context: JsIrBackendContext) : IrEl
|
||||
|
||||
return if (target.isSecondaryConstructorCall) {
|
||||
val klass = target.parentAsClass
|
||||
val ctor = oldCtorToNewMap.getOrPut(target) { buildConstructorStubDeclarations(target, klass) }
|
||||
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, ctor.delegate.symbol)
|
||||
val delegate = context.buildConstructorDelegate(target, klass)
|
||||
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, delegate.symbol)
|
||||
|
||||
val readThis = expression.run {
|
||||
if (data!! is IrConstructor) {
|
||||
|
||||
@@ -6,51 +6,29 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.ir.addChild
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.util.getPackageFragment
|
||||
import org.jetbrains.kotlin.ir.util.file
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitorVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.acceptChildrenVoid
|
||||
|
||||
// Move static member declarations from classes to top level
|
||||
class StaticMembersLowering(val context: CommonBackendContext) : FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
val staticDeclarationsInClasses = mutableListOf<IrDeclaration>()
|
||||
irFile.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
element.acceptChildrenVoid(this)
|
||||
class StaticMembersLowering(val context: CommonBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
(declaration.parent as? IrClass)?.let { irClass ->
|
||||
val isStatic = when (declaration) {
|
||||
is IrClass -> !declaration.isEffectivelyExternal()
|
||||
is IrSimpleFunction -> declaration.isStaticMethodOfClass && !declaration.isEffectivelyExternal()
|
||||
is IrField -> declaration.isStatic
|
||||
else -> false
|
||||
}
|
||||
|
||||
override fun visitClass(declaration: IrClass) {
|
||||
if (declaration.parent is IrClass && !declaration.isEffectivelyExternal())
|
||||
staticDeclarationsInClasses.add(declaration)
|
||||
super.visitClass(declaration)
|
||||
if (isStatic) {
|
||||
declaration.parent = irClass.file
|
||||
irClass.file.declarations += declaration
|
||||
return listOf()
|
||||
}
|
||||
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
if (declaration.parent is IrClass && declaration.isStaticMethodOfClass && !declaration.isEffectivelyExternal())
|
||||
staticDeclarationsInClasses.add(declaration)
|
||||
super.visitSimpleFunction(declaration)
|
||||
}
|
||||
|
||||
override fun visitField(declaration: IrField) {
|
||||
if (declaration.parent is IrClass && declaration.isStatic)
|
||||
staticDeclarationsInClasses.add(declaration)
|
||||
super.visitField(declaration)
|
||||
}
|
||||
})
|
||||
|
||||
for (declaration in staticDeclarationsInClasses) {
|
||||
val klass = declaration.parentAsClass
|
||||
klass.declarations.remove(declaration)
|
||||
irFile.addChild(declaration)
|
||||
declaration.parent = irFile
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -22,6 +22,14 @@ import org.jetbrains.kotlin.ir.util.fqNameWhenAvailable
|
||||
import org.jetbrains.kotlin.ir.util.isEffectivelyExternal
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
fun generateTests(context: JsIrBackendContext, moduleFragment: IrModuleFragment) {
|
||||
val generator = TestGenerator(context)
|
||||
|
||||
moduleFragment.files.forEach {
|
||||
generator.lower(it)
|
||||
}
|
||||
}
|
||||
|
||||
class TestGenerator(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
|
||||
@@ -5,21 +5,21 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.types.isNullableString
|
||||
import org.jetbrains.kotlin.ir.types.makeNotNull
|
||||
import org.jetbrains.kotlin.ir.util.isThrowable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
|
||||
class ThrowableLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class ThrowableLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val nothingNType get() = context.irBuiltIns.nothingNType
|
||||
|
||||
private val throwableConstructors = context.throwableConstructors
|
||||
@@ -33,8 +33,10 @@ class ThrowableLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
val cause: IrExpression
|
||||
)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildren(Transformer(), irFile)
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
container.parentClassOrNull.let { enclosingClass ->
|
||||
irBody.transformChildren(Transformer(), enclosingClass ?: container.file)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunctionAccessExpression.extractThrowableArguments(): ThrowableArguments =
|
||||
|
||||
@@ -5,7 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrArithBuilder
|
||||
@@ -14,11 +14,7 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isPure
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationParent
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpressionWithCopy
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperator
|
||||
import org.jetbrains.kotlin.ir.expressions.IrTypeOperatorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCompositeImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrTypeOperatorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
@@ -27,7 +23,7 @@ import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class TypeOperatorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val unit = context.irBuiltIns.unitType
|
||||
private val unitValue get() = JsIrBuilder.buildGetObjectValue(unit, unit.classifierOrFail as IrClassSymbol)
|
||||
|
||||
@@ -66,8 +62,8 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
private val litFalse: IrExpression get() = JsIrBuilder.buildBoolean(context.irBuiltIns.booleanType, false)
|
||||
private val litNull: IrExpression get() = JsIrBuilder.buildNull(context.irBuiltIns.nothingNType)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildren(object : IrElementTransformer<IrDeclarationParent> {
|
||||
override fun visitDeclaration(declaration: IrDeclaration, data: IrDeclarationParent) =
|
||||
super.visitDeclaration(declaration, declaration as? IrDeclarationParent ?: data)
|
||||
|
||||
@@ -375,6 +371,6 @@ class TypeOperatorLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
|
||||
return expression.run { IrCompositeImpl(startOffset, endOffset, toType, null, newStatements) }
|
||||
}
|
||||
}, irFile)
|
||||
}, container as? IrDeclarationParent ?: container.parent)
|
||||
}
|
||||
}
|
||||
@@ -5,11 +5,10 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.name
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
@@ -21,12 +20,12 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class VarargLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(VarargTransformer(context))
|
||||
class VarargLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(VarargTransformer(context))
|
||||
}
|
||||
}
|
||||
|
||||
private class VarargTransformer(
|
||||
val context: JsIrBackendContext
|
||||
) : IrElementTransformerVoid() {
|
||||
|
||||
@@ -5,18 +5,19 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.calls
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBody
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.util.hasAnnotation
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class CallsLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
class CallsLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val transformers = listOf(
|
||||
NumberOperatorCallsTransformer(context),
|
||||
NumberConversionCallsTransformer(context),
|
||||
@@ -30,8 +31,10 @@ class CallsLowering(val context: JsIrBackendContext) : FileLoweringPass {
|
||||
JsonIntrinsics(context)
|
||||
)
|
||||
|
||||
override fun lower(irFile: IrFile) {
|
||||
irFile.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (container is IrFunction && container.hasAnnotation(context.intrinsics.doNotIntrinsifyAnnotationSymbol)) return
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitFunction(declaration: IrFunction): IrStatement {
|
||||
if (declaration.hasAnnotation(context.intrinsics.doNotIntrinsifyAnnotationSymbol))
|
||||
return declaration
|
||||
|
||||
@@ -5,16 +5,47 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower.inline
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationContainerLoweringPass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationContainer
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.util.transformDeclarationsFlat
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrBlockBody
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrBlockBodyImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrExpressionBodyImpl
|
||||
import org.jetbrains.kotlin.ir.util.deepCopyWithSymbols
|
||||
|
||||
class RemoveInlineFunctionsWithReifiedTypeParametersLowering: DeclarationTransformer {
|
||||
|
||||
class RemoveInlineFunctionsWithReifiedTypeParametersLowering: DeclarationContainerLoweringPass {
|
||||
override fun lower(irDeclarationContainer: IrDeclarationContainer) {
|
||||
irDeclarationContainer.transformDeclarationsFlat {
|
||||
if (it is IrFunction && it.isInline && it.typeParameters.any { it.isReified }) listOf() else null
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
|
||||
if (declaration is IrFunction && declaration.isInline && declaration.typeParameters.any { it.isReified }) {
|
||||
return emptyList()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
class CopyInlineFunctionBodyLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrFunction && declaration.isInline) {
|
||||
declaration.body?.let { originalBody ->
|
||||
declaration.body = IrBlockBodyImpl(originalBody.startOffset, originalBody.endOffset) {
|
||||
statements += (originalBody.deepCopyWithSymbols(declaration) as IrBlockBody).statements
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (declaration is IrValueParameter && declaration.parent.let { it is IrFunction && it.isInline }) {
|
||||
declaration.defaultValue?.let { originalDefault ->
|
||||
declaration.defaultValue = IrExpressionBodyImpl(originalDefault.startOffset, originalDefault.endOffset) {
|
||||
expression = originalDefault.expression.deepCopyWithSymbols(declaration.parent)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
}
|
||||
@@ -50,17 +50,21 @@ class IrModuleToJsTransformer(
|
||||
|
||||
namer.merge(module.files, additionalPackages)
|
||||
|
||||
val jsCode = if (fullJs) generateWrappedModuleBody(module, exportedModule) else null
|
||||
val jsCode = if (fullJs) generateWrappedModuleBody(module, exportedModule, namer) else null
|
||||
|
||||
val dceJsCode = if (dceJs) {
|
||||
eliminateDeadDeclarations(module, backendContext, mainFunction)
|
||||
generateWrappedModuleBody(module, exportedModule)
|
||||
// Use a fresh namer for DCE so that we could compare the result with DCE-driven
|
||||
// TODO: is this mode relevant for scripting? If yes, refactor so that the external name tables are used here when needed.
|
||||
val namer = NameTables(emptyList())
|
||||
namer.merge(module.files, additionalPackages)
|
||||
generateWrappedModuleBody(module, exportedModule, namer)
|
||||
} else null
|
||||
|
||||
return CompilerResult(jsCode, dceJsCode, dts)
|
||||
}
|
||||
|
||||
private fun generateWrappedModuleBody(module: IrModuleFragment, exportedModule: ExportedModule): String {
|
||||
private fun generateWrappedModuleBody(module: IrModuleFragment, exportedModule: ExportedModule, namer: NameTables): String {
|
||||
val program = JsProgram()
|
||||
|
||||
val nameGenerator = IrNamerImpl(
|
||||
|
||||
@@ -33,6 +33,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
fun generate(): JsStatement {
|
||||
assert(!irClass.descriptor.isExpect)
|
||||
|
||||
maybeGeneratePrimaryConstructor()
|
||||
val transformer = IrDeclarationToJsTransformer()
|
||||
|
||||
// Properties might be lowered out of classes
|
||||
@@ -142,6 +143,15 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return null
|
||||
}
|
||||
|
||||
private fun maybeGeneratePrimaryConstructor() {
|
||||
if (!irClass.declarations.any { it is IrConstructor }) {
|
||||
val func = JsFunction(emptyScope, JsBlock(), "Ctor for ${irClass.name}")
|
||||
func.name = className
|
||||
classBlock.statements += func.makeStmt()
|
||||
classModel.preDeclarationBlock.statements += generateInheritanceCode()
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateInheritanceCode(): List<JsStatement> {
|
||||
if (baseClass == null || baseClass.isAny()) {
|
||||
return emptyList()
|
||||
|
||||
@@ -332,6 +332,11 @@ class NameTables(
|
||||
val signature = fieldSignature(field)
|
||||
val name = memberNames.names[signature] ?: mappedNames[mapToKey(signature)]
|
||||
|
||||
// TODO investigate
|
||||
if (name == null) {
|
||||
return sanitizeName(field.name.asString()) + "__error"
|
||||
}
|
||||
|
||||
require(name != null) {
|
||||
"Can't find name for member field ${field.render()}"
|
||||
}
|
||||
@@ -346,6 +351,14 @@ class NameTables(
|
||||
// of `invoke` functions in FunctionN interfaces
|
||||
if (name == null && signature is ParameterTypeBasedSignature && signature.suggestedName.startsWith("invoke"))
|
||||
return signature.suggestedName
|
||||
|
||||
// TODO Add a compiler flag, which enables this behaviour
|
||||
// TODO remove in DCE
|
||||
if (name == null) {
|
||||
return sanitizeName(function.name.asString()) + "__error" // TODO one case is a virtual method of an abstract class with no implementation
|
||||
}
|
||||
|
||||
// TODO report backend error
|
||||
require(name != null) {
|
||||
"Can't find name for member function ${function.render()}"
|
||||
}
|
||||
|
||||
@@ -6,6 +6,8 @@
|
||||
package org.jetbrains.kotlin.backend.jvm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.DefaultMapping
|
||||
import org.jetbrains.kotlin.backend.common.Mapping
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.lower.irThrow
|
||||
import org.jetbrains.kotlin.backend.common.phaser.PhaseConfig
|
||||
@@ -32,7 +34,6 @@ import org.jetbrains.kotlin.ir.builders.irNull
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrConstructorImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionReference
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
@@ -58,6 +59,9 @@ class JvmBackendContext(
|
||||
) : CommonBackendContext {
|
||||
override val transformedFunction: MutableMap<IrFunctionSymbol, IrSimpleFunctionSymbol>
|
||||
get() = TODO("not implemented")
|
||||
|
||||
override val extractedLocalClasses: MutableSet<IrClass> = hashSetOf()
|
||||
|
||||
override val scriptMode: Boolean = false
|
||||
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||
|
||||
@@ -68,6 +72,8 @@ class JvmBackendContext(
|
||||
override val declarationFactory: JvmDeclarationFactory = JvmDeclarationFactory(methodSignatureMapper)
|
||||
override val sharedVariablesManager = JvmSharedVariablesManager(state.module, builtIns, irBuiltIns)
|
||||
|
||||
override val mapping: Mapping = DefaultMapping()
|
||||
|
||||
val psiErrorBuilder = PsiErrorBuilder(psiSourceManager, state.diagnostics)
|
||||
|
||||
override val ir = JvmIr(irModuleFragment, this.symbolTable)
|
||||
|
||||
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.*
|
||||
import org.jetbrains.kotlin.backend.common.lower.loops.forLoopsPhase
|
||||
import org.jetbrains.kotlin.backend.common.lower.optimizations.foldConstantLoweringPhase
|
||||
import org.jetbrains.kotlin.backend.common.phaser.*
|
||||
import org.jetbrains.kotlin.backend.jvm.ir.getJvmVisibilityOfDefaultArgumentStub
|
||||
import org.jetbrains.kotlin.backend.jvm.lower.*
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibility
|
||||
@@ -79,9 +80,21 @@ private val expectDeclarationsRemovingPhase = makeIrModulePhase<JvmBackendContex
|
||||
description = "Remove expect declaration from module fragment"
|
||||
)
|
||||
|
||||
private val lateinitPhase = makeIrFilePhase(
|
||||
::LateinitLowering,
|
||||
name = "Lateinit",
|
||||
private val lateinitNullableFieldsPhase = makeIrFilePhase(
|
||||
::NullableFieldsForLateinitCreationLowering,
|
||||
name = "LateinitNullableFields",
|
||||
description = "Create nullable fields for lateinit properties"
|
||||
)
|
||||
|
||||
private val lateinitDeclarationLoweringPhase = makeIrFilePhase(
|
||||
::NullableFieldsDeclarationLowering,
|
||||
name = "LateinitDeclarations",
|
||||
description = "Reference nullable fields from properties and getters + insert checks"
|
||||
)
|
||||
|
||||
private val lateinitUsageLoweringPhase = makeIrFilePhase(
|
||||
::LateinitUsageLowering,
|
||||
name = "LateinitUsage",
|
||||
description = "Insert checks for lateinit field references"
|
||||
)
|
||||
|
||||
@@ -150,11 +163,18 @@ private val defaultArgumentStubPhase = makeIrFilePhase(
|
||||
prerequisite = setOf(localDeclarationsPhase)
|
||||
)
|
||||
|
||||
private val defaultArgumentCleanerPhase = makeIrFilePhase(
|
||||
{ context: JvmBackendContext -> DefaultParameterCleaner(context, replaceDefaultValuesWithStubs = true) },
|
||||
name = "DefaultParameterCleaner",
|
||||
description = "Replace default values arguments with stubs",
|
||||
prerequisite = setOf(defaultArgumentStubPhase)
|
||||
)
|
||||
|
||||
private val defaultArgumentInjectorPhase = makeIrFilePhase(
|
||||
::JvmDefaultParameterInjector,
|
||||
name = "DefaultParameterInjector",
|
||||
description = "Transform calls with default arguments into calls to stubs",
|
||||
prerequisite = setOf(defaultArgumentStubPhase, callableReferencePhase, inlineCallableReferenceToLambdaPhase)
|
||||
prerequisite = setOf(callableReferencePhase, inlineCallableReferenceToLambdaPhase)
|
||||
)
|
||||
|
||||
private val interfacePhase = makeIrFilePhase(
|
||||
@@ -171,6 +191,13 @@ private val innerClassesPhase = makeIrFilePhase(
|
||||
prerequisite = setOf(localDeclarationsPhase)
|
||||
)
|
||||
|
||||
private val innerClassesMemberBodyPhase = makeIrFilePhase(
|
||||
::InnerClassesMemberBodyLowering,
|
||||
name = "InnerClassesMemberBody",
|
||||
description = "Replace `this` with 'outer this' field references",
|
||||
prerequisite = setOf(innerClassesPhase)
|
||||
)
|
||||
|
||||
private val staticInitializersPhase = makeIrFilePhase(
|
||||
::StaticInitializersLowering,
|
||||
name = "StaticInitializers",
|
||||
@@ -178,14 +205,21 @@ private val staticInitializersPhase = makeIrFilePhase(
|
||||
)
|
||||
|
||||
private val initializersPhase = makeIrFilePhase<JvmBackendContext>(
|
||||
{ context ->
|
||||
object : InitializersLowering(context) {
|
||||
override fun shouldEraseFieldInitializer(irField: IrField): Boolean =
|
||||
irField.constantValue(context) == null
|
||||
}
|
||||
},
|
||||
::InitializersLowering,
|
||||
name = "Initializers",
|
||||
description = "Merge init blocks and field initializers into constructors",
|
||||
// Depends on local class extraction, because otherwise local classes in initializers will be copied into each constructor.
|
||||
prerequisite = setOf(jvmLocalClassExtractionPhase)
|
||||
)
|
||||
|
||||
private val initializersCleanupPhase = makeIrFilePhase<JvmBackendContext>(
|
||||
{ context ->
|
||||
InitializersCleanupLowering(context) {
|
||||
it.constantValue(context) == null && (!it.isStatic || it.correspondingPropertySymbol?.owner?.isConst != true)
|
||||
}
|
||||
},
|
||||
name = "InitializersCleanup",
|
||||
description = "Remove non-static anonymous initializers and non-constant non-static field init expressions",
|
||||
stickyPostconditions = setOf(fun(irFile: IrFile) {
|
||||
irFile.acceptVoid(object : IrElementVisitorVoid {
|
||||
override fun visitElement(element: IrElement) {
|
||||
@@ -197,8 +231,7 @@ private val initializersPhase = makeIrFilePhase<JvmBackendContext>(
|
||||
}
|
||||
})
|
||||
}),
|
||||
// Depends on local class extraction, because otherwise local classes in initializers will be copied into each constructor.
|
||||
prerequisite = setOf(jvmLocalClassExtractionPhase)
|
||||
prerequisite = setOf(initializersPhase)
|
||||
)
|
||||
|
||||
private val returnableBlocksPhase = makeIrFilePhase(
|
||||
@@ -235,7 +268,9 @@ private val jvmFilePhases =
|
||||
arrayConstructorPhase then
|
||||
checkNotNullPhase then
|
||||
|
||||
lateinitPhase then
|
||||
lateinitNullableFieldsPhase then
|
||||
lateinitDeclarationLoweringPhase then
|
||||
lateinitUsageLoweringPhase then
|
||||
|
||||
moveOrCopyCompanionObjectFieldsPhase then
|
||||
inlineCallableReferenceToLambdaPhase then
|
||||
@@ -274,6 +309,7 @@ private val jvmFilePhases =
|
||||
|
||||
defaultArgumentStubPhase then
|
||||
defaultArgumentInjectorPhase then
|
||||
defaultArgumentCleanerPhase then
|
||||
|
||||
interfacePhase then
|
||||
inheritedDefaultMethodsOnClassesPhase then
|
||||
@@ -285,6 +321,7 @@ private val jvmFilePhases =
|
||||
addContinuationPhase then
|
||||
|
||||
innerClassesPhase then
|
||||
innerClassesMemberBodyPhase then
|
||||
innerClassConstructorCallsPhase then
|
||||
|
||||
makePatchParentsPhase(2) then
|
||||
@@ -293,6 +330,7 @@ private val jvmFilePhases =
|
||||
objectClassPhase then
|
||||
staticInitializersPhase then
|
||||
initializersPhase then
|
||||
initializersCleanupPhase then
|
||||
collectionStubMethodLowering then
|
||||
functionNVarargBridgePhase then
|
||||
bridgePhase then
|
||||
|
||||
@@ -39,6 +39,7 @@ class JvmDeclarationFactory(
|
||||
private val interfaceCompanionFieldDeclarations = HashMap<IrSymbolOwner, IrField>()
|
||||
private val outerThisDeclarations = HashMap<IrClass, IrField>()
|
||||
private val innerClassConstructors = HashMap<IrConstructor, IrConstructor>()
|
||||
private val originalInnerClassPrimaryConstructorByClass = HashMap<IrClass, IrConstructor>()
|
||||
private val staticBackingFields = HashMap<IrProperty, IrField>()
|
||||
|
||||
private val defaultImplsMethods = HashMap<IrSimpleFunction, IrSimpleFunction>()
|
||||
@@ -74,13 +75,24 @@ class JvmDeclarationFactory(
|
||||
}
|
||||
|
||||
override fun getInnerClassConstructorWithOuterThisParameter(innerClassConstructor: IrConstructor): IrConstructor {
|
||||
assert((innerClassConstructor.parent as IrClass).isInner) { "Class is not inner: ${(innerClassConstructor.parent as IrClass).dump()}" }
|
||||
val innerClass = innerClassConstructor.parent as IrClass
|
||||
assert(innerClass.isInner) { "Class is not inner: ${(innerClassConstructor.parent as IrClass).dump()}" }
|
||||
|
||||
return innerClassConstructors.getOrPut(innerClassConstructor) {
|
||||
createInnerClassConstructorWithOuterThisParameter(innerClassConstructor)
|
||||
}.also {
|
||||
if (innerClassConstructor.isPrimary) {
|
||||
originalInnerClassPrimaryConstructorByClass[innerClass] = innerClassConstructor
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun getInnerClassOriginalPrimaryConstructorOrNull(innerClass: IrClass): IrConstructor? {
|
||||
assert(innerClass.isInner) { "Class is not inner: $innerClass" }
|
||||
|
||||
return originalInnerClassPrimaryConstructorByClass[innerClass]
|
||||
}
|
||||
|
||||
private fun createInnerClassConstructorWithOuterThisParameter(oldConstructor: IrConstructor): IrConstructor {
|
||||
val newDescriptor = WrappedClassConstructorDescriptor(oldConstructor.descriptor.annotations)
|
||||
return IrConstructorImpl(
|
||||
@@ -97,7 +109,7 @@ class JvmDeclarationFactory(
|
||||
isExpect = oldConstructor.isExpect
|
||||
).apply {
|
||||
newDescriptor.bind(this)
|
||||
annotations.addAll(oldConstructor.annotations.map { it.deepCopyWithSymbols(this) })
|
||||
annotations = oldConstructor.annotations.map { it.deepCopyWithSymbols(this) }
|
||||
parent = oldConstructor.parent
|
||||
returnType = oldConstructor.returnType
|
||||
copyTypeParametersFrom(oldConstructor)
|
||||
@@ -117,9 +129,7 @@ class JvmDeclarationFactory(
|
||||
outerThisDescriptor.bind(it)
|
||||
it.parent = this
|
||||
}
|
||||
valueParameters.add(outerThisValueParameter)
|
||||
|
||||
oldConstructor.valueParameters.mapTo(valueParameters) { it.copyTo(this, index = it.index + 1) }
|
||||
valueParameters = listOf(outerThisValueParameter) + oldConstructor.valueParameters.map { it.copyTo(this, index = it.index + 1) }
|
||||
metadata = oldConstructor.metadata
|
||||
}
|
||||
}
|
||||
@@ -267,9 +277,9 @@ class JvmDeclarationFactory(
|
||||
).apply {
|
||||
descriptor.bind(this)
|
||||
parent = irClass
|
||||
overriddenSymbols.addAll(fakeOverride.overriddenSymbols)
|
||||
overriddenSymbols = fakeOverride.overriddenSymbols
|
||||
copyParameterDeclarationsFrom(fakeOverride)
|
||||
annotations.addAll(fakeOverride.annotations)
|
||||
annotations = fakeOverride.annotations
|
||||
fakeOverride.correspondingPropertySymbol?.owner?.let { fakeOverrideProperty ->
|
||||
// NB: property is only generated for the sake of the type mapper.
|
||||
// If both setter and getter are present, original property will be duplicated.
|
||||
|
||||
@@ -58,7 +58,7 @@ class JvmSharedVariablesManager(
|
||||
}.apply {
|
||||
parent = jvmInternalPackage
|
||||
jvmInternalPackage.addChild(this)
|
||||
superTypes.add(irBuiltIns.anyType)
|
||||
superTypes += irBuiltIns.anyType
|
||||
}
|
||||
|
||||
private abstract class RefProvider {
|
||||
@@ -96,7 +96,7 @@ class JvmSharedVariablesManager(
|
||||
}.apply {
|
||||
parent = refNamespaceClass
|
||||
refNamespaceClass.addMember(this)
|
||||
superTypes.add(irBuiltIns.anyType)
|
||||
superTypes += irBuiltIns.anyType
|
||||
thisReceiver = buildValueParameter {
|
||||
type = IrSimpleTypeImpl(symbol, hasQuestionMark = false, arguments = emptyList(), annotations = emptyList())
|
||||
name = Name.identifier("$this")
|
||||
@@ -118,7 +118,7 @@ class JvmSharedVariablesManager(
|
||||
name = Name.identifier("ObjectRef")
|
||||
}.apply {
|
||||
val irClass = this
|
||||
typeParameters.add(
|
||||
typeParameters +=
|
||||
IrTypeParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
SHARED_VARIABLE_ORIGIN,
|
||||
@@ -132,10 +132,9 @@ class JvmSharedVariablesManager(
|
||||
parent = irClass
|
||||
superTypes.add(irBuiltIns.anyNType)
|
||||
}
|
||||
)
|
||||
parent = refNamespaceClass
|
||||
refNamespaceClass.addMember(this)
|
||||
superTypes.add(irBuiltIns.anyType)
|
||||
superTypes += irBuiltIns.anyType
|
||||
thisReceiver = buildValueParameter {
|
||||
type = IrSimpleTypeImpl(
|
||||
symbol,
|
||||
|
||||
@@ -138,7 +138,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
copyAttributes(info.reference)
|
||||
copyTypeParametersFrom(info.function)
|
||||
val functionNClass = context.ir.symbols.getJvmFunctionClass(info.arity + 1)
|
||||
superTypes.add(
|
||||
superTypes +=
|
||||
IrSimpleTypeImpl(
|
||||
functionNClass,
|
||||
hasQuestionMark = false,
|
||||
@@ -147,7 +147,6 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
.map { makeTypeProjection(it, Variance.INVARIANT) },
|
||||
annotations = emptyList()
|
||||
)
|
||||
)
|
||||
|
||||
addField(COROUTINE_LABEL_FIELD_NAME, context.irBuiltIns.intType)
|
||||
|
||||
@@ -217,7 +216,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
Modality.FINAL,
|
||||
origin = JvmLoweredDeclarationOrigin.FOR_INLINE_STATE_MACHINE_TEMPLATE
|
||||
).apply {
|
||||
invokeSuspend.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
|
||||
valueParameters += invokeSuspend.valueParameters.map { it.copyTo(this) }
|
||||
}.also { it.copySuspendLambdaBodyFrom(irFunction, receiverField, fields) }
|
||||
}
|
||||
|
||||
@@ -268,8 +267,8 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
modality: Modality = Modality.FINAL
|
||||
): IrSimpleFunction =
|
||||
addFunction(function.name.asString(), function.returnType, modality).apply {
|
||||
overriddenSymbols.add(function.symbol)
|
||||
function.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
|
||||
overriddenSymbols += function.symbol
|
||||
valueParameters += function.valueParameters.map { it.copyTo(this) }
|
||||
}
|
||||
|
||||
// Invoke function in lambdas is responsible for
|
||||
@@ -394,7 +393,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
visibility = newVisibility
|
||||
}.also { irClass ->
|
||||
irClass.createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
irClass.superTypes.add(defaultType)
|
||||
irClass.superTypes += defaultType
|
||||
|
||||
irClass.parent = parent
|
||||
}
|
||||
@@ -622,7 +621,7 @@ private class AddContinuationLowering(private val context: JvmBackendContext) :
|
||||
copyTypeParameters(view.typeParameters)
|
||||
dispatchReceiverParameter = view.dispatchReceiverParameter?.copyTo(this)
|
||||
extensionReceiverParameter = view.extensionReceiverParameter?.copyTo(this)
|
||||
view.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
|
||||
valueParameters += view.valueParameters.map { it.copyTo(this) }
|
||||
body = view.copyBodyTo(this)
|
||||
copyAttributes(view)
|
||||
}
|
||||
@@ -758,15 +757,15 @@ private fun IrFunction.suspendFunctionStub(context: JvmBackendContext): IrFuncti
|
||||
}.also { function ->
|
||||
function.parent = parent
|
||||
|
||||
function.annotations.addAll(annotations)
|
||||
function.annotations += annotations
|
||||
function.metadata = metadata
|
||||
|
||||
function.copyAttributes(this)
|
||||
function.copyTypeParametersFrom(this)
|
||||
|
||||
if (origin != JvmLoweredDeclarationOrigin.DEFAULT_IMPLS_BRIDGE) {
|
||||
function.overriddenSymbols
|
||||
.addAll(overriddenSymbols.map { it.owner.suspendFunctionViewOrStub(context).symbol as IrSimpleFunctionSymbol })
|
||||
function.overriddenSymbols +=
|
||||
overriddenSymbols.map { it.owner.suspendFunctionViewOrStub(context).symbol as IrSimpleFunctionSymbol }
|
||||
}
|
||||
|
||||
// Copy the value parameters and insert the continuation parameter. The continuation parameter
|
||||
|
||||
@@ -137,11 +137,10 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
|
||||
irClass.hasAnnotation(FqName("java.lang.annotation.Documented"))
|
||||
) return
|
||||
|
||||
irClass.annotations.add(
|
||||
irClass.annotations +=
|
||||
IrConstructorCallImpl.fromSymbolOwner(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, documentedConstructor.returnType, documentedConstructor.symbol, 0
|
||||
)
|
||||
)
|
||||
}
|
||||
|
||||
private val annotationRetentionMap = mapOf(
|
||||
@@ -158,7 +157,7 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
|
||||
val kotlinRetentionPolicy = kotlinRetentionPolicyName?.let { KotlinRetention.valueOf(it) }
|
||||
val javaRetentionPolicy = kotlinRetentionPolicy?.let { annotationRetentionMap[it] } ?: rpRuntime
|
||||
|
||||
irClass.annotations.add(
|
||||
irClass.annotations +=
|
||||
IrConstructorCallImpl.fromSymbolOwner(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, retentionConstructor.returnType, retentionConstructor.symbol, 0
|
||||
).apply {
|
||||
@@ -169,7 +168,6 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
|
||||
)
|
||||
)
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private val jvm6TargetMap = mutableMapOf(
|
||||
@@ -221,13 +219,12 @@ private class AdditionalClassAnnotationLowering(private val context: JvmBackendC
|
||||
)
|
||||
}
|
||||
|
||||
irClass.annotations.add(
|
||||
irClass.annotations +=
|
||||
IrConstructorCallImpl.fromSymbolOwner(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET, targetConstructor.returnType, targetConstructor.symbol, 0
|
||||
).apply {
|
||||
putValueArgument(0, vararg)
|
||||
}
|
||||
)
|
||||
// TODO
|
||||
}
|
||||
}
|
||||
|
||||
@@ -205,8 +205,8 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
// For lambda classes, we move override from the `invoke` function to its bridge. This will allow us to avoid boxing
|
||||
// the return type of `invoke` in codegen, in case lambda's return type is primitive.
|
||||
if (method.name == OperatorNameConventions.INVOKE && irClass.origin == JvmLoweredDeclarationOrigin.LAMBDA_IMPL) {
|
||||
target.overriddenSymbols.remove(method.symbol)
|
||||
bridge.overriddenSymbols.add(method.symbol)
|
||||
target.overriddenSymbols = target.overriddenSymbols.filter { it != method.symbol }
|
||||
bridge.overriddenSymbols += method.symbol
|
||||
}
|
||||
|
||||
signaturesToSkip.add(signature)
|
||||
@@ -227,7 +227,7 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
parent = this@copyRenamingTo.parent
|
||||
dispatchReceiverParameter = this@copyRenamingTo.dispatchReceiverParameter?.copyTo(this)
|
||||
extensionReceiverParameter = this@copyRenamingTo.extensionReceiverParameter?.copyTo(this)
|
||||
valueParameters.addAll(this@copyRenamingTo.valueParameters.map { it.copyTo(this) })
|
||||
valueParameters = this@copyRenamingTo.valueParameters.map { it.copyTo(this) }
|
||||
}
|
||||
}
|
||||
|
||||
@@ -267,8 +267,8 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
dispatchReceiverParameter = irClass.thisReceiver?.copyTo(this, type = irClass.defaultType)
|
||||
extensionReceiverParameter = signatureFunction.extensionReceiverParameter
|
||||
?.copyWithTypeErasure(this)
|
||||
signatureFunction.valueParameters.mapIndexed { i, param ->
|
||||
valueParameters.add(i, param.copyWithTypeErasure(this))
|
||||
valueParameters = signatureFunction.valueParameters.map { param ->
|
||||
param.copyWithTypeErasure(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -304,12 +304,13 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
body = irBlockBody {
|
||||
// Change the parameter types to be Any? so that null checks are not generated. The checks
|
||||
// we insert here make them superfluous.
|
||||
val newValueParameters = ArrayList(valueParameters)
|
||||
argumentsToCheck.forEach {
|
||||
val parameterType = it.type
|
||||
if (!parameterType.isNullable()) {
|
||||
val newParameter = it.copyTo(this@rewriteSpecialMethodBody, type = context.irBuiltIns.anyNType)
|
||||
variableMap.put(valueParameters[it.index], newParameter)
|
||||
valueParameters[it.index] = newParameter
|
||||
newValueParameters[it.index] = newParameter
|
||||
addParameterTypeCheck(
|
||||
newParameter,
|
||||
parameterType,
|
||||
@@ -318,6 +319,7 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
)
|
||||
}
|
||||
}
|
||||
valueParameters = newValueParameters
|
||||
// After the checks, insert the orignal method body.
|
||||
if (body is IrExpressionBody) {
|
||||
+irReturn((body as IrExpressionBody).expression)
|
||||
@@ -330,11 +332,13 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
} else {
|
||||
// If the signature of this method will be changed in the output to take a boxed argument instead of a primitive,
|
||||
// rewrite the argument so that code will be generated for a boxed argument and not a primitive.
|
||||
for ((i, p) in valueParameters.withIndex()) {
|
||||
valueParameters = valueParameters.mapIndexed { i, p ->
|
||||
if (AsmUtil.isPrimitive(context.typeMapper.mapType(p.type)) && ourSignature.argumentTypes[i].sort == Type.OBJECT) {
|
||||
val newParameter = p.copyTo(this, type = p.type.makeNullable())
|
||||
variableMap[p] = newParameter
|
||||
valueParameters[i] = newParameter
|
||||
newParameter
|
||||
} else {
|
||||
p
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -408,9 +412,7 @@ private class BridgeLowering(val context: JvmBackendContext) : ClassLoweringPass
|
||||
copyTypeParametersFrom(this@orphanedCopy)
|
||||
this@orphanedCopy.dispatchReceiverParameter?.let { dispatchReceiverParameter = it.copyTo(this) }
|
||||
this@orphanedCopy.extensionReceiverParameter?.let { extensionReceiverParameter = it.copyTo(this) }
|
||||
this@orphanedCopy.valueParameters.forEachIndexed { index, param ->
|
||||
valueParameters.add(index, param.copyTo(this))
|
||||
}
|
||||
valueParameters = this@orphanedCopy.valueParameters.map { it.copyTo(this) }
|
||||
/* Do NOT copy overriddenSymbols */
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@ private class CollectionStubMethodLowering(val context: JvmBackendContext) : Cla
|
||||
if (existingMethod != null) {
|
||||
// In the case that we find a defined method that matches the stub signature, we add the overridden symbols to that
|
||||
// defined method, so that bridge lowering can still generate correct bridge for that method
|
||||
existingMethod.overriddenSymbols.addAll(member.overriddenSymbols)
|
||||
existingMethod.overriddenSymbols += member.overriddenSymbols
|
||||
} else {
|
||||
irClass.declarations.add(member)
|
||||
}
|
||||
@@ -78,13 +78,11 @@ private class CollectionStubMethodLowering(val context: JvmBackendContext) : Cla
|
||||
}.apply {
|
||||
// Replace Function metadata with the data from class
|
||||
// Add the abstract function symbol to stub function for bridge lowering
|
||||
overriddenSymbols.add(function.symbol)
|
||||
overriddenSymbols = listOf(function.symbol)
|
||||
parent = irClass
|
||||
dispatchReceiverParameter = function.dispatchReceiverParameter?.copyWithSubstitution(this, substitutionMap)
|
||||
extensionReceiverParameter = function.extensionReceiverParameter?.copyWithSubstitution(this, substitutionMap)
|
||||
for (parameter in function.valueParameters) {
|
||||
valueParameters.add(parameter.copyWithSubstitution(this, substitutionMap))
|
||||
}
|
||||
valueParameters = function.valueParameters.map { it.copyWithSubstitution(this, substitutionMap) }
|
||||
// Function body consist only of throwing UnsupportedOperationException statement
|
||||
body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||
+irThrow(
|
||||
|
||||
@@ -81,7 +81,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
||||
|
||||
private fun buildEnumEntryField(enumEntry: IrEnumEntry): IrField =
|
||||
context.declarationFactory.getFieldForEnumEntry(enumEntry).apply {
|
||||
initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!.patchDeclarationParents(this))
|
||||
initializer = IrExpressionBodyImpl(enumEntry.initializerExpression!!.expression.patchDeclarationParents(this))
|
||||
annotations += enumEntry.annotations
|
||||
}
|
||||
|
||||
@@ -119,7 +119,7 @@ private class EnumClassLowering(val context: JvmBackendContext) : ClassLoweringP
|
||||
addValueParameter(
|
||||
"\$enum\$ordinal", context.irBuiltIns.intType, JvmLoweredDeclarationOrigin.ENUM_CONSTRUCTOR_SYNTHETIC_PARAMETER
|
||||
)
|
||||
declaration.valueParameters.mapTo(valueParameters) { param ->
|
||||
valueParameters += declaration.valueParameters.map { param ->
|
||||
param.copyTo(this, index = param.index + 2).also { newParam ->
|
||||
loweredEnumConstructorParameters[param.symbol] = newParam
|
||||
}
|
||||
|
||||
@@ -111,7 +111,7 @@ private class FileClassLowering(val context: JvmBackendContext) : FileLoweringPa
|
||||
isFun = false
|
||||
).apply {
|
||||
descriptor.bind(this)
|
||||
superTypes.add(context.irBuiltIns.anyType)
|
||||
superTypes += context.irBuiltIns.anyType
|
||||
parent = irFile
|
||||
declarations.addAll(fileClassMembers)
|
||||
createImplicitParameterDeclarationWithWrappedDescriptor()
|
||||
|
||||
@@ -81,7 +81,7 @@ private class FunctionNVarargBridgeLowering(val context: JvmBackendContext) :
|
||||
|
||||
// Fix super class
|
||||
val superType = bigArityFunctionSuperTypes.single()
|
||||
declaration.superTypes.remove(superType)
|
||||
declaration.superTypes -= superType
|
||||
declaration.superTypes += context.ir.symbols.functionN.typeWith(
|
||||
(superType.arguments.last() as IrTypeProjection).type
|
||||
)
|
||||
@@ -90,7 +90,7 @@ private class FunctionNVarargBridgeLowering(val context: JvmBackendContext) :
|
||||
val invokeFunction = declaration.functions.single {
|
||||
it.name.asString() == "invoke" && it.valueParameters.size == superType.arguments.size - if (it.isSuspend) 0 else 1
|
||||
}
|
||||
invokeFunction.overriddenSymbols.clear()
|
||||
invokeFunction.overriddenSymbols = emptyList()
|
||||
declaration.addBridge(invokeFunction, functionNInvokeFun.owner)
|
||||
|
||||
return declaration
|
||||
|
||||
@@ -123,7 +123,7 @@ private fun generateMultifileFacades(
|
||||
}
|
||||
if (shouldGeneratePartHierarchy) {
|
||||
val superClass = modifyMultifilePartsForHierarchy(context, partClasses)
|
||||
superTypes.add(superClass.typeWith())
|
||||
superTypes += superClass.typeWith()
|
||||
|
||||
addConstructor {
|
||||
visibility = Visibilities.PRIVATE
|
||||
@@ -165,8 +165,7 @@ private fun modifyMultifilePartsForHierarchy(context: JvmBackendContext, unsorte
|
||||
klass.modality = Modality.OPEN
|
||||
klass.visibility = JavaVisibilities.PACKAGE_VISIBILITY
|
||||
|
||||
klass.superTypes.clear()
|
||||
klass.superTypes.add(superClass.typeWith())
|
||||
klass.superTypes = listOf(superClass.typeWith())
|
||||
|
||||
klass.addConstructor {
|
||||
isPrimary = true
|
||||
@@ -211,8 +210,7 @@ private fun IrSimpleFunction.createMultifileDelegateIfNeeded(
|
||||
if (shouldGeneratePartHierarchy) {
|
||||
function.body = null
|
||||
function.origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
function.overriddenSymbols.clear()
|
||||
function.overriddenSymbols.add(symbol)
|
||||
function.overriddenSymbols = listOf(symbol)
|
||||
} else {
|
||||
function.body = context.createIrBuilder(function.symbol).irBlockBody {
|
||||
+irReturn(irCall(this@createMultifileDelegateIfNeeded).also { call ->
|
||||
|
||||
@@ -70,7 +70,7 @@ private class InheritedDefaultMethodsOnClassesLowering(val context: JvmBackendCo
|
||||
// Here we use the same logic as the delegation itself (`getTargetForRedirection`) to determine
|
||||
// if the overriden symbol has been, or will be, replaced and patch it accordingly.
|
||||
override fun visitSimpleFunction(declaration: IrSimpleFunction) {
|
||||
declaration.overriddenSymbols.replaceAll { symbol ->
|
||||
declaration.overriddenSymbols = declaration.overriddenSymbols.map { symbol ->
|
||||
if (symbol.owner.findInterfaceImplementation() != null)
|
||||
context.declarationFactory.getDefaultImplsRedirection(symbol.owner).symbol
|
||||
else symbol
|
||||
|
||||
@@ -53,7 +53,7 @@ private class JvmDefaultConstructorLowering(val context: JvmBackendContext) : Cl
|
||||
visibility = primaryConstructor.visibility
|
||||
}.apply {
|
||||
val irBuilder = context.createIrBuilder(this.symbol, startOffset, endOffset)
|
||||
primaryConstructor.annotations.mapTo(annotations) { it.deepCopyWithSymbols(this) }
|
||||
annotations += primaryConstructor.annotations.map { it.deepCopyWithSymbols(this) }
|
||||
body = irBuilder.irBlockBody {
|
||||
+irDelegatingConstructorCall(primaryConstructor).apply {
|
||||
passTypeArgumentsFrom(irClass)
|
||||
|
||||
@@ -165,11 +165,11 @@ private class JvmOverloadsAnnotationLowering(val context: JvmBackendContext) : C
|
||||
}
|
||||
|
||||
res.parent = oldFunction.parent
|
||||
res.annotations.addAll(oldFunction.annotations.map { it.deepCopyWithSymbols(res) })
|
||||
res.annotations += oldFunction.annotations.map { it.deepCopyWithSymbols(res) }
|
||||
res.copyTypeParametersFrom(oldFunction)
|
||||
res.dispatchReceiverParameter = oldFunction.dispatchReceiverParameter?.copyTo(res)
|
||||
res.extensionReceiverParameter = oldFunction.extensionReceiverParameter?.copyTo(res)
|
||||
res.valueParameters.addAll(res.generateNewValueParameters(oldFunction, numDefaultParametersToExpect))
|
||||
res.valueParameters += res.generateNewValueParameters(oldFunction, numDefaultParametersToExpect)
|
||||
return res
|
||||
}
|
||||
|
||||
|
||||
@@ -83,7 +83,7 @@ class JvmPropertiesLowering(private val context: JvmBackendContext) : IrElementT
|
||||
body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||
parent = declaration.parent
|
||||
|
||||
annotations.addAll(declaration.annotations)
|
||||
annotations = declaration.annotations
|
||||
metadata = declaration.metadata
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,9 +120,9 @@ private class CompanionObjectJvmStaticLowering(val context: JvmBackendContext) :
|
||||
parent = irClass
|
||||
copyTypeParametersFrom(target)
|
||||
target.extensionReceiverParameter?.let { extensionReceiverParameter = it.copyTo(this) }
|
||||
target.valueParameters.mapTo(valueParameters) { it.copyTo(this) }
|
||||
valueParameters = target.valueParameters.map { it.copyTo(this) }
|
||||
|
||||
target.annotations.mapTo(annotations) { it.deepCopyWithSymbols() }
|
||||
annotations = target.annotations.map { it.deepCopyWithSymbols() }
|
||||
|
||||
body = createProxyBody(target, this, companion)
|
||||
}
|
||||
@@ -241,7 +241,7 @@ private class MakeCallsStatic(
|
||||
newDescriptor.bind(it)
|
||||
it.parent = parent
|
||||
it.correspondingPropertySymbol = correspondingPropertySymbol
|
||||
it.annotations.addAll(annotations)
|
||||
it.annotations += annotations
|
||||
it.copyParameterDeclarationsFrom(this)
|
||||
it.dispatchReceiverParameter = null
|
||||
}
|
||||
|
||||
@@ -123,10 +123,9 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
modality = Modality.OPEN
|
||||
origin = JvmLoweredDeclarationOrigin.GENERATED_MEMBER_IN_CALLABLE_REFERENCE
|
||||
}.apply {
|
||||
overriddenSymbols.add(method.symbol)
|
||||
overriddenSymbols += method.symbol
|
||||
dispatchReceiverParameter = thisReceiver!!.copyTo(this)
|
||||
for (parameter in method.valueParameters)
|
||||
valueParameters.add(parameter.copyTo(this))
|
||||
valueParameters = method.valueParameters.map { it.copyTo(this) }
|
||||
body = context.createIrBuilder(symbol, startOffset, endOffset).run {
|
||||
irExprBody(buildBody(listOf(dispatchReceiverParameter!!) + valueParameters))
|
||||
}
|
||||
@@ -139,10 +138,9 @@ internal class PropertyReferenceLowering(val context: JvmBackendContext) : Class
|
||||
visibility = method.visibility
|
||||
origin = IrDeclarationOrigin.FAKE_OVERRIDE
|
||||
}.apply {
|
||||
overriddenSymbols.add(method.symbol)
|
||||
overriddenSymbols += method.symbol
|
||||
dispatchReceiverParameter = thisReceiver!!.copyTo(this)
|
||||
for (parameter in method.valueParameters)
|
||||
valueParameters.add(parameter.copyTo(this))
|
||||
valueParameters = method.valueParameters.map { it.copyTo(this) }
|
||||
}
|
||||
|
||||
private class PropertyReferenceKind(
|
||||
|
||||
@@ -39,7 +39,7 @@ private class RenameAnonymousParametersLowering(val context: JvmBackendContext)
|
||||
|
||||
override fun lower(irFile: IrFile) = irFile.transformChildrenVoid()
|
||||
|
||||
override fun visitValueParameter(declaration: IrValueParameter) =
|
||||
override fun visitValueParameterNew(declaration: IrValueParameter) =
|
||||
declaration.computeNewParameterName()?.let { name ->
|
||||
val descriptor = if (declaration.descriptor is ReceiverParameterDescriptor) {
|
||||
WrappedReceiverParameterDescriptor(declaration.descriptor.annotations)
|
||||
@@ -63,7 +63,7 @@ private class RenameAnonymousParametersLowering(val context: JvmBackendContext)
|
||||
annotations += declaration.annotations
|
||||
oldParameterToNew[declaration] = this
|
||||
}
|
||||
} ?: super.visitValueParameter(declaration)
|
||||
} ?: super.visitValueParameterNew(declaration)
|
||||
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val oldParameter = expression.symbol.owner
|
||||
|
||||
@@ -5,6 +5,7 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.jvm.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.ClassLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.lower.InitializersLoweringBase
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmBackendContext
|
||||
import org.jetbrains.kotlin.backend.jvm.JvmLoweredDeclarationOrigin
|
||||
@@ -19,7 +20,7 @@ import org.jetbrains.kotlin.ir.util.patchDeclarationParents
|
||||
import org.jetbrains.kotlin.load.java.JavaVisibilities
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
class StaticInitializersLowering(override val context: JvmBackendContext) : InitializersLoweringBase(context) {
|
||||
class StaticInitializersLowering(override val context: JvmBackendContext) : InitializersLoweringBase(context), ClassLoweringPass {
|
||||
override fun lower(irClass: IrClass) {
|
||||
val staticInitializerStatements = extractInitializers(irClass) {
|
||||
// JVM implementations are required to generate initializers for all static fields with ConstantValue,
|
||||
|
||||
@@ -156,8 +156,8 @@ internal class SyntheticAccessorLowering(val context: JvmBackendContext) : IrEle
|
||||
accessor.metadata = declaration.metadata
|
||||
declaration.safeAs<IrConstructorImpl>()?.metadata = null
|
||||
accessor.annotations += declaration.annotations
|
||||
declaration.annotations.clear()
|
||||
declaration.valueParameters.forEach { it.annotations.clear() }
|
||||
declaration.annotations = emptyList()
|
||||
declaration.valueParameters.forEach { it.annotations = emptyList() }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -95,7 +95,7 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow
|
||||
irFunction.parent = irClass
|
||||
|
||||
typeParameter.parent = irFunction
|
||||
irFunction.typeParameters.add(typeParameter)
|
||||
irFunction.typeParameters += typeParameter
|
||||
|
||||
val dispatchReceiverParameterDescriptor = WrappedValueParameterDescriptor()
|
||||
irFunction.dispatchReceiverParameter = IrValueParameterImpl(
|
||||
@@ -112,7 +112,7 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow
|
||||
parent = irFunction
|
||||
}
|
||||
val valueParameterDescriptor = WrappedValueParameterDescriptor()
|
||||
irFunction.valueParameters.add(
|
||||
irFunction.valueParameters +=
|
||||
IrValueParameterImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
JvmLoweredDeclarationOrigin.TO_ARRAY,
|
||||
@@ -127,7 +127,6 @@ private class ToArrayLowering(private val context: JvmBackendContext) : ClassLow
|
||||
valueParameterDescriptor.bind(this)
|
||||
parent = irFunction
|
||||
}
|
||||
)
|
||||
|
||||
irFunction.body = context.createIrBuilder(irFunction.symbol).irBlockBody {
|
||||
+irReturn(
|
||||
|
||||
@@ -50,7 +50,7 @@ class TypeAliasAnnotationMethodsLowering(val context: CommonBackendContext) :
|
||||
origin = JvmLoweredDeclarationOrigin.SYNTHETIC_METHOD_FOR_TYPEALIAS_ANNOTATIONS
|
||||
}.apply {
|
||||
body = IrBlockBodyImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET)
|
||||
annotations.addAll(alias.annotations)
|
||||
annotations += alias.annotations
|
||||
metadata = alias.metadata
|
||||
}
|
||||
}
|
||||
|
||||
@@ -146,8 +146,9 @@ class MemoizedInlineClassReplacements {
|
||||
val parameterMap = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||
val replacement = buildReplacement(function) {
|
||||
metadata = function.metadata
|
||||
overriddenSymbols.addAll(overrides)
|
||||
overriddenSymbols += overrides
|
||||
|
||||
val newValueParameters = ArrayList<IrValueParameter>()
|
||||
for ((index, parameter) in function.explicitParameters.withIndex()) {
|
||||
val name = if (parameter == function.extensionReceiverParameter) Name.identifier("\$receiver") else parameter.name
|
||||
val newParameter: IrValueParameter
|
||||
@@ -156,13 +157,14 @@ class MemoizedInlineClassReplacements {
|
||||
dispatchReceiverParameter = newParameter
|
||||
} else {
|
||||
newParameter = parameter.copyTo(this, index = index - 1, name = name, defaultValue = null)
|
||||
valueParameters.add(newParameter)
|
||||
newValueParameters += newParameter
|
||||
}
|
||||
// Assuming that constructors and non-override functions are always replaced with the unboxed
|
||||
// equivalent, deep-copying the value here is unnecessary. See `JvmInlineClassLowering`.
|
||||
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
|
||||
parameterMap[parameter.symbol] = newParameter
|
||||
}
|
||||
valueParameters = newValueParameters
|
||||
}
|
||||
return IrReplacementFunction(replacement, parameterMap)
|
||||
}
|
||||
@@ -171,12 +173,13 @@ class MemoizedInlineClassReplacements {
|
||||
val parameterMap = mutableMapOf<IrValueParameterSymbol, IrValueParameter>()
|
||||
val replacement = buildReplacement(function) {
|
||||
// Generate metadata for the replacement function instead of the original.
|
||||
if (function is IrFunctionBase) {
|
||||
if (function is IrFunctionBase<*>) {
|
||||
metadata = function.metadata
|
||||
function.metadata = null
|
||||
}
|
||||
|
||||
for ((index, parameter) in function.explicitParameters.withIndex()) {
|
||||
|
||||
valueParameters += function.explicitParameters.mapIndexed { index, parameter ->
|
||||
val name = when (parameter) {
|
||||
function.dispatchReceiverParameter -> Name.identifier("arg$index")
|
||||
function.extensionReceiverParameter -> Name.identifier("\$this\$${function.name}")
|
||||
@@ -188,10 +191,12 @@ class MemoizedInlineClassReplacements {
|
||||
else -> parameter.origin
|
||||
}
|
||||
val newParameter = parameter.copyTo(this, index = index, name = name, defaultValue = null, origin = parameterOrigin)
|
||||
valueParameters.add(newParameter)
|
||||
valueParameters += newParameter
|
||||
// See comment next to a similar line above.
|
||||
newParameter.defaultValue = parameter.defaultValue?.patchDeclarationParents(this)
|
||||
parameterMap[parameter.symbol] = newParameter
|
||||
|
||||
newParameter
|
||||
}
|
||||
}
|
||||
return IrReplacementFunction(replacement, parameterMap)
|
||||
|
||||
@@ -5,7 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.backend.wasm
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.CommonBackendContext
|
||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||
import org.jetbrains.kotlin.backend.js.JsDeclarationFactory
|
||||
@@ -14,14 +13,16 @@ import org.jetbrains.kotlin.descriptors.ModuleDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.PackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.descriptors.impl.EmptyPackageFragmentDescriptor
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsMapping
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsSharedVariablesManager
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.declarations.impl.IrExternalPackageFragmentImpl
|
||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrExternalPackageFragmentSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.impl.IrExternalPackageFragmentSymbolImpl
|
||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||
import org.jetbrains.kotlin.ir.util.UniqId
|
||||
@@ -34,12 +35,13 @@ class WasmBackendContext(
|
||||
irModuleFragment: IrModuleFragment,
|
||||
val additionalExportedDeclarations: Set<FqName>,
|
||||
override val configuration: CompilerConfiguration
|
||||
) : CommonBackendContext {
|
||||
) : JsCommonBackendContext {
|
||||
override val builtIns = module.builtIns
|
||||
override var inVerbosePhase: Boolean = false
|
||||
override val scriptMode = false
|
||||
override val transformedFunction = mutableMapOf<IrFunctionSymbol, IrSimpleFunctionSymbol>()
|
||||
override val lateinitNullableFields = mutableMapOf<IrField, IrField>()
|
||||
override val extractedLocalClasses: MutableSet<IrClass> = hashSetOf()
|
||||
|
||||
// Place to store declarations excluded from code generation
|
||||
val excludedDeclarations: IrPackageFragment by lazy {
|
||||
@@ -49,7 +51,9 @@ class WasmBackendContext(
|
||||
)
|
||||
}
|
||||
|
||||
override val declarationFactory = JsDeclarationFactory()
|
||||
override val mapping = JsMapping()
|
||||
|
||||
override val declarationFactory = JsDeclarationFactory(mapping)
|
||||
|
||||
val objectToGetInstanceFunction = mutableMapOf<IrClassSymbol, IrSimpleFunction>()
|
||||
override val internalPackageFqn = FqName("kotlin.wasm")
|
||||
|
||||
@@ -71,12 +71,25 @@ private val expectDeclarationsRemovingPhase = makeWasmModulePhase(
|
||||
description = "Remove expect declaration from module fragment"
|
||||
)
|
||||
|
||||
private val lateinitLoweringPhase = makeWasmModulePhase(
|
||||
::LateinitLowering,
|
||||
name = "LateinitLowering",
|
||||
private val lateinitNullableFieldsPhase = makeWasmModulePhase(
|
||||
::NullableFieldsForLateinitCreationLowering,
|
||||
name = "LateinitNullableFields",
|
||||
description = "Create nullable fields for lateinit properties"
|
||||
)
|
||||
|
||||
private val lateinitDeclarationLoweringPhase = makeWasmModulePhase(
|
||||
::NullableFieldsDeclarationLowering,
|
||||
name = "LateinitDeclarations",
|
||||
description = "Reference nullable fields from properties and getters + insert checks"
|
||||
)
|
||||
|
||||
private val lateinitUsageLoweringPhase = makeWasmModulePhase(
|
||||
::LateinitUsageLowering,
|
||||
name = "LateinitUsage",
|
||||
description = "Insert checks for lateinit field references"
|
||||
)
|
||||
|
||||
|
||||
// TODO make all lambda-related stuff work with IrFunctionExpression and drop this phase
|
||||
private val provisionalFunctionExpressionPhase = makeWasmModulePhase(
|
||||
{ ProvisionalFunctionExpressionLowering() },
|
||||
@@ -152,6 +165,13 @@ private val innerClassesLoweringPhase = makeWasmModulePhase(
|
||||
description = "Capture outer this reference to inner class"
|
||||
)
|
||||
|
||||
private val innerClassesMemberBodyLoweringPhase = makeWasmModulePhase(
|
||||
::InnerClassesMemberBodyLowering,
|
||||
name = "InnerClassesMemberBody",
|
||||
description = "Replace `this` with 'outer this' field references",
|
||||
prerequisite = setOf(innerClassesLoweringPhase)
|
||||
)
|
||||
|
||||
private val innerClassConstructorCallsLoweringPhase = makeWasmModulePhase(
|
||||
::InnerClassConstructorCallsLowering,
|
||||
name = "InnerClassConstructorCallsLowering",
|
||||
@@ -164,6 +184,13 @@ private val defaultArgumentStubGeneratorPhase = makeWasmModulePhase(
|
||||
description = "Generate synthetic stubs for functions with default parameter values"
|
||||
)
|
||||
|
||||
private val defaultArgumentPatchOverridesPhase = makeWasmModulePhase(
|
||||
::DefaultParameterPatchOverridenSymbolsLowering,
|
||||
name = "DefaultArgumentsPatchOverrides",
|
||||
description = "Patch overrides for fake override dispatch functions",
|
||||
prerequisite = setOf(defaultArgumentStubGeneratorPhase)
|
||||
)
|
||||
|
||||
private val defaultParameterInjectorPhase = makeWasmModulePhase(
|
||||
{ context -> DefaultParameterInjector(context, skipExternalMethods = true) },
|
||||
name = "DefaultParameterInjector",
|
||||
@@ -201,6 +228,13 @@ private val primaryConstructorLoweringPhase = makeWasmModulePhase(
|
||||
description = "Creates primary constructor if it doesn't exist"
|
||||
)
|
||||
|
||||
private val delegateToPrimaryConstructorLoweringPhase = makeWasmModulePhase(
|
||||
::DelegateToSyntheticPrimaryConstructor,
|
||||
name = "DelegateToSyntheticPrimaryConstructor",
|
||||
description = "Delegates to synthetic primary constructor",
|
||||
prerequisite = setOf(primaryConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val initializersLoweringPhase = makeWasmModulePhase(
|
||||
::InitializersLowering,
|
||||
name = "InitializersLowering",
|
||||
@@ -208,6 +242,13 @@ private val initializersLoweringPhase = makeWasmModulePhase(
|
||||
prerequisite = setOf(primaryConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val initializersCleanupLoweringPhase = makeWasmModulePhase(
|
||||
::InitializersCleanupLowering,
|
||||
name = "InitializersCleanupLowering",
|
||||
description = "Remove non-static anonymous initializers and field init expressions",
|
||||
prerequisite = setOf(initializersLoweringPhase)
|
||||
)
|
||||
|
||||
private val excludeDeclarationsFromCodegenPhase = makeCustomWasmModulePhase(
|
||||
{ context, module ->
|
||||
excludeDeclarationsFromCodegen(context, module)
|
||||
@@ -229,15 +270,16 @@ private val bridgesConstructionPhase = makeWasmModulePhase(
|
||||
description = "Generate bridges"
|
||||
)
|
||||
|
||||
private val inlineClassLoweringPhase = makeCustomWasmModulePhase(
|
||||
{ context, module ->
|
||||
InlineClassLowering(context).run {
|
||||
inlineClassDeclarationLowering.runOnFilesPostfix(module)
|
||||
inlineClassUsageLowering.lower(module)
|
||||
}
|
||||
},
|
||||
name = "InlineClassLowering",
|
||||
description = "Handle inline classes"
|
||||
private val inlineClassDeclarationLoweringPhase = makeWasmModulePhase(
|
||||
{ InlineClassLowering(it).inlineClassDeclarationLowering },
|
||||
name = "InlineClassDeclarationLowering",
|
||||
description = "Handle inline class declarations"
|
||||
)
|
||||
|
||||
private val inlineClassUsageLoweringPhase = makeWasmModulePhase(
|
||||
{ InlineClassLowering(it).inlineClassUsageLowering },
|
||||
name = "InlineClassUsageLowering",
|
||||
description = "Handle inline class usages"
|
||||
)
|
||||
|
||||
//private val autoboxingTransformerPhase = makeJsModulePhase(
|
||||
@@ -297,14 +339,14 @@ private val builtInsLoweringPhase = makeWasmModulePhase(
|
||||
description = "Lower IR buildins"
|
||||
)
|
||||
|
||||
private val objectDeclarationLoweringPhase = makeCustomWasmModulePhase(
|
||||
{ context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
||||
private val objectDeclarationLoweringPhase = makeWasmModulePhase(
|
||||
::ObjectUsageLowering,
|
||||
name = "ObjectDeclarationLowering",
|
||||
description = "Create lazy object instance generator functions"
|
||||
)
|
||||
|
||||
private val objectUsageLoweringPhase = makeCustomWasmModulePhase(
|
||||
{ context, module -> ObjectUsageLowering(context, context.objectToGetInstanceFunction).lower(module) },
|
||||
private val objectUsageLoweringPhase = makeWasmModulePhase(
|
||||
::ObjectUsageLowering,
|
||||
name = "ObjectUsageLowering",
|
||||
description = "Transform IrGetObjectValue into instance generator call"
|
||||
)
|
||||
@@ -321,7 +363,9 @@ val wasmPhases = namedIrModulePhase<WasmBackendContext>(
|
||||
// arrayConstructorPhase then
|
||||
|
||||
functionInliningPhase then
|
||||
lateinitLoweringPhase then
|
||||
lateinitNullableFieldsPhase then
|
||||
lateinitDeclarationLoweringPhase then
|
||||
lateinitUsageLoweringPhase then
|
||||
tailrecLoweringPhase then
|
||||
|
||||
enumClassConstructorLoweringPhase then
|
||||
@@ -331,10 +375,13 @@ val wasmPhases = namedIrModulePhase<WasmBackendContext>(
|
||||
localDeclarationsLoweringPhase then
|
||||
localClassExtractionPhase then
|
||||
innerClassesLoweringPhase then
|
||||
innerClassesMemberBodyLoweringPhase then
|
||||
innerClassConstructorCallsLoweringPhase then
|
||||
propertiesLoweringPhase then
|
||||
primaryConstructorLoweringPhase then
|
||||
delegateToPrimaryConstructorLoweringPhase then
|
||||
initializersLoweringPhase then
|
||||
initializersCleanupLoweringPhase then
|
||||
// Common prefix ends
|
||||
|
||||
builtInsLoweringPhase then
|
||||
@@ -357,6 +404,7 @@ val wasmPhases = namedIrModulePhase<WasmBackendContext>(
|
||||
// callableReferenceLoweringPhase then
|
||||
|
||||
defaultArgumentStubGeneratorPhase then
|
||||
defaultArgumentPatchOverridesPhase then
|
||||
defaultParameterInjectorPhase then
|
||||
defaultParameterCleanerPhase then
|
||||
|
||||
@@ -384,7 +432,8 @@ val wasmPhases = namedIrModulePhase<WasmBackendContext>(
|
||||
// TODO: Reimplement
|
||||
// classReferenceLoweringPhase then
|
||||
|
||||
inlineClassLoweringPhase then
|
||||
inlineClassDeclarationLoweringPhase then
|
||||
inlineClassUsageLoweringPhase then
|
||||
|
||||
// TODO: Commonize box/unbox intrinsics
|
||||
// autoboxingTransformerPhase then
|
||||
|
||||
@@ -40,8 +40,10 @@ class AnnotationGenerator(context: GeneratorContext) : IrElementVisitorVoid {
|
||||
declaration.descriptor.backingField
|
||||
else declaration.descriptor
|
||||
|
||||
annotatedDescriptor?.annotations?.mapNotNullTo(declaration.annotations) {
|
||||
constantValueGenerator.generateAnnotationConstructorCall(it)
|
||||
if (annotatedDescriptor != null) {
|
||||
declaration.annotations += annotatedDescriptor.annotations.mapNotNull {
|
||||
constantValueGenerator.generateAnnotationConstructorCall(it)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -87,7 +87,7 @@ class ClassGenerator(
|
||||
).buildWithScope { irClass ->
|
||||
declarationGenerator.generateGlobalTypeParametersDeclarations(irClass, classDescriptor.declaredTypeParameters)
|
||||
|
||||
classDescriptor.typeConstructor.supertypes.mapTo(irClass.superTypes) {
|
||||
irClass.superTypes = classDescriptor.typeConstructor.supertypes.map {
|
||||
it.toIrType()
|
||||
}
|
||||
|
||||
@@ -462,8 +462,8 @@ class ClassGenerator(
|
||||
|
||||
if (!enumEntryDescriptor.isExpect) {
|
||||
irEnumEntry.initializerExpression =
|
||||
createBodyGenerator(irEnumEntry.symbol)
|
||||
.generateEnumEntryInitializer(ktEnumEntry, enumEntryDescriptor)
|
||||
IrExpressionBodyImpl(createBodyGenerator(irEnumEntry.symbol)
|
||||
.generateEnumEntryInitializer(ktEnumEntry, enumEntryDescriptor))
|
||||
}
|
||||
|
||||
if (ktEnumEntry.hasMemberDeclarations()) {
|
||||
|
||||
@@ -126,7 +126,7 @@ class DeclarationGenerator(override val context: GeneratorContext) : Generator {
|
||||
from: List<TypeParameterDescriptor>,
|
||||
declareTypeParameter: (Int, Int, TypeParameterDescriptor) -> IrTypeParameter
|
||||
) {
|
||||
from.mapTo(irTypeParametersOwner.typeParameters) { typeParameterDescriptor ->
|
||||
irTypeParametersOwner.typeParameters += from.map { typeParameterDescriptor ->
|
||||
val ktTypeParameterDeclaration = DescriptorToSourceUtils.getSourceFromDescriptor(typeParameterDescriptor)
|
||||
val startOffset = ktTypeParameterDeclaration.startOffsetOrUndefined
|
||||
val endOffset = ktTypeParameterDeclaration.endOffsetOrUndefined
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user