[K/JS] Add support of compilation with ES-classes
This commit is contained in:
+8
-8
@@ -65,7 +65,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
boolean hasFlags();
|
||||
@@ -73,7 +73,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
int getFlags();
|
||||
@@ -433,7 +433,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasFlags() {
|
||||
@@ -443,7 +443,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
public int getFlags() {
|
||||
@@ -1225,7 +1225,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
public boolean hasFlags() {
|
||||
@@ -1235,7 +1235,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
public int getFlags() {
|
||||
@@ -1245,7 +1245,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
public Builder setFlags(int value) {
|
||||
@@ -1258,7 +1258,7 @@ public final class DebugKlibMetadataProtoBuf {
|
||||
* <code>optional int32 flags = 2;</code>
|
||||
*
|
||||
* <pre>
|
||||
*0x1 = preRelease
|
||||
*Possible values are listed in KlibMetadataHeaderFlags class.
|
||||
* </pre>
|
||||
*/
|
||||
public Builder clearFlags() {
|
||||
|
||||
+11
@@ -291,6 +291,17 @@ class K2JSCompilerArguments : CommonCompilerArguments() {
|
||||
)
|
||||
var strictImplicitExportType: Boolean by FreezableVar(false)
|
||||
|
||||
@GradleOption(
|
||||
value = DefaultValue.BOOLEAN_FALSE_DEFAULT,
|
||||
gradleInputType = GradleInputTypes.INPUT,
|
||||
shouldGenerateDeprecatedKotlinOptions = true,
|
||||
)
|
||||
@Argument(
|
||||
value = "-Xes-classes",
|
||||
description = "Generated JavaScript will use ES2015 classes."
|
||||
)
|
||||
var useEsClasses: Boolean by FreezableVar(false)
|
||||
|
||||
@GradleOption(
|
||||
value = DefaultValue.BOOLEAN_TRUE_DEFAULT,
|
||||
gradleInputType = GradleInputTypes.INPUT,
|
||||
|
||||
@@ -144,7 +144,8 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
arguments.irSafeExternalBooleanDiagnostic,
|
||||
messageCollector
|
||||
),
|
||||
granularity = arguments.granularity
|
||||
granularity = arguments.granularity,
|
||||
es6mode = arguments.useEsClasses
|
||||
)
|
||||
}
|
||||
|
||||
@@ -668,7 +669,14 @@ class K2JsIrCompiler : CLICompiler<K2JSCompilerArguments>() {
|
||||
compilerConfiguration = configurationJs,
|
||||
irFactory = { IrFactoryImplForJsIC(WholeWorldStageController()) },
|
||||
mainArguments = mainCallArguments,
|
||||
compilerInterfaceFactory = { mainModule, cfg -> JsIrCompilerWithIC(mainModule, cfg, arguments.granularity) }
|
||||
compilerInterfaceFactory = { mainModule, cfg ->
|
||||
JsIrCompilerWithIC(
|
||||
mainModule,
|
||||
cfg,
|
||||
arguments.granularity,
|
||||
es6mode = arguments.useEsClasses
|
||||
)
|
||||
}
|
||||
)
|
||||
|
||||
val artifacts = cacheUpdater.actualizeCaches()
|
||||
|
||||
+1
-1
@@ -30,6 +30,6 @@ abstract class AbstractValueRemapper : IrElementTransformerVoid() {
|
||||
}
|
||||
}
|
||||
|
||||
open class ValueRemapper(private val map: Map<IrValueSymbol, IrValueSymbol>) : AbstractValueRemapper() {
|
||||
open class ValueRemapper(protected open val map: Map<IrValueSymbol, IrValueSymbol>) : AbstractValueRemapper() {
|
||||
override fun remapValue(oldValue: IrValueSymbol): IrValueSymbol? = map[oldValue]
|
||||
}
|
||||
+7
@@ -125,6 +125,13 @@ class InlineClassLowering(val context: CommonBackendContext) {
|
||||
return builder.irGet(initFunction.valueParameters.single())
|
||||
return expression
|
||||
}
|
||||
|
||||
override fun visitSetValue(expression: IrSetValue): IrExpression {
|
||||
expression.transformChildrenVoid()
|
||||
if (expression.symbol == origParameterSymbol)
|
||||
return builder.irSet(initFunction.valueParameters.single(), expression.value)
|
||||
return expression
|
||||
}
|
||||
})
|
||||
}
|
||||
+irReturn(unboxedInlineClassValue())
|
||||
|
||||
@@ -152,11 +152,9 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsAnyToString = getInternalFunction("anyToString")
|
||||
val jsCompareTo = getInternalFunction("compareTo")
|
||||
val jsEquals = getInternalFunction("equals")
|
||||
val jsConstruct = getInternalFunction("construct")
|
||||
val jsNewTarget = getInternalFunction("jsNewTarget")
|
||||
val jsEmptyObject = getInternalFunction("emptyObject")
|
||||
val jsOpenInitializerBox = getInternalFunction("openInitializerBox")
|
||||
val es6DefaultType = getInternalFunction("DefaultType")
|
||||
|
||||
val jsImul = getInternalFunction("imul")
|
||||
|
||||
@@ -167,6 +165,8 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
val jsBooleanInExternalLog = getInternalFunction("booleanInExternalLog")
|
||||
val jsBooleanInExternalException = getInternalFunction("booleanInExternalException")
|
||||
|
||||
val jsNewAnonymousClass = getInternalFunction("jsNewAnonymousClass")
|
||||
|
||||
// Coroutines
|
||||
|
||||
val jsCoroutineContext
|
||||
@@ -369,7 +369,10 @@ class JsIntrinsics(private val irBuiltIns: IrBuiltIns, val context: JsIrBackendC
|
||||
|
||||
val jsPrototypeOfSymbol = getInternalFunction("protoOf")
|
||||
val jsDefinePropertySymbol = getInternalFunction("defineProp")
|
||||
val jsObjectCreateSymbol = getInternalFunction("objectCreate") // Object.create
|
||||
val jsObjectCreateSymbol = getInternalFunction("objectCreate") // Object.create(x)
|
||||
val jsCreateThisSymbol = getInternalFunction("createThis") // Object.create(x.prototype)
|
||||
val jsBoxApplySymbol = getInternalFunction("boxApply")
|
||||
val jsCreateExternalThisSymbol = getInternalFunction("createExternalThis")
|
||||
|
||||
// Helpers:
|
||||
|
||||
|
||||
@@ -29,6 +29,12 @@ private fun DeclarationContainerLoweringPass.runOnFilesPostfix(files: Iterable<I
|
||||
|
||||
private fun ClassLoweringPass.runOnFilesPostfix(moduleFragment: IrModuleFragment) = moduleFragment.files.forEach { runOnFilePostfix(it) }
|
||||
|
||||
private fun List<Lowering>.toCompilerPhase() =
|
||||
map {
|
||||
@Suppress("USELESS_CAST")
|
||||
it.modulePhase as CompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>, Iterable<IrModuleFragment>>
|
||||
}.reduce { acc, lowering -> acc.then(lowering) }
|
||||
|
||||
private fun makeJsModulePhase(
|
||||
lowering: (JsIrBackendContext) -> FileLoweringPass,
|
||||
name: String,
|
||||
@@ -683,19 +689,6 @@ private val typeOperatorLoweringPhase = makeBodyLoweringPhase(
|
||||
)
|
||||
)
|
||||
|
||||
private val es6AddInternalParametersToConstructorPhase = makeBodyLoweringPhase(
|
||||
::ES6AddInternalParametersToConstructorPhase,
|
||||
name = "ES6CreateInitFunctionPhase",
|
||||
description = "Add `box` and `resultType` params, create init functions for constructors"
|
||||
)
|
||||
|
||||
private val es6ConstructorLowering = makeBodyLoweringPhase(
|
||||
::ES6ConstructorLowering,
|
||||
name = "ES6ConstructorLoweringPhase",
|
||||
description = "Lower constructors",
|
||||
prerequisite = setOf(es6AddInternalParametersToConstructorPhase)
|
||||
)
|
||||
|
||||
private val secondaryConstructorLoweringPhase = makeDeclarationTransformerPhase(
|
||||
::SecondaryConstructorLowering,
|
||||
name = "SecondaryConstructorLoweringPhase",
|
||||
@@ -791,10 +784,31 @@ private val invokeStaticInitializersPhase = makeBodyLoweringPhase(
|
||||
prerequisite = setOf(objectDeclarationLoweringPhase)
|
||||
)
|
||||
|
||||
private val es6AddBoxParameterToConstructorsLowering = makeDeclarationTransformerPhase(
|
||||
::ES6AddBoxParameterToConstructorsLowering,
|
||||
name = "ES6AddBoxParameterToConstructorsLowering",
|
||||
description = "Add box parameter to a constructor if needed",
|
||||
)
|
||||
|
||||
private val es6ConstructorLowering = makeDeclarationTransformerPhase(
|
||||
::ES6ConstructorLowering,
|
||||
name = "ES6ConstructorLowering",
|
||||
description = "Lower constructors declarations to support ES classes",
|
||||
prerequisite = setOf(es6AddBoxParameterToConstructorsLowering)
|
||||
)
|
||||
|
||||
private val es6ConstructorUsageLowering = makeBodyLoweringPhase(
|
||||
::ES6ConstructorCallLowering,
|
||||
name = "ES6ConstructorCallLowering",
|
||||
description = "Lower constructor usages to support ES classes",
|
||||
prerequisite = setOf(es6ConstructorLowering)
|
||||
)
|
||||
|
||||
private val objectUsageLoweringPhase = makeBodyLoweringPhase(
|
||||
::ObjectUsageLowering,
|
||||
name = "ObjectUsageLowering",
|
||||
description = "Transform IrGetObjectValue into instance generator call"
|
||||
description = "Transform IrGetObjectValue into instance generator call",
|
||||
prerequisite = setOf(primaryConstructorLoweringPhase)
|
||||
)
|
||||
|
||||
private val escapedIdentifiersLowering = makeBodyLoweringPhase(
|
||||
@@ -809,7 +823,6 @@ private val implicitlyExportedDeclarationsMarkingLowering = makeDeclarationTrans
|
||||
description = "Add @JsImplicitExport annotation to declarations which are not exported but are used inside other exported declarations as a type"
|
||||
)
|
||||
|
||||
|
||||
private val cleanupLoweringPhase = makeBodyLoweringPhase(
|
||||
{ CleanupLowering() },
|
||||
name = "CleanupLowering",
|
||||
@@ -912,8 +925,6 @@ val loweringList = listOf<Lowering>(
|
||||
defaultParameterCleanerPhase,
|
||||
captureStackTraceInThrowablesPhase,
|
||||
throwableSuccessorsLoweringPhase,
|
||||
es6AddInternalParametersToConstructorPhase,
|
||||
es6ConstructorLowering,
|
||||
varargLoweringPhase,
|
||||
multipleCatchesLoweringPhase,
|
||||
errorExpressionLoweringPhase,
|
||||
@@ -927,10 +938,13 @@ val loweringList = listOf<Lowering>(
|
||||
inlineClassDeclarationLoweringPhase,
|
||||
inlineClassUsageLoweringPhase,
|
||||
autoboxingTransformerPhase,
|
||||
blockDecomposerLoweringPhase,
|
||||
objectDeclarationLoweringPhase,
|
||||
blockDecomposerLoweringPhase,
|
||||
invokeStaticInitializersPhase,
|
||||
objectUsageLoweringPhase,
|
||||
es6AddBoxParameterToConstructorsLowering,
|
||||
es6ConstructorLowering,
|
||||
es6ConstructorUsageLowering,
|
||||
callsLoweringPhase,
|
||||
escapedIdentifiersLowering,
|
||||
implicitlyExportedDeclarationsMarkingLowering,
|
||||
@@ -947,10 +961,56 @@ val pirLowerings = loweringList.filter { it is DeclarationLowering || it is Body
|
||||
val jsPhases = SameTypeNamedCompilerPhase(
|
||||
name = "IrModuleLowering",
|
||||
description = "IR module lowering",
|
||||
lower = loweringList.map {
|
||||
@Suppress("USELESS_CAST")
|
||||
it.modulePhase as CompilerPhase<JsIrBackendContext, Iterable<IrModuleFragment>, Iterable<IrModuleFragment>>
|
||||
}.reduce { acc, lowering -> acc.then(lowering) },
|
||||
lower = loweringList.toCompilerPhase(),
|
||||
actions = setOf(defaultDumper.toMultiModuleAction(), validationAction.toMultiModuleAction()),
|
||||
nlevels = 1
|
||||
)
|
||||
|
||||
private val es6CollectConstructorsWhichNeedBoxParameterLowering = makeDeclarationTransformerPhase(
|
||||
::ES6CollectConstructorsWhichNeedBoxParameters,
|
||||
name = "ES6CollectConstructorsWhichNeedBoxParameters",
|
||||
description = "[Optimization] Collect all of the constructors which requires box parameter",
|
||||
)
|
||||
|
||||
private val es6BoxParameterOptimization = makeBodyLoweringPhase(
|
||||
::ES6ConstructorBoxParameterOptimizationLowering,
|
||||
name = "ES6ConstructorBoxParameterOptimizationLowering",
|
||||
description = "[Optimization] Remove box parameter from the constructors which don't require box parameter",
|
||||
prerequisite = setOf(es6CollectConstructorsWhichNeedBoxParameterLowering)
|
||||
)
|
||||
|
||||
private val es6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering = makeDeclarationTransformerPhase(
|
||||
::ES6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering,
|
||||
name = "ES6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering",
|
||||
description = "[Optimization] Collect all of the constructors which could be translated into a regular constructor",
|
||||
)
|
||||
|
||||
private val es6PrimaryConstructorOptimizationLowering = makeDeclarationTransformerPhase(
|
||||
::ES6PrimaryConstructorOptimizationLowering,
|
||||
name = "ES6PrimaryConstructorOptimizationLowering",
|
||||
description = "[Optimization] Replace synthetically generated static fabric method with a plain old ES6 constructors whenever it's possible",
|
||||
prerequisite = setOf(es6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering)
|
||||
)
|
||||
|
||||
private val es6PrimaryConstructorUsageOptimizationLowering = makeBodyLoweringPhase(
|
||||
::ES6PrimaryConstructorUsageOptimizationLowering,
|
||||
name = "ES6PrimaryConstructorUsageOptimizationLowering",
|
||||
description = "[Optimization] Replace usage of synthetically generated static fabric method with a plain old ES6 constructors whenever it's possible",
|
||||
prerequisite = setOf(es6BoxParameterOptimization, es6PrimaryConstructorOptimizationLowering)
|
||||
)
|
||||
|
||||
val optimizationLoweringList = listOf<Lowering>(
|
||||
es6CollectConstructorsWhichNeedBoxParameterLowering,
|
||||
es6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering,
|
||||
es6BoxParameterOptimization,
|
||||
es6PrimaryConstructorOptimizationLowering,
|
||||
es6PrimaryConstructorUsageOptimizationLowering,
|
||||
)
|
||||
|
||||
val jsOptimizationPhases = SameTypeNamedCompilerPhase(
|
||||
name = "IrModuleOptimizationLowering",
|
||||
description = "IR module optimization lowering",
|
||||
lower = optimizationLoweringList.toCompilerPhase(),
|
||||
actions = setOf(defaultDumper.toMultiModuleAction(), validationAction.toMultiModuleAction()),
|
||||
nlevels = 1
|
||||
)
|
||||
|
||||
@@ -7,9 +7,13 @@ package org.jetbrains.kotlin.ir.backend.js
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DefaultDelegateFactory
|
||||
import org.jetbrains.kotlin.backend.common.DefaultMapping
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.MutableReference
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
|
||||
class JsMapping : DefaultMapping() {
|
||||
val esClassWhichNeedBoxParameters = mutableSetOf<IrClass>()
|
||||
val esClassToPossibilityForOptimization = mutableMapOf<IrClass, MutableReference<Boolean>>()
|
||||
|
||||
val outerThisFieldSymbols = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrField>()
|
||||
val innerClassConstructors = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
||||
val originalInnerClassPrimaryConstructorByClass = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
||||
@@ -20,8 +24,6 @@ class JsMapping : DefaultMapping() {
|
||||
val classToSyntheticPrimaryConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrClass, IrConstructor>()
|
||||
val privateMemberToCorrespondingStatic = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrFunction, IrSimpleFunction>()
|
||||
|
||||
val constructorToInitFunction = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrSimpleFunction>()
|
||||
|
||||
val enumEntryToGetInstanceFun = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrEnumEntry, IrSimpleFunction>()
|
||||
val enumEntryToInstanceField = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrEnumEntry, IrField>()
|
||||
val enumConstructorToNewConstructor = DefaultDelegateFactory.newDeclarationToDeclarationMapping<IrConstructor, IrConstructor>()
|
||||
|
||||
+73
-44
@@ -9,26 +9,35 @@ import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrGetValue
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.config.JSConfigurationKeys
|
||||
import org.jetbrains.kotlin.serialization.js.ModuleKind
|
||||
|
||||
internal class JsUsefulDeclarationProcessor(
|
||||
override val context: JsIrBackendContext,
|
||||
printReachabilityInfo: Boolean,
|
||||
removeUnusedAssociatedObjects: Boolean
|
||||
) : UsefulDeclarationProcessor(printReachabilityInfo, removeUnusedAssociatedObjects) {
|
||||
|
||||
private val equalsMethod = getMethodOfAny("equals")
|
||||
private val hashCodeMethod = getMethodOfAny("hashCode")
|
||||
private val isEsModules = context.configuration[JSConfigurationKeys.MODULE_KIND] == ModuleKind.ES
|
||||
|
||||
override val bodyVisitor: BodyVisitorBase = object : BodyVisitorBase() {
|
||||
override fun visitCall(expression: IrCall, data: IrDeclaration) {
|
||||
super.visitCall(expression, data)
|
||||
|
||||
if (expression.usePrototype(data)) {
|
||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(expression.symbol.owner, "access to super type")
|
||||
}
|
||||
|
||||
when (expression.symbol) {
|
||||
context.intrinsics.jsBoxIntrinsic -> {
|
||||
val inlineClass = context.inlineClassesUtils.getInlinedClass(expression.getTypeArgument(0)!!)!!
|
||||
@@ -68,6 +77,21 @@ internal class JsUsefulDeclarationProcessor(
|
||||
constructedClasses += classToCreate
|
||||
}
|
||||
|
||||
context.intrinsics.jsCreateThisSymbol -> {
|
||||
val jsClassOrThis = expression.getValueArgument(0)
|
||||
|
||||
val classTypeToCreate = when (jsClassOrThis) {
|
||||
is IrCall -> jsClassOrThis.getTypeArgument(0)!!
|
||||
is IrGetValue -> jsClassOrThis.type
|
||||
else -> error("Unexpected first argument of createThis function call")
|
||||
}
|
||||
|
||||
val classToCreate = classTypeToCreate.classifierOrFail.owner as IrClass
|
||||
|
||||
classToCreate.enqueue(data, "intrinsic: jsCreateThis")
|
||||
constructedClasses += classToCreate
|
||||
}
|
||||
|
||||
context.intrinsics.jsEquals -> {
|
||||
equalsMethod.enqueue(data, "intrinsic: jsEquals")
|
||||
}
|
||||
@@ -86,26 +110,6 @@ internal class JsUsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
context.intrinsics.jsConstruct -> {
|
||||
val callType = expression.getTypeArgument(0)!!
|
||||
val constructor = callType.getClass()!!.primaryConstructor
|
||||
constructor!!.enqueue(data, "ctor call from jsConstruct-intrinsic")
|
||||
}
|
||||
|
||||
context.intrinsics.es6DefaultType -> {
|
||||
//same as jsClass
|
||||
val ref = expression.getTypeArgument(0)!!.classifierOrFail.owner as IrDeclaration
|
||||
ref.enqueue(data, "intrinsic: jsClass")
|
||||
referencedJsClasses += ref
|
||||
|
||||
//Generate klass in `val currResultType = resultType || klass`
|
||||
val arg = expression.getTypeArgument(0)!!
|
||||
val klass = arg.getClass()
|
||||
if (klass != null) {
|
||||
constructedClasses.add(klass)
|
||||
}
|
||||
}
|
||||
|
||||
context.intrinsics.jsInvokeSuspendSuperType,
|
||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiver,
|
||||
context.intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam -> {
|
||||
@@ -137,48 +141,57 @@ internal class JsUsefulDeclarationProcessor(
|
||||
}
|
||||
}
|
||||
|
||||
if (irClass.containsMetadata()) {
|
||||
when {
|
||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||
if (!irClass.containsMetadata()) return
|
||||
|
||||
irClass.isInterface -> {
|
||||
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
}
|
||||
when {
|
||||
irClass.isObject -> context.intrinsics.metadataObjectConstructorSymbol.owner.enqueue(irClass, "object metadata")
|
||||
|
||||
else -> {
|
||||
context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
irClass.isInterface -> {
|
||||
context.intrinsics.implementSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
context.intrinsics.metadataInterfaceConstructorSymbol.owner.enqueue(irClass, "interface metadata")
|
||||
}
|
||||
|
||||
else -> context.intrinsics.metadataClassConstructorSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
|
||||
if (!irClass.isExpect && !irClass.isExternal && !irClass.defaultType.isAny()) {
|
||||
if (!irClass.isInterface) {
|
||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
||||
|
||||
if (irClass.superTypes.any { !it.isInterface() }) {
|
||||
context.intrinsics.jsObjectCreateSymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
if (irClass.containsInterfaceDefaultImplementation()) {
|
||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "interface default implementation")
|
||||
}
|
||||
|
||||
if (irClass.isInner || irClass.isObject) {
|
||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irClass, "class metadata")
|
||||
}
|
||||
if ((!context.es6mode || !isEsModules) && (irClass.isInner || irClass.isObject)) {
|
||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irClass, "object lazy initialization")
|
||||
}
|
||||
|
||||
context.intrinsics.setMetadataForSymbol.owner.enqueue(irClass, "metadata")
|
||||
if (context.es6mode) return
|
||||
|
||||
if (!irClass.isInterface) {
|
||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irClass, "class prototype access")
|
||||
}
|
||||
|
||||
if (irClass.superTypes.any { !it.isInterface() }) {
|
||||
context.intrinsics.jsObjectCreateSymbol.owner.enqueue(irClass, "class inheritance code")
|
||||
}
|
||||
}
|
||||
|
||||
override fun processSimpleFunction(irFunction: IrSimpleFunction) {
|
||||
super.processSimpleFunction(irFunction)
|
||||
|
||||
if (irFunction.isEs6ConstructorReplacement) {
|
||||
constructedClasses += irFunction.dispatchReceiverParameter?.type?.classOrNull?.owner!!
|
||||
}
|
||||
|
||||
if (irFunction.isReal && irFunction.body != null) {
|
||||
irFunction.parentClassOrNull?.takeIf { it.isInterface }?.enqueue(irFunction, "interface default method is used")
|
||||
}
|
||||
|
||||
if (context.es6mode && isEsModules) return
|
||||
|
||||
val property = irFunction.correspondingPropertySymbol?.owner ?: return
|
||||
|
||||
if (property.isExported(context) || property.isOverriddenExternal()) {
|
||||
if (property.isExported(context) || property.getJsName() != null || property.isOverriddenExternal()) {
|
||||
context.intrinsics.jsPrototypeOfSymbol.owner.enqueue(irFunction, "property for export")
|
||||
context.intrinsics.jsDefinePropertySymbol.owner.enqueue(irFunction, "property for export")
|
||||
}
|
||||
}
|
||||
@@ -225,8 +238,24 @@ internal class JsUsefulDeclarationProcessor(
|
||||
}
|
||||
|
||||
override fun isExported(declaration: IrDeclaration): Boolean = declaration.isExported(context)
|
||||
}
|
||||
|
||||
private fun IrCall.usePrototype(container: IrDeclaration?): Boolean {
|
||||
if (superQualifierSymbol == null) return false
|
||||
|
||||
val currentFun = (container as? IrSimpleFunction)
|
||||
val currentClass = currentFun?.parentClassOrNull
|
||||
|
||||
return !context.es6mode ||
|
||||
currentFun?.dispatchReceiverParameter == null ||
|
||||
currentClass != null && (currentClass.isInner || currentClass.isLocal)
|
||||
}
|
||||
|
||||
private fun IrClass.containsInterfaceDefaultImplementation(): Boolean {
|
||||
return superTypes.any { it.classOrNull?.owner?.isExternal == true } ||
|
||||
isExported(context) ||
|
||||
isInterface && declarations.any { it is IrFunction && it.body != null }
|
||||
}
|
||||
}
|
||||
|
||||
private fun Collection<IrClass>.filterDescendantsOf(bases: Collection<IrClass>): Collection<IrClass> {
|
||||
val visited = hashSetOf<IrClass>()
|
||||
|
||||
-1
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.backend.js.utils.isAssociatedObjectAnnotatedAnnot
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
|
||||
+8
-6
@@ -13,8 +13,8 @@ import org.jetbrains.kotlin.descriptors.DescriptorVisibility
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBoxParameter
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
@@ -86,7 +86,7 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
returnType = exportType(function.returnType),
|
||||
typeParameters = function.typeParameters.map(::exportTypeParameter),
|
||||
isMember = parent is IrClass,
|
||||
isStatic = function.isStaticMethodOfClass,
|
||||
isStatic = function.isStaticMethod,
|
||||
isAbstract = parent is IrClass && !parent.isInterface && function.modality == Modality.ABSTRACT,
|
||||
isProtected = function.visibility == DescriptorVisibilities.PROTECTED,
|
||||
ir = function,
|
||||
@@ -100,10 +100,9 @@ class ExportModelGenerator(val context: JsIrBackendContext, val generateNamespac
|
||||
|
||||
private fun exportConstructor(constructor: IrConstructor): ExportedDeclaration? {
|
||||
if (!constructor.isPrimary) return null
|
||||
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) +
|
||||
constructor.valueParameters.filterNot { it.origin === ES6_RESULT_TYPE_PARAMETER || it.origin === ES6_INIT_BOX_PARAMETER }
|
||||
val allValueParameters = listOfNotNull(constructor.extensionReceiverParameter) + constructor.valueParameters
|
||||
return ExportedConstructor(
|
||||
parameters = allValueParameters.map { exportParameter(it) },
|
||||
parameters = allValueParameters.filterNot { it.isBoxParameter }.map { exportParameter(it) },
|
||||
visibility = constructor.visibility.toExportedVisibility()
|
||||
)
|
||||
}
|
||||
@@ -696,6 +695,9 @@ private class ExportedClassDeclarationsInfo(
|
||||
private val IrClassifierSymbol.isInterface
|
||||
get() = (owner as? IrClass)?.isInterface == true
|
||||
|
||||
private val IrFunction.isStaticMethod: Boolean
|
||||
get() = isEs6ConstructorReplacement || isStaticMethodOfClass
|
||||
|
||||
private fun getExportCandidate(declaration: IrDeclaration): IrDeclarationWithName? {
|
||||
// Only actual public declarations with name can be exported
|
||||
if (declaration !is IrDeclarationWithVisibility ||
|
||||
|
||||
+139
-61
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.export
|
||||
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.JsAstUtils
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.defineProperty
|
||||
import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsAssignment
|
||||
@@ -15,13 +16,16 @@ import org.jetbrains.kotlin.ir.backend.js.transformers.irToJs.jsElementAccess
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.emptyScope
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getJsNameOrKotlinName
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.util.companionObject
|
||||
import org.jetbrains.kotlin.ir.util.isObject
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||
|
||||
class ExportModelToJsStatements(
|
||||
private val namer: JsStaticContext,
|
||||
private val declareNewNamespace: (String) -> String
|
||||
private val staticContext: JsStaticContext,
|
||||
private val es6mode: Boolean,
|
||||
private val declareNewNamespace: (String) -> String,
|
||||
) {
|
||||
private val namespaceToRefMap = mutableMapOf<String, JsNameRef>()
|
||||
|
||||
@@ -38,7 +42,8 @@ class ExportModelToJsStatements(
|
||||
fun generateDeclarationExport(
|
||||
declaration: ExportedDeclaration,
|
||||
namespace: JsExpression?,
|
||||
esModules: Boolean
|
||||
esModules: Boolean,
|
||||
parentClass: IrClass? = null
|
||||
): List<JsStatement> {
|
||||
return when (declaration) {
|
||||
is ExportedNamespace -> {
|
||||
@@ -73,7 +78,7 @@ class ExportModelToJsStatements(
|
||||
}
|
||||
|
||||
is ExportedFunction -> {
|
||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
||||
val name = staticContext.getNameForStaticDeclaration(declaration.ir)
|
||||
when {
|
||||
namespace != null ->
|
||||
listOf(jsAssignment(jsElementAccess(declaration.name, namespace), JsNameRef(name)).makeStmt())
|
||||
@@ -88,28 +93,29 @@ class ExportModelToJsStatements(
|
||||
|
||||
is ExportedProperty -> {
|
||||
require(namespace != null || esModules) { "Only namespaced properties are allowed" }
|
||||
val getter = declaration.irGetter?.let { namer.getNameForStaticDeclaration(it) }
|
||||
val setter = declaration.irSetter?.let { namer.getNameForStaticDeclaration(it) }
|
||||
if (namespace == null) {
|
||||
val property = JsVars.JsVar(
|
||||
JsName(declaration.name, false),
|
||||
JsObjectLiteral(false).apply {
|
||||
getter?.let {
|
||||
val fieldName = when (declaration.irGetter.origin) {
|
||||
JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION -> "getInstance"
|
||||
else -> "get"
|
||||
}
|
||||
propertyInitializers += JsPropertyInitializer(JsStringLiteral(fieldName), it.makeRef())
|
||||
}
|
||||
setter?.let { propertyInitializers += JsPropertyInitializer(JsStringLiteral("set"), it.makeRef()) }
|
||||
}
|
||||
)
|
||||
listOf(
|
||||
JsVars(property),
|
||||
JsExport(property.name, JsName(declaration.name, false))
|
||||
)
|
||||
} else {
|
||||
listOf(defineProperty(namespace, declaration.name, getter?.makeRef(), setter?.makeRef(), namer).makeStmt())
|
||||
when {
|
||||
namespace == null -> {
|
||||
val property = declaration.generateTopLevelGetters()
|
||||
listOf(JsVars(property), JsExport(property.name, JsName(declaration.name, false)))
|
||||
}
|
||||
es6mode && declaration.isMember -> {
|
||||
val jsClass = parentClass?.getCorrespondingJsClass() ?: error("Expect to have parentClass at this point")
|
||||
jsClass.members += declaration.generateClassMembers()
|
||||
listOf(JsEmpty)
|
||||
}
|
||||
else -> {
|
||||
val getter = declaration.irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||
val setter = declaration.irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||
listOf(
|
||||
defineProperty(
|
||||
namespace,
|
||||
declaration.name,
|
||||
getter?.makeRef(),
|
||||
setter?.makeRef(),
|
||||
staticContext
|
||||
).makeStmt()
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -120,24 +126,31 @@ class ExportModelToJsStatements(
|
||||
val newNameSpace = when {
|
||||
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||
else ->
|
||||
jsElementAccess(Namer.PROTOTYPE_NAME, namer.getNameForClass(declaration.ir).makeRef())
|
||||
jsElementAccess(Namer.PROTOTYPE_NAME, staticContext.getNameForClass(declaration.ir).makeRef())
|
||||
}
|
||||
val staticsExport = declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
||||
val staticsExport =
|
||||
declaration.nestedClasses.flatMap { generateDeclarationExport(it, newNameSpace, esModules, declaration.ir) }
|
||||
|
||||
val objectExport = when (namespace) {
|
||||
null -> generateDeclarationExport(
|
||||
ExportedProperty(declaration.name, ExportedType.Primitive.Any, irGetter = declaration.irGetter),
|
||||
val objectExport = when {
|
||||
es6mode || namespace == null -> generateDeclarationExport(
|
||||
ExportedProperty(
|
||||
declaration.name,
|
||||
ExportedType.Primitive.Any,
|
||||
isStatic = parentClass?.isObject != true,
|
||||
irGetter = declaration.irGetter,
|
||||
isMember = parentClass != null
|
||||
),
|
||||
namespace,
|
||||
esModules
|
||||
esModules,
|
||||
parentClass
|
||||
)
|
||||
|
||||
else -> listOf(
|
||||
defineProperty(
|
||||
namespace,
|
||||
declaration.name,
|
||||
namer.getNameForStaticDeclaration(declaration.irGetter).makeRef(),
|
||||
staticContext.getNameForStaticDeclaration(declaration.irGetter).makeRef(),
|
||||
null,
|
||||
namer
|
||||
staticContext
|
||||
).makeStmt()
|
||||
)
|
||||
}
|
||||
@@ -147,11 +160,11 @@ class ExportModelToJsStatements(
|
||||
|
||||
is ExportedRegularClass -> {
|
||||
if (declaration.isInterface) return emptyList()
|
||||
val name = namer.getNameForStaticDeclaration(declaration.ir)
|
||||
val name = staticContext.getNameForStaticDeclaration(declaration.ir)
|
||||
val newNameSpace = when {
|
||||
namespace != null -> jsElementAccess(declaration.name, namespace)
|
||||
esModules -> name.makeRef()
|
||||
else -> prototypeOf(namer.getNameForClass(declaration.ir).makeRef(), namer)
|
||||
else -> prototypeOf(staticContext.getNameForClass(declaration.ir).makeRef(), staticContext)
|
||||
}
|
||||
val klassExport = when {
|
||||
namespace != null -> jsAssignment(newNameSpace, JsNameRef(name)).makeStmt()
|
||||
@@ -161,7 +174,7 @@ class ExportModelToJsStatements(
|
||||
|
||||
// These are only used when exporting secondary constructors annotated with @JsName
|
||||
val staticFunctions = declaration.members
|
||||
.filter { it is ExportedFunction && it.isStatic }
|
||||
.filter { it is ExportedFunction && it.isStatic && !it.ir.isEs6ConstructorReplacement }
|
||||
.takeIf { !declaration.ir.isInner }.orEmpty()
|
||||
|
||||
val enumEntries = declaration.members.filter { it is ExportedProperty && it.isStatic }
|
||||
@@ -171,22 +184,75 @@ class ExportModelToJsStatements(
|
||||
.map { it.generateInnerClassAssignment(declaration) }
|
||||
|
||||
val staticsExport = (staticFunctions + enumEntries + declaration.nestedClasses)
|
||||
.flatMap { generateDeclarationExport(it, newNameSpace, esModules) }
|
||||
.flatMap { generateDeclarationExport(it, newNameSpace, esModules, declaration.ir) }
|
||||
|
||||
listOfNotNull(klassExport) + staticsExport + innerClassesAssignments
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExportedProperty.generateTopLevelGetters(): JsVars.JsVar {
|
||||
val getter = irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||
val setter = irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||
|
||||
return JsVars.JsVar(
|
||||
JsName(name, false),
|
||||
JsObjectLiteral(false).apply {
|
||||
getter?.let {
|
||||
val fieldName = when (irGetter?.origin) {
|
||||
JsLoweredDeclarationOrigin.OBJECT_GET_INSTANCE_FUNCTION -> "getInstance"
|
||||
else -> "get"
|
||||
}
|
||||
propertyInitializers += JsPropertyInitializer(JsStringLiteral(fieldName), it.makeRef())
|
||||
}
|
||||
setter?.let { propertyInitializers += JsPropertyInitializer(JsStringLiteral("set"), it.makeRef()) }
|
||||
}
|
||||
)
|
||||
}
|
||||
|
||||
private fun ExportedProperty.generateClassMembers(): List<JsFunction> {
|
||||
val getter = irGetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||
val setter = irSetter?.let { staticContext.getNameForStaticDeclaration(it) }
|
||||
|
||||
return buildList {
|
||||
if (getter != null) {
|
||||
add(JsFunction(emptyScope, "").also {
|
||||
it.name = JsName(name, false)
|
||||
if (isStatic) {
|
||||
it.modifiers.add(JsFunction.Modifier.STATIC)
|
||||
}
|
||||
it.modifiers.add(JsFunction.Modifier.GET)
|
||||
it.body = JsBlock().apply {
|
||||
statements.add(JsReturn(JsInvocation(getter.makeRef())))
|
||||
}
|
||||
})
|
||||
}
|
||||
if (setter != null) {
|
||||
add(JsFunction(emptyScope, "").also {
|
||||
val value = JsName("value", true)
|
||||
it.name = JsName(name, false)
|
||||
it.parameters.add(JsParameter(value))
|
||||
if (isStatic) {
|
||||
it.modifiers.add(JsFunction.Modifier.STATIC)
|
||||
}
|
||||
it.modifiers.add(JsFunction.Modifier.SET)
|
||||
it.body = JsBlock().apply {
|
||||
statements.add(JsExpressionStatement(JsInvocation(setter.makeRef(), value.makeRef())))
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun ExportedClass.generateInnerClassAssignment(outerClass: ExportedClass): JsStatement {
|
||||
val innerClassRef = namer.getNameForStaticDeclaration(ir).makeRef()
|
||||
val outerClassRef = namer.getNameForStaticDeclaration(outerClass.ir).makeRef()
|
||||
val innerClassRef = staticContext.getNameForStaticDeclaration(ir).makeRef()
|
||||
val outerClassRef = staticContext.getNameForStaticDeclaration(outerClass.ir).makeRef()
|
||||
val companionObject = ir.companionObject()
|
||||
val secondaryConstructors = members.filterIsInstanceAnd<ExportedFunction> { it.isStatic }
|
||||
val bindConstructor = JsName("__bind_constructor_", false)
|
||||
|
||||
val blockStatements = mutableListOf<JsStatement>(
|
||||
JsVars(JsVars.JsVar(bindConstructor, innerClassRef.bindToThis()))
|
||||
JsVars(JsVars.JsVar(bindConstructor, innerClassRef.bindToThis(innerClassRef)))
|
||||
)
|
||||
|
||||
if (companionObject != null) {
|
||||
@@ -200,35 +266,47 @@ class ExportModelToJsStatements(
|
||||
}
|
||||
|
||||
secondaryConstructors.forEach {
|
||||
val currentFunRef = namer.getNameForStaticDeclaration(it.ir).makeRef()
|
||||
val currentFunRef = if (it.ir.isEs6ConstructorReplacement) {
|
||||
JsNameRef(staticContext.getNameForMemberFunction(it.ir), innerClassRef)
|
||||
} else {
|
||||
staticContext.getNameForStaticDeclaration(it.ir).makeRef()
|
||||
}
|
||||
|
||||
val assignment = jsAssignment(
|
||||
JsNameRef(it.name, bindConstructor.makeRef()),
|
||||
currentFunRef.bindToThis()
|
||||
currentFunRef.bindToThis(innerClassRef)
|
||||
).makeStmt()
|
||||
|
||||
blockStatements.add(assignment)
|
||||
}
|
||||
|
||||
blockStatements.add(JsReturn(bindConstructor.makeRef()))
|
||||
val innerClassGetter = JsFunction(emptyScope, JsBlock(*blockStatements.toTypedArray()), "inner class '$name' getter")
|
||||
|
||||
return defineProperty(
|
||||
prototypeOf(outerClassRef, namer),
|
||||
name,
|
||||
JsFunction(
|
||||
emptyScope,
|
||||
JsBlock(*blockStatements.toTypedArray()),
|
||||
"inner class '$name' getter"
|
||||
),
|
||||
null,
|
||||
namer
|
||||
).makeStmt()
|
||||
return if (es6mode) {
|
||||
outerClass.ir.getCorrespondingJsClass().members += innerClassGetter.also {
|
||||
it.name = JsName(name, false)
|
||||
it.modifiers.add(JsFunction.Modifier.GET)
|
||||
}
|
||||
JsEmpty
|
||||
} else {
|
||||
defineProperty(
|
||||
prototypeOf(outerClassRef, staticContext),
|
||||
name,
|
||||
innerClassGetter,
|
||||
null,
|
||||
staticContext
|
||||
).makeStmt()
|
||||
}
|
||||
}
|
||||
|
||||
private fun JsNameRef.bindToThis(): JsInvocation {
|
||||
return JsInvocation(
|
||||
JsNameRef("bind", this),
|
||||
JsNullLiteral(),
|
||||
JsThisRef()
|
||||
)
|
||||
private fun IrClass.getCorrespondingJsClass(): JsClass {
|
||||
val jsClassModel = staticContext.classModels[symbol] ?: error("Class with name '$name' was not found")
|
||||
return (jsClassModel.preDeclarationBlock.statements.first() as? JsExpressionStatement)?.expression as? JsClass
|
||||
?: error("Expect to have JsClass as a first statement inside JsIrClassModel")
|
||||
}
|
||||
|
||||
private fun JsNameRef.bindToThis(bindTo: JsExpression): JsInvocation {
|
||||
return JsInvocation(JsNameRef("bind", this), bindTo, JsThisRef())
|
||||
}
|
||||
}
|
||||
|
||||
-1
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.types.impl.IrSimpleTypeImpl
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.superTypes
|
||||
|
||||
@@ -734,6 +734,7 @@ fun rebuildCacheForDirtyFiles(
|
||||
irFactory: IrFactory,
|
||||
exportedDeclarations: Set<FqName>,
|
||||
mainArguments: List<String>?,
|
||||
es6mode: Boolean
|
||||
): Pair<IrModuleFragment, List<Pair<IrFile, JsIrProgramFragment>>> {
|
||||
val emptyMetadata = object : KotlinSourceFileExports() {
|
||||
override val inverseDependencies = KotlinSourceFileMap<Set<IdSignature>>(emptyMap())
|
||||
@@ -753,7 +754,13 @@ fun rebuildCacheForDirtyFiles(
|
||||
currentIrModule.files.filter { irFile -> irFile.fileEntry.name in files }
|
||||
} ?: currentIrModule.files
|
||||
|
||||
val compilerWithIC = JsIrCompilerWithIC(currentIrModule, configuration, JsGenerationGranularity.PER_MODULE, exportedDeclarations)
|
||||
val compilerWithIC = JsIrCompilerWithIC(
|
||||
currentIrModule,
|
||||
configuration,
|
||||
JsGenerationGranularity.PER_MODULE,
|
||||
exportedDeclarations,
|
||||
es6mode
|
||||
)
|
||||
|
||||
// Load declarations referenced during `context` initialization
|
||||
jsIrLinker.loadUnboundSymbols()
|
||||
|
||||
@@ -15,19 +15,19 @@ import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.*
|
||||
import org.jetbrains.kotlin.ir.symbols.*
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
object JsIrBuilder {
|
||||
|
||||
|
||||
object SYNTHESIZED_DECLARATION : IrDeclarationOriginImpl("SYNTHESIZED_DECLARATION")
|
||||
|
||||
fun buildCall(
|
||||
target: IrSimpleFunctionSymbol,
|
||||
type: IrType? = null,
|
||||
typeArguments: List<IrType>? = null,
|
||||
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT
|
||||
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT,
|
||||
superQualifierSymbol: IrClassSymbol? = null,
|
||||
): IrCall {
|
||||
val owner = target.owner
|
||||
return IrCallImpl(
|
||||
@@ -35,6 +35,7 @@ object JsIrBuilder {
|
||||
UNDEFINED_OFFSET,
|
||||
type ?: owner.returnType,
|
||||
target,
|
||||
superQualifierSymbol = superQualifierSymbol,
|
||||
typeArgumentsCount = owner.typeParameters.size,
|
||||
valueArgumentsCount = owner.valueParameters.size,
|
||||
origin = origin
|
||||
@@ -46,54 +47,95 @@ object JsIrBuilder {
|
||||
}
|
||||
}
|
||||
|
||||
fun buildConstructorCall(
|
||||
target: IrConstructorSymbol,
|
||||
type: IrType? = null,
|
||||
typeArguments: List<IrType>? = null,
|
||||
constructorTypeArguments: List<IrType>? = null,
|
||||
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT
|
||||
): IrConstructorCall {
|
||||
fun buildArray(elements: List<IrExpression>, type: IrType, elementType: IrType): IrExpression {
|
||||
return IrVarargImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
type,
|
||||
elementType,
|
||||
elements
|
||||
)
|
||||
}
|
||||
|
||||
fun buildDelegatingConstructorCall(target: IrConstructorSymbol, typeArguments: List<IrType?>? = null): IrDelegatingConstructorCall {
|
||||
val owner = target.owner
|
||||
val parent = owner.parentAsClass
|
||||
return IrConstructorCallImpl(
|
||||
val irClass = owner.parentAsClass
|
||||
|
||||
return IrDelegatingConstructorCallImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
type ?: owner.returnType,
|
||||
owner.returnType,
|
||||
target,
|
||||
typeArgumentsCount = parent.typeParameters.size,
|
||||
typeArgumentsCount = irClass.typeParameters.size,
|
||||
valueArgumentsCount = owner.valueParameters.size,
|
||||
constructorTypeArgumentsCount = owner.typeParameters.size,
|
||||
origin = origin
|
||||
).apply {
|
||||
typeArguments?.let {
|
||||
assert(typeArguments.size == typeArgumentsCount)
|
||||
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||
}
|
||||
constructorTypeArguments?.let {
|
||||
assert(constructorTypeArguments.size == constructorTypeArgumentsCount)
|
||||
assert(it.size == typeArgumentsCount)
|
||||
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun buildConstructorCall(
|
||||
target: IrConstructorSymbol,
|
||||
typeArguments: List<IrType?>? = null,
|
||||
constructorTypeArguments: List<IrType?>? = null,
|
||||
origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT
|
||||
): IrConstructorCall {
|
||||
val owner = target.owner
|
||||
val irClass = owner.parentAsClass
|
||||
|
||||
return IrConstructorCallImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
owner.returnType,
|
||||
target,
|
||||
typeArgumentsCount = irClass.typeParameters.size,
|
||||
constructorTypeArgumentsCount = owner.typeParameters.size,
|
||||
valueArgumentsCount = owner.valueParameters.size,
|
||||
origin = origin
|
||||
).apply {
|
||||
typeArguments?.let {
|
||||
assert(it.size == typeArgumentsCount)
|
||||
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||
}
|
||||
|
||||
constructorTypeArguments?.let {
|
||||
assert(it.size == typeArgumentsCount)
|
||||
it.withIndex().forEach { (i, t) -> putTypeArgument(i, t) }
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fun buildRawReference(targetSymbol: IrFunctionSymbol, type: IrType): IrRawFunctionReference =
|
||||
IrRawFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, targetSymbol)
|
||||
|
||||
fun buildReturn(targetSymbol: IrFunctionSymbol, value: IrExpression, type: IrType) =
|
||||
IrReturnImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, targetSymbol, value)
|
||||
|
||||
fun buildThrow(type: IrType, value: IrExpression) = IrThrowImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, value)
|
||||
|
||||
fun buildValueParameter(parent: IrFunction, name: String, index: Int, type: IrType): IrValueParameter =
|
||||
fun buildValueParameter(
|
||||
parent: IrFunction,
|
||||
name: String,
|
||||
index: Int,
|
||||
type: IrType,
|
||||
isAssignable: Boolean = false,
|
||||
origin: IrDeclarationOrigin = SYNTHESIZED_DECLARATION
|
||||
): IrValueParameter =
|
||||
buildValueParameter(parent) {
|
||||
this.origin = SYNTHESIZED_DECLARATION
|
||||
this.origin = origin
|
||||
this.name = Name.identifier(name)
|
||||
this.index = index
|
||||
this.type = type
|
||||
this.isAssignable = isAssignable
|
||||
}
|
||||
|
||||
fun buildGetObjectValue(type: IrType, classSymbol: IrClassSymbol) =
|
||||
IrGetObjectValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, type, classSymbol)
|
||||
|
||||
fun buildGetValue(symbol: IrValueSymbol) =
|
||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
||||
fun buildGetValue(symbol: IrValueSymbol, origin: IrStatementOrigin = JsStatementOrigins.SYNTHESIZED_STATEMENT) =
|
||||
IrGetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, origin)
|
||||
|
||||
fun buildSetValue(symbol: IrValueSymbol, value: IrExpression) =
|
||||
IrSetValueImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, symbol.owner.type, symbol, value, JsStatementOrigins.SYNTHESIZED_STATEMENT)
|
||||
|
||||
+8
-2
@@ -5,17 +5,20 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
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.backend.js.JsCommonBackendContext
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
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
|
||||
|
||||
class AnnotationConstructorLowering(context: CommonBackendContext) : DeclarationTransformer {
|
||||
class AnnotationConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private val unitType = context.irBuiltIns.unitType
|
||||
private val anyConstructor = context.irBuiltIns.anyClass.constructors.first()
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrConstructor || !declaration.isPrimary) return null
|
||||
@@ -27,6 +30,9 @@ class AnnotationConstructorLowering(context: CommonBackendContext) : Declaration
|
||||
// put empty body to make sure proper initializer is generated
|
||||
// TODO what about its previous body?
|
||||
declaration.body = declaration.factory.createBlockBody(declaration.startOffset, declaration.endOffset) {
|
||||
if (context.es6mode) {
|
||||
statements += IrDelegatingConstructorCallImpl(startOffset, endOffset, context.irBuiltIns.anyType, anyConstructor, 0, 0)
|
||||
}
|
||||
statements += IrInstanceInitializerCallImpl(startOffset, endOffset, irClass.symbol, unitType)
|
||||
}
|
||||
|
||||
|
||||
+1
-3
@@ -36,9 +36,7 @@ class JsBlockDecomposerLowering(val context: JsIrBackendContext) : AbstractBlock
|
||||
JsIrBuilder.buildCall(context.intrinsics.unreachable, context.irBuiltIns.nothingType)
|
||||
}
|
||||
|
||||
abstract class AbstractBlockDecomposerLowering(
|
||||
private val context: JsCommonBackendContext
|
||||
) : BodyLoweringPass {
|
||||
abstract class AbstractBlockDecomposerLowering(private val context: JsCommonBackendContext) : BodyLoweringPass {
|
||||
|
||||
private val nothingType = context.irBuiltIns.nothingType
|
||||
|
||||
|
||||
+5
-1
@@ -179,7 +179,11 @@ class CallableReferenceLowering(private val context: CommonBackendContext) : Bod
|
||||
origin = if (isKReference || !isLambda) FUNCTION_REFERENCE_IMPL else LAMBDA_IMPL
|
||||
name = makeContextDependentName()
|
||||
}.apply {
|
||||
superTypes = listOfNotNull(superClass, referenceType, secondFunctionInterface?.symbol?.typeWithArguments(referenceType.arguments))
|
||||
superTypes = listOfNotNull(
|
||||
this@CallableReferenceBuilder.superClass,
|
||||
referenceType,
|
||||
secondFunctionInterface?.symbol?.typeWithArguments(referenceType.arguments)
|
||||
)
|
||||
// if (samSuperType == null)
|
||||
// superTypes += functionSuperClass.typeWith(parameterTypes)
|
||||
// if (irFunctionReference.isSuspend) superTypes += context.ir.symbols.suspendFunctionInterface.defaultType
|
||||
|
||||
+34
-8
@@ -6,18 +6,23 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Visibilities
|
||||
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.IrConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
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.IrDelegatingConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrRawFunctionReferenceImpl
|
||||
import org.jetbrains.kotlin.ir.util.isSubclassOf
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
object ES6_THROWABLE_CONSTRUCTOR_SLOT : IrDeclarationOriginImpl("ES6_THROWABLE_CONSTRUCTOR_SLOT")
|
||||
/**
|
||||
* Capture stack trace in primary constructors of Throwable
|
||||
*/
|
||||
@@ -31,15 +36,36 @@ class CaptureStackTraceInThrowables(val context: JsIrBackendContext) : BodyLower
|
||||
if (!klass.isSubclassOf(context.irBuiltIns.throwableClass.owner))
|
||||
return
|
||||
|
||||
val statements = (irBody as IrBlockBody).statements
|
||||
val statements = (irBody as? IrBlockBody)?.statements ?: return
|
||||
val delegatingConstructorCallIndex = statements.indexOfLast { it is IrDelegatingConstructorCall }
|
||||
|
||||
statements.add(delegatingConstructorCallIndex + 1, JsIrBuilder.buildCall(context.intrinsics.captureStack).also { call ->
|
||||
call.putValueArgument(0, JsIrBuilder.buildGetValue(klass.thisReceiver!!.symbol))
|
||||
call.putValueArgument(
|
||||
1,
|
||||
IrRawFunctionReferenceImpl(UNDEFINED_OFFSET, UNDEFINED_OFFSET, context.irBuiltIns.anyType, container.symbol)
|
||||
)
|
||||
val self = klass.thisReceiver!!.symbol
|
||||
|
||||
val constructorRef = if (context.es6mode) {
|
||||
JsIrBuilder.buildGetField(klass.addThrowableConstructorSlot().symbol, JsIrBuilder.buildGetValue(self))
|
||||
} else {
|
||||
JsIrBuilder.buildRawReference(container.symbol, context.irBuiltIns.anyType)
|
||||
}
|
||||
|
||||
call.putValueArgument(0, JsIrBuilder.buildGetValue(self))
|
||||
call.putValueArgument(1, constructorRef)
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrClass.addThrowableConstructorSlot(): IrField {
|
||||
return factory.buildField {
|
||||
type = context.dynamicType
|
||||
isFinal = false
|
||||
isExternal = false
|
||||
isStatic = false
|
||||
metadata = null
|
||||
name = Name.identifier(Namer.THROWABLE_CONSTRUCTOR)
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
origin = ES6_THROWABLE_CONSTRUCTOR_SLOT
|
||||
}.apply {
|
||||
parent = this@addThrowableConstructorSlot
|
||||
declarations.add(this)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+13
-1
@@ -8,14 +8,20 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.declarations.IrConstructor
|
||||
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
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
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.types.IrType
|
||||
import org.jetbrains.kotlin.ir.types.classifierOrNull
|
||||
import org.jetbrains.kotlin.ir.types.defaultType
|
||||
@@ -33,7 +39,13 @@ class ConstTransformer(private val context: JsIrBackendContext) : IrElementTrans
|
||||
): IrExpression {
|
||||
val constructor = irClass.constructors.single { it.owner.isPrimary }
|
||||
val argType = constructor.owner.valueParameters.first().type
|
||||
return IrConstructorCallImpl.fromSymbolOwner(expression.startOffset, expression.endOffset, irClass.defaultType, constructor).apply {
|
||||
|
||||
return IrConstructorCallImpl.fromSymbolOwner(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
irClass.defaultType,
|
||||
constructor
|
||||
).apply {
|
||||
for (i in args.indices) {
|
||||
putValueArgument(i, carrierFactory(startOffset, endOffset, argType, args[i]))
|
||||
}
|
||||
|
||||
+182
@@ -0,0 +1,182 @@
|
||||
/*
|
||||
* 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||
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.getVoid
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.hasStrictSignature
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
|
||||
object ES6_BOX_PARAMETER : IrDeclarationOriginImpl("ES6_BOX_PARAMETER")
|
||||
object ES6_BOX_PARAMETER_DEFAULT_RESOLUTION : IrStatementOriginImpl("ES6_BOX_PARAMETER_DEFAULT_RESOLUTION")
|
||||
|
||||
val IrValueParameter.isBoxParameter: Boolean
|
||||
get() = origin == ES6_BOX_PARAMETER
|
||||
|
||||
val IrWhen.isBoxParameterDefaultResolution: Boolean
|
||||
get() = origin == ES6_BOX_PARAMETER_DEFAULT_RESOLUTION
|
||||
|
||||
val IrFunction.boxParameter: IrValueParameter?
|
||||
get() = valueParameters.lastOrNull()?.takeIf { it.isBoxParameter }
|
||||
|
||||
class ES6AddBoxParameterToConstructorsLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (!context.es6mode || declaration !is IrConstructor || declaration.hasStrictSignature(context)) return null
|
||||
|
||||
hackEnums(declaration)
|
||||
hackExceptions(declaration)
|
||||
hackSimpleClassWithCapturing(declaration)
|
||||
|
||||
if (!declaration.isSyntheticPrimaryConstructor) {
|
||||
declaration.addBoxParameter()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun IrConstructor.addBoxParameter() {
|
||||
val irClass = parentAsClass
|
||||
val boxParameter = generateBoxParameter(irClass).also { valueParameters += it }
|
||||
|
||||
val body = body as? IrBlockBody ?: return
|
||||
val isBoxUsed = body.replaceThisWithBoxBeforeSuperCall(irClass, boxParameter.symbol)
|
||||
|
||||
if (isBoxUsed) {
|
||||
body.statements.add(0, boxParameter.generateDefaultResolution())
|
||||
}
|
||||
}
|
||||
|
||||
private fun createJsObjectLiteral(): IrExpression {
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsEmptyObject)
|
||||
}
|
||||
|
||||
private fun IrConstructor.generateBoxParameter(irClass: IrClass): IrValueParameter {
|
||||
return JsIrBuilder.buildValueParameter(
|
||||
parent = this,
|
||||
name = Namer.ES6_BOX_PARAMETER_NAME,
|
||||
index = valueParameters.size,
|
||||
type = irClass.defaultType.makeNullable(),
|
||||
origin = ES6_BOX_PARAMETER,
|
||||
isAssignable = true
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrValueParameter.generateDefaultResolution(): IrExpression {
|
||||
return with(context.createIrBuilder(symbol, UNDEFINED_OFFSET, UNDEFINED_OFFSET)) {
|
||||
irIfThen(
|
||||
context.irBuiltIns.unitType,
|
||||
irEqeqeqWithoutBox(irGet(type, symbol), this@ES6AddBoxParameterToConstructorsLowering.context.getVoid()),
|
||||
irSet(symbol, createJsObjectLiteral()),
|
||||
ES6_BOX_PARAMETER_DEFAULT_RESOLUTION
|
||||
)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrBody.replaceThisWithBoxBeforeSuperCall(irClass: IrClass, boxParameterSymbol: IrValueSymbol): Boolean {
|
||||
var meetCapturing = false
|
||||
var meetDelegatingConstructor = false
|
||||
val selfParameterSymbol = irClass.thisReceiver!!.symbol
|
||||
|
||||
transformChildrenVoid(object : ValueRemapper(mapOf(selfParameterSymbol to boxParameterSymbol)) {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
return if (meetDelegatingConstructor) {
|
||||
expression
|
||||
} else {
|
||||
super.visitGetValue(expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitSetField(expression: IrSetField): IrExpression {
|
||||
if (meetDelegatingConstructor) return expression
|
||||
val newExpression = super.visitSetField(expression)
|
||||
val receiver = expression.receiver as? IrGetValue
|
||||
|
||||
if (receiver?.symbol == boxParameterSymbol) {
|
||||
meetCapturing = true
|
||||
}
|
||||
|
||||
return newExpression
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
meetDelegatingConstructor = true
|
||||
return super.visitDelegatingConstructorCall(expression)
|
||||
}
|
||||
})
|
||||
|
||||
return meetCapturing
|
||||
}
|
||||
|
||||
private fun hackEnums(constructor: IrConstructor) {
|
||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||
return (expression.argument as? IrDelegatingConstructorCall) ?: expression
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun hackSimpleClassWithCapturing(constructor: IrConstructor) {
|
||||
val irClass = constructor.parentAsClass
|
||||
|
||||
if (irClass.superClass != null || (!irClass.isInner && !irClass.isLocal)) return
|
||||
|
||||
val statements = (constructor.body as? IrBlockBody)?.statements ?: return
|
||||
val delegationConstructorIndex = statements.indexOfFirst { it is IrDelegatingConstructorCall }
|
||||
|
||||
if (delegationConstructorIndex == -1) return
|
||||
|
||||
val firstClassFieldAssignment = statements.indexOfFirst { statement ->
|
||||
statement is IrSetField && statement.receiver?.let { it is IrGetValue && it.symbol == irClass.thisReceiver?.symbol } == true
|
||||
}
|
||||
|
||||
if (firstClassFieldAssignment == -1 || firstClassFieldAssignment > delegationConstructorIndex) return
|
||||
|
||||
statements.add(firstClassFieldAssignment, statements[delegationConstructorIndex])
|
||||
statements.removeAt(delegationConstructorIndex + 1)
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap call synthetic primary ctor and call extendThrowable
|
||||
*/
|
||||
private fun hackExceptions(constructor: IrConstructor) {
|
||||
val setPropertiesSymbol = context.setPropertiesToThrowableInstanceSymbol
|
||||
|
||||
val statements = (constructor.body as? IrBlockBody)?.statements ?: return
|
||||
|
||||
var callIndex = -1
|
||||
var superCallIndex = -1
|
||||
for (i in statements.indices) {
|
||||
val s = statements[i]
|
||||
|
||||
if (s is IrCall && s.symbol === setPropertiesSymbol) {
|
||||
callIndex = i
|
||||
}
|
||||
if (s is IrDelegatingConstructorCall && s.symbol.owner.origin === PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR) {
|
||||
superCallIndex = i
|
||||
}
|
||||
}
|
||||
|
||||
if (callIndex != -1 && superCallIndex != -1) {
|
||||
val tmp = statements[callIndex]
|
||||
statements[callIndex] = statements[superCallIndex]
|
||||
statements[superCallIndex] = tmp
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
-216
@@ -1,216 +0,0 @@
|
||||
/*
|
||||
* 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
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.backend.js.lower.PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrDelegatingConstructorCallImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetValueImpl
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.statements
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
|
||||
/**
|
||||
* Add ES6_INIT_BOX_PARAMETER for each constructor (except constructors
|
||||
* of inline, external and primitive (string, arrays) classes).
|
||||
* Uses: Inline class's constructor initialize field of outer class before
|
||||
* call `super`, but its impossible in ES6. ES6_INIT_BOX_PARAMETER - object,
|
||||
* that collect these values and pass to super constructor. In the last
|
||||
* constructor of delegation chain ES6_INIT_BOX_PARAMETER will be open
|
||||
* with `Object.assign(this, box)`
|
||||
*
|
||||
* Add ES6_RESULT_TYPE PARAMETER for each secondary ctor (except
|
||||
* constructors of external and primitive (string, arrays) classes).
|
||||
* Uses: Pass information about type of new object to `Reflect.construct()`
|
||||
*
|
||||
* Transform SYNTHETIC_PRIMARY_CONSTRUCTOR:
|
||||
* constructor() {
|
||||
* //statements
|
||||
* }
|
||||
* ==>
|
||||
* constructor() {
|
||||
* init(this)
|
||||
* }
|
||||
* init($this$) {
|
||||
* //statements from ctor
|
||||
* }
|
||||
*/
|
||||
class ES6AddInternalParametersToConstructorPhase(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
object ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION")
|
||||
object ES6_INIT_BOX_PARAMETER : IrDeclarationOriginImpl("ES6_INIT_BOX_PARAMETER")
|
||||
object ES6_RESULT_TYPE_PARAMETER : IrDeclarationOriginImpl("ES6_RESULT_TYPE_PARAMETER")
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (!context.es6mode) return
|
||||
|
||||
container.transform(CallSiteTransformer(), null)
|
||||
|
||||
if (container !is IrConstructor) return
|
||||
|
||||
if (!container.hasStrictSignature()) container.addInternalValueParameters()
|
||||
|
||||
if (container.origin === SYNTHETIC_PRIMARY_CONSTRUCTOR) {
|
||||
createInitFunction(container)
|
||||
openInitializerBox(container)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrConstructor.addInternalValueParameters() {
|
||||
addValueParameter("box", context.dynamicType, ES6_INIT_BOX_PARAMETER)
|
||||
|
||||
if (!isPrimary) {
|
||||
addValueParameter("resultType", context.dynamicType, ES6_RESULT_TYPE_PARAMETER)
|
||||
}
|
||||
}
|
||||
|
||||
private fun createInitFunction(constructor: IrConstructor) {
|
||||
val irClass = constructor.parentAsClass
|
||||
val initFunction = buildInitFunction(constructor, irClass)
|
||||
irClass.declarations += initFunction
|
||||
|
||||
context.mapping.constructorToInitFunction[constructor] = initFunction
|
||||
|
||||
initFunction.transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitDeclaration(declaration: IrDeclarationBase): IrStatement {
|
||||
declaration.parent = initFunction
|
||||
return declaration
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun openInitializerBox(constructor: IrConstructor) = with(constructor.body as IrBlockBody) {
|
||||
statements.clear()
|
||||
statements += JsIrBuilder.buildCall(context.intrinsics.jsOpenInitializerBox).also {
|
||||
it.putValueArgument(0, JsIrBuilder.buildGetValue(constructor.parentAsClass.thisReceiver!!.symbol))
|
||||
it.putValueArgument(1, JsIrBuilder.buildGetValue(constructor.valueParameters.last().symbol))
|
||||
}
|
||||
}
|
||||
|
||||
private fun buildInitFunction(constructor: IrConstructor, irClass: IrClass): IrSimpleFunction {
|
||||
val functionName = "${irClass.name}_init"
|
||||
|
||||
return context.irFactory.buildFun {
|
||||
name = Name.identifier(functionName)
|
||||
returnType = context.irBuiltIns.unitType
|
||||
visibility = DescriptorVisibilities.PROTECTED
|
||||
modality = Modality.FINAL
|
||||
isInline = constructor.isInline
|
||||
isExternal = constructor.isExternal
|
||||
origin = ES6_SYNTHETIC_PRIMARY_INIT_FUNCTION
|
||||
}.apply {
|
||||
parent = irClass
|
||||
addValueParameter("\$this\$", context.dynamicType)
|
||||
|
||||
body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET, constructor.body?.statements.orEmpty())
|
||||
|
||||
transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
return if (expression.symbol.owner === constructor.parentAsClass.thisReceiver!!) {
|
||||
with(expression) { IrGetValueImpl(startOffset, endOffset, type, valueParameters.single().symbol) }
|
||||
} else {
|
||||
expression
|
||||
}
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Pass `null` for ES6_INIT_BOX_PARAMETER and ES6_RESULT_TYPE_PARAMETER
|
||||
*/
|
||||
inner class CallSiteTransformer : IrElementTransformerVoid() {
|
||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||
val constructor = expression.symbol.owner
|
||||
val parent = constructor.parentAsClass
|
||||
|
||||
if (constructor.hasStrictSignature() || parent.defaultType.isAny()) return expression
|
||||
|
||||
val newArgsCount = if (constructor.isPrimary) 1 else 2
|
||||
return expression.run {
|
||||
IrConstructorCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
type,
|
||||
symbol,
|
||||
typeArgumentsCount,
|
||||
constructorTypeArgumentsCount,
|
||||
valueArgumentsCount + newArgsCount
|
||||
).also {
|
||||
for (i in 0 until valueArgumentsCount) {
|
||||
it.putValueArgument(i, getValueArgument(i))
|
||||
}
|
||||
|
||||
it.putValueArgument(
|
||||
valueArgumentsCount,
|
||||
JsIrBuilder.buildNull(context.dynamicType)
|
||||
)
|
||||
|
||||
if (!constructor.isPrimary) {
|
||||
it.putValueArgument(
|
||||
valueArgumentsCount + 1,
|
||||
JsIrBuilder.buildNull(context.dynamicType)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
val constructor = expression.symbol.owner
|
||||
val parent = constructor.parentAsClass
|
||||
|
||||
if (constructor.hasStrictSignature() || parent.defaultType.isAny()) return expression
|
||||
|
||||
val newArgsCount = if (constructor.isPrimary) 1 else 2
|
||||
|
||||
return expression.run {
|
||||
IrDelegatingConstructorCallImpl(
|
||||
startOffset,
|
||||
endOffset,
|
||||
type,
|
||||
symbol,
|
||||
typeArgumentsCount,
|
||||
valueArgumentsCount + newArgsCount
|
||||
).also {
|
||||
for (i in 0 until valueArgumentsCount) {
|
||||
it.putValueArgument(i, getValueArgument(i))
|
||||
}
|
||||
|
||||
it.putValueArgument(
|
||||
valueArgumentsCount,
|
||||
JsIrBuilder.buildNull(context.dynamicType)
|
||||
)
|
||||
|
||||
if (!constructor.isPrimary) {
|
||||
it.putValueArgument(
|
||||
valueArgumentsCount + 1,
|
||||
JsIrBuilder.buildNull(context.dynamicType)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrConstructor.hasStrictSignature(): Boolean {
|
||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
||||
return with(parentAsClass) { isExternal || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives }
|
||||
}
|
||||
}
|
||||
+140
@@ -0,0 +1,140 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.irEmpty
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrCallImpl
|
||||
import org.jetbrains.kotlin.ir.util.isLocal
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.superClass
|
||||
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
|
||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||
|
||||
class ES6ConstructorBoxParameterOptimizationLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private val esClassWhichNeedBoxParameters = context.mapping.esClassWhichNeedBoxParameters
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (!context.es6mode) return
|
||||
|
||||
val containerFunction = container as? IrFunction
|
||||
|
||||
val shouldRemoveBoxRelatedDeclarationsAndStatements =
|
||||
containerFunction?.isEs6ConstructorReplacement == true && !containerFunction.parentAsClass.requiredToHaveBoxParameter()
|
||||
|
||||
if (containerFunction != null && shouldRemoveBoxRelatedDeclarationsAndStatements && irBody is IrBlockBody) {
|
||||
containerFunction.valueParameters = containerFunction.valueParameters.filter { !it.isBoxParameter }
|
||||
}
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitWhen(expression: IrWhen): IrExpression {
|
||||
return if (shouldRemoveBoxRelatedDeclarationsAndStatements && expression.isBoxParameterDefaultResolution) {
|
||||
irEmpty(context)
|
||||
} else {
|
||||
super.visitWhen(expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val callee = expression.symbol.owner
|
||||
|
||||
return when {
|
||||
shouldRemoveBoxRelatedDeclarationsAndStatements && (callee.symbol == context.intrinsics.jsCreateThisSymbol || callee.symbol == context.intrinsics.jsCreateExternalThisSymbol) -> {
|
||||
expression.putValueArgument(expression.valueArgumentsCount - 1, context.getVoid())
|
||||
super.visitCall(expression)
|
||||
}
|
||||
callee.isEs6ConstructorReplacement && (!callee.parentAsClass.requiredToHaveBoxParameter() || shouldRemoveBoxRelatedDeclarationsAndStatements) -> {
|
||||
val newArgumentsSize = expression.valueArgumentsCount - 1
|
||||
super.visitCall(IrCallImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
expression.type,
|
||||
expression.symbol,
|
||||
expression.typeArgumentsCount,
|
||||
newArgumentsSize,
|
||||
expression.origin,
|
||||
superQualifierSymbol = expression.superQualifierSymbol
|
||||
).apply {
|
||||
copyTypeArgumentsFrom(expression)
|
||||
|
||||
dispatchReceiver = expression.dispatchReceiver
|
||||
extensionReceiver = expression.extensionReceiver
|
||||
|
||||
for (i in 0 until newArgumentsSize) {
|
||||
putValueArgument(i, expression.getValueArgument(i))
|
||||
}
|
||||
})
|
||||
}
|
||||
else -> super.visitCall(expression)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrClass.requiredToHaveBoxParameter(): Boolean {
|
||||
return esClassWhichNeedBoxParameters.contains(this)
|
||||
}
|
||||
}
|
||||
|
||||
class ES6CollectConstructorsWhichNeedBoxParameters(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
private val esClassWhichNeedBoxParameters = context.mapping.esClassWhichNeedBoxParameters
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (!context.es6mode || declaration !is IrClass) return null
|
||||
|
||||
val hasSuperClass = declaration.superClass != null
|
||||
|
||||
if (hasSuperClass && declaration.isInner) {
|
||||
declaration.addToClassListWhichNeedBoxParameter()
|
||||
}
|
||||
if (hasSuperClass && declaration.isLocal && declaration.containsCapturedValues()) {
|
||||
declaration.addToClassListWhichNeedBoxParameter()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun IrClass.containsCapturedValues(): Boolean {
|
||||
if (superClass == null) return false
|
||||
|
||||
declarations
|
||||
.filterIsInstanceAnd<IrFunction> { it.isEs6ConstructorReplacement }
|
||||
.forEach {
|
||||
var meetCapturing = false
|
||||
val boxParameter = it.boxParameter
|
||||
|
||||
it.body?.acceptChildrenVoid(object : IrElementVisitorVoid {
|
||||
override fun visitSetField(expression: IrSetField) {
|
||||
val receiver = expression.receiver as? IrGetValue
|
||||
if (receiver != null && receiver.symbol == boxParameter?.symbol) {
|
||||
meetCapturing = true
|
||||
}
|
||||
super.visitSetField(expression)
|
||||
}
|
||||
})
|
||||
|
||||
if (meetCapturing) return true
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
private fun IrClass.addToClassListWhichNeedBoxParameter() {
|
||||
if (isExternal) return
|
||||
esClassWhichNeedBoxParameters.add(this)
|
||||
superClass?.addToClassListWhichNeedBoxParameter()
|
||||
}
|
||||
}
|
||||
+73
@@ -0,0 +1,73 @@
|
||||
/*
|
||||
* 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.IrElementTransformerVoidWithContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.hasStrictSignature
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.jsConstructorReference
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
class ES6ConstructorCallLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
private var IrConstructor.constructorFactory by context.mapping.secondaryConstructorToFactory
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (!context.es6mode) return
|
||||
|
||||
val containerFunction = container as? IrFunction
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoidWithContext() {
|
||||
override fun visitConstructorCall(expression: IrConstructorCall): IrExpression {
|
||||
val currentConstructor = expression.symbol.owner
|
||||
val irClass = currentConstructor.parentAsClass
|
||||
val currentFunction = currentFunction?.irElement as? IrFunction ?: containerFunction
|
||||
|
||||
if (irClass.symbol == context.irBuiltIns.anyClass || currentConstructor.hasStrictSignature(context)) {
|
||||
return super.visitConstructorCall(expression)
|
||||
}
|
||||
|
||||
val factoryFunction = currentConstructor.constructorFactory ?: error("Replacement for the constructor is not found")
|
||||
|
||||
if (expression.isInitCall) {
|
||||
assert(factoryFunction.isInitFunction) { "Expect to have init function replacement" }
|
||||
return JsIrBuilder.buildCall(factoryFunction.symbol).apply {
|
||||
copyValueArgumentsFrom(expression, factoryFunction)
|
||||
}
|
||||
}
|
||||
|
||||
val isDelegatingCall =
|
||||
expression.isSyntheticDelegatingReplacement && currentFunction != null && currentFunction.parentAsClass != irClass
|
||||
|
||||
val factoryFunctionCall = JsIrBuilder.buildCall(
|
||||
factoryFunction.symbol,
|
||||
superQualifierSymbol = irClass.symbol.takeIf { isDelegatingCall },
|
||||
origin = if (isDelegatingCall) ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT else JsStatementOrigins.SYNTHESIZED_STATEMENT
|
||||
).apply {
|
||||
copyValueArgumentsFrom(expression, factoryFunction)
|
||||
|
||||
if (expression.isSyntheticDelegatingReplacement) {
|
||||
currentFunction?.boxParameter?.let {
|
||||
putValueArgument(valueArgumentsCount - 1, JsIrBuilder.buildGetValue(it.symbol))
|
||||
}
|
||||
if (superQualifierSymbol == null) {
|
||||
dispatchReceiver = JsIrBuilder.buildGetValue(factoryFunction.dispatchReceiverParameter!!.symbol)
|
||||
}
|
||||
} else {
|
||||
dispatchReceiver = irClass.jsConstructorReference(context)
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitCall(factoryFunctionCall)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
+204
-519
@@ -5,568 +5,253 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.ir.IrElement
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_INIT_BOX_PARAMETER
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.ES6AddInternalParametersToConstructorPhase.ES6_RESULT_TYPE_PARAMETER
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
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.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrVariableSymbol
|
||||
import org.jetbrains.kotlin.ir.types.isAny
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.statements
|
||||
import org.jetbrains.kotlin.ir.util.transformInPlace
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementVisitor
|
||||
import org.jetbrains.kotlin.ir.types.typeWith
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
object ES6_THIS_VARIABLE_ORIGIN : IrDeclarationOriginImpl("ES6_THIS_VARIABLE_ORIGIN")
|
||||
object ES6_INIT_CALL : IrStatementOriginImpl("ES6_INIT_CALL")
|
||||
object ES6_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_CONSTRUCTOR_REPLACEMENT")
|
||||
object ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT : IrDeclarationOriginImpl("ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT")
|
||||
object ES6_INIT_FUNCTION : IrDeclarationOriginImpl("ES6_INIT_FUNCTION")
|
||||
object ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT : IrStatementOriginImpl("ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT")
|
||||
|
||||
class ES6ConstructorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (!context.es6mode) return
|
||||
val IrDeclaration.isEs6ConstructorReplacement: Boolean
|
||||
get() = origin == ES6_CONSTRUCTOR_REPLACEMENT || origin == ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
|
||||
|
||||
if (container !is IrConstructor) return
|
||||
val IrDeclaration.isEs6PrimaryConstructorReplacement: Boolean
|
||||
get() = origin == ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
|
||||
|
||||
if (container.hasStrictSignature()) return
|
||||
val IrFunctionAccessExpression.isSyntheticDelegatingReplacement: Boolean
|
||||
get() = origin == ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT
|
||||
|
||||
hackEnums(container)
|
||||
hackExceptions(context, container)
|
||||
val IrDeclaration.isInitFunction: Boolean
|
||||
get() = origin == ES6_INIT_FUNCTION
|
||||
|
||||
val superCall = getSuperCall(container) ?: return
|
||||
val superCtor = superCall.symbol.owner
|
||||
val helper = LowerCtorHelper(context, container, superCtor)
|
||||
val IrFunctionAccessExpression.isInitCall: Boolean
|
||||
get() = origin == ES6_INIT_CALL
|
||||
|
||||
if (container.isPrimary) {
|
||||
if (superCtor.isPrimary) primaryToPrimary(helper)
|
||||
else primaryToSecondary(helper)
|
||||
class ES6ConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
private var IrConstructor.constructorFactory by context.mapping.secondaryConstructorToFactory
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (!context.es6mode || declaration !is IrConstructor || declaration.hasStrictSignature(context)) return null
|
||||
|
||||
return if (declaration.isSyntheticPrimaryConstructor) {
|
||||
listOf(declaration.generateInitFunction())
|
||||
} else {
|
||||
if (superCtor.isPrimary) secondaryToPrimary(helper)
|
||||
else secondaryToSecondary(helper)
|
||||
|
||||
replaceCallToDefaultPrimary(context, container)
|
||||
changeIrConstructorToIrFunction(context, container)
|
||||
val factoryFunction = declaration.generateCreateFunction()
|
||||
listOfNotNull(factoryFunction, declaration.generateExportedConstructorIfNeed(factoryFunction))
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor(args, box) {
|
||||
* var currBox = box || {}
|
||||
*
|
||||
* //1. Superclass is Any
|
||||
* Object.assign(this, currBox)
|
||||
* //body
|
||||
*
|
||||
* //2. Base class isInline or isExternal or array/string
|
||||
* super(args)
|
||||
* Object.assign(this, currBox)
|
||||
* //body
|
||||
*
|
||||
* //3. Base class !isInline and !isExternal and !(array/string)
|
||||
* //fill initialization box
|
||||
* super(args, currBox)
|
||||
* //body
|
||||
* }
|
||||
*/
|
||||
private fun primaryToPrimary(helper: LowerCtorHelper) = with(helper) {
|
||||
statements.add(0, boxOrEmptyObject)
|
||||
|
||||
if (superCtor.parentAsClass.defaultType.isAny()) {
|
||||
//after superCall
|
||||
statements.add(1, openBoxStatement(thisSymbol, boxSymbol))
|
||||
return
|
||||
}
|
||||
|
||||
if (superCtor.hasStrictSignature()) {
|
||||
//after superCall
|
||||
statements.add(2, openBoxStatement(thisSymbol, boxSymbol))
|
||||
} else {
|
||||
fillInitializerBox(boxSymbol, constructor)
|
||||
putBoxToSuperCall(boxSymbol, constructor)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* constructor(args, box) {
|
||||
* var currBox = box || {}
|
||||
*
|
||||
* //1. Base class isExternal or array/string
|
||||
* var $this$ = Base_constructor(.., currBox)
|
||||
* Object.assign(this, currBox)
|
||||
* return $this$
|
||||
*
|
||||
* //2. Base class !isInline and !isExternal and !(array/string)
|
||||
* //fill initialization box
|
||||
* var $this$ = Base_constructor(.., currBox, new.target)
|
||||
* //body
|
||||
* return $this$
|
||||
* }
|
||||
*/
|
||||
private fun primaryToSecondary(helper: LowerCtorHelper) = with(helper) {
|
||||
statements.add(0, boxOrEmptyObject)
|
||||
|
||||
if (superCtor.hasStrictSignature()) {
|
||||
fun createNewSuperCall(): IrCall {
|
||||
val callType = JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(superCtor.returnType))
|
||||
val newTarget = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
||||
val args = IrVarargImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
context.dynamicType,
|
||||
context.dynamicType,
|
||||
getElements(constructor)
|
||||
)
|
||||
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct).apply {
|
||||
putValueArgument(0, callType)
|
||||
putValueArgument(1, newTarget)
|
||||
putValueArgument(2, args)
|
||||
|
||||
putTypeArgument(0, superCtor.returnType)
|
||||
private fun IrConstructor.generateExportedConstructorIfNeed(factoryFunction: IrSimpleFunction): IrConstructor? {
|
||||
return runIf(isExported(context) && isPrimary) {
|
||||
apply {
|
||||
valueParameters = valueParameters.filterNot { it.isBoxParameter }
|
||||
(body as? IrBlockBody)?.let {
|
||||
val selfReplacedConstructorCall = JsIrBuilder.buildCall(factoryFunction.symbol).apply {
|
||||
valueParameters.forEachIndexed { i, it -> putValueArgument(i, JsIrBuilder.buildGetValue(it.symbol)) }
|
||||
dispatchReceiver = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
||||
}
|
||||
it.statements.add(JsIrBuilder.buildReturn(symbol, selfReplacedConstructorCall, returnType))
|
||||
}
|
||||
}
|
||||
|
||||
val newThis = createThisVariable(createNewSuperCall())
|
||||
changeReturnUnitToReturnInstance(newThis)
|
||||
|
||||
statements.add(2, openBoxStatement(newThis.symbol, boxSymbol))
|
||||
statements += returnThis(constructor, newThis)
|
||||
|
||||
redirectOldThisToNewOne(constructor, newThis)
|
||||
} else {
|
||||
putBoxToSuperCall(boxSymbol, constructor)
|
||||
fillInitializerBox(boxSymbol, constructor)
|
||||
|
||||
val newTarget = JsIrBuilder.buildCall(context.intrinsics.jsNewTarget)
|
||||
val newThis = createThisVariable(createNewSuperCallPrimaryToSecondary(superCall, newTarget))
|
||||
changeReturnUnitToReturnInstance(newThis)
|
||||
|
||||
statements += returnThis(constructor, newThis)
|
||||
|
||||
redirectOldThisToNewOne(constructor, newThis)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived_constructor(.., box, resultType) {
|
||||
* var currBox = box || {}
|
||||
* var currResultType = resultType || Derived
|
||||
*
|
||||
* //1. Base class isInline or isExternal or array/string
|
||||
* var $this$ = construct(Base, currResultType, [..])
|
||||
* Object.assign(this, currBox)
|
||||
* //body
|
||||
* return $this$
|
||||
*
|
||||
* //2. Base class !isInline and !isExternal and !(array/string)
|
||||
* //fill initialization box
|
||||
* var $this$ = construct(Base, currResultType, [.., currBox])
|
||||
* //body
|
||||
* return $this$
|
||||
* }
|
||||
*/
|
||||
private fun secondaryToPrimary(helper: LowerCtorHelper) = with(helper) {
|
||||
statements.add(0, boxOrEmptyObject)
|
||||
statements.add(1, resultTypeOrDefaultType())
|
||||
val resultTypeSymbol = (statements[1] as IrVariable).symbol
|
||||
private fun IrConstructor.generateInitFunction(): IrSimpleFunction {
|
||||
val constructor = this
|
||||
val irClass = parentAsClass
|
||||
val constructorName = "init_${irClass.constructorPostfix}"
|
||||
return context.irFactory.buildFun {
|
||||
name = Name.identifier(constructorName)
|
||||
returnType = context.irBuiltIns.unitType
|
||||
visibility = DescriptorVisibilities.PRIVATE
|
||||
modality = Modality.FINAL
|
||||
isInline = constructor.isInline
|
||||
isExternal = constructor.isExternal
|
||||
origin = ES6_INIT_FUNCTION
|
||||
}.also { factory ->
|
||||
factory.parent = irClass
|
||||
factory.copyTypeParametersFrom(irClass)
|
||||
factory.annotations = annotations
|
||||
factory.extensionReceiverParameter = irClass.thisReceiver?.copyTo(factory)
|
||||
|
||||
if (superCtor.hasStrictSignature()) {
|
||||
val newThis = createThisVariable(createNewSuperCallSecondaryToPrimary(constructor, superCtor, resultTypeSymbol))
|
||||
changeReturnUnitToReturnInstance(newThis)
|
||||
|
||||
statements.add(3, openBoxStatement(newThis.symbol, boxSymbol))
|
||||
statements.add(returnThis(constructor, newThis))
|
||||
|
||||
redirectOldThisToNewOne(constructor, newThis)
|
||||
} else {
|
||||
fillInitializerBox(boxSymbol, constructor)
|
||||
|
||||
val newThis = createThisVariable(createNewSuperCallSecondaryToPrimary(constructor, superCtor, resultTypeSymbol, boxSymbol))
|
||||
changeReturnUnitToReturnInstance(newThis)
|
||||
|
||||
statements.add(returnThis(constructor, newThis))
|
||||
|
||||
redirectOldThisToNewOne(constructor, newThis)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Derived_constructor(.., box, resultType) {
|
||||
* var currBox = box || {}
|
||||
* var currResultType = resultType || Derived
|
||||
* //fill initialization box
|
||||
*
|
||||
* //1. Base class isInline or isExternal or array/string
|
||||
* var $this$ = Base_constructor(..)
|
||||
* Object.assign(this, currBox)
|
||||
* //body
|
||||
* return $this$
|
||||
*
|
||||
* //2. Base class !isInline and !isExternal and !(array/string)
|
||||
* var $this$ = Base_constructor(.., currBox, currResultType)
|
||||
* //body
|
||||
* return $this$
|
||||
* }
|
||||
*/
|
||||
private fun secondaryToSecondary(helper: LowerCtorHelper) = with(helper) {
|
||||
statements.add(0, boxOrEmptyObject)
|
||||
statements.add(1, resultTypeOrDefaultType())
|
||||
val resultTypeSymbol = (statements[1] as IrVariable).symbol
|
||||
|
||||
putBoxToSuperCall(boxSymbol, constructor)
|
||||
fillInitializerBox(boxSymbol, constructor)
|
||||
|
||||
if (superCtor.hasStrictSignature()) {
|
||||
val newThis = createThisVariable(superCall)
|
||||
changeReturnUnitToReturnInstance(newThis)
|
||||
|
||||
statements.add(3, openBoxStatement(newThis.symbol, boxSymbol))
|
||||
statements += returnThis(constructor, newThis)
|
||||
|
||||
redirectOldThisToNewOne(constructor, newThis)
|
||||
} else {
|
||||
val newThis = createThisVariable(createNewSuperCallSecondaryToSecondary(superCall, boxSymbol, resultTypeSymbol))
|
||||
changeReturnUnitToReturnInstance(newThis)
|
||||
|
||||
statements += returnThis(constructor, newThis)
|
||||
|
||||
redirectOldThisToNewOne(constructor, newThis)
|
||||
}
|
||||
}
|
||||
|
||||
//superCallBuilder
|
||||
private fun createNewSuperCallSecondaryToSecondary(
|
||||
superCall: IrDelegatingConstructorCall,
|
||||
boxSymbol: IrValueSymbol,
|
||||
resultTypeSymbol: IrVariableSymbol
|
||||
) = superCall.apply {
|
||||
putValueArgument(ES6_INIT_BOX_PARAMETER, JsIrBuilder.buildGetValue(boxSymbol))
|
||||
putValueArgument(ES6_RESULT_TYPE_PARAMETER, JsIrBuilder.buildGetValue(resultTypeSymbol))
|
||||
}
|
||||
|
||||
//superCallBuilder
|
||||
private fun createNewSuperCallPrimaryToSecondary(
|
||||
superCall: IrDelegatingConstructorCall,
|
||||
newTarget: IrCall? = null
|
||||
) = superCall.apply { putValueArgument(ES6_RESULT_TYPE_PARAMETER, newTarget) }
|
||||
|
||||
private fun IrDelegatingConstructorCall.putValueArgument(origin: IrDeclarationOrigin, value: IrExpression?) {
|
||||
val valueParameters = symbol.owner.valueParameters
|
||||
for (i in valueParameters.indices) {
|
||||
if (valueParameters[i].origin === origin) {
|
||||
putValueArgument(i, value)
|
||||
factory.body = constructor.body?.deepCopyWithSymbols(factory)?.apply {
|
||||
transformChildrenVoid(ValueRemapper(mapOf(irClass.thisReceiver!!.symbol to factory.extensionReceiverParameter!!.symbol)))
|
||||
}
|
||||
|
||||
constructorFactory = factory
|
||||
}
|
||||
}
|
||||
|
||||
//superCallBuilder
|
||||
private fun createNewSuperCallSecondaryToPrimary(
|
||||
constructor: IrConstructor,
|
||||
superCtor: IrConstructor,
|
||||
resultTypeSymbol: IrVariableSymbol,
|
||||
boxSymbol: IrVariableSymbol? = null
|
||||
): IrCall {
|
||||
val callType = JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(superCtor.returnType))
|
||||
val resultType = JsIrBuilder.buildGetValue(resultTypeSymbol)
|
||||
val arguments = IrVarargImpl(
|
||||
UNDEFINED_OFFSET, UNDEFINED_OFFSET,
|
||||
context.irBuiltIns.anyNType,
|
||||
context.irBuiltIns.anyNType,
|
||||
getElements(constructor, boxSymbol)
|
||||
private fun IrConstructor.generateCreateFunction(): IrSimpleFunction {
|
||||
val constructor = this
|
||||
val irClass = parentAsClass
|
||||
val type = irClass.defaultType
|
||||
val constructorName = "new_${irClass.constructorPostfix}"
|
||||
|
||||
return context.irFactory.buildFun {
|
||||
name = Name.identifier(constructorName)
|
||||
returnType = type
|
||||
visibility = constructor.visibility
|
||||
modality = Modality.FINAL
|
||||
isInline = constructor.isInline
|
||||
isExternal = constructor.isExternal
|
||||
origin = when {
|
||||
constructor.isPrimary -> ES6_PRIMARY_CONSTRUCTOR_REPLACEMENT
|
||||
else -> ES6_CONSTRUCTOR_REPLACEMENT
|
||||
}
|
||||
}.also { factory ->
|
||||
factory.parent = irClass
|
||||
factory.copyTypeParametersFrom(irClass)
|
||||
factory.copyValueParametersFrom(constructor)
|
||||
factory.annotations = annotations
|
||||
factory.dispatchReceiverParameter = irClass.thisReceiver?.copyTo(factory)
|
||||
|
||||
if (irClass.isExported(context) && constructor.isPrimary) {
|
||||
factory.excludeFromExport()
|
||||
}
|
||||
|
||||
factory.body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
val bodyCopy = constructor.body?.deepCopyWithSymbols(factory) ?: return@createBlockBody
|
||||
val self = bodyCopy.replaceSuperCallsAndThisUsages(irClass, factory, constructor)
|
||||
statements.addAll(bodyCopy.statements)
|
||||
statements.add(JsIrBuilder.buildReturn(factory.symbol, JsIrBuilder.buildGetValue(self), irClass.defaultType))
|
||||
}
|
||||
|
||||
constructorFactory = factory
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.generateThisVariable(irClass: IrClass, initializer: IrExpression): IrVariable {
|
||||
return JsIrBuilder.buildVar(
|
||||
type = irClass.defaultType,
|
||||
parent = this,
|
||||
name = Namer.SYNTHETIC_RECEIVER_NAME,
|
||||
initializer = initializer
|
||||
)
|
||||
|
||||
if (superCtor.parentAsClass.defaultType.isAny()) {
|
||||
//superType is Any, and we have default primary --> create call to default primary
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct, context.irBuiltIns.nothingType).apply {
|
||||
arguments.elements.clear()
|
||||
arguments.addElement(JsIrBuilder.buildGetValue(boxSymbol!!))
|
||||
|
||||
putValueArgument(0, JsIrBuilder.buildCall(context.intrinsics.jsClass, context.dynamicType, listOf(constructor.returnType)))
|
||||
putValueArgument(1, resultType)
|
||||
putValueArgument(2, arguments)
|
||||
|
||||
putTypeArgument(0, constructor.returnType)
|
||||
}
|
||||
}
|
||||
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsConstruct, context.irBuiltIns.nothingType).apply {
|
||||
putValueArgument(0, callType)
|
||||
putValueArgument(1, resultType)
|
||||
putValueArgument(2, arguments)
|
||||
|
||||
putTypeArgument(0, superCtor.returnType)
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Copy arguments from superCall
|
||||
*/
|
||||
private fun getElements(constructor: IrConstructor, boxSymbol: IrValueSymbol? = null): List<IrVarargElement> {
|
||||
val result = mutableListOf<IrVarargElement>()
|
||||
private val IrClass.constructorPostfix: String
|
||||
get() = fqNameWhenAvailable?.asString()?.replace('.', '_') ?: name.toString()
|
||||
|
||||
val superCall = constructor.body!!.statements.filterIsInstance<IrDelegatingConstructorCall>().first()
|
||||
repeat(superCall.valueArgumentsCount) { i ->
|
||||
val arg = superCall.getValueArgument(i) ?: return@repeat
|
||||
if (superCall.symbol.owner.valueParameters[i].origin === ES6_INIT_BOX_PARAMETER) {
|
||||
result += JsIrBuilder.buildGetValue(boxSymbol!!)
|
||||
} else {
|
||||
if (context.inlineClassesUtils.getInlinedClass(arg.type) != null) {
|
||||
val any = context.irBuiltIns.anyNType
|
||||
result += JsIrBuilder.buildTypeOperator(any, IrTypeOperator.REINTERPRET_CAST, arg, any)
|
||||
private fun irAnyArray(elements: List<IrExpression>): IrExpression {
|
||||
return JsIrBuilder.buildArray(
|
||||
elements,
|
||||
context.irBuiltIns.arrayClass.typeWith(context.irBuiltIns.anyNType),
|
||||
context.irBuiltIns.anyNType,
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrBody.replaceSuperCallsAndThisUsages(
|
||||
irClass: IrClass,
|
||||
constructorReplacement: IrSimpleFunction,
|
||||
currentConstructor: IrConstructor,
|
||||
): IrValueSymbol {
|
||||
var generatedThisValueSymbol: IrValueSymbol? = null
|
||||
val selfParameterSymbol = irClass.thisReceiver!!.symbol
|
||||
val boxParameterSymbol = constructorReplacement.boxParameter
|
||||
|
||||
transformChildrenVoid(object : ValueRemapper(emptyMap()) {
|
||||
override val map: MutableMap<IrValueSymbol, IrValueSymbol> = currentConstructor.valueParameters
|
||||
.zip(constructorReplacement.valueParameters)
|
||||
.associate { it.first.symbol to it.second.symbol }
|
||||
.toMutableMap()
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
return if (expression.returnTargetSymbol == currentConstructor.symbol) {
|
||||
super.visitReturn(
|
||||
JsIrBuilder.buildReturn(
|
||||
constructorReplacement.symbol,
|
||||
JsIrBuilder.buildGetValue(selfParameterSymbol),
|
||||
irClass.defaultType
|
||||
)
|
||||
)
|
||||
} else {
|
||||
result += arg
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return result
|
||||
}
|
||||
|
||||
//builder
|
||||
private fun returnThis(constructor: IrConstructor, newThis: IrVariable): IrReturn {
|
||||
return JsIrBuilder.buildReturn(
|
||||
constructor.symbol,
|
||||
JsIrBuilder.buildGetValue(newThis.symbol),
|
||||
context.irBuiltIns.nothingType
|
||||
)
|
||||
}
|
||||
|
||||
/**
|
||||
* Transform statements like `this.x = y` to `box.x = y`
|
||||
*/
|
||||
private fun fillInitializerBox(boxSymbol: IrValueSymbol, constructor: IrConstructor) {
|
||||
val statements = (constructor.body as IrBlockBody).statements
|
||||
for (i in statements.indices) {
|
||||
val current = statements[i]
|
||||
if (current is IrSetField) {
|
||||
if ((current.receiver as? IrGetValue)?.symbol?.owner === constructor.parentAsClass.thisReceiver) {
|
||||
current.receiver = JsIrBuilder.buildGetValue(boxSymbol)
|
||||
super.visitReturn(expression)
|
||||
}
|
||||
}
|
||||
|
||||
if (statements[i] is IrDelegatingConstructorCall) {
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//transformer
|
||||
private fun putBoxToSuperCall(boxSymbol: IrValueSymbol, constructor: IrConstructor) {
|
||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
return expression.also { it.putValueArgument(ES6_INIT_BOX_PARAMETER, JsIrBuilder.buildGetValue(boxSymbol)) }
|
||||
val constructor = expression.symbol.owner
|
||||
|
||||
if (constructor.isSyntheticPrimaryConstructor) {
|
||||
return JsIrBuilder.buildConstructorCall(expression.symbol, origin = ES6_INIT_CALL)
|
||||
.apply {
|
||||
copyValueArgumentsFrom(expression, constructor)
|
||||
extensionReceiver = JsIrBuilder.buildGetValue(selfParameterSymbol)
|
||||
}
|
||||
.run { visitConstructorCall(this) }
|
||||
}
|
||||
|
||||
val boxParameterGetter = boxParameterSymbol?.let { JsIrBuilder.buildGetValue(it.symbol) } ?: context.getVoid()
|
||||
|
||||
val newThisValue = when {
|
||||
constructor.isEffectivelyExternal() ->
|
||||
JsIrBuilder.buildCall(context.intrinsics.jsCreateExternalThisSymbol)
|
||||
.apply {
|
||||
putValueArgument(0, irClass.getCurrentConstructorReference(constructorReplacement))
|
||||
putValueArgument(1, expression.symbol.owner.parentAsClass.jsConstructorReference(context))
|
||||
putValueArgument(2, irAnyArray(expression.valueArguments.map { it ?: context.getVoid() }))
|
||||
putValueArgument(3, boxParameterGetter)
|
||||
}
|
||||
constructor.parentAsClass.symbol == context.irBuiltIns.anyClass ->
|
||||
JsIrBuilder.buildCall(context.intrinsics.jsCreateThisSymbol)
|
||||
.apply {
|
||||
putValueArgument(0, irClass.getCurrentConstructorReference(constructorReplacement))
|
||||
putValueArgument(1, boxParameterGetter)
|
||||
}
|
||||
else ->
|
||||
JsIrBuilder.buildConstructorCall(
|
||||
expression.symbol,
|
||||
null,
|
||||
expression.typeArguments,
|
||||
ES6_DELEGATING_CONSTRUCTOR_REPLACEMENT
|
||||
).apply {
|
||||
copyValueArgumentsFrom(expression, constructor)
|
||||
}
|
||||
}
|
||||
|
||||
val newThisVariable = constructorReplacement.generateThisVariable(irClass, newThisValue)
|
||||
.also {
|
||||
generatedThisValueSymbol = it.symbol
|
||||
map[selfParameterSymbol] = it.symbol
|
||||
}
|
||||
|
||||
return super.visitComposite(JsIrBuilder.buildComposite(context.irBuiltIns.unitType, listOf(newThisVariable)))
|
||||
}
|
||||
}, null)
|
||||
})
|
||||
|
||||
return generatedThisValueSymbol!!
|
||||
}
|
||||
|
||||
//builder
|
||||
private fun openBoxStatement(thisSymbol: IrValueSymbol, boxSymbol: IrValueSymbol): IrCall {
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsOpenInitializerBox).also {
|
||||
it.putValueArgument(0, JsIrBuilder.buildGetValue(thisSymbol))
|
||||
it.putValueArgument(1, JsIrBuilder.buildGetValue(boxSymbol))
|
||||
private fun IrClass.getCurrentConstructorReference(currentFactoryFunction: IrSimpleFunction): IrExpression {
|
||||
return if (isFinalClass) {
|
||||
jsConstructorReference(context)
|
||||
} else {
|
||||
JsIrBuilder.buildGetValue(currentFactoryFunction.dispatchReceiverParameter!!.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
//util
|
||||
private fun IrConstructor.hasStrictSignature(): Boolean {
|
||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
||||
return with(parentAsClass) { isExternal || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives }
|
||||
private fun IrDeclaration.excludeFromExport() {
|
||||
val jsExportIgnoreClass = context.intrinsics.jsExportIgnoreAnnotationSymbol.owner
|
||||
val jsExportIgnoreCtor = jsExportIgnoreClass.primaryConstructor ?: return
|
||||
annotations += JsIrBuilder.buildConstructorCall(jsExportIgnoreCtor.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
//transformer
|
||||
private fun replaceCallToDefaultPrimary(context: JsIrBackendContext, constructor: IrConstructor) {
|
||||
val thisSymbol = (((constructor.body as IrBlockBody).statements
|
||||
.find { it is IrVariable && it.origin === ES6_THIS_VARIABLE_ORIGIN }) as IrVariable?)?.symbol ?: return
|
||||
|
||||
(constructor.body as IrBlockBody).statements.transformInPlace {
|
||||
if (it is IrDelegatingConstructorCall) {
|
||||
val superCtor = it.symbol.owner
|
||||
val initFunc = context.mapping.constructorToInitFunction[superCtor]!!
|
||||
|
||||
JsIrBuilder.buildCall(initFunc.symbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(thisSymbol))
|
||||
}
|
||||
} else it
|
||||
}
|
||||
}
|
||||
|
||||
//transformer
|
||||
private fun redirectOldThisToNewOne(constructor: IrConstructor, newThis: IrVariable) {
|
||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
return if (expression.symbol.owner === constructor.parentAsClass.thisReceiver!!) {
|
||||
with(expression) { IrGetValueImpl(startOffset, endOffset, type, newThis.symbol) }
|
||||
} else {
|
||||
expression
|
||||
}
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Change `return Unit` to `return $this$`
|
||||
*/
|
||||
private fun LowerCtorHelper.changeReturnUnitToReturnInstance(newThis: IrVariable) {
|
||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
return JsIrBuilder.buildReturn(
|
||||
constructor.symbol,
|
||||
JsIrBuilder.buildGetValue(newThis.symbol),
|
||||
expression.type
|
||||
)
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
private fun hackEnums(constructor: IrConstructor) {
|
||||
constructor.transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitTypeOperator(expression: IrTypeOperatorCall): IrExpression {
|
||||
return (expression.argument as? IrDelegatingConstructorCall) ?: expression
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
/**
|
||||
* Swap call synthetic primary ctor and call extendThrowable
|
||||
*/
|
||||
private fun hackExceptions(context: JsIrBackendContext, constructor: IrConstructor) {
|
||||
val setPropertiesSymbol = context.setPropertiesToThrowableInstanceSymbol
|
||||
|
||||
val statements = (constructor.body as IrBlockBody).statements
|
||||
|
||||
var callIndex = -1
|
||||
var superCallIndex = -1
|
||||
for (i in statements.indices) {
|
||||
val s = statements[i]
|
||||
|
||||
if (s is IrCall && s.symbol === setPropertiesSymbol) callIndex = i
|
||||
if (s is IrDelegatingConstructorCall && s.symbol.owner.origin === SYNTHETIC_PRIMARY_CONSTRUCTOR) superCallIndex = i
|
||||
}
|
||||
|
||||
if (callIndex != -1 && superCallIndex != -1) {
|
||||
val tmp = statements[callIndex]
|
||||
statements[callIndex] = statements[superCallIndex]
|
||||
statements[superCallIndex] = tmp
|
||||
}
|
||||
}
|
||||
|
||||
private class LowerCtorHelper(
|
||||
private val context: JsIrBackendContext,
|
||||
val constructor: IrConstructor,
|
||||
val superCtor: IrConstructor
|
||||
) {
|
||||
private val boxParameterSymbol = constructor.valueParameters.find { it.origin === ES6_INIT_BOX_PARAMETER }!!.symbol
|
||||
val resultTypeParameterSymbol by lazy {
|
||||
constructor.valueParameters.find { it.origin === ES6_RESULT_TYPE_PARAMETER }!!.symbol
|
||||
}
|
||||
|
||||
val statements = (constructor.body as IrBlockBody).statements
|
||||
|
||||
/**
|
||||
* var currBox = box || {}
|
||||
*/
|
||||
val boxOrEmptyObject = boxOrEmptyObject(boxParameterSymbol, constructor)
|
||||
private fun boxOrEmptyObject(boxSymbol: IrValueSymbol, parent: IrConstructor): IrVariable {
|
||||
val emptyObject = JsIrBuilder.buildCall(context.intrinsics.jsEmptyObject)
|
||||
val or = JsIrBuilder.buildCall(context.intrinsics.jsOr, context.dynamicType).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(boxSymbol))
|
||||
putValueArgument(1, emptyObject)
|
||||
}
|
||||
return JsIrBuilder.buildVar(context.dynamicType, parent, "currBox", initializer = or)
|
||||
}
|
||||
|
||||
val boxSymbol = boxOrEmptyObject.symbol
|
||||
val thisSymbol = constructor.parentAsClass.thisReceiver!!.symbol
|
||||
|
||||
val superCall: IrDelegatingConstructorCall by lazy { getSuperCall(constructor)!! }
|
||||
|
||||
/**
|
||||
* var $this$ = `newSuperCall`
|
||||
*/
|
||||
fun createThisVariable(newSuperCall: IrExpression): IrVariable {
|
||||
val newThis = JsIrBuilder.buildVar(
|
||||
context.dynamicType,
|
||||
constructor,
|
||||
"\$this\$",
|
||||
initializer = newSuperCall
|
||||
).apply {
|
||||
origin = ES6_THIS_VARIABLE_ORIGIN
|
||||
}
|
||||
|
||||
(constructor.body as IrBlockBody).statements.transformInPlace {
|
||||
if (it === superCall) newThis
|
||||
else it
|
||||
}
|
||||
|
||||
return newThis
|
||||
}
|
||||
|
||||
/**
|
||||
* var currResultType = resultType || D
|
||||
*/
|
||||
fun resultTypeOrDefaultType(): IrStatement {
|
||||
val defaultType = JsIrBuilder.buildCall(context.intrinsics.es6DefaultType).apply {
|
||||
putTypeArgument(0, constructor.parentAsClass.defaultType)
|
||||
}
|
||||
val or = JsIrBuilder.buildCall(context.intrinsics.jsOr, context.dynamicType).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(resultTypeParameterSymbol))
|
||||
putValueArgument(1, defaultType)
|
||||
}
|
||||
return JsIrBuilder.buildVar(context.dynamicType, constructor, "currResultType", initializer = or)
|
||||
}
|
||||
}
|
||||
|
||||
private fun getSuperCall(constructor: IrConstructor): IrDelegatingConstructorCall? {
|
||||
var result: IrDelegatingConstructorCall? = null
|
||||
(constructor.body as IrBlockBody).acceptChildren(object : IrElementVisitor<Unit, Any?> {
|
||||
override fun visitElement(element: IrElement, data: Any?) { }
|
||||
|
||||
override fun visitBlock(expression: IrBlock, data: Any?) {
|
||||
expression.statements.forEach { it.accept(this, data) }
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall, data: Any?) {
|
||||
result = result ?: expression
|
||||
}
|
||||
}, null)
|
||||
return result
|
||||
}
|
||||
|
||||
private fun changeIrConstructorToIrFunction(context: JsIrBackendContext, container: IrConstructor) {
|
||||
val newConstructor = context.irFactory.buildFun {
|
||||
name = Name.identifier("${container.parentAsClass.name}_constructor")
|
||||
returnType = container.returnType
|
||||
origin = JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||
}.apply {
|
||||
parent = container.parent
|
||||
container.valueParameters.forEach { param ->
|
||||
addValueParameter(param.name.asString(), param.type, param.origin)
|
||||
}
|
||||
|
||||
val parametersMap = container.valueParameters.zip(valueParameters).toMap()
|
||||
body = container.body
|
||||
transformChildren(object : IrElementTransformerVoid() {
|
||||
override fun visitGetValue(expression: IrGetValue): IrExpression {
|
||||
val newParam = parametersMap[expression.symbol.owner]
|
||||
return if (newParam != null) JsIrBuilder.buildGetValue(newParam.symbol) else expression
|
||||
}
|
||||
}, null)
|
||||
}
|
||||
|
||||
container.parentAsClass.declarations.transformInPlace {
|
||||
if (it === container) newConstructor else it
|
||||
}
|
||||
|
||||
context.mapping.secondaryConstructorToDelegate[container] = newConstructor
|
||||
}
|
||||
|
||||
+258
@@ -0,0 +1,258 @@
|
||||
/*
|
||||
* 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.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.MutableReference
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.irEmpty
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.mutableReferenceOf
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrValueSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.util.collectionUtils.filterIsInstanceAnd
|
||||
|
||||
const val CREATE_EXTERNAL_THIS_CONSTRUCTOR_PARAMETERS = 2
|
||||
|
||||
class ES6PrimaryConstructorOptimizationLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (!context.es6mode || declaration !is IrFunction || !declaration.shouldBeConvertedToPlainConstructor(context)) {
|
||||
return null
|
||||
}
|
||||
|
||||
val irClass = declaration.parentAsClass
|
||||
|
||||
if (irClass.isExported(context)) {
|
||||
irClass.removeConstructorForExport()
|
||||
}
|
||||
|
||||
return listOf(declaration.convertToRegularConstructor(irClass))
|
||||
}
|
||||
|
||||
private fun IrFunction.convertToRegularConstructor(irClass: IrClass): IrConstructor {
|
||||
val original = this
|
||||
val superClass = irClass.superClass
|
||||
val classThisSymbol = irClass.thisReceiver!!.symbol
|
||||
|
||||
return factory.buildConstructor {
|
||||
updateFrom(original)
|
||||
isPrimary = true
|
||||
returnType = original.returnType
|
||||
origin = IrDeclarationOrigin.DEFINED
|
||||
}.also { constructor ->
|
||||
constructor.copyAnnotationsFrom(original)
|
||||
constructor.copyParameterDeclarationsFrom(original)
|
||||
constructor.parent = irClass
|
||||
|
||||
if (irClass.isExported(context)) {
|
||||
constructor.annotations = original.annotations.withoutFirst { it.isAnnotation(JsAnnotations.jsExportIgnoreFqn) }
|
||||
}
|
||||
|
||||
val boxParameter = constructor.boxParameter
|
||||
val body = (original.body?.deepCopyWithSymbols(constructor) as IrBlockBody)
|
||||
.also { constructor.body = it }
|
||||
|
||||
body.transformChildrenVoid(object : ValueRemapper(emptyMap()) {
|
||||
override val map = original.valueParameters.zip(constructor.valueParameters)
|
||||
.associate { it.first.symbol to it.second.symbol }
|
||||
.toMutableMap<IrValueSymbol, IrValueSymbol>()
|
||||
|
||||
override fun visitReturn(expression: IrReturn): IrExpression {
|
||||
return if (expression.returnTargetSymbol == original.symbol) {
|
||||
return irEmpty(context)
|
||||
} else {
|
||||
super.visitReturn(expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
return if (expression.symbol == context.intrinsics.jsBoxApplySymbol) {
|
||||
irEmpty(context)
|
||||
} else {
|
||||
super.visitCall(expression)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitVariable(declaration: IrVariable): IrStatement {
|
||||
val initializer = declaration.initializer
|
||||
|
||||
if (initializer is IrCall) {
|
||||
when {
|
||||
initializer.isSyntheticDelegatingReplacement -> {
|
||||
map[declaration.symbol] = classThisSymbol
|
||||
return super.visitCall(initializer)
|
||||
}
|
||||
initializer.symbol == context.intrinsics.jsCreateThisSymbol -> {
|
||||
map[declaration.symbol] = classThisSymbol
|
||||
|
||||
return if (boxParameter != null && superClass == null) {
|
||||
super.visitCall(JsIrBuilder.buildCall(context.intrinsics.jsBoxApplySymbol).apply {
|
||||
putValueArgument(0, JsIrBuilder.buildGetValue(irClass.thisReceiver!!.symbol))
|
||||
putValueArgument(1, JsIrBuilder.buildGetValue(boxParameter.symbol))
|
||||
})
|
||||
} else {
|
||||
irEmpty(context)
|
||||
}
|
||||
}
|
||||
initializer.symbol == context.intrinsics.jsCreateExternalThisSymbol -> {
|
||||
map[declaration.symbol] = classThisSymbol
|
||||
|
||||
val externalConstructor =
|
||||
superClass?.primaryConstructor?.symbol ?: error("Expect to have external constructor here")
|
||||
val parameters = initializer.getValueArgument(CREATE_EXTERNAL_THIS_CONSTRUCTOR_PARAMETERS) as? IrVararg
|
||||
?: error("Wrong type of argument was provided")
|
||||
|
||||
return JsIrBuilder.buildDelegatingConstructorCall(externalConstructor).apply {
|
||||
parameters.elements.forEachIndexed { i, it -> putValueArgument(i, it as IrExpression) }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return super.visitVariable(declaration)
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.removeConstructorForExport() {
|
||||
declarations.removeIf { it is IrConstructor }
|
||||
}
|
||||
|
||||
private inline fun <T> Iterable<T>.withoutFirst(predicate: (T) -> Boolean): List<T> {
|
||||
val original = this
|
||||
return buildList {
|
||||
var isFirstMatch = true
|
||||
for (element in original) {
|
||||
if (!isFirstMatch || !predicate(element)) {
|
||||
add(element)
|
||||
} else {
|
||||
isFirstMatch = false
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ES6PrimaryConstructorUsageOptimizationLowering(private val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
val callee = expression.symbol.owner
|
||||
return when {
|
||||
!callee.shouldBeConvertedToPlainConstructor(context) -> super.visitCall(expression)
|
||||
expression.isSyntheticDelegatingReplacement -> {
|
||||
super.visitDelegatingConstructorCall(JsIrBuilder.buildDelegatingConstructorCall(callee.parentAsClass.primaryConstructor!!.symbol)
|
||||
.apply { copyTypeAndValueArgumentsFrom(expression) })
|
||||
}
|
||||
else -> {
|
||||
super.visitConstructorCall(JsIrBuilder.buildConstructorCall(callee.parentAsClass.primaryConstructor!!.symbol)
|
||||
.apply { copyTypeAndValueArgumentsFrom(expression) })
|
||||
}
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* When we can't optimize class hierarchy chain if there is a class inside which:
|
||||
* 1. Has primary constructor which delegates to a secondary
|
||||
* 2. Has secondary constructor which delegates to a primary
|
||||
* 3. Has a constructor with a box parameter, and it has an external superclass
|
||||
* 4. Is a subtype for Throwable, because we replace the super call inside constructors with `setPropertiesToThrowableInstance` call
|
||||
* Otherwise, we can generate a simple ES-class constructor in each class of the hierarchy
|
||||
*/
|
||||
class ES6CollectPrimaryConstructorsWhichCouldBeOptimizedLowering(private val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
private val esClassWhichNeedBoxParameters = context.mapping.esClassWhichNeedBoxParameters
|
||||
private val esClassToPossibilityForOptimization = context.mapping.esClassToPossibilityForOptimization
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (
|
||||
context.es6mode &&
|
||||
declaration is IrClass &&
|
||||
!declaration.isExternal &&
|
||||
!context.inlineClassesUtils.isClassInlineLike(declaration) &&
|
||||
!esClassToPossibilityForOptimization.contains(declaration)
|
||||
) {
|
||||
declaration.checkIfCanBeOptimized()
|
||||
}
|
||||
|
||||
return null
|
||||
}
|
||||
|
||||
private fun IrClass.checkIfCanBeOptimized() {
|
||||
var currentClass: IrClass? = this
|
||||
var nearestOptimizationDecision: MutableReference<Boolean>? = null
|
||||
|
||||
while (currentClass != null && !currentClass.isExternal) {
|
||||
val currentClassOptimizationDecision = esClassToPossibilityForOptimization[currentClass]
|
||||
|
||||
if (currentClassOptimizationDecision != null) {
|
||||
nearestOptimizationDecision = currentClassOptimizationDecision
|
||||
break
|
||||
}
|
||||
|
||||
currentClass = currentClass.superClass
|
||||
}
|
||||
|
||||
if (nearestOptimizationDecision == null) {
|
||||
nearestOptimizationDecision = mutableReferenceOf(true)
|
||||
}
|
||||
|
||||
currentClass = this
|
||||
while (currentClass != null && !currentClass.isExternal && !esClassToPossibilityForOptimization.contains(currentClass)) {
|
||||
esClassToPossibilityForOptimization[currentClass] = nearestOptimizationDecision
|
||||
|
||||
if (nearestOptimizationDecision.value && !currentClass.canBeOptimized()) {
|
||||
nearestOptimizationDecision.value = false
|
||||
}
|
||||
|
||||
currentClass = currentClass.superClass
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrClass.canBeOptimized(): Boolean {
|
||||
return superClass?.symbol != context.throwableClass && !isSubclassOfExternalClassWithRequiredBoxParameter() && !hasPrimaryDelegatedToSecondaryOrSecondaryToPrimary()
|
||||
}
|
||||
|
||||
private fun IrClass.hasPrimaryDelegatedToSecondaryOrSecondaryToPrimary(): Boolean {
|
||||
declarations
|
||||
.filterIsInstanceAnd<IrFunction> { it.isEs6ConstructorReplacement }
|
||||
.forEach {
|
||||
var meetUnoptimizedDelegation = false
|
||||
it.body?.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
override fun visitCall(expression: IrCall): IrExpression {
|
||||
if (expression.isSyntheticDelegatingReplacement && expression.symbol.owner.origin != it.origin) {
|
||||
meetUnoptimizedDelegation = true
|
||||
}
|
||||
return super.visitCall(expression)
|
||||
}
|
||||
})
|
||||
|
||||
if (meetUnoptimizedDelegation) return true
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
private fun IrClass.isSubclassOfExternalClassWithRequiredBoxParameter(): Boolean {
|
||||
return superClass?.isExternal == true && esClassWhichNeedBoxParameters.contains(this)
|
||||
}
|
||||
}
|
||||
|
||||
private fun IrFunction.shouldBeConvertedToPlainConstructor(context: JsIrBackendContext): Boolean {
|
||||
return isEs6PrimaryConstructorReplacement && context.mapping.esClassToPossibilityForOptimization[parentAsClass]?.value == true
|
||||
}
|
||||
+2
-3
@@ -6,11 +6,10 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.isJsImplicitExport
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrTypeParameterSymbol
|
||||
@@ -86,7 +85,7 @@ class ImplicitlyExportedDeclarationsMarkingLowering(private val context: JsIrBac
|
||||
|
||||
private fun IrDeclaration.markWithJsImplicitExport() {
|
||||
val jsImplicitExportCtor = context.intrinsics.jsImplicitExportAnnotationSymbol.constructors.single()
|
||||
annotations += context.createIrBuilder(symbol).irCall(jsImplicitExportCtor)
|
||||
annotations += JsIrBuilder.buildConstructorCall(jsImplicitExportCtor)
|
||||
|
||||
parentClassOrNull?.takeIf { it.shouldBeMarkedWithImplicitExport() }?.markWithJsImplicitExport()
|
||||
}
|
||||
|
||||
+3
-5
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.jsConstructorReference
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
@@ -44,7 +45,7 @@ class JsClassUsageInReflectionLowering(val backendContext: JsIrBackendContext) :
|
||||
|
||||
private fun IrClassReference.generateDirectValueUsage(): IrExpression? {
|
||||
return with(backendContext) {
|
||||
when(val classSymbol = symbol as? IrClassSymbol ?: return null) {
|
||||
when (val classSymbol = symbol as? IrClassSymbol ?: return null) {
|
||||
irBuiltIns.nothingClass -> null
|
||||
irBuiltIns.anyClass ->
|
||||
JsIrBuilder.buildCall(intrinsics.jsCode).apply {
|
||||
@@ -59,10 +60,7 @@ class JsClassUsageInReflectionLowering(val backendContext: JsIrBackendContext) :
|
||||
)
|
||||
}
|
||||
|
||||
else ->
|
||||
JsIrBuilder.buildCall(intrinsics.jsClass, origin = JsStatementOrigins.CLASS_REFERENCE).apply {
|
||||
putTypeArgument(0, classSymbol.owner.defaultType)
|
||||
}
|
||||
else -> classSymbol.owner.jsConstructorReference(backendContext)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+6
-13
@@ -17,13 +17,11 @@ import org.jetbrains.kotlin.ir.backend.js.utils.JsAnnotations
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.realOverrideTarget
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.addValueParameter
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
@@ -72,18 +70,13 @@ class JsDefaultArgumentStubGenerator(override val context: JsIrBackendContext) :
|
||||
?.also { new -> variables[param] = new } ?: param
|
||||
}
|
||||
|
||||
val defaultResolutionStatements = valueParameters.mapNotNull {
|
||||
irBuilder.createResolutionStatement(it, it.defaultValue?.expression)
|
||||
}
|
||||
|
||||
if (variables.isNotEmpty()) {
|
||||
body?.transformChildren(VariableRemapper(variables), null)
|
||||
|
||||
body = context.irFactory.createBlockBody(UNDEFINED_OFFSET, UNDEFINED_OFFSET) {
|
||||
statements += defaultResolutionStatements
|
||||
statements += body?.statements ?: emptyList()
|
||||
}
|
||||
val blockBody = body as? IrBlockBody
|
||||
|
||||
if (blockBody != null && variables.isNotEmpty()) {
|
||||
blockBody.transformChildren(VariableRemapper(variables), null)
|
||||
blockBody.statements.addAll(0, valueParameters.mapNotNull {
|
||||
irBuilder.createResolutionStatement(it, it.defaultValue?.expression)
|
||||
})
|
||||
}
|
||||
|
||||
return also {
|
||||
|
||||
+2
-13
@@ -12,6 +12,7 @@ import org.jetbrains.kotlin.ir.backend.js.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.jsConstructorReference
|
||||
import org.jetbrains.kotlin.ir.declarations.IrFunction
|
||||
import org.jetbrains.kotlin.ir.declarations.IrValueParameter
|
||||
import org.jetbrains.kotlin.ir.expressions.IrCall
|
||||
@@ -91,19 +92,7 @@ class JsDefaultParameterInjector(override val context: JsIrBackendContext) :
|
||||
0,
|
||||
1
|
||||
).apply {
|
||||
putValueArgument(
|
||||
0,
|
||||
IrCallImpl(
|
||||
UNDEFINED_OFFSET,
|
||||
UNDEFINED_OFFSET,
|
||||
context.dynamicType,
|
||||
context.intrinsics.jsClass,
|
||||
1,
|
||||
0
|
||||
).apply {
|
||||
putTypeArgument(0, owner.defaultType)
|
||||
}
|
||||
)
|
||||
putValueArgument(0, owner.jsConstructorReference(context))
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+2
-1
@@ -11,6 +11,7 @@ import org.jetbrains.kotlin.backend.common.lower.InnerClassesSupport
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsMapping
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder.SYNTHESIZED_DECLARATION
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.Namer
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildConstructor
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
@@ -41,7 +42,7 @@ class JsInnerClassesSupport(mapping: JsMapping, private val irFactory: IrFactory
|
||||
|
||||
irFactory.buildField {
|
||||
origin = IrDeclarationOrigin.FIELD_FOR_OUTER_THIS
|
||||
name = Name.identifier("\$this")
|
||||
name = Name.identifier(Namer.SYNTHETIC_RECEIVER_NAME)
|
||||
type = outerClass.defaultType
|
||||
visibility = DescriptorVisibilities.PROTECTED
|
||||
isFinal = true
|
||||
|
||||
+51
-28
@@ -12,15 +12,19 @@ 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.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.JsLoweredDeclarationOrigin
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.builders.*
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildField
|
||||
import org.jetbrains.kotlin.ir.builders.declarations.buildFun
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.*
|
||||
import org.jetbrains.kotlin.ir.symbols.IrFieldSymbol
|
||||
import org.jetbrains.kotlin.ir.types.makeNullable
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
@@ -28,9 +32,7 @@ import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.safeAs
|
||||
|
||||
class ObjectDeclarationLowering(
|
||||
val context: JsCommonBackendContext
|
||||
) : DeclarationTransformer {
|
||||
class ObjectDeclarationLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrClass.instanceField by context.mapping.objectToInstanceField
|
||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||
@@ -39,7 +41,6 @@ class ObjectDeclarationLowering(
|
||||
* If the object being lowered is nested inside an enum class, we want to also initialize the enum entries when initializing the object.
|
||||
*/
|
||||
private var IrClass.initEntryInstancesFun: IrSimpleFunction? by context.mapping.enumClassToInitEntryInstancesFun
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration !is IrClass || declaration.kind != ClassKind.OBJECT || declaration.isEffectivelyExternal())
|
||||
return null
|
||||
@@ -67,7 +68,7 @@ class ObjectDeclarationLowering(
|
||||
if (initEntryInstancesFun != null)
|
||||
+irCall(initEntryInstancesFun)
|
||||
+irIfThen(
|
||||
irEqualsNull(irGetField(null, instanceField)),
|
||||
irNullabilityCheck(instanceField),
|
||||
// Instance field initialized inside constructor
|
||||
irCallConstructor(primaryConstructor.symbol, emptyList())
|
||||
)
|
||||
@@ -77,35 +78,30 @@ class ObjectDeclarationLowering(
|
||||
|
||||
return listOf(declaration, instanceField, getInstanceFun)
|
||||
}
|
||||
|
||||
private fun IrBuilderWithScope.irNullabilityCheck(instanceField: IrField): IrExpression {
|
||||
val context = this@ObjectDeclarationLowering.context
|
||||
return if (context is JsIrBackendContext && context.es6mode) {
|
||||
irEqeqeqWithoutBox(irGetField(null, instanceField), context.getVoid())
|
||||
} else {
|
||||
irEqualsNull(irGetField(null, instanceField))
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
class ObjectUsageLowering(
|
||||
val context: JsCommonBackendContext
|
||||
) : BodyLoweringPass {
|
||||
class ObjectUsageLowering(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!!))
|
||||
}
|
||||
if (context.es6mode) {
|
||||
//find `superCall` and put after
|
||||
(irBody as IrBlockBody).statements.transformFlat {
|
||||
if (it is IrDelegatingConstructorCall) listOf(it, initInstanceField)
|
||||
else if (it is IrVariable && it.origin === ES6_THIS_VARIABLE_ORIGIN) {
|
||||
initInstanceField.value = JsIrBuilder.buildGetValue(it.symbol)
|
||||
listOf(it, initInstanceField)
|
||||
} else null
|
||||
}
|
||||
} else {
|
||||
(irBody as IrBlockBody).statements.add(0, initInstanceField)
|
||||
}
|
||||
}
|
||||
val functionContainer = container.takeIf { it is IrConstructor && it.isPrimary }
|
||||
val irClass = functionContainer?.parentAsClass
|
||||
|
||||
irClass?.instanceField?.let {
|
||||
if (context.es6mode && irClass.superClass == null) return@let
|
||||
// Initialize instance field in the beginning of the constructor because it can be used inside the constructor later
|
||||
val initInstanceField = generateInitInstanceField(it, irClass.getValueForInstanceFieldForTheFirstTime())
|
||||
(irBody as IrBlockBody).statements.add(0, initInstanceField)
|
||||
}
|
||||
|
||||
irBody.transformChildrenVoid(object : IrElementTransformerVoid() {
|
||||
@@ -114,8 +110,35 @@ class ObjectUsageLowering(
|
||||
if (obj.isEffectivelyExternal()) return expression
|
||||
return JsIrBuilder.buildCall(context.getOrCreateGetInstanceFunction(obj).symbol)
|
||||
}
|
||||
|
||||
override fun visitDelegatingConstructorCall(expression: IrDelegatingConstructorCall): IrExpression {
|
||||
val instanceField = irClass?.instanceField
|
||||
return if (!context.es6mode || instanceField == null) {
|
||||
super.visitDelegatingConstructorCall(expression)
|
||||
} else {
|
||||
JsIrBuilder.buildComposite(
|
||||
context.irBuiltIns.unitType,
|
||||
listOf(
|
||||
super.visitDelegatingConstructorCall(expression),
|
||||
generateInitInstanceField(instanceField, JsIrBuilder.buildGetValue(irClass.thisReceiver!!.symbol))
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
private fun IrClass.getValueForInstanceFieldForTheFirstTime(): IrExpression {
|
||||
return if (context.es6mode && context is JsIrBackendContext) {
|
||||
JsIrBuilder.buildNull(thisReceiver!!.type)
|
||||
} else {
|
||||
JsIrBuilder.buildGetValue(thisReceiver!!.symbol)
|
||||
}
|
||||
}
|
||||
|
||||
private fun generateInitInstanceField(instanceField: IrField, value: IrExpression): IrStatement {
|
||||
return JsIrBuilder.buildSetField(instanceField.symbol, null, value, context.irBuiltIns.unitType)
|
||||
}
|
||||
}
|
||||
|
||||
private fun JsCommonBackendContext.getOrCreateGetInstanceFunction(obj: IrClass) =
|
||||
|
||||
+5
-2
@@ -7,6 +7,7 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.descriptors.ClassKind
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.ir.IrStatement
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsCommonBackendContext
|
||||
@@ -17,18 +18,20 @@ import org.jetbrains.kotlin.ir.expressions.IrInstanceInitializerCall
|
||||
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.isInterface
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformerVoid
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
|
||||
val IrDeclaration.isSyntheticPrimaryConstructor: Boolean
|
||||
get() = origin == PrimaryConstructorLowering.SYNTHETIC_PRIMARY_CONSTRUCTOR
|
||||
|
||||
// Create primary constructor if it doesn't exist
|
||||
class PrimaryConstructorLowering(val context: JsCommonBackendContext) : DeclarationTransformer {
|
||||
|
||||
private var IrClass.syntheticPrimaryConstructor by context.mapping.classToSyntheticPrimaryConstructor
|
||||
|
||||
override fun transformFlat(declaration: IrDeclaration): List<IrDeclaration>? {
|
||||
if (declaration is IrClass && !declaration.isInterface) {
|
||||
if (declaration is IrClass && declaration.kind != ClassKind.INTERFACE) {
|
||||
val constructors = declaration.constructors
|
||||
|
||||
if (constructors.any { it.isPrimary }) return null
|
||||
|
||||
+16
-29
@@ -7,7 +7,6 @@ package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.BodyLoweringPass
|
||||
import org.jetbrains.kotlin.backend.common.DeclarationTransformer
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.backend.common.getOrPut
|
||||
import org.jetbrains.kotlin.backend.common.ir.ValueRemapper
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
@@ -33,6 +32,7 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
import org.jetbrains.kotlin.ir.visitors.transformChildrenVoid
|
||||
import org.jetbrains.kotlin.name.Name
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class SecondaryConstructorLowering(val context: JsIrBackendContext) : DeclarationTransformer {
|
||||
|
||||
@@ -234,6 +234,7 @@ private fun JsIrBackendContext.buildConstructorFactory(constructor: IrConstructo
|
||||
class SecondaryFactoryInjectorLowering(val context: JsIrBackendContext) : BodyLoweringPass {
|
||||
|
||||
override fun lower(irBody: IrBody, container: IrDeclaration) {
|
||||
if (context.es6mode) return
|
||||
// TODO Simplify? Is this needed at all?
|
||||
var parentFunction: IrFunction? = container as? IrFunction
|
||||
var declaration = container
|
||||
@@ -266,14 +267,7 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
||||
|
||||
val target = expression.symbol.owner
|
||||
return if (target.isSecondaryConstructorCall) {
|
||||
val factory = with(context) {
|
||||
if (es6mode) mapping.secondaryConstructorToDelegate[target]
|
||||
?: compilationException(
|
||||
"Not found IrFunction for secondary ctor",
|
||||
expression
|
||||
)
|
||||
else buildConstructorFactory(target, target.parentAsClass)
|
||||
}
|
||||
val factory = context.buildConstructorFactory(target, target.parentAsClass)
|
||||
replaceSecondaryConstructorWithFactoryFunction(expression, factory.symbol)
|
||||
} else expression
|
||||
}
|
||||
@@ -285,18 +279,8 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
||||
|
||||
return if (target.isSecondaryConstructorCall) {
|
||||
val klass = target.parentAsClass
|
||||
val delegate = with(context) {
|
||||
if (es6mode) mapping.secondaryConstructorToDelegate[target]
|
||||
?: compilationException(
|
||||
"Not found IrFunction for secondary ctor",
|
||||
expression
|
||||
)
|
||||
else buildConstructorDelegate(target, klass)
|
||||
}
|
||||
val delegate = context.buildConstructorDelegate(target, klass)
|
||||
val newCall = replaceSecondaryConstructorWithFactoryFunction(expression, delegate.symbol)
|
||||
if (context.es6mode) {
|
||||
return newCall
|
||||
}
|
||||
|
||||
val readThis = expression.run {
|
||||
if (data is IrConstructor) {
|
||||
@@ -315,16 +299,19 @@ private class CallsiteRedirectionTransformer(private val context: JsIrBackendCon
|
||||
private fun replaceSecondaryConstructorWithFactoryFunction(
|
||||
call: IrFunctionAccessExpression,
|
||||
newTarget: IrSimpleFunctionSymbol
|
||||
) = IrCallImpl(
|
||||
call.startOffset, call.endOffset, call.type, newTarget,
|
||||
typeArgumentsCount = call.typeArgumentsCount,
|
||||
valueArgumentsCount = newTarget.owner.valueParameters.size
|
||||
).apply {
|
||||
): IrCall {
|
||||
val irClass = call.symbol.owner.parentAsClass
|
||||
return IrCallImpl(
|
||||
call.startOffset, call.endOffset, call.type, newTarget,
|
||||
typeArgumentsCount = call.typeArgumentsCount,
|
||||
valueArgumentsCount = newTarget.owner.valueParameters.size,
|
||||
superQualifierSymbol = irClass.symbol.takeIf { context.es6mode && call.isSyntheticDelegatingReplacement }
|
||||
).apply {
|
||||
copyTypeArgumentsFrom(call)
|
||||
|
||||
copyTypeArgumentsFrom(call)
|
||||
|
||||
for (i in 0 until call.valueArgumentsCount) {
|
||||
putValueArgument(i, call.getValueArgument(i))
|
||||
for (i in 0 until call.valueArgumentsCount) {
|
||||
putValueArgument(i, call.getValueArgument(i))
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
+24
-8
@@ -6,8 +6,8 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.lower
|
||||
|
||||
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.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.getVoid
|
||||
import org.jetbrains.kotlin.ir.declarations.IrClass
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclaration
|
||||
@@ -21,12 +21,7 @@ import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.ir.visitors.IrElementTransformer
|
||||
|
||||
|
||||
class ThrowableLowering(
|
||||
val context: JsIrBackendContext,
|
||||
val extendThrowableFunction: IrSimpleFunctionSymbol
|
||||
) : BodyLoweringPass {
|
||||
private val nothingNType = context.irBuiltIns.nothingNType
|
||||
|
||||
class ThrowableLowering(val context: JsIrBackendContext, val extendThrowableFunction: IrSimpleFunctionSymbol) : BodyLoweringPass {
|
||||
private val throwableConstructors = context.throwableConstructors
|
||||
private val newThrowableFunction = context.newThrowableSymbol
|
||||
|
||||
@@ -64,6 +59,8 @@ class ThrowableLowering(
|
||||
}
|
||||
|
||||
inner class Transformer : IrElementTransformer<IrDeclarationParent> {
|
||||
private val anyConstructor = context.irBuiltIns.anyClass.constructors.first()
|
||||
|
||||
override fun visitClass(declaration: IrClass, data: IrDeclarationParent) = super.visitClass(declaration, declaration)
|
||||
|
||||
override fun visitConstructorCall(expression: IrConstructorCall, data: IrDeclarationParent): IrExpression {
|
||||
@@ -93,7 +90,7 @@ class ThrowableLowering(
|
||||
val klass = data as IrClass
|
||||
val thisReceiver = IrGetValueImpl(expression.startOffset, expression.endOffset, klass.thisReceiver!!.symbol)
|
||||
|
||||
return expression.run {
|
||||
val expressionReplacement = expression.run {
|
||||
IrCallImpl(
|
||||
startOffset, endOffset, type, extendThrowableFunction,
|
||||
valueArgumentsCount = 3,
|
||||
@@ -104,6 +101,25 @@ class ThrowableLowering(
|
||||
it.putValueArgument(2, causeArg)
|
||||
}
|
||||
}
|
||||
|
||||
return if (!context.es6mode) {
|
||||
expressionReplacement
|
||||
} else {
|
||||
JsIrBuilder.buildComposite(
|
||||
context.irBuiltIns.unitType,
|
||||
listOf(
|
||||
IrDelegatingConstructorCallImpl(
|
||||
expression.startOffset,
|
||||
expression.endOffset,
|
||||
context.irBuiltIns.anyType,
|
||||
anyConstructor,
|
||||
0,
|
||||
0
|
||||
),
|
||||
expressionReplacement
|
||||
)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.phaser.PhaseConfig
|
||||
import org.jetbrains.kotlin.backend.common.phaser.invokeToplevel
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
||||
import org.jetbrains.kotlin.ir.declarations.IrModuleFragment
|
||||
|
||||
fun optimizeProgramByIr(
|
||||
modules: Iterable<IrModuleFragment>,
|
||||
context: JsIrBackendContext,
|
||||
removeUnusedAssociatedObjects: Boolean
|
||||
) {
|
||||
eliminateDeadDeclarations(modules, context, removeUnusedAssociatedObjects)
|
||||
jsOptimizationPhases.invokeToplevel(PhaseConfig(jsOptimizationPhases), context, modules)
|
||||
}
|
||||
+1
-1
@@ -166,7 +166,7 @@ class IrElementToJsExpressionTransformer : BaseIrElementToJsNodeTransformer<JsEx
|
||||
}
|
||||
|
||||
return if (context.staticContext.backendContext.es6mode) {
|
||||
JsInvocation(JsNameRef("super"), arguments)
|
||||
JsInvocation(JsSuperRef(), arguments)
|
||||
} else {
|
||||
JsInvocation(callFuncRef, listOf(thisRef) + arguments)
|
||||
}.withSource(expression, context)
|
||||
|
||||
+5
-1
@@ -65,7 +65,11 @@ class IrElementToJsStatementTransformer : BaseIrElementToJsNodeTransformer<JsSta
|
||||
}
|
||||
|
||||
override fun visitComposite(expression: IrComposite, context: JsGenerationContext): JsStatement {
|
||||
return JsBlock(expression.statements.map { it.accept(this, context) }).withSource(expression, context)
|
||||
return if (expression.statements.isEmpty()) {
|
||||
JsEmpty
|
||||
} else {
|
||||
JsBlock(expression.statements.map { it.accept(this, context) }).withSource(expression, context)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitExpression(expression: IrExpression, context: JsGenerationContext): JsStatement {
|
||||
|
||||
+31
-27
@@ -8,7 +8,6 @@ package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
import org.jetbrains.kotlin.backend.common.serialization.checkIsFunctionInterface
|
||||
import org.jetbrains.kotlin.config.CommonConfigurationKeys
|
||||
import org.jetbrains.kotlin.ir.backend.js.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.dce.eliminateDeadDeclarations
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.StaticMembersLowering
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isBuiltInClass
|
||||
@@ -46,29 +45,33 @@ val IrModuleFragment.safeName: String
|
||||
get() = name.asString().safeModuleName
|
||||
|
||||
enum class TranslationMode(
|
||||
val dce: Boolean,
|
||||
val production: Boolean,
|
||||
val perModule: Boolean,
|
||||
val minimizedMemberNames: Boolean,
|
||||
) {
|
||||
FULL(dce = false, perModule = false, minimizedMemberNames = false),
|
||||
FULL_DCE(dce = true, perModule = false, minimizedMemberNames = false),
|
||||
FULL_DCE_MINIMIZED_NAMES(dce = true, perModule = false, minimizedMemberNames = true),
|
||||
PER_MODULE(dce = false, perModule = true, minimizedMemberNames = false),
|
||||
PER_MODULE_DCE(dce = true, perModule = true, minimizedMemberNames = false),
|
||||
PER_MODULE_DCE_MINIMIZED_NAMES(dce = true, perModule = true, minimizedMemberNames = true);
|
||||
FULL_DEV(production = false, perModule = false, minimizedMemberNames = false),
|
||||
FULL_PROD(production = true, perModule = false, minimizedMemberNames = false),
|
||||
FULL_PROD_MINIMIZED_NAMES(production = true, perModule = false, minimizedMemberNames = true),
|
||||
PER_MODULE_DEV(production = false, perModule = true, minimizedMemberNames = false),
|
||||
PER_MODULE_PROD(production = true, perModule = true, minimizedMemberNames = false),
|
||||
PER_MODULE_PROD_MINIMIZED_NAMES(production = true, perModule = true, minimizedMemberNames = true);
|
||||
|
||||
companion object {
|
||||
fun fromFlags(dce: Boolean, perModule: Boolean, minimizedMemberNames: Boolean): TranslationMode {
|
||||
fun fromFlags(
|
||||
production: Boolean,
|
||||
perModule: Boolean,
|
||||
minimizedMemberNames: Boolean
|
||||
): TranslationMode {
|
||||
return if (perModule) {
|
||||
if (dce) {
|
||||
if (minimizedMemberNames) PER_MODULE_DCE_MINIMIZED_NAMES
|
||||
else PER_MODULE_DCE
|
||||
} else PER_MODULE
|
||||
if (production) {
|
||||
if (minimizedMemberNames) PER_MODULE_PROD_MINIMIZED_NAMES
|
||||
else PER_MODULE_PROD
|
||||
} else PER_MODULE_DEV
|
||||
} else {
|
||||
if (dce) {
|
||||
if (minimizedMemberNames) FULL_DCE_MINIMIZED_NAMES
|
||||
else FULL_DCE
|
||||
} else FULL
|
||||
if (production) {
|
||||
if (minimizedMemberNames) FULL_PROD_MINIMIZED_NAMES
|
||||
else FULL_PROD
|
||||
} else FULL_DEV
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -146,15 +149,15 @@ class IrModuleToJsTransformer(
|
||||
|
||||
val result = EnumMap<TranslationMode, CompilationOutputs>(TranslationMode::class.java)
|
||||
|
||||
modes.filter { !it.dce }.forEach {
|
||||
modes.filter { !it.production }.forEach {
|
||||
result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true)
|
||||
}
|
||||
|
||||
if (modes.any { it.dce }) {
|
||||
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
|
||||
if (modes.any { it.production }) {
|
||||
optimizeProgramByIr(modules, backendContext, removeUnusedAssociatedObjects)
|
||||
}
|
||||
|
||||
modes.filter { it.dce }.forEach {
|
||||
modes.filter { it.production }.forEach {
|
||||
result[it] = makeJsCodeGeneratorFromIr(exportData, it).generateJsCode(relativeRequirePath, true)
|
||||
}
|
||||
|
||||
@@ -165,8 +168,8 @@ class IrModuleToJsTransformer(
|
||||
val exportData = associateIrAndExport(modules)
|
||||
doStaticMembersLowering(modules)
|
||||
|
||||
if (mode.dce) {
|
||||
eliminateDeadDeclarations(modules, backendContext, removeUnusedAssociatedObjects)
|
||||
if (mode.production) {
|
||||
optimizeProgramByIr(modules, backendContext, removeUnusedAssociatedObjects)
|
||||
}
|
||||
|
||||
return makeJsCodeGeneratorFromIr(exportData, mode)
|
||||
@@ -242,8 +245,12 @@ class IrModuleToJsTransformer(
|
||||
|
||||
val internalModuleName = ReservedJsNames.makeInternalModuleName().takeIf { !isEsModules }
|
||||
val globalNames = NameTable<String>(globalNameScope)
|
||||
|
||||
val statements = result.declarations.statements
|
||||
val fileStatements = fileExports.file.accept(IrFileToJsTransformer(useBareParameterNames = true), staticContext).statements
|
||||
|
||||
val exportStatements =
|
||||
ExportModelToJsStatements(staticContext, { globalNames.declareFreshName(it, it) }).generateModuleExport(
|
||||
ExportModelToJsStatements(staticContext, backendContext.es6mode, { globalNames.declareFreshName(it, it) }).generateModuleExport(
|
||||
ExportedModule(mainModuleName, moduleKind, fileExports.exports),
|
||||
internalModuleName,
|
||||
isEsModules
|
||||
@@ -252,9 +259,6 @@ class IrModuleToJsTransformer(
|
||||
result.exports.statements += exportStatements
|
||||
result.dts = fileExports.tsDeclarations
|
||||
|
||||
val statements = result.declarations.statements
|
||||
|
||||
val fileStatements = fileExports.file.accept(IrFileToJsTransformer(useBareParameterNames = true), staticContext).statements
|
||||
if (fileStatements.isNotEmpty()) {
|
||||
var startComment = ""
|
||||
|
||||
|
||||
+71
-47
@@ -6,39 +6,32 @@
|
||||
package org.jetbrains.kotlin.ir.backend.js.transformers.irToJs
|
||||
|
||||
import org.jetbrains.kotlin.backend.common.compilationException
|
||||
import org.jetbrains.kotlin.backend.common.lower.createIrBuilder
|
||||
import org.jetbrains.kotlin.descriptors.DescriptorVisibilities
|
||||
import org.jetbrains.kotlin.descriptors.Modality
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isAllowedFakeOverriddenDeclaration
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isOverriddenExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.isEs6ConstructorReplacement
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.builders.irCall
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrVarargImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassifierSymbol
|
||||
import org.jetbrains.kotlin.ir.symbols.IrSimpleFunctionSymbol
|
||||
import org.jetbrains.kotlin.ir.types.*
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.js.backend.ast.*
|
||||
import org.jetbrains.kotlin.js.common.isValidES5Identifier
|
||||
import org.jetbrains.kotlin.utils.addIfNotNull
|
||||
import org.jetbrains.kotlin.utils.addToStdlib.runIf
|
||||
|
||||
class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationContext) {
|
||||
private val className = context.getNameForClass(irClass)
|
||||
private val classNameRef = className.makeRef()
|
||||
private val baseClass: IrType? = irClass.superTypes.firstOrNull { !it.classifierOrFail.isInterface }
|
||||
|
||||
private val classPrototypeRef by lazy { prototypeOf(classNameRef, context.staticContext) }
|
||||
private val baseClassRef by lazy { // Lazy in case was not collected by namer during JsClassGenerator construction
|
||||
if (baseClass != null && !baseClass.isAny()) baseClass.getClassRef(context) else null
|
||||
}
|
||||
private val classPrototypeRef = prototypeOf(classNameRef, context.staticContext)
|
||||
private val classBlock = JsCompositeBlock()
|
||||
private val classModel = JsIrClassModel(irClass)
|
||||
|
||||
@@ -67,14 +60,9 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
when (declaration) {
|
||||
is IrConstructor -> {
|
||||
if (es6mode) {
|
||||
declaration.accept(IrFunctionToJsTransformer(), context).let {
|
||||
//HACK: add superCall to Error
|
||||
if ((baseClass?.classifierOrNull?.owner as? IrClass)?.symbol === context.staticContext.backendContext.throwableClass) {
|
||||
it.body.statements.add(0, JsInvocation(JsNameRef("super")).makeStmt())
|
||||
}
|
||||
|
||||
if (it.body.statements.any { it !is JsEmpty }) {
|
||||
jsClass.constructor = it
|
||||
declaration.accept(IrFunctionToJsTransformer(), context).let { fn ->
|
||||
if (fn.body.statements.any { it !is JsEmpty && !it.isSimpleSuperCall(fn) }) {
|
||||
jsClass.constructor = fn
|
||||
}
|
||||
}
|
||||
} else {
|
||||
@@ -85,13 +73,15 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
properties.addIfNotNull(declaration.correspondingPropertySymbol?.owner)
|
||||
|
||||
if (es6mode) {
|
||||
val (memberRef, function) = generateMemberFunction(declaration)
|
||||
function?.let { jsClass.members += it }
|
||||
declaration.generateAssignmentIfMangled(memberRef)
|
||||
if (declaration.isEs6ConstructorReplacement && irClass.isInterface) continue
|
||||
val (memberName, function) = generateMemberFunction(declaration)
|
||||
function?.let { jsClass.members += it.escapedIfNeed() }
|
||||
declaration.generateAssignmentIfMangled(memberName)
|
||||
} else {
|
||||
val (memberRef, function) = generateMemberFunction(declaration)
|
||||
val (memberName, function) = generateMemberFunction(declaration)
|
||||
val memberRef = jsElementAccess(memberName, classPrototypeRef)
|
||||
function?.let { classBlock.statements += jsAssignment(memberRef, it.apply { name = null }).makeStmt() }
|
||||
declaration.generateAssignmentIfMangled(memberRef)
|
||||
declaration.generateAssignmentIfMangled(memberName)
|
||||
}
|
||||
}
|
||||
is IrClass -> {
|
||||
@@ -164,6 +154,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
getterOverridesExternal ||
|
||||
property.getJsName() != null
|
||||
) {
|
||||
val propertyName = context.getNameForProperty(property)
|
||||
|
||||
// Use "direct dispatch" for final properties, i. e. instead of this:
|
||||
// Object.defineProperty(Foo.prototype, 'prop', {
|
||||
@@ -180,7 +171,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
val getterForwarder = property.getter
|
||||
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
||||
.getOrGenerateIfFinal {
|
||||
.getOrGenerateIfFinalOrEs6Mode {
|
||||
propertyAccessorForwarder("getter forwarder") {
|
||||
JsReturn(JsInvocation(it))
|
||||
}
|
||||
@@ -188,7 +179,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
val setterForwarder = property.setter
|
||||
.takeIf { it.shouldExportAccessor(context.staticContext.backendContext) }
|
||||
.getOrGenerateIfFinal {
|
||||
.getOrGenerateIfFinalOrEs6Mode {
|
||||
val setterArgName = JsName("value", false)
|
||||
propertyAccessorForwarder("setter forwarder") {
|
||||
JsInvocation(it, JsNameRef(setterArgName)).makeStmt()
|
||||
@@ -197,29 +188,37 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
classBlock.statements += JsExpressionStatement(
|
||||
defineProperty(
|
||||
classPrototypeRef,
|
||||
context.getNameForProperty(property).ident,
|
||||
getter = getterForwarder,
|
||||
setter = setterForwarder,
|
||||
context.staticContext
|
||||
if (es6mode) {
|
||||
jsClass.members += listOfNotNull(
|
||||
(getterForwarder as? JsFunction)?.apply {
|
||||
name = propertyName
|
||||
modifiers.add(JsFunction.Modifier.GET)
|
||||
},
|
||||
(setterForwarder as? JsFunction)?.apply {
|
||||
name = propertyName
|
||||
modifiers.add(JsFunction.Modifier.SET)
|
||||
}
|
||||
)
|
||||
)
|
||||
} else {
|
||||
classBlock.statements += JsExpressionStatement(
|
||||
defineProperty(classPrototypeRef, propertyName.ident, getterForwarder, setterForwarder, context.staticContext)
|
||||
)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
classModel.preDeclarationBlock.statements += generateSetMetadataCall()
|
||||
val metadataPlace = if (es6mode) classModel.postDeclarationBlock else classModel.preDeclarationBlock
|
||||
|
||||
metadataPlace.statements += generateSetMetadataCall()
|
||||
context.staticContext.classModels[irClass.symbol] = classModel
|
||||
|
||||
return classBlock
|
||||
}
|
||||
|
||||
private inline fun IrSimpleFunction?.getOrGenerateIfFinal(generateFunc: IrSimpleFunction.() -> JsFunction?): JsExpression? {
|
||||
private inline fun IrSimpleFunction?.getOrGenerateIfFinalOrEs6Mode(generateFunc: IrSimpleFunction.() -> JsFunction?): JsExpression? {
|
||||
if (this == null) return null
|
||||
return if (modality == Modality.FINAL) accessorRef() else generateFunc()
|
||||
return if (!es6mode && modality == Modality.FINAL) accessorRef() else generateFunc()
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.isDefinedInsideExportedInterface(): Boolean {
|
||||
@@ -237,13 +236,13 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
)
|
||||
}
|
||||
|
||||
private fun IrSimpleFunction.generateAssignmentIfMangled(memberRef: JsExpression) {
|
||||
private fun IrSimpleFunction.generateAssignmentIfMangled(memberName: JsName) {
|
||||
if (
|
||||
irClass.isExported(context.staticContext.backendContext) &&
|
||||
visibility.isPublicAPI && hasMangledName() &&
|
||||
correspondingPropertySymbol == null
|
||||
) {
|
||||
classBlock.statements += jsAssignment(prototypeAccessRef(), memberRef).makeStmt()
|
||||
classBlock.statements += jsAssignment(prototypeAccessRef(), jsElementAccess(memberName, classPrototypeRef)).makeStmt()
|
||||
}
|
||||
}
|
||||
|
||||
@@ -259,9 +258,8 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
return isInterface && !isEffectivelyExternal()
|
||||
}
|
||||
|
||||
private fun generateMemberFunction(declaration: IrSimpleFunction): Pair<JsExpression, JsFunction?> {
|
||||
private fun generateMemberFunction(declaration: IrSimpleFunction): Pair<JsName, JsFunction?> {
|
||||
val memberName = context.getNameForMemberFunction(declaration.realOverrideTarget)
|
||||
val memberRef = jsElementAccess(memberName.ident, classPrototypeRef)
|
||||
|
||||
if (declaration.isReal && declaration.body != null) {
|
||||
val translatedFunction: JsFunction = declaration.accept(IrFunctionToJsTransformer(), context)
|
||||
@@ -269,10 +267,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
if (irClass.isInterface) {
|
||||
classModel.preDeclarationBlock.statements += translatedFunction.makeStmt()
|
||||
return Pair(memberRef, null)
|
||||
return Pair(memberName, null)
|
||||
}
|
||||
|
||||
return Pair(memberRef, translatedFunction)
|
||||
return Pair(memberName, translatedFunction)
|
||||
}
|
||||
|
||||
// do not generate code like
|
||||
@@ -294,7 +292,10 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
if (implClassDeclaration.shouldCopyFrom()) {
|
||||
val reference = context.getNameForStaticDeclaration(it).makeRef()
|
||||
classModel.postDeclarationBlock.statements += jsAssignment(memberRef, reference).makeStmt()
|
||||
classModel.postDeclarationBlock.statements += jsAssignment(
|
||||
jsElementAccess(memberName, classPrototypeRef),
|
||||
reference
|
||||
).makeStmt()
|
||||
if (isFakeOverride) {
|
||||
classModel.postDeclarationBlock.statements += missedOverrides
|
||||
.map { missedOverride ->
|
||||
@@ -307,7 +308,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
return Pair(memberRef, null)
|
||||
return Pair(memberName, null)
|
||||
}
|
||||
|
||||
private fun maybeGeneratePrimaryConstructor() {
|
||||
@@ -322,7 +323,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
val setMetadataFor = context.staticContext.backendContext.intrinsics.setMetadataForSymbol.owner
|
||||
|
||||
val ctor = classNameRef
|
||||
val parent = baseClassRef
|
||||
val parent = baseClassRef?.takeIf { !es6mode }
|
||||
val name = generateSimpleName()
|
||||
val interfaces = generateInterfacesList()
|
||||
val metadataConstructor = getMetadataConstructor()
|
||||
@@ -352,8 +353,6 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
|
||||
private fun IrType.isFunctionType() = isFunctionOrKFunction() || isSuspendFunctionOrKFunction()
|
||||
|
||||
private fun isCoroutineClass(): Boolean = irClass.superTypes.any { it.isSuspendFunctionTypeOrSubtype() }
|
||||
|
||||
private fun generateSimpleName(): JsStringLiteral? {
|
||||
return irClass.name.takeIf { !it.isSpecial }?.let { JsStringLiteral(it.identifier) }
|
||||
}
|
||||
@@ -386,7 +385,7 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
.distinct()
|
||||
.map { JsIntLiteral(it) }
|
||||
|
||||
return JsArrayLiteral(arity)
|
||||
return JsArrayLiteral(arity).takeIf { arity.isNotEmpty() }
|
||||
}
|
||||
|
||||
private fun generateAssociatedObjectKey(): JsIntLiteral? {
|
||||
@@ -411,6 +410,31 @@ class JsClassGenerator(private val irClass: IrClass, val context: JsGenerationCo
|
||||
}
|
||||
}
|
||||
|
||||
fun JsFunction.escapedIfNeed(): JsFunction {
|
||||
if (name?.ident?.isValidES5Identifier() == false) {
|
||||
name = JsName("'${name.ident}'", name.isTemporary)
|
||||
}
|
||||
return this
|
||||
|
||||
}
|
||||
|
||||
fun JsStatement.isSimpleSuperCall(container: JsFunction): Boolean {
|
||||
if (this !is JsExpressionStatement) return false
|
||||
val invocation = expression as? JsInvocation ?: return false
|
||||
if (invocation.qualifier !is JsSuperRef || container.parameters.size != invocation.arguments.size) return false
|
||||
|
||||
for (i in 0..container.parameters.lastIndex) {
|
||||
val declaredParameter = container.parameters[i]
|
||||
val providedParameter = (invocation.arguments[i] as? JsNameRef)?.takeIf { it.qualifier == null } ?: return false
|
||||
|
||||
if (declaredParameter.name != providedParameter.name) {
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
||||
fun IrSimpleFunction?.shouldExportAccessor(context: JsIrBackendContext): Boolean {
|
||||
if (this == null) return false
|
||||
|
||||
|
||||
+10
-5
@@ -119,11 +119,6 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
JsObjectLiteral()
|
||||
}
|
||||
|
||||
add(intrinsics.es6DefaultType) { call, context ->
|
||||
val typeArgument = call.getTypeArgument(0)!!
|
||||
typeArgument.getClassRef(context)
|
||||
}
|
||||
|
||||
addIfNotNull(intrinsics.jsCode) { call, _ ->
|
||||
compilationException(
|
||||
"Should not be called",
|
||||
@@ -272,6 +267,16 @@ class JsIntrinsicTransformers(backendContext: JsIrBackendContext) {
|
||||
add(intrinsics.jsInvokeSuspendSuperTypeWithReceiverAndParam, suspendInvokeTransform)
|
||||
|
||||
add(intrinsics.jsArguments) { _, _ -> Namer.ARGUMENTS }
|
||||
|
||||
add(intrinsics.jsNewAnonymousClass) { call, context ->
|
||||
val baseClass = translateCallArguments(call, context).single() as JsNameRef
|
||||
JsClass(baseClass = baseClass)
|
||||
}
|
||||
|
||||
add(intrinsics.void.owner.getter!!.symbol) { _, context ->
|
||||
val backingField = context.getNameForField(intrinsics.void.owner.backingField!!)
|
||||
JsNameRef(backingField)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
+3
-2
@@ -39,8 +39,9 @@ class Merger(
|
||||
importStatements.putIfAbsent(declaration, JsVars(JsVars.JsVar(importName, rename(importExpression))))
|
||||
}
|
||||
|
||||
val classModels = mutableMapOf<JsName, JsIrIcClassModel>() + f.classes
|
||||
f.classes.clear()
|
||||
val classModels = (mutableMapOf<JsName, JsIrIcClassModel>() + f.classes)
|
||||
.also { f.classes.clear() }
|
||||
|
||||
classModels.entries.forEach { (name, model) ->
|
||||
f.classes[rename(name)] = JsIrIcClassModel(model.superClasses.map { rename(it) }).also {
|
||||
it.preDeclarationBlock.statements += model.preDeclarationBlock.statements
|
||||
|
||||
+20
-3
@@ -13,6 +13,7 @@ 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.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.lower.*
|
||||
import org.jetbrains.kotlin.ir.backend.js.sourceMapsInfo
|
||||
import org.jetbrains.kotlin.ir.backend.js.utils.*
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
@@ -32,7 +33,6 @@ import java.io.IOException
|
||||
import java.io.InputStreamReader
|
||||
import java.nio.charset.StandardCharsets
|
||||
|
||||
|
||||
fun jsUndefined(context: IrNamer, backendContext: JsIrBackendContext): JsExpression {
|
||||
return when (val void = backendContext.getVoid()) {
|
||||
is IrGetField -> context.getNameForField(void.symbol.owner).makeRef()
|
||||
@@ -114,6 +114,7 @@ fun translateFunction(declaration: IrFunction, name: JsName?, context: JsGenerat
|
||||
val body = declaration.body?.accept(IrElementToJsStatementTransformer(), functionContext) as? JsBlock ?: JsBlock()
|
||||
|
||||
val function = JsFunction(emptyScope, body, "member function ${name ?: "annon"}")
|
||||
.apply { if (declaration.isEs6ConstructorReplacement) modifiers.add(JsFunction.Modifier.STATIC) }
|
||||
.withSource(declaration, context, useNameOf = declaration)
|
||||
|
||||
function.name = name
|
||||
@@ -147,6 +148,7 @@ fun translateCall(
|
||||
transformer: IrElementToJsExpressionTransformer
|
||||
): JsExpression {
|
||||
val function = expression.symbol.owner.realOverrideTarget
|
||||
val currentDispatchReceiver = context.currentFunction?.parentClassOrNull
|
||||
|
||||
context.staticContext.intrinsics[function.symbol]?.let {
|
||||
return it(expression, context)
|
||||
@@ -194,6 +196,10 @@ fun translateCall(
|
||||
Pair(function, superQualifier.owner)
|
||||
}
|
||||
|
||||
if (expression.isSyntheticDelegatingReplacement || currentDispatchReceiver.canUseSuperRef(function, context, klass)) {
|
||||
return JsInvocation(JsNameRef(context.getNameForMemberFunction(target), JsSuperRef()), arguments)
|
||||
}
|
||||
|
||||
val callRef = if (klass.isInterface) {
|
||||
val nameForStaticDeclaration = context.getNameForStaticDeclaration(target)
|
||||
JsNameRef(Namer.CALL_FUNCTION, JsNameRef(nameForStaticDeclaration))
|
||||
@@ -373,12 +379,15 @@ fun translateCallArguments(
|
||||
): List<JsExpression> {
|
||||
val size = expression.valueArgumentsCount
|
||||
|
||||
val varargParameterIndex = expression.symbol.owner.realOverrideTarget.varargParameterIndex()
|
||||
val function = expression.symbol.owner
|
||||
val varargParameterIndex = function.realOverrideTarget.varargParameterIndex()
|
||||
|
||||
val validWithNullArgs = expression.validWithNullArgs()
|
||||
val arguments = (0 until size)
|
||||
.mapTo(ArrayList(size)) { index ->
|
||||
expression.getValueArgument(index).checkOnNullability(validWithNullArgs)
|
||||
expression.getValueArgument(index).checkOnNullability(
|
||||
validWithNullArgs || function.valueParameters[index].isBoxParameter
|
||||
)
|
||||
}
|
||||
.dropLastWhile {
|
||||
allowDropTailVoids &&
|
||||
@@ -635,3 +644,11 @@ private val nameMappingOriginAllowList = setOf(
|
||||
BOUND_VALUE_PARAMETER,
|
||||
JsLoweredDeclarationOrigin.JS_SHADOWED_DEFAULT_PARAMETER,
|
||||
)
|
||||
|
||||
private fun IrClass?.canUseSuperRef(function: IrFunction, context: JsGenerationContext, superClass: IrClass): Boolean {
|
||||
return this != null &&
|
||||
function.origin != IrDeclarationOrigin.LOWERED_SUSPEND_FUNCTION &&
|
||||
context.staticContext.backendContext.es6mode &&
|
||||
!superClass.isInterface && !isInner && !isLocal &&
|
||||
context.currentFunction?.isEs6ConstructorReplacement != true
|
||||
}
|
||||
|
||||
+13
-1
@@ -74,8 +74,20 @@ private fun JsNode.computeScopes(): Scope {
|
||||
accept(object : RecursiveJsVisitor() {
|
||||
var currentScope: Scope = rootScope
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
override fun visitClass(x: JsClass) {
|
||||
x.name?.let { currentScope.declaredNames += it }
|
||||
// We need it to not rename methods and fields inside class body
|
||||
// Because if they are in clash with something, it means overriding
|
||||
x.constructor?.accept(this)
|
||||
x.members.forEach { visitFunction(it, shouldReserveName = false) }
|
||||
}
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
visitFunction(x, shouldReserveName = true)
|
||||
}
|
||||
|
||||
fun visitFunction(x: JsFunction, shouldReserveName: Boolean) {
|
||||
x.name?.takeIf { shouldReserveName }?.let { currentScope.declaredNames += it }
|
||||
val oldScope = currentScope
|
||||
currentScope = Scope().apply {
|
||||
currentScope.children += this
|
||||
|
||||
@@ -12,7 +12,6 @@ import org.jetbrains.kotlin.ir.declarations.IrOverridableDeclaration
|
||||
import org.jetbrains.kotlin.ir.expressions.IrClassReference
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConst
|
||||
import org.jetbrains.kotlin.ir.expressions.IrConstructorCall
|
||||
import org.jetbrains.kotlin.ir.expressions.IrVararg
|
||||
import org.jetbrains.kotlin.ir.symbols.IrClassSymbol
|
||||
import org.jetbrains.kotlin.ir.util.*
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
@@ -37,10 +36,6 @@ object JsAnnotations {
|
||||
fun IrConstructorCall.getSingleConstStringArgument() =
|
||||
(getValueArgument(0) as IrConst<String>).value
|
||||
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun IrConstructorCall.getClassReferencVarargArguments() =
|
||||
(getValueArgument(0) as? IrVararg)?.elements as? List<IrClassReference>
|
||||
|
||||
fun IrAnnotationContainer.getJsModule(): String? =
|
||||
getAnnotation(JsAnnotations.jsModuleFqn)?.getSingleConstStringArgument()
|
||||
|
||||
|
||||
@@ -9,16 +9,28 @@ import org.jetbrains.kotlin.descriptors.isClass
|
||||
import org.jetbrains.kotlin.descriptors.isInterface
|
||||
import org.jetbrains.kotlin.ir.UNDEFINED_OFFSET
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsIrBackendContext
|
||||
import org.jetbrains.kotlin.ir.backend.js.JsStatementOrigins
|
||||
import org.jetbrains.kotlin.ir.backend.js.export.isExported
|
||||
import org.jetbrains.kotlin.ir.backend.js.ir.JsIrBuilder
|
||||
import org.jetbrains.kotlin.ir.declarations.*
|
||||
import org.jetbrains.kotlin.ir.expressions.IrExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrFunctionAccessExpression
|
||||
import org.jetbrains.kotlin.ir.expressions.IrReturn
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrConstImpl
|
||||
import org.jetbrains.kotlin.ir.expressions.impl.IrGetFieldImpl
|
||||
import org.jetbrains.kotlin.ir.symbols.IrReturnableBlockSymbol
|
||||
import org.jetbrains.kotlin.ir.types.IrType
|
||||
import org.jetbrains.kotlin.ir.util.defaultType
|
||||
import org.jetbrains.kotlin.ir.util.isAnnotationClass
|
||||
import org.jetbrains.kotlin.ir.util.parentAsClass
|
||||
import org.jetbrains.kotlin.ir.util.parentClassOrNull
|
||||
import org.jetbrains.kotlin.name.FqName
|
||||
|
||||
fun IrClass.jsConstructorReference(context: JsIrBackendContext): IrExpression {
|
||||
return JsIrBuilder.buildCall(context.intrinsics.jsClass, origin = JsStatementOrigins.CLASS_REFERENCE)
|
||||
.apply { putTypeArgument(0, defaultType) }
|
||||
}
|
||||
|
||||
fun IrDeclaration.isExportedMember(context: JsIrBackendContext) =
|
||||
(this is IrDeclarationWithVisibility && visibility.isPublicAPI) &&
|
||||
parentClassOrNull?.isExported(context) == true
|
||||
@@ -42,10 +54,23 @@ fun IrDeclarationWithName.getFqNameWithJsNameWhenAvailable(shouldIncludePackage:
|
||||
}
|
||||
}
|
||||
|
||||
fun IrConstructor.hasStrictSignature(context: JsIrBackendContext): Boolean {
|
||||
val primitives = with(context.irBuiltIns) { primitiveTypesToPrimitiveArrays.values + stringClass }
|
||||
return with(parentAsClass) {
|
||||
isExternal || isExpect || isAnnotationClass || context.inlineClassesUtils.isClassInlineLike(this) || symbol in primitives
|
||||
}
|
||||
}
|
||||
|
||||
private fun getKotlinOrJsQualifier(parent: IrPackageFragment, shouldIncludePackage: Boolean): FqName? {
|
||||
return (parent as? IrFile)?.getJsQualifier()?.let { FqName(it) } ?: parent.fqName.takeIf { shouldIncludePackage }
|
||||
}
|
||||
|
||||
val IrFunctionAccessExpression.typeArguments: List<IrType?>
|
||||
get() = List(typeArgumentsCount) { getTypeArgument(it) }
|
||||
|
||||
val IrFunctionAccessExpression.valueArguments: List<IrExpression?>
|
||||
get() = List(valueArgumentsCount) { getValueArgument(it) }
|
||||
|
||||
// TODO: the code is written to pass Repl tests, so we should understand. why in Repl tests we don't have backingField
|
||||
fun JsIrBackendContext.getVoid(): IrExpression =
|
||||
intrinsics.void.owner.backingField?.let {
|
||||
@@ -60,3 +85,8 @@ fun JsIrBackendContext.getVoid(): IrExpression =
|
||||
UNDEFINED_OFFSET,
|
||||
irBuiltIns.nothingNType
|
||||
)
|
||||
|
||||
fun irEmpty(context: JsIrBackendContext): IrExpression {
|
||||
return JsIrBuilder.buildComposite(context.dynamicType, emptyList())
|
||||
}
|
||||
|
||||
|
||||
@@ -15,10 +15,13 @@ object Namer {
|
||||
|
||||
val OUTER_NAME = "\$outer"
|
||||
val UNREACHABLE_NAME = "\$unreachable"
|
||||
val THROWABLE_CONSTRUCTOR = "\$throwableCtor"
|
||||
|
||||
val DELEGATE = "\$delegate"
|
||||
|
||||
val IMPLICIT_RECEIVER_NAME = "this"
|
||||
val SYNTHETIC_RECEIVER_NAME = "\$this"
|
||||
val ES6_BOX_PARAMETER_NAME = "\$box"
|
||||
|
||||
val ARGUMENTS = JsNameRef("arguments")
|
||||
|
||||
|
||||
@@ -0,0 +1,10 @@
|
||||
/*
|
||||
* Copyright 2010-2022 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.utils
|
||||
|
||||
class MutableReference<T>(var value: T)
|
||||
|
||||
fun <T> mutableReferenceOf(value: T): MutableReference<T> = MutableReference(value)
|
||||
+2
@@ -54,4 +54,6 @@ object ExpressionIds {
|
||||
const val PROPERTY_REFERENCE = 19
|
||||
const val INVOCATION = 20
|
||||
const val NEW = 21
|
||||
const val CLASS = 22
|
||||
const val SUPER_REF = 23
|
||||
}
|
||||
+23
-5
@@ -240,6 +240,7 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
private val sideEffectKindValues = SideEffectKind.values()
|
||||
private val jsBinaryOperatorValues = JsBinaryOperator.values()
|
||||
private val jsUnaryOperatorValues = JsUnaryOperator.values()
|
||||
private val jsFunctionModifiersValues = JsFunction.Modifier.values()
|
||||
|
||||
private fun readExpression(): JsExpression {
|
||||
return withComments {
|
||||
@@ -249,6 +250,9 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
THIS_REF -> {
|
||||
JsThisRef()
|
||||
}
|
||||
SUPER_REF -> {
|
||||
JsSuperRef()
|
||||
}
|
||||
NULL -> {
|
||||
JsNullLiteral()
|
||||
}
|
||||
@@ -283,10 +287,15 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
)
|
||||
}
|
||||
FUNCTION -> {
|
||||
JsFunction(scope, readBlock(), "").apply {
|
||||
readRepeated { parameters += readParameter() }
|
||||
ifTrue { name = nameTable[readInt()] }
|
||||
isLocal = readBoolean()
|
||||
readFunction()
|
||||
}
|
||||
CLASS -> {
|
||||
JsClass(
|
||||
ifTrue { nameTable[readInt()] },
|
||||
ifTrue { nameTable[readInt()].makeRef() },
|
||||
ifTrue { readFunction() },
|
||||
).apply {
|
||||
readRepeated { members += readFunction() }
|
||||
}
|
||||
}
|
||||
DOC_COMMENT -> {
|
||||
@@ -353,6 +362,15 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
}
|
||||
}
|
||||
|
||||
private fun readFunction(): JsFunction {
|
||||
return JsFunction(scope, readBlock(), "").apply {
|
||||
readRepeated { parameters += readParameter() }
|
||||
readRepeated { modifiers += jsFunctionModifiersValues[readInt()] }
|
||||
ifTrue { name = nameTable[readInt()] }
|
||||
isLocal = readBoolean()
|
||||
}
|
||||
}
|
||||
|
||||
private fun readJsImportedModule(): JsImportedModule {
|
||||
return JsImportedModule(
|
||||
stringTable[readInt()],
|
||||
@@ -447,4 +465,4 @@ private class JsIrAstDeserializer(private val source: ByteArray) {
|
||||
ifTrue { this.commentsAfterNode = readArray { readComment() }.toList() }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
+29
-3
@@ -336,6 +336,10 @@ private class JsIrAstSerializer {
|
||||
writeByte(ExpressionIds.THIS_REF)
|
||||
}
|
||||
|
||||
override fun visitSuper(x: JsSuperRef) {
|
||||
writeByte(ExpressionIds.SUPER_REF)
|
||||
}
|
||||
|
||||
override fun visitNull(x: JsNullLiteral) {
|
||||
writeByte(ExpressionIds.NULL)
|
||||
}
|
||||
@@ -387,12 +391,24 @@ private class JsIrAstSerializer {
|
||||
|
||||
override fun visitFunction(x: JsFunction) {
|
||||
writeByte(ExpressionIds.FUNCTION)
|
||||
writeBlock(x.body)
|
||||
writeCollection(x.parameters) { writeParameter(it) }
|
||||
writeFunction(x)
|
||||
}
|
||||
|
||||
override fun visitClass(x: JsClass) {
|
||||
writeByte(ExpressionIds.CLASS)
|
||||
ifNotNull(x.name) {
|
||||
writeInt(internalizeName(it))
|
||||
}
|
||||
writeBoolean(x.isLocal)
|
||||
// TODO: add more complex JsNameRef parsing in future when we will support `class` expressions inside a `js` call
|
||||
ifNotNull(x.baseClass?.name) {
|
||||
writeInt(internalizeName(it))
|
||||
}
|
||||
ifNotNull(x.constructor) {
|
||||
writeFunction(it)
|
||||
}
|
||||
writeCollection(x.members) {
|
||||
writeFunction(it)
|
||||
}
|
||||
}
|
||||
|
||||
override fun visitDocComment(comment: JsDocComment) {
|
||||
@@ -494,6 +510,16 @@ private class JsIrAstSerializer {
|
||||
ifNotNull(module.plainReference) { writeExpression(it) }
|
||||
}
|
||||
|
||||
private fun DataWriter.writeFunction(function: JsFunction) {
|
||||
writeBlock(function.body)
|
||||
writeCollection(function.parameters) { writeParameter(it) }
|
||||
writeCollection(function.modifiers) { writeInt(it.ordinal) }
|
||||
ifNotNull(function.name) {
|
||||
writeInt(internalizeName(it))
|
||||
}
|
||||
writeBoolean(function.isLocal)
|
||||
}
|
||||
|
||||
private fun DataWriter.writeParameter(parameter: JsParameter) {
|
||||
writeInt(internalizeName(parameter.name))
|
||||
writeBoolean(parameter.hasDefaultValue)
|
||||
|
||||
@@ -5,8 +5,6 @@
|
||||
|
||||
package org.jetbrains.kotlin.ir.expressions
|
||||
|
||||
import org.jetbrains.kotlin.ir.declarations.IrDeclarationOriginImpl
|
||||
|
||||
abstract class IrStatementOriginImpl(val debugName: String) : IrStatementOrigin {
|
||||
override fun toString(): String = debugName
|
||||
}
|
||||
|
||||
@@ -205,6 +205,12 @@ val IrProperty.isSimpleProperty: Boolean
|
||||
val IrClass.functions: Sequence<IrSimpleFunction>
|
||||
get() = declarations.asSequence().filterIsInstance<IrSimpleFunction>()
|
||||
|
||||
val IrClass.superClass: IrClass?
|
||||
get() = superTypes
|
||||
.firstOrNull { !it.isInterface() && !it.isAny() }
|
||||
?.classOrNull
|
||||
?.owner
|
||||
|
||||
val IrClassSymbol.functions: Sequence<IrSimpleFunctionSymbol>
|
||||
get() = owner.functions.map { it.symbol }
|
||||
|
||||
@@ -823,8 +829,11 @@ fun IrFunction.copyValueParametersFrom(from: IrFunction, substitutionMap: Map<Ir
|
||||
fun IrFunction.copyParameterDeclarationsFrom(from: IrFunction) {
|
||||
assert(typeParameters.isEmpty())
|
||||
copyTypeParametersFrom(from)
|
||||
val substitutionMap = makeTypeParameterSubstitutionMap(from, this)
|
||||
copyValueParametersFrom(from, substitutionMap)
|
||||
copyValueParametersFrom(from)
|
||||
}
|
||||
|
||||
fun IrFunction.copyValueParametersFrom(from: IrFunction) {
|
||||
copyValueParametersFrom(from, makeTypeParameterSubstitutionMap(from, this))
|
||||
}
|
||||
|
||||
fun IrTypeParametersContainer.copyTypeParameters(
|
||||
|
||||
+1
@@ -45,6 +45,7 @@ where advanced options include:
|
||||
-Xtyped-arrays Translate primitive arrays to JS typed arrays
|
||||
-Xuse-deprecated-legacy-compiler
|
||||
Use deprecated legacy compiler without error
|
||||
-Xes-classes Generated JavaScript will use ES2015 classes.
|
||||
-Xwasm Use experimental WebAssembly compiler backend
|
||||
-Xwasm-debug-info Add debug info to WebAssembly compiled module
|
||||
-Xwasm-enable-array-range-checks
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR, WASM
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||
var result = ""
|
||||
|
||||
fun sideEffecting(): Int {
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
|
||||
|
||||
// The code in this test should be prohibited in the frontend, see KT-36188.
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6
|
||||
// !JVM_DEFAULT_MODE: all
|
||||
// JVM_TARGET: 1.8
|
||||
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
// ^ wasm-function[1893]:0x1cf8a: RuntimeError: dereferencing a null pointer
|
||||
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// ^ TypeError: tmp is not a function
|
||||
|
||||
// FILE: funInterfaceConstructedObjectsEquality.kt
|
||||
|
||||
+1
-1
@@ -7,7 +7,7 @@
|
||||
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
||||
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// ^ Failed: ks1 != ks2 (same file, same SAM type)
|
||||
|
||||
// FILE: funInterfaceConstructorEquality.kt
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// !LANGUAGE: +DefinitelyNonNullableTypes
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// IGNORE_BACKEND: WASM
|
||||
|
||||
fun <T> test(t: T) = t as (T & Any)
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR, WASM
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||
@Suppress("UNCHECKED_CAST")
|
||||
fun <T> f() = 1L as T
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS, JS_IR, WASM
|
||||
// IGNORE_BACKEND: JS, JS_IR, JS_IR_ES6, WASM
|
||||
|
||||
// boxed primitive comparisons
|
||||
fun isBoolean(a: Any) = a::class == true::class
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// IGNORE_BACKEND_K2: JS_IR
|
||||
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
|
||||
|
||||
class Outer(val x: Any) {
|
||||
inner class Inner(
|
||||
|
||||
+1
-2
@@ -1,5 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// IGNORE_BACKEND_K2: JS_IR
|
||||
// IGNORE_BACKEND_K2: JS_IR, JS_IR_ES6
|
||||
|
||||
class Outer(val x: Any) {
|
||||
inner class Inner(
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
|
||||
|
||||
Vendored
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// MODULE: lib(support)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// MODULE: lib(support)
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// KT-55464
|
||||
// IGNORE_BACKEND_K2: NATIVE
|
||||
// WITH_COROUTINES
|
||||
|
||||
+1
-1
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
// WITH_COROUTINES
|
||||
// WITH_STDLIB
|
||||
// MODULE: lib(support)
|
||||
|
||||
Vendored
-1
@@ -1,7 +1,6 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: NESTED_OBJECT_INIT
|
||||
// IGNORE_BACKEND: NATIVE
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// WITH_STDLIB
|
||||
// WITH_COROUTINES
|
||||
import helpers.*
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
// WITH_STDLIB
|
||||
// FULL_JDK
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
import kotlin.coroutines.*
|
||||
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
// IGNORE_BACKEND: JVM, JS, JS_IR
|
||||
// IGNORE_BACKEND: JVM, JS, JS_IR, JS_IR_ES6
|
||||
// KT-30080
|
||||
|
||||
data class A(
|
||||
|
||||
+1
-1
@@ -1,7 +1,7 @@
|
||||
// WITH_STDLIB
|
||||
// CHECK_BYTECODE_LISTING
|
||||
// FIR_IDENTICAL
|
||||
// IGNORE_BACKEND: JS_IR
|
||||
// IGNORE_BACKEND: JS_IR, JS_IR_ES6
|
||||
|
||||
import kotlin.reflect.KProperty
|
||||
import kotlin.test.assertEquals
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
open class A {
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun noTails() {
|
||||
// nothing here
|
||||
|
||||
Vendored
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
tailrec fun test(x : Int) : Int {
|
||||
var z = if (x > 3) 3 else x
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
-1
@@ -1,7 +1,6 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// !DIAGNOSTICS: -UNUSED_PARAMETER
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
|
||||
bar {
|
||||
|
||||
Vendored
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun foo() {
|
||||
fun bar() {
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(counter : Int) : Int {
|
||||
if (counter == 0) return 0
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
Vendored
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
|
||||
<!NO_TAIL_CALLS_FOUND!>tailrec<!> fun test(go: Boolean) : Unit {
|
||||
if (!go) return
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
// IGNORE_BACKEND: JVM
|
||||
// IGNORE_FIR_DIAGNOSTICS_DIFF
|
||||
|
||||
-1
@@ -1,4 +1,3 @@
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// DONT_RUN_GENERATED_CODE: JS
|
||||
|
||||
object O {
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
-1
@@ -1,6 +1,5 @@
|
||||
// IGNORE_BACKEND: WASM
|
||||
// WASM_MUTE_REASON: IGNORED_IN_JS
|
||||
// IGNORE_BACKEND: JS_IR_ES6
|
||||
// TODO: muted automatically, investigate should it be ran for JS or not
|
||||
// IGNORE_BACKEND: JS
|
||||
|
||||
|
||||
Some files were not shown because too many files have changed in this diff Show More
Reference in New Issue
Block a user