Add Secondary constructor lowering
This commit is contained in:
+27
-20
@@ -37,14 +37,18 @@ import org.jetbrains.kotlin.resolve.descriptorUtil.builtIns
|
|||||||
import java.util.*
|
import java.util.*
|
||||||
|
|
||||||
|
|
||||||
class InitializersLowering(val context: CommonBackendContext, val declarationOrigin: IrDeclarationOrigin) : ClassLoweringPass {
|
class InitializersLowering(
|
||||||
|
val context: CommonBackendContext,
|
||||||
|
val declarationOrigin: IrDeclarationOrigin,
|
||||||
|
private val clinitNeeded: Boolean
|
||||||
|
) : ClassLoweringPass {
|
||||||
override fun lower(irClass: IrClass) {
|
override fun lower(irClass: IrClass) {
|
||||||
val classInitializersBuilder = ClassInitializersBuilder(irClass)
|
val classInitializersBuilder = ClassInitializersBuilder(irClass)
|
||||||
irClass.acceptChildrenVoid(classInitializersBuilder)
|
irClass.acceptChildrenVoid(classInitializersBuilder)
|
||||||
|
|
||||||
classInitializersBuilder.transformInstanceInitializerCallsInConstructors(irClass)
|
classInitializersBuilder.transformInstanceInitializerCallsInConstructors(irClass)
|
||||||
|
|
||||||
classInitializersBuilder.createStaticInitializationMethod(irClass)
|
if (clinitNeeded) classInitializersBuilder.createStaticInitializationMethod(irClass)
|
||||||
}
|
}
|
||||||
|
|
||||||
private inner class ClassInitializersBuilder(val irClass: IrClass) : IrElementVisitorVoid {
|
private inner class ClassInitializersBuilder(val irClass: IrClass) : IrElementVisitorVoid {
|
||||||
@@ -60,22 +64,23 @@ class InitializersLowering(val context: CommonBackendContext, val declarationOri
|
|||||||
val irFieldInitializer = declaration.initializer?.expression ?: return
|
val irFieldInitializer = declaration.initializer?.expression ?: return
|
||||||
|
|
||||||
val receiver =
|
val receiver =
|
||||||
if (declaration.descriptor.dispatchReceiverParameter != null) // TODO isStaticField
|
if (declaration.descriptor.dispatchReceiverParameter != null) // TODO isStaticField
|
||||||
IrGetValueImpl(irFieldInitializer.startOffset, irFieldInitializer.endOffset,
|
IrGetValueImpl(
|
||||||
irClass.descriptor.thisAsReceiverParameter)
|
irFieldInitializer.startOffset, irFieldInitializer.endOffset,
|
||||||
else null
|
irClass.descriptor.thisAsReceiverParameter
|
||||||
|
)
|
||||||
|
else null
|
||||||
val irSetField = IrSetFieldImpl(
|
val irSetField = IrSetFieldImpl(
|
||||||
irFieldInitializer.startOffset, irFieldInitializer.endOffset,
|
irFieldInitializer.startOffset, irFieldInitializer.endOffset,
|
||||||
declaration.descriptor,
|
declaration.descriptor,
|
||||||
receiver,
|
receiver,
|
||||||
irFieldInitializer,
|
irFieldInitializer,
|
||||||
null, null
|
null, null
|
||||||
)
|
)
|
||||||
|
|
||||||
if (DescriptorUtils.isStaticDeclaration(declaration.descriptor)) {
|
if (DescriptorUtils.isStaticDeclaration(declaration.descriptor)) {
|
||||||
staticInitializerStatements.add(irSetField)
|
staticInitializerStatements.add(irSetField)
|
||||||
}
|
} else {
|
||||||
else {
|
|
||||||
instanceInitializerStatements.add(irSetField)
|
instanceInitializerStatements.add(irSetField)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -100,15 +105,17 @@ class InitializersLowering(val context: CommonBackendContext, val declarationOri
|
|||||||
SourceElement.NO_SOURCE
|
SourceElement.NO_SOURCE
|
||||||
)
|
)
|
||||||
staticInitializerDescriptor.initialize(
|
staticInitializerDescriptor.initialize(
|
||||||
null, null, emptyList(), emptyList(),
|
null, null, emptyList(), emptyList(),
|
||||||
irClass.descriptor.builtIns.unitType,
|
irClass.descriptor.builtIns.unitType,
|
||||||
Modality.FINAL, Visibilities.PUBLIC
|
Modality.FINAL, Visibilities.PUBLIC
|
||||||
)
|
)
|
||||||
irClass.declarations.add(
|
irClass.declarations.add(
|
||||||
IrFunctionImpl(irClass.startOffset, irClass.endOffset, declarationOrigin,
|
IrFunctionImpl(
|
||||||
staticInitializerDescriptor,
|
irClass.startOffset, irClass.endOffset, declarationOrigin,
|
||||||
IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
|
staticInitializerDescriptor,
|
||||||
staticInitializerStatements.map { it.copy() }))
|
IrBlockBodyImpl(irClass.startOffset, irClass.endOffset,
|
||||||
|
staticInitializerStatements.map { it.copy() })
|
||||||
|
)
|
||||||
)
|
)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,4 +10,6 @@ import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
|||||||
|
|
||||||
object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
|
object JsLoweredDeclarationOrigin : IrDeclarationOrigin {
|
||||||
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
|
object CLASS_STATIC_INITIALIZER : IrDeclarationOriginImpl("CLASS_STATIC_INITIALIZER")
|
||||||
|
object SECONDARY_CTOR_RECEIVER : IrDeclarationOriginImpl("SECONDARY_CTOR_RECEIVER")
|
||||||
|
object JS_INTRINSICS_STUB : IrDeclarationOriginImpl("JS_INTRINSICS_STUB")
|
||||||
}
|
}
|
||||||
@@ -10,16 +10,23 @@ import org.jetbrains.kotlin.backend.common.ReflectionTypes
|
|||||||
import org.jetbrains.kotlin.backend.common.ir.Ir
|
import org.jetbrains.kotlin.backend.common.ir.Ir
|
||||||
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
import org.jetbrains.kotlin.backend.common.ir.Symbols
|
||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.TypeParameterDescriptorImpl
|
||||||
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
import org.jetbrains.kotlin.incremental.components.NoLookupLocation
|
||||||
import org.jetbrains.kotlin.ir.IrElement
|
import org.jetbrains.kotlin.ir.IrElement
|
||||||
import org.jetbrains.kotlin.ir.declarations.*
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
import org.jetbrains.kotlin.ir.descriptors.IrBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.util.DeclarationStubGenerator
|
||||||
import org.jetbrains.kotlin.ir.util.SymbolTable
|
import org.jetbrains.kotlin.ir.util.SymbolTable
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
import org.jetbrains.kotlin.resolve.scopes.MemberScope
|
||||||
|
import org.jetbrains.kotlin.types.KotlinTypeFactory
|
||||||
|
import org.jetbrains.kotlin.types.Variance
|
||||||
|
|
||||||
class JsIrBackendContext(
|
class JsIrBackendContext(
|
||||||
val module: ModuleDescriptor,
|
val module: ModuleDescriptor,
|
||||||
@@ -80,6 +87,41 @@ class JsIrBackendContext(
|
|||||||
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
override fun shouldGenerateHandlerParameterForDefaultBodyFun() = true
|
||||||
}
|
}
|
||||||
|
|
||||||
|
data class SecondaryCtorPair(val delegate: IrSimpleFunctionSymbol, val stub: IrSimpleFunctionSymbol)
|
||||||
|
|
||||||
|
val secondaryConstructorsMap = mutableMapOf<IrConstructorSymbol, SecondaryCtorPair>()
|
||||||
|
|
||||||
|
private val stubBuilder = DeclarationStubGenerator(symbolTable, JsLoweredDeclarationOrigin.JS_INTRINSICS_STUB)
|
||||||
|
|
||||||
|
val objectCreate: IrSimpleFunction = defineObjectCreateIntrinsic()
|
||||||
|
|
||||||
|
private fun defineObjectCreateIntrinsic(): IrSimpleFunction {
|
||||||
|
|
||||||
|
val typeParam = TypeParameterDescriptorImpl.createWithDefaultBound(
|
||||||
|
builtIns.any,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
true,
|
||||||
|
Variance.INVARIANT,
|
||||||
|
Name.identifier("T"),
|
||||||
|
0
|
||||||
|
)
|
||||||
|
|
||||||
|
val returnType = KotlinTypeFactory.simpleType(Annotations.EMPTY, typeParam.typeConstructor, emptyList(), false)
|
||||||
|
|
||||||
|
val desc = SimpleFunctionDescriptorImpl.create(
|
||||||
|
module,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Name.identifier("Object\$create"),
|
||||||
|
CallableMemberDescriptor.Kind.SYNTHESIZED,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
).apply {
|
||||||
|
initialize(null, null, listOf(typeParam), emptyList(), returnType, Modality.FINAL, Visibilities.PUBLIC)
|
||||||
|
isInline = true
|
||||||
|
}
|
||||||
|
|
||||||
|
return stubBuilder.generateFunctionStub(desc)
|
||||||
|
}
|
||||||
|
|
||||||
private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
|
private fun find(memberScope: MemberScope, className: String): ClassDescriptor {
|
||||||
return find(memberScope, Name.identifier(className))
|
return find(memberScope, Name.identifier(className))
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -9,12 +9,10 @@ import com.intellij.openapi.project.Project
|
|||||||
import org.jetbrains.kotlin.backend.common.lower.*
|
import org.jetbrains.kotlin.backend.common.lower.*
|
||||||
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
import org.jetbrains.kotlin.backend.common.runOnFilePostfix
|
||||||
import org.jetbrains.kotlin.config.CompilerConfiguration
|
import org.jetbrains.kotlin.config.CompilerConfiguration
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.lower.SecondaryCtorLowering
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrModuleToJsTransformer
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOrigin
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrFile
|
import org.jetbrains.kotlin.ir.declarations.IrFile
|
||||||
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
import org.jetbrains.kotlin.ir.util.ExternalDependenciesGenerator
|
||||||
import org.jetbrains.kotlin.ir.util.dump
|
|
||||||
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
import org.jetbrains.kotlin.js.analyze.TopDownAnalyzerFacadeForJS
|
||||||
import org.jetbrains.kotlin.name.FqName
|
import org.jetbrains.kotlin.name.FqName
|
||||||
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
import org.jetbrains.kotlin.progress.ProgressIndicatorAndCompilationCanceledStatus
|
||||||
@@ -37,21 +35,29 @@ fun compile(
|
|||||||
|
|
||||||
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files)
|
val moduleFragment = psi2IrTranslator.generateModuleFragment(psi2IrContext, files)
|
||||||
|
|
||||||
val context = JsIrBackendContext(analysisResult.moduleDescriptor, psi2IrContext.irBuiltIns, moduleFragment, psi2IrContext.symbolTable)
|
val context = JsIrBackendContext(
|
||||||
|
analysisResult.moduleDescriptor,
|
||||||
|
psi2IrContext.irBuiltIns,
|
||||||
|
moduleFragment,
|
||||||
|
psi2IrContext.symbolTable
|
||||||
|
)
|
||||||
|
|
||||||
ExternalDependenciesGenerator(psi2IrContext.symbolTable, psi2IrContext.irBuiltIns).generateUnboundSymbolsAsDependencies(moduleFragment)
|
ExternalDependenciesGenerator(psi2IrContext.symbolTable, psi2IrContext.irBuiltIns).generateUnboundSymbolsAsDependencies(moduleFragment)
|
||||||
|
|
||||||
moduleFragment.files.forEach { context.lower(it) }
|
moduleFragment.files.forEach { context.lower(it) }
|
||||||
|
val transformer = SecondaryCtorLowering.CallsiteRedirectionTransformer(context)
|
||||||
|
moduleFragment.files.forEach { it.accept(transformer, null) }
|
||||||
|
|
||||||
val program = moduleFragment.accept(IrModuleToJsTransformer(), null)
|
val program = moduleFragment.accept(IrModuleToJsTransformer(context), null)
|
||||||
|
|
||||||
return program.toString()
|
return program.toString()
|
||||||
}
|
}
|
||||||
|
|
||||||
fun JsIrBackendContext.lower(file: IrFile) {
|
fun JsIrBackendContext.lower(file: IrFile) {
|
||||||
LateinitLowering(this, true).lower(file)
|
LateinitLowering(this, true).lower(file)
|
||||||
PropertiesLowering().lower(file)
|
|
||||||
LocalFunctionsLowering(this).lower(file)
|
LocalFunctionsLowering(this).lower(file)
|
||||||
DefaultArgumentStubGenerator(this).runOnFilePostfix(file)
|
DefaultArgumentStubGenerator(this).runOnFilePostfix(file)
|
||||||
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER).runOnFilePostfix(file)
|
PropertiesLowering().lower(file)
|
||||||
|
InitializersLowering(this, JsLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, false).runOnFilePostfix(file)
|
||||||
|
SecondaryCtorLowering(this).lower(file)
|
||||||
}
|
}
|
||||||
+322
@@ -0,0 +1,322 @@
|
|||||||
|
/*
|
||||||
|
* Copyright 2010-2018 JetBrains s.r.o. 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.lower
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.backend.common.FileLoweringPass
|
||||||
|
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||||
|
import org.jetbrains.kotlin.descriptors.SourceElement
|
||||||
|
import org.jetbrains.kotlin.descriptors.annotations.Annotations
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.LazyClassReceiverParameterDescriptor
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.SimpleFunctionDescriptorImpl
|
||||||
|
import org.jetbrains.kotlin.descriptors.impl.ValueParameterDescriptorImpl
|
||||||
|
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.JsLoweredDeclarationOrigin
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.utils.isPrimary
|
||||||
|
import org.jetbrains.kotlin.ir.builders.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrFunctionImpl
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.impl.IrValueParameterImpl
|
||||||
|
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
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||||
|
import org.jetbrains.kotlin.ir.symbols.IrValueParameterSymbol
|
||||||
|
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.IrElementTransformer
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||||
|
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||||
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
|
class SecondaryCtorLowering(val context: JsIrBackendContext) : IrElementTransformerVoid(), FileLoweringPass {
|
||||||
|
|
||||||
|
private val oldCtorToNewMap = mutableMapOf<IrConstructorSymbol, JsIrBackendContext.SecondaryCtorPair>()
|
||||||
|
|
||||||
|
override fun lower(irFile: IrFile) {
|
||||||
|
irFile.accept(this, null)
|
||||||
|
context.secondaryConstructorsMap.putAll(oldCtorToNewMap)
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitFile(irFile: IrFile): IrFile {
|
||||||
|
irFile.declarations.transformFlat { declaration ->
|
||||||
|
if (declaration is IrClass) {
|
||||||
|
listOf(declaration) + lowerClass(declaration)
|
||||||
|
} else null
|
||||||
|
}
|
||||||
|
|
||||||
|
return irFile
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun lowerClass(irClass: IrClass): List<IrSimpleFunction> {
|
||||||
|
val className = irClass.name.asString()
|
||||||
|
val oldConstructors = mutableListOf<IrConstructor>()
|
||||||
|
val newConstructors = mutableListOf<IrSimpleFunction>()
|
||||||
|
|
||||||
|
for (declaration in irClass.declarations) {
|
||||||
|
if (declaration is IrConstructor && !declaration.symbol.isPrimary) {
|
||||||
|
// TODO delegate name generation
|
||||||
|
val constructorName = "${className}_init"
|
||||||
|
// 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
|
||||||
|
// * Creation function which has same signature with original constructor,
|
||||||
|
// creates new object via `Object.create` builtIn and passes it to corresponding `Init` function
|
||||||
|
// In other words:
|
||||||
|
// Foo::constructor(...) {
|
||||||
|
// body
|
||||||
|
// }
|
||||||
|
// =>
|
||||||
|
// Foo_init_$Init$(..., $this) {
|
||||||
|
// body[ this = $this ]
|
||||||
|
// return $this
|
||||||
|
// }
|
||||||
|
// Foo_init_$Create$(...) {
|
||||||
|
// val t = Object.create(Foo.prototype);
|
||||||
|
// return Foo_init_$Init$(..., t)
|
||||||
|
// }
|
||||||
|
val newInitConstructor = createInitConstructor(declaration, constructorName)
|
||||||
|
val newCreateConstructor = createCreateConstructor(declaration, newInitConstructor, constructorName)
|
||||||
|
|
||||||
|
oldCtorToNewMap[declaration.symbol] =
|
||||||
|
JsIrBackendContext.SecondaryCtorPair(newInitConstructor.symbol, newCreateConstructor.symbol)
|
||||||
|
|
||||||
|
oldConstructors += declaration
|
||||||
|
newConstructors += newInitConstructor
|
||||||
|
newConstructors += newCreateConstructor
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
irClass.declarations.removeAll(oldConstructors)
|
||||||
|
|
||||||
|
return newConstructors
|
||||||
|
}
|
||||||
|
|
||||||
|
private class ThisUsageReplaceTransformer(val function: IrFunctionSymbol, val thisSymbol: IrValueParameterSymbol) :
|
||||||
|
IrElementTransformerVoid() {
|
||||||
|
|
||||||
|
override fun visitReturn(expression: IrReturn): IrExpression = IrReturnImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
function,
|
||||||
|
IrGetValueImpl(expression.startOffset, expression.endOffset, thisSymbol)
|
||||||
|
)
|
||||||
|
|
||||||
|
override fun visitGetValue(expression: IrGetValue): IrExpression =
|
||||||
|
if (expression.descriptor.name.isSpecial && expression.descriptor.name.asString() == Namer.THIS_SPECIAL_NAME) IrGetValueImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
thisSymbol,
|
||||||
|
expression.origin
|
||||||
|
) else {
|
||||||
|
expression
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun createInitConstructor(declaration: IrConstructor, name: String): IrSimpleFunction {
|
||||||
|
// TODO delegate name generation
|
||||||
|
val actualName = "${name}_\$Init\$"
|
||||||
|
|
||||||
|
//region TODO: get rid of descriptors and replace them with direct symbol creation
|
||||||
|
val thisParamDesc = ValueParameterDescriptorImpl(
|
||||||
|
declaration.descriptor,
|
||||||
|
null,
|
||||||
|
declaration.descriptor.valueParameters.size,
|
||||||
|
Annotations.EMPTY,
|
||||||
|
Name.identifier("\$this"),
|
||||||
|
declaration.descriptor.returnType,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
false,
|
||||||
|
null,
|
||||||
|
SourceElement.NO_SOURCE
|
||||||
|
)
|
||||||
|
|
||||||
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
|
declaration.descriptor.containingDeclaration,
|
||||||
|
declaration.descriptor.annotations,
|
||||||
|
Name.identifier(actualName),
|
||||||
|
declaration.descriptor.kind,
|
||||||
|
declaration.descriptor.source
|
||||||
|
).initialize(
|
||||||
|
null,
|
||||||
|
declaration.descriptor.dispatchReceiverParameter,
|
||||||
|
declaration.descriptor.typeParameters,
|
||||||
|
declaration.descriptor.valueParameters + thisParamDesc,
|
||||||
|
declaration.returnType,
|
||||||
|
declaration.descriptor.modality,
|
||||||
|
declaration.visibility
|
||||||
|
)
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
|
||||||
|
val thisSymbol = IrValueParameterSymbolImpl(thisParamDesc)
|
||||||
|
val functionSymbol = IrSimpleFunctionSymbolImpl(functionDescriptor)
|
||||||
|
|
||||||
|
val thisParam = IrValueParameterImpl(
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
JsLoweredDeclarationOrigin.SECONDARY_CTOR_RECEIVER,
|
||||||
|
thisSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
val constructor = IrFunctionImpl(
|
||||||
|
declaration.startOffset, declaration.endOffset,
|
||||||
|
declaration.origin, functionSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
var statements = (declaration.body as IrStatementContainer).statements.map { it.deepCopyWithSymbols() }
|
||||||
|
val fixer = ThisUsageReplaceTransformer(functionSymbol, thisSymbol)
|
||||||
|
for (stmt in statements) {
|
||||||
|
stmt.transformChildrenVoid(fixer)
|
||||||
|
}
|
||||||
|
|
||||||
|
val retStmt = IrReturnImpl(
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
UNDEFINED_OFFSET,
|
||||||
|
functionSymbol,
|
||||||
|
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, thisSymbol)
|
||||||
|
)
|
||||||
|
|
||||||
|
statements += retStmt
|
||||||
|
val newBody = IrBlockBodyImpl(declaration.body!!.startOffset, declaration.body!!.endOffset, statements)
|
||||||
|
|
||||||
|
constructor.valueParameters += declaration.valueParameters
|
||||||
|
constructor.typeParameters += declaration.typeParameters
|
||||||
|
constructor.parent = declaration.parent
|
||||||
|
constructor.valueParameters += thisParam
|
||||||
|
constructor.body = newBody
|
||||||
|
|
||||||
|
return constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private fun createCreateConstructor(ctorOrig: IrConstructor, ctorImpl: IrSimpleFunction, name: String): IrSimpleFunction {
|
||||||
|
// TODO delegate name generation
|
||||||
|
val actualName = "${name}_\$Create\$"
|
||||||
|
|
||||||
|
//region TODO: descriptor -> symbol
|
||||||
|
val functionDescriptor = SimpleFunctionDescriptorImpl.create(
|
||||||
|
ctorOrig.descriptor,
|
||||||
|
ctorOrig.descriptor.annotations,
|
||||||
|
Name.identifier(actualName),
|
||||||
|
ctorOrig.descriptor.kind,
|
||||||
|
ctorOrig.descriptor.source
|
||||||
|
).initialize(
|
||||||
|
null,
|
||||||
|
ctorOrig.descriptor.dispatchReceiverParameter,
|
||||||
|
ctorOrig.descriptor.typeParameters,
|
||||||
|
ctorOrig.descriptor.valueParameters,
|
||||||
|
ctorOrig.returnType,
|
||||||
|
ctorOrig.descriptor.modality,
|
||||||
|
ctorOrig.visibility
|
||||||
|
)
|
||||||
|
//endregion
|
||||||
|
|
||||||
|
val functionSymbol = IrSimpleFunctionSymbolImpl(functionDescriptor)
|
||||||
|
|
||||||
|
val constructor = IrFunctionImpl(
|
||||||
|
ctorOrig.startOffset, ctorOrig.endOffset,
|
||||||
|
ctorOrig.origin, functionSymbol
|
||||||
|
)
|
||||||
|
|
||||||
|
val createFunctionIntrinsic = context.objectCreate
|
||||||
|
val irBuilder = context.createIrBuilder(functionSymbol, ctorOrig.startOffset, ctorOrig.endOffset).irBlockBody {
|
||||||
|
val thisVar = irTemporaryVar(
|
||||||
|
IrCallImpl(
|
||||||
|
startOffset,
|
||||||
|
endOffset,
|
||||||
|
ctorOrig.returnType,
|
||||||
|
createFunctionIntrinsic.symbol,
|
||||||
|
createFunctionIntrinsic.descriptor,
|
||||||
|
mapOf(createFunctionIntrinsic.typeParameters[0].descriptor to ctorOrig.returnType)
|
||||||
|
)
|
||||||
|
)
|
||||||
|
+irReturn(
|
||||||
|
irCall(ctorImpl.symbol).apply {
|
||||||
|
ctorOrig.valueParameters.forEachIndexed { index, irValueParameter ->
|
||||||
|
putValueArgument(index, irGet(irValueParameter.symbol))
|
||||||
|
}
|
||||||
|
putValueArgument(ctorOrig.valueParameters.size, irGet(thisVar.symbol))
|
||||||
|
}
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
constructor.valueParameters += ctorOrig.valueParameters
|
||||||
|
constructor.typeParameters += ctorOrig.typeParameters
|
||||||
|
constructor.parent = ctorOrig.parent
|
||||||
|
constructor.body = IrBlockBodyImpl(ctorOrig.body?.startOffset!!, ctorOrig.body?.endOffset!!, irBuilder.statements)
|
||||||
|
|
||||||
|
return constructor
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
class CallsiteRedirectionTransformer(val context: JsIrBackendContext) : IrElementTransformer<IrFunction?> {
|
||||||
|
|
||||||
|
override fun visitFunction(declaration: IrFunction, data: IrFunction?): IrStatement = super.visitFunction(declaration, declaration)
|
||||||
|
|
||||||
|
override fun visitCall(expression: IrCall, ownerFunc: IrFunction?): IrElement {
|
||||||
|
val target = expression.symbol.owner as IrFunction
|
||||||
|
|
||||||
|
if (target is IrConstructor) {
|
||||||
|
if (!target.descriptor.isPrimary) {
|
||||||
|
return redirectCall(expression, context.secondaryConstructorsMap[target.symbol]!!.stub)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, ownerFunc: IrFunction?): IrElement {
|
||||||
|
val target = expression.symbol.owner
|
||||||
|
if (target.symbol.isPrimary) {
|
||||||
|
// nothing to do here
|
||||||
|
return expression
|
||||||
|
}
|
||||||
|
|
||||||
|
val fromPrimary = ownerFunc!! is IrConstructor
|
||||||
|
val newCall = redirectCall(expression, context.secondaryConstructorsMap[target.symbol]!!.delegate)
|
||||||
|
|
||||||
|
val readThis = if (fromPrimary) {
|
||||||
|
IrGetValueImpl(
|
||||||
|
expression.startOffset,
|
||||||
|
expression.endOffset,
|
||||||
|
IrValueParameterSymbolImpl(LazyClassReceiverParameterDescriptor(target.descriptor.containingDeclaration))
|
||||||
|
)
|
||||||
|
} else {
|
||||||
|
IrGetValueImpl(expression.startOffset, expression.endOffset, ownerFunc.valueParameters.last().symbol)
|
||||||
|
}
|
||||||
|
|
||||||
|
newCall.putValueArgument(expression.valueArgumentsCount, readThis)
|
||||||
|
|
||||||
|
return newCall
|
||||||
|
}
|
||||||
|
|
||||||
|
private fun redirectCall(
|
||||||
|
call: IrFunctionAccessExpression,
|
||||||
|
newTarget: IrSimpleFunctionSymbol
|
||||||
|
): IrCallImpl {
|
||||||
|
val newCall = IrCallImpl(call.startOffset, call.endOffset, newTarget)
|
||||||
|
|
||||||
|
newCall.copyTypeArgumentsFrom(call)
|
||||||
|
|
||||||
|
for (i in 0 until call.valueArgumentsCount) {
|
||||||
|
newCall.putValueArgument(i, call.getValueArgument(i))
|
||||||
|
}
|
||||||
|
|
||||||
|
return newCall
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
+11
-4
@@ -7,10 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.isPrimary
|
import org.jetbrains.kotlin.ir.backend.js.utils.isPrimary
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrProperty
|
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|
||||||
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatement, JsGenerationContext> {
|
||||||
@@ -29,4 +26,14 @@ class IrDeclarationToJsTransformer : BaseIrElementToJsNodeTransformer<JsStatemen
|
|||||||
override fun visitClass(declaration: IrClass, context: JsGenerationContext): JsStatement {
|
override fun visitClass(declaration: IrClass, context: JsGenerationContext): JsStatement {
|
||||||
return JsClassGenerator(declaration, context).generate()
|
return JsClassGenerator(declaration, context).generate()
|
||||||
}
|
}
|
||||||
|
|
||||||
|
override fun visitField(declaration: IrField, context: JsGenerationContext): JsStatement {
|
||||||
|
val fieldName = declaration.name.toJsName()
|
||||||
|
val initExpression =
|
||||||
|
declaration.initializer?.accept(IrElementToJsExpressionTransformer(), context) ?: JsPrefixOperation(
|
||||||
|
JsUnaryOperator.VOID,
|
||||||
|
JsIntLiteral(1)
|
||||||
|
)
|
||||||
|
return jsAssignment(JsNameRef(fieldName, JsThisRef()), initExpression).makeStmt()
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
+14
-2
@@ -5,8 +5,10 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.builtins.extractParameterNameFromFunctionTypeArgument
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
import org.jetbrains.kotlin.ir.declarations.IrSimpleFunction
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrConstructorSymbol
|
||||||
@@ -73,8 +75,10 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsExpression {
|
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, context: JsGenerationContext): JsExpression {
|
||||||
val classNameRef = expression.symbol.owner.descriptor.constructedClass.name.toJsName().makeRef()
|
val classNameRef = expression.symbol.owner.descriptor.constructedClass.name.toJsName().makeRef()
|
||||||
val callFuncRef = JsNameRef(Namer.CALL_FUNCTION, classNameRef)
|
val callFuncRef = JsNameRef(Namer.CALL_FUNCTION, classNameRef)
|
||||||
|
val fromPrimary = context.currentFunction is IrConstructor
|
||||||
|
val thisRef = if (fromPrimary) JsThisRef() else JsNameRef("\$this")
|
||||||
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
|
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
|
||||||
return JsInvocation(callFuncRef, listOf(JsThisRef()) + arguments)
|
return JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitCall(expression: IrCall, context: JsGenerationContext): JsExpression {
|
override fun visitCall(expression: IrCall, context: JsGenerationContext): JsExpression {
|
||||||
@@ -86,6 +90,14 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
// * getters and setters
|
// * getters and setters
|
||||||
// * binary and unary operations
|
// * binary and unary operations
|
||||||
|
|
||||||
|
if (expression.symbol == context.staticContext.backendContext.objectCreate.symbol) {
|
||||||
|
// TODO: temporary workaround until there is no an intrinsic infrastructure
|
||||||
|
assert(expression.typeArgumentsCount == 1 && expression.valueArgumentsCount == 0)
|
||||||
|
val classToCreate = expression.getTypeArgument(0)!!
|
||||||
|
val prototype = prototypeOf(classToCreate.constructor.declarationDescriptor!!.name.toJsName().makeRef())
|
||||||
|
return JsInvocation(Namer.JS_OBJECT_CREATE_FUNCTION, prototype)
|
||||||
|
}
|
||||||
|
|
||||||
val symbol = expression.symbol
|
val symbol = expression.symbol
|
||||||
|
|
||||||
val dispatchReceiver = expression.dispatchReceiver?.accept(this, context)
|
val dispatchReceiver = expression.dispatchReceiver?.accept(this, context)
|
||||||
@@ -94,7 +106,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
|||||||
|
|
||||||
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
|
val arguments = translateCallArguments(expression, expression.symbol.parameterCount, context)
|
||||||
|
|
||||||
return if (symbol is IrConstructorSymbol && symbol.isPrimary) {
|
return if (symbol is IrConstructorSymbol) {
|
||||||
JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
|
JsNew(JsNameRef((symbol.owner.parent as IrClass).name.asString()), arguments)
|
||||||
} else {
|
} else {
|
||||||
// TODO sanitize name
|
// TODO sanitize name
|
||||||
|
|||||||
+1
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
|||||||
|
|
||||||
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
import org.jetbrains.kotlin.builtins.KotlinBuiltIns
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||||
|
import org.jetbrains.kotlin.ir.declarations.IrField
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
import org.jetbrains.kotlin.ir.declarations.IrVariable
|
||||||
import org.jetbrains.kotlin.ir.expressions.*
|
import org.jetbrains.kotlin.ir.expressions.*
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
|||||||
+3
-2
@@ -15,12 +15,13 @@ import org.jetbrains.kotlin.js.backend.ast.JsStatement
|
|||||||
|
|
||||||
open class IrFunctionToJsTransformer : BaseIrElementToJsNodeTransformer<JsFunction, JsGenerationContext> {
|
open class IrFunctionToJsTransformer : BaseIrElementToJsNodeTransformer<JsFunction, JsGenerationContext> {
|
||||||
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsFunction {
|
override fun visitSimpleFunction(declaration: IrSimpleFunction, context: JsGenerationContext): JsFunction {
|
||||||
return translateFunction(declaration, declaration.name, context)
|
val funcName = context.getNameForSymbol(declaration.symbol)
|
||||||
|
return translateFunction(declaration, funcName, context)
|
||||||
}
|
}
|
||||||
|
|
||||||
override fun visitConstructor(declaration: IrConstructor, context: JsGenerationContext): JsFunction {
|
override fun visitConstructor(declaration: IrConstructor, context: JsGenerationContext): JsFunction {
|
||||||
assert(declaration.symbol.isPrimary)
|
assert(declaration.symbol.isPrimary)
|
||||||
return translateFunction(declaration, declaration.symbol.constructedClassName, context)
|
return translateFunction(declaration, declaration.symbol.constructedClassName.toJsName(), context)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
+3
-2
@@ -5,16 +5,17 @@
|
|||||||
|
|
||||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||||
|
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
import org.jetbrains.kotlin.ir.backend.js.utils.JsGenerationContext
|
||||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
import org.jetbrains.kotlin.js.backend.ast.JsNode
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
import org.jetbrains.kotlin.js.backend.ast.JsProgram
|
||||||
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
import org.jetbrains.kotlin.js.backend.ast.JsRootScope
|
||||||
|
|
||||||
class IrModuleToJsTransformer : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
class IrModuleToJsTransformer(val backendContext: JsIrBackendContext) : BaseIrElementToJsNodeTransformer<JsNode, Nothing?> {
|
||||||
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
|
override fun visitModuleFragment(declaration: IrModuleFragment, data: Nothing?): JsNode {
|
||||||
val program = JsProgram()
|
val program = JsProgram()
|
||||||
val rootContext = JsGenerationContext(JsRootScope(program))
|
val rootContext = JsGenerationContext(JsRootScope(program), backendContext)
|
||||||
|
|
||||||
declaration.files.forEach {
|
declaration.files.forEach {
|
||||||
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
program.globalBlock.statements.add(it.accept(IrFileToJsTransformer(), rootContext))
|
||||||
|
|||||||
+3
-3
@@ -38,13 +38,13 @@ fun jsAssignment(left: JsExpression, right: JsExpression) = JsBinaryOperation(Js
|
|||||||
|
|
||||||
fun prototypeOf(classNameRef: JsExpression) = JsNameRef(Namer.PROTOTYPE_NAME, classNameRef)
|
fun prototypeOf(classNameRef: JsExpression) = JsNameRef(Namer.PROTOTYPE_NAME, classNameRef)
|
||||||
|
|
||||||
fun translateFunction(declaration: IrFunction, name: Name?, context: JsGenerationContext): JsFunction {
|
fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerationContext): JsFunction {
|
||||||
val functionScope = JsFunctionScope(context.currentScope, "scope for ${name ?: "annon"}")
|
val functionScope = JsFunctionScope(context.currentScope, "scope for ${name ?: "annon"}")
|
||||||
val functionContext = context.newDeclaration(functionScope)
|
val functionContext = context.newDeclaration(functionScope, declaration)
|
||||||
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
||||||
val function = JsFunction(functionScope, body, "member function ${name ?: "annon"}")
|
val function = JsFunction(functionScope, body, "member function ${name ?: "annon"}")
|
||||||
|
|
||||||
function.name = name?.toJsName()
|
function.name = name
|
||||||
|
|
||||||
fun JsFunction.addParameter(parameterName: String) {
|
fun JsFunction.addParameter(parameterName: String) {
|
||||||
val parameter = function.scope.declareName(parameterName)
|
val parameter = function.scope.declareName(parameterName)
|
||||||
|
|||||||
+9
-5
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsExpressionTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsExpressionTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsStatementTransformer
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.IrElementToJsStatementTransformer
|
||||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.toJsName
|
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.toJsName
|
||||||
@@ -16,31 +17,34 @@ import org.jetbrains.kotlin.js.backend.ast.*
|
|||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class JsGenerationContext {
|
class JsGenerationContext {
|
||||||
fun newDeclaration(scope: JsScope): JsGenerationContext {
|
fun newDeclaration(scope: JsScope, func: IrFunction? = null): JsGenerationContext {
|
||||||
return JsGenerationContext(this, JsBlock(), scope)
|
return JsGenerationContext(this, JsBlock(), scope, func)
|
||||||
}
|
}
|
||||||
|
|
||||||
val currentBlock: JsBlock
|
val currentBlock: JsBlock
|
||||||
val currentScope: JsScope
|
val currentScope: JsScope
|
||||||
|
val currentFunction: IrFunction?
|
||||||
val parent: JsGenerationContext?
|
val parent: JsGenerationContext?
|
||||||
val staticContext: JsStaticContext
|
val staticContext: JsStaticContext
|
||||||
private val program: JsProgram
|
private val program: JsProgram
|
||||||
|
|
||||||
constructor(rootScope: JsRootScope) {
|
constructor(rootScope: JsRootScope, backendContext: JsIrBackendContext) {
|
||||||
|
|
||||||
this.parent = null
|
this.parent = null
|
||||||
this.program = rootScope.program
|
this.program = rootScope.program
|
||||||
this.staticContext = JsStaticContext(rootScope, program.globalBlock, SimpleNameGenerator())
|
this.staticContext = JsStaticContext(rootScope, program.globalBlock, SimpleNameGenerator(), backendContext)
|
||||||
this.currentScope = rootScope
|
this.currentScope = rootScope
|
||||||
this.currentBlock = program.globalBlock
|
this.currentBlock = program.globalBlock
|
||||||
|
this.currentFunction = null
|
||||||
}
|
}
|
||||||
|
|
||||||
constructor(parent: JsGenerationContext, block: JsBlock, scope: JsScope) {
|
constructor(parent: JsGenerationContext, block: JsBlock, scope: JsScope, func: IrFunction?) {
|
||||||
this.parent = parent
|
this.parent = parent
|
||||||
this.program = parent.program
|
this.program = parent.program
|
||||||
this.staticContext = parent.staticContext
|
this.staticContext = parent.staticContext
|
||||||
this.currentBlock = block
|
this.currentBlock = block
|
||||||
this.currentScope = scope
|
this.currentScope = scope
|
||||||
|
this.currentFunction = func
|
||||||
}
|
}
|
||||||
|
|
||||||
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol)
|
fun getNameForSymbol(symbol: IrSymbol): JsName = staticContext.getNameForSymbol(symbol)
|
||||||
|
|||||||
+3
-1
@@ -6,6 +6,7 @@
|
|||||||
package org.jetbrains.kotlin.ir.backend.js.utils
|
package org.jetbrains.kotlin.ir.backend.js.utils
|
||||||
|
|
||||||
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
import org.jetbrains.kotlin.descriptors.DeclarationDescriptor
|
||||||
|
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
@@ -14,7 +15,8 @@ import org.jetbrains.kotlin.name.Name
|
|||||||
class JsStaticContext(
|
class JsStaticContext(
|
||||||
private val rootScope: JsRootScope,
|
private val rootScope: JsRootScope,
|
||||||
private val globalBlock: JsGlobalBlock,
|
private val globalBlock: JsGlobalBlock,
|
||||||
private val nameGenerator: NameGenerator
|
private val nameGenerator: NameGenerator,
|
||||||
|
val backendContext: JsIrBackendContext
|
||||||
) {
|
) {
|
||||||
|
|
||||||
fun getNameForSymbol(irSymbol: IrSymbol) = nameGenerator.getNameForSymbol(irSymbol, rootScope)
|
fun getNameForSymbol(irSymbol: IrSymbol) = nameGenerator.getNameForSymbol(irSymbol, rootScope)
|
||||||
|
|||||||
+10
-1
@@ -8,6 +8,8 @@ package org.jetbrains.kotlin.ir.backend.js.utils
|
|||||||
import org.jetbrains.kotlin.descriptors.*
|
import org.jetbrains.kotlin.descriptors.*
|
||||||
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
import org.jetbrains.kotlin.ir.symbols.IrSymbol
|
||||||
import org.jetbrains.kotlin.js.backend.ast.*
|
import org.jetbrains.kotlin.js.backend.ast.*
|
||||||
|
import org.jetbrains.kotlin.js.naming.isES5IdentifierPart
|
||||||
|
import org.jetbrains.kotlin.js.naming.isES5IdentifierStart
|
||||||
import org.jetbrains.kotlin.name.Name
|
import org.jetbrains.kotlin.name.Name
|
||||||
|
|
||||||
class SimpleNameGenerator : NameGenerator {
|
class SimpleNameGenerator : NameGenerator {
|
||||||
@@ -48,6 +50,13 @@ class SimpleNameGenerator : NameGenerator {
|
|||||||
}
|
}
|
||||||
|
|
||||||
}
|
}
|
||||||
return@getOrPut scope.declareName(nameBuilder.toString())
|
scope.declareName(sanitizeName(nameBuilder.toString()))
|
||||||
})
|
})
|
||||||
|
|
||||||
|
private fun sanitizeName(name: String): String {
|
||||||
|
if (name.isEmpty()) return "_"
|
||||||
|
|
||||||
|
val first = name.first().let { if (it.isES5IdentifierStart()) it else '_' }
|
||||||
|
return first.toString() + name.drop(1).map { if (it.isES5IdentifierPart()) it else '_' }.joinToString("")
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -51,7 +51,7 @@ class JvmLower(val context: JvmBackendContext) {
|
|||||||
EnumClassLowering(context).runOnFilePostfix(irFile)
|
EnumClassLowering(context).runOnFilePostfix(irFile)
|
||||||
//Should be before SyntheticAccessorLowering cause of synthetic accessor for companion constructor
|
//Should be before SyntheticAccessorLowering cause of synthetic accessor for companion constructor
|
||||||
ObjectClassLowering(context).lower(irFile)
|
ObjectClassLowering(context).lower(irFile)
|
||||||
InitializersLowering(context, JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER).runOnFilePostfix(irFile)
|
InitializersLowering(context, JvmLoweredDeclarationOrigin.CLASS_STATIC_INITIALIZER, true).runOnFilePostfix(irFile)
|
||||||
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
SingletonReferencesLowering(context).runOnFilePostfix(irFile)
|
||||||
SyntheticAccessorLowering(context).lower(irFile)
|
SyntheticAccessorLowering(context).lower(irFile)
|
||||||
BridgeLowering(context).runOnFilePostfix(irFile)
|
BridgeLowering(context).runOnFilePostfix(irFile)
|
||||||
|
|||||||
+5
-60
@@ -21287,18 +21287,7 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
@TestMetadata("primCtorDelegation1.kt")
|
@TestMetadata("primCtorDelegation1.kt")
|
||||||
public void testPrimCtorDelegation1() throws Exception {
|
public void testPrimCtorDelegation1() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/primCtorDelegation1.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/primCtorDelegation1.kt");
|
||||||
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("propertiesAsParametersInitialized.kt")
|
@TestMetadata("propertiesAsParametersInitialized.kt")
|
||||||
@@ -21327,69 +21316,25 @@ public class IrBoxJsTestGenerated extends AbstractIrBoxJsTest {
|
|||||||
@TestMetadata("secCtorDelegation1.kt")
|
@TestMetadata("secCtorDelegation1.kt")
|
||||||
public void testSecCtorDelegation1() throws Exception {
|
public void testSecCtorDelegation1() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation1.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation1.kt");
|
||||||
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("secCtorDelegation2.kt")
|
@TestMetadata("secCtorDelegation2.kt")
|
||||||
public void testSecCtorDelegation2() throws Exception {
|
public void testSecCtorDelegation2() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation2.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation2.kt");
|
||||||
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("secCtorDelegation3.kt")
|
@TestMetadata("secCtorDelegation3.kt")
|
||||||
public void testSecCtorDelegation3() throws Exception {
|
public void testSecCtorDelegation3() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation3.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation3.kt");
|
||||||
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("secCtorDelegation4.kt")
|
@TestMetadata("secCtorDelegation4.kt")
|
||||||
public void testSecCtorDelegation4() throws Exception {
|
public void testSecCtorDelegation4() throws Exception {
|
||||||
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation4.kt");
|
String fileName = KotlinTestUtils.navigationMetadata("js/js.translator/testData/box/simple/secCtorDelegation4.kt");
|
||||||
if (KotlinTestUtils.RUN_IGNORED_TESTS_AS_REGULAR) {
|
doTest(fileName);
|
||||||
doTest(fileName);
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
try {
|
|
||||||
doTest(fileName);
|
|
||||||
}
|
|
||||||
catch (Throwable ignore) {
|
|
||||||
ignore.printStackTrace();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
throw new AssertionError("Looks like this test can be unmuted. Remove IGNORE_BACKEND directive or add it to whitelist for that.");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
@TestMetadata("simpleInitializer.kt")
|
@TestMetadata("simpleInitializer.kt")
|
||||||
|
|||||||
Reference in New Issue
Block a user